zx 3 months ago
parent 974db7e0c0
commit bf70654dcf

@ -1,157 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Notesmaster"
tools:targetApi="31">
<activity
android:name=".ui.NotesListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@style/NoteTheme"
android:uiOptions="splitActionBarWhenNarrow"
android:windowSoftInputMode="adjustPan"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.NoteEditActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:launchMode="singleTop"
android:theme="@style/NoteTheme"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/text_note" />
<data android:mimeType="vnd.android.cursor.item/call_note" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.INSERT_OR_EDIT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/text_note" />
<data android:mimeType="vnd.android.cursor.item/call_note" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<provider
android:name="net.micode.notes.data.NotesProvider"
android:authorities="micode_notes"
android:multiprocess="true" />
<receiver
android:name=".widget.NoteWidgetProvider_2x"
android:label="@string/app_widget2x2"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_2x_info" />
</receiver>
<receiver
android:name=".widget.NoteWidgetProvider_4x"
android:label="@string/app_widget4x4"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_4x_info" />
</receiver>
<receiver android:name=".ui.AlarmInitReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver
android:name="net.micode.notes.ui.AlarmReceiver"
android:process=":remote" >
</receiver>
<activity
android:name=".ui.AlarmAlertActivity"
android:label="@string/app_name"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar" >
</activity>
<activity
android:name="net.micode.notes.ui.NotesPreferenceActivity"
android:label="@string/preferences_title"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Holo.Light" >
</activity>
<service
android:name="net.micode.notes.gtask.remote.GTaskSyncService"
android:exported="false" >
</service>
<meta-data
android:name="android.app.default_searchable"
android:value=".ui.NoteEditActivity" />
<!-- <activity-->
<!-- android:name=".MainActivity"-->
<!-- android:exported="true">-->
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.MAIN" />-->
<!-- <category android:name="android.intent.category.LAUNCHER" />-->
<!-- </intent-filter>-->
<!-- </activity>-->
</application>
</manifest>

@ -1,2 +0,0 @@
# notes-master1

@ -26,31 +26,25 @@ import android.util.Log;
import java.util.HashMap; import java.util.HashMap;
public class Contact { public class Contact {
// 静态HashMap缓存已查询的电话号码与姓名的映射
private static HashMap<String, String> sContactCache; private static HashMap<String, String> sContactCache;
private static final String TAG = "Contact"; private static final String TAG = "Contact";
// SQL查询条件模板用于匹配电话号码对应的联系人
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 "
+ "(SELECT raw_contact_id " + "(SELECT raw_contact_id "
+ " FROM phone_lookup" + " FROM phone_lookup"
+ " WHERE min_match = '+')"; + " WHERE min_match = '+')";
// 根据电话号码查询联系人姓名
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);
} }
// 动态构建查询条件(替换模板中的"+"为实际的匹配前缀)
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(
@ -60,7 +54,6 @@ 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);

@ -18,10 +18,8 @@ package net.micode.notes.data;
import android.net.Uri; import android.net.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";
//定义了标签的类型,分别表示便签、文件夹和系统类型
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;
@ -32,13 +30,11 @@ public class Notes {
* {@link Notes#ID_TEMPARAY_FOLDER } is for notes belonging no folder * {@link Notes#ID_TEMPARAY_FOLDER } is for notes belonging no folder
* {@link Notes#ID_CALL_RECORD_FOLDER} is to store call records * {@link Notes#ID_CALL_RECORD_FOLDER} is to store call records
*/ */
//定义了系统文件夹的标识符
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;
//定义了意图中的额外数据键
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";
@ -46,7 +42,6 @@ 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";
//定义了组件的类型、无效类型、2倍大小和4倍大小
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;
@ -59,24 +54,13 @@ public class Notes {
/** /**
* Uri to query all notes and folders * Uri to query all notes and folders
*/ */
/**
* 便NoteURI访便
*/
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 to query data * Uri to query data
*/ */
//表示数据Data的内容URI用于访问数据相关信息。
public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data");
/**
便Note
*便IDID
*IDID
* 便IDIDGTask ID*/
public interface NoteColumns { public interface NoteColumns {
/** /**
* The unique ID for a row * The unique ID for a row
@ -183,11 +167,6 @@ public class Notes {
public static final String VERSION = "version"; public static final String VERSION = "version";
} }
/**
* Data
* IDMIME便ID
* 5data1data5
*/
public interface DataColumns { public interface DataColumns {
/** /**
* The unique ID for a row * The unique ID for a row
@ -226,19 +205,39 @@ public class Notes {
public static final String CONTENT = "content"; public static final String CONTENT = "content";
/**
* 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";
/**
* 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";
/**
* 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";
/**
* 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";
/**
* 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";
} }
@ -247,45 +246,34 @@ public class Notes {
* Mode to indicate the text in check list mode or not * Mode to indicate the text in check list mode or not
* <P> Type: Integer 1:check list mode 0: normal mode </P> * <P> Type: Integer 1:check list mode 0: normal mode </P>
*/ */
//表示文本便签的形式,用于指示是否处于检查列表模式
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 { public static final class CallNote implements DataColumns {
/** /**
* Call date for this record * Call date for this record
* <P> Type: INTEGER (long) </P> * <P> Type: INTEGER (long) </P>
*/ */
//表示通话记录的日期
public static final String CALL_DATE = DATA1; public static final String CALL_DATE = DATA1;
/** /**
* Phone number for this record * Phone number for this record
* <P> Type: TEXT </P> * <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");
} }
} }

@ -22,34 +22,26 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log; import android.util.Log;
//对Notes类中DataColumns、DataConstants、NoteColumns进行引用
import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants; import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.Notes.NoteColumns;
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;
//定义了TABLE接口
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";
//定义了一个静态变量mInstance用于表示NotesDatabaseHelper类的实例
private static NotesDatabaseHelper mInstance; private static NotesDatabaseHelper mInstance;
//定义了SQL语句分别用于创建便签表、数据表、包含ID、便签和数据的表格
private static final String CREATE_NOTE_TABLE_SQL = private static final String CREATE_NOTE_TABLE_SQL =
"CREATE TABLE " + TABLE.NOTE + "(" + "CREATE TABLE " + TABLE.NOTE + "(" +
NoteColumns.ID + " INTEGER PRIMARY KEY," + NoteColumns.ID + " INTEGER PRIMARY KEY," +
@ -92,9 +84,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/** /**
* Increase folder's note count when move note to the folder * Increase folder's note count when move note to the folder
*
*/ */
//定义了对数据库进行增删改查等工作的SQL语句
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER increase_folder_count_on_update "+ "CREATE TRIGGER increase_folder_count_on_update "+
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
@ -106,7 +96,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/** /**
* Decrease folder's note count when move note from folder * Decrease folder's note count when move note from folder
*
*/ */
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER decrease_folder_count_on_update " + "CREATE TRIGGER decrease_folder_count_on_update " +
@ -120,7 +109,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/** /**
* Increase folder's note count when insert new note to the folder * Increase folder's note count when insert new note to the folder
*
*/ */
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER = private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER =
"CREATE TRIGGER increase_folder_count_on_insert " + "CREATE TRIGGER increase_folder_count_on_insert " +
@ -133,7 +121,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/** /**
* Decrease folder's note count when delete note from the folder * Decrease folder's note count when delete note from the folder
*
*/ */
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER =
"CREATE TRIGGER decrease_folder_count_on_delete " + "CREATE TRIGGER decrease_folder_count_on_delete " +
@ -147,7 +134,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/** /**
* Update note's content when insert data with type {@link DataConstants#NOTE} * Update note's content when insert data with type {@link DataConstants#NOTE}
* DataConstants.Note
*/ */
private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER = private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER =
"CREATE TRIGGER update_note_content_on_insert " + "CREATE TRIGGER update_note_content_on_insert " +
@ -161,7 +147,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/** /**
* Update note's content when data with {@link DataConstants#NOTE} type has changed * Update note's content when data with {@link DataConstants#NOTE} type has changed
* DataConstants.Note
*/ */
private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER = private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER update_note_content_on_update " + "CREATE TRIGGER update_note_content_on_update " +
@ -175,7 +160,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/** /**
* Update note's content when data with {@link DataConstants#NOTE} type has deleted * Update note's content when data with {@link DataConstants#NOTE} type has deleted
* DataConstants.Note
*/ */
private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER = private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER =
"CREATE TRIGGER update_note_content_on_delete " + "CREATE TRIGGER update_note_content_on_delete " +
@ -189,7 +173,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/** /**
* Delete datas belong to note which has been deleted * Delete datas belong to note which has been deleted
*
*/ */
private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER = private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER =
"CREATE TRIGGER delete_data_on_delete " + "CREATE TRIGGER delete_data_on_delete " +
@ -201,7 +184,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/** /**
* Delete notes belong to folder which has been deleted * Delete notes belong to folder which has been deleted
*
*/ */
private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER = private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER =
"CREATE TRIGGER folder_delete_notes_on_delete " + "CREATE TRIGGER folder_delete_notes_on_delete " +
@ -213,7 +195,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/** /**
* Move notes belong to folder which has been moved to trash folder * Move notes belong to folder which has been moved to trash folder
*
*/ */
private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER = private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER =
"CREATE TRIGGER folder_move_notes_on_trash " + "CREATE TRIGGER folder_move_notes_on_trash " +
@ -229,19 +210,13 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
super(context, DB_NAME, null, DB_VERSION); super(context, DB_NAME, null, DB_VERSION);
} }
//创建便签表
public void createNoteTable(SQLiteDatabase db) { public void createNoteTable(SQLiteDatabase db) {
//执行创建表的SQL语句
db.execSQL(CREATE_NOTE_TABLE_SQL); db.execSQL(CREATE_NOTE_TABLE_SQL);
//重新创建表的触发器
reCreateNoteTableTriggers(db); reCreateNoteTableTriggers(db);
//创建系统文件夹
createSystemFolder(db); createSystemFolder(db);
//打印日志
Log.d(TAG, "note table has been created"); Log.d(TAG, "note table has been created");
} }
//重新创建便签表的触发器
private void reCreateNoteTableTriggers(SQLiteDatabase db) { private void reCreateNoteTableTriggers(SQLiteDatabase db) {
db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update"); db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update");
db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update"); db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update");
@ -260,7 +235,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
} }
//创建系统文件夹,包括通话记录文件夹、默认文件夹、临时文件夹和回收站文件夹。
private void createSystemFolder(SQLiteDatabase db) { private void createSystemFolder(SQLiteDatabase db) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
@ -296,19 +270,13 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.insert(TABLE.NOTE, null, values); db.insert(TABLE.NOTE, null, values);
} }
//创建数据表
public void createDataTable(SQLiteDatabase db) { public void createDataTable(SQLiteDatabase db) {
//执行创建表的SQL语句
db.execSQL(CREATE_DATA_TABLE_SQL); db.execSQL(CREATE_DATA_TABLE_SQL);
//重新创建表的触发器
reCreateDataTableTriggers(db); reCreateDataTableTriggers(db);
//创建数据表的索引
db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL);
//打印日志
Log.d(TAG, "data table has been created"); Log.d(TAG, "data table has been created");
} }
//重新创建数据表的触发器
private void reCreateDataTableTriggers(SQLiteDatabase db) { private void reCreateDataTableTriggers(SQLiteDatabase db) {
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert"); db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert");
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update"); db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update");
@ -319,7 +287,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER);
} }
//获取NotesDatabaseHelper类的实例
static synchronized NotesDatabaseHelper getInstance(Context context) { static synchronized NotesDatabaseHelper getInstance(Context context) {
if (mInstance == null) { if (mInstance == null) {
mInstance = new NotesDatabaseHelper(context); mInstance = new NotesDatabaseHelper(context);
@ -327,14 +294,12 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
return mInstance; return mInstance;
} }
//在数据库创建时调用,执行创建便签表和数据表的操作。
@Override @Override
public void onCreate(SQLiteDatabase db) { public void onCreate(SQLiteDatabase db) {
createNoteTable(db); createNoteTable(db);
createDataTable(db); createDataTable(db);
} }
//在数据库升级时调用,根据旧版本和新版本执行相应的升级操作
@Override @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
boolean reCreateTriggers = false; boolean reCreateTriggers = false;
@ -368,7 +333,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
} }
} }
//升级数据库到版本2的操作
private void upgradeToV2(SQLiteDatabase db) { private void upgradeToV2(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE);
db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA);
@ -376,7 +340,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
createDataTable(db); createDataTable(db);
} }
//升级数据库到版本3的操作
private void upgradeToV3(SQLiteDatabase db) { private void upgradeToV3(SQLiteDatabase db) {
// drop unused triggers // drop unused triggers
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert"); db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert");
@ -392,7 +355,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.insert(TABLE.NOTE, null, values); db.insert(TABLE.NOTE, null, values);
} }
//升级数据库到版本4的操作
private void upgradeToV4(SQLiteDatabase db) { private void upgradeToV4(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0"); + " INTEGER NOT NULL DEFAULT 0");

@ -36,16 +36,12 @@ import net.micode.notes.data.NotesDatabaseHelper.TABLE;
public class NotesProvider extends ContentProvider { public class NotesProvider extends ContentProvider {
//UriMatcher对象用于匹配URI并返回相应的整数值
private static final UriMatcher mMatcher; private static final UriMatcher mMatcher;
//表示NotesDatabaseHelper的实例
private NotesDatabaseHelper mHelper; private NotesDatabaseHelper mHelper;
//用于标识日志的标签
private static final String TAG = "NotesProvider"; private static final String TAG = "NotesProvider";
//定义了不同类型的URI匹配值
private static final int URI_NOTE = 1; private static final int URI_NOTE = 1;
private static final int URI_NOTE_ITEM = 2; private static final int URI_NOTE_ITEM = 2;
private static final int URI_DATA = 3; private static final int URI_DATA = 3;
@ -69,7 +65,6 @@ public class NotesProvider extends ContentProvider {
* x'0A' represents the '\n' character in sqlite. For title and content in the search result, * x'0A' represents the '\n' character in sqlite. For title and content in the search result,
* we will trim '\n' and white space in order to show more information. * we will trim '\n' and white space in order to show more information.
*/ */
//定义了搜索结果的投影包括便签ID、额外数据、文本1、文本2、图标、意图操作和数据
private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + ","
+ NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + ","
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + "," + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + ","
@ -78,7 +73,6 @@ public class NotesProvider extends ContentProvider {
+ "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + ","
+ "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA;
//定义了搜索便签摘要的查询语句,用于从便签表中查询符合条件的便签摘要数据
private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION
+ " FROM " + TABLE.NOTE + " FROM " + TABLE.NOTE
+ " WHERE " + NoteColumns.SNIPPET + " LIKE ?" + " WHERE " + NoteColumns.SNIPPET + " LIKE ?"
@ -91,7 +85,6 @@ public class NotesProvider extends ContentProvider {
return true; return true;
} }
//处理查询操作根据URI匹配不同的查询类型包括便签、数据和搜索结果的查询。
@Override @Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) { String sortOrder) {
@ -154,7 +147,6 @@ public class NotesProvider extends ContentProvider {
return c; return c;
} }
//处理插入操作
@Override @Override
public Uri insert(Uri uri, ContentValues values) { public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = mHelper.getWritableDatabase(); SQLiteDatabase db = mHelper.getWritableDatabase();
@ -189,7 +181,6 @@ public class NotesProvider extends ContentProvider {
return ContentUris.withAppendedId(uri, insertedId); return ContentUris.withAppendedId(uri, insertedId);
} }
//处理删除操作
@Override @Override
public int delete(Uri uri, String selection, String[] selectionArgs) { public int delete(Uri uri, String selection, String[] selectionArgs) {
int count = 0; int count = 0;
@ -236,7 +227,6 @@ public class NotesProvider extends ContentProvider {
return count; return count;
} }
//处理更新操作
@Override @Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int count = 0; int count = 0;
@ -277,12 +267,10 @@ public class NotesProvider extends ContentProvider {
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) { private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
StringBuilder sql = new StringBuilder(120); StringBuilder sql = new StringBuilder(120);
sql.append("UPDATE "); sql.append("UPDATE ");
@ -308,7 +296,6 @@ public class NotesProvider extends ContentProvider {
mHelper.getWritableDatabase().execSQL(sql.toString()); mHelper.getWritableDatabase().execSQL(sql.toString());
} }
//获取URI的MIME类型暂未实现
@Override @Override
public String getType(Uri uri) { public String getType(Uri uri) {
// TODO Auto-generated method stub // TODO Auto-generated method stub

@ -24,58 +24,31 @@ import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
public class MetaData extends Task { public class MetaData extends Task {
/*
* TAG
* getSimpleName ()
*/
private final static String TAG = MetaData.class.getSimpleName(); private final static String TAG = MetaData.class.getSimpleName();
// 存储关联的Google Tasks ID
private String mRelatedGid = null; private String mRelatedGid = null;
/*
*
* JSONObjectput ()TasksetNotes ()setName ()
*
*/
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);
/*
* metaInfojsonobject
*/
} catch (JSONException e) { } catch (JSONException e) {
Log.e(TAG, "failed to put related gid"); Log.e(TAG, "failed to put related gid");
/*
*
*/
} }
setNotes(metaInfo.toString()); setNotes(metaInfo.toString());
setName(GTaskStringUtils.META_NOTE_NAME); setName(GTaskStringUtils.META_NOTE_NAME);
} }
/*
* Gid
*/
public String getRelatedGid() { public String getRelatedGid() {
return mRelatedGid; return mRelatedGid;
} }
/*
*
*/
@Override @Override
public boolean isWorthSaving() { public boolean isWorthSaving() {
return getNotes() != null; return getNotes() != null;
} }
/*
* 使json
* TasksetContentByRemoteJSON ()
*
*/
@Override @Override
public void setContentByRemoteJSON(JSONObject js) { public void setContentByRemoteJSON(JSONObject js) {
super.setContentByRemoteJSON(js); super.setContentByRemoteJSON(js);
@ -90,27 +63,20 @@ public class MetaData extends Task {
} }
} }
/*
* 使json
*/
@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
*/
@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");
} }
/*
*
*/
@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");
} }
} }

@ -21,24 +21,32 @@ import android.database.Cursor;
import org.json.JSONObject; import org.json.JSONObject;
public abstract class Node { public abstract class Node {
// 同步动作常量定义9种同步操作类型
public static final int SYNC_ACTION_NONE = 0; public static final int SYNC_ACTION_NONE = 0;
public static final int SYNC_ACTION_ADD_REMOTE = 1; public static final int SYNC_ACTION_ADD_REMOTE = 1;
public static final int SYNC_ACTION_ADD_LOCAL = 2; public static final int SYNC_ACTION_ADD_LOCAL = 2;
public static final int SYNC_ACTION_DEL_REMOTE = 3; public static final int SYNC_ACTION_DEL_REMOTE = 3;
public static final int SYNC_ACTION_DEL_LOCAL = 4; public static final int SYNC_ACTION_DEL_LOCAL = 4;
public static final int SYNC_ACTION_UPDATE_REMOTE = 5; public static final int SYNC_ACTION_UPDATE_REMOTE = 5;
public static final int SYNC_ACTION_UPDATE_LOCAL = 6; public static final int SYNC_ACTION_UPDATE_LOCAL = 6;
public static final int SYNC_ACTION_UPDATE_CONFLICT = 7; public static final int SYNC_ACTION_UPDATE_CONFLICT = 7;
public static final int SYNC_ACTION_ERROR = 8; public static final int SYNC_ACTION_ERROR = 8;
// 节点基础属性 private String mGid;
private String mGid; // Google Tasks ID或全局唯一标识
private String mName; // 节点名称 private String mName;
private long mLastModified; // 最后修改时间
private boolean mDeleted; // 删除状态 private long mLastModified;
private boolean mDeleted;
// 构造函数:初始化属性默认值
public Node() { public Node() {
mGid = null; mGid = null;
mName = ""; mName = "";
@ -46,21 +54,48 @@ public abstract class Node {
mDeleted = false; mDeleted = false;
} }
// 抽象方法:由子类实现具体逻辑 public abstract JSONObject getCreateAction(int actionId);
public abstract JSONObject getCreateAction(int actionId); // 创建同步动作的JSON
public abstract JSONObject getUpdateAction(int actionId); // 更新同步动作的JSON public abstract JSONObject getUpdateAction(int actionId);
public abstract void setContentByRemoteJSON(JSONObject js); // 从远程JSON设置内容
public abstract void setContentByLocalJSON(JSONObject js); // 从本地JSON设置内容 public abstract void setContentByRemoteJSON(JSONObject js);
public abstract JSONObject getLocalJSONFromContent(); // 从内容生成本地JSON
public abstract int getSyncAction(Cursor c); // 获取同步动作类型 public abstract void setContentByLocalJSON(JSONObject js);
// 基础属性的getter和setter方法 public abstract JSONObject getLocalJSONFromContent();
public void setGid(String gid) { this.mGid = gid; }
public void setName(String name) { this.mName = name; } public abstract int getSyncAction(Cursor c);
public void setLastModified(long lastModified) { this.mLastModified = lastModified; }
public void setDeleted(boolean deleted) { this.mDeleted = deleted; } public void setGid(String gid) {
public String getGid() { return mGid; } this.mGid = gid;
public String getName() { return mName; } }
public long getLastModified() { return mLastModified; }
public boolean getDeleted() { return mDeleted; } public void setName(String name) {
} this.mName = name;
}
public void setLastModified(long lastModified) {
this.mLastModified = lastModified;
}
public void setDeleted(boolean deleted) {
this.mDeleted = deleted;
}
public String getGid() {
return this.mGid;
}
public String getName() {
return this.mName;
}
public long getLastModified() {
return this.mLastModified;
}
public boolean getDeleted() {
return this.mDeleted;
}
}

@ -37,31 +37,40 @@ import org.json.JSONObject;
public class SqlData { public class SqlData {
private static final String TAG = SqlData.class.getSimpleName(); private static final String TAG = SqlData.class.getSimpleName();
private static final int INVALID_ID = -99999; // 无效ID标识
// 数据库查询投影(指定查询的列) private static final int INVALID_ID = -99999;
public static final String[] PROJECTION_DATA = new String[] { public static final String[] PROJECTION_DATA = new String[] {
DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1,
DataColumns.DATA1, DataColumns.DATA3 DataColumns.DATA3
}; };
// 投影列的索引常量
public static final int DATA_ID_COLUMN = 0; public static final int DATA_ID_COLUMN = 0;
public static final int DATA_MIME_TYPE_COLUMN = 1; public static final int DATA_MIME_TYPE_COLUMN = 1;
public static final int DATA_CONTENT_COLUMN = 2; public static final int DATA_CONTENT_COLUMN = 2;
public static final int DATA_CONTENT_DATA_1_COLUMN = 3; public static final int DATA_CONTENT_DATA_1_COLUMN = 3;
public static final int DATA_CONTENT_DATA_3_COLUMN = 4; public static final int DATA_CONTENT_DATA_3_COLUMN = 4;
// 对象属性(对应数据库表字段) private ContentResolver mContentResolver;
private ContentResolver mContentResolver; // 内容解析器
private boolean mIsCreate; // 是否为新建状态 private boolean mIsCreate;
private long mDataId; // 数据ID
private String mDataMimeType; // MIME类型 private long mDataId;
private String mDataContent; // 数据内容
private long mDataContentData1; // 附加数据1长整型 private String mDataMimeType;
private String mDataContentData3; // 附加数据3字符串
private ContentValues mDiffDataValues; // 记录变更的ContentValues private String mDataContent;
// 构造函数:初始化新对象 private long mDataContentData1;
private String mDataContentData3;
private ContentValues mDiffDataValues;
public SqlData(Context context) { public SqlData(Context context) {
mContentResolver = context.getContentResolver(); mContentResolver = context.getContentResolver();
mIsCreate = true; mIsCreate = true;
@ -73,15 +82,13 @@ public class SqlData {
mDiffDataValues = new ContentValues(); mDiffDataValues = new ContentValues();
} }
// 从Cursor加载数据的构造函数
public SqlData(Context context, Cursor c) { public SqlData(Context context, Cursor c) {
mContentResolver = context.getContentResolver(); mContentResolver = context.getContentResolver();
mIsCreate = false; mIsCreate = false;
loadFromCursor(c); // 从游标加载数据 loadFromCursor(c);
mDiffDataValues = new ContentValues(); mDiffDataValues = new ContentValues();
} }
// 从Cursor加载数据的辅助方法
private void loadFromCursor(Cursor c) { private void loadFromCursor(Cursor c) {
mDataId = c.getLong(DATA_ID_COLUMN); mDataId = c.getLong(DATA_ID_COLUMN);
mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN);
@ -90,16 +97,13 @@ public class SqlData {
mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN);
} }
// 根据JSON设置数据内容并记录变更
public void setContent(JSONObject js) throws JSONException { public void setContent(JSONObject js) throws JSONException {
// 解析ID
long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;
if (mIsCreate || mDataId != dataId) { if (mIsCreate || mDataId != dataId) {
mDiffDataValues.put(DataColumns.ID, dataId); mDiffDataValues.put(DataColumns.ID, dataId);
} }
mDataId = dataId; mDataId = dataId;
// 解析MIME类型
String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE) String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE)
: DataConstants.NOTE; : DataConstants.NOTE;
if (mIsCreate || !mDataMimeType.equals(dataMimeType)) { if (mIsCreate || !mDataMimeType.equals(dataMimeType)) {
@ -107,21 +111,18 @@ public class SqlData {
} }
mDataMimeType = dataMimeType; mDataMimeType = dataMimeType;
// 解析内容
String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : ""; String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : "";
if (mIsCreate || !mDataContent.equals(dataContent)) { if (mIsCreate || !mDataContent.equals(dataContent)) {
mDiffDataValues.put(DataColumns.CONTENT, dataContent); mDiffDataValues.put(DataColumns.CONTENT, dataContent);
} }
mDataContent = dataContent; mDataContent = dataContent;
// 解析附加数据1
long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0; long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0;
if (mIsCreate || mDataContentData1 != dataContentData1) { if (mIsCreate || mDataContentData1 != dataContentData1) {
mDiffDataValues.put(DataColumns.DATA1, dataContentData1); mDiffDataValues.put(DataColumns.DATA1, dataContentData1);
} }
mDataContentData1 = dataContentData1; mDataContentData1 = dataContentData1;
// 解析附加数据3
String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : ""; String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : "";
if (mIsCreate || !mDataContentData3.equals(dataContentData3)) { if (mIsCreate || !mDataContentData3.equals(dataContentData3)) {
mDiffDataValues.put(DataColumns.DATA3, dataContentData3); mDiffDataValues.put(DataColumns.DATA3, dataContentData3);
@ -129,10 +130,9 @@ public class SqlData {
mDataContentData3 = dataContentData3; mDataContentData3 = dataContentData3;
} }
// 将对象数据转换为JSON
public JSONObject getContent() throws JSONException { public JSONObject getContent() throws JSONException {
if (mIsCreate) { if (mIsCreate) {
Log.e(TAG, "数据未创建到数据库中"); Log.e(TAG, "it seems that we haven't created this in database yet");
return null; return null;
} }
JSONObject js = new JSONObject(); JSONObject js = new JSONObject();
@ -144,52 +144,46 @@ public class SqlData {
return js; return js;
} }
// 提交数据到数据库(插入或更新)
public void commit(long noteId, boolean validateVersion, long version) { public void commit(long noteId, boolean validateVersion, long version) {
if (mIsCreate) { if (mIsCreate) {
// 新建数据时移除无效ID并添加noteId关联
if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) { if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) {
mDiffDataValues.remove(DataColumns.ID); mDiffDataValues.remove(DataColumns.ID);
} }
mDiffDataValues.put(DataColumns.NOTE_ID, noteId); mDiffDataValues.put(DataColumns.NOTE_ID, noteId);
// 插入数据
Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues); Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues);
try { try {
mDataId = Long.parseLong(uri.getPathSegments().get(1)); mDataId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
Log.e(TAG, "获取ID失败", e); Log.e(TAG, "Get note id error :" + e.toString());
throw new ActionFailureException("创建笔记失败"); throw new ActionFailureException("create note failed");
} }
} else { } else {
// 更新数据时支持版本验证
if (mDiffDataValues.size() > 0) { if (mDiffDataValues.size() > 0) {
int result = 0; int result = 0;
if (!validateVersion) { if (!validateVersion) {
// 不验证版本时直接更新 result = mContentResolver.update(ContentUris.withAppendedId(
result = mContentResolver.update( Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null);
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, mDataId),
mDiffDataValues, null, null);
} else { } else {
// 验证版本时添加条件(防止并发冲突) result = mContentResolver.update(ContentUris.withAppendedId(
result = mContentResolver.update( Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues,
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, mDataId), " ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE
mDiffDataValues, + " WHERE " + NoteColumns.VERSION + "=?)", new String[] {
" ? IN (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE String.valueOf(noteId), String.valueOf(version)
+ " WHERE " + NoteColumns.VERSION + "=?)", });
new String[] {String.valueOf(noteId), String.valueOf(version)});
} }
if (result == 0) { if (result == 0) {
Log.w(TAG, "更新失败,可能同步时用户已修改笔记"); Log.w(TAG, "there is no update. maybe user updates note when syncing");
} }
} }
} }
// 清空变更记录,并标记为非新建状态
mDiffDataValues.clear(); mDiffDataValues.clear();
mIsCreate = false; mIsCreate = false;
} }
// 获取数据ID
public long getId() { public long getId() {
return mDataId; return mDataId;
} }
} }

@ -38,37 +38,11 @@ import org.json.JSONObject;
import java.util.ArrayList; import java.util.ArrayList;
import android.appwidget.AppWidgetManager;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.exception.ActionFailureException;
import net.micode.notes.tool.GTaskStringUtils;
import net.micode.notes.tool.ResourceParser;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
/*
* TAG
* getSimpleName ()
*/
public class SqlNote { public class SqlNote {
private static final String TAG = SqlNote.class.getSimpleName(); private static final String TAG = SqlNote.class.getSimpleName();
private static final int INVALID_ID = -99999; private static final int INVALID_ID = -99999;
// 集合了interface DataColumns中所有SF常量
public static final String[] PROJECTION_NOTE = new String[] { public static final String[] PROJECTION_NOTE = new String[] {
NoteColumns.ID, NoteColumns.ALERTED_DATE, NoteColumns.BG_COLOR_ID, NoteColumns.ID, NoteColumns.ALERTED_DATE, NoteColumns.BG_COLOR_ID,
NoteColumns.CREATED_DATE, NoteColumns.HAS_ATTACHMENT, NoteColumns.MODIFIED_DATE, NoteColumns.CREATED_DATE, NoteColumns.HAS_ATTACHMENT, NoteColumns.MODIFIED_DATE,
@ -78,9 +52,6 @@ public class SqlNote {
NoteColumns.VERSION NoteColumns.VERSION
}; };
/*
* sql5
*/
public static final int ID_COLUMN = 0; public static final int ID_COLUMN = 0;
public static final int ALERTED_DATE_COLUMN = 1; public static final int ALERTED_DATE_COLUMN = 1;
@ -118,7 +89,7 @@ public class SqlNote {
private Context mContext; private Context mContext;
private ContentResolver mContentResolver; private ContentResolver mContentResolver;
//判断是否直接用Content生成是为true否则为false
private boolean mIsCreate; private boolean mIsCreate;
private long mId; private long mId;
@ -172,13 +143,6 @@ public class SqlNote {
mDataList = new ArrayList<SqlData>(); mDataList = new ArrayList<SqlData>();
} }
/*
*
* mContentResolverContentProvider
* mIsCreate
*
*/
public SqlNote(Context context, Cursor c) { public SqlNote(Context context, Cursor c) {
mContext = context; mContext = context;
mContentResolver = context.getContentResolver(); mContentResolver = context.getContentResolver();
@ -190,13 +154,6 @@ public class SqlNote {
mDiffNoteValues = new ContentValues(); mDiffNoteValues = new ContentValues();
} }
/*
*
* mContentResolverContentProvider
* mIsCreate
*
*/
public SqlNote(Context context, long id) { public SqlNote(Context context, long id) {
mContext = context; mContext = context;
mContentResolver = context.getContentResolver(); mContentResolver = context.getContentResolver();
@ -209,16 +166,12 @@ public class SqlNote {
} }
/*
*
*
*/
private void loadFromCursor(long id) { private void loadFromCursor(long id) {
Cursor c = null; Cursor c = null;
try { try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)", c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)",
new String[] { new String[] {
String.valueOf(id) String.valueOf(id)
}, null); }, null);
if (c != null) { if (c != null) {
c.moveToNext(); c.moveToNext();
@ -253,7 +206,7 @@ public class SqlNote {
try { try {
c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA, c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA,
"(note_id=?)", new String[] { "(note_id=?)", new String[] {
String.valueOf(mId) String.valueOf(mId)
}, null); }, null);
if (c != null) { if (c != null) {
if (c.getCount() == 0) { if (c.getCount() == 0) {
@ -273,10 +226,6 @@ public class SqlNote {
} }
} }
/*
*
*
*/
public boolean setContent(JSONObject js) { public boolean setContent(JSONObject js) {
try { try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
@ -410,12 +359,6 @@ public class SqlNote {
return true; return true;
} }
/*
*
*
* Made By CuiCan
*/
public JSONObject getContent() { public JSONObject getContent() {
try { try {
JSONObject js = new JSONObject(); JSONObject js = new JSONObject();
@ -481,12 +424,6 @@ public class SqlNote {
mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0); mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0);
} }
/*
* id
*
*
* Made By CuiCan
*/
public long getId() { public long getId() {
return mId; return mId;
} }
@ -503,11 +440,6 @@ public class SqlNote {
return mType == Notes.TYPE_NOTE; return mType == Notes.TYPE_NOTE;
} }
/*
* commit
*
* Made By CuiCan
*/
public void commit(boolean validateVersion) { public void commit(boolean validateVersion) {
if (mIsCreate) { if (mIsCreate) {
if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) { if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) {
@ -541,11 +473,11 @@ public class SqlNote {
if (!validateVersion) { if (!validateVersion) {
result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("
+ NoteColumns.ID + "=?)", new String[] { + NoteColumns.ID + "=?)", new String[] {
String.valueOf(mId) String.valueOf(mId)
}); });
} else { } else {
result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("
+ NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)", + NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)",
new String[] { new String[] {
String.valueOf(mId), String.valueOf(mVersion) String.valueOf(mId), String.valueOf(mVersion)
}); });

@ -34,13 +34,17 @@ import org.json.JSONObject;
public class Task extends Node { public class Task extends Node {
private static final String TAG = Task.class.getSimpleName(); private static final String TAG = Task.class.getSimpleName();
private boolean mCompleted; // 任务完成状态
private String mNotes; // 任务备注
private JSONObject mMetaInfo; // 元数据存储本地笔记与GTask的映射
private Task mPriorSibling; // 前一个兄弟任务(用于排序)
private TaskList mParent; // 所属任务列表
// 构造函数:初始化任务属性 private boolean mCompleted;
private String mNotes;
private JSONObject mMetaInfo;
private Task mPriorSibling;
private TaskList mParent;
public Task() { public Task() {
super(); super();
mCompleted = false; mCompleted = false;
@ -50,94 +54,166 @@ public class Task extends Node {
mMetaInfo = null; mMetaInfo = null;
} }
// 生成创建任务的JSON请求
public JSONObject getCreateAction(int actionId) { public JSONObject getCreateAction(int actionId) {
JSONObject js = new JSONObject(); JSONObject js = new JSONObject();
try { try {
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, "create"); // 动作类型 // action_type
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); // 动作ID js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this)); // 排序索引 GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);
// 任务实体数据
// action_id
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// index
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this));
// entity_delta
JSONObject entity = new JSONObject(); JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 任务名称 entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE, "task"); // 实体类型 entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");
if (getNotes() != null) entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_TASK);
if (getNotes() != null) {
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
}
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
// 父任务列表信息
// parent_id
js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid()); js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid());
// dest_parent_type
js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_GROUP);
// list_id
js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid()); js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid());
// 前一个兄弟任务ID用于排序
// prior_sibling_id
if (mPriorSibling != null) { if (mPriorSibling != null) {
js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid()); js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid());
} }
} catch (JSONException e) { } catch (JSONException e) {
throw new ActionFailureException("生成创建任务JSON失败"); Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate task-create jsonobject");
} }
return js; return js;
} }
// 生成更新任务的JSON请求
public JSONObject getUpdateAction(int actionId) { public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject(); JSONObject js = new JSONObject();
try { try {
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, "update"); // 动作类型 // action_type
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); // 动作ID js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); // 任务ID GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);
// 任务实体数据(仅更新变更字段)
// action_id
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// id
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());
// entity_delta
JSONObject entity = new JSONObject(); JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
if (getNotes() != null) entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); if (getNotes() != null) {
entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); // 删除状态 entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
}
entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted());
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
} catch (JSONException e) { } catch (JSONException e) {
throw new ActionFailureException("生成更新任务JSON失败"); Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate task-update jsonobject");
} }
return js; return js;
} }
// 从远程JSONGTask数据设置任务内容
public void setContentByRemoteJSON(JSONObject js) { public void setContentByRemoteJSON(JSONObject js) {
if (js != null) { if (js != null) {
try { try {
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); // 设置GTask ID // id
setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); // 最后修改时间 if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); // 任务名称 setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));
setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES)); // 任务备注 }
setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED)); // 删除状态
setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED)); // 完成状态 // last_modified
if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {
setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));
}
// name
if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) {
setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME));
}
// notes
if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) {
setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES));
}
// deleted
if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) {
setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED));
}
// completed
if (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) {
setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED));
}
} catch (JSONException e) { } catch (JSONException e) {
throw new ActionFailureException("解析远程JSON失败"); Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to get task content from jsonobject");
} }
} }
} }
// 从本地JSON笔记数据设置任务内容
public void setContentByLocalJSON(JSONObject js) { public void setContentByLocalJSON(JSONObject js) {
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) return; if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)
|| !js.has(GTaskStringUtils.META_HEAD_DATA)) {
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
}
try { try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
// 仅处理普通笔记类型
if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) return; if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) {
// 从数据列表中获取笔记内容作为任务名称 Log.e(TAG, "invalid type");
return;
}
for (int i = 0; i < dataArray.length(); i++) { for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i); JSONObject data = dataArray.getJSONObject(i);
if (data.getString(DataColumns.MIME_TYPE).equals(DataConstants.NOTE)) { if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
setName(data.getString(DataColumns.CONTENT)); setName(data.getString(DataColumns.CONTENT));
break; break;
} }
} }
} catch (JSONException e) { } catch (JSONException e) {
Log.e(TAG, "解析本地JSON失败", e); Log.e(TAG, e.toString());
e.printStackTrace();
} }
} }
// 从任务内容生成本地JSON用于存储到本地数据库
public JSONObject getLocalJSONFromContent() { public JSONObject getLocalJSONFromContent() {
String name = getName(); String name = getName();
try { try {
if (mMetaInfo == null) { if (mMetaInfo == null) {
// 新建任务(无元数据) // new task created from web
if (name == null) {
Log.w(TAG, "the note seems to be an empty one");
return null;
}
JSONObject js = new JSONObject(); JSONObject js = new JSONObject();
JSONObject note = new JSONObject(); JSONObject note = new JSONObject();
JSONArray dataArray = new JSONArray(); JSONArray dataArray = new JSONArray();
@ -149,87 +225,127 @@ public class Task extends Node {
js.put(GTaskStringUtils.META_HEAD_NOTE, note); js.put(GTaskStringUtils.META_HEAD_NOTE, note);
return js; return js;
} else { } else {
// 已同步任务(更新元数据) // synced task
JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA); JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
for (int i = 0; i < dataArray.length(); i++) { for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i); JSONObject data = dataArray.getJSONObject(i);
if (data.getString(DataColumns.MIME_TYPE).equals(DataConstants.NOTE)) { if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
data.put(DataColumns.CONTENT, name); data.put(DataColumns.CONTENT, getName());
break; break;
} }
} }
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE); note.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
return mMetaInfo; return mMetaInfo;
} }
} catch (JSONException e) { } catch (JSONException e) {
Log.e(TAG, "生成本地JSON失败", e); Log.e(TAG, e.toString());
e.printStackTrace();
return null; return null;
} }
} }
// 设置元数据本地笔记与GTask的映射
public void setMetaInfo(MetaData metaData) { public void setMetaInfo(MetaData metaData) {
if (metaData != null && metaData.getNotes() != null) { if (metaData != null && metaData.getNotes() != null) {
try { try {
mMetaInfo = new JSONObject(metaData.getNotes()); mMetaInfo = new JSONObject(metaData.getNotes());
} catch (JSONException e) { } catch (JSONException e) {
Log.w(TAG, "解析元数据失败", e); Log.w(TAG, e.toString());
mMetaInfo = null; mMetaInfo = null;
} }
} }
} }
// 判断当前同步动作类型
public int getSyncAction(Cursor c) { public int getSyncAction(Cursor c) {
try { try {
if (mMetaInfo == null || !mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) { JSONObject noteInfo = null;
return SYNC_ACTION_UPDATE_REMOTE; // 元数据不存在,需从远程更新 if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) {
noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
}
if (noteInfo == null) {
Log.w(TAG, "it seems that note meta has been deleted");
return SYNC_ACTION_UPDATE_REMOTE;
}
if (!noteInfo.has(NoteColumns.ID)) {
Log.w(TAG, "remote note id seems to be deleted");
return SYNC_ACTION_UPDATE_LOCAL;
} }
JSONObject noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
// 验证笔记ID // validate the note id now
if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) { if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) {
return SYNC_ACTION_UPDATE_LOCAL; // ID不匹配需更新本地 Log.w(TAG, "note id doesn't match");
return SYNC_ACTION_UPDATE_LOCAL;
} }
// 判断本地修改状态
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
// 本地未修改 // there is no local update
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
return SYNC_ACTION_NONE; // 无变更 // no update both side
return SYNC_ACTION_NONE;
} else { } else {
return SYNC_ACTION_UPDATE_LOCAL; // 远程有更新,需同步到本地 // apply remote to local
return SYNC_ACTION_UPDATE_LOCAL;
} }
} else { } else {
// 本地已修改 // validate gtask id
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) {
return SYNC_ACTION_ERROR; // GTask ID不匹配错误 Log.e(TAG, "gtask id doesn't match");
return SYNC_ACTION_ERROR;
} }
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
return SYNC_ACTION_UPDATE_REMOTE; // 本地修改,需同步到远程 // local modification only
return SYNC_ACTION_UPDATE_REMOTE;
} else { } else {
return SYNC_ACTION_UPDATE_CONFLICT; // 本地与远程都有修改,冲突 return SYNC_ACTION_UPDATE_CONFLICT;
} }
} }
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "获取同步动作失败", e); Log.e(TAG, e.toString());
e.printStackTrace();
} }
return SYNC_ACTION_ERROR; return SYNC_ACTION_ERROR;
} }
// 判断任务是否值得保存
public boolean isWorthSaving() { public boolean isWorthSaving() {
return mMetaInfo != null || return mMetaInfo != null || (getName() != null && getName().trim().length() > 0)
(getName() != null && getName().trim().length() > 0) || || (getNotes() != null && getNotes().trim().length() > 0);
(getNotes() != null && getNotes().trim().length() > 0); }
}
public void setCompleted(boolean completed) {
// Getter和Setter方法 this.mCompleted = completed;
public void setCompleted(boolean completed) { this.mCompleted = completed; } }
public void setNotes(String notes) { this.mNotes = notes; }
public void setPriorSibling(Task priorSibling) { this.mPriorSibling = priorSibling; } public void setNotes(String notes) {
public void setParent(TaskList parent) { this.mParent = parent; } this.mNotes = notes;
public boolean getCompleted() { return mCompleted; } }
public String getNotes() { return mNotes; }
public Task getPriorSibling() { return mPriorSibling; } public void setPriorSibling(Task priorSibling) {
public TaskList getParent() { return mParent; } this.mPriorSibling = priorSibling;
} }
public void setParent(TaskList parent) {
this.mParent = parent;
}
public boolean getCompleted() {
return this.mCompleted;
}
public String getNotes() {
return this.mNotes;
}
public Task getPriorSibling() {
return this.mPriorSibling;
}
public TaskList getParent() {
return this.mParent;
}
}

@ -31,11 +31,11 @@ import java.util.ArrayList;
public class TaskList extends Node { public class TaskList extends Node {
private static final String TAG = TaskList.class.getSimpleName();//tag标记 private static final String TAG = TaskList.class.getSimpleName();
private int mIndex;//当前TaskList的指针 private int mIndex;
private ArrayList<Task> mChildren;//类中主要的保存数据的单元用来实现一个以Task为元素的ArrayList private ArrayList<Task> mChildren;
public TaskList() { public TaskList() {
super(); super();
@ -43,10 +43,6 @@ public class TaskList extends Node {
mIndex = 1; mIndex = 1;
} }
/* (non-Javadoc)
* @see net.micode.notes.gtask.data.Node#getCreateAction(int)
* JSONObject
*/
public JSONObject getCreateAction(int actionId) { public JSONObject getCreateAction(int actionId) {
JSONObject js = new JSONObject(); JSONObject js = new JSONObject();
@ -78,10 +74,6 @@ public class TaskList extends Node {
return js; return js;
} }
/* (non-Javadoc)
* @see net.micode.notes.gtask.data.Node#getUpdateAction(int)
* JSONObject
*/
public JSONObject getUpdateAction(int actionId) { public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject(); JSONObject js = new JSONObject();
@ -228,11 +220,6 @@ public class TaskList extends Node {
return mChildren.size(); return mChildren.size();
} }
/*
* @param task
* @return
*
*/
public boolean addChildTask(Task task) { public boolean addChildTask(Task task) {
boolean ret = false; boolean ret = false;
if (task != null && !mChildren.contains(task)) { if (task != null && !mChildren.contains(task)) {
@ -247,12 +234,6 @@ public class TaskList extends Node {
return ret; return ret;
} }
/*
* @param task
* @param index
* @return
*
*/
public boolean addChildTask(Task task, int index) { public boolean addChildTask(Task task, int index) {
if (index < 0 || index > mChildren.size()) { if (index < 0 || index > mChildren.size()) {
Log.e(TAG, "add child task: invalid index"); Log.e(TAG, "add child task: invalid index");
@ -279,11 +260,6 @@ public class TaskList extends Node {
return true; return true;
} }
/*
* @param task
* @return
* TaskListTask
*/
public boolean removeChildTask(Task task) { public boolean removeChildTask(Task task) {
boolean ret = false; boolean ret = false;
int index = mChildren.indexOf(task); int index = mChildren.indexOf(task);
@ -305,12 +281,6 @@ public class TaskList extends Node {
return ret; return ret;
} }
/*
* @param task
* @param index
* @return
* TaskListTaskindex
*/
public boolean moveChildTask(Task task, int index) { public boolean moveChildTask(Task task, int index) {
if (index < 0 || index >= mChildren.size()) { if (index < 0 || index >= mChildren.size()) {
@ -329,11 +299,6 @@ public class TaskList extends Node {
return (removeChildTask(task) && addChildTask(task, index)); return (removeChildTask(task) && addChildTask(task, index));
} }
/**
* @param gid
* @return
* gidTask
*/
public Task findChildTaskByGid(String gid) { public Task findChildTaskByGid(String gid) {
for (int i = 0; i < mChildren.size(); i++) { for (int i = 0; i < mChildren.size(); i++) {
Task t = mChildren.get(i); Task t = mChildren.get(i);
@ -344,20 +309,10 @@ public class TaskList extends Node {
return null; return null;
} }
/**
* @param task
* @return
* Taskindex
*/
public int getChildTaskIndex(Task task) { public int getChildTaskIndex(Task task) {
return mChildren.indexOf(task); return mChildren.indexOf(task);
} }
/**
* @param index
* @return
* indexTask
*/
public Task getChildTaskByIndex(int index) { public Task getChildTaskByIndex(int index) {
if (index < 0 || index >= mChildren.size()) { if (index < 0 || index >= mChildren.size()) {
Log.e(TAG, "getTaskByIndex: invalid index"); Log.e(TAG, "getTaskByIndex: invalid index");
@ -366,11 +321,6 @@ public class TaskList extends Node {
return mChildren.get(index); return mChildren.get(index);
} }
/**
* @param gid
* @return
* gidTask
*/
public Task getChilTaskByGid(String gid) { public Task getChilTaskByGid(String gid) {
for (Task task : mChildren) { for (Task task : mChildren) {
if (task.getGid().equals(gid)) if (task.getGid().equals(gid))

@ -16,24 +16,13 @@
package net.micode.notes.gtask.exception; package net.micode.notes.gtask.exception;
/*
* Description便
*/
public class ActionFailureException extends RuntimeException { public class ActionFailureException extends RuntimeException {
private static final long serialVersionUID = 4425249765923293627L; private static final long serialVersionUID = 4425249765923293627L;
/*
* serialVersionUIDjava
* serialVersionUID
*/
public ActionFailureException() { public ActionFailureException() {
super(); super();
} }
/*
* JAVA使superthis.
* new
* 使super
* super()super (paramString)Exception ()Exception (paramString)
*/
public ActionFailureException(String paramString) { public ActionFailureException(String paramString) {
super(paramString); super(paramString);
} }

@ -13,27 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* Description便
*/
package net.micode.notes.gtask.exception; package net.micode.notes.gtask.exception;
public class NetworkFailureException extends Exception { public class NetworkFailureException extends Exception {
private static final long serialVersionUID = 2107610287180234136L; private static final long serialVersionUID = 2107610287180234136L;
/*
* serialVersionUIDjava
* serialVersionUID
*/
public NetworkFailureException() { public NetworkFailureException() {
super(); super();
} }
/*
* JAVA使superthis.
* new
* 使super
* super()super (paramString)Exception ()Exception (paramString)
*/
public NetworkFailureException(String paramString) { public NetworkFailureException(String paramString) {
super(paramString); super(paramString);
} }

@ -28,106 +28,114 @@ import net.micode.notes.R;
import net.micode.notes.ui.NotesListActivity; import net.micode.notes.ui.NotesListActivity;
import net.micode.notes.ui.NotesPreferenceActivity; import net.micode.notes.ui.NotesPreferenceActivity;
/*GTask
*
* private void showNotification(int tickerId, String content)
* protected Integer doInBackground(Void... unused) 线
* protected void onProgressUpdate(String... progress) 使 线
* protected void onPostExecute(Integer result) Handler UI使doInBackground UI
*/
public class GTaskASyncTask extends AsyncTask<Void, String, Integer> { public class GTaskASyncTask extends AsyncTask<Void, String, Integer> {
private static int GTASK_SYNC_NOTIFICATION_ID = 5234235; // 通知ID
// 同步完成回调接口 private static int GTASK_SYNC_NOTIFICATION_ID = 5234235;
public interface OnCompleteListener { public interface OnCompleteListener {
void onComplete(); void onComplete();
} }
private Context mContext; // 上下文 private Context mContext;
private NotificationManager mNotifiManager; // 通知管理器
private GTaskManager mTaskManager; // GTask管理类 private NotificationManager mNotifiManager;
private OnCompleteListener mOnCompleteListener; // 完成回调
private GTaskManager mTaskManager;
private OnCompleteListener mOnCompleteListener;
// 构造函数:初始化任务
public GTaskASyncTask(Context context, OnCompleteListener listener) { public GTaskASyncTask(Context context, OnCompleteListener listener) {
mContext = context; mContext = context;
mOnCompleteListener = listener; mOnCompleteListener = listener;
mNotifiManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); mNotifiManager = (NotificationManager) mContext
mTaskManager = GTaskManager.getInstance(); // 获取GTask管理单例 .getSystemService(Context.NOTIFICATION_SERVICE);
mTaskManager = GTaskManager.getInstance();
} }
// 取消同步任务
public void cancelSync() { public void cancelSync() {
mTaskManager.cancelSync(); mTaskManager.cancelSync();
} }
// 发布进度(封装参数格式)
public void publishProgess(String message) { public void publishProgess(String message) {
publishProgress(new String[] { message }); publishProgress(new String[] {
message
});
} }
// 显示同步通知 // private void showNotification(int tickerId, String content) {
private void showNotification(int tickerId, String content) { // Notification notification = new Notification(R.drawable.notification, mContext
PendingIntent pendingIntent; // .getString(tickerId), System.currentTimeMillis());
// 根据通知类型设置点击跳转的页面 // notification.defaults = Notification.DEFAULT_LIGHTS;
if (tickerId != R.string.ticker_success) { // notification.flags = Notification.FLAG_AUTO_CANCEL;
pendingIntent = PendingIntent.getActivity(mContext, 0, // PendingIntent pendingIntent;
new Intent(mContext, NotesPreferenceActivity.class), // if (tickerId != R.string.ticker_success) {
PendingIntent.FLAG_IMMUTABLE); // pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
} else { // NotesPreferenceActivity.class), 0);
pendingIntent = PendingIntent.getActivity(mContext, 0, //
new Intent(mContext, NotesListActivity.class), // } else {
PendingIntent.FLAG_IMMUTABLE); // pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
} // NotesListActivity.class), 0);
// 构建通知 // }
Notification.Builder builder = new Notification.Builder(mContext) // notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
.setAutoCancel(true) // 点击后自动取消 // pendingIntent);
.setContentTitle(mContext.getString(R.string.app_name)) // mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);
.setContentText(content) // }
.setContentIntent(pendingIntent) // 点击通知后的跳转意图 private void showNotification(int tickerId, String content) {
.setWhen(System.currentTimeMillis()) PendingIntent pendingIntent;
.setOngoing(true); // 显示为进行中状态 if (tickerId != R.string.ticker_success) {
mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, builder.getNotification()); pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesPreferenceActivity.class), PendingIntent.FLAG_IMMUTABLE);
} else {
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesListActivity.class), PendingIntent.FLAG_IMMUTABLE);
} }
Notification.Builder builder = new Notification.Builder(mContext)
// 后台执行同步任务(异步任务核心方法) .setAutoCancel(true)
.setContentTitle(mContext.getString(R.string.app_name))
.setContentText(content)
.setContentIntent(pendingIntent)
.setWhen(System.currentTimeMillis())
.setOngoing(true);
Notification notification=builder.getNotification();
mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);
}
@Override @Override
protected Integer doInBackground(Void... unused) { protected Integer doInBackground(Void... unused) {
// 发布登录进度通知 publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity
publishProgess(mContext.getString(R.string.sync_progress_login, .getSyncAccountName(mContext)));
NotesPreferenceActivity.getSyncAccountName(mContext)));
// 调用GTaskManager执行同步返回状态码
return mTaskManager.sync(mContext, this); return mTaskManager.sync(mContext, this);
} }
// 更新进度UI线程执行
@Override @Override
protected void onProgressUpdate(String... progress) { protected void onProgressUpdate(String... progress) {
showNotification(R.string.ticker_syncing, progress[0]); // 显示同步中通知 showNotification(R.string.ticker_syncing, progress[0]);
// 向服务发送广播如果上下文是GTaskSyncService
if (mContext instanceof GTaskSyncService) { if (mContext instanceof GTaskSyncService) {
((GTaskSyncService) mContext).sendBroadcast(progress[0]); ((GTaskSyncService) mContext).sendBroadcast(progress[0]);
} }
} }
// 任务完成后执行UI线程执行
@Override @Override
protected void onPostExecute(Integer result) { protected void onPostExecute(Integer result) {
// 根据同步结果显示不同通知
if (result == GTaskManager.STATE_SUCCESS) { if (result == GTaskManager.STATE_SUCCESS) {
showNotification(R.string.ticker_success, showNotification(R.string.ticker_success, mContext.getString(
mContext.getString(R.string.success_sync_account, mTaskManager.getSyncAccount())); R.string.success_sync_account, mTaskManager.getSyncAccount()));
NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis()); // 记录最后同步时间 NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis());
} else if (result == GTaskManager.STATE_NETWORK_ERROR) { } else if (result == GTaskManager.STATE_NETWORK_ERROR) {
showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_network)); showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_network));
} else if (result == GTaskManager.STATE_INTERNAL_ERROR) { } else if (result == GTaskManager.STATE_INTERNAL_ERROR) {
showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal)); showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal));
} else if (result == GTaskManager.STATE_SYNC_CANCELLED) { } else if (result == GTaskManager.STATE_SYNC_CANCELLED) {
showNotification(R.string.ticker_cancel, mContext.getString(R.string.error_sync_cancelled)); showNotification(R.string.ticker_cancel, mContext
.getString(R.string.error_sync_cancelled));
} }
// 异步执行回调避免阻塞UI线程
if (mOnCompleteListener != null) { if (mOnCompleteListener != null) {
new Thread(() -> mOnCompleteListener.onComplete()).start(); new Thread(new Runnable() {
public void run() {
mOnCompleteListener.onComplete();
}
}).start();
} }
} }
} }

@ -24,6 +24,8 @@ import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
//import com.google.firebase.crashlytics.buildtools.reloc.org.apache.http.HttpEntity;
import net.micode.notes.gtask.data.Node; import net.micode.notes.gtask.data.Node;
import net.micode.notes.gtask.data.Task; import net.micode.notes.gtask.data.Task;
import net.micode.notes.gtask.data.TaskList; import net.micode.notes.gtask.data.TaskList;
@ -31,7 +33,6 @@ import net.micode.notes.gtask.exception.ActionFailureException;
import net.micode.notes.gtask.exception.NetworkFailureException; import net.micode.notes.gtask.exception.NetworkFailureException;
import net.micode.notes.tool.GTaskStringUtils; import net.micode.notes.tool.GTaskStringUtils;
import net.micode.notes.ui.NotesPreferenceActivity; import net.micode.notes.ui.NotesPreferenceActivity;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ClientProtocolException;
@ -60,10 +61,7 @@ import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater; import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream; import java.util.zip.InflaterInputStream;
/*
* GTASKGTASK
* 使accountManager JSONObject HttpParams authToken Gid
*/
public class GTaskClient { public class GTaskClient {
private static final String TAG = GTaskClient.class.getSimpleName(); private static final String TAG = GTaskClient.class.getSimpleName();
@ -93,7 +91,6 @@ public class GTaskClient {
private JSONArray mUpdateArray; private JSONArray mUpdateArray;
private GTaskClient() { private GTaskClient() {
mHttpClient = null; mHttpClient = null;
mGetUrl = GTASK_GET_URL; mGetUrl = GTASK_GET_URL;
@ -106,10 +103,6 @@ public class GTaskClient {
mUpdateArray = null; mUpdateArray = null;
} }
/*
* 使 getInstance()
* mInstance
*/
public static synchronized GTaskClient getInstance() { public static synchronized GTaskClient getInstance() {
if (mInstance == null) { if (mInstance == null) {
mInstance = new GTaskClient(); mInstance = new GTaskClient();
@ -117,54 +110,42 @@ public class GTaskClient {
return mInstance; return mInstance;
} }
/*Activity
*
* 使URL使URL
* truefalse
*/
public boolean login(Activity activity) { public boolean login(Activity activity) {
// we suppose that the cookie would expire after 5 minutes // we suppose that the cookie would expire after 5 minutes
// then we need to re-login // then we need to re-login
//判断距离最后一次登录操作是否超过5分钟
final long interval = 1000 * 60 * 5; final long interval = 1000 * 60 * 5;
if (mLastLoginTime + interval < System.currentTimeMillis()) { if (mLastLoginTime + interval < System.currentTimeMillis()) {
mLoggedin = false; mLoggedin = false;
} }
// need to re-login after account switch 重新登录操作 // need to re-login after account switch
if (mLoggedin if (mLoggedin
&& !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity && !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity
.getSyncAccountName(activity))) { .getSyncAccountName(activity))) {
mLoggedin = false; mLoggedin = false;
} }
//如果没超过时间,则不需要重新登录
if (mLoggedin) { if (mLoggedin) {
Log.d(TAG, "already logged in"); Log.d(TAG, "already logged in");
return true; return true;
} }
//更新最后登录时间,改为系统当前的时间
mLastLoginTime = System.currentTimeMillis(); mLastLoginTime = System.currentTimeMillis();
String authToken = loginGoogleAccount(activity, false); String authToken = loginGoogleAccount(activity, false);
//判断是否登录到谷歌账户
if (authToken == null) { if (authToken == null) {
Log.e(TAG, "login google account failed"); Log.e(TAG, "login google account failed");
return false; return false;
} }
// login with custom domain if necessary // login with custom domain if necessary
if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase() if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase()
//将用户账号名改为统一格式(小写)后判断是否为一个谷歌账号地址
.endsWith("googlemail.com"))) { .endsWith("googlemail.com"))) {
StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); StringBuilder url = new StringBuilder(GTASK_URL).append("a/");
int index = mAccount.name.indexOf('@') + 1; int index = mAccount.name.indexOf('@') + 1;
String suffix = mAccount.name.substring(index); String suffix = mAccount.name.substring(index);
url.append(suffix + "/"); url.append(suffix + "/");
mGetUrl = url.toString() + "ig"; //设置用户对应的getUrl mGetUrl = url.toString() + "ig";
mPostUrl = url.toString() + "r/ig";//设置用户对应的postUrl mPostUrl = url.toString() + "r/ig";
if (tryToLoginGtask(activity, authToken)) { if (tryToLoginGtask(activity, authToken)) {
mLoggedin = true; mLoggedin = true;
@ -172,7 +153,6 @@ public class GTaskClient {
} }
// try to login with google official url // try to login with google official url
//如果用户账户无法登录则使用谷歌官方的URI进行登录
if (!mLoggedin) { if (!mLoggedin) {
mGetUrl = GTASK_GET_URL; mGetUrl = GTASK_GET_URL;
mPostUrl = GTASK_POST_URL; mPostUrl = GTASK_POST_URL;
@ -185,17 +165,9 @@ public class GTaskClient {
return true; return true;
} }
/* private String loginGoogleAccount(Activity activity, boolean invalidateToken) {
* 使
* 使AccountManager
*
*/
private String loginGoogleAccount(Activity activity, boolean invalidateToken) {//令牌,是登录操作保证安全性的一个方法
String authToken; String authToken;
//AccountManager这个类给用户提供了集中注册账号的接口
AccountManager accountManager = AccountManager.get(activity); AccountManager accountManager = AccountManager.get(activity);
//获取全部以com.google结尾的account
Account[] accounts = accountManager.getAccountsByType("com.google"); Account[] accounts = accountManager.getAccountsByType("com.google");
if (accounts.length == 0) { if (accounts.length == 0) {
@ -205,7 +177,6 @@ public class GTaskClient {
String accountName = NotesPreferenceActivity.getSyncAccountName(activity); String accountName = NotesPreferenceActivity.getSyncAccountName(activity);
Account account = null; Account account = null;
//遍历获得的accounts信息寻找已经记录过的账户信息
for (Account a : accounts) { for (Account a : accounts) {
if (a.name.equals(accountName)) { if (a.name.equals(accountName)) {
account = a; account = a;
@ -220,13 +191,11 @@ public class GTaskClient {
} }
// get the token now // get the token now
//获取选中账号的令牌
AccountManagerFuture<Bundle> accountManagerFuture = accountManager.getAuthToken(account, AccountManagerFuture<Bundle> accountManagerFuture = accountManager.getAuthToken(account,
"goanna_mobile", null, activity, null, null); "goanna_mobile", null, activity, null, null);
try { try {
Bundle authTokenBundle = accountManagerFuture.getResult(); Bundle authTokenBundle = accountManagerFuture.getResult();
authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);
//如果是invalidateToken那么需要调用invalidateAuthToken(String, String)方法废除这个无效token
if (invalidateToken) { if (invalidateToken) {
accountManager.invalidateAuthToken("com.google", authToken); accountManager.invalidateAuthToken("com.google", authToken);
loginGoogleAccount(activity, false); loginGoogleAccount(activity, false);
@ -239,13 +208,10 @@ public class GTaskClient {
return authToken; return authToken;
} }
//尝试登陆Gtask这只是一个预先判断令牌是否是有效以及是否能登上GTask的方法,而不是具体实现登陆的方法
private boolean tryToLoginGtask(Activity activity, String authToken) { private boolean tryToLoginGtask(Activity activity, String authToken) {
if (!loginGtask(authToken)) { if (!loginGtask(authToken)) {
// maybe the auth token is out of date, now let's invalidate the // maybe the auth token is out of date, now let's invalidate the
// token and try again // token and try again
//删除过一个无效的authToken申请一个新的后再次尝试登陆
authToken = loginGoogleAccount(activity, true); authToken = loginGoogleAccount(activity, true);
if (authToken == null) { if (authToken == null) {
Log.e(TAG, "login google account failed"); Log.e(TAG, "login google account failed");
@ -260,34 +226,25 @@ public class GTaskClient {
return true; return true;
} }
//实现登录GTask的具体操作
private boolean loginGtask(String authToken) { private boolean loginGtask(String authToken) {
int timeoutConnection = 10000; int timeoutConnection = 10000;
int timeoutSocket = 15000; int timeoutSocket = 15000;
//socket是一种通信连接实现数据的交换的端口
HttpParams httpParameters = new BasicHttpParams(); HttpParams httpParameters = new BasicHttpParams();
//实例化一个新的HTTP参数类
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
//设置连接超时时间
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
//设置设置端口超时时间
mHttpClient = new DefaultHttpClient(httpParameters); mHttpClient = new DefaultHttpClient(httpParameters);
BasicCookieStore localBasicCookieStore = new BasicCookieStore(); BasicCookieStore localBasicCookieStore = new BasicCookieStore();
//设置本地cookie
mHttpClient.setCookieStore(localBasicCookieStore); mHttpClient.setCookieStore(localBasicCookieStore);
HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false);
// login gtask // login gtask
try { try {
String loginUrl = mGetUrl + "?auth=" + authToken; String loginUrl = mGetUrl + "?auth=" + authToken;
//设置登录的url
HttpGet httpGet = new HttpGet(loginUrl); HttpGet httpGet = new HttpGet(loginUrl);
//通过登录的uri实例化网页上资源的查找
HttpResponse response = null; HttpResponse response = null;
response = mHttpClient.execute(httpGet); response = mHttpClient.execute(httpGet);
// get the cookie now // get the cookie now
//获取CookieStore里存放的cookie,看如果存有“GTL(不知道什么意思)”则说明有验证成功的有效的cookie
List<Cookie> cookies = mHttpClient.getCookieStore().getCookies(); List<Cookie> cookies = mHttpClient.getCookieStore().getCookies();
boolean hasAuthCookie = false; boolean hasAuthCookie = false;
for (Cookie cookie : cookies) { for (Cookie cookie : cookies) {
@ -300,7 +257,6 @@ public class GTaskClient {
} }
// get the client version // get the client version
//获取client的内容具体操作是在返回的Content中截取从_setup(开始到)}</script>中间的字符串内容也就是gtask_url的内容
String resString = getResponseContent(response.getEntity()); String resString = getResponseContent(response.getEntity());
String jsBegin = "_setup("; String jsBegin = "_setup(";
String jsEnd = ")}</script>"; String jsEnd = ")}</script>";
@ -329,10 +285,6 @@ public class GTaskClient {
return mActionId++; return mActionId++;
} }
/*
* 使HttpPost
* httpPost
*/
private HttpPost createHttpPost() { private HttpPost createHttpPost() {
HttpPost httpPost = new HttpPost(mPostUrl); HttpPost httpPost = new HttpPost(mPostUrl);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
@ -340,23 +292,17 @@ public class GTaskClient {
return httpPost; return httpPost;
} }
/*URL
* 使getContentEncoding()
*
*/
private String getResponseContent(HttpEntity entity) throws IOException { private String getResponseContent(HttpEntity entity) throws IOException {
String contentEncoding = null; String contentEncoding = null;
if (entity.getContentEncoding() != null) { if (entity.getContentEncoding() != null) {
//通过URL得到HttpEntity对象如果不为空则使用getContent方法创建一个流将数据从网络都过来
contentEncoding = entity.getContentEncoding().getValue(); contentEncoding = entity.getContentEncoding().getValue();
Log.d(TAG, "encoding: " + contentEncoding); Log.d(TAG, "encoding: " + contentEncoding);
} }
InputStream input = entity.getContent(); InputStream input = entity.getContent();
if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) { if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {
//GZIP是使用DEFLATE进行压缩数据的另一个压缩库
input = new GZIPInputStream(entity.getContent()); input = new GZIPInputStream(entity.getContent());
} else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {//DEFLATE是一个无专利的压缩算法它可以实现无损数据压缩 } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {
Inflater inflater = new Inflater(true); Inflater inflater = new Inflater(true);
input = new InflaterInputStream(entity.getContent(), inflater); input = new InflaterInputStream(entity.getContent(), inflater);
} }
@ -364,7 +310,6 @@ public class GTaskClient {
try { try {
InputStreamReader isr = new InputStreamReader(input); InputStreamReader isr = new InputStreamReader(input);
BufferedReader br = new BufferedReader(isr); BufferedReader br = new BufferedReader(isr);
//是一个包装类,它可以包装字符流,将字符流放入缓存里,先把字符读到缓存里,到缓存满了时候,再读入内存,是为了提供读的效率而设计的
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
while (true) { while (true) {
@ -379,19 +324,12 @@ public class GTaskClient {
} }
} }
/*JSON
* jsonjs
* UrlEncodedFormEntity entityhttpPost.setEntity(entity)jshttpPost
* 使getResponseContent
* json
*/
private JSONObject postRequest(JSONObject js) throws NetworkFailureException { private JSONObject postRequest(JSONObject js) throws NetworkFailureException {
if (!mLoggedin) { if (!mLoggedin) {
Log.e(TAG, "please login first"); Log.e(TAG, "please login first");
throw new ActionFailureException("not logged in"); throw new ActionFailureException("not logged in");
} }
//实例化一个httpPost的对象用来向服务器传输数据在这里就是发送请求而请求的内容在js里
HttpPost httpPost = createHttpPost(); HttpPost httpPost = createHttpPost();
try { try {
LinkedList<BasicNameValuePair> list = new LinkedList<BasicNameValuePair>(); LinkedList<BasicNameValuePair> list = new LinkedList<BasicNameValuePair>();
@ -423,13 +361,6 @@ public class GTaskClient {
} }
} }
/*
* .gtask.data.TaskTask
* jsonTask,jsPost
* postRequest
* 使task.setGidtasknew_ID
*/
public void createTask(Task task) throws NetworkFailureException { public void createTask(Task task) throws NetworkFailureException {
commitUpdate(); commitUpdate();
try { try {
@ -456,9 +387,6 @@ public class GTaskClient {
} }
} }
/*
* createTasktasklistgid
*/
public void createTaskList(TaskList tasklist) throws NetworkFailureException { public void createTaskList(TaskList tasklist) throws NetworkFailureException {
commitUpdate(); commitUpdate();
try { try {
@ -485,11 +413,6 @@ public class GTaskClient {
} }
} }
/*
*
* 使JSONObject使jsPost.putPutUpdateArrayClientVersion
* 使postRequestjspost,
*/
public void commitUpdate() throws NetworkFailureException { public void commitUpdate() throws NetworkFailureException {
if (mUpdateArray != null) { if (mUpdateArray != null) {
try { try {
@ -511,10 +434,6 @@ public class GTaskClient {
} }
} }
/*
*
* commitUpdate()
*/
public void addUpdateNode(Node node) throws NetworkFailureException { public void addUpdateNode(Node node) throws NetworkFailureException {
if (node != null) { if (node != null) {
// too many update items may result in an error // too many update items may result in an error
@ -529,12 +448,6 @@ public class GTaskClient {
} }
} }
/*
* task,tasktask
* getGidtaskgid
* JSONObject.put(String name, Object value)task
* postRequest
*/
public void moveTask(Task task, TaskList preParent, TaskList curParent) public void moveTask(Task task, TaskList preParent, TaskList curParent)
throws NetworkFailureException { throws NetworkFailureException {
commitUpdate(); commitUpdate();
@ -550,8 +463,6 @@ public class GTaskClient {
action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid()); action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid());
if (preParent == curParent && task.getPriorSibling() != null) { if (preParent == curParent && task.getPriorSibling() != null) {
// put prioring_sibing_id only if moving within the tasklist and // put prioring_sibing_id only if moving within the tasklist and
//设置优先级ID只有当移动是发生在文件中
// it is not the first one // it is not the first one
action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling()); action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling());
} }
@ -562,7 +473,6 @@ public class GTaskClient {
action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid());
} }
actionList.put(action); actionList.put(action);
//最后将ACTION_LIST加入到jsPost中
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client_version // client_version
@ -577,11 +487,6 @@ public class GTaskClient {
} }
} }
/*
*
* JSON
* 使postRequest
*/
public void deleteNode(Node node) throws NetworkFailureException { public void deleteNode(Node node) throws NetworkFailureException {
commitUpdate(); commitUpdate();
try { try {
@ -605,11 +510,6 @@ public class GTaskClient {
} }
} }
/*
*
* GetURI使getResponseContent
* "_setup(")}</script>GTASK_JSON_LISTS
*/
public JSONArray getTaskLists() throws NetworkFailureException { public JSONArray getTaskLists() throws NetworkFailureException {
if (!mLoggedin) { if (!mLoggedin) {
Log.e(TAG, "please login first"); Log.e(TAG, "please login first");
@ -622,7 +522,6 @@ public class GTaskClient {
response = mHttpClient.execute(httpGet); response = mHttpClient.execute(httpGet);
// get the task list // get the task list
//筛选工作把筛选出的字符串放入jsString
String resString = getResponseContent(response.getEntity()); String resString = getResponseContent(response.getEntity());
String jsBegin = "_setup("; String jsBegin = "_setup(";
String jsEnd = ")}</script>"; String jsEnd = ")}</script>";
@ -649,9 +548,6 @@ public class GTaskClient {
} }
} }
/*
* TASKListgid,
*/
public JSONArray getTaskList(String listGid) throws NetworkFailureException { public JSONArray getTaskList(String listGid) throws NetworkFailureException {
commitUpdate(); commitUpdate();
try { try {
@ -684,8 +580,6 @@ public class GTaskClient {
return mAccount; return mAccount;
} }
//重置更新的内容
public void resetUpdateArray() { public void resetUpdateArray() {
mUpdateArray = null; mUpdateArray = null;
} }

@ -87,13 +87,10 @@ public class GTaskManager {
private HashMap<Long, String> mNidToGid; private HashMap<Long, String> mNidToGid;
private GTaskManager() {//对象初始化函数 private GTaskManager() {
mSyncing = false; mSyncing = false;
//正在同步,flase代表未执行
mCancelled = false; mCancelled = false;
//全局标识flase代表可以执行
mGTaskListHashMap = new HashMap<String, TaskList>(); mGTaskListHashMap = new HashMap<String, TaskList>();
//<>代表Java的泛型,就是创建一个用类型作为参数的类。
mGTaskHashMap = new HashMap<String, Node>(); mGTaskHashMap = new HashMap<String, Node>();
mMetaHashMap = new HashMap<String, MetaData>(); mMetaHashMap = new HashMap<String, MetaData>();
mMetaList = null; mMetaList = null;
@ -101,42 +98,22 @@ public class GTaskManager {
mGidToNid = new HashMap<String, Long>(); mGidToNid = new HashMap<String, Long>();
mNidToGid = new HashMap<Long, String>(); mNidToGid = new HashMap<Long, String>();
} }
/*
* synchronized线 public static synchronized GTaskManager getInstance() {
*
* @author TTS
* @return GtaskManger
*/
public static synchronized GTaskManager getInstance() { //可能运行在多线程环境下,使用语言级同步--synchronized
if (mInstance == null) { if (mInstance == null) {
mInstance = new GTaskManager(); mInstance = new GTaskManager();
} }
return mInstance; return mInstance;
} }
/*
* synchronized线
* @author TTS
* @param activity
*/
public synchronized void setActivityContext(Activity activity) { public synchronized void setActivityContext(Activity activity) {
// used for getting authtoken // used for getting authtoken
mActivity = activity; mActivity = activity;
} }
/*
*
*
* @author TTS
* @param context-----
* @param asyncTask-------
* @return int
*/
public int sync(Context context, GTaskASyncTask asyncTask) { public int sync(Context context, GTaskASyncTask asyncTask) {
if (mSyncing) { if (mSyncing) {
Log.d(TAG, "Sync is in progress"); Log.d(TAG, "Sync is in progress");
//创建日志文件调试信息debug
return STATE_SYNC_IN_PROGRESS; return STATE_SYNC_IN_PROGRESS;
} }
mContext = context; mContext = context;
@ -153,7 +130,6 @@ public class GTaskManager {
try { try {
GTaskClient client = GTaskClient.getInstance(); GTaskClient client = GTaskClient.getInstance();
client.resetUpdateArray(); client.resetUpdateArray();
//JSONArray类型reset即置为NULL
// login google task // login google task
if (!mCancelled) { if (!mCancelled) {
@ -165,18 +141,14 @@ public class GTaskManager {
// get the task list from google // get the task list from google
asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list)); asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list));
initGTaskList(); initGTaskList();
//获取Google上的JSONtasklist转为本地TaskList
// do content sync work // do content sync work
asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing)); asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing));
syncContent(); syncContent();
} catch (NetworkFailureException e) { } catch (NetworkFailureException e) {
//分为两种异常,此类异常为网络异常
Log.e(TAG, e.toString()); Log.e(TAG, e.toString());
//创建日志文件调试信息error
return STATE_NETWORK_ERROR; return STATE_NETWORK_ERROR;
} catch (ActionFailureException e) { } catch (ActionFailureException e) {
//此类异常为操作异常
Log.e(TAG, e.toString()); Log.e(TAG, e.toString());
return STATE_INTERNAL_ERROR; return STATE_INTERNAL_ERROR;
} catch (Exception e) { } catch (Exception e) {
@ -196,22 +168,11 @@ public class GTaskManager {
return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS;
} }
/*
*GtaskListGoogleJSONtasklistTaskList
*mMetaListmGTaskListHashMapmGTaskHashMap
*@author TTS
*@exception NetworkFailureException
*@return void
*/
private void initGTaskList() throws NetworkFailureException { private void initGTaskList() throws NetworkFailureException {
if (mCancelled) if (mCancelled)
return; return;
GTaskClient client = GTaskClient.getInstance(); GTaskClient client = GTaskClient.getInstance();
try {//Json对象是Name Value对(即子元素)的无序集合相当于一个Map对象。JsonObject类是bantouyan-json库对Json对象的抽象提供操纵Json对象的各种方法。 try {
//其格式为{"key1":value1,"key2",value2....};key 必须是字符串。
//因为ajax请求不刷新页面但配合js可以实现局部刷新因此json常常被用来作为异步请求的返回对象使用。
JSONArray jsTaskLists = client.getTaskLists(); JSONArray jsTaskLists = client.getTaskLists();
// init meta list first // init meta list first
@ -224,7 +185,7 @@ public class GTaskManager {
if (name if (name
.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { .equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) {
mMetaList = new TaskList(); mMetaList = new TaskList();
mMetaList.setContentByRemoteJSON(object);//将JSON中部分数据复制到自己定义的对象中相对应的数据name->mname... mMetaList.setContentByRemoteJSON(object);
// load meta data // load meta data
JSONArray jsMetas = client.getTaskList(gid); JSONArray jsMetas = client.getTaskList(gid);
@ -286,17 +247,9 @@ public class GTaskManager {
} }
} }
/*
*
* @throws NetworkFailureException
* @return
*/
private void syncContent() throws NetworkFailureException { private void syncContent() throws NetworkFailureException {
//本地内容同步操作
int syncType; int syncType;
Cursor c = null; Cursor c = null;
//数据库指针
String gid; String gid;
Node node; Node node;
@ -523,14 +476,6 @@ public class GTaskManager {
GTaskClient.getInstance().commitUpdate(); GTaskClient.getInstance().commitUpdate();
} }
/*
* syncTypeaddLocalNodeaddRemoteNodedeleteNodeupdateLocalNodeupdateRemoteNode
* @author TTS
* @param syncType
* @param node
* @param c
* @throws NetworkFailureException
*/
private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException { private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) { if (mCancelled) {
return; return;
@ -577,12 +522,6 @@ public class GTaskManager {
} }
} }
/*
* Node
* @author TTS
* @param node
* @throws NetworkFailureException
*/
private void addLocalNode(Node node) throws NetworkFailureException { private void addLocalNode(Node node) throws NetworkFailureException {
if (mCancelled) { if (mCancelled) {
return; return;
@ -657,16 +596,6 @@ public class GTaskManager {
updateRemoteMeta(node.getGid(), sqlNote); updateRemoteMeta(node.getGid(), sqlNote);
} }
/*
* updatenode
* @author TTS
* @param node
* ----
* @param c
* ----Cursor
* @throws NetworkFailureException
*/
private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException { private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) { if (mCancelled) {
return; return;
@ -690,17 +619,6 @@ public class GTaskManager {
updateRemoteMeta(node.getGid(), sqlNote); updateRemoteMeta(node.getGid(), sqlNote);
} }
/*
* Node
* updateRemoteMeta
* @author TTS
* @param node
* ----
* @param c
* --Cursor
* @throws NetworkFailureException
*/
private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) { if (mCancelled) {
return; return;
@ -720,7 +638,7 @@ public class GTaskManager {
throw new ActionFailureException("cannot add remote task"); throw new ActionFailureException("cannot add remote task");
} }
mGTaskListHashMap.get(parentGid).addChildTask(task); mGTaskListHashMap.get(parentGid).addChildTask(task);
//登录远程服务器创建Task
GTaskClient.getInstance().createTask(task); GTaskClient.getInstance().createTask(task);
n = (Node) task; n = (Node) task;
@ -738,7 +656,6 @@ public class GTaskManager {
else else
folderName += sqlNote.getSnippet(); folderName += sqlNote.getSnippet();
//iterator迭代器通过统一的接口迭代所有的map元素
Iterator<Map.Entry<String, TaskList>> iter = mGTaskListHashMap.entrySet().iterator(); Iterator<Map.Entry<String, TaskList>> iter = mGTaskListHashMap.entrySet().iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
Map.Entry<String, TaskList> entry = iter.next(); Map.Entry<String, TaskList> entry = iter.next();
@ -775,16 +692,6 @@ public class GTaskManager {
mNidToGid.put(sqlNote.getId(), n.getGid()); mNidToGid.put(sqlNote.getId(), n.getGid());
} }
/*
* Nodemeta(updateRemoteMeta)
* @author TTS
* @param node
* ----
* @param c
* --Cursor
* @throws NetworkFailureException
*/
private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException { private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) { if (mCancelled) {
return; return;
@ -803,14 +710,12 @@ public class GTaskManager {
if (sqlNote.isNoteType()) { if (sqlNote.isNoteType()) {
Task task = (Task) node; Task task = (Task) node;
TaskList preParentList = task.getParent(); TaskList preParentList = task.getParent();
//preParentList为通过node获取的父节点列表
String curParentGid = mNidToGid.get(sqlNote.getParentId()); String curParentGid = mNidToGid.get(sqlNote.getParentId());
if (curParentGid == null) { if (curParentGid == null) {
Log.e(TAG, "cannot find task's parent tasklist"); Log.e(TAG, "cannot find task's parent tasklist");
throw new ActionFailureException("cannot update remote task"); throw new ActionFailureException("cannot update remote task");
} }
//通过HashMap找到对应Gid的TaskList
TaskList curParentList = mGTaskListHashMap.get(curParentGid); TaskList curParentList = mGTaskListHashMap.get(curParentGid);
if (preParentList != curParentList) { if (preParentList != curParentList) {
@ -822,18 +727,9 @@ public class GTaskManager {
// clear local modified flag // clear local modified flag
sqlNote.resetLocalModified(); sqlNote.resetLocalModified();
sqlNote.commit(true); //commit到本地数据库 sqlNote.commit(true);
} }
/**
* meta meta----------
* @author TTS
* @param gid
* ---GoogleIDString
* @param sqlNote
* ---使SqlNote
* @throws NetworkFailureException
*/
private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException { private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException {
if (sqlNote != null && sqlNote.isNoteType()) { if (sqlNote != null && sqlNote.isNoteType()) {
MetaData metaData = mMetaHashMap.get(gid); MetaData metaData = mMetaHashMap.get(gid);
@ -850,12 +746,6 @@ public class GTaskManager {
} }
} }
/**
* syncID
* @author TTS
* @return void
* @throws NetworkFailureException
*/
private void refreshLocalSyncId() throws NetworkFailureException { private void refreshLocalSyncId() throws NetworkFailureException {
if (mCancelled) { if (mCancelled) {
return; return;
@ -900,19 +790,10 @@ public class GTaskManager {
} }
} }
/**
* ,mAccount.name
* @author TTS
* @return String
*/
public String getSyncAccount() { public String getSyncAccount() {
return GTaskClient.getInstance().getSyncAccount().name; return GTaskClient.getInstance().getSyncAccount().name;
} }
/**
* mCancelledtrue
* @author TTS
*/
public void cancelSync() { public void cancelSync() {
mCancelled = true; mCancelled = true;
} }

@ -15,22 +15,6 @@
*/ */
package net.micode.notes.gtask.remote; package net.micode.notes.gtask.remote;
/*
* Service
*
* private void startSync()
* private void cancelSync()
* public void onCreate()
* public int onStartCommand(Intent intent, int flags, int startId) serviceserviceservice
* public void onLowMemory() serviceservice
* public IBinder onBind()
* public void sendBroadcast(String msg)
* public static void startSync(Activity activity)
* public static void cancelSync(Context context)
* public static boolean isSyncing()
* public static String getProgressString()
*/
import android.app.Activity; import android.app.Activity;
import android.app.Service; import android.app.Service;
@ -58,7 +42,7 @@ public class GTaskSyncService extends Service {
private static String mSyncProgress = ""; private static String mSyncProgress = "";
private void startSync() {//开始一个同步的工作 private void startSync() {
if (mSyncTask == null) { if (mSyncTask == null) {
mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() { mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() {
public void onComplete() { public void onComplete() {
@ -68,7 +52,7 @@ public class GTaskSyncService extends Service {
} }
}); });
sendBroadcast(""); sendBroadcast("");
mSyncTask.execute();//这个函数让任务是以单线程队列方式或线程池队列方式运行 mSyncTask.execute();
} }
} }
@ -78,7 +62,6 @@ public class GTaskSyncService extends Service {
} }
} }
//初始化一个service
@Override @Override
public void onCreate() { public void onCreate() {
mSyncTask = null; mSyncTask = null;
@ -89,7 +72,6 @@ public class GTaskSyncService extends Service {
Bundle bundle = intent.getExtras(); Bundle bundle = intent.getExtras();
if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) { if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) {
switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) { switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) {
//两种情况,开始同步或者取消同步
case ACTION_START_SYNC: case ACTION_START_SYNC:
startSync(); startSync();
break; break;
@ -99,7 +81,7 @@ public class GTaskSyncService extends Service {
default: default:
break; break;
} }
return START_STICKY;//等待新的intent来是这个service继续运行 return START_STICKY;
} }
return super.onStartCommand(intent, flags, startId); return super.onStartCommand(intent, flags, startId);
} }
@ -117,20 +99,20 @@ public class GTaskSyncService extends Service {
public void sendBroadcast(String msg) { public void sendBroadcast(String msg) {
mSyncProgress = msg; mSyncProgress = msg;
Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME);//创建一个新的Intent Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME);
intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null);//附加INTENT中的相应参数的值 intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null);
intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg); intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg);
sendBroadcast(intent); //发送这个通知 sendBroadcast(intent);
} }
public static void startSync(Activity activity) {//执行一个serviceservice的内容里的同步动作就是开始同步 public static void startSync(Activity activity) {
GTaskManager.getInstance().setActivityContext(activity); GTaskManager.getInstance().setActivityContext(activity);
Intent intent = new Intent(activity, GTaskSyncService.class); Intent intent = new Intent(activity, GTaskSyncService.class);
intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC); intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC);
activity.startService(intent); activity.startService(intent);
} }
public static void cancelSync(Context context) {//执行一个serviceservice的内容里的同步动作就是取消同步 public static void cancelSync(Context context) {
Intent intent = new Intent(context, GTaskSyncService.class); Intent intent = new Intent(context, GTaskSyncService.class);
intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC); intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC);
context.startService(intent); context.startService(intent);

@ -49,10 +49,8 @@ public class Note {
values.put(NoteColumns.MODIFIED_DATE, createdTime); values.put(NoteColumns.MODIFIED_DATE, createdTime);
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 = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values); Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
//ContentResolver()主要是实现外部应用对ContentProvider中的数据
//进行添加、删除、修改和查询操作
long noteId = 0; long noteId = 0;
try { try {
@ -67,38 +65,38 @@ public class Note {
return noteId; return noteId;
} }
public Note() {//定义两个变量用来存储便签的数据,一个是存储便签属性、一个是存储便签内容 public Note() {
mNoteDiffValues = new ContentValues(); mNoteDiffValues = new ContentValues();
mNoteData = new NoteData(); mNoteData = new NoteData();
} }
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());
} }
public void setTextData(String key, String value) {//设置数据库表格的标签文本内容的数据 public void setTextData(String key, String value) {
mNoteData.setTextData(key, value); mNoteData.setTextData(key, value);
} }
public void setTextDataId(long id) {//设置文本数据的ID public void setTextDataId(long id) {
mNoteData.setTextDataId(id); mNoteData.setTextDataId(id);
} }
public long getTextDataId() {//得到文本数据的ID public long getTextDataId() {
return mNoteData.mTextDataId; return mNoteData.mTextDataId;
} }
public void setCallDataId(long id) {//设置电话号码数据的ID public void setCallDataId(long id) {
mNoteData.setCallDataId(id); mNoteData.setCallDataId(id);
} }
public void setCallData(String key, String value) {//得到电话号码数据的ID public void setCallData(String key, String value) {
mNoteData.setCallData(key, value); mNoteData.setCallData(key, value);
} }
public boolean isLocalModified() {//判断是否本地修改 public boolean isLocalModified() {
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified(); return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
} }
@ -132,7 +130,6 @@ public class Note {
return true; return true;
} }
//定义一个基本的便签内容的数据类,主要包含文本数据和电话号码数据
private class NoteData { private class NoteData {
private long mTextDataId; private long mTextDataId;
@ -180,7 +177,7 @@ public class Note {
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的操作存储到数据库
Uri pushIntoContentResolver(Context context, long noteId) { Uri pushIntoContentResolver(Context context, long noteId) {
/** /**
* Check for safety * Check for safety
@ -212,7 +209,7 @@ public class Note {
operationList.add(builder.build()); operationList.add(builder.build());
} }
mTextDataValues.clear(); mTextDataValues.clear();
}//把文本数据存入DataColumns }
if(mCallDataValues.size() > 0) { if(mCallDataValues.size() > 0) {
mCallDataValues.put(DataColumns.NOTE_ID, noteId); mCallDataValues.put(DataColumns.NOTE_ID, noteId);
@ -234,7 +231,7 @@ public class Note {
operationList.add(builder.build()); operationList.add(builder.build());
} }
mCallDataValues.clear(); mCallDataValues.clear();
}//把电话号码数据存入DataColumns }
if (operationList.size() > 0) { if (operationList.size() > 0) {
try { try {
@ -249,7 +246,7 @@ public class Note {
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;
} }
}//存储过程中的异常处理 }
return null; return null;
} }
} }

@ -61,7 +61,7 @@ public class WorkingNote {
private boolean mIsDeleted; private boolean mIsDeleted;
private NoteSettingChangedListener mNoteSettingStatusListener; private NoteSettingChangedListener mNoteSettingStatusListener;
// 声明 DATA_PROJECTION字符串数组
public static final String[] DATA_PROJECTION = new String[] { public static final String[] DATA_PROJECTION = new String[] {
DataColumns.ID, DataColumns.ID,
DataColumns.CONTENT, DataColumns.CONTENT,
@ -123,13 +123,12 @@ public class WorkingNote {
mNote = new Note(); mNote = new Note();
loadNote(); loadNote();
} }
// 加载Note
// 通过数据库调用query函数找到第一个条目
private void loadNote() { private void loadNote() {
Cursor cursor = mContext.getContentResolver().query( Cursor cursor = mContext.getContentResolver().query(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null, ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null,
null, null); null, null);
// 若存在,储存相应信息
if (cursor != null) { if (cursor != null) {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN);
@ -140,18 +139,17 @@ public class WorkingNote {
mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN);
} }
cursor.close(); cursor.close();
// 若不存在,报错
} else { } else {
Log.e(TAG, "No note with id:" + mNoteId); Log.e(TAG, "No note with id:" + mNoteId);
throw new IllegalArgumentException("Unable to find note with id " + mNoteId); throw new IllegalArgumentException("Unable to find note with id " + mNoteId);
} }
loadNoteData(); loadNoteData();
} }
// 加载NoteData
private void loadNoteData() { private void loadNoteData() {
Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION,
DataColumns.NOTE_ID + "=?", new String[] { DataColumns.NOTE_ID + "=?", new String[] {
String.valueOf(mNoteId) String.valueOf(mNoteId)
}, null); }, null);
if (cursor != null) { if (cursor != null) {
@ -175,12 +173,10 @@ public class WorkingNote {
throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId); throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId);
} }
} }
// 创建空的Note
// 传参context文件夹idwidget背景颜色
public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId,
int widgetType, int defaultBgColorId) { int widgetType, int defaultBgColorId) {
WorkingNote note = new WorkingNote(context, folderId); WorkingNote note = new WorkingNote(context, folderId);
// 设定相关属性
note.setBgColorId(defaultBgColorId); note.setBgColorId(defaultBgColorId);
note.setWidgetId(widgetId); note.setWidgetId(widgetId);
note.setWidgetType(widgetType); note.setWidgetType(widgetType);
@ -191,7 +187,6 @@ public class WorkingNote {
return new WorkingNote(context, id, 0); return new WorkingNote(context, id, 0);
} }
// 保存Note
public synchronized boolean saveNote() { public synchronized boolean saveNote() {
if (isWorthSaving()) { if (isWorthSaving()) {
if (!existInDatabase()) { if (!existInDatabase()) {
@ -229,12 +224,11 @@ public class WorkingNote {
return true; return true;
} }
} }
// 设置mNoteSettingStatusListener
public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) { public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) {
mNoteSettingStatusListener = l; mNoteSettingStatusListener = l;
} }
// 设置AlertDate
// 若 mAlertDate与data不同则更改mAlertDate并设定NoteValue
public void setAlertDate(long date, boolean set) { public void setAlertDate(long date, boolean set) {
if (date != mAlertDate) { if (date != mAlertDate) {
mAlertDate = date; mAlertDate = date;
@ -244,17 +238,17 @@ public class WorkingNote {
mNoteSettingStatusListener.onClockAlertChanged(date, set); mNoteSettingStatusListener.onClockAlertChanged(date, set);
} }
} }
// 设定删除标记
public void markDeleted(boolean mark) { public void markDeleted(boolean mark) {
mIsDeleted = mark; mIsDeleted = mark;
if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) { && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onWidgetChanged();// 调用mNoteSettingStatusListener的 onWidgetChanged方法 mNoteSettingStatusListener.onWidgetChanged();
} }
} }
// 设定背景颜色
public void setBgColorId(int id) { public void setBgColorId(int id) {
if (id != mBgColorId) {//设定条件 id != mBgColorId if (id != mBgColorId) {
mBgColorId = id; mBgColorId = id;
if (mNoteSettingStatusListener != null) { if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onBackgroundColorChanged(); mNoteSettingStatusListener.onBackgroundColorChanged();
@ -262,8 +256,7 @@ public class WorkingNote {
mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id)); mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id));
} }
} }
// 设定检查列表模式
// 参数mode
public void setCheckListMode(int mode) { public void setCheckListMode(int mode) {
if (mMode != mode) { if (mMode != mode) {
if (mNoteSettingStatusListener != null) { if (mNoteSettingStatusListener != null) {
@ -273,88 +266,82 @@ public class WorkingNote {
mNote.setTextData(TextNote.MODE, String.valueOf(mMode)); mNote.setTextData(TextNote.MODE, String.valueOf(mMode));
} }
} }
// 设定WidgetType
// 参数type
public void setWidgetType(int type) { public void setWidgetType(int type) {
if (type != mWidgetType) { if (type != mWidgetType) {
mWidgetType = type; mWidgetType = type;
mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType)); mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType));
} }
} }
// 设定WidgetId
// 参数id
public void setWidgetId(int id) { public void setWidgetId(int id) {
if (id != mWidgetId) { if (id != mWidgetId) {
mWidgetId = id; mWidgetId = id;
mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId)); mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId));
} }
} }
// 设定WorkingTex
// 参数更改的text
public void setWorkingText(String text) { public void setWorkingText(String text) {
if (!TextUtils.equals(mContent, text)) { if (!TextUtils.equals(mContent, text)) {
mContent = text; mContent = text;
mNote.setTextData(DataColumns.CONTENT, mContent); mNote.setTextData(DataColumns.CONTENT, mContent);
} }
} }
// 转变mNote的CallData及CallNote信息
// 参数String phoneNumber, long callDate
public void convertToCallNote(String phoneNumber, long callDate) { public void convertToCallNote(String phoneNumber, long callDate) {
mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate)); mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate));
mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber); mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber);
mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(Notes.ID_CALL_RECORD_FOLDER)); mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(Notes.ID_CALL_RECORD_FOLDER));
} }
// 判断是否有时钟题型
public boolean hasClockAlert() { public boolean hasClockAlert() {
return (mAlertDate > 0 ? true : false); return (mAlertDate > 0 ? true : false);
} }
// 获取Content
public String getContent() { public String getContent() {
return mContent; return mContent;
} }
// 获取AlertDate
public long getAlertDate() { public long getAlertDate() {
return mAlertDate; return mAlertDate;
} }
// 获取ModifiedDate
public long getModifiedDate() { public long getModifiedDate() {
return mModifiedDate; return mModifiedDate;
} }
// 获取背景颜色来源id
public int getBgColorResId() { public int getBgColorResId() {
return NoteBgResources.getNoteBgResource(mBgColorId); return NoteBgResources.getNoteBgResource(mBgColorId);
} }
// 获取背景颜色id
public int getBgColorId() { public int getBgColorId() {
return mBgColorId; return mBgColorId;
} }
// 获取标题背景颜色id
public int getTitleBgResId() { public int getTitleBgResId() {
return NoteBgResources.getNoteTitleBgResource(mBgColorId); return NoteBgResources.getNoteTitleBgResource(mBgColorId);
} }
// 获取CheckListMode
public int getCheckListMode() { public int getCheckListMode() {
return mMode; return mMode;
} }
// 获取便签id
public long getNoteId() { public long getNoteId() {
return mNoteId; return mNoteId;
} }
// 获取文件夹id
public long getFolderId() { public long getFolderId() {
return mFolderId; return mFolderId;
} }
// 获取WidgetId
public int getWidgetId() { public int getWidgetId() {
return mWidgetId; return mWidgetId;
} }
// 获取WidgetType
public int getWidgetType() { public int getWidgetType() {
return mWidgetType; return mWidgetType;
} }
// 创建接口 NoteSettingChangedListener,便签更新监视
// 为NoteEditActivity提供接口
// 提供函数有
public interface NoteSettingChangedListener { public interface NoteSettingChangedListener {
/** /**
* Called when the background color of current note has just changed * Called when the background color of current note has just changed

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
//哈哈哈哈
package net.micode.notes.tool; package net.micode.notes.tool;
import android.content.Context; import android.content.Context;
@ -39,15 +39,10 @@ import java.io.PrintStream;
public class BackupUtils { public class BackupUtils {
private static final String TAG = "BackupUtils"; private static final String TAG = "BackupUtils";
// Singleton stuff // Singleton stuff
private static BackupUtils sInstance;//类里面为什么可以定义自身类的对象? private static BackupUtils sInstance;
public static synchronized BackupUtils getInstance(Context context) { public static synchronized BackupUtils getInstance(Context context) {
//ynchronized 关键字,代表这个方法加锁,相当于不管哪一个线程例如线程A
//运行到这个方法时,都要检查有没有其它线程B或者C、 D等正在用这个方法(或者该类的其他同步方法)有的话要等正在使用synchronized方法的线程B或者C 、D运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。
//它包括两种用法synchronized 方法和 synchronized 块。
if (sInstance == null) { if (sInstance == null) {
//如果当前备份不存在,则新声明一个
sInstance = new BackupUtils(context); sInstance = new BackupUtils(context);
} }
return sInstance; return sInstance;
@ -70,12 +65,10 @@ public class BackupUtils {
private TextExport mTextExport; private TextExport mTextExport;
//初始化函数
private BackupUtils(Context context) { private BackupUtils(Context context) {
mTextExport = new TextExport(context); mTextExport = new TextExport(context);
} }
//外部存储功能是否可用
private static boolean externalStorageAvailable() { private static boolean externalStorageAvailable() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
} }
@ -153,7 +146,7 @@ public class BackupUtils {
folderId folderId
}, null); }, null);
if (notesCursor != null) {//利用光标来扫描内容区别为callnote和note两种靠ps.printline输出 if (notesCursor != null) {
if (notesCursor.moveToFirst()) { if (notesCursor.moveToFirst()) {
do { do {
// Print note's last modified date // Print note's last modified date
@ -225,7 +218,7 @@ public class BackupUtils {
/** /**
* Note will be exported as text which is user readable * Note will be exported as text which is user readable
*/ */
public int exportToText() {//总函数调用上面的exportFolder和exportNote public int exportToText() {
if (!externalStorageAvailable()) { if (!externalStorageAvailable()) {
Log.d(TAG, "Media was not mounted"); Log.d(TAG, "Media was not mounted");
return STATE_SD_CARD_UNMOUONTED; return STATE_SD_CARD_UNMOUONTED;

@ -52,13 +52,13 @@ public class DataUtils {
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;
}//如果发现是根文件夹,则不删除 }
ContentProviderOperation.Builder builder = ContentProviderOperation ContentProviderOperation.Builder builder = ContentProviderOperation
.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) {
Log.d(TAG, "delete notes failed, ids:" + ids.toString()); Log.d(TAG, "delete notes failed, ids:" + ids.toString());
return false; return false;

@ -1,19 +1,3 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui; package net.micode.notes.ui;
import android.app.Activity; import android.app.Activity;
@ -39,58 +23,81 @@ import net.micode.notes.tool.DataUtils;
import java.io.IOException; import java.io.IOException;
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener { public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
private long mNoteId; private long mNoteId; //文本在数据库存储中的ID号
private String mSnippet; private String mSnippet; //闹钟提示时出现的文本片段
private static final int SNIPPET_PREW_MAX_LEN = 60; private static final int SNIPPET_PREW_MAX_LEN = 60;
MediaPlayer mPlayer; MediaPlayer mPlayer;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
//Bundle类型的数据与Map类型的数据相似都是以key-value的形式存储数据的
//onsaveInstanceState方法是用来保存Activity的状态的
//能从onCreate的参数savedInsanceState中获得状态数据
requestWindowFeature(Window.FEATURE_NO_TITLE); requestWindowFeature(Window.FEATURE_NO_TITLE);
//界面显示——无标题
final Window win = getWindow(); final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
if (!isScreenOn()) { if (!isScreenOn()) {
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
//保持窗体点亮
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
//将窗体点亮
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
//允许窗体点亮时锁屏
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
} }//在手机锁屏后如果到了闹钟提示时间,点亮屏幕
Intent intent = getIntent(); Intent intent = getIntent();
try { try {
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1)); mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));
mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId); mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId);
//根据ID从数据库中获取标签的内容
//getContentResolver是实现数据共享实例存储。
mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0, mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0,
SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info) SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info)
: mSnippet; : mSnippet;
//判断标签片段是否达到符合长度
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
e.printStackTrace(); e.printStackTrace();
return; return;
} }
/*
try
{
// 代码区
}
catch(Exception e)
{
// 异常处理
}
*/
mPlayer = new MediaPlayer(); mPlayer = new MediaPlayer();
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) { if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {
showActionDialog(); showActionDialog();
//弹出对话框
playAlarmSound(); playAlarmSound();
//闹钟提示音激发
} else { } else {
finish(); finish();
//完成闹钟动作
} }
} }
private boolean isScreenOn() { private boolean isScreenOn() {
//判断屏幕是否锁屏,调用系统函数判断,最后返回值是布尔类型
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
return pm.isScreenOn(); return pm.isScreenOn();
} }
private void playAlarmSound() { private void playAlarmSound() {
//闹钟提示音激发
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM); Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM);
//调用系统的铃声管理URI得到闹钟提示音
int silentModeStreams = Settings.System.getInt(getContentResolver(), int silentModeStreams = Settings.System.getInt(getContentResolver(),
Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0); Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
@ -101,12 +108,19 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
} }
try { try {
mPlayer.setDataSource(this, url); mPlayer.setDataSource(this, url);
//方法setDataSource(Context context, Uri uri)
//解释:无返回值,设置多媒体数据来源【根据 Uri】
mPlayer.prepare(); mPlayer.prepare();
//准备同步
mPlayer.setLooping(true); mPlayer.setLooping(true);
//设置是否循环播放
mPlayer.start(); mPlayer.start();
//开始播放
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
//e.printStackTrace()函数功能是抛出异常, 还将显示出更深的调用信息
//System.out.println(e),这个方法打印出异常,并且输出在哪里出现的异常
} catch (SecurityException e) { } catch (SecurityException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
@ -121,38 +135,58 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
private void showActionDialog() { private void showActionDialog() {
AlertDialog.Builder dialog = new AlertDialog.Builder(this); AlertDialog.Builder dialog = new AlertDialog.Builder(this);
//AlertDialog的构造方法全部是Protected的
//所以不能直接通过new一个AlertDialog来创建出一个AlertDialog。
//要创建一个AlertDialog就要用到AlertDialog.Builder中的create()方法
//如这里的dialog就是新建了一个AlertDialog
dialog.setTitle(R.string.app_name); dialog.setTitle(R.string.app_name);
//为对话框设置标题
dialog.setMessage(mSnippet); dialog.setMessage(mSnippet);
//为对话框设置内容
dialog.setPositiveButton(R.string.notealert_ok, this); dialog.setPositiveButton(R.string.notealert_ok, this);
//给对话框添加"Yes"按钮
if (isScreenOn()) { if (isScreenOn()) {
dialog.setNegativeButton(R.string.notealert_enter, this); dialog.setNegativeButton(R.string.notealert_enter, this);
} }//对话框添加"No"按钮
dialog.show().setOnDismissListener(this); dialog.show().setOnDismissListener(this);
} }
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
switch (which) { switch (which) {
//用which来选择click后下一步的操作
case DialogInterface.BUTTON_NEGATIVE: case DialogInterface.BUTTON_NEGATIVE:
//这是取消操作
Intent intent = new Intent(this, NoteEditActivity.class); Intent intent = new Intent(this, NoteEditActivity.class);
//实现两个类间的数据传输
intent.setAction(Intent.ACTION_VIEW); intent.setAction(Intent.ACTION_VIEW);
//设置动作属性
intent.putExtra(Intent.EXTRA_UID, mNoteId); intent.putExtra(Intent.EXTRA_UID, mNoteId);
//实现key-value对
//EXTRA_UID为keymNoteId为键
startActivity(intent); startActivity(intent);
//开始动作
break; break;
default: default:
//这是确定操作
break; break;
} }
} }
public void onDismiss(DialogInterface dialog) { public void onDismiss(DialogInterface dialog) {
//忽略
stopAlarmSound(); stopAlarmSound();
//停止闹钟声音
finish(); finish();
//完成该动作
} }
private void stopAlarmSound() { private void stopAlarmSound() {
if (mPlayer != null) { if (mPlayer != null) {
mPlayer.stop(); mPlayer.stop();
//停止播放
mPlayer.release(); mPlayer.release();
//释放MediaPlayer对象
mPlayer = null; mPlayer = null;
} }
} }
} }

@ -1,19 +1,3 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui; package net.micode.notes.ui;
import android.app.AlarmManager; import android.app.AlarmManager;
@ -31,21 +15,25 @@ import net.micode.notes.data.Notes.NoteColumns;
public class AlarmInitReceiver extends BroadcastReceiver { public class AlarmInitReceiver extends BroadcastReceiver {
private static final String [] PROJECTION = new String [] { private static final String [] PROJECTION = new String [] {
NoteColumns.ID, NoteColumns.ID,
NoteColumns.ALERTED_DATE NoteColumns.ALERTED_DATE
}; };
//对数据库的操作调用标签ID和闹钟时间
private static final int COLUMN_ID = 0; private static final int COLUMN_ID = 0;
private static final int COLUMN_ALERTED_DATE = 1; private static final int COLUMN_ALERTED_DATE = 1;
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
long currentDate = System.currentTimeMillis(); long currentDate = System.currentTimeMillis();
//System.currentTimeMillis()产生一个当前的毫秒
//这个毫秒其实就是自1970年1月1日0时起的毫秒数
Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI, Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION, PROJECTION,
NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE, NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE,
new String[] { String.valueOf(currentDate) }, new String[] { String.valueOf(currentDate) },
//将long变量currentDate转化为字符串
null); null);
//Cursor在这里的作用是通过查找数据库中的标签内容找到和当前系统时间相等的标签
if (c != null) { if (c != null) {
if (c.moveToFirst()) { if (c.moveToFirst()) {
@ -61,5 +49,8 @@ public class AlarmInitReceiver extends BroadcastReceiver {
} }
c.close(); c.close();
} }
//然而通过网上查找资料发现,对于闹钟机制的启动,通常需要上面的几个步骤
//如新建Intent、PendingIntent以及AlarmManager等
//这里就是根据数据库里的闹钟时间创建一个闹钟机制
} }
} }

@ -1,19 +1,3 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui; package net.micode.notes.ui;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
@ -24,7 +8,13 @@ public class AlarmReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
intent.setClass(context, AlarmAlertActivity.class); intent.setClass(context, AlarmAlertActivity.class);
//启动AlarmAlertActivity
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//activity要存在于activity的栈中而非activity的途径启动activity时必然不存在一个activity的栈
//所以要新起一个栈装入启动的activity
context.startActivity(intent); context.startActivity(intent);
} }
} }
//这是实现alarm这个功能最接近用户层的包基于上面的两个包
//作用还需要深究但是对于setClass和addFlags的

@ -1,19 +1,3 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui; package net.micode.notes.ui;
import java.text.DateFormatSymbols; import java.text.DateFormatSymbols;
@ -29,7 +13,8 @@ import android.widget.FrameLayout;
import android.widget.NumberPicker; import android.widget.NumberPicker;
public class DateTimePicker extends FrameLayout { public class DateTimePicker extends FrameLayout {
//FrameLayout是布局模板之一
//所有的子元素全部在屏幕的右上方
private static final boolean DEFAULT_ENABLE_STATE = true; private static final boolean DEFAULT_ENABLE_STATE = true;
private static final int HOURS_IN_HALF_DAY = 12; private static final int HOURS_IN_HALF_DAY = 12;
@ -45,13 +30,15 @@ public class DateTimePicker extends FrameLayout {
private static final int MINUT_SPINNER_MAX_VAL = 59; private static final int MINUT_SPINNER_MAX_VAL = 59;
private static final int AMPM_SPINNER_MIN_VAL = 0; private static final int AMPM_SPINNER_MIN_VAL = 0;
private static final int AMPM_SPINNER_MAX_VAL = 1; private static final int AMPM_SPINNER_MAX_VAL = 1;
//初始化控件
private final NumberPicker mDateSpinner; private final NumberPicker mDateSpinner;
private final NumberPicker mHourSpinner; private final NumberPicker mHourSpinner;
private final NumberPicker mMinuteSpinner; private final NumberPicker mMinuteSpinner;
private final NumberPicker mAmPmSpinner; private final NumberPicker mAmPmSpinner;
//NumberPicker是数字选择器
//这里定义的四个变量全部是在设置闹钟时需要选择的变量(如日期、时、分、上午或者下午)
private Calendar mDate; private Calendar mDate;
//定义了Calendar类型的变量mDate用于操作时间
private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK]; private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK];
private boolean mIsAm; private boolean mIsAm;
@ -71,41 +58,49 @@ public class DateTimePicker extends FrameLayout {
updateDateControl(); updateDateControl();
onDateTimeChanged(); onDateTimeChanged();
} }
}; };//OnValueChangeListener这是时间改变监听器这里主要是对日期的监听
//将现在日期的值传递给mDateupdateDateControl是同步操作
private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() { private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() {
//这里是对 小时Hour 的监听
@Override @Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) { public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
boolean isDateChanged = false; boolean isDateChanged = false;
Calendar cal = Calendar.getInstance(); Calendar cal = Calendar.getInstance();
//声明一个Calendar的变量cal便于后续的操作
if (!mIs24HourView) { if (!mIs24HourView) {
if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) { if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) {
cal.setTimeInMillis(mDate.getTimeInMillis()); cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1); cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true; isDateChanged = true;
//这里是对于12小时制时晚上11点和12点交替时对日期的更改
} else if (mIsAm && oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) { } else if (mIsAm && oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
cal.setTimeInMillis(mDate.getTimeInMillis()); cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1); cal.add(Calendar.DAY_OF_YEAR, -1);
isDateChanged = true; isDateChanged = true;
} }
//这里是对于12小时制时凌晨11点和12点交替时对日期的更改
if (oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY || if (oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY ||
oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) { oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
mIsAm = !mIsAm; mIsAm = !mIsAm;
updateAmPmControl(); updateAmPmControl();
} }//这里是对于12小时制时中午11点和12点交替时对AM和PM的更改
} else { } else {
if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) { if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) {
cal.setTimeInMillis(mDate.getTimeInMillis()); cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1); cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true; isDateChanged = true;
//这里是对于24小时制时晚上11点和12点交替时对日期的更改
} else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) { } else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) {
cal.setTimeInMillis(mDate.getTimeInMillis()); cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1); cal.add(Calendar.DAY_OF_YEAR, -1);
isDateChanged = true; isDateChanged = true;
} }
} } //这里是对于12小时制时凌晨11点和12点交替时对日期的更改
int newHour = mHourSpinner.getValue() % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY); int newHour = mHourSpinner.getValue() % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY);
//通过数字选择器对newHour的赋值
mDate.set(Calendar.HOUR_OF_DAY, newHour); mDate.set(Calendar.HOUR_OF_DAY, newHour);
//通过set函数将新的Hour值传给mDate
onDateTimeChanged(); onDateTimeChanged();
if (isDateChanged) { if (isDateChanged) {
setCurrentYear(cal.get(Calendar.YEAR)); setCurrentYear(cal.get(Calendar.YEAR));
@ -117,15 +112,19 @@ public class DateTimePicker extends FrameLayout {
private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() { private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() {
@Override @Override
//这里是对 分钟Minute改变的监听
public void onValueChange(NumberPicker picker, int oldVal, int newVal) { public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
int minValue = mMinuteSpinner.getMinValue(); int minValue = mMinuteSpinner.getMinValue();
int maxValue = mMinuteSpinner.getMaxValue(); int maxValue = mMinuteSpinner.getMaxValue();
int offset = 0; int offset = 0;
//设置offset作为小时改变的一个记录数据
if (oldVal == maxValue && newVal == minValue) { if (oldVal == maxValue && newVal == minValue) {
offset += 1; offset += 1;
} else if (oldVal == minValue && newVal == maxValue) { } else if (oldVal == minValue && newVal == maxValue) {
offset -= 1; offset -= 1;
} }
//如果原值为59新值为0则offset加1
//如果原值为0新值为59则offset减1
if (offset != 0) { if (offset != 0) {
mDate.add(Calendar.HOUR_OF_DAY, offset); mDate.add(Calendar.HOUR_OF_DAY, offset);
mHourSpinner.setValue(getCurrentHour()); mHourSpinner.setValue(getCurrentHour());
@ -145,6 +144,7 @@ public class DateTimePicker extends FrameLayout {
}; };
private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() { private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() {
//对AM和PM的监听
@Override @Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) { public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
mIsAm = !mIsAm; mIsAm = !mIsAm;
@ -160,24 +160,27 @@ public class DateTimePicker extends FrameLayout {
public interface OnDateTimeChangedListener { public interface OnDateTimeChangedListener {
void onDateTimeChanged(DateTimePicker view, int year, int month, void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute); int dayOfMonth, int hourOfDay, int minute);
} }
public DateTimePicker(Context context) { public DateTimePicker(Context context) {
this(context, System.currentTimeMillis()); this(context, System.currentTimeMillis());
} }//通过对数据库的访问,获取当前的系统时间
public DateTimePicker(Context context, long date) { public DateTimePicker(Context context, long date) {
this(context, date, DateFormat.is24HourFormat(context)); this(context, date, DateFormat.is24HourFormat(context));
} }//上面函数的得到的是一个天文数字1970至今的秒数需要DateFormat将其变得有意义
public DateTimePicker(Context context, long date, boolean is24HourView) { public DateTimePicker(Context context, long date, boolean is24HourView) {
super(context); super(context);
//获取系统时间
mDate = Calendar.getInstance(); mDate = Calendar.getInstance();
mInitialising = true; mInitialising = true;
mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY; mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY;
inflate(context, R.layout.datetime_picker, this); inflate(context, R.layout.datetime_picker, this);
//如果当前Activity里用到别的layout比如对话框layout
//还要设置这个layout上的其他组件的内容就必须用inflate()方法先将对话框的layout找出来
//然后再用findViewById()找到它上面的其它组件
mDateSpinner = (NumberPicker) findViewById(R.id.date); mDateSpinner = (NumberPicker) findViewById(R.id.date);
mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL); mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL);
mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL); mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL);
@ -185,7 +188,7 @@ public class DateTimePicker extends FrameLayout {
mHourSpinner = (NumberPicker) findViewById(R.id.hour); mHourSpinner = (NumberPicker) findViewById(R.id.hour);
mHourSpinner.setOnValueChangedListener(mOnHourChangedListener); mHourSpinner.setOnValueChangedListener(mOnHourChangedListener);
mMinuteSpinner = (NumberPicker) findViewById(R.id.minute); mMinuteSpinner = (NumberPicker) findViewById(R.id.minute);
mMinuteSpinner.setMinValue(MINUT_SPINNER_MIN_VAL); mMinuteSpinner.setMinValue(MINUT_SPINNER_MIN_VAL);
mMinuteSpinner.setMaxValue(MINUT_SPINNER_MAX_VAL); mMinuteSpinner.setMaxValue(MINUT_SPINNER_MAX_VAL);
mMinuteSpinner.setOnLongPressUpdateInterval(100); mMinuteSpinner.setOnLongPressUpdateInterval(100);
@ -226,7 +229,9 @@ public class DateTimePicker extends FrameLayout {
mAmPmSpinner.setEnabled(enabled); mAmPmSpinner.setEnabled(enabled);
mIsEnabled = enabled; mIsEnabled = enabled;
} }
//存在疑问setEnabled的作用
//下面的代码通过原程序的注释已经比较清晰,另外可以通过函数名来判断
//下面的各函数主要是对上面代码引用到的各函数功能的实现
@Override @Override
public boolean isEnabled() { public boolean isEnabled() {
return mIsEnabled; return mIsEnabled;
@ -239,7 +244,7 @@ public class DateTimePicker extends FrameLayout {
*/ */
public long getCurrentDateInTimeMillis() { public long getCurrentDateInTimeMillis() {
return mDate.getTimeInMillis(); return mDate.getTimeInMillis();
} }//实现函数——得到当前的秒数
/** /**
* Set the current date * Set the current date
@ -251,7 +256,7 @@ public class DateTimePicker extends FrameLayout {
cal.setTimeInMillis(date); cal.setTimeInMillis(date);
setCurrentDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), setCurrentDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH),
cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE)); cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE));
} }//实现函数功能——设置当前的时间参数是date
/** /**
* Set the current date * Set the current date
@ -263,19 +268,20 @@ public class DateTimePicker extends FrameLayout {
* @param minute The current minute * @param minute The current minute
*/ */
public void setCurrentDate(int year, int month, public void setCurrentDate(int year, int month,
int dayOfMonth, int hourOfDay, int minute) { int dayOfMonth, int hourOfDay, int minute) {
setCurrentYear(year); setCurrentYear(year);
setCurrentMonth(month); setCurrentMonth(month);
setCurrentDay(dayOfMonth); setCurrentDay(dayOfMonth);
setCurrentHour(hourOfDay); setCurrentHour(hourOfDay);
setCurrentMinute(minute); setCurrentMinute(minute);
} }//实现函数功能——设置当前的时间,参数是各详细的变量
/** /**
* Get current year * Get current year
* *
* @return The current year * @return The current year
*/ */
//下面是得到year、month、day等值
public int getCurrentYear() { public int getCurrentYear() {
return mDate.get(Calendar.YEAR); return mDate.get(Calendar.YEAR);
} }
@ -446,7 +452,7 @@ public class DateTimePicker extends FrameLayout {
mDateSpinner.setDisplayedValues(mDateDisplayValues); mDateSpinner.setDisplayedValues(mDateDisplayValues);
mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2); mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2);
mDateSpinner.invalidate(); mDateSpinner.invalidate();
} }// 对于星期几的算法
private void updateAmPmControl() { private void updateAmPmControl() {
if (mIs24HourView) { if (mIs24HourView) {
@ -455,7 +461,7 @@ public class DateTimePicker extends FrameLayout {
int index = mIsAm ? Calendar.AM : Calendar.PM; int index = mIsAm ? Calendar.AM : Calendar.PM;
mAmPmSpinner.setValue(index); mAmPmSpinner.setValue(index);
mAmPmSpinner.setVisibility(View.VISIBLE); mAmPmSpinner.setVisibility(View.VISIBLE);
} }// 对于上下午操作的算法
} }
private void updateHourControl() { private void updateHourControl() {
@ -465,7 +471,7 @@ public class DateTimePicker extends FrameLayout {
} else { } else {
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW); mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW);
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW); mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW);
} }// 对与小时的算法
} }
/** /**
@ -482,4 +488,4 @@ public class DateTimePicker extends FrameLayout {
getCurrentMonth(), getCurrentDay(), getCurrentHourOfDay(), getCurrentMinute()); getCurrentMonth(), getCurrentDay(), getCurrentHourOfDay(), getCurrentMinute());
} }
} }
} }

@ -1,19 +1,3 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui; package net.micode.notes.ui;
import java.util.Calendar; import java.util.Calendar;
@ -32,35 +16,47 @@ import android.text.format.DateUtils;
public class DateTimePickerDialog extends AlertDialog implements OnClickListener { public class DateTimePickerDialog extends AlertDialog implements OnClickListener {
private Calendar mDate = Calendar.getInstance(); private Calendar mDate = Calendar.getInstance();
//创建一个Calendar类型的变量 mDate方便时间的操作
private boolean mIs24HourView; private boolean mIs24HourView;
private OnDateTimeSetListener mOnDateTimeSetListener; private OnDateTimeSetListener mOnDateTimeSetListener;
//声明一个时间日期滚动选择控件 mOnDateTimeSetListener
private DateTimePicker mDateTimePicker; private DateTimePicker mDateTimePicker;
//DateTimePicker控件控件一般用于让用户可以从日期列表中选择单个值。
//运行时,单击控件边上的下拉箭头,会显示为两个部分:一个下拉列表,一个用于选择日期的
public interface OnDateTimeSetListener { public interface OnDateTimeSetListener {
void OnDateTimeSet(AlertDialog dialog, long date); void OnDateTimeSet(AlertDialog dialog, long date);
} }
public DateTimePickerDialog(Context context, long date) { public DateTimePickerDialog(Context context, long date) {
//对该界面对话框的实例化
super(context); super(context);
//对数据库的操作
mDateTimePicker = new DateTimePicker(context); mDateTimePicker = new DateTimePicker(context);
setView(mDateTimePicker); setView(mDateTimePicker);
//添加一个子视图
mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() { mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() {
public void onDateTimeChanged(DateTimePicker view, int year, int month, public void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute) { int dayOfMonth, int hourOfDay, int minute) {
mDate.set(Calendar.YEAR, year); mDate.set(Calendar.YEAR, year);
mDate.set(Calendar.MONTH, month); mDate.set(Calendar.MONTH, month);
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
mDate.set(Calendar.MINUTE, minute); mDate.set(Calendar.MINUTE, minute);
//将视图中的各选项设置为系统当前时间
updateTitle(mDate.getTimeInMillis()); updateTitle(mDate.getTimeInMillis());
} }
}); });
mDate.setTimeInMillis(date); mDate.setTimeInMillis(date);
//得到系统时间
mDate.set(Calendar.SECOND, 0); mDate.set(Calendar.SECOND, 0);
//将秒数设置为0
mDateTimePicker.setCurrentDate(mDate.getTimeInMillis()); mDateTimePicker.setCurrentDate(mDate.getTimeInMillis());
setButton(context.getString(R.string.datetime_dialog_ok), this); setButton(context.getString(R.string.datetime_dialog_ok), this);
setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null); setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null);
//设置按钮
set24HourView(DateFormat.is24HourFormat(this.getContext())); set24HourView(DateFormat.is24HourFormat(this.getContext()));
//时间标准化打印
updateTitle(mDate.getTimeInMillis()); updateTitle(mDate.getTimeInMillis());
} }
@ -70,21 +66,22 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) { public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) {
mOnDateTimeSetListener = callBack; mOnDateTimeSetListener = callBack;
} }//将时间日期滚动选择控件实例化
private void updateTitle(long date) { private void updateTitle(long date) {
int flag = int flag =
DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_YEAR |
DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_DATE |
DateUtils.FORMAT_SHOW_TIME; DateUtils.FORMAT_SHOW_TIME;
flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR; flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR;
setTitle(DateUtils.formatDateTime(this.getContext(), date, flag)); setTitle(DateUtils.formatDateTime(this.getContext(), date, flag));
} }//android开发中常见日期管理工具类API——DateUtils按照上下午显示时间
public void onClick(DialogInterface arg0, int arg1) { public void onClick(DialogInterface arg0, int arg1) {
if (mOnDateTimeSetListener != null) { if (mOnDateTimeSetListener != null) {
mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis()); mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis());
} }
} }//第一个参数arg0是接收到点击事件的对话框
//第二个参数arg1是该对话框上的按钮
} }

@ -1,19 +1,3 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui; package net.micode.notes.ui;
import android.content.Context; import android.content.Context;
@ -30,14 +14,18 @@ import net.micode.notes.R;
public class DropdownMenu { public class DropdownMenu {
private Button mButton; private Button mButton;
private PopupMenu mPopupMenu; private PopupMenu mPopupMenu;
//声明一个下拉菜单
private Menu mMenu; private Menu mMenu;
public DropdownMenu(Context context, Button button, int menuId) { public DropdownMenu(Context context, Button button, int menuId) {
mButton = button; mButton = button;
mButton.setBackgroundResource(R.drawable.dropdown_icon); mButton.setBackgroundResource(R.drawable.dropdown_icon);
//设置这个view的背景
mPopupMenu = new PopupMenu(context, mButton); mPopupMenu = new PopupMenu(context, mButton);
mMenu = mPopupMenu.getMenu(); mMenu = mPopupMenu.getMenu();
mPopupMenu.getMenuInflater().inflate(menuId, mMenu); mPopupMenu.getMenuInflater().inflate(menuId, mMenu);
//MenuInflater是用来实例化Menu目录下的Menu布局文件
//根据ID来确认menu的内容选项
mButton.setOnClickListener(new OnClickListener() { mButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
mPopupMenu.show(); mPopupMenu.show();
@ -48,14 +36,14 @@ public class DropdownMenu {
public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) { public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) {
if (mPopupMenu != null) { if (mPopupMenu != null) {
mPopupMenu.setOnMenuItemClickListener(listener); mPopupMenu.setOnMenuItemClickListener(listener);
} }//设置菜单的监听
} }
public MenuItem findItem(int id) { public MenuItem findItem(int id) {
return mMenu.findItem(id); return mMenu.findItem(id);
} }//对于菜单选项的初始化,根据索引搜索菜单需要的选项
public void setTitle(CharSequence title) { public void setTitle(CharSequence title) {
mButton.setText(title); mButton.setText(title);
} }//布局文件,设置标题
} }

@ -1,19 +1,3 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui; package net.micode.notes.ui;
import android.content.Context; import android.content.Context;
@ -30,10 +14,14 @@ import net.micode.notes.data.Notes.NoteColumns;
public class FoldersListAdapter extends CursorAdapter { public class FoldersListAdapter extends CursorAdapter {
//CursorAdapter是Cursor和ListView的接口
//FoldersListAdapter继承了CursorAdapter的类
//主要作用是便签数据库和用户的交互
//这里就是用folder文件夹的形式展现给用户
public static final String [] PROJECTION = { public static final String [] PROJECTION = {
NoteColumns.ID, NoteColumns.ID,
NoteColumns.SNIPPET NoteColumns.SNIPPET
}; };//调用数据库中便签的ID和片段
public static final int ID_COLUMN = 0; public static final int ID_COLUMN = 0;
public static final int NAME_COLUMN = 1; public static final int NAME_COLUMN = 1;
@ -41,12 +29,13 @@ public class FoldersListAdapter extends CursorAdapter {
public FoldersListAdapter(Context context, Cursor c) { public FoldersListAdapter(Context context, Cursor c) {
super(context, c); super(context, c);
// TODO Auto-generated constructor stub // TODO Auto-generated constructor stub
} }//数据库操作
@Override @Override
public View newView(Context context, Cursor cursor, ViewGroup parent) { public View newView(Context context, Cursor cursor, ViewGroup parent) {
//ViewGroup是容器
return new FolderListItem(context); return new FolderListItem(context);
} }//创建一个文件夹,对于各文件夹中子标签的初始化
@Override @Override
public void bindView(View view, Context context, Cursor cursor) { public void bindView(View view, Context context, Cursor cursor) {
@ -55,20 +44,22 @@ public class FoldersListAdapter extends CursorAdapter {
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN); .getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
((FolderListItem) view).bind(folderName); ((FolderListItem) view).bind(folderName);
} }
} }//将各个布局文件绑定起来
public String getFolderName(Context context, int position) { public String getFolderName(Context context, int position) {
Cursor cursor = (Cursor) getItem(position); Cursor cursor = (Cursor) getItem(position);
return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN); .getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
} }//根据数据库中标签的ID得到标签的各项内容
private class FolderListItem extends LinearLayout { private class FolderListItem extends LinearLayout {
private TextView mName; private TextView mName;
public FolderListItem(Context context) { public FolderListItem(Context context) {
super(context); super(context);
//操作数据库
inflate(context, R.layout.folder_list_item, this); inflate(context, R.layout.folder_list_item, this);
//根据布局文件的名字等信息将其找出来
mName = (TextView) findViewById(R.id.tv_folder_name); mName = (TextView) findViewById(R.id.tv_folder_name);
} }
@ -77,4 +68,4 @@ public class FoldersListAdapter extends CursorAdapter {
} }
} }
} }

@ -1,19 +1,3 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui; package net.micode.notes.ui;
import android.app.Activity; import android.app.Activity;
@ -74,6 +58,8 @@ import java.util.regex.Pattern;
public class NoteEditActivity extends Activity implements OnClickListener, public class NoteEditActivity extends Activity implements OnClickListener,
NoteSettingChangedListener, OnTextViewChangeListener { NoteSettingChangedListener, OnTextViewChangeListener {
//该类主要是针对标签的编辑
//继承了系统内部许多和监听有关的类
private class HeadViewHolder { private class HeadViewHolder {
public TextView tvModified; public TextView tvModified;
@ -83,7 +69,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
public ImageView ibSetBgColor; public ImageView ibSetBgColor;
} }
//使用Map实现数据存储
private static final Map<Integer, Integer> sBgSelectorBtnsMap = new HashMap<Integer, Integer>(); private static final Map<Integer, Integer> sBgSelectorBtnsMap = new HashMap<Integer, Integer>();
static { static {
sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW); sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW);
@ -91,6 +77,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
sBgSelectorBtnsMap.put(R.id.iv_bg_blue, ResourceParser.BLUE); sBgSelectorBtnsMap.put(R.id.iv_bg_blue, ResourceParser.BLUE);
sBgSelectorBtnsMap.put(R.id.iv_bg_green, ResourceParser.GREEN); sBgSelectorBtnsMap.put(R.id.iv_bg_green, ResourceParser.GREEN);
sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE); sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE);
//put函数是将指定值和指定键相连
} }
private static final Map<Integer, Integer> sBgSelectorSelectionMap = new HashMap<Integer, Integer>(); private static final Map<Integer, Integer> sBgSelectorSelectionMap = new HashMap<Integer, Integer>();
@ -100,6 +87,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
sBgSelectorSelectionMap.put(ResourceParser.BLUE, R.id.iv_bg_blue_select); sBgSelectorSelectionMap.put(ResourceParser.BLUE, R.id.iv_bg_blue_select);
sBgSelectorSelectionMap.put(ResourceParser.GREEN, R.id.iv_bg_green_select); sBgSelectorSelectionMap.put(ResourceParser.GREEN, R.id.iv_bg_green_select);
sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select); sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select);
//put函数是将指定值和指定键相连
} }
private static final Map<Integer, Integer> sFontSizeBtnsMap = new HashMap<Integer, Integer>(); private static final Map<Integer, Integer> sFontSizeBtnsMap = new HashMap<Integer, Integer>();
@ -108,6 +96,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
sFontSizeBtnsMap.put(R.id.ll_font_small, ResourceParser.TEXT_SMALL); sFontSizeBtnsMap.put(R.id.ll_font_small, ResourceParser.TEXT_SMALL);
sFontSizeBtnsMap.put(R.id.ll_font_normal, ResourceParser.TEXT_MEDIUM); sFontSizeBtnsMap.put(R.id.ll_font_normal, ResourceParser.TEXT_MEDIUM);
sFontSizeBtnsMap.put(R.id.ll_font_super, ResourceParser.TEXT_SUPER); sFontSizeBtnsMap.put(R.id.ll_font_super, ResourceParser.TEXT_SUPER);
//put函数是将指定值和指定键相连
} }
private static final Map<Integer, Integer> sFontSelectorSelectionMap = new HashMap<Integer, Integer>(); private static final Map<Integer, Integer> sFontSelectorSelectionMap = new HashMap<Integer, Integer>();
@ -116,6 +105,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
sFontSelectorSelectionMap.put(ResourceParser.TEXT_SMALL, R.id.iv_small_select); sFontSelectorSelectionMap.put(ResourceParser.TEXT_SMALL, R.id.iv_small_select);
sFontSelectorSelectionMap.put(ResourceParser.TEXT_MEDIUM, R.id.iv_medium_select); sFontSelectorSelectionMap.put(ResourceParser.TEXT_MEDIUM, R.id.iv_medium_select);
sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select); sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select);
//put函数是将指定值和指定键相连
} }
private static final String TAG = "NoteEditActivity"; private static final String TAG = "NoteEditActivity";
@ -123,20 +113,23 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private HeadViewHolder mNoteHeaderHolder; private HeadViewHolder mNoteHeaderHolder;
private View mHeadViewPanel; private View mHeadViewPanel;
//私有化一个界面操作mHeadViewPanel对表头的操作
private View mNoteBgColorSelector; private View mNoteBgColorSelector;
//私有化一个界面操作mNoteBgColorSelector对背景颜色的操作
private View mFontSizeSelector; private View mFontSizeSelector;
//私有化一个界面操作mFontSizeSelector对标签字体的操作
private EditText mNoteEditor; private EditText mNoteEditor;
//声明编辑控件,对文本操作
private View mNoteEditorPanel; private View mNoteEditorPanel;
//私有化一个界面操作mNoteEditorPanel文本编辑的控制板
private WorkingNote mWorkingNote; //private WorkingNote mWorkingNote;
public WorkingNote mWorkingNote;
//对模板WorkingNote的初始化
private SharedPreferences mSharedPrefs; private SharedPreferences mSharedPrefs;
//私有化SharedPreferences的数据存储方式
//它的本质是基于XML文件存储key-value键值对数据
private int mFontSizeId; private int mFontSizeId;
//用于操作字体的大小
private static final String PREFERENCE_FONT_SIZE = "pref_font_size"; private static final String PREFERENCE_FONT_SIZE = "pref_font_size";
private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10; private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10;
@ -145,7 +138,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
public static final String TAG_UNCHECKED = String.valueOf('\u25A1'); public static final String TAG_UNCHECKED = String.valueOf('\u25A1');
private LinearLayout mEditTextList; private LinearLayout mEditTextList;
//线性布局
private String mUserQuery; private String mUserQuery;
private Pattern mPattern; private Pattern mPattern;
@ -153,7 +146,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
this.setContentView(R.layout.note_edit); this.setContentView(R.layout.note_edit);
//对数据库的访问操作
if (savedInstanceState == null && !initActivityState(getIntent())) { if (savedInstanceState == null && !initActivityState(getIntent())) {
finish(); finish();
return; return;
@ -176,7 +169,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return; return;
} }
Log.d(TAG, "Restoring from killed activity"); Log.d(TAG, "Restoring from killed activity");
} }//为防止内存不足时程序的终止,在这里有一个保存现场的函数
} }
private boolean initActivityState(Intent intent) { private boolean initActivityState(Intent intent) {
@ -188,34 +181,42 @@ public class NoteEditActivity extends Activity implements OnClickListener,
if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) { if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) {
long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0); long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0);
mUserQuery = ""; mUserQuery = "";
//如果用户实例化标签时系统并未给出标签ID
/** /**
* Starting from the searched result * Starting from the searched result
*/ */
//根据键值查找ID
if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) { if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) {
noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY)); noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY); mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY);
} }
//如果ID在数据库中未找到
if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) { if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) {
Intent jump = new Intent(this, NotesListActivity.class); Intent jump = new Intent(this, NotesListActivity.class);
startActivity(jump); startActivity(jump);
//程序将跳转到上面声明的intent——jump
showToast(R.string.error_note_not_exist); showToast(R.string.error_note_not_exist);
finish(); finish();
return false; return false;
} else { }
//ID在数据库中找到
else {
mWorkingNote = WorkingNote.load(this, noteId); mWorkingNote = WorkingNote.load(this, noteId);
if (mWorkingNote == null) { if (mWorkingNote == null) {
Log.e(TAG, "load note failed with note id" + noteId); Log.e(TAG, "load note failed with note id" + noteId);
//打印出红色的错误信息
finish(); finish();
return false; return false;
} }
} }
//setSoftInputMode——软键盘输入模式
getWindow().setSoftInputMode( getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN
| WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
} else if(TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) { } else if(TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) {
// New note // intent.getAction()
// 大多用于broadcast发送广播时给机制intent设置一个action就是一个字符串
// 用户可以通过receive接受intent通过 getAction得到的字符串来决定做什么
long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0); long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0);
int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID, int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID); AppWidgetManager.INVALID_APPWIDGET_ID);
@ -223,7 +224,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
Notes.TYPE_WIDGET_INVALIDE); Notes.TYPE_WIDGET_INVALIDE);
int bgResId = intent.getIntExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, int bgResId = intent.getIntExtra(Notes.INTENT_EXTRA_BACKGROUND_ID,
ResourceParser.getDefaultBgId(this)); ResourceParser.getDefaultBgId(this));
// intent.getIntLong、StringExtra是对各变量的语法分析
// Parse call-record note // Parse call-record note
String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
long callDate = intent.getLongExtra(Notes.INTENT_EXTRA_CALL_DATE, 0); long callDate = intent.getLongExtra(Notes.INTENT_EXTRA_CALL_DATE, 0);
@ -240,15 +241,17 @@ public class NoteEditActivity extends Activity implements OnClickListener,
finish(); finish();
return false; return false;
} }
//将电话号码与手机的号码簿相关
} else { } else {
mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId,
widgetType, bgResId); widgetType, bgResId);
mWorkingNote.convertToCallNote(phoneNumber, callDate); mWorkingNote.convertToCallNote(phoneNumber, callDate);
//
} }
} else { } else {
mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, widgetType, mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, widgetType,
bgResId); bgResId);
} }//创建一个新的WorkingNote
getWindow().setSoftInputMode( getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
@ -269,8 +272,10 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} }
private void initNoteScreen() { private void initNoteScreen() {
//对界面的初始化操作
mNoteEditor.setTextAppearance(this, TextAppearanceResources mNoteEditor.setTextAppearance(this, TextAppearanceResources
.getTexAppearanceResource(mFontSizeId)); .getTexAppearanceResource(mFontSizeId));
//设置外观
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {
switchToListMode(mWorkingNote.getContent()); switchToListMode(mWorkingNote.getContent());
} else { } else {
@ -294,18 +299,21 @@ public class NoteEditActivity extends Activity implements OnClickListener,
*/ */
showAlertHeader(); showAlertHeader();
} }
//设置闹钟的显示
private void showAlertHeader() { private void showAlertHeader() {
if (mWorkingNote.hasClockAlert()) { if (mWorkingNote.hasClockAlert()) {
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
if (time > mWorkingNote.getAlertDate()) { if (time > mWorkingNote.getAlertDate()) {
mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired); mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired);
} else { }
//如果系统时间大于了闹钟设置的时间,那么闹钟失效
else {
mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString( mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString(
mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS)); mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS));
} }
mNoteHeaderHolder.tvAlertDate.setVisibility(View.VISIBLE); mNoteHeaderHolder.tvAlertDate.setVisibility(View.VISIBLE);
mNoteHeaderHolder.ivAlertIcon.setVisibility(View.VISIBLE); mNoteHeaderHolder.ivAlertIcon.setVisibility(View.VISIBLE);
//显示闹钟开启的图标
} else { } else {
mNoteHeaderHolder.tvAlertDate.setVisibility(View.GONE); mNoteHeaderHolder.tvAlertDate.setVisibility(View.GONE);
mNoteHeaderHolder.ivAlertIcon.setVisibility(View.GONE); mNoteHeaderHolder.ivAlertIcon.setVisibility(View.GONE);
@ -329,26 +337,29 @@ public class NoteEditActivity extends Activity implements OnClickListener,
if (!mWorkingNote.existInDatabase()) { if (!mWorkingNote.existInDatabase()) {
saveNote(); saveNote();
} }
//在创建一个新的标签时,先在数据库中匹配
//如果不存在,那么先在数据库中存储
outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId()); outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId());
Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState"); Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState");
} }
@Override @Override
//MotionEvent是对屏幕触控的传递机制
public boolean dispatchTouchEvent(MotionEvent ev) { public boolean dispatchTouchEvent(MotionEvent ev) {
if (mNoteBgColorSelector.getVisibility() == View.VISIBLE if (mNoteBgColorSelector.getVisibility() == View.VISIBLE
&& !inRangeOfView(mNoteBgColorSelector, ev)) { && !inRangeOfView(mNoteBgColorSelector, ev)) {
mNoteBgColorSelector.setVisibility(View.GONE); mNoteBgColorSelector.setVisibility(View.GONE);
return true; return true;
} }//颜色选择器在屏幕上可见
if (mFontSizeSelector.getVisibility() == View.VISIBLE if (mFontSizeSelector.getVisibility() == View.VISIBLE
&& !inRangeOfView(mFontSizeSelector, ev)) { && !inRangeOfView(mFontSizeSelector, ev)) {
mFontSizeSelector.setVisibility(View.GONE); mFontSizeSelector.setVisibility(View.GONE);
return true; return true;
} }//字体大小选择器在屏幕上可见
return super.dispatchTouchEvent(ev); return super.dispatchTouchEvent(ev);
} }
//对屏幕触控的坐标进行操作
private boolean inRangeOfView(View view, MotionEvent ev) { private boolean inRangeOfView(View view, MotionEvent ev) {
int []location = new int[2]; int []location = new int[2];
view.getLocationOnScreen(location); view.getLocationOnScreen(location);
@ -357,9 +368,11 @@ public class NoteEditActivity extends Activity implements OnClickListener,
if (ev.getX() < x if (ev.getX() < x
|| ev.getX() > (x + view.getWidth()) || ev.getX() > (x + view.getWidth())
|| ev.getY() < y || ev.getY() < y
|| ev.getY() > (y + view.getHeight())) { || ev.getY() > (y + view.getHeight()))
return false; //如果触控的位置超出了给定的范围返回false
} {
return false;
}
return true; return true;
} }
@ -377,13 +390,13 @@ public class NoteEditActivity extends Activity implements OnClickListener,
for (int id : sBgSelectorBtnsMap.keySet()) { for (int 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); mFontSizeSelector = findViewById(R.id.font_size_selector);
for (int id : sFontSizeBtnsMap.keySet()) { for (int id : sFontSizeBtnsMap.keySet()) {
View view = findViewById(id); View view = findViewById(id);
view.setOnClickListener(this); 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);
/** /**
@ -405,7 +418,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} }
clearSettingState(); clearSettingState();
} }
//和桌面小工具的同步
private void updateWidget() { private void updateWidget() {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) { if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) {
@ -418,7 +431,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} }
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {
mWorkingNote.getWidgetId() mWorkingNote.getWidgetId()
}); });
sendBroadcast(intent); sendBroadcast(intent);
@ -450,7 +463,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} }
mFontSizeSelector.setVisibility(View.GONE); mFontSizeSelector.setVisibility(View.GONE);
} }
} }//************************存在问题
@Override @Override
public void onBackPressed() { public void onBackPressed() {
@ -481,6 +494,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} }
@Override @Override
//对选择菜单的准备
public boolean onPrepareOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) {
if (isFinishing()) { if (isFinishing()) {
return true; return true;
@ -489,6 +503,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
menu.clear(); menu.clear();
if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) { if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) {
getMenuInflater().inflate(R.menu.call_note_edit, menu); getMenuInflater().inflate(R.menu.call_note_edit, menu);
// MenuInflater是用来实例化Menu目录下的Menu布局文件的
} else { } else {
getMenuInflater().inflate(R.menu.note_edit, menu); getMenuInflater().inflate(R.menu.note_edit, menu);
} }
@ -506,45 +521,71 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} }
@Override @Override
/*
*
*
*/
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
//根据菜单的id来编剧相关项目
case R.id.menu_new_note: case R.id.menu_new_note:
//创建一个新的便签
createNewNote(); createNewNote();
break; break;
case R.id.menu_delete: case R.id.menu_delete:
//删除便签
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
//创建关于删除操作的对话框
builder.setTitle(getString(R.string.alert_title_delete)); builder.setTitle(getString(R.string.alert_title_delete));
// 设置标签的标题为alert_title_delete
builder.setIcon(android.R.drawable.ic_dialog_alert); builder.setIcon(android.R.drawable.ic_dialog_alert);
//设置对话框图标
builder.setMessage(getString(R.string.alert_message_delete_note)); builder.setMessage(getString(R.string.alert_message_delete_note));
//设置对话框内容
builder.setPositiveButton(android.R.string.ok, builder.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
//建立按键监听器
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
//点击所触发事件
deleteCurrentNote(); deleteCurrentNote();
// 删除单签便签
finish(); finish();
} }
}); });
//添加“YES”按钮
builder.setNegativeButton(android.R.string.cancel, null); builder.setNegativeButton(android.R.string.cancel, null);
//添加“NO”的按钮
builder.show(); builder.show();
//显示对话框
break; break;
case R.id.menu_font_size: case R.id.menu_font_size:
//字体大小的编辑
mFontSizeSelector.setVisibility(View.VISIBLE); mFontSizeSelector.setVisibility(View.VISIBLE);
// 将字体选择器置为可见
findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE);
// 通过id找到相应的大小
break; break;
case R.id.menu_list_mode: case R.id.menu_list_mode:
//选择列表模式
mWorkingNote.setCheckListMode(mWorkingNote.getCheckListMode() == 0 ? mWorkingNote.setCheckListMode(mWorkingNote.getCheckListMode() == 0 ?
TextNote.MODE_CHECK_LIST : 0); TextNote.MODE_CHECK_LIST : 0);
break; break;
case R.id.menu_share: case R.id.menu_share:
//菜单共享
getWorkingText(); getWorkingText();
sendTo(this, mWorkingNote.getContent()); sendTo(this, mWorkingNote.getContent());
// 用sendto函数将运行文本发送到遍历的本文内
break; break;
case R.id.menu_send_to_desktop: case R.id.menu_send_to_desktop:
//发送到桌面
sendToDesktop(); sendToDesktop();
break; break;
case R.id.menu_alert: case R.id.menu_alert:
//创建提醒器
setReminder(); setReminder();
break; break;
case R.id.menu_delete_remind: case R.id.menu_delete_remind:
//删除日期提醒
mWorkingNote.setAlertDate(0, false); mWorkingNote.setAlertDate(0, false);
break; break;
default: default:
@ -553,111 +594,170 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return true; return true;
} }
/*
*
*
*/
private void setReminder() { private void setReminder() {
DateTimePickerDialog d = new DateTimePickerDialog(this, System.currentTimeMillis()); DateTimePickerDialog d = new DateTimePickerDialog(this, System.currentTimeMillis());
// 建立修改时间日期的对话框
d.setOnDateTimeSetListener(new OnDateTimeSetListener() { d.setOnDateTimeSetListener(new OnDateTimeSetListener() {
public void OnDateTimeSet(AlertDialog dialog, long date) { public void OnDateTimeSet(AlertDialog dialog, long date) {
mWorkingNote.setAlertDate(date , true); mWorkingNote.setAlertDate(date , true);
//选择提醒的日期
} }
}); });
//建立时间日期的监听器
d.show(); d.show();
//显示对话框
} }
/** /**
* Share note to apps that support {@link Intent#ACTION_SEND} action * Share note to apps that support {@link Intent#ACTION_SEND} action
* and {@text/plain} type * and {@text/plain} type
*/ */
/*
* 便
*
*/
private void sendTo(Context context, String info) { private void sendTo(Context context, String info) {
Intent intent = new Intent(Intent.ACTION_SEND); Intent intent = new Intent(Intent.ACTION_SEND);
//建立intent链接选项
intent.putExtra(Intent.EXTRA_TEXT, info); intent.putExtra(Intent.EXTRA_TEXT, info);
//将需要传递的便签信息放入text文件中
intent.setType("text/plain"); intent.setType("text/plain");
//编辑连接器的类型
context.startActivity(intent); context.startActivity(intent);
//在acti中进行链接
} }
/*
* 便
*
*/
private void createNewNote() { private void createNewNote() {
// Firstly, save current editing notes // Firstly, save current editing notes
//保存当前便签
saveNote(); saveNote();
// For safety, start a new NoteEditActivity // For safety, start a new NoteEditActivity
finish(); finish();
Intent intent = new Intent(this, NoteEditActivity.class); Intent intent = new Intent(this, NoteEditActivity.class);
//设置链接器
intent.setAction(Intent.ACTION_INSERT_OR_EDIT); intent.setAction(Intent.ACTION_INSERT_OR_EDIT);
//该活动定义为创建或编辑
intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId()); intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId());
//将运行便签的id添加到INTENT_EXTRA_FOLDER_ID标记中
startActivity(intent); startActivity(intent);
//开始activity并链接
} }
/*
* 便
*
*/
private void deleteCurrentNote() { private void deleteCurrentNote() {
if (mWorkingNote.existInDatabase()) { if (mWorkingNote.existInDatabase()) {
//假如当前运行的便签内存有数据
HashSet<Long> ids = new HashSet<Long>(); HashSet<Long> ids = new HashSet<Long>();
long id = mWorkingNote.getNoteId(); long id = mWorkingNote.getNoteId();
if (id != Notes.ID_ROOT_FOLDER) { if (id != Notes.ID_ROOT_FOLDER) {
ids.add(id); ids.add(id);
//如果不是头文件夹建立一个hash表把便签id存起来
} else { } else {
Log.d(TAG, "Wrong note id, should not happen"); Log.d(TAG, "Wrong note id, should not happen");
//否则报错
} }
if (!isSyncMode()) { if (!isSyncMode()) {
//在非同步模式情况下
//删除操作
if (!DataUtils.batchDeleteNotes(getContentResolver(), ids)) { if (!DataUtils.batchDeleteNotes(getContentResolver(), ids)) {
Log.e(TAG, "Delete Note error"); Log.e(TAG, "Delete Note error");
} }
} else { } else {
//同步模式
//移动至垃圾文件夹的操作
if (!DataUtils.batchMoveToFolder(getContentResolver(), ids, Notes.ID_TRASH_FOLER)) { if (!DataUtils.batchMoveToFolder(getContentResolver(), ids, Notes.ID_TRASH_FOLER)) {
Log.e(TAG, "Move notes to trash folder error, should not happens"); Log.e(TAG, "Move notes to trash folder error, should not happens");
} }
} }
} }
mWorkingNote.markDeleted(true); mWorkingNote.markDeleted(true);
//将这些标签的删除标记置为true
} }
/*
*
* NotesPreferenceActivity
*/
private boolean isSyncMode() { private boolean isSyncMode() {
return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0;
} }
/*
*
*
*/
public void onClockAlertChanged(long date, boolean set) { public void onClockAlertChanged(long date, boolean set) {
/** /**
* User could set clock to an unsaved note, so before setting the * User could set clock to an unsaved note, so before setting the
* alert clock, we should save the note first * alert clock, we should save the note first
*/ */
if (!mWorkingNote.existInDatabase()) { if (!mWorkingNote.existInDatabase()) {
//首先保存已有的便签
saveNote(); saveNote();
} }
if (mWorkingNote.getNoteId() > 0) { if (mWorkingNote.getNoteId() > 0) {
Intent intent = new Intent(this, AlarmReceiver.class); Intent intent = new Intent(this, AlarmReceiver.class);
intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mWorkingNote.getNoteId())); intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mWorkingNote.getNoteId()));
//若有有运行的便签就是建立一个链接器将标签id都存在uri中
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE)); AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE));
//设置提醒管理器
showAlertHeader(); showAlertHeader();
if(!set) { if(!set) {
alarmManager.cancel(pendingIntent); alarmManager.cancel(pendingIntent);
} else { } else {
alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent); alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent);
} }
//如果用户设置了时间,就通过提醒管理器设置一个监听事项
} else { } else {
/** /**
* There is the condition that user has input nothing (the note is * There is the condition that user has input nothing (the note is
* not worthy saving), we have no note id, remind the user that he * not worthy saving), we have no note id, remind the user that he
* should input something * should input something
*/ */
//没有运行的便签就报错
Log.e(TAG, "Clock alert setting error"); Log.e(TAG, "Clock alert setting error");
showToast(R.string.error_note_empty_for_clock); showToast(R.string.error_note_empty_for_clock);
} }
} }
/*
* Widget
*/
public void onWidgetChanged() { public void onWidgetChanged() {
updateWidget(); updateWidget();//更新Widget
} }
/*
*
*
*/
public void onEditTextDelete(int index, String text) { public void onEditTextDelete(int index, String text) {
int childCount = mEditTextList.getChildCount(); int childCount = mEditTextList.getChildCount();
if (childCount == 1) { if (childCount == 1) {
return; return;
} }
//没有编辑框的话直接返回
for (int i = index + 1; i < childCount; i++) { for (int i = index + 1; i < childCount; i++) {
((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text))
.setIndex(i - 1); .setIndex(i - 1);
//通过id把编辑框存在便签编辑框中
} }
mEditTextList.removeViewAt(index); mEditTextList.removeViewAt(index);
//删除特定位置的视图
NoteEditText edit = null; NoteEditText edit = null;
if(index == 0) { if(index == 0) {
edit = (NoteEditText) mEditTextList.getChildAt(0).findViewById( edit = (NoteEditText) mEditTextList.getChildAt(0).findViewById(
@ -666,69 +766,101 @@ public class NoteEditActivity extends Activity implements OnClickListener,
edit = (NoteEditText) mEditTextList.getChildAt(index - 1).findViewById( edit = (NoteEditText) mEditTextList.getChildAt(index - 1).findViewById(
R.id.et_edit_text); R.id.et_edit_text);
} }
//通过id把编辑框存在空的NoteEditText中
int length = edit.length(); int length = edit.length();
edit.append(text); edit.append(text);
edit.requestFocus(); edit.requestFocus();//请求优先完成该此 编辑
edit.setSelection(length); edit.setSelection(length);//定位到length位置处的条目
} }
/*
*
*
*/
public void onEditTextEnter(int index, String text) { public void onEditTextEnter(int index, String text) {
/** /**
* Should not happen, check for debug * Should not happen, check for debug
*/ */
if(index > mEditTextList.getChildCount()) { if(index > mEditTextList.getChildCount()) {
Log.e(TAG, "Index out of mEditTextList boundrary, should not happen"); Log.e(TAG, "Index out of mEditTextList boundrary, should not happen");
//越界把偶偶
} }
View view = getListItem(text, index); View view = getListItem(text, index);
mEditTextList.addView(view, index); mEditTextList.addView(view, index);
//建立一个新的视图并添加到编辑文本框内
NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);
edit.requestFocus(); edit.requestFocus();//请求优先操作
edit.setSelection(0); edit.setSelection(0);//定位到起始位置
for (int i = index + 1; i < mEditTextList.getChildCount(); i++) { for (int i = index + 1; i < mEditTextList.getChildCount(); i++) {
((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text))
.setIndex(i); .setIndex(i);
//遍历子文本框并设置对应对下标
} }
} }
/*
*
*
*/
private void switchToListMode(String text) { private void switchToListMode(String text) {
mEditTextList.removeAllViews(); mEditTextList.removeAllViews();
String[] items = text.split("\n"); String[] items = text.split("\n");
int index = 0; int index = 0;
//清空所有视图,初始化下标
for (String item : items) { for (String item : items) {
if(!TextUtils.isEmpty(item)) { if(!TextUtils.isEmpty(item)) {
mEditTextList.addView(getListItem(item, index)); mEditTextList.addView(getListItem(item, index));
index++; index++;
//遍历所有文本单元并添加到文本框中
} }
} }
mEditTextList.addView(getListItem("", index)); mEditTextList.addView(getListItem("", index));
mEditTextList.getChildAt(index).findViewById(R.id.et_edit_text).requestFocus(); mEditTextList.getChildAt(index).findViewById(R.id.et_edit_text).requestFocus();
//优先请求此操作
mNoteEditor.setVisibility(View.GONE); mNoteEditor.setVisibility(View.GONE);
//便签编辑器不可见
mEditTextList.setVisibility(View.VISIBLE); mEditTextList.setVisibility(View.VISIBLE);
//将文本编辑框置为可见
} }
/*
*
*
*/
private Spannable getHighlightQueryResult(String fullText, String userQuery) { private Spannable getHighlightQueryResult(String fullText, String userQuery) {
SpannableString spannable = new SpannableString(fullText == null ? "" : fullText); SpannableString spannable = new SpannableString(fullText == null ? "" : fullText);
//新建一个效果选项
if (!TextUtils.isEmpty(userQuery)) { if (!TextUtils.isEmpty(userQuery)) {
mPattern = Pattern.compile(userQuery); mPattern = Pattern.compile(userQuery);
//将用户的询问进行解析
Matcher m = mPattern.matcher(fullText); Matcher m = mPattern.matcher(fullText);
//建立一个状态机检查Pattern并进行匹配
int start = 0; int start = 0;
while (m.find(start)) { while (m.find(start)) {
spannable.setSpan( spannable.setSpan(
new BackgroundColorSpan(this.getResources().getColor( new BackgroundColorSpan(this.getResources().getColor(
R.color.user_query_highlight)), m.start(), m.end(), R.color.user_query_highlight)), m.start(), m.end(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE); Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
//设置背景颜色
start = m.end(); start = m.end();
//跟新起始位置
} }
} }
return spannable; return spannable;
} }
/*
*
*
*/
private View getListItem(String item, int index) { private View getListItem(String item, int index) {
View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null); View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null);
//创建一个视图
final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);
edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId));
//创建一个文本编辑框并设置可见性
CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item)); CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item));
cb.setOnCheckedChangeListener(new OnCheckedChangeListener() { cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
@ -739,12 +871,15 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} }
} }
}); });
//建立一个打钩框并设置监听器
if (item.startsWith(TAG_CHECKED)) { if (item.startsWith(TAG_CHECKED)) {
//选择勾选
cb.setChecked(true); cb.setChecked(true);
edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
item = item.substring(TAG_CHECKED.length(), item.length()).trim(); item = item.substring(TAG_CHECKED.length(), item.length()).trim();
} else if (item.startsWith(TAG_UNCHECKED)) { } else if (item.startsWith(TAG_UNCHECKED)) {
//选择不勾选
cb.setChecked(false); cb.setChecked(false);
edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
item = item.substring(TAG_UNCHECKED.length(), item.length()).trim(); item = item.substring(TAG_UNCHECKED.length(), item.length()).trim();
@ -753,61 +888,94 @@ public class NoteEditActivity extends Activity implements OnClickListener,
edit.setOnTextViewChangeListener(this); edit.setOnTextViewChangeListener(this);
edit.setIndex(index); edit.setIndex(index);
edit.setText(getHighlightQueryResult(item, mUserQuery)); edit.setText(getHighlightQueryResult(item, mUserQuery));
//运行编辑框的监听器对该行为作出反应,并设置下标及文本内容
return view; return view;
} }
/*
* 便
*
*/
public void onTextChange(int index, boolean hasText) { public void onTextChange(int index, boolean hasText) {
if (index >= mEditTextList.getChildCount()) { if (index >= mEditTextList.getChildCount()) {
Log.e(TAG, "Wrong index, should not happen"); Log.e(TAG, "Wrong index, should not happen");
return; return;
//越界报错
} }
if(hasText) { if(hasText) {
mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.VISIBLE); mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.VISIBLE);
} else { } else {
mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.GONE); mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.GONE);
} }
//如果内容不为空则将其子编辑框可见性置为可见,否则不可见
} }
/*
*
*
*/
public void onCheckListModeChanged(int oldMode, int newMode) { public void onCheckListModeChanged(int oldMode, int newMode) {
if (newMode == TextNote.MODE_CHECK_LIST) { if (newMode == TextNote.MODE_CHECK_LIST) {
switchToListMode(mNoteEditor.getText().toString()); switchToListMode(mNoteEditor.getText().toString());
//检查模式切换到列表模式
} else { } else {
if (!getWorkingText()) { if (!getWorkingText()) {
mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ", mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ",
"")); ""));
} }
//若是获取到文本就改变其检查标记
mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery));
mEditTextList.setVisibility(View.GONE); mEditTextList.setVisibility(View.GONE);
mNoteEditor.setVisibility(View.VISIBLE); mNoteEditor.setVisibility(View.VISIBLE);
//修改文本编辑器的内容和可见性
} }
} }
/*
*
*
*/
private boolean getWorkingText() { private boolean getWorkingText() {
boolean hasChecked = false; boolean hasChecked = false;
//初始化check标记
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {
// 若模式为CHECK_LIST
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
//创建可变字符串
for (int i = 0; i < mEditTextList.getChildCount(); i++) { for (int i = 0; i < mEditTextList.getChildCount(); i++) {
View view = mEditTextList.getChildAt(i); View view = mEditTextList.getChildAt(i);
//遍历所有子编辑框的视图
NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);
if (!TextUtils.isEmpty(edit.getText())) { if (!TextUtils.isEmpty(edit.getText())) {
//若文本不为空
if (((CheckBox) view.findViewById(R.id.cb_edit_item)).isChecked()) { if (((CheckBox) view.findViewById(R.id.cb_edit_item)).isChecked()) {
//该选项框已打钩
sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n"); sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n");
hasChecked = true; hasChecked = true;
//扩展字符串为已打钩并把标记置true
} else { } else {
sb.append(TAG_UNCHECKED).append(" ").append(edit.getText()).append("\n"); sb.append(TAG_UNCHECKED).append(" ").append(edit.getText()).append("\n");
//扩展字符串添加未打钩
} }
} }
} }
mWorkingNote.setWorkingText(sb.toString()); mWorkingNote.setWorkingText(sb.toString());
//利用编辑好的字符串设置运行便签的内容
} else { } else {
mWorkingNote.setWorkingText(mNoteEditor.getText().toString()); mWorkingNote.setWorkingText(mNoteEditor.getText().toString());
// 若不是该模式直接用编辑器中的内容设置运行中标签的内容
} }
return hasChecked; return hasChecked;
} }
/*
* 便
*
*/
private boolean saveNote() { private boolean saveNote() {
getWorkingText(); getWorkingText();
boolean saved = mWorkingNote.saveNote(); boolean saved = mWorkingNote.saveNote();
//运行 getWorkingText()之后保存
if (saved) { if (saved) {
/** /**
* There are two modes from List view to edit view, open one note, * There are two modes from List view to edit view, open one note,
@ -816,11 +984,16 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* new node requires to the top of the list. This code * new node requires to the top of the list. This code
* {@link #RESULT_OK} is used to identify the create/edit state * {@link #RESULT_OK} is used to identify the create/edit state
*/ */
//如英文注释所说链接RESULT_OK是为了识别保存的2种情况一是创建后保存二是修改后保存
setResult(RESULT_OK); setResult(RESULT_OK);
} }
return saved; return saved;
} }
/*
* 便
*
*/
private void sendToDesktop() { private void sendToDesktop() {
/** /**
* Before send message to home, we should make sure that current * Before send message to home, we should make sure that current
@ -829,12 +1002,16 @@ public class NoteEditActivity extends Activity implements OnClickListener,
*/ */
if (!mWorkingNote.existInDatabase()) { if (!mWorkingNote.existInDatabase()) {
saveNote(); saveNote();
//若不存在数据也就是新的标签就保存起来先
} }
if (mWorkingNote.getNoteId() > 0) { if (mWorkingNote.getNoteId() > 0) {
//若是有内容
Intent sender = new Intent(); Intent sender = new Intent();
Intent shortcutIntent = new Intent(this, NoteEditActivity.class); Intent shortcutIntent = new Intent(this, NoteEditActivity.class);
//建立发送到桌面的连接器
shortcutIntent.setAction(Intent.ACTION_VIEW); shortcutIntent.setAction(Intent.ACTION_VIEW);
//链接为一个视图
shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId()); shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId());
sender.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); sender.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
sender.putExtra(Intent.EXTRA_SHORTCUT_NAME, sender.putExtra(Intent.EXTRA_SHORTCUT_NAME,
@ -842,9 +1019,12 @@ public class NoteEditActivity extends Activity implements OnClickListener,
sender.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, sender.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
Intent.ShortcutIconResource.fromContext(this, R.drawable.icon_app)); Intent.ShortcutIconResource.fromContext(this, R.drawable.icon_app));
sender.putExtra("duplicate", true); sender.putExtra("duplicate", true);
//将便签的相关信息都添加到要发送的文件里
sender.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); sender.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
//设置sneder的行为是发送
showToast(R.string.info_note_enter_desktop); showToast(R.string.info_note_enter_desktop);
sendBroadcast(sender); sendBroadcast(sender);
//显示到桌面
} else { } else {
/** /**
* There is the condition that user has input nothing (the note is * There is the condition that user has input nothing (the note is
@ -853,21 +1033,35 @@ public class NoteEditActivity extends Activity implements OnClickListener,
*/ */
Log.e(TAG, "Send to desktop error"); Log.e(TAG, "Send to desktop error");
showToast(R.string.error_note_empty_for_send_to_desktop); showToast(R.string.error_note_empty_for_send_to_desktop);
//空便签直接报错
} }
} }
/*
*
*
*/
private String makeShortcutIconTitle(String content) { private String makeShortcutIconTitle(String content) {
content = content.replace(TAG_CHECKED, ""); content = content.replace(TAG_CHECKED, "");
content = content.replace(TAG_UNCHECKED, ""); content = content.replace(TAG_UNCHECKED, "");
return content.length() > SHORTCUT_ICON_TITLE_MAX_LEN ? content.substring(0, return content.length() > SHORTCUT_ICON_TITLE_MAX_LEN ? content.substring(0,
SHORTCUT_ICON_TITLE_MAX_LEN) : content; SHORTCUT_ICON_TITLE_MAX_LEN) : content;
//直接设置为content中的内容并返回有勾选和未勾选2种
} }
/*
*
*
*/
private void showToast(int resId) { private void showToast(int resId) {
showToast(resId, Toast.LENGTH_SHORT); showToast(resId, Toast.LENGTH_SHORT);
} }
/*
*
* duration
*/
private void showToast(int resId, int duration) { private void showToast(int resId, int duration) {
Toast.makeText(this, resId, duration).show(); Toast.makeText(this, resId, duration).show();
} }
} }

@ -1,19 +1,3 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui; package net.micode.notes.ui;
import android.content.Context; import android.content.Context;
@ -37,6 +21,7 @@ import net.micode.notes.R;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
//继承edittext设置便签设置文本框
public class NoteEditText extends EditText { public class NoteEditText extends EditText {
private static final String TAG = "NoteEditText"; private static final String TAG = "NoteEditText";
private int mIndex; private int mIndex;
@ -46,6 +31,7 @@ public class NoteEditText extends EditText {
private static final String SCHEME_HTTP = "http:" ; private static final String SCHEME_HTTP = "http:" ;
private static final String SCHEME_EMAIL = "mailto:" ; private static final String SCHEME_EMAIL = "mailto:" ;
///建立一个字符和整数的hash表用于链接电话网站还有邮箱
private static final Map<String, Integer> sSchemaActionResMap = new HashMap<String, Integer>(); private static final Map<String, Integer> sSchemaActionResMap = new HashMap<String, Integer>();
static { static {
sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel); sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel);
@ -56,17 +42,20 @@ public class NoteEditText extends EditText {
/** /**
* Call by the {@link NoteEditActivity} to delete or add edit text * Call by the {@link NoteEditActivity} to delete or add edit text
*/ */
//在NoteEditActivity中删除或添加文本的操作可以看做是一个文本是否被变的标记英文注释已说明的很清楚
public interface OnTextViewChangeListener { public interface OnTextViewChangeListener {
/** /**
* Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens * Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens
* and the text is null * and the text is null
*/ */
//处理删除按键时的操作
void onEditTextDelete(int index, String text); void onEditTextDelete(int index, String text);
/** /**
* Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER} * Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER}
* happen * happen
*/ */
//处理进入按键时的操作
void onEditTextEnter(int index, String text); void onEditTextEnter(int index, String text);
/** /**
@ -77,33 +66,43 @@ public class NoteEditText extends EditText {
private OnTextViewChangeListener mOnTextViewChangeListener; private OnTextViewChangeListener mOnTextViewChangeListener;
//根据context设置文本
public NoteEditText(Context context) { public NoteEditText(Context context) {
super(context, null); super(context, null);//用super引用父类变量
mIndex = 0; mIndex = 0;
} }
//设置当前光标
public void setIndex(int index) { public void setIndex(int index) {
mIndex = index; mIndex = index;
} }
//初始化文本修改标记
public void setOnTextViewChangeListener(OnTextViewChangeListener listener) { public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
mOnTextViewChangeListener = listener; mOnTextViewChangeListener = listener;
} }
public NoteEditText(Context context, AttributeSet attrs) { //AttributeSet 百度了一下是自定义空控件属性,用于维护便签动态变化的属性
//初始化便签
public NoteEditText(Context context, AttributeSet attrs) {
super(context, attrs, android.R.attr.editTextStyle); super(context, attrs, android.R.attr.editTextStyle);
} }
// 根据defstyle自动初始化
public NoteEditText(Context context, AttributeSet attrs, int defStyle) { public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
// TODO Auto-generated constructor stub // TODO Auto-generated construct or stub
} }
@Override @Override
//view里的函数处理手机屏幕的所有事件
/*event
*/
public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) { switch (event.getAction()) {
//重写了需要处理屏幕被按下的事件
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
//跟新当前坐标值
int x = (int) event.getX(); int x = (int) event.getX();
int y = (int) event.getY(); int y = (int) event.getY();
x -= getTotalPaddingLeft(); x -= getTotalPaddingLeft();
@ -111,9 +110,12 @@ public class NoteEditText extends EditText {
x += getScrollX(); x += getScrollX();
y += getScrollY(); y += getScrollY();
//用布局控件layout根据x,y的新值设置新的位置
Layout layout = getLayout(); Layout layout = getLayout();
int line = layout.getLineForVertical(y); int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x); int off = layout.getOffsetForHorizontal(line, x);
//更新光标新的位置
Selection.setSelection(getText(), off); Selection.setSelection(getText(), off);
break; break;
} }
@ -122,96 +124,147 @@ public class NoteEditText extends EditText {
} }
@Override @Override
/*
*
*
*/
public boolean onKeyDown(int keyCode, KeyEvent event) { public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) { switch (keyCode) {
//根据按键的 Unicode 编码值来处理
case KeyEvent.KEYCODE_ENTER: case KeyEvent.KEYCODE_ENTER:
//“进入”按键
if (mOnTextViewChangeListener != null) { if (mOnTextViewChangeListener != null) {
return false; return false;
} }
break; break;
case KeyEvent.KEYCODE_DEL: case KeyEvent.KEYCODE_DEL:
//“删除”按键
mSelectionStartBeforeDelete = getSelectionStart(); mSelectionStartBeforeDelete = getSelectionStart();
break; break;
default: default:
break; break;
} }
//继续执行父类的其他点击事件
return super.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event);
} }
@Override @Override
/*
*
*
*/
public boolean onKeyUp(int keyCode, KeyEvent event) { public boolean onKeyUp(int keyCode, KeyEvent event) {
switch(keyCode) { switch(keyCode) {
//根据按键的 Unicode 编码值来处理有删除和进入2种操作
case KeyEvent.KEYCODE_DEL: case KeyEvent.KEYCODE_DEL:
if (mOnTextViewChangeListener != null) { if (mOnTextViewChangeListener != null) {
//若是被修改过
if (0 == mSelectionStartBeforeDelete && mIndex != 0) { if (0 == mSelectionStartBeforeDelete && mIndex != 0) {
//若之前有被修改并且文档不为空
mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString()); mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString());
//利用上文OnTextViewChangeListener对KEYCODE_DEL按键情况的删除函数进行删除
return true; return true;
} }
} else { } else {
Log.d(TAG, "OnTextViewChangeListener was not seted"); Log.d(TAG, "OnTextViewChangeListener was not seted");
//其他情况报错,文档的改动监听器并没有建立
} }
break; break;
case KeyEvent.KEYCODE_ENTER: case KeyEvent.KEYCODE_ENTER:
//同上也是分为监听器是否建立2种情况
if (mOnTextViewChangeListener != null) { if (mOnTextViewChangeListener != null) {
int selectionStart = getSelectionStart(); int selectionStart = getSelectionStart();
//获取当前位置
String text = getText().subSequence(selectionStart, length()).toString(); String text = getText().subSequence(selectionStart, length()).toString();
//获取当前文本
setText(getText().subSequence(0, selectionStart)); setText(getText().subSequence(0, selectionStart));
//根据获取的文本设置当前文本
mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text); mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text);
//当{@link KeyEvent#KEYCODE_ENTER}添加新文本
} else { } else {
Log.d(TAG, "OnTextViewChangeListener was not seted"); Log.d(TAG, "OnTextViewChangeListener was not seted");
//其他情况报错,文档的改动监听器并没有建立
} }
break; break;
default: default:
break; break;
} }
//继续执行父类的其他按键弹起的事件
return super.onKeyUp(keyCode, event); return super.onKeyUp(keyCode, event);
} }
@Override @Override
/*
*
*
* focusedViewFocusedtruefalse
direction
RectViewnull
*/
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
if (mOnTextViewChangeListener != null) { if (mOnTextViewChangeListener != null) {
//若监听器已经建立
if (!focused && TextUtils.isEmpty(getText())) { if (!focused && TextUtils.isEmpty(getText())) {
//获取到焦点并且文本不为空
mOnTextViewChangeListener.onTextChange(mIndex, false); mOnTextViewChangeListener.onTextChange(mIndex, false);
//mOnTextViewChangeListener子函数置false隐藏事件选项
} else { } else {
mOnTextViewChangeListener.onTextChange(mIndex, true); mOnTextViewChangeListener.onTextChange(mIndex, true);
//mOnTextViewChangeListener子函数置true显示事件选项
} }
} }
//继续执行父类的其他焦点变化的事件
super.onFocusChanged(focused, direction, previouslyFocusedRect); super.onFocusChanged(focused, direction, previouslyFocusedRect);
} }
@Override @Override
/*
*
*
*/
protected void onCreateContextMenu(ContextMenu menu) { protected void onCreateContextMenu(ContextMenu menu) {
if (getText() instanceof Spanned) { if (getText() instanceof Spanned) {
//有文本存在
int selStart = getSelectionStart(); int selStart = getSelectionStart();
int selEnd = getSelectionEnd(); int selEnd = getSelectionEnd();
//获取文本开始和结尾位置
int min = Math.min(selStart, selEnd); int min = Math.min(selStart, selEnd);
int max = Math.max(selStart, selEnd); int max = Math.max(selStart, selEnd);
//获取开始到结尾的最大值和最小值
final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class); final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class);
//设置url的信息的范围值
if (urls.length == 1) { if (urls.length == 1) {
int defaultResId = 0; int defaultResId = 0;
for(String schema: sSchemaActionResMap.keySet()) { for(String schema: sSchemaActionResMap.keySet()) {
//获取计划表中所有的key值
if(urls[0].getURL().indexOf(schema) >= 0) { if(urls[0].getURL().indexOf(schema) >= 0) {
//若url可以添加则在添加后将defaultResId置为key所映射的值
defaultResId = sSchemaActionResMap.get(schema); defaultResId = sSchemaActionResMap.get(schema);
break; break;
} }
} }
if (defaultResId == 0) { if (defaultResId == 0) {
//defaultResId == 0则说明url并没有添加任何东西所以置为连接其他SchemaActionResMap的值
defaultResId = R.string.note_link_other; defaultResId = R.string.note_link_other;
} }
//建立菜单
menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener( menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener(
new OnMenuItemClickListener() { new OnMenuItemClickListener() {
//新建按键监听器
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {
// goto a new intent // goto a new intent
urls[0].onClick(NoteEditText.this); urls[0].onClick(NoteEditText.this);
//根据相应的文本设置菜单的按键
return true; return true;
} }
}); });
} }
} }
//继续执行父类的其他菜单创建的事件
super.onCreateContextMenu(menu); super.onCreateContextMenu(menu);
} }
} }

@ -28,18 +28,18 @@ import net.micode.notes.tool.DataUtils;
public class NoteItemData { public class NoteItemData {
static final String [] PROJECTION = new String [] { static final String [] PROJECTION = new String [] {
NoteColumns.ID, NoteColumns.ID,
NoteColumns.ALERTED_DATE, NoteColumns.ALERTED_DATE,
NoteColumns.BG_COLOR_ID, NoteColumns.BG_COLOR_ID,
NoteColumns.CREATED_DATE, NoteColumns.CREATED_DATE,
NoteColumns.HAS_ATTACHMENT, NoteColumns.HAS_ATTACHMENT,
NoteColumns.MODIFIED_DATE, NoteColumns.MODIFIED_DATE,
NoteColumns.NOTES_COUNT, NoteColumns.NOTES_COUNT,
NoteColumns.PARENT_ID, NoteColumns.PARENT_ID,
NoteColumns.SNIPPET, NoteColumns.SNIPPET,
NoteColumns.TYPE, NoteColumns.TYPE,
NoteColumns.WIDGET_ID, NoteColumns.WIDGET_ID,
NoteColumns.WIDGET_TYPE, NoteColumns.WIDGET_TYPE,
}; };
private static final int ID_COLUMN = 0; private static final int ID_COLUMN = 0;

File diff suppressed because it is too large Load Diff

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="#88555555" />
<item android:state_selected="true" android:color="#ff999999" />
<item android:color="#ff000000" />
</selector>

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#50000000" />
</selector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 554 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save