Compare commits

...

24 Commits

9
doc/.gitignore vendored

@ -1,9 +0,0 @@
# generated files
bin/
gen/
# Local configuration file (sdk path, etc)
project.properties
.settings/
.classpath
.project

@ -1,150 +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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.micode.notes"
android:versionCode="1"
android:versionName="0.1" >
<uses-sdk android:minSdkVersion="14" />
<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:icon="@drawable/icon_app"
android:label="@string/app_name" >
<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" >
<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" >
<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" >
<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" >
<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" >
<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" />
</application>
</manifest>

@ -1,190 +0,0 @@
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.
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.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

@ -1,23 +0,0 @@
[中文]
1. MiCode便签是小米便签的社区开源版由MIUI团队(www.miui.com) 发起并贡献第一批代码遵循NOTICE文件所描述的开源协议
今后为MiCode社区(www.micode.net) 拥有,并由社区发布和维护。
2. Bug反馈和跟踪请访问Github,
https://github.com/MiCode/Notes/issues?sort=created&direction=desc&state=open
3. 功能建议和综合讨论请访问MiCode,
http://micode.net/forum.php?mod=forumdisplay&fid=38
[English]
1. MiCode Notes is open source edition of XM notepad, it's first initiated and sponsored by MIUI team (www.miui.com).
It's opened under license described by NOTICE file. It's owned by the MiCode community (www.micode.net). In future,
the MiCode community will release and maintain this project.
2. Regarding issue tracking, please visit Github,
https://github.com/MiCode/Notes/issues?sort=created&direction=desc&state=open
3. Regarding feature request and general discussion, please visit Micode forum,
http://micode.net/forum.php?mod=forumdisplay&fid=38

Binary file not shown.

@ -17,6 +17,7 @@
package net.micode.notes.data; package net.micode.notes.data;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Data; import android.provider.ContactsContract.Data;
@ -24,29 +25,35 @@ import android.telephony.PhoneNumberUtils;
import android.util.Log; import android.util.Log;
import java.util.HashMap; import java.util.HashMap;
//change
public class Contact { public class Contact { //联系人
private static HashMap<String, String> sContactCache; private static HashMap<String, String> sContactCache;
private static final String TAG = "Contact"; private static final String TAG = "Contact";
private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER // 定义字符串CALLER_ID_SELECTION
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>();
} }
// 查找HashMap中是否已有phoneNumber信息
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));
// 查找数据库中phoneNumber的信息
Cursor cursor = context.getContentResolver().query( Cursor cursor = context.getContentResolver().query(
Data.CONTENT_URI, Data.CONTENT_URI,
new String [] { Phone.DISPLAY_NAME }, new String [] { Phone.DISPLAY_NAME },
@ -54,17 +61,22 @@ public class Contact {
new String[] { phoneNumber }, new String[] { phoneNumber },
null); null);
// 判定查询结果
// moveToFirst()返回第一条
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
try { try {
// 找到相关信息
String name = cursor.getString(0); String name = cursor.getString(0);
sContactCache.put(phoneNumber, name); sContactCache.put(phoneNumber, name);
return name; return name;
// 异常
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
Log.e(TAG, " Cursor get string error " + e.toString()); Log.e(TAG, " Cursor get string error " + e.toString());
return null; return null;
} finally { } finally {
cursor.close(); cursor.close();
} }
// 未找到相关信息
} else { } else {
Log.d(TAG, "No contact matched with number:" + phoneNumber); Log.d(TAG, "No contact matched with number:" + phoneNumber);
return null; return null;

@ -16,10 +16,14 @@
package net.micode.notes.data; package net.micode.notes.data;
import android.content.ContentUris;
import android.net.Uri; import android.net.Uri;
// Notes 类中定义了很多常量这些常量大多是int型和string型
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";
//以下三个常量对NoteColumns.TYPE的值进行设置时会用到
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;
@ -35,12 +39,24 @@ public class Notes {
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 =
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"; "net.micode.notes.alert_date";
public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type"; public static final String INTENT_EXTRA_BACKGROUND_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"; "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_TYPE =
"net.micode.notes.widget_type";
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 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;
@ -54,13 +70,20 @@ public class Notes {
/** /**
* Uri to query all notes and folders * Uri to query all notes and folders
*/ */
public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note"); public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" +
AUTHORITY + "/note");//定义查询便签和文件夹的指针。
// public static final Uri my_URI = ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI , 10);
/** /**
* Uri to query data * Uri to query data
*/ */
public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); public static final Uri CONTENT_DATA_URI = Uri.parse("content://" +
AUTHORITY + "/data");//定义查找数据的指针。
// 定义NoteColumns的常量,用于后面创建数据库的表头
public interface NoteColumns { public interface NoteColumns {
/** /**
* The unique ID for a row * The unique ID for a row
@ -72,7 +95,7 @@ public class Notes {
* The parent's id for note or folder * The parent's id for note or folder
* <P> Type: INTEGER (long) </P> * <P> Type: INTEGER (long) </P>
*/ */
public static final String PARENT_ID = "parent_id"; public static final String PARENT_ID = "parent_id";//为什么会有parent_id
/** /**
* Created data for note or folder * Created data for note or folder
@ -140,7 +163,7 @@ public class Notes {
* The last sync id * The last sync id
* <P> Type: INTEGER (long) </P> * <P> Type: INTEGER (long) </P>
*/ */
public static final String SYNC_ID = "sync_id"; public static final String SYNC_ID = "sync_id";//同步
/** /**
* Sign to indicate local modified or not * Sign to indicate local modified or not
@ -165,8 +188,9 @@ public class Notes {
* <P> Type : INTEGER (long) </P> * <P> Type : INTEGER (long) </P>
*/ */
public static final String VERSION = "version"; public static final String VERSION = "version";
} }//这些常量主要是定义便签的属性的。
// 定义DataColumns的常量,用于后面创建数据库的表头
public interface DataColumns { public interface DataColumns {
/** /**
* The unique ID for a row * The unique ID for a row
@ -206,41 +230,45 @@ public class Notes {
/** /**
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for * Generic data column, the meaning is {@link #MIMETYPE} specific,
used for
* integer data type * integer data type
* <P> Type: INTEGER </P> * <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 * Generic data column, the meaning is {@link #MIMETYPE} specific,
used for
* integer data type * integer data type
* <P> Type: INTEGER </P> * <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 * Generic data column, the meaning is {@link #MIMETYPE} specific,
used for
* TEXT data type * TEXT data type
* <P> Type: TEXT </P> * <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 * Generic data column, the meaning is {@link #MIMETYPE} specific,
used for
* TEXT data type * TEXT data type
* <P> Type: TEXT </P> * <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 * Generic data column, the meaning is {@link #MIMETYPE} specific,
used for
* TEXT data type * TEXT data type
* <P> Type: TEXT </P> * <P> Type: TEXT </P>
*/ */
public static final String DATA5 = "data5"; public static final String DATA5 = "data5";
} }//主要是定义存储便签内容数据的
public static final class TextNote implements DataColumns { public static final class TextNote implements DataColumns {
/** /**
* Mode to indicate the text in check list mode or not * Mode to indicate the text in check list mode or not
@ -250,12 +278,18 @@ public class Notes {
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 =
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; "vnd.android.cursor.dir/text_note";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); public static final String CONTENT_ITEM_TYPE =
}
"vnd.android.cursor.item/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 {
/** /**
@ -270,10 +304,16 @@ public class Notes {
*/ */
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 =
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note"; "vnd.android.cursor.dir/call_note";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note"); public static final String CONTENT_ITEM_TYPE =
}
"vnd.android.cursor.item/call_note";
public static final Uri CONTENT_URI = Uri.parse("content://" +
AUTHORITY + "/call_note");
}//电话内容的数据结构
} }

@ -16,23 +16,23 @@
package net.micode.notes.data; package net.micode.notes.data;
import android.content.ContentValues; import android.content.ContentValues;//就是用于保存一些数据string boolean byte double float int long short ...)信息,这些信息可以被数据库操作时使用。
import android.content.Context; import android.content.Context;//加载和访问资源。android中主要是这两个功能但是这里具体不清楚
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;//主要提供了对应于添加、删除、更新、查询的操作方法: insert()、delete()、update()和query()。配合content.values
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;//用来管理数据的创建和版本更新
import android.util.Log; import android.util.Log;
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;
//数据库操作用SQLOpenhelper,对一些note和文件进行数据库的操作比如删除文件后将文件里的note也相应删除
public class NotesDatabaseHelper extends SQLiteOpenHelper { public class NotesDatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "note.db"; private static final String DB_NAME = "note.db";
private static final int DB_VERSION = 4; private static final int DB_VERSION = 4;
public interface TABLE { public interface TABLE { //接口分成note和data在后面的程序里分别使用过
public static final String NOTE = "note"; public static final String NOTE = "note";
public static final String DATA = "data"; public static final String DATA = "data";
@ -61,7 +61,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +
")"; ")";//数据库中需要存储的项目的名称,就相当于创建一个表格的表头的内容。
private static final String CREATE_DATA_TABLE_SQL = private static final String CREATE_DATA_TABLE_SQL =
"CREATE TABLE " + TABLE.DATA + "(" + "CREATE TABLE " + TABLE.DATA + "(" +
@ -76,11 +76,11 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" +
")"; ")";//和上面的功能一样,主要是存储的项目不同
private static final String CREATE_DATA_NOTE_ID_INDEX_SQL = private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
"CREATE INDEX IF NOT EXISTS note_id_index ON " + "CREATE INDEX IF NOT EXISTS note_id_index ON " +
TABLE.DATA + "(" + DataColumns.NOTE_ID + ");"; TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";//存储便签编号的一个数据表格
/** /**
* Increase folder's note count when move note to the folder * Increase folder's note count when move note to the folder
@ -92,7 +92,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" UPDATE " + TABLE.NOTE + " UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END"; " END";//在文件夹中移入一个Note之后需要更改的数据的表格。
/** /**
* Decrease folder's note count when move note from folder * Decrease folder's note count when move note from folder
@ -105,7 +105,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" +
" END"; " END";//在文件夹中移出一个Note之后需要更改的数据的表格。
/** /**
* Increase folder's note count when insert new note to the folder * Increase folder's note count when insert new note to the folder
@ -117,7 +117,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" UPDATE " + TABLE.NOTE + " UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END"; " END";//在文件夹中插入一个Note之后需要更改的数据的表格。
/** /**
* Decrease folder's note count when delete note from the folder * Decrease folder's note count when delete note from the folder
@ -130,7 +130,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0;" + " AND " + NoteColumns.NOTES_COUNT + ">0;" +
" END"; " END";//在文件夹中删除一个Note之后需要更改的数据的表格。
/** /**
* Update note's content when insert data with type {@link DataConstants#NOTE} * Update note's content when insert data with type {@link DataConstants#NOTE}
@ -143,7 +143,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" UPDATE " + TABLE.NOTE + " UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END"; " END";//在文件夹中对一个Note导入新的数据之后需要更改的数据的表格。
/** /**
* 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
@ -156,7 +156,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" UPDATE " + TABLE.NOTE + " UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END"; " END";//Note数据被修改后需要更改的数据的表格。
/** /**
* 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
@ -169,7 +169,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" UPDATE " + TABLE.NOTE + " UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=''" + " SET " + NoteColumns.SNIPPET + "=''" +
" WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" +
" END"; " END";//Note数据被删除后需要更改的数据的表格。
/** /**
* Delete datas belong to note which has been deleted * Delete datas belong to note which has been deleted
@ -180,7 +180,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" BEGIN" + " BEGIN" +
" DELETE FROM " + TABLE.DATA + " DELETE FROM " + TABLE.DATA +
" WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" +
" END"; " END";//删除已删除的便签的数据后需要更改的数据的表格。
/** /**
* Delete notes belong to folder which has been deleted * Delete notes belong to folder which has been deleted
@ -191,7 +191,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" BEGIN" + " BEGIN" +
" DELETE FROM " + TABLE.NOTE + " DELETE FROM " + TABLE.NOTE +
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END"; " END";//删除已删除的文件夹的便签后需要更改的数据的表格。
/** /**
* Move notes belong to folder which has been moved to trash folder * Move notes belong to folder which has been moved to trash folder
@ -204,18 +204,18 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" UPDATE " + TABLE.NOTE + " UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + " SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END"; " END";//还原垃圾桶中便签后需要更改的数据的表格。
public NotesDatabaseHelper(Context context) { public NotesDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION); super(context, DB_NAME, null, DB_VERSION);
} }//构造函数,传入数据库的名称和版本
public void createNoteTable(SQLiteDatabase db) { public void createNoteTable(SQLiteDatabase db) {
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");
@ -233,7 +233,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER); db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER);
db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER); db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER);
db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
} }//execSQL是数据库操作的API主要是更改行为的SQL语句。
//在这里主要是用来重新创建上述定义的表格用的,先删除原来有的数据库的触发器再重新创建新的数据库
private void createSystemFolder(SQLiteDatabase db) { private void createSystemFolder(SQLiteDatabase db) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
@ -268,14 +269,14 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values); db.insert(TABLE.NOTE, null, values);
} }//创建几个系统文件夹
public void createDataTable(SQLiteDatabase db) { public void createDataTable(SQLiteDatabase db) {
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");
@ -285,20 +286,22 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER); db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER); db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER);
} }//同上面的execSQL
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);
} }
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) {
@ -331,14 +334,14 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
throw new IllegalStateException("Upgrade notes database to version " + newVersion throw new IllegalStateException("Upgrade notes database to version " + newVersion
+ "fails"); + "fails");
} }
} }//数据库版本的更新(数据库内容的更改)
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);
createNoteTable(db); createNoteTable(db);
createDataTable(db); createDataTable(db);
} }//更新到V2版本
private void upgradeToV3(SQLiteDatabase db) { private void upgradeToV3(SQLiteDatabase db) {
// drop unused triggers // drop unused triggers
@ -353,10 +356,10 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values); db.insert(TABLE.NOTE, null, values);
} }//更新到V3版本
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");
} }//更新到V4版本,但是不知道V2、V3、V4是什么意思
} }

@ -16,7 +16,6 @@
package net.micode.notes.data; package net.micode.notes.data;
import android.app.SearchManager; import android.app.SearchManager;
import android.content.ContentProvider; import android.content.ContentProvider;
import android.content.ContentUris; import android.content.ContentUris;
@ -33,9 +32,15 @@ import net.micode.notes.R;
import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.NotesDatabaseHelper.TABLE; import net.micode.notes.data.NotesDatabaseHelper.TABLE;
//为存储和获取数据提供接口。可以在不同的应用程序之间共享数据
//ContentProvider提供的方法
//query查询
//insert插入
//update更新
//delete删除
//getType得到数据类型
public class NotesProvider extends ContentProvider { public class NotesProvider extends ContentProvider {
// UriMatcher用于匹配Uri
private static final UriMatcher mMatcher; private static final UriMatcher mMatcher;
private NotesDatabaseHelper mHelper; private NotesDatabaseHelper mHelper;
@ -51,7 +56,9 @@ public class NotesProvider extends ContentProvider {
private static final int URI_SEARCH_SUGGEST = 6; private static final int URI_SEARCH_SUGGEST = 6;
static { static {
// 创建UriMatcher时调用UriMatcher(UriMatcher.NO_MATCH)表示不匹配任何路径的返回码
mMatcher = new UriMatcher(UriMatcher.NO_MATCH); mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 把需要匹配Uri路径全部给注册上
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE);
mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM);
mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA);
@ -65,6 +72,7 @@ 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.
*/ */
// 声明 NOTES_SEARCH_PROJECTION
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 + ","
@ -72,7 +80,7 @@ public class NotesProvider extends ContentProvider {
+ R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + "," + R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + ","
+ "'" + 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;
// 声明NOTES_SNIPPET_SEARCH_QUERY
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 ?"
@ -80,18 +88,24 @@ public class NotesProvider extends ContentProvider {
+ " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE;
@Override @Override
// Context只有在onCreate()中才被初始化
// 对mHelper进行实例化
public boolean onCreate() { public boolean onCreate() {
mHelper = NotesDatabaseHelper.getInstance(getContext()); mHelper = NotesDatabaseHelper.getInstance(getContext());
return true; return true;
} }
@Override @Override
// 查询uri在数据库中对应的位置
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) {
Cursor c = null; Cursor c = null;
// 获取可读数据库
SQLiteDatabase db = mHelper.getReadableDatabase(); SQLiteDatabase db = mHelper.getReadableDatabase();
String id = null; String id = null;
// 匹配查找uri
switch (mMatcher.match(uri)) { switch (mMatcher.match(uri)) {
// 对于不同的匹配值,在数据库中查找相应的条目
case URI_NOTE: case URI_NOTE:
c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null,
sortOrder); sortOrder);
@ -113,6 +127,7 @@ public class NotesProvider extends ContentProvider {
case URI_SEARCH: case URI_SEARCH:
case URI_SEARCH_SUGGEST: case URI_SEARCH_SUGGEST:
if (sortOrder != null || projection != null) { if (sortOrder != null || projection != null) {
// 不合法的参数异常
throw new IllegalArgumentException( throw new IllegalArgumentException(
"do not specify sortOrder, selection, selectionArgs, or projection" + "with this query"); "do not specify sortOrder, selection, selectionArgs, or projection" + "with this query");
} }
@ -120,6 +135,8 @@ public class NotesProvider extends ContentProvider {
String searchString = null; String searchString = null;
if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) {
if (uri.getPathSegments().size() > 1) { if (uri.getPathSegments().size() > 1) {
// getPathSegments()方法得到一个String的List
// 在uri.getPathSegments().get(1)为第2个元素
searchString = uri.getPathSegments().get(1); searchString = uri.getPathSegments().get(1);
} }
} else { } else {
@ -139,6 +156,7 @@ public class NotesProvider extends ContentProvider {
} }
break; break;
default: default:
// 抛出异常
throw new IllegalArgumentException("Unknown URI " + uri); throw new IllegalArgumentException("Unknown URI " + uri);
} }
if (c != null) { if (c != null) {
@ -148,13 +166,17 @@ public class NotesProvider extends ContentProvider {
} }
@Override @Override
// 插入一个uri
public Uri insert(Uri uri, ContentValues values) { public Uri insert(Uri uri, ContentValues values) {
// 获得可写的数据库
SQLiteDatabase db = mHelper.getWritableDatabase(); SQLiteDatabase db = mHelper.getWritableDatabase();
long dataId = 0, noteId = 0, insertedId = 0; long dataId = 0, noteId = 0, insertedId = 0;
switch (mMatcher.match(uri)) { switch (mMatcher.match(uri)) {
// 新增一个条目
case URI_NOTE: case URI_NOTE:
insertedId = noteId = db.insert(TABLE.NOTE, null, values); insertedId = noteId = db.insert(TABLE.NOTE, null, values);
break; break;
// 如果存在查找NOTE_ID
case URI_DATA: case URI_DATA:
if (values.containsKey(DataColumns.NOTE_ID)) { if (values.containsKey(DataColumns.NOTE_ID)) {
noteId = values.getAsLong(DataColumns.NOTE_ID); noteId = values.getAsLong(DataColumns.NOTE_ID);
@ -167,6 +189,7 @@ public class NotesProvider extends ContentProvider {
throw new IllegalArgumentException("Unknown URI " + uri); throw new IllegalArgumentException("Unknown URI " + uri);
} }
// Notify the note uri // Notify the note uri
// notifyChange获得一个ContextResolver对象并且更新里面的内容
if (noteId > 0) { if (noteId > 0) {
getContext().getContentResolver().notifyChange( getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
@ -178,13 +201,17 @@ public class NotesProvider extends ContentProvider {
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
} }
// 返回插入的uri的路径
return ContentUris.withAppendedId(uri, insertedId); return ContentUris.withAppendedId(uri, insertedId);
} }
@Override @Override
// 删除一个uri
public int delete(Uri uri, String selection, String[] selectionArgs) { public int delete(Uri uri, String selection, String[] selectionArgs) {
//Uri代表要操作的数据Android上可用的每种资源 -包括 图像、视频片段、音频资源等都可以用Uri来表示。
int count = 0; int count = 0;
String id = null; String id = null;
// 获得可写的数据库
SQLiteDatabase db = mHelper.getWritableDatabase(); SQLiteDatabase db = mHelper.getWritableDatabase();
boolean deleteData = false; boolean deleteData = false;
switch (mMatcher.match(uri)) { switch (mMatcher.match(uri)) {
@ -228,6 +255,7 @@ public class NotesProvider extends ContentProvider {
} }
@Override @Override
// 更新一个uri
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;
String id = null; String id = null;
@ -267,10 +295,12 @@ 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 + ')' : "");
} }
//增加一个noteVersion
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 ");
@ -293,6 +323,7 @@ public class NotesProvider extends ContentProvider {
sql.append(selectString); sql.append(selectString);
} }
// execSQL()方法可以执行insert、delete、update和CREATE TABLE之类有更改行为的SQL语句
mHelper.getWritableDatabase().execSQL(sql.toString()); mHelper.getWritableDatabase().execSQL(sql.toString());
} }

@ -1,43 +1,21 @@
/*
* 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.model; package net.micode.notes.model;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.net.Uri;
import android.os.RemoteException;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.Notes.TextNote;
import java.util.ArrayList;
import android.content.ContentProviderOperation;//批量的更新、插入、删除数据。
import android.content.ContentProviderResult;//操作的结果
import android.content.ContentUris;//用于添加和获取Uri后面的ID
import android.content.ContentValues;//一种用来存储基本数据类型数据的存储机制
import android.content.Context;//需要用该类来弄清楚调用者的实例
import android.content.OperationApplicationException;//操作应用程序容错
import android.net.Uri;//表示待操作的数据
import android.os.RemoteException;//远程容错
import android.util.Log;//输出日志,比如说出错、警告等
public class Note { public class Note {
private ContentValues mNoteDiffValues; // private ContentValues mNoteDiffValues;
ContentValues mNoteDiffValues;//
private NoteData mNoteData; private NoteData mNoteData;
private static final String TAG = "Note"; private static final String TAG = "Note";
/** /**
* Create a new note id for adding a new note to databases * Create a new note id for adding a new note to databases
*/ */
@ -49,16 +27,17 @@ 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 {
noteId = Long.valueOf(uri.getPathSegments().get(1)); noteId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString()); Log.e(TAG, "Get note id error :" + e.toString());
noteId = 0; noteId = 0;
} }//try-catch异常处理
if (noteId == -1) { if (noteId == -1) {
throw new IllegalStateException("Wrong note id:" + noteId); throw new IllegalStateException("Wrong note id:" + noteId);
} }
@ -68,37 +47,37 @@ public class Note {
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) { public void setTextDataId(long id) {
mNoteData.setTextDataId(id); mNoteData.setTextDataId(id);
} }//设置文本数据的ID
public long getTextDataId() { public long getTextDataId() {
return mNoteData.mTextDataId; return mNoteData.mTextDataId;
} }//得到文本数据的ID
public void setCallDataId(long id) { public void setCallDataId(long id) {
mNoteData.setCallDataId(id); mNoteData.setCallDataId(id);
} }//设置电话号码数据的ID
public void setCallData(String key, String value) { public void setCallData(String key, String value) {
mNoteData.setCallData(key, value); mNoteData.setCallData(key, value);
} }//得到电话号码数据的ID
public boolean isLocalModified() { public boolean isLocalModified() {
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified(); return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
} }//判断是否是本地修改
public boolean syncNote(Context context, long noteId) { public boolean syncNote(Context context, long noteId) {
if (noteId <= 0) { if (noteId <= 0) {
@ -128,16 +107,16 @@ public class Note {
} }
return true; return true;
} }//判断数据是否同步
private class NoteData { private class NoteData {//定义一个基本的便签内容的数据类,主要包含文本数据和电话号码数据
private long mTextDataId; private long mTextDataId;
private ContentValues mTextDataValues; private ContentValues mTextDataValues;//文本数据
private long mCallDataId; private long mCallDataId;
private ContentValues mCallDataValues; private ContentValues mCallDataValues;//电话号码数据
private static final String TAG = "NoteData"; private static final String TAG = "NoteData";
@ -147,7 +126,7 @@ public class Note {
mTextDataId = 0; mTextDataId = 0;
mCallDataId = 0; mCallDataId = 0;
} }
//下面是上述几个函数的具体实现
boolean isLocalModified() { boolean isLocalModified() {
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0; return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
} }
@ -177,17 +156,17 @@ 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
*/ */
if (noteId <= 0) { if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId); throw new IllegalArgumentException("Wrong note id:" + noteId);
} }//判断数据是否合法
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>(); ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
ContentProviderOperation.Builder builder = null; ContentProviderOperation.Builder builder = null;//数据库的操作列表
if(mTextDataValues.size() > 0) { if(mTextDataValues.size() > 0) {
mTextDataValues.put(DataColumns.NOTE_ID, noteId); mTextDataValues.put(DataColumns.NOTE_ID, noteId);
@ -209,7 +188,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);
@ -231,7 +210,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 {
@ -246,7 +225,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;
} }
} }

@ -1,37 +1,5 @@
/*
* 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.model; package net.micode.notes.model;
import android.appwidget.AppWidgetManager;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.Notes.TextNote;
import net.micode.notes.tool.ResourceParser.NoteBgResources;
public class WorkingNote { public class WorkingNote {
// Note for the working note // Note for the working note
private Note mNote; private Note mNote;
@ -43,17 +11,11 @@ public class WorkingNote {
private int mMode; private int mMode;
private long mAlertDate; private long mAlertDate;
private long mModifiedDate; private long mModifiedDate;
private int mBgColorId; private int mBgColorId;
private int mWidgetId; private int mWidgetId;
private int mWidgetType; private int mWidgetType;
private long mFolderId; private long mFolderId;
private Context mContext; private Context mContext;
private static final String TAG = "WorkingNote"; private static final String TAG = "WorkingNote";
@ -62,6 +24,7 @@ public class WorkingNote {
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,
@ -72,6 +35,7 @@ public class WorkingNote {
DataColumns.DATA4, DataColumns.DATA4,
}; };
// 声明 NOTE_PROJECTION字符串数组
public static final String[] NOTE_PROJECTION = new String[] { public static final String[] NOTE_PROJECTION = new String[] {
NoteColumns.PARENT_ID, NoteColumns.PARENT_ID,
NoteColumns.ALERTED_DATE, NoteColumns.ALERTED_DATE,
@ -82,27 +46,18 @@ public class WorkingNote {
}; };
private static final int DATA_ID_COLUMN = 0; private static final int DATA_ID_COLUMN = 0;
private static final int DATA_CONTENT_COLUMN = 1; private static final int DATA_CONTENT_COLUMN = 1;
private static final int DATA_MIME_TYPE_COLUMN = 2; private static final int DATA_MIME_TYPE_COLUMN = 2;
private static final int DATA_MODE_COLUMN = 3; private static final int DATA_MODE_COLUMN = 3;
private static final int NOTE_PARENT_ID_COLUMN = 0; private static final int NOTE_PARENT_ID_COLUMN = 0;
private static final int NOTE_ALERTED_DATE_COLUMN = 1; private static final int NOTE_ALERTED_DATE_COLUMN = 1;
private static final int NOTE_BG_COLOR_ID_COLUMN = 2; private static final int NOTE_BG_COLOR_ID_COLUMN = 2;
private static final int NOTE_WIDGET_ID_COLUMN = 3; private static final int NOTE_WIDGET_ID_COLUMN = 3;
private static final int NOTE_WIDGET_TYPE_COLUMN = 4; private static final int NOTE_WIDGET_TYPE_COLUMN = 4;
private static final int NOTE_MODIFIED_DATE_COLUMN = 5; private static final int NOTE_MODIFIED_DATE_COLUMN = 5;
// New note construct // New note construct
private WorkingNote(Context context, long folderId) { public WorkingNote(Context context, long folderId) {
mContext = context; mContext = context;
mAlertDate = 0; mAlertDate = 0;
mModifiedDate = System.currentTimeMillis(); mModifiedDate = System.currentTimeMillis();
@ -114,6 +69,7 @@ public class WorkingNote {
mWidgetType = Notes.TYPE_WIDGET_INVALIDE; mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
} }
// WorkingNote的构造函数
// Existing note construct // Existing note construct
private WorkingNote(Context context, long noteId, long folderId) { private WorkingNote(Context context, long noteId, long folderId) {
mContext = context; mContext = context;
@ -124,11 +80,14 @@ public class WorkingNote {
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);
@ -139,6 +98,7 @@ 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);
@ -146,6 +106,7 @@ public class WorkingNote {
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[] {
@ -153,7 +114,8 @@ public class WorkingNote {
}, null); }, null);
if (cursor != null) { if (cursor != null) {
if (cursor.moveToFirst()) { // 查到信息不为空
if (cursor.moveToFirst()) { // 查看第一项是否存在
do { do {
String type = cursor.getString(DATA_MIME_TYPE_COLUMN); String type = cursor.getString(DATA_MIME_TYPE_COLUMN);
if (DataConstants.NOTE.equals(type)) { if (DataConstants.NOTE.equals(type)) {
@ -165,7 +127,7 @@ public class WorkingNote {
} else { } else {
Log.d(TAG, "Wrong note type with type:" + type); Log.d(TAG, "Wrong note type with type:" + type);
} }
} while (cursor.moveToNext()); } while (cursor.moveToNext());//查阅所有项,直到为空
} }
cursor.close(); cursor.close();
} else { } else {
@ -174,9 +136,12 @@ public class WorkingNote {
} }
} }
// 创建空的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);
@ -187,9 +152,10 @@ 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()) { // 是否存在数据库中
if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) { if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) {
Log.e(TAG, "Create new note fail with id:" + mNoteId); Log.e(TAG, "Create new note fail with id:" + mNoteId);
return false; return false;
@ -212,11 +178,14 @@ public class WorkingNote {
} }
} }
// 是否在数据库中存在
public boolean existInDatabase() { public boolean existInDatabase() {
return mNoteId > 0; return mNoteId > 0;
} }
// 是否值得保存
private boolean isWorthSaving() { private boolean isWorthSaving() {
// 被删除,或(不在数据库中 内容为空),或 本地已保存过
if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent)) if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent))
|| (existInDatabase() && !mNote.isLocalModified())) { || (existInDatabase() && !mNote.isLocalModified())) {
return false; return false;
@ -225,10 +194,14 @@ public class WorkingNote {
} }
} }
// 设置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;
@ -239,16 +212,20 @@ public class WorkingNote {
} }
} }
// 设定删除标记
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) { if (id != mBgColorId) { //设定条件 id != mBgColorId
mBgColorId = id; mBgColorId = id;
if (mNoteSettingStatusListener != null) { if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onBackgroundColorChanged(); mNoteSettingStatusListener.onBackgroundColorChanged();
@ -257,8 +234,10 @@ public class WorkingNote {
} }
} }
// 设定检查列表模式
// 参数mode
public void setCheckListMode(int mode) { public void setCheckListMode(int mode) {
if (mMode != mode) { if (mMode != mode) { //设定条件 mMode != mode
if (mNoteSettingStatusListener != null) { if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode); mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode);
} }
@ -267,81 +246,108 @@ public class WorkingNote {
} }
} }
// 设定WidgetType
// 参数type
public void setWidgetType(int type) { public void setWidgetType(int type) {
if (type != mWidgetType) { if (type != mWidgetType) {//设定条件 type != mWidgetType
mWidgetType = type; mWidgetType = type;
mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType)); mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType));
// 调用Note的setNoteValue方法更改WidgetType
} }
} }
// 设定WidgetId
// 参数id
public void setWidgetId(int id) { public void setWidgetId(int id) {
if (id != mWidgetId) { if (id != mWidgetId) {//设定条件 id != mWidgetId
mWidgetId = id; mWidgetId = id;
mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId)); mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId));
// 调用Note的setNoteValue方法更改WidgetId
} }
} }
// 设定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; mContent = text;
mNote.setTextData(DataColumns.CONTENT, mContent); mNote.setTextData(DataColumns.CONTENT, mContent);
// 调用Note的setTextData方法更改WorkingText
} }
} }
// 转变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

@ -1,48 +1,16 @@
/*
* 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.tool; package net.micode.notes.tool;
import android.content.Context;
import android.database.Cursor;
import android.os.Environment;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.Log;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
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;
@ -52,24 +20,24 @@ public class BackupUtils {
* Following states are signs to represents backup or restore * Following states are signs to represents backup or restore
* status * status
*/ */
// Currently, the sdcard is not mounted // Currently, the sdcard is not mounted SD卡没有被装入手机
public static final int STATE_SD_CARD_UNMOUONTED = 0; public static final int STATE_SD_CARD_UNMOUONTED = 0;
// The backup file not exist // The backup file not exist 备份文件夹不存在
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1; public static final int STATE_BACKUP_FILE_NOT_EXIST = 1;
// The data is not well formated, may be changed by other programs // The data is not well formated, may be changed by other programs 数据已被破坏,可能被修改
public static final int STATE_DATA_DESTROIED = 2; public static final int STATE_DATA_DESTROIED = 2;
// Some run-time exception which causes restore or backup fails // Some run-time exception which causes restore or backup fails 超时异常
public static final int STATE_SYSTEM_ERROR = 3; public static final int STATE_SYSTEM_ERROR = 3;
// Backup or restore success // Backup or restore success 成功存储
public static final int STATE_SUCCESS = 4; public static final int STATE_SUCCESS = 4;
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());
} }
@ -128,11 +96,11 @@ public class BackupUtils {
public TextExport(Context context) { public TextExport(Context context) {
TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note); TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note);
mContext = context; mContext = context;
mFileName = ""; mFileName = ""; //为什么为空?
mFileDirectory = ""; mFileDirectory = "";
} }
private String getFormat(int id) { private String getFormat(int id) { //获取文本的组成部分
return TEXT_FORMAT[id]; return TEXT_FORMAT[id];
} }
@ -140,7 +108,7 @@ public class BackupUtils {
* Export the folder identified by folder id to text * Export the folder identified by folder id to text
*/ */
private void exportFolderToText(String folderId, PrintStream ps) { private void exportFolderToText(String folderId, PrintStream ps) {
// Query notes belong to this folder // Query notes belong to this folder 通过查询parent id是文件夹id的note来选出制定ID文件夹下的Note
Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI, Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] { NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] {
folderId folderId
@ -149,13 +117,13 @@ public class BackupUtils {
if (notesCursor != null) { if (notesCursor != null) {
if (notesCursor.moveToFirst()) { if (notesCursor.moveToFirst()) {
do { do {
// Print note's last modified date // Print note's last modified date ps里面保存有这份note的日期
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format( ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
mContext.getString(R.string.format_datetime_mdhm), mContext.getString(R.string.format_datetime_mdhm),
notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
// Query data belong to this note // Query data belong to this note
String noteId = notesCursor.getString(NOTE_COLUMN_ID); String noteId = notesCursor.getString(NOTE_COLUMN_ID);
exportNoteToText(noteId, ps); exportNoteToText(noteId, ps); //将文件导出到text
} while (notesCursor.moveToNext()); } while (notesCursor.moveToNext());
} }
notesCursor.close(); notesCursor.close();
@ -171,7 +139,7 @@ public class BackupUtils {
noteId noteId
}, null); }, null);
if (dataCursor != null) { if (dataCursor != null) { //利用光标来扫描内容区别为callnote和note两种靠ps.printline输出
if (dataCursor.moveToFirst()) { if (dataCursor.moveToFirst()) {
do { do {
String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE); String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE);
@ -181,7 +149,7 @@ public class BackupUtils {
long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE); long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE);
String location = dataCursor.getString(DATA_COLUMN_CONTENT); String location = dataCursor.getString(DATA_COLUMN_CONTENT);
if (!TextUtils.isEmpty(phoneNumber)) { if (!TextUtils.isEmpty(phoneNumber)) { //判断是否为空字符
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
phoneNumber)); phoneNumber));
} }
@ -218,7 +186,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() { public int exportToText() { //总函数调用上面的exportFolder和exportNote
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;
@ -229,7 +197,7 @@ public class BackupUtils {
Log.e(TAG, "get print stream error"); Log.e(TAG, "get print stream error");
return STATE_SYSTEM_ERROR; return STATE_SYSTEM_ERROR;
} }
// First export folder and its notes // First export folder and its notes 导出文件夹,就是导出里面包含的便签
Cursor folderCursor = mContext.getContentResolver().query( Cursor folderCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI, Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION, NOTE_PROJECTION,
@ -257,7 +225,7 @@ public class BackupUtils {
folderCursor.close(); folderCursor.close();
} }
// Export notes in root's folder // Export notes in root's folder 将根目录里的便签导出(由于不属于任何文件夹,因此无法通过文件夹导出来实现这一部分便签的导出)
Cursor noteCursor = mContext.getContentResolver().query( Cursor noteCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI, Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION, NOTE_PROJECTION,
@ -297,7 +265,7 @@ public class BackupUtils {
PrintStream ps = null; PrintStream ps = null;
try { try {
FileOutputStream fos = new FileOutputStream(file); FileOutputStream fos = new FileOutputStream(file);
ps = new PrintStream(fos); ps = new PrintStream(fos); //将ps输出流输出到特定的文件目的就是导出到文件而不是直接输出
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
return null; return null;
@ -314,16 +282,16 @@ public class BackupUtils {
*/ */
private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) { private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(Environment.getExternalStorageDirectory()); sb.append(Environment.getExternalStorageDirectory()); //外部SD卡的存储路径
sb.append(context.getString(filePathResId)); sb.append(context.getString(filePathResId)); //文件的存储路径
File filedir = new File(sb.toString()); File filedir = new File(sb.toString()); //filedir应该就是用来存储路径信息
sb.append(context.getString( sb.append(context.getString(
fileNameFormatResId, fileNameFormatResId,
DateFormat.format(context.getString(R.string.format_date_ymd), DateFormat.format(context.getString(R.string.format_date_ymd),
System.currentTimeMillis()))); System.currentTimeMillis())));
File file = new File(sb.toString()); File file = new File(sb.toString());
try { try { //如果这些文件不存在,则新建
if (!filedir.exists()) { if (!filedir.exists()) {
filedir.mkdir(); filedir.mkdir();
} }
@ -336,9 +304,8 @@ public class BackupUtils {
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
// try catch 异常处理
return null; return null;
} }
} }

@ -1,43 +1,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.
*/
package net.micode.notes.tool; package net.micode.notes.tool;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.os.RemoteException;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;
import java.util.ArrayList;
import java.util.HashSet;
public class DataUtils { public class DataUtils {
public static final String TAG = "DataUtils"; public static final String TAG = "DataUtils";
public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) { public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) { //直接删除多个笔记
if (ids == null) { if (ids == null) {
Log.d(TAG, "the ids is null"); Log.d(TAG, "the ids is null");
return true; return true;
@ -47,18 +12,19 @@ public class DataUtils {
return true; return true;
} }
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>(); ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>(); //提供一个任务列表
for (long id : ids) { for (long id : ids) {
if(id == Notes.ID_ROOT_FOLDER) { if(id == Notes.ID_ROOT_FOLDER) {
Log.e(TAG, "Don't delete system folder root"); Log.e(TAG, "Don't delete system folder root");
continue; continue;
} } //如果发现是根文件夹,则不删除
ContentProviderOperation.Builder builder = ContentProviderOperation ContentProviderOperation.Builder builder = ContentProviderOperation
.newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); .newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); //用newDelete实现删除功能
operationList.add(builder.build()); operationList.add(builder.build()); //
} }
try { try {
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);//主机名或叫Authority用于唯一标识这个ContentProvider外部调用者可以根据这个标识来找到它。
//数据库事务,数据库事务是由一组数据库操作序列组成,事务作为一个整体被执行
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;
@ -77,7 +43,7 @@ public class DataUtils {
values.put(NoteColumns.PARENT_ID, desFolderId); values.put(NoteColumns.PARENT_ID, desFolderId);
values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId); values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId);
values.put(NoteColumns.LOCAL_MODIFIED, 1); values.put(NoteColumns.LOCAL_MODIFIED, 1);
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); //对需要移动的便签进行数据更新然后用update实现
} }
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids, public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,
@ -90,14 +56,14 @@ public class DataUtils {
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>(); ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
for (long id : ids) { for (long id : ids) {
ContentProviderOperation.Builder builder = ContentProviderOperation ContentProviderOperation.Builder builder = ContentProviderOperation
.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); .newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); //通过withAppendedId方法为该Uri加上ID
builder.withValue(NoteColumns.PARENT_ID, folderId); builder.withValue(NoteColumns.PARENT_ID, folderId);
builder.withValue(NoteColumns.LOCAL_MODIFIED, 1); builder.withValue(NoteColumns.LOCAL_MODIFIED, 1);
operationList.add(builder.build()); operationList.add(builder.build());
} }//将ids里包含的每一列的数据逐次加入到operationList中等待最后的批量处理
try { try {
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); //applyBatch一次性处理一个操作列表
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;
@ -119,7 +85,7 @@ public class DataUtils {
new String[] { "COUNT(*)" }, new String[] { "COUNT(*)" },
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?", NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?",
new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)}, new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)},
null); null); //筛选条件源文件不为trash folder
int count = 0; int count = 0;
if(cursor != null) { if(cursor != null) {
@ -137,15 +103,15 @@ public class DataUtils {
} }
public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) { public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), //通过withAppendedId方法为该Uri加上ID
null, null,
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER, NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER,
new String [] {String.valueOf(type)}, new String [] {String.valueOf(type)},
null); null); //查询条件type符合且不属于垃圾文件夹
boolean exist = false; boolean exist = false;
if (cursor != null) { if (cursor != null) {
if (cursor.getCount() > 0) { if (cursor.getCount() > 0) {//用getcount函数判断cursor是否为空
exist = true; exist = true;
} }
cursor.close(); cursor.close();
@ -187,6 +153,7 @@ public class DataUtils {
" AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +
" AND " + NoteColumns.SNIPPET + "=?", " AND " + NoteColumns.SNIPPET + "=?",
new String[] { name }, null); new String[] { name }, null);
//通过名字查询文件是否存在
boolean exist = false; boolean exist = false;
if(cursor != null) { if(cursor != null) {
if(cursor.getCount() > 0) { if(cursor.getCount() > 0) {
@ -202,7 +169,7 @@ public class DataUtils {
new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE }, new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE },
NoteColumns.PARENT_ID + "=?", NoteColumns.PARENT_ID + "=?",
new String[] { String.valueOf(folderId) }, new String[] { String.valueOf(folderId) },
null); null); //查询条件父ID是传入的folderId;
HashSet<AppWidgetAttribute> set = null; HashSet<AppWidgetAttribute> set = null;
if (c != null) { if (c != null) {
@ -211,13 +178,13 @@ public class DataUtils {
do { do {
try { try {
AppWidgetAttribute widget = new AppWidgetAttribute(); AppWidgetAttribute widget = new AppWidgetAttribute();
widget.widgetId = c.getInt(0); widget.widgetId = c.getInt(0); //0对应的NoteColumns.WIDGET_ID
widget.widgetType = c.getInt(1); widget.widgetType = c.getInt(1); //1对应的NoteColumns.WIDGET_TYPE
set.add(widget); set.add(widget);
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
Log.e(TAG, e.toString()); Log.e(TAG, e.toString());
} }
} while (c.moveToNext()); } while (c.moveToNext()); //查询下一条
} }
c.close(); c.close();
} }
@ -250,11 +217,12 @@ public class DataUtils {
+ CallNote.PHONE_NUMBER + ",?)", + CallNote.PHONE_NUMBER + ",?)",
new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber }, new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber },
null); null);
//通过数据库操作查询条件是callDate和phoneNumber匹配传入参数的值
if (cursor != null) { if (cursor != null) {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
try { try {
return cursor.getLong(0); return cursor.getLong(0); //0对应的CallNote.NOTE_ID
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
Log.e(TAG, "Get call note id fails " + e.toString()); Log.e(TAG, "Get call note id fails " + e.toString());
} }
@ -269,7 +237,7 @@ public class DataUtils {
new String [] { NoteColumns.SNIPPET }, new String [] { NoteColumns.SNIPPET },
NoteColumns.ID + "=?", NoteColumns.ID + "=?",
new String [] { String.valueOf(noteId)}, new String [] { String.valueOf(noteId)},
null); null);//查询条件noteId
if (cursor != null) { if (cursor != null) {
String snippet = ""; String snippet = "";
@ -281,8 +249,7 @@ public class DataUtils {
} }
throw new IllegalArgumentException("Note is not found with id: " + noteId); throw new IllegalArgumentException("Note is not found with id: " + noteId);
} }
public static String getFormattedSnippet(String snippet) { //对字符串进行格式处理,将字符串两头的空格去掉,同时将换行符去掉
public static String getFormattedSnippet(String snippet) {
if (snippet != null) { if (snippet != null) {
snippet = snippet.trim(); snippet = snippet.trim();
int index = snippet.indexOf('\n'); int index = snippet.indexOf('\n');
@ -292,4 +259,5 @@ public class DataUtils {
} }
return snippet; return snippet;
} }
} }

@ -1,21 +1,7 @@
/* //简介定义了很多的静态字符串目的就是为了提供jsonObject中相应字符串的"key"。把这些静态的定义单独写到了一个类里面,这是非常好的编程规范
* 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.tool; package net.micode.notes.tool;
//这个类就是定义了一堆static string实际就是为jsonObject提供Key把这些定义全部写到一个类里方便查看管理是一个非常好的编程习惯
public class GTaskStringUtils { public class GTaskStringUtils {
public final static String GTASK_JSON_ACTION_ID = "action_id"; public final static String GTASK_JSON_ACTION_ID = "action_id";

@ -1,26 +1,19 @@
/*
* 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.tool; package net.micode.notes.tool;
import android.content.Context; /*使
import android.preference.PreferenceManager; * R.java
* R.id
import net.micode.notes.R; * R.drawable 使
import net.micode.notes.ui.NotesPreferenceActivity; * R.layout
* R.menu
* R.String
* R.style 使
* idgetXXX
*
*
* @BG_DEFAULT_COLOR
* BG_DEFAULT_FONT_SIZE
*/
public class ResourceParser { public class ResourceParser {
@ -64,7 +57,7 @@ public class ResourceParser {
return BG_EDIT_TITLE_RESOURCES[id]; return BG_EDIT_TITLE_RESOURCES[id];
} }
} }
//直接获取默认的背景颜色。看不太懂这个PREFERENCE_SET_BG_COLOR_KEY是个final string,也就是说getBoolean肯定执行else为什么要这么写
public static int getDefaultBgId(Context context) { public static int getDefaultBgId(Context context) {
if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean( if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) { NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) {
@ -162,6 +155,7 @@ public class ResourceParser {
R.style.TextAppearanceSuper R.style.TextAppearanceSuper
}; };
//这里有一个容错的函数防止输入的id大于资源总量若如此则自动返回默认的设置结果
public static int getTexAppearanceResource(int id) { public static int getTexAppearanceResource(int id) {
/** /**
* HACKME: Fix bug of store the resource id in shared preference. * HACKME: Fix bug of store the resource id in shared preference.

@ -39,92 +39,113 @@ 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)); //获得所有的ID
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(); //e.printStackTrace()函数功能是抛出异常, 还将显示出更深的调用信息
return; return;
} }
mPlayer = new MediaPlayer(); mPlayer = new MediaPlayer(); //媒体控制模块
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) { if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) { //如果ID和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); //系统中设置音频流格式的值
if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) { if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) {
//铃声模式是否影响闹钟音量,是则音频流模式设置跟随系统设置,不是则设为默认
mPlayer.setAudioStreamType(silentModeStreams); mPlayer.setAudioStreamType(silentModeStreams);
} else { } else {
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM); mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
} }
try { try {
mPlayer.setDataSource(this, url); mPlayer.setDataSource(this, url);
//设置多媒体数据来源 根据 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
e.printStackTrace(); e.printStackTrace();
} catch (SecurityException e) { } catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} catch (IOException e) { } catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
} }
private void showActionDialog() { private void showActionDialog() {
AlertDialog.Builder dialog = new AlertDialog.Builder(this); AlertDialog.Builder dialog = new AlertDialog.Builder(this);
//新建一个dialog
//注意AlertDialog的构造方法全部是Protected的所以不能直接通过new一个AlertDialog来创建出一个AlertDialog
//要调用AlertDialog.Builder中的create()
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);
if (isScreenOn()) { //给对话框添加"Yes"按钮
if (isScreenOn()) { //如果亮屏,则对话框添加"No"按钮
dialog.setNegativeButton(R.string.notealert_enter, this); dialog.setNegativeButton(R.string.notealert_enter, this);
} }
dialog.show().setOnDismissListener(this); dialog.show().setOnDismissListener(this);
@ -132,26 +153,28 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
switch (which) { switch (which) {
case DialogInterface.BUTTON_NEGATIVE: //用which来选择click后下一步的操作
Intent intent = new Intent(this, NoteEditActivity.class); case DialogInterface.BUTTON_NEGATIVE: //如果是“取消”
intent.setAction(Intent.ACTION_VIEW); Intent intent = new Intent(this, NoteEditActivity.class); //实现两个类间的数据传输
intent.putExtra(Intent.EXTRA_UID, mNoteId); intent.setAction(Intent.ACTION_VIEW); //设置动作属性
startActivity(intent); intent.putExtra(Intent.EXTRA_UID, mNoteId); //实现key-value对 XTRA_UID为keymNoteId为键
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;
} }
} }

@ -34,18 +34,21 @@ public class AlarmInitReceiver extends BroadcastReceiver {
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();
//获取一个当前的毫秒数,即当前时间
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);
//通过查找数据库中的标签内容,找到晚于当前时间的标签
if (c != null) { if (c != null) {
if (c.moveToFirst()) { if (c.moveToFirst()) {
@ -53,13 +56,15 @@ public class AlarmInitReceiver extends BroadcastReceiver {
long alertDate = c.getLong(COLUMN_ALERTED_DATE); long alertDate = c.getLong(COLUMN_ALERTED_DATE);
Intent sender = new Intent(context, AlarmReceiver.class); Intent sender = new Intent(context, AlarmReceiver.class);
sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID))); sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID)));
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0); //获得一个可广播的intent对象
AlarmManager alermManager = (AlarmManager) context AlarmManager alermManager = (AlarmManager) context //设置闹钟
.getSystemService(Context.ALARM_SERVICE); .getSystemService(Context.ALARM_SERVICE);
alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent); alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent);
} while (c.moveToNext()); } while (c.moveToNext());
} }
c.close(); c.close();
} }
//查询结果不为空,就遍历结果集并为每个标签创建一个闹钟
//这里就是根据数据库里的闹钟时间创建一个闹钟机制
} }
} }

@ -24,7 +24,14 @@ 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时必然不存在一个activity的栈
//所以要新起一个栈装入启动的activity
context.startActivity(intent); context.startActivity(intent);
} }
} }
//用于捕获闹钟触发的事件并在接收到广播时启动相应的Activity来处理闹钟提醒
//作用还需要深究但是对于setClass和addFlags的

@ -29,7 +29,6 @@ import android.widget.FrameLayout;
import android.widget.NumberPicker; import android.widget.NumberPicker;
public class DateTimePicker extends FrameLayout { public class DateTimePicker extends 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;
@ -50,6 +49,7 @@ public class DateTimePicker extends FrameLayout {
private final NumberPicker mHourSpinner; private final NumberPicker mHourSpinner;
private final NumberPicker mMinuteSpinner; private final NumberPicker mMinuteSpinner;
private final NumberPicker mAmPmSpinner; private final NumberPicker mAmPmSpinner;
private Calendar mDate; private Calendar mDate;
private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK]; private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK];
@ -121,11 +121,13 @@ public class DateTimePicker extends FrameLayout {
int minValue = mMinuteSpinner.getMinValue(); int minValue = mMinuteSpinner.getMinValue();
int maxValue = mMinuteSpinner.getMaxValue(); int maxValue = mMinuteSpinner.getMaxValue();
int offset = 0; int offset = 0;
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;
} }
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 +147,7 @@ public class DateTimePicker extends FrameLayout {
}; };
private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() { private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() {
@Override @Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) { public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
mIsAm = !mIsAm; mIsAm = !mIsAm;
@ -170,14 +173,12 @@ public class DateTimePicker extends FrameLayout {
public DateTimePicker(Context context, long date) { public DateTimePicker(Context context, long date) {
this(context, date, DateFormat.is24HourFormat(context)); this(context, date, DateFormat.is24HourFormat(context));
} }
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);
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);
@ -198,19 +199,19 @@ public class DateTimePicker extends FrameLayout {
mAmPmSpinner.setDisplayedValues(stringsForAmPm); mAmPmSpinner.setDisplayedValues(stringsForAmPm);
mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener); mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener);
// update controls to initial state
updateDateControl(); updateDateControl();
updateHourControl(); updateHourControl();
updateAmPmControl(); updateAmPmControl();
set24HourView(is24HourView); set24HourView(is24HourView);
// set to current time
setCurrentDate(date); setCurrentDate(date);
setEnabled(isEnabled()); setEnabled(isEnabled());
// set the content descriptions
mInitialising = false; mInitialising = false;
} }

@ -40,7 +40,6 @@ 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
} }
@Override @Override

@ -74,6 +74,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;
@ -86,11 +88,13 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private static final Map<Integer, Integer> sBgSelectorBtnsMap = new HashMap<Integer, Integer>(); private static final Map<Integer, Integer> sBgSelectorBtnsMap = new HashMap<Integer, Integer>();
static { static {
//使用Map实现数据存储
sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW); sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW);
sBgSelectorBtnsMap.put(R.id.iv_bg_red, ResourceParser.RED); sBgSelectorBtnsMap.put(R.id.iv_bg_red, ResourceParser.RED);
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>();
@ -123,19 +127,27 @@ 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;
//初始化模板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";
@ -145,6 +157,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 +166,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 +189,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 +201,40 @@ 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 // 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);
@ -224,6 +243,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
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 +260,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 +291,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 +318,18 @@ 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);
@ -326,6 +350,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* generate a id. If the editing note is not worth saving, there * generate a id. If the editing note is not worth saving, there
* is no id which is equivalent to create new note * is no id which is equivalent to create new note
*/ */
//在创建新的标签时,先在数据库中匹配
//如果不存在,那么在数据库中存储
if (!mWorkingNote.existInDatabase()) { if (!mWorkingNote.existInDatabase()) {
saveNote(); saveNote();
} }
@ -334,21 +360,23 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} }
@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,7 +385,7 @@ 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())) {//如果触控的位置超出了给定的范围返回false
return false; return false;
} }
return true; return true;
@ -377,13 +405,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);
/** /**
@ -406,6 +434,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) {
@ -481,6 +510,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 +519,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 +537,67 @@ 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();
} }
}); });
builder.setNegativeButton(android.R.string.cancel, null); builder.setNegativeButton(android.R.string.cancel, null);
//添加否定按钮
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,13 +606,17 @@ 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();
} }
@ -567,85 +624,112 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* 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
} }
private boolean isSyncMode() { //判断是否为同步模式
private boolean isSyncMode() {//查看NotesPreferenceActivity中同步名称是否为空
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) {
@ -654,10 +738,11 @@ public class NoteEditActivity extends Activity implements OnClickListener,
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(
@ -665,13 +750,14 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} else { } else {
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
@ -682,53 +768,66 @@ public class NoteEditActivity extends Activity implements OnClickListener,
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,8 +838,10 @@ 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();
@ -753,61 +854,79 @@ 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标记,默认为false
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 +935,13 @@ 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是为了识别保存的情况:一是创建后保存,二是修改后保存
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
@ -828,13 +949,15 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* save it * save it
*/ */
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 +965,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
@ -856,17 +982,21 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} }
} }
//编辑小图标的标题
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();
} }

@ -37,6 +37,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 +47,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 +58,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 +82,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;
} }
//AttributeSet 百度了一下是自定义空控件属性,用于维护便签动态变化的属性
//初始化便签
public NoteEditText(Context context, AttributeSet attrs) { 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 construct or 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 +126,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 +140,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);
} }
} }

@ -41,7 +41,7 @@ public class NoteItemData {
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;
private static final int ALERTED_DATE_COLUMN = 1; private static final int ALERTED_DATE_COLUMN = 1;
private static final int BG_COLOR_ID_COLUMN = 2; private static final int BG_COLOR_ID_COLUMN = 2;
@ -75,8 +75,9 @@ public class NoteItemData {
private boolean mIsOnlyOneItem; private boolean mIsOnlyOneItem;
private boolean mIsOneNoteFollowingFolder; private boolean mIsOneNoteFollowingFolder;
private boolean mIsMultiNotesFollowingFolder; private boolean mIsMultiNotesFollowingFolder;
//初始化NoteItemData主要利用光标cursor获取的东西
public NoteItemData(Context context, Cursor cursor) { public NoteItemData(Context context, Cursor cursor) {
//getxxx为转换格式
mId = cursor.getLong(ID_COLUMN); mId = cursor.getLong(ID_COLUMN);
mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN); mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN);
mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN); mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN);
@ -92,10 +93,11 @@ public class NoteItemData {
mWidgetId = cursor.getInt(WIDGET_ID_COLUMN); mWidgetId = cursor.getInt(WIDGET_ID_COLUMN);
mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN); mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN);
//初始化电话号码的信息
mPhoneNumber = ""; mPhoneNumber = "";
if (mParentId == Notes.ID_CALL_RECORD_FOLDER) { if (mParentId == Notes.ID_CALL_RECORD_FOLDER) {
mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId); mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId);
if (!TextUtils.isEmpty(mPhoneNumber)) { if (!TextUtils.isEmpty(mPhoneNumber)) {//mphonenumber里有符合字符串则用contart功能连接
mName = Contact.getContact(context, mPhoneNumber); mName = Contact.getContact(context, mPhoneNumber);
if (mName == null) { if (mName == null) {
mName = mPhoneNumber; mName = mPhoneNumber;
@ -108,32 +110,35 @@ public class NoteItemData {
} }
checkPostion(cursor); checkPostion(cursor);
} }
///根据鼠标的位置设置标记,和位置
private void checkPostion(Cursor cursor) { private void checkPostion(Cursor cursor) {
//初始化几个标记cursor具体功能笔记中已提到不一一叙述
mIsLastItem = cursor.isLast() ? true : false; mIsLastItem = cursor.isLast() ? true : false;
mIsFirstItem = cursor.isFirst() ? true : false; mIsFirstItem = cursor.isFirst() ? true : false;
mIsOnlyOneItem = (cursor.getCount() == 1); mIsOnlyOneItem = (cursor.getCount() == 1);
//初始化“多重子文件”“单一子文件”2个标记
mIsMultiNotesFollowingFolder = false; mIsMultiNotesFollowingFolder = false;
mIsOneNoteFollowingFolder = false; mIsOneNoteFollowingFolder = false;
if (mType == Notes.TYPE_NOTE && !mIsFirstItem) { //主要是设置上诉2标记
if (mType == Notes.TYPE_NOTE && !mIsFirstItem) {//若是note格式并且不是第一个元素
int position = cursor.getPosition(); int position = cursor.getPosition();
if (cursor.moveToPrevious()) { if (cursor.moveToPrevious()) {//获取光标位置后看上一行
if (cursor.getInt(TYPE_COLUMN) == Notes.TYPE_FOLDER if (cursor.getInt(TYPE_COLUMN) == Notes.TYPE_FOLDER
|| cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) { || cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) {//若光标满足系统或note格式
if (cursor.getCount() > (position + 1)) { if (cursor.getCount() > (position + 1)) {
mIsMultiNotesFollowingFolder = true; mIsMultiNotesFollowingFolder = true;//若是数据行数大于但前位置+1则设置成正确
} else { } else {
mIsOneNoteFollowingFolder = true; mIsOneNoteFollowingFolder = true;//否则单一文件夹标记为true
} }
} }
if (!cursor.moveToNext()) { if (!cursor.moveToNext()) {//若不能再往下走则报错
throw new IllegalStateException("cursor move to previous but can't move back"); throw new IllegalStateException("cursor move to previous but can't move back");
} }
} }
} }
} }
///以下都是获取标记没什么好说的,不过倒数第二个需要说明下,很具体看下面
public boolean isOneFollowingFolder() { public boolean isOneFollowingFolder() {
return mIsOneNoteFollowingFolder; return mIsOneNoteFollowingFolder;
} }
@ -214,6 +219,7 @@ public class NoteItemData {
return (mAlertDate > 0); return (mAlertDate > 0);
} }
//若数据父id为保存至文件夹模式的id且满足电话号码单元不为空则isCallRecord为true
public boolean isCallRecord() { public boolean isCallRecord() {
return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber)); return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber));
} }

@ -77,8 +77,12 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.HashSet; import java.util.HashSet;
//主界面,一进入就是这个界面
public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener { /**
* @author k
*
*/
public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener { //没有用特定的标签加注释。。。感觉没有什么用
private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0; private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0;
private static final int FOLDER_LIST_QUERY_TOKEN = 1; private static final int FOLDER_LIST_QUERY_TOKEN = 1;
@ -89,7 +93,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
private static final int MENU_FOLDER_CHANGE_NAME = 2; private static final int MENU_FOLDER_CHANGE_NAME = 2;
private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction"; private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction"; //单行超过80个字符
private enum ListEditState { private enum ListEditState {
NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER
@ -136,8 +140,13 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
private final static int REQUEST_CODE_NEW_NODE = 103; private final static int REQUEST_CODE_NEW_NODE = 103;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { // 创建类
super.onCreate(savedInstanceState); protected void onCreate(final Bundle savedInstanceState) { //需要是final类型 根据程序上下文环境Java关键字final有“这是无法改变的”或者“终态的”含义它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变设计或效率。
// final类不能被继承没有子类final类中的方法默认是final的。
//final方法不能被子类的方法覆盖但可以被继承。
//final成员变量表示常量只能被赋值一次赋值后值不再改变。
//final不能用于修饰构造方法。
super.onCreate(savedInstanceState); // 调用父类的onCreate函数
setContentView(R.layout.note_list); setContentView(R.layout.note_list);
initResources(); initResources();
@ -148,26 +157,32 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
} }
@Override @Override
// 返回一些子模块完成的数据交给主Activity处理
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// 结果值 和 要求值 符合要求
if (resultCode == RESULT_OK if (resultCode == RESULT_OK
&& (requestCode == REQUEST_CODE_OPEN_NODE || requestCode == REQUEST_CODE_NEW_NODE)) { && (requestCode == REQUEST_CODE_OPEN_NODE || requestCode == REQUEST_CODE_NEW_NODE)) {
mNotesListAdapter.changeCursor(null); mNotesListAdapter.changeCursor(null);
} else { } else {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
// 调用 Activity 的onActivityResult
} }
} }
private void setAppInfoFromRawRes() { private void setAppInfoFromRawRes() {
// Android平台给我们提供了一个SharedPreferences类它是一个轻量级的存储类特别适合用于保存软件配置参数。
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) { if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
InputStream in = null; InputStream in = null;
try { try {
// 把资源文件放到应用程序的/raw/raw下那么就可以在应用中使用getResources获取资源后,
// 以openRawResource方法不带后缀的资源文件名打开这个文件。
in = getResources().openRawResource(R.raw.introduction); in = getResources().openRawResource(R.raw.introduction);
if (in != null) { if (in != null) {
InputStreamReader isr = new InputStreamReader(in); InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr); BufferedReader br = new BufferedReader(isr);
char [] buf = new char[1024]; char [] buf = new char[1024]; // 自行定义的数值,使用者不知道有什么意义
int len = 0; int len = 0;
while ((len = br.read(buf)) > 0) { while ((len = br.read(buf)) > 0) {
sb.append(buf, 0, len); sb.append(buf, 0, len);
@ -190,11 +205,13 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
} }
} }
// 创建空的WorkingNote
WorkingNote note = WorkingNote.createEmptyNote(this, Notes.ID_ROOT_FOLDER, WorkingNote note = WorkingNote.createEmptyNote(this, Notes.ID_ROOT_FOLDER,
AppWidgetManager.INVALID_APPWIDGET_ID, Notes.TYPE_WIDGET_INVALIDE, AppWidgetManager.INVALID_APPWIDGET_ID, Notes.TYPE_WIDGET_INVALIDE,
ResourceParser.RED); ResourceParser.RED);
note.setWorkingText(sb.toString()); note.setWorkingText(sb.toString());
if (note.saveNote()) { if (note.saveNote()) {
// 更新保存note的信息
sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit(); sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit();
} else { } else {
Log.e(TAG, "Save introduction note error"); Log.e(TAG, "Save introduction note error");
@ -209,18 +226,21 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
startAsyncNotesListQuery(); startAsyncNotesListQuery();
} }
// 初始化资源
private void initResources() { private void initResources() {
mContentResolver = this.getContentResolver(); mContentResolver = this.getContentResolver(); // 获取应用程序的数据,得到类似数据表的东西
mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver()); mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver());
mCurrentFolderId = Notes.ID_ROOT_FOLDER; mCurrentFolderId = Notes.ID_ROOT_FOLDER;
mNotesListView = (ListView) findViewById(R.id.notes_list);
// findViewById 是安卓编程的定位函数,主要是引用.R文件里的引用名
mNotesListView = (ListView) findViewById(R.id.notes_list); // 绑定XML中的ListView作为Item的容器
mNotesListView.addFooterView(LayoutInflater.from(this).inflate(R.layout.note_list_footer, null), mNotesListView.addFooterView(LayoutInflater.from(this).inflate(R.layout.note_list_footer, null),
null, false); null, false);
mNotesListView.setOnItemClickListener(new OnListItemClickListener()); mNotesListView.setOnItemClickListener(new OnListItemClickListener());
mNotesListView.setOnItemLongClickListener(this); mNotesListView.setOnItemLongClickListener(this);
mNotesListAdapter = new NotesListAdapter(this); mNotesListAdapter = new NotesListAdapter(this);
mNotesListView.setAdapter(mNotesListAdapter); mNotesListView.setAdapter(mNotesListAdapter);
mAddNewNote = (Button) findViewById(R.id.btn_new_note); mAddNewNote = (Button) findViewById(R.id.btn_new_note);// 在activity中要获取该按钮
mAddNewNote.setOnClickListener(this); mAddNewNote.setOnClickListener(this);
mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener()); mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener());
mDispatch = false; mDispatch = false;
@ -231,6 +251,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mModeCallBack = new ModeCallback(); mModeCallBack = new ModeCallback();
} }
// 继承自ListView.MultiChoiceModeListener 和 OnMenuItemClickListener
private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener { private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener {
private DropdownMenu mDropDownMenu; private DropdownMenu mDropDownMenu;
private ActionMode mActionMode; private ActionMode mActionMode;
@ -259,7 +280,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
(Button) customView.findViewById(R.id.selection_menu), (Button) customView.findViewById(R.id.selection_menu),
R.menu.note_list_dropdown); R.menu.note_list_dropdown);
mDropDownMenu.setOnDropdownMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){ mDropDownMenu.setOnDropdownMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(final MenuItem item) {
mNotesListAdapter.selectAll(!mNotesListAdapter.isAllSelected()); mNotesListAdapter.selectAll(!mNotesListAdapter.isAllSelected());
updateMenu(); updateMenu();
return true; return true;
@ -269,11 +290,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
return true; return true;
} }
// 更新菜单
private void updateMenu() { private void updateMenu() {
int selectedCount = mNotesListAdapter.getSelectedCount(); int selectedCount = mNotesListAdapter.getSelectedCount();
// Update dropdown menu // Update dropdown menu
String format = getResources().getString(R.string.menu_select_title, selectedCount); String format = getResources().getString(R.string.menu_select_title, selectedCount);
mDropDownMenu.setTitle(format); mDropDownMenu.setTitle(format); // 更改标题
MenuItem item = mDropDownMenu.findItem(R.id.action_select_all); MenuItem item = mDropDownMenu.findItem(R.id.action_select_all);
if (item != null) { if (item != null) {
if (mNotesListAdapter.isAllSelected()) { if (mNotesListAdapter.isAllSelected()) {
@ -366,7 +388,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
/** /**
* HACKME:When click the transparent part of "New Note" button, dispatch * HACKME:When click the transparent part of "New Note" button, dispatch
* the event to the list view behind this button. The transparent part of * the event to the list view behind this button. The transparent part of
* "New Note" button could be expressed by formula y=-0.12x+94Unit:pixel * "New Note" button could be expressed by formula y=-0.12x+94nit:pixel<EFBFBD>
* and the line top of the button. The coordinate based on left of the "New * and the line top of the button. The coordinate based on left of the "New
* Note" button. The 94 represents maximum height of the transparent part. * Note" button. The 94 represents maximum height of the transparent part.
* Notice that, if the background of the button changes, the formula should * Notice that, if the background of the button changes, the formula should
@ -664,9 +686,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}); });
} }
/* (non-Javadoc)
* @see android.app.Activity#onBackPressed()
*
*/
@Override @Override
public void onBackPressed() { public void onBackPressed() { switch (mState) {
switch (mState) {
case SUB_FOLDER: case SUB_FOLDER:
mCurrentFolderId = Notes.ID_ROOT_FOLDER; mCurrentFolderId = Notes.ID_ROOT_FOLDER;
mState = ListEditState.NOTE_LIST; mState = ListEditState.NOTE_LIST;
@ -688,6 +713,11 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
} }
} }
/**
* @param appWidgetId
* @param appWidgetType
* widgetintent
*/
private void updateWidget(int appWidgetId, int appWidgetType) { private void updateWidget(int appWidgetId, int appWidgetType) {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
if (appWidgetType == Notes.TYPE_WIDGET_2X) { if (appWidgetType == Notes.TYPE_WIDGET_2X) {
@ -707,6 +737,9 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
setResult(RESULT_OK, intent); setResult(RESULT_OK, intent);
} }
/**
*
*/
private final OnCreateContextMenuListener mFolderOnCreateContextMenuListener = new OnCreateContextMenuListener() { private final OnCreateContextMenuListener mFolderOnCreateContextMenuListener = new OnCreateContextMenuListener() {
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
if (mFocusNoteDataItem != null) { if (mFocusNoteDataItem != null) {
@ -726,6 +759,10 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
super.onContextMenuClosed(menu); super.onContextMenuClosed(menu);
} }
/* (non-Javadoc)
* @see android.app.Activity#onContextItemSelected(android.view.MenuItem)
* menu
*/
@Override @Override
public boolean onContextItemSelected(MenuItem item) { public boolean onContextItemSelected(MenuItem item) {
if (mFocusNoteDataItem == null) { if (mFocusNoteDataItem == null) {
@ -734,10 +771,10 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
} }
switch (item.getItemId()) { switch (item.getItemId()) {
case MENU_FOLDER_VIEW: case MENU_FOLDER_VIEW:
openFolder(mFocusNoteDataItem); openFolder(mFocusNoteDataItem);//打开对应文件
break; break;
case MENU_FOLDER_DELETE: case MENU_FOLDER_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));
builder.setIcon(android.R.drawable.ic_dialog_alert); builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setMessage(getString(R.string.alert_message_delete_folder)); builder.setMessage(getString(R.string.alert_message_delete_folder));
@ -748,7 +785,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
} }
}); });
builder.setNegativeButton(android.R.string.cancel, null); builder.setNegativeButton(android.R.string.cancel, null);
builder.show(); builder.show();//显示对话框
break; break;
case MENU_FOLDER_CHANGE_NAME: case MENU_FOLDER_CHANGE_NAME:
showCreateOrModifyFolderDialog(false); showCreateOrModifyFolderDialog(false);
@ -818,12 +855,19 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
return true; return true;
} }
/* (non-Javadoc)
* @see android.app.Activity#onSearchRequested()
* startSearch
*/
@Override @Override
public boolean onSearchRequested() { public boolean onSearchRequested() {
startSearch(null, false, null /* appData */, false); startSearch(null, false, null /* appData */, false);
return true; return true;
} }
/**
* 便
*/
private void exportNoteToText() { private void exportNoteToText() {
final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this); final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this);
new AsyncTask<Void, Void, Integer>() { new AsyncTask<Void, Void, Integer>() {
@ -866,16 +910,27 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}.execute(); }.execute();
} }
/**
* @return
*
*/
private boolean isSyncMode() { private boolean isSyncMode() {
return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0;
} }
/**
* PreferenceActivity
*/
private void startPreferenceActivity() { private void startPreferenceActivity() {
Activity from = getParent() != null ? getParent() : this; Activity from = getParent() != null ? getParent() : this;
Intent intent = new Intent(from, NotesPreferenceActivity.class); Intent intent = new Intent(from, NotesPreferenceActivity.class);
from.startActivityIfNeeded(intent, -1); from.startActivityIfNeeded(intent, -1);
} }
/**
* @author k
* 便
*/
private class OnListItemClickListener implements OnItemClickListener { private class OnListItemClickListener implements OnItemClickListener {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
@ -917,6 +972,9 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
} }
/**
*
*/
private void startQueryDestinationFolders() { private void startQueryDestinationFolders() {
String selection = NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>? AND " + NoteColumns.ID + "<>?"; String selection = NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>? AND " + NoteColumns.ID + "<>?";
selection = (mState == ListEditState.NOTE_LIST) ? selection: selection = (mState == ListEditState.NOTE_LIST) ? selection:
@ -935,6 +993,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
NoteColumns.MODIFIED_DATE + " DESC"); NoteColumns.MODIFIED_DATE + " DESC");
} }
/* (non-Javadoc)
* @see android.widget.AdapterView.OnItemLongClickListener#onItemLongClick(android.widget.AdapterView, android.view.View, int, long)
*
* 便ActionModeContextMenu
* ActionMOdeContextMenu
*/
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if (view instanceof NotesListItem) { if (view instanceof NotesListItem) {
mFocusNoteDataItem = ((NotesListItem) view).getItemData(); mFocusNoteDataItem = ((NotesListItem) view).getItemData();

@ -23,6 +23,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CursorAdapter; import android.widget.CursorAdapter;
import net.micode.notes.data.Notes; import net.micode.notes.data.Notes;
import java.util.Collection; import java.util.Collection;
@ -43,6 +44,7 @@ public class NotesListAdapter extends CursorAdapter {
public int widgetType; public int widgetType;
}; };
public NotesListAdapter(Context context) { public NotesListAdapter(Context context) {
super(context, null); super(context, null);
mSelectedIndex = new HashMap<Integer, Boolean>(); mSelectedIndex = new HashMap<Integer, Boolean>();
@ -51,33 +53,43 @@ public class NotesListAdapter extends CursorAdapter {
} }
@Override @Override
public View newView(Context context, Cursor cursor, ViewGroup parent) { public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new NotesListItem(context); return new NotesListItem(context);
} }
@Override @Override
public void bindView(View view, Context context, Cursor cursor) { public void bindView(View view, Context context, Cursor cursor) {
if (view instanceof NotesListItem) { if (view instanceof NotesListItem) {
NoteItemData itemData = new NoteItemData(context, cursor); NoteItemData itemData = new NoteItemData(context, cursor);
((NotesListItem) view).bind(context, itemData, mChoiceMode, ((NotesListItem) view).bind(context, itemData, mChoiceMode,
isSelectedItem(cursor.getPosition())); isSelectedItem(cursor.getPosition()));
} }
} }
public void setCheckedItem(final int position, final boolean checked) { public void setCheckedItem(final int position, final boolean checked) {
mSelectedIndex.put(position, checked); mSelectedIndex.put(position, checked);
notifyDataSetChanged(); notifyDataSetChanged();
} }
public boolean isInChoiceMode() { public boolean isInChoiceMode() {
return mChoiceMode; return mChoiceMode;
} }
public void setChoiceMode(boolean mode) { public void setChoiceMode(boolean mode) {
mSelectedIndex.clear(); mSelectedIndex.clear();
mChoiceMode = mode; mChoiceMode = mode;
} }
public void selectAll(boolean checked) { public void selectAll(boolean checked) {
Cursor cursor = getCursor(); Cursor cursor = getCursor();
for (int i = 0; i < getCount(); i++) { for (int i = 0; i < getCount(); i++) {
@ -89,8 +101,10 @@ public class NotesListAdapter extends CursorAdapter {
} }
} }
public HashSet<Long> getSelectedItemIds() { public HashSet<Long> getSelectedItemIds() {
HashSet<Long> itemSet = new HashSet<Long>(); HashSet<Long> itemSet = new HashSet<Long>();
for (Integer position : mSelectedIndex.keySet()) { for (Integer position : mSelectedIndex.keySet()) {
if (mSelectedIndex.get(position) == true) { if (mSelectedIndex.get(position) == true) {
Long id = getItemId(position); Long id = getItemId(position);
@ -105,6 +119,7 @@ public class NotesListAdapter extends CursorAdapter {
return itemSet; return itemSet;
} }
public HashSet<AppWidgetAttribute> getSelectedWidget() { public HashSet<AppWidgetAttribute> getSelectedWidget() {
HashSet<AppWidgetAttribute> itemSet = new HashSet<AppWidgetAttribute>(); HashSet<AppWidgetAttribute> itemSet = new HashSet<AppWidgetAttribute>();
for (Integer position : mSelectedIndex.keySet()) { for (Integer position : mSelectedIndex.keySet()) {
@ -116,9 +131,6 @@ public class NotesListAdapter extends CursorAdapter {
widget.widgetId = item.getWidgetId(); widget.widgetId = item.getWidgetId();
widget.widgetType = item.getWidgetType(); widget.widgetType = item.getWidgetType();
itemSet.add(widget); itemSet.add(widget);
/**
* Don't close cursor here, only the adapter could close it
*/
} else { } else {
Log.e(TAG, "Invalid cursor"); Log.e(TAG, "Invalid cursor");
return null; return null;
@ -143,11 +155,13 @@ public class NotesListAdapter extends CursorAdapter {
return count; return count;
} }
public boolean isAllSelected() { public boolean isAllSelected() {
int checkedCount = getSelectedCount(); int checkedCount = getSelectedCount();
return (checkedCount != 0 && checkedCount == mNotesCount); return (checkedCount != 0 && checkedCount == mNotesCount);
} }
public boolean isSelectedItem(final int position) { public boolean isSelectedItem(final int position) {
if (null == mSelectedIndex.get(position)) { if (null == mSelectedIndex.get(position)) {
return false; return false;
@ -156,8 +170,11 @@ public class NotesListAdapter extends CursorAdapter {
} }
@Override @Override
protected void onContentChanged() { protected void onContentChanged() {
super.onContentChanged(); super.onContentChanged();
calcNotesCount(); calcNotesCount();
} }
@ -167,6 +184,7 @@ public class NotesListAdapter extends CursorAdapter {
calcNotesCount(); calcNotesCount();
} }
private void calcNotesCount() { private void calcNotesCount() {
mNotesCount = 0; mNotesCount = 0;
for (int i = 0; i < getCount(); i++) { for (int i = 0; i < getCount(); i++) {

@ -30,6 +30,7 @@ import net.micode.notes.tool.DataUtils;
import net.micode.notes.tool.ResourceParser.NoteItemBgResources; import net.micode.notes.tool.ResourceParser.NoteItemBgResources;
public class NotesListItem extends LinearLayout { public class NotesListItem extends LinearLayout {
private ImageView mAlert; private ImageView mAlert;
private TextView mTitle; private TextView mTitle;
@ -38,6 +39,7 @@ public class NotesListItem extends LinearLayout {
private NoteItemData mItemData; private NoteItemData mItemData;
private CheckBox mCheckBox; private CheckBox mCheckBox;
public NotesListItem(Context context) { public NotesListItem(Context context) {
super(context); super(context);
inflate(context, R.layout.note_item, this); inflate(context, R.layout.note_item, this);
@ -57,10 +59,13 @@ public class NotesListItem extends LinearLayout {
} }
mItemData = data; mItemData = data;
if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
mCallName.setVisibility(View.GONE); mCallName.setVisibility(View.GONE);
mAlert.setVisibility(View.VISIBLE); mAlert.setVisibility(View.VISIBLE);
mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem);
mTitle.setText(context.getString(R.string.call_record_folder_name) mTitle.setText(context.getString(R.string.call_record_folder_name)
+ context.getString(R.string.format_folder_files_count, data.getNotesCount())); + context.getString(R.string.format_folder_files_count, data.getNotesCount()));
mAlert.setImageResource(R.drawable.call_record); mAlert.setImageResource(R.drawable.call_record);
@ -69,6 +74,7 @@ public class NotesListItem extends LinearLayout {
mCallName.setText(data.getCallName()); mCallName.setText(data.getCallName());
mTitle.setTextAppearance(context,R.style.TextAppearanceSecondaryItem); mTitle.setTextAppearance(context,R.style.TextAppearanceSecondaryItem);
mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet()));
if (data.hasAlert()) { if (data.hasAlert()) {
mAlert.setImageResource(R.drawable.clock); mAlert.setImageResource(R.drawable.clock);
mAlert.setVisibility(View.VISIBLE); mAlert.setVisibility(View.VISIBLE);
@ -94,6 +100,7 @@ public class NotesListItem extends LinearLayout {
} }
} }
} }
mTime. setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate())); mTime. setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate()));
setBackground(data); setBackground(data);
@ -101,7 +108,9 @@ public class NotesListItem extends LinearLayout {
private void setBackground(NoteItemData data) { private void setBackground(NoteItemData data) {
int id = data.getBgColorId(); int id = data.getBgColorId();
if (data.getType() == Notes.TYPE_NOTE) { if (data.getType() == Notes.TYPE_NOTE) {
if (data.isSingle() || data.isOneFollowingFolder()) { if (data.isSingle() || data.isOneFollowingFolder()) {
setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id)); setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id));
} else if (data.isLast()) { } else if (data.isLast()) {
@ -112,10 +121,10 @@ public class NotesListItem extends LinearLayout {
setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id)); setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id));
} }
} else { } else {
setBackgroundResource(NoteItemBgResources.getFolderBgRes()); setBackgroundResource(NoteItemBgResources.getFolderBgRes());
} }
} }
public NoteItemData getItemData() { public NoteItemData getItemData() {
return mItemData; return mItemData;
} }

@ -69,14 +69,17 @@ public class NotesPreferenceActivity extends PreferenceActivity {
private boolean mHasAddedAccount; private boolean mHasAddedAccount;
@Override @Override
protected void onCreate(Bundle icicle) { protected void onCreate(Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
/* using the app icon for navigation */
getActionBar().setDisplayHomeAsUpEnabled(true); getActionBar().setDisplayHomeAsUpEnabled(true);
addPreferencesFromResource(R.xml.preferences); addPreferencesFromResource(R.xml.preferences);
mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY); mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY);
mReceiver = new GTaskReceiver(); mReceiver = new GTaskReceiver();
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
@ -89,13 +92,15 @@ public class NotesPreferenceActivity extends PreferenceActivity {
} }
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
// need to set sync account automatically if user has added a new
// account
if (mHasAddedAccount) { if (mHasAddedAccount) {
Account[] accounts = getGoogleAccounts(); Account[] accounts = getGoogleAccounts();
if (mOriAccounts != null && accounts.length > mOriAccounts.length) { if (mOriAccounts != null && accounts.length > mOriAccounts.length) {
for (Account accountNew : accounts) { for (Account accountNew : accounts) {
boolean found = false; boolean found = false;
@ -114,32 +119,35 @@ public class NotesPreferenceActivity extends PreferenceActivity {
} }
refreshUI(); refreshUI();
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
if (mReceiver != null) { if (mReceiver != null) {
unregisterReceiver(mReceiver); unregisterReceiver(mReceiver);
} }
super.onDestroy(); super.onDestroy();
} }
private void loadAccountPreference() { private void loadAccountPreference() {
mAccountCategory.removeAll(); mAccountCategory.removeAll();
Preference accountPref = new Preference(this); Preference accountPref = new Preference(this);
final String defaultAccount = getSyncAccountName(this); final String defaultAccount = getSyncAccountName(this);
accountPref.setTitle(getString(R.string.preferences_account_title)); accountPref.setTitle(getString(R.string.preferences_account_title));
accountPref.setSummary(getString(R.string.preferences_account_summary)); accountPref.setSummary(getString(R.string.preferences_account_summary));
accountPref.setOnPreferenceClickListener(new OnPreferenceClickListener() { accountPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
if (!GTaskSyncService.isSyncing()) { if (!GTaskSyncService.isSyncing()) {
if (TextUtils.isEmpty(defaultAccount)) { if (TextUtils.isEmpty(defaultAccount)) {
// the first time to set account
showSelectAccountAlertDialog(); showSelectAccountAlertDialog();
} else { } else {
// if the account has already been set, we need to promp
// user about the risk
showChangeAccountConfirmAlertDialog(); showChangeAccountConfirmAlertDialog();
} }
} else { } else {
@ -157,15 +165,15 @@ public class NotesPreferenceActivity extends PreferenceActivity {
private void loadSyncButton() { private void loadSyncButton() {
Button syncButton = (Button) findViewById(R.id.preference_sync_button); Button syncButton = (Button) findViewById(R.id.preference_sync_button);
TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview); TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview);
// set button state
if (GTaskSyncService.isSyncing()) { if (GTaskSyncService.isSyncing()) {
syncButton.setText(getString(R.string.preferences_button_sync_cancel)); syncButton.setText(getString(R.string.preferences_button_sync_cancel));
syncButton.setOnClickListener(new View.OnClickListener() { syncButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
GTaskSyncService.cancelSync(NotesPreferenceActivity.this); GTaskSyncService.cancelSync(NotesPreferenceActivity.this);
} }
}); });
} else { } else {
syncButton.setText(getString(R.string.preferences_button_sync_immediately)); syncButton.setText(getString(R.string.preferences_button_sync_immediately));
syncButton.setOnClickListener(new View.OnClickListener() { syncButton.setOnClickListener(new View.OnClickListener() {
@ -173,21 +181,25 @@ public class NotesPreferenceActivity extends PreferenceActivity {
GTaskSyncService.startSync(NotesPreferenceActivity.this); GTaskSyncService.startSync(NotesPreferenceActivity.this);
} }
}); });
} }
syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this))); syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this)));
// set last sync time
if (GTaskSyncService.isSyncing()) { if (GTaskSyncService.isSyncing()) {
lastSyncTimeView.setText(GTaskSyncService.getProgressString()); lastSyncTimeView.setText(GTaskSyncService.getProgressString());
lastSyncTimeView.setVisibility(View.VISIBLE); lastSyncTimeView.setVisibility(View.VISIBLE);
} else { } else {
long lastSyncTime = getLastSyncTime(this); long lastSyncTime = getLastSyncTime(this);
if (lastSyncTime != 0) { if (lastSyncTime != 0) {
lastSyncTimeView.setText(getString(R.string.preferences_last_sync_time, lastSyncTimeView.setText(getString(R.string.preferences_last_sync_time,
DateFormat.format(getString(R.string.preferences_last_sync_time_format), DateFormat.format(getString(R.string.preferences_last_sync_time_format),
lastSyncTime))); lastSyncTime)));
lastSyncTimeView.setVisibility(View.VISIBLE); lastSyncTimeView.setVisibility(View.VISIBLE);
} else { } else {
lastSyncTimeView.setVisibility(View.GONE); lastSyncTimeView.setVisibility(View.GONE);
} }
} }
@ -201,6 +213,7 @@ public class NotesPreferenceActivity extends PreferenceActivity {
private void showSelectAccountAlertDialog() { private void showSelectAccountAlertDialog() {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null); View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null);
TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title); TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title);
titleTextView.setText(getString(R.string.preferences_dialog_select_account_title)); titleTextView.setText(getString(R.string.preferences_dialog_select_account_title));
@ -249,9 +262,11 @@ public class NotesPreferenceActivity extends PreferenceActivity {
"gmail-ls" "gmail-ls"
}); });
startActivityForResult(intent, -1); startActivityForResult(intent, -1);
dialog.dismiss(); dialog.dismiss();
} }
}); });
} }
private void showChangeAccountConfirmAlertDialog() { private void showChangeAccountConfirmAlertDialog() {
@ -263,6 +278,7 @@ public class NotesPreferenceActivity extends PreferenceActivity {
getSyncAccountName(this))); getSyncAccountName(this)));
TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle); TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle);
subtitleTextView.setText(getString(R.string.preferences_dialog_change_account_warn_msg)); subtitleTextView.setText(getString(R.string.preferences_dialog_change_account_warn_msg));
dialogBuilder.setCustomTitle(titleView); dialogBuilder.setCustomTitle(titleView);
CharSequence[] menuItemArray = new CharSequence[] { CharSequence[] menuItemArray = new CharSequence[] {
@ -270,8 +286,10 @@ public class NotesPreferenceActivity extends PreferenceActivity {
getString(R.string.preferences_menu_remove_account), getString(R.string.preferences_menu_remove_account),
getString(R.string.preferences_menu_cancel) getString(R.string.preferences_menu_cancel)
}; };
dialogBuilder.setItems(menuItemArray, new DialogInterface.OnClickListener() { dialogBuilder.setItems(menuItemArray, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
if (which == 0) { if (which == 0) {
showSelectAccountAlertDialog(); showSelectAccountAlertDialog();
} else if (which == 1) { } else if (which == 1) {
@ -281,28 +299,32 @@ public class NotesPreferenceActivity extends PreferenceActivity {
} }
}); });
dialogBuilder.show(); dialogBuilder.show();
} }
private Account[] getGoogleAccounts() { private Account[] getGoogleAccounts() {
AccountManager accountManager = AccountManager.get(this); AccountManager accountManager = AccountManager.get(this);
return accountManager.getAccountsByType("com.google"); return accountManager.getAccountsByType("com.google");
} }
private void setSyncAccount(String account) { private void setSyncAccount(String account) {
if (!getSyncAccountName(this).equals(account)) { if (!getSyncAccountName(this).equals(account)) {
SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit(); SharedPreferences.Editor editor = settings.edit();
if (account != null) { if (account != null) {
editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, account); editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, account);
} else { } else {
editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, "");
} }
editor.commit(); editor.commit();
// clean up last sync time
setLastSyncTime(this, 0); setLastSyncTime(this, 0);
// clean up local gtask related info
new Thread(new Runnable() { new Thread(new Runnable() {
public void run() { public void run() {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
@ -312,15 +334,18 @@ public class NotesPreferenceActivity extends PreferenceActivity {
} }
}).start(); }).start();
Toast.makeText(NotesPreferenceActivity.this, Toast.makeText(NotesPreferenceActivity.this,
getString(R.string.preferences_toast_success_set_accout, account), getString(R.string.preferences_toast_success_set_accout, account),
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
} }
} }
private void removeSyncAccount() { private void removeSyncAccount() {
SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit(); SharedPreferences.Editor editor = settings.edit();
if (settings.contains(PREFERENCE_SYNC_ACCOUNT_NAME)) { if (settings.contains(PREFERENCE_SYNC_ACCOUNT_NAME)) {
editor.remove(PREFERENCE_SYNC_ACCOUNT_NAME); editor.remove(PREFERENCE_SYNC_ACCOUNT_NAME);
} }
@ -329,7 +354,8 @@ public class NotesPreferenceActivity extends PreferenceActivity {
} }
editor.commit(); editor.commit();
// clean up local gtask related info
new Thread(new Runnable() { new Thread(new Runnable() {
public void run() { public void run() {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
@ -338,20 +364,25 @@ public class NotesPreferenceActivity extends PreferenceActivity {
getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null);
} }
}).start(); }).start();
} }
public static String getSyncAccountName(Context context) { public static String getSyncAccountName(Context context) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE); Context.MODE_PRIVATE);
return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, "");
} }
public static void setLastSyncTime(Context context, long time) { public static void setLastSyncTime(Context context, long time) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE); Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit(); SharedPreferences.Editor editor = settings.edit();
editor.putLong(PREFERENCE_LAST_SYNC_TIME, time); editor.putLong(PREFERENCE_LAST_SYNC_TIME, time);
editor.commit(); editor.commit();
} }
public static long getLastSyncTime(Context context) { public static long getLastSyncTime(Context context) {
@ -360,6 +391,7 @@ public class NotesPreferenceActivity extends PreferenceActivity {
return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0); return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0);
} }
private class GTaskReceiver extends BroadcastReceiver { private class GTaskReceiver extends BroadcastReceiver {
@Override @Override
@ -374,6 +406,7 @@ public class NotesPreferenceActivity extends PreferenceActivity {
} }
} }
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case android.R.id.home: case android.R.id.home:
@ -386,3 +419,4 @@ public class NotesPreferenceActivity extends PreferenceActivity {
} }
} }
} }

@ -46,6 +46,7 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider {
private static final String TAG = "NoteWidgetProvider"; private static final String TAG = "NoteWidgetProvider";
@Override @Override
//小组件被删除时被调用
public void onDeleted(Context context, int[] appWidgetIds) { public void onDeleted(Context context, int[] appWidgetIds) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
@ -57,6 +58,8 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider {
} }
} }
//用于查询与给定小组件ID相关的笔记信息并返回一个Cursor对象
private Cursor getNoteWidgetInfo(Context context, int widgetId) { private Cursor getNoteWidgetInfo(Context context, int widgetId) {
return context.getContentResolver().query(Notes.CONTENT_NOTE_URI, return context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION, PROJECTION,
@ -69,6 +72,8 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider {
update(context, appWidgetManager, appWidgetIds, false); update(context, appWidgetManager, appWidgetIds, false);
} }
//根据查询结果设置小组件的背景资源、文本内容和点击意图并通过AppWidgetManager的updateAppWidget方法更新小组件的视图
private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds, private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds,
boolean privacyMode) { boolean privacyMode) {
for (int i = 0; i < appWidgetIds.length; i++) { for (int i = 0; i < appWidgetIds.length; i++) {
@ -106,6 +111,7 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider {
/** /**
* Generate the pending intent to start host for the widget * Generate the pending intent to start host for the widget
*/ */
//根据小组件ID查询对应的笔记信息并根据查询结果设置相应的视图内容。如果查询结果为空则显示默认的提示文本和插入/编辑操作的意图
PendingIntent pendingIntent = null; PendingIntent pendingIntent = null;
if (privacyMode) { if (privacyMode) {
rv.setTextViewText(R.id.widget_text, rv.setTextViewText(R.id.widget_text,

@ -23,9 +23,10 @@ import net.micode.notes.R;
import net.micode.notes.data.Notes; import net.micode.notes.data.Notes;
import net.micode.notes.tool.ResourceParser; import net.micode.notes.tool.ResourceParser;
//NoteWidgetProvider_2x类继承自NoteWidgetProvider并覆盖了其中的一些方法
public class NoteWidgetProvider_2x extends NoteWidgetProvider { public class NoteWidgetProvider_2x extends NoteWidgetProvider {
@Override @Override
//小组件需要更新时被调用。它调用父类的update方法并传入相应的参数。
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.update(context, appWidgetManager, appWidgetIds); super.update(context, appWidgetManager, appWidgetIds);
} }
@ -36,11 +37,13 @@ public class NoteWidgetProvider_2x extends NoteWidgetProvider {
} }
@Override @Override
//根据给定的背景ID返回相应的背景资源ID。这里调用了ResourceParser类的静态方法getWidget2xBgResource来获取2x小组件的背景资源ID。
protected int getBgResourceId(int bgId) { protected int getBgResourceId(int bgId) {
return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId); return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId);
} }
@Override @Override
//返回小组件的类型
protected int getWidgetType() { protected int getWidgetType() {
return Notes.TYPE_WIDGET_2X; return Notes.TYPE_WIDGET_2X;
} }

@ -23,7 +23,7 @@ import net.micode.notes.R;
import net.micode.notes.data.Notes; import net.micode.notes.data.Notes;
import net.micode.notes.tool.ResourceParser; import net.micode.notes.tool.ResourceParser;
//跟Provider_2x一模一样类名字不同
public class NoteWidgetProvider_4x extends NoteWidgetProvider { public class NoteWidgetProvider_4x extends NoteWidgetProvider {
@Override @Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {

Loading…
Cancel
Save