最终代码

ganshihao_branch
ganshihao 10 months ago
parent 5235166661
commit 2fb0fe6f1b

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:theme="@style/ThemeOverlay.Notesmaster3.FullscreenContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/fullscreenBackgroundColor"
tools:context=".ui.SplashActivity">
<!-- The primary full-screen view. This can be replaced with whatever view
is needed to present your content, e.g. VideoView, SurfaceView,
TextureView, etc. -->
<!-- This FrameLayout insets its children based on system windows using
android:fitsSystemWindows. -->
<TextView
android:id="@id/fullscreen_content_controls"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:keepScreenOn="true"
android:text="@string/dummy_content"
android:textColor="#33b5e5"
android:textSize="50sp"
android:textStyle="bold" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<LinearLayout
android:id="@+id/fullscreen_content_controls"
style="@style/Widget.Theme.Notesmaster3.ButtonBar.Fullscreen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:orientation="horizontal"
tools:ignore="UselessParent">
<Button
android:id="@+id/dummy_button"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/dummy_button" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/opic"
android:gravity="top"
android:keepScreenOn="true"
android:text="欢迎使用"
android:textSize="50sp"
android:textStyle="bold"
/>
</FrameLayout>
</FrameLayout>

@ -397,4 +397,20 @@
android:src="@drawable/selected" />
</FrameLayout>
</LinearLayout>
<ImageButton
android:id="@+id/add_img_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="7dp"
android:layout_marginTop="600dp"
android:layout_marginBottom="7dp"
android:src="@android:drawable/ic_menu_gallery" />
<TextView
android:id="@+id/text_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|center_vertical"
android:layout_marginRight="8dip" />
</FrameLayout>

@ -49,4 +49,5 @@
<item
android:id="@+id/menu_delete_remind"
android:title="@string/menu_remove_remind" />
</menu>

@ -36,4 +36,7 @@
<item
android:id="@+id/menu_search"
android:title="@string/menu_search"/>
<item
android:id="@+id/menu_countallNotes"
android:title="@string/menu_countallNotes"/>
</menu>

@ -0,0 +1,6 @@
<resources>
<style name="ThemeOverlay.Notesmaster3.FullscreenContainer" parent="">
<item name="fullscreenBackgroundColor">@color/light_blue_900</item>
<item name="fullscreenTextColor">@color/light_blue_A400</item>
</style>
</resources>

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)

@ -0,0 +1,6 @@
<resources>
<declare-styleable name="FullscreenAttrs">
<attr name="fullscreenBackgroundColor" format="color" />
<attr name="fullscreenTextColor" format="color" />
</declare-styleable>
</resources>

@ -17,4 +17,9 @@
<resources>
<color name="user_query_highlight">#335b5b5b</color>
<color name="light_blue_600">#FF039BE5</color>
<color name="light_blue_900">#FF01579B</color>
<color name="light_blue_A200">#FF40C4FF</color>
<color name="light_blue_A400">#FF00B0FF</color>
<color name="black_overlay">#66000000</color>
</resources>

@ -131,5 +131,11 @@
<!-- Case of 0 or 2 or more results. -->
<item quantity="other"><xliff:g id="number" example="15">%1$s</xliff:g> results for \"<xliff:g id="search" example="???">%2$s</xliff:g>\"</item>
</plurals>
<string name="title_activity_fullscreen">FullscreenActivity</string>
<string name="dummy_button">Dummy Button</string>
<string name="dummy_content">欢迎使用</string>
<string name="title_activity_splash">SplashActivity</string>
<string name="menu_countallNotes" translatable="false">countallNotes" </string>
<string name="menu_font_style">Select font</string>
</resources>

@ -64,6 +64,15 @@
<style name="NoteActionBarStyle" parent="@android:style/Widget.Holo.Light.ActionBar.Solid">
<item name="android:displayOptions" />
<item name="android:visibility">gone</item>
<item name="android:visibility">visible</item>
</style>
<style name="Widget.Theme.Notesmaster3.ActionBar.Fullscreen"
parent="Widget.AppCompat.ActionBar">
<item name="android:background">@color/black_overlay</item>
</style>
<style name="Widget.Theme.Notesmaster3.ButtonBar.Fullscreen" parent="">
<item name="android:background">@color/black_overlay</item>
<item name="android:buttonBarStyle">?android:attr/buttonBarStyle</item>
</style>
</resources>

@ -0,0 +1,14 @@
<resources>
<style name="Theme.Notesmaster3" parent="Theme.AppCompat.Light"/>
<style name="Theme.Notesmaster3.Fullscreen" parent="Theme.Notesmaster3">
<item name="android:actionBarStyle">@style/Widget.Theme.Notesmaster3.ActionBar.Fullscreen
</item>
<item name="android:windowActionBarOverlay">true</item>
<item name="android:windowBackground">@null</item>
</style>
<style name="ThemeOverlay.Notesmaster3.FullscreenContainer" parent="">
<item name="fullscreenBackgroundColor">@color/light_blue_600</item>
<item name="fullscreenTextColor">@color/light_blue_A200</item>
</style>
</resources>

@ -13,74 +13,64 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
package net.micode.notes.data;
/**
*Android
*/
import android.content.Context;//引入context类用于提供全局信息环境
import android.database.Cursor;//引入cursor类表示数据库的结果集
import android.provider.ContactsContract.CommonDataKinds.Phone;//引入其中的Phone子类包含了关于联系人电话号码的常量定义
import android.provider.ContactsContract.Data;//引入ContactsContract类中的Data类用于访问设备上的联系人数据
import android.telephony.PhoneNumberUtils;//引入PhoneNumberUtils类提供电话号码处理的实用方法
import android.util.Log;//引入Log类它提供在代码中打印日志信息的方法
import android.content.Context; //用于获取应用程序的上下文。
import android.database.Cursor; //用于在查询结果中移动并访问特定列的数据。
import android.provider.ContactsContract.CommonDataKinds.Phone; //用于访问通讯录中电话号码相关的数据。
import android.provider.ContactsContract.Data; //通讯录数据的内容提供者,用于访问通讯录数据。
import android.telephony.PhoneNumberUtils; //包含用于处理电话号码的实用方法。
import android.util.Log; //用于在Android中记录调试信息的类。
import java.util.HashMap; //Java中的HashMap类用于存储联系人姓名和手机号码的映射关系。
import java.util.HashMap;
public class Contact {
private static HashMap<String, String> sContactCache;
private static final String TAG = "Contact"; //包含一个私有静态变量sContactCache
//用于缓存联系人信息以及一个私有静态常量TAG用于在日志中标识这个类。
//键值对数据结构电话号码可以作为键联系人姓名作为值TAG是用于日志记录的标签常量。
private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER //PHONE_NUMBERS_EQUAL()是一个内置函数,用于比较两个电话号码是否相等。
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"//Phone.NUMBER是通讯录中电话号码的列名
+ " AND " + Data.RAW_CONTACT_ID + " IN " //Data.MIMETYPE是通讯录数据中的MIME类型列名用于指定查询电话号码的数据类型为电话号码。
+ "(SELECT raw_contact_id " //Phone.CONTENT_ITEM_TYPE是电话号码的MIME类型值。
+ " FROM phone_lookup" //Data.RAW_CONTACT_ID是通讯录数据中的原始联系人ID列名。
+ " WHERE min_match = '+')"; //phone_lookup是一个表名用于存储电话号码的查找结果。
//用于实现根据给定的手机号码获取对应的联系人姓名
public class Contact {
private static HashMap<String, String> sContactCache;//用于缓存已查询的联系人信息,键是手机号码,值是对应的联系人姓名
private static final String TAG = "Contact";//定义一个常量,用于在日志中打印标签
/**
* .
* @param context
* @param phoneNumber
* @return
*/
private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
+ " AND " + Data.RAW_CONTACT_ID + " IN "
+ "(SELECT raw_contact_id "
+ " FROM phone_lookup"
+ " WHERE min_match = '+')";
public static String getContact(Context context, String phoneNumber) {
if(sContactCache == null) { //首先检查sContactCache是否为null如果是则初始化一个新的HashMap.
public static String getContact(Context context, String phoneNumber) { //用于根据给定的电话号码查询联系人
if(sContactCache == null) { // 如果sContactCache为空则创建一个新的HashMap对象
sContactCache = new HashMap<String, String>();
}
if(sContactCache.containsKey(phoneNumber)) { //接下来如果sContactCache中包含给定电话号码的键值对则直接返回缓存中的联系人姓名。
// 如果sContactCache中已经包含了phoneNumber对应的联系人姓名则直接返回缓存中的姓名
if(sContactCache.containsKey(phoneNumber)) {
return sContactCache.get(phoneNumber);
}
String selection = CALLER_ID_SELECTION.replace("+", //首先将给定的电话号码转换为最小匹配形式然后使用replace()方法将查询条件中的"+"替换为最小匹配的电话号码形式。
String selection = CALLER_ID_SELECTION.replace("+",
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
Cursor cursor = context.getContentResolver().query( //执行了一个查询操作该方法会返回一个Cursor对象用于遍历查询结果
Data.CONTENT_URI, //指定了要查询的数据表的URI表示通讯录数据。
new String [] { Phone.DISPLAY_NAME }, //是要查询的列名,这里是查询联系人的显示名称。
selection, //是查询条件,根据前面处理过的最小匹配电话号码来查询匹配的联系人信息。
new String[] { phoneNumber }, //是查询条件中的参数值,用于替换查询条件中的"?"占位符。
null); //最后一个参数是排序方式,这里为空,表示不进行排序。
if (cursor != null && cursor.moveToFirst()) { //这个条件语句检查Cursor对象是否不为空并且能够将游标移动到第一行。如果满足条件则表示查询结果非空且至少存在一个匹配项。
Cursor cursor = context.getContentResolver().query(
Data.CONTENT_URI,
new String [] { Phone.DISPLAY_NAME },
selection,
new String[] { phoneNumber },
null);
// 如果查询结果不为空同时在移动到第一条记录的情况下将从Cursor中获取联系人姓名
if (cursor != null && cursor.moveToFirst()) {
try {
String name = cursor.getString(0); //获取查询结果中第一列索引为0的数据即联系人的显示名称。
sContactCache.put(phoneNumber, name); //将此信息存储在sContactCache缓存中
String name = cursor.getString(0);
sContactCache.put(phoneNumber, name);
return name;
} catch (IndexOutOfBoundsException e) { //如果在获取查询结果的过程中发生异常说明查询结果中没有有效数据此时会打印错误日志并返回null
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, " Cursor get string error " + e.toString());
return null;
} finally { //无论是否出现异常最后都会通过cursor.close()方法关闭Cursor对象释放资源。
} finally {
cursor.close();
}
} else { //如果查询结果为空或者没有匹配项就会执行这个分支。它会打印调试日志指示没有找到与给定电话号码匹配的联系人并返回null。
} else {
// 如果查询结果为空打印日志并返回null表示没有找到匹配的联系人
Log.d(TAG, "No contact matched with number:" + phoneNumber);
return null;
}
}
}

@ -1,26 +1,14 @@
/*
* 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.data;
import android.content.ContentUris;
import android.net.Uri;
// Notes 类中定义了很多常量这些常量大多是int型和string型
public class Notes {
public static final String AUTHORITY = "micode_notes"; //定义了一个字符串常量AUTHORITY代表了内容提供者的授权信息。
public static final String TAG = "Notes"; //定义了一个字符串常量TAG可能用于在日志中进行标记或调试。
public static final int TYPE_NOTE = 0; //定义了三个整型常量,分别表示笔记、文件夹和系统类型。
public static final String AUTHORITY = "micode_notes";
public static final String TAG = "Notes";
//以下三个常量对NoteColumns.TYPE的值进行设置时会用到
public static final int TYPE_NOTE = 0;
public static final int TYPE_FOLDER = 1;
public static final int TYPE_SYSTEM = 2;
@ -30,23 +18,35 @@ public class Notes {
* {@link Notes#ID_TEMPARAY_FOLDER } is for notes belonging no folder
* {@link Notes#ID_CALL_RECORD_FOLDER} is to store call records
*/
public static final int ID_ROOT_FOLDER = 0; //定义了一些文件夹的标识符常量。ID_ROOT_FOLDER表示根文件夹的标识符为0
public static final int ID_TEMPARAY_FOLDER = -1; //表示临时文件夹的标识符为-1
public static final int ID_CALL_RECORD_FOLDER = -2; //表示通话记录文件夹的标识符为-2
public static final int ID_TRASH_FOLER = -3; //ID_TRASH_FOLER表示回收站文件夹的标识符为-3
//定义了一些 Intent 传递参数的键名常量
public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date";//日期
public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id";//背景颜色
public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id";//小部件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";//文件夹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_2X = 0; //2x大小的小部件类型
public static final int TYPE_WIDGET_4X = 1; //4x
public static class DataConstants { //内部静态类(定义在一个类的内部,无法从内部静态类的实例中访问外部类的非静态成员)
public static final int ID_ROOT_FOLDER = 0;
public static final int ID_TEMPARAY_FOLDER = -1;
public static final int ID_CALL_RECORD_FOLDER = -2;
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_BACKGROUND_ID =
"net.micode.notes.background_color_id";
public static final String INTENT_EXTRA_WIDGET_ID =
"net.micode.notes.widget_id";
public static final String INTENT_EXTRA_WIDGET_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_2X = 0;
public static final int TYPE_WIDGET_4X = 1;
public static class DataConstants {
public static final String NOTE = TextNote.CONTENT_ITEM_TYPE;
public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE;
}
@ -54,18 +54,20 @@ public class Notes {
/**
* 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
*/
public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data");//可以用于在应用程序中执行查询操作,以获取特定类型的数据。
public static final Uri CONTENT_DATA_URI = Uri.parse("content://" +
/**
* JavaNoteColumns
*/
//Uri统一资源标识符是用来唯一标识资源的字符串格式。在Android中Uri经常被用于访问和操作应用程序中的数据
AUTHORITY + "/data");//定义查找数据的指针。
// 定义NoteColumns的常量,用于后面创建数据库的表头
public interface NoteColumns {
/**
* The unique ID for a row
@ -77,7 +79,7 @@ public class Notes {
* The parent's id for note or folder
* <P> Type: INTEGER (long) </P>
*/
public static final String PARENT_ID = "parent_id";
public static final String PARENT_ID = "parent_id";//为什么会有parent_id
/**
* Created data for note or folder
@ -145,7 +147,7 @@ public class Notes {
* The last sync id
* <P> Type: INTEGER (long) </P>
*/
public static final String SYNC_ID = "sync_id";
public static final String SYNC_ID = "sync_id";//同步
/**
* Sign to indicate local modified or not
@ -170,11 +172,9 @@ public class Notes {
* <P> Type : INTEGER (long) </P>
*/
public static final String VERSION = "version";
}
}//这些常量主要是定义便签的属性的。
/**
* JavaDataColumns
*/
// 定义DataColumns的常量,用于后面创建数据库的表头
public interface DataColumns {
/**
* The unique ID for a row
@ -214,56 +214,66 @@ 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
* <P> Type: INTEGER </P>
*/
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
* <P> Type: INTEGER </P>
*/
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
* <P> Type: TEXT </P>
*/
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
* <P> Type: TEXT </P>
*/
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
* <P> Type: TEXT </P>
*/
public static final String DATA5 = "data5";
}
}//主要是定义存储便签内容数据的
public static final class TextNote implements DataColumns {
/**
* Mode to indicate the text in check list mode or not
* <P> Type: Integer 1:check list mode 0: normal mode </P>
*/
public static final String MODE = DATA1; //模式
public static final String MODE = DATA1;
public static final int MODE_CHECK_LIST = 1; //1是检查模式0是普通模式
public static final int MODE_CHECK_LIST = 1;
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note";//MIME类型指定返回的数据类型为目录类型
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");//标示URI访问内容
}
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 {
/**
@ -276,12 +286,18 @@ public class Notes {
* Phone number for this record
* <P> Type: TEXT </P>
*/
public static final String PHONE_NUMBER = DATA3; //通话记录的日期
public static final String PHONE_NUMBER = DATA3;
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note";//电话号码
public static final String CONTENT_TYPE =
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");//表示通话记录的内容URI用于访问通话记录的内容。
}
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");
}//电话内容的数据结构
}

@ -27,57 +27,50 @@ import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
public class NotesDatabaseHelper extends SQLiteOpenHelper { //类的继承,前是后的子集
private static final String DB_NAME = "note.db"; //私有变量
public class NotesDatabaseHelper extends SQLiteOpenHelper {
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 { //内部接口table
public static final String NOTE = "note"; //笔记本的名字叫note
public interface TABLE {
public static final String NOTE = "note";
public static final String DATA = "data"; //数据表的名字叫data
public static final String DATA = "data";
}
private static final String TAG = "NotesDatabaseHelper"; //日志标签,用于在日志中标记该类的信息
private static final String TAG = "NotesDatabaseHelper";
private static NotesDatabaseHelper mInstance; //mInstance会在NotesDatabaseHelper类中作为单例模式的实现以确保在应用程序中只有一个NotesDatabaseHelper类的实例被创建并被全局范围内所使用。
private static NotesDatabaseHelper mInstance;
/**
*
*/
private static final String CREATE_NOTE_TABLE_SQL =
"CREATE TABLE " + TABLE.NOTE + "(" +
NoteColumns.ID + " INTEGER PRIMARY KEY," + //主键(保证表中的每一行都有唯一性)
NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + //父级的id
NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + //用于标识的标识符
NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + //背景颜色
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + //笔记的创建时间
NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," + //表示是否包含部件
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + //笔记的修改时间
NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + //子笔记的数量
NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + //笔记的摘要或片段内容
NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + //类型
NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + //关联的小部件的id
NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + //小部件的类型
NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + //用于同步的id与远程同步服务有关
NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," + //笔记是否在本地被修改
NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + //原始父级的id
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + //google任务服务的id
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + //笔记的版本号
NoteColumns.ID + " INTEGER PRIMARY KEY," +
NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," +
NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +
")";
/**
* SQLSQL
*/
private static final String CREATE_DATA_TABLE_SQL =
"CREATE TABLE " + TABLE.DATA + "(" +
DataColumns.ID + " INTEGER PRIMARY KEY," + //DataColumns.ID表示一个名为"ID"的列数据类型为INTEGER(整数),并且被定义为主键。
DataColumns.MIME_TYPE + " TEXT NOT NULL," + //版本
DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + //笔记的名称
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + //创建时间
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + //上一次修改时间
DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," + //摘要
DataColumns.ID + " INTEGER PRIMARY KEY," +
DataColumns.MIME_TYPE + " TEXT NOT NULL," +
DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA1 + " INTEGER," +
DataColumns.DATA2 + " INTEGER," +
DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," +
@ -213,18 +206,10 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { //类的继承,
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END";
/**
* cotext
* @param context
*/
public NotesDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
/**
* note
* @param db
*/
public void createNoteTable(SQLiteDatabase db) {
db.execSQL(CREATE_NOTE_TABLE_SQL);
reCreateNoteTableTriggers(db);
@ -250,10 +235,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { //类的继承,
db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
}
/**
*
* @param db
*/
private void createSystemFolder(SQLiteDatabase db) {
ContentValues values = new ContentValues();
@ -289,10 +270,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { //类的继承,
db.insert(TABLE.NOTE, null, values);
}
/**
* SQL
* @param db
*/
public void createDataTable(SQLiteDatabase db) {
db.execSQL(CREATE_DATA_TABLE_SQL);
reCreateDataTableTriggers(db);
@ -300,10 +277,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { //类的继承,
Log.d(TAG, "data table has been created");
}
/**
*
* @param 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_update");
@ -314,47 +287,37 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { //类的继承,
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER);
}
static synchronized NotesDatabaseHelper getInstance(Context context) { //static synchronized 是Java中的修饰符用于同时指定一个方法或代码块为静态和同步。
static synchronized NotesDatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new NotesDatabaseHelper(context);
}
return mInstance;
}
/**
*
* @param db
*/
@Override
public void onCreate(SQLiteDatabase db) {
createNoteTable(db);
createDataTable(db);
}
/**
*
* @param db
* @param oldVersion
* @param newVersion
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { //db是要升级的数据库对象oldVersion是当前数据库版本号newVersion是要升级到的新版本号。
boolean reCreateTriggers = false; //是否重新创建触发器和是否跳过V2版本的升级。
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
boolean reCreateTriggers = false;
boolean skipV2 = false;
if (oldVersion == 1) { //执行升级到V2版本的操作。
if (oldVersion == 1) {
upgradeToV2(db);
skipV2 = true; // this upgrade including the upgrade from v2 to v3
oldVersion++;
}
if (oldVersion == 2 && !skipV2) { //执行升级到V3版本的操作。
if (oldVersion == 2 && !skipV2) {
upgradeToV3(db);
reCreateTriggers = true;
oldVersion++;
}
if (oldVersion == 3) { //执行升级到V4版本的操作。
if (oldVersion == 3) {
upgradeToV4(db);
oldVersion++;
}
@ -364,36 +327,36 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { //类的继承,
reCreateDataTableTriggers(db);
}
if (oldVersion != newVersion) { //判断升级后的数据库版本号是否与目标版本号相等。如果不相等,则抛出一个异常。
if (oldVersion != newVersion) {
throw new IllegalStateException("Upgrade notes database to version " + newVersion
+ "fails");
}
}
private void upgradeToV2(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); //删除名为Note和Data的表。
db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE);
db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA);
createNoteTable(db); //创建新的表
createNoteTable(db);
createDataTable(db);
}
private void upgradeToV3(SQLiteDatabase db) {
// drop unused triggers
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert"); //删除三个触发器
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert");
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete");
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update");
// add a column for gtask id
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID //向Note表中添加一个名为gtask_id的列。该列的数据类型为TEXT非空并设置默认值为空字符串。
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID
+ " TEXT NOT NULL DEFAULT ''");
// add a trash system folder
ContentValues values = new ContentValues(); //创建一个ContentValues对象用于存储待插入到数据库的键值对。
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); //系统级别的文件夹,用于存放已经删除的笔记。
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); //表示向Note表中插入的记录类型为Notes.TYPE_SYSTEM即系统级别的记录
ContentValues values = new ContentValues();
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
}
private void upgradeToV4(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION //向Note表中添加一个名为version的列。该列的数据类型为INTEGER
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0");
}
}

@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//执行与 GTaskGoogle 任务)相关的同步操作,并在执行过程中显示通知,并在操作完成后调用回调接口通知完成事件。
package net.micode.notes.gtask.remote;
@ -28,7 +29,6 @@ import net.micode.notes.R;
import net.micode.notes.ui.NotesListActivity;
import net.micode.notes.ui.NotesPreferenceActivity;
public class GTaskASyncTask extends AsyncTask<Void, String, Integer> {
private static int GTASK_SYNC_NOTIFICATION_ID = 5234235;
@ -37,13 +37,13 @@ public class GTaskASyncTask extends AsyncTask<Void, String, Integer> {
void onComplete();
}
private Context mContext;
private Context mContext;//成员变量——上下文对象,用于获取系统服务。
private NotificationManager mNotifiManager;
private NotificationManager mNotifiManager;//成员变量——通知管理器,用于发送通知。
private GTaskManager mTaskManager;
private GTaskManager mTaskManager;//成员变量——GTaskManager 实例,用于执行 GTask 相关的操作。
private OnCompleteListener mOnCompleteListener;
private OnCompleteListener mOnCompleteListener;//成员变量——任务完成的回调接口。
public GTaskASyncTask(Context context, OnCompleteListener listener) {
mContext = context;
@ -53,16 +53,19 @@ public class GTaskASyncTask extends AsyncTask<Void, String, Integer> {
mTaskManager = GTaskManager.getInstance();
}
//取消同步操作,调用 mTaskManager.cancelSync()
public void cancelSync() {
mTaskManager.cancelSync();
}
//更新执行进度,调用 publishProgress(),并传入进度信息。
public void publishProgess(String message) {
publishProgress(new String[] {
message
});
}
//向用户提示当前同步的状态,显示通知,是一个用于交互的方法
private void showNotification(int tickerId, String content) {
Notification notification = new Notification(R.drawable.notification, mContext
.getString(tickerId), System.currentTimeMillis());
@ -77,11 +80,14 @@ public class GTaskASyncTask extends AsyncTask<Void, String, Integer> {
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesListActivity.class), 0);
}
notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
pendingIntent);
// notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
// pendingIntent);
notification.contentIntent = pendingIntent;
mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);
}
//此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间
@Override
protected Integer doInBackground(Void... unused) {
publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity
@ -89,6 +95,7 @@ public class GTaskASyncTask extends AsyncTask<Void, String, Integer> {
return mTaskManager.sync(mContext, this);
}
//可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
@Override
protected void onProgressUpdate(String... progress) {
showNotification(R.string.ticker_syncing, progress[0]);
@ -97,6 +104,7 @@ public class GTaskASyncTask extends AsyncTask<Void, String, Integer> {
}
}
//相当于Handler 处理UI的方式在这里面可以使用在doInBackground 得到的结果处理操作UI
@Override
protected void onPostExecute(Integer result) {
if (result == GTaskManager.STATE_SUCCESS) {

@ -13,6 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* GTASKGTASK
* 使accountManager JSONObject HttpParams authToken Gid
*/
package net.micode.notes.gtask.remote;
@ -60,7 +64,6 @@ import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
<<<<<<< HEAD
//标明了这个类的名字
public class GTaskClient {
private static final String TAG = GTaskClient.class.getSimpleName(); //私有化一个用于日志输出的标签常量
@ -95,40 +98,6 @@ public class GTaskClient {
//GTaskClient 类的一个私有构造方法,使用 private 关键字修饰,表示只能在类内部调用
private GTaskClient() {
mHttpClient = null; //初始化为null
=======
public class GTaskClient {
private static final String TAG = GTaskClient.class.getSimpleName();
private static final String GTASK_URL = "https://mail.google.com/tasks/";
private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig";
private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig";
private static GTaskClient mInstance = null;
private DefaultHttpClient mHttpClient;
private String mGetUrl;
private String mPostUrl;
private long mClientVersion;
private boolean mLoggedin;
private long mLastLoginTime;
private int mActionId;
private Account mAccount;
private JSONArray mUpdateArray;
private GTaskClient() {
mHttpClient = null;
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
mGetUrl = GTASK_GET_URL;
mPostUrl = GTASK_POST_URL;
mClientVersion = -1;
@ -139,7 +108,6 @@ public class GTaskClient {
mUpdateArray = null;
}
<<<<<<< HEAD
//用来获取的实例化对象
public static synchronized GTaskClient getInstance() { //使用 public 关键字修饰,表示可以从任何地方访问
if (mInstance == null) { //首先判断 mInstance 是否为 null即判断是否已经存在单例实例
@ -258,121 +226,11 @@ public class GTaskClient {
//尝试登陆Gtask这只是一个预先判断令牌是否是有效以及是否能登上GTask的方法,而不是具体实现登陆的方法
=======
public static synchronized GTaskClient getInstance() {
if (mInstance == null) {
mInstance = new GTaskClient();
}
return mInstance;
}
public boolean login(Activity activity) {
// we suppose that the cookie would expire after 5 minutes
// then we need to re-login
final long interval = 1000 * 60 * 5;
if (mLastLoginTime + interval < System.currentTimeMillis()) {
mLoggedin = false;
}
// need to re-login after account switch
if (mLoggedin
&& !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity
.getSyncAccountName(activity))) {
mLoggedin = false;
}
if (mLoggedin) {
Log.d(TAG, "already logged in");
return true;
}
mLastLoginTime = System.currentTimeMillis();
String authToken = loginGoogleAccount(activity, false);
if (authToken == null) {
Log.e(TAG, "login google account failed");
return false;
}
// login with custom domain if necessary
if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase()
.endsWith("googlemail.com"))) {
StringBuilder url = new StringBuilder(GTASK_URL).append("a/");
int index = mAccount.name.indexOf('@') + 1;
String suffix = mAccount.name.substring(index);
url.append(suffix + "/");
mGetUrl = url.toString() + "ig";
mPostUrl = url.toString() + "r/ig";
if (tryToLoginGtask(activity, authToken)) {
mLoggedin = true;
}
}
// try to login with google official url
if (!mLoggedin) {
mGetUrl = GTASK_GET_URL;
mPostUrl = GTASK_POST_URL;
if (!tryToLoginGtask(activity, authToken)) {
return false;
}
}
mLoggedin = true;
return true;
}
private String loginGoogleAccount(Activity activity, boolean invalidateToken) {
String authToken;
AccountManager accountManager = AccountManager.get(activity);
Account[] accounts = accountManager.getAccountsByType("com.google");
if (accounts.length == 0) {
Log.e(TAG, "there is no available google account");
return null;
}
String accountName = NotesPreferenceActivity.getSyncAccountName(activity);
Account account = null;
for (Account a : accounts) {
if (a.name.equals(accountName)) {
account = a;
break;
}
}
if (account != null) {
mAccount = account;
} else {
Log.e(TAG, "unable to get an account with the same name in the settings");
return null;
}
// get the token now
AccountManagerFuture<Bundle> accountManagerFuture = accountManager.getAuthToken(account,
"goanna_mobile", null, activity, null, null);
try {
Bundle authTokenBundle = accountManagerFuture.getResult();
authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);
if (invalidateToken) {
accountManager.invalidateAuthToken("com.google", authToken);
loginGoogleAccount(activity, false);
}
} catch (Exception e) {
Log.e(TAG, "get auth token failed");
authToken = null;
}
return authToken;
}
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
private boolean tryToLoginGtask(Activity activity, String authToken) {
if (!loginGtask(authToken)) {
// maybe the auth token is out of date, now let's invalidate the
// token and try again
<<<<<<< HEAD
//删除过一个无效的authToken申请一个新的后再次尝试登陆
=======
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
authToken = loginGoogleAccount(activity, true);
if (authToken == null) {
Log.e(TAG, "login google account failed");
@ -387,7 +245,6 @@ public class GTaskClient {
return true;
}
<<<<<<< HEAD
//实现登录GTask的具体操作
private boolean loginGtask(String authToken) {
int timeoutConnection = 10000;
@ -397,22 +254,11 @@ public class GTaskClient {
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); //设置设置端口超时时间
mHttpClient = new DefaultHttpClient(httpParameters);
BasicCookieStore localBasicCookieStore = new BasicCookieStore(); //设置本地cookie
=======
private boolean loginGtask(String authToken) {
int timeoutConnection = 10000;
int timeoutSocket = 15000;
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
mHttpClient = new DefaultHttpClient(httpParameters);
BasicCookieStore localBasicCookieStore = new BasicCookieStore();
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
mHttpClient.setCookieStore(localBasicCookieStore);
HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false);
// login gtask
try {
<<<<<<< HEAD
String loginUrl = mGetUrl + "?auth=" + authToken; //设置登录的url
HttpGet httpGet = new HttpGet(loginUrl); //通过登录的uri实例化网页上资源的查找
HttpResponse response = null;
@ -423,17 +269,6 @@ public class GTaskClient {
List<Cookie> cookies = mHttpClient.getCookieStore().getCookies();
boolean hasAuthCookie = false;
for (Cookie cookie : cookies) { //看如果存有“GTL”则说明有验证成功的有效的cookie
=======
String loginUrl = mGetUrl + "?auth=" + authToken;
HttpGet httpGet = new HttpGet(loginUrl);
HttpResponse response = null;
response = mHttpClient.execute(httpGet);
// get the cookie now
List<Cookie> cookies = mHttpClient.getCookieStore().getCookies();
boolean hasAuthCookie = false;
for (Cookie cookie : cookies) {
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
if (cookie.getName().contains("GTL")) {
hasAuthCookie = true;
}
@ -443,21 +278,14 @@ public class GTaskClient {
}
// get the client version
<<<<<<< HEAD
//获取client的内容
=======
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
String resString = getResponseContent(response.getEntity());
String jsBegin = "_setup(";
String jsEnd = ")}</script>";
int begin = resString.indexOf(jsBegin);
int end = resString.lastIndexOf(jsEnd);
String jsString = null;
<<<<<<< HEAD
if (begin != -1 && end != -1 && begin < end) { //if循环用来在返回的Content中截取从_setup(开始到)}</script>中间的字符串内容也就是gtask_url的内容
=======
if (begin != -1 && end != -1 && begin < end) {
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
jsString = resString.substring(begin + jsBegin.length(), end);
}
JSONObject js = new JSONObject(jsString);
@ -479,15 +307,11 @@ public class GTaskClient {
return mActionId++;
}
<<<<<<< HEAD
//实例化创建一个用于向网络传输数据的对象
=======
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
private HttpPost createHttpPost() {
HttpPost httpPost = new HttpPost(mPostUrl);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
httpPost.setHeader("AT", "1");
<<<<<<< HEAD
return httpPost; //返回一个空的httpPost实例化对象
}
@ -495,39 +319,21 @@ public class GTaskClient {
private String getResponseContent(HttpEntity entity) throws IOException {
String contentEncoding = null;
if (entity.getContentEncoding() != null) { //使用getContentEncoding()获取网络上的资源和数据
=======
return httpPost;
}
private String getResponseContent(HttpEntity entity) throws IOException {
String contentEncoding = null;
if (entity.getContentEncoding() != null) {
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
contentEncoding = entity.getContentEncoding().getValue();
Log.d(TAG, "encoding: " + contentEncoding);
}
InputStream input = entity.getContent();
<<<<<<< HEAD
if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) { //GZIP是使用DEFLATE进行压缩数据的另一个压缩库
input = new GZIPInputStream(entity.getContent());
} else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) { //DEFLATE是一个无专利的压缩算法它可以实现无损数据压缩
=======
if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {
input = new GZIPInputStream(entity.getContent());
} else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
Inflater inflater = new Inflater(true);
input = new InflaterInputStream(entity.getContent(), inflater);
}
try {
InputStreamReader isr = new InputStreamReader(input);
<<<<<<< HEAD
BufferedReader br = new BufferedReader(isr); //是一个包装类,它可以包装字符流,将字符流放入缓存里,先把字符读到缓存里,到缓存满了时候,再读入内存,是为了提供读的效率而设计的
=======
BufferedReader br = new BufferedReader(isr);
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
StringBuilder sb = new StringBuilder();
while (true) {
@ -542,21 +348,15 @@ public class GTaskClient {
}
}
<<<<<<< HEAD
//通过JSON发送请求
//请求的具体内容在json的实例化对象js中然后传入
=======
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
private JSONObject postRequest(JSONObject js) throws NetworkFailureException {
if (!mLoggedin) {
Log.e(TAG, "please login first");
throw new ActionFailureException("not logged in");
}
<<<<<<< HEAD
//实例化一个httpPost的对象用来向服务器传输数据在这里就是发送请求而请求的内容在js里
=======
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
HttpPost httpPost = createHttpPost();
try {
LinkedList<BasicNameValuePair> list = new LinkedList<BasicNameValuePair>();
@ -565,10 +365,7 @@ public class GTaskClient {
httpPost.setEntity(entity);
// execute the post
<<<<<<< HEAD
//执行这个请求
=======
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
HttpResponse response = mHttpClient.execute(httpPost);
String jsString = getResponseContent(response.getEntity());
return new JSONObject(jsString);
@ -592,7 +389,6 @@ public class GTaskClient {
}
}
<<<<<<< HEAD
//创建单个任务
//传入参数是一个.gtask.data.Task包里Task类的对象
public void createTask(Task task) throws NetworkFailureException {
@ -600,12 +396,6 @@ public class GTaskClient {
try {
JSONObject jsPost = new JSONObject();//利用json获取Task里的内容,并且创建相应的jsPost
=======
public void createTask(Task task) throws NetworkFailureException {
commitUpdate();
try {
JSONObject jsPost = new JSONObject();
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
JSONArray actionList = new JSONArray();
// action_list
@ -619,11 +409,7 @@ public class GTaskClient {
JSONObject jsResponse = postRequest(jsPost);
JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
<<<<<<< HEAD
task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); //使用task.setGid设置task的new_ID
=======
task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
} catch (JSONException e) {
Log.e(TAG, e.toString());
@ -632,10 +418,7 @@ public class GTaskClient {
}
}
<<<<<<< HEAD
//创建一个任务列表
=======
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
public void createTaskList(TaskList tasklist) throws NetworkFailureException {
commitUpdate();
try {
@ -662,7 +445,6 @@ public class GTaskClient {
}
}
<<<<<<< HEAD
//同步更新操作
public void commitUpdate() throws NetworkFailureException {
if (mUpdateArray != null) {
@ -671,24 +453,11 @@ public class GTaskClient {
// action_list
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); //使用jsPost.putPut的信息包括UpdateArray和ClientVersion
=======
public void commitUpdate() throws NetworkFailureException {
if (mUpdateArray != null) {
try {
JSONObject jsPost = new JSONObject();
// action_list
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray);
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
<<<<<<< HEAD
postRequest(jsPost); //使用postRequest发送这个jspost,进行处理
=======
postRequest(jsPost);
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
mUpdateArray = null;
} catch (JSONException e) {
Log.e(TAG, e.toString());
@ -698,20 +467,13 @@ public class GTaskClient {
}
}
<<<<<<< HEAD
//添加更新的事项
=======
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
public void addUpdateNode(Node node) throws NetworkFailureException {
if (node != null) {
// too many update items may result in an error
// set max to 10 items
if (mUpdateArray != null && mUpdateArray.length() > 10) {
<<<<<<< HEAD
commitUpdate(); //调用commitUpdate()来提交更新
=======
commitUpdate();
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
}
if (mUpdateArray == null)
@ -720,10 +482,7 @@ public class GTaskClient {
}
}
<<<<<<< HEAD
//用来移动任务,它通过构建 JSON 对象和发送 POST 请求来实现任务的移动操作
=======
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
public void moveTask(Task task, TaskList preParent, TaskList curParent)
throws NetworkFailureException {
commitUpdate();
@ -733,11 +492,8 @@ public class GTaskClient {
JSONObject action = new JSONObject();
// action_list
<<<<<<< HEAD
//type——移动类型ID——操作的 IDGTASK_JSON_ID——要移动的任务的 ID
//SOURCE_LIST——要移动任务的原始父任务列表的 IDDEST_PARENT——要移动任务的新父任务列表的 ID
=======
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE);
action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());
@ -745,27 +501,17 @@ public class GTaskClient {
if (preParent == curParent && task.getPriorSibling() != null) {
// put prioring_sibing_id only if moving within the tasklist and
// it is not the first one
<<<<<<< HEAD
//设置优先级ID只有当移动是发生在文件中
action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling());
}
action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid());//设置移动前所属列表
action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid());//设置当前所属列表
=======
action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling());
}
action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid());
action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid());
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
if (preParent != curParent) {
// put the dest_list only if moving between tasklists
action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid());
}
actionList.put(action);
<<<<<<< HEAD
//最后将ACTION_LIST加入到jsPost中
=======
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client_version
@ -780,7 +526,6 @@ public class GTaskClient {
}
}
<<<<<<< HEAD
//用来删除节点,它通过构建 JSON 对象和发送 POST 请求来实现节点的删除操作
public void deleteNode(Node node) throws NetworkFailureException {
commitUpdate(); // 提交更新操作
@ -858,84 +603,11 @@ public class GTaskClient {
JSONObject jsPost = new JSONObject();//创建一个新的 JSONObject jsPost 用于存储 POST 请求的数据。
JSONArray actionList = new JSONArray();//创建一个新的 JSONArray actionList 用于存列表。
JSONObject action = new JSONObject();//创建一个新的 JSONObject action 用于表示单个操作。
=======
public void deleteNode(Node node) throws NetworkFailureException {
commitUpdate();
try {
JSONObject jsPost = new JSONObject();
JSONArray actionList = new JSONArray();
// action_list
node.setDeleted(true);
actionList.put(node.getUpdateAction(getActionId()));
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
postRequest(jsPost);
mUpdateArray = null;
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("delete node: handing jsonobject failed");
}
}
public JSONArray getTaskLists() throws NetworkFailureException {
if (!mLoggedin) {
Log.e(TAG, "please login first");
throw new ActionFailureException("not logged in");
}
try {
HttpGet httpGet = new HttpGet(mGetUrl);
HttpResponse response = null;
response = mHttpClient.execute(httpGet);
// get the task list
String resString = getResponseContent(response.getEntity());
String jsBegin = "_setup(";
String jsEnd = ")}</script>";
int begin = resString.indexOf(jsBegin);
int end = resString.lastIndexOf(jsEnd);
String jsString = null;
if (begin != -1 && end != -1 && begin < end) {
jsString = resString.substring(begin + jsBegin.length(), end);
}
JSONObject js = new JSONObject(jsString);
return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS);
} catch (ClientProtocolException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new NetworkFailureException("gettasklists: httpget failed");
} catch (IOException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new NetworkFailureException("gettasklists: httpget failed");
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("get task lists: handing jasonobject failed");
}
}
public JSONArray getTaskList(String listGid) throws NetworkFailureException {
commitUpdate();
try {
JSONObject jsPost = new JSONObject();
JSONArray actionList = new JSONArray();
JSONObject action = new JSONObject();
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
// action_list
action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL);
<<<<<<< HEAD
action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());//这里设置为传入的listGid
=======
action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid);
action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false);
actionList.put(action);
@ -953,18 +625,12 @@ public class GTaskClient {
}
}
<<<<<<< HEAD
//用于获取同步账户信息
=======
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
public Account getSyncAccount() {
return mAccount;
}
<<<<<<< HEAD
//重置更新内容
=======
>>>>>>> 3a7a23b9d2717a31b97b2a5c6deed09784b90564
public void resetUpdateArray() {
mUpdateArray = null;
}

@ -38,7 +38,7 @@ public class WorkingNote {
// Note Id
private long mNoteId;
// Note content
private String mContent;
public String mContent;
// Note mode
private int mMode;

@ -34,10 +34,10 @@ import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;
import java.util.ArrayList;
import java.util.HashSet;
//数据处理的函数
public class 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) {
Log.d(TAG, "the ids is null");
return true;
@ -72,7 +72,7 @@ public class DataUtils {
return false;
}
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {//将笔记移动到指定文件夹。给定笔记的ID、源文件夹ID和目标文件夹ID通过ContentValues设置新的父文件夹ID和原始父文件夹ID然后调用ContentResolver的update方法更新笔记
ContentValues values = new ContentValues();
values.put(NoteColumns.PARENT_ID, desFolderId);
values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId);
@ -80,7 +80,7 @@ public class DataUtils {
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null);
}
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,//批量移动笔记到指定文件夹
long folderId) {
if (ids == null) {
Log.d(TAG, "the ids is null");
@ -114,7 +114,7 @@ public class DataUtils {
/**
* Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}}
*/
public static int getUserFolderCount(ContentResolver resolver) {
public static int getUserFolderCount(ContentResolver resolver) {//获取用户文件夹的数量
Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI,
new String[] { "COUNT(*)" },
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?",
@ -135,7 +135,7 @@ public class DataUtils {
}
return count;
}
//检查笔记是否在数据库中可见
public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null,
@ -152,7 +152,7 @@ public class DataUtils {
}
return exist;
}
//检查笔记是否存在于数据库中
public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) {
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null, null, null, null);
@ -166,7 +166,7 @@ public class DataUtils {
}
return exist;
}
//作用同上
public static boolean existInDataDatabase(ContentResolver resolver, long dataId) {
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId),
null, null, null, null);
@ -180,7 +180,7 @@ public class DataUtils {
}
return exist;
}
//检查可见文件夹名称是否已存在
public static boolean checkVisibleFolderName(ContentResolver resolver, String name) {
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null,
NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER +
@ -223,7 +223,7 @@ public class DataUtils {
}
return set;
}
//根据笔记ID获取通话号码
public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) {
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.PHONE_NUMBER },
@ -242,7 +242,7 @@ public class DataUtils {
}
return "";
}
//根据电话号码和通话日期获取笔记ID
public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) {
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.NOTE_ID },
@ -263,7 +263,7 @@ public class DataUtils {
}
return 0;
}
//根据笔记ID获取摘要内容
public static String getSnippetById(ContentResolver resolver, long noteId) {
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,
new String [] { NoteColumns.SNIPPET },
@ -281,7 +281,7 @@ public class DataUtils {
}
throw new IllegalArgumentException("Note is not found with id: " + noteId);
}
//格式化摘要内容
public static String getFormattedSnippet(String snippet) {
if (snippet != null) {
snippet = snippet.trim();

@ -62,4 +62,13 @@ public class AlarmInitReceiver extends BroadcastReceiver {
c.close();
}
}
public static class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
intent.setClass(context, AlarmAlertActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
}

@ -1,30 +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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
intent.setClass(context, AlarmAlertActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}

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

@ -30,14 +30,18 @@ import net.micode.notes.R;
public class DropdownMenu {
private Button mButton;
private PopupMenu mPopupMenu;
//声明一个下拉菜单
private Menu mMenu;
public DropdownMenu(Context context, Button button, int menuId) {
mButton = button;
mButton.setBackgroundResource(R.drawable.dropdown_icon);
//设置这个view的背景
mPopupMenu = new PopupMenu(context, mButton);
mMenu = mPopupMenu.getMenu();
mPopupMenu.getMenuInflater().inflate(menuId, mMenu);
//MenuInflater是用来实例化Menu目录下的Menu布局文件
//根据ID来确认menu的内容选项
mButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mPopupMenu.show();
@ -48,14 +52,14 @@ public class DropdownMenu {
public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) {
if (mPopupMenu != null) {
mPopupMenu.setOnMenuItemClickListener(listener);
}
}//设置菜单的监听
}
public MenuItem findItem(int id) {
return mMenu.findItem(id);
}
}//对于菜单选项的初始化,根据索引搜索菜单需要的选项
public void setTitle(CharSequence title) {
mButton.setText(title);
}
}//布局文件,设置标题
}

@ -30,10 +30,14 @@ import net.micode.notes.data.Notes.NoteColumns;
public class FoldersListAdapter extends CursorAdapter {
//CursorAdapter是Cursor和ListView的接口
//FoldersListAdapter继承了CursorAdapter的类
//主要作用是便签数据库和用户的交互
//这里就是用folder文件夹的形式展现给用户
public static final String [] PROJECTION = {
NoteColumns.ID,
NoteColumns.SNIPPET
};
};//调用数据库中便签的ID和片段
public static final int ID_COLUMN = 0;
public static final int NAME_COLUMN = 1;
@ -41,12 +45,13 @@ public class FoldersListAdapter extends CursorAdapter {
public FoldersListAdapter(Context context, Cursor c) {
super(context, c);
// TODO Auto-generated constructor stub
}
}//数据库操作
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
//ViewGroup是容器
return new FolderListItem(context);
}
}//创建一个文件夹,对于各文件夹中子标签的初始化
@Override
public void bindView(View view, Context context, Cursor cursor) {
@ -55,20 +60,22 @@ public class FoldersListAdapter extends CursorAdapter {
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
((FolderListItem) view).bind(folderName);
}
}
}//将各个布局文件绑定起来
public String getFolderName(Context context, int position) {
Cursor cursor = (Cursor) getItem(position);
return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
}
}//根据数据库中标签的ID得到标签的各项内容
private class FolderListItem extends LinearLayout {
private TextView mName;
public FolderListItem(Context context) {
super(context);
//操作数据库
inflate(context, R.layout.folder_list_item, this);
//根据布局文件的名字等信息将其找出来
mName = (TextView) findViewById(R.id.tv_folder_name);
}

@ -22,19 +22,32 @@ import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.SearchManager;
import android.appwidget.AppWidgetManager;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.format.DateUtils;
import android.text.style.BackgroundColorSpan;
import android.text.style.ImageSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@ -47,11 +60,14 @@ import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.graphics.Typeface;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.TextNote;
@ -65,6 +81,7 @@ import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener;
import net.micode.notes.widget.NoteWidgetProvider_2x;
import net.micode.notes.widget.NoteWidgetProvider_4x;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@ -149,6 +166,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private String mUserQuery;
private Pattern mPattern;
private final int PHOTO_REQUEST = 1;//请求码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -158,13 +177,32 @@ public class NoteEditActivity extends Activity implements OnClickListener,
finish();
return;
}
initResources();
//根据id获取添加图片按钮
final ImageButton add_img_btn = (ImageButton) findViewById(R.id.add_img_btn);
//为点击图片按钮设置监听器
add_img_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d(TAG, "onClick: click add image button");
//ACTION_GET_CONTENT: 允许用户选择特殊种类的数据,并返回(特殊种类的数据:照一张相片或录一段音)
Intent loadImage = new Intent(Intent.ACTION_GET_CONTENT);
//Category属性用于指定当前动作Action被执行的环境.
//CATEGORY_OPENABLE; 用来指示一个ACTION_GET_CONTENT的intent
loadImage.addCategory(Intent.CATEGORY_OPENABLE);
loadImage.setType("image/*");
startActivityForResult(loadImage, PHOTO_REQUEST);
}
});
count();
}
/**
* Current activity may be killed when the memory is low. Once it is killed, for another time
* user load this activity, we should restore the former state
*/
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
@ -263,14 +301,13 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
@Override
protected void onResume() {
protected void onResume() {//能获得用户焦点:可以操作
super.onResume();
initNoteScreen();
initNoteScreen();//初始化便签屏幕
}
private void initNoteScreen() {
mNoteEditor.setTextAppearance(this, TextAppearanceResources
.getTexAppearanceResource(mFontSizeId));
mNoteEditor.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId));
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {
switchToListMode(mWorkingNote.getContent());
} else {
@ -288,11 +325,9 @@ public class NoteEditActivity extends Activity implements OnClickListener,
| DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_TIME
| DateUtils.FORMAT_SHOW_YEAR));
/**
* TODO: Add the menu for setting alert. Currently disable it because the DateTimePicker
* is not ready
*/
showAlertHeader();
//将有图片路径的位置转换为图片
convertToImage();
}
private void showAlertHeader() {
@ -312,6 +347,47 @@ public class NoteEditActivity extends Activity implements OnClickListener,
};
}
//路径字符串格式 转换为 图片image格式
private void convertToImage() {
NoteEditText noteEditText = (NoteEditText) findViewById(R.id.note_edit_view); //获取当前的edit
Editable editable = noteEditText.getText();//1.获取text
String noteText = editable.toString(); //2.将note内容转换为字符串
int length = editable.length(); //内容的长度
//3.截取img片段 [local]+uri+[local]提取uri
for(int i = 0; i < length; i++) {
for(int j = i; j < length; j++) {
String img_fragment = noteText.substring(i, j+1); //img_fragment关于图片路径的片段
if(img_fragment.length() > 15 && img_fragment.endsWith("[/local]") && img_fragment.startsWith("[local]")){
int limit = 7; //[local]为7个字符
//[local][/local]共15个字符剩下的为真正的path长度
int len = img_fragment.length()-15;
//从[local]之后的len个字符就是path
String path = img_fragment.substring(limit,limit+len);//获取到了图片路径
Bitmap bitmap = null;
Log.d(TAG, "图片的路径是:"+path);
try {
bitmap = BitmapFactory.decodeFile(path);//将图片路径解码为图片格式
} catch (Exception e) {
e.printStackTrace();
}
if(bitmap!=null){ //若图片存在
Log.d(TAG, "图片不为null");
ImageSpan imageSpan = new ImageSpan(NoteEditActivity.this, bitmap);
//4.创建一个SpannableString对象以便插入用ImageSpan对象封装的图像
String ss = "[local]" + path + "[/local]";
SpannableString spannableString = new SpannableString(ss);
//5.将指定的标记对象附加到文本的开始...结束范围
spannableString.setSpan(imageSpan, 0, ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Log.d(TAG, "Create spannable string success!");
Editable edit_text = noteEditText.getEditableText();
edit_text.delete(i,i+len+15); //6.删掉图片路径的文字
edit_text.insert(i, spannableString); //7.在路径的起始位置插入图片
}
}
}
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
@ -364,6 +440,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
private void initResources() {
editText = (EditText) findViewById(R.id.note_edit_view);
textView = (TextView) findViewById(R.id.text_num);
mHeadViewPanel = findViewById(R.id.note_title);
mNoteHeaderHolder = new HeadViewHolder();
mNoteHeaderHolder.tvModified = (TextView) findViewById(R.id.tv_modified_date);
@ -430,7 +508,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
if (id == R.id.btn_set_bg_color) {
mNoteBgColorSelector.setVisibility(View.VISIBLE);
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
- View.VISIBLE);
View.VISIBLE);
} else if (sBgSelectorBtnsMap.containsKey(id)) {
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
View.GONE);
@ -563,10 +641,6 @@ public class NoteEditActivity extends Activity implements OnClickListener,
d.show();
}
/**
* Share note to apps that support {@link Intent#ACTION_SEND} action
* and {@text/plain} type
*/
private void sendTo(Context context, String info) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, info);
@ -621,7 +695,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
saveNote();
}
if (mWorkingNote.getNoteId() > 0) {
Intent intent = new Intent(this, AlarmReceiver.class);
Intent intent = new Intent(this, AlarmInitReceiver.AlarmReceiver.class);
intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mWorkingNote.getNoteId()));
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE));
@ -773,12 +847,12 @@ public class NoteEditActivity extends Activity implements OnClickListener,
switchToListMode(mNoteEditor.getText().toString());
} else {
if (!getWorkingText()) {
mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ",
""));
mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ", ""));
}
mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery));
mEditTextList.setVisibility(View.GONE);
mNoteEditor.setVisibility(View.VISIBLE);
convertToImage(); //退出清单模式,应该将有图片的地方显示出来
}
}
@ -870,4 +944,201 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private void showToast(int resId, int duration) {
Toast.makeText(this, resId, duration).show();
}
@Override
//重写onActivityResult()来处理返回的数据
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
ContentResolver resolver = getContentResolver();
switch (requestCode) {
case PHOTO_REQUEST:
Uri originalUri = intent.getData(); //1.获得图片的真实路径
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(resolver.openInputStream(originalUri));//2.解码图片
} catch (FileNotFoundException e) {
Log.d(TAG, "onActivityResult: get file_exception");
e.printStackTrace();
}
if(bitmap != null){
//3.根据Bitmap对象创建ImageSpan对象
Log.d(TAG, "onActivityResult: bitmap is not null");
ImageSpan imageSpan = new ImageSpan(NoteEditActivity.this, bitmap);
String path = getPath(this,originalUri);
//4.使用[local][/local]将path括起来用于之后方便识别图片路径在note中的位置
String img_fragment= "[local]" + path + "[/local]";
//创建一个SpannableString对象以便插入用ImageSpan对象封装的图像
SpannableString spannableString = new SpannableString(img_fragment);
spannableString.setSpan(imageSpan, 0, img_fragment.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
//5.将选择的图片追加到EditText中光标所在位置
NoteEditText e = (NoteEditText) findViewById(R.id.note_edit_view);
int index = e.getSelectionStart(); //获取光标所在位置
Log.d(TAG, "Index是: " + index);
Editable edit_text = e.getEditableText();
edit_text.insert(index, spannableString); //将图片插入到光标所在位置
mWorkingNote.mContent = e.getText().toString();
//6.把改动提交到数据库中,两个数据库表都要改的
ContentResolver contentResolver = getContentResolver();
ContentValues contentValues = new ContentValues();
final long id = mWorkingNote.getNoteId();
contentValues.put("snippet",mWorkingNote.mContent);
contentResolver.update(Uri.parse("content://micode_notes/note"), contentValues,"_id=?",new String[]{""+id});
ContentValues contentValues1 = new ContentValues();
contentValues1.put("content",mWorkingNote.mContent);
contentResolver.update(Uri.parse("content://micode_notes/data"), contentValues1,"mime_type=? and note_id=?", new String[]{"vnd.android.cursor.item/text_note",""+id});
}else{
Toast.makeText(NoteEditActivity.this, "获取图片失败", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
//获取文件的real path
public String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
//ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
//MediaProvider
if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// Media
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
//获取数据列_获取此 Uri 的数据列的值。这对MediaStore Uris 和其他基于文件的 ContentProvider。
public String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
public boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
//是否为下载文件
public boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
//是否为媒体文件
public boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
private EditText editText;
private TextView textView;
private String Textchange(String oriText){
StringBuffer stringBuffer = new StringBuffer(oriText);
int Flag1 = -1;
int Flag2 = -1;
do {//不计入表示图片的字符
Flag1 = stringBuffer.indexOf("<img");
Flag2 = stringBuffer.indexOf(">");
if (Flag1 != -1 && Flag2 != -1) {
stringBuffer = stringBuffer.replace(Flag1, Flag2+1, "");
}
} while (Flag1 != -1 && Flag2 != -1);
do {//不计入换行字符
Flag1 = stringBuffer.indexOf("\n");
if (Flag1 != -1){
stringBuffer = stringBuffer.replace(Flag1, Flag1+1, "");
}
} while (Flag1 != -1);
do {//不计入空格字符
Flag1 = stringBuffer.indexOf(" ");
if (Flag1 != -1) {
stringBuffer = stringBuffer.replace(Flag1, Flag1+1, "");
}
} while (Flag1 != -1);
return stringBuffer.toString();
}
private void count() {
mNoteEditor.addTextChangedListener(new TextWatcher() {
int currentLength = 0;
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
textView.setText("字符数:" + currentLength);
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
currentLength = Textchange(mNoteEditor.getText().toString()).length();
}
@Override
public void afterTextChanged(Editable s) {
textView.setText("字符数:" + currentLength);
}
});
}
}

@ -14,150 +14,116 @@
* limitations under the License.
*/
/**
* UI
*/
package net.micode.notes.ui;
/**
* Android
* UI
*/
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.appwidget.AppWidgetManager;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.ActionMode;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Display;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnCreateContextMenuListener;
import android.view.View.OnTouchListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.TextView;
import android.widget.Toast;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.remote.GTaskSyncService;
import net.micode.notes.model.WorkingNote;
import net.micode.notes.tool.BackupUtils;
import net.micode.notes.tool.DataUtils;
import net.micode.notes.tool.ResourceParser;
import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;
import net.micode.notes.widget.NoteWidgetProvider_2x;
import net.micode.notes.widget.NoteWidgetProvider_4x;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import android.app.Activity; //表示应用程序中的一个活动,例如界面展示等
import android.app.AlertDialog; //用于显示对话框的类
import android.app.Dialog; //用于创建对话框的类
import android.appwidget.AppWidgetManager; //用于管理桌面小组件的类
import android.content.AsyncQueryHandler; //用于在后台执行异步数据库查询的处理器。
import android.content.ContentResolver; //用于访问应用程序的内容提供者,进行数据的增删改查。
import android.content.ContentValues; //用于存储键值对,用于对数据库进行操作。
import android.content.Context; //表示 Android 应用程序的当前状态,提供访问应用程序的资源和类的接口。
import android.content.DialogInterface; //用于创建对话框与用户进行交互。
import android.content.Intent; //用于在应用程序内部或者不同应用程序之间进行交互或传递信息。
import android.content.SharedPreferences; //用于存储应用程序的轻量级 key-value 数据。
import android.database.Cursor; //用于在数据集中进行移动并访问查询结果。
import android.os.AsyncTask; //用于在后台执行长时间运行的操作,并在主线程更新用户界面。
import android.os.Bundle; //用于传递数据。
import android.preference.PreferenceManager; //用于访问应用程序的默认共享偏好设置。
import android.text.Editable; //表示文本框中的可编辑文本。
import android.text.TextUtils; //用于处理和操作文本数据。
import android.text.TextWatcher; //用于监听文本变化的接口。
import android.util.Log; //用于在调试时记录日志。
import android.view.ActionMode; //用于在用户界面上执行上下文操作的模式。
import android.view.ContextMenu; //用于在视图组件上下文菜单的呈现。
import android.view.ContextMenu.ContextMenuInfo; //提供有关创建上下文菜单的视图组件的额外信息。
import android.view.Display; //表示屏幕上的显示内容。
import android.view.HapticFeedbackConstants; //用于触觉反馈的常量值。
import android.view.LayoutInflater; //用于动态加载 XML 布局文件。
import android.view.Menu; //表示应用程序的菜单。
import android.view.MenuItem; //用于表示菜单项。
import android.view.MenuItem.OnMenuItemClickListener; //用于监听菜单项点击事件的接口。
import android.view.MotionEvent; //用于表示单个事件的运动事件。
import android.view.View; //用户界面上的可视元素。
import android.view.View.OnClickListener; //用于监听视图点击事件的接口。
import android.view.View.OnCreateContextMenuListener; //用于监听创建上下文菜单的接口。
import android.view.View.OnTouchListener; //用于监听视图触摸事件的接口。
import android.view.inputmethod.InputMethodManager; //用于管理输入法框架的接口。
import android.widget.AdapterView; //用于在视图组件中表示数据项的子集合。
import android.widget.AdapterView.OnItemClickListener; //用于监听列表项点击事件的接口。
import android.widget.AdapterView.OnItemLongClickListener; //用于监听列表项长按事件的接口。
import android.widget.Button; //用于在用户界面中表示按钮。
import android.widget.EditText; //用于在用户界面中表示可编辑的文本视图。
import android.widget.ListView; //用于在用户界面中表示列表视图。
import android.widget.PopupMenu; //用于显示弹出菜单的类。
import android.widget.TextView; //用于在用户界面中表示文本视图。
import android.widget.Toast; //用于显示简短消息的类。
import net.micode.notes.R; //引用应用程序的资源。
import net.micode.notes.data.Notes; //包含与笔记相关的数据的类。
import net.micode.notes.data.Notes.NoteColumns; //包含笔记数据列的类。
import net.micode.notes.gtask.remote.GTaskSyncService; //用于与 Google 任务同步服务进行交互的类
import net.micode.notes.model.WorkingNote; //与正在编辑的笔记相关联的类。
import net.micode.notes.tool.BackupUtils; //用于处理备份的工具类
import net.micode.notes.tool.DataUtils; //包含处理数据的实用方法的类。
import net.micode.notes.tool.ResourceParser; //用于解析资源的类。
import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute; //用于在笔记列表适配器中表示应用程序小部件属性的类。
import net.micode.notes.widget.NoteWidgetProvider_2x; //用于创建 2x 大小笔记应用程序小部件的类。
import net.micode.notes.widget.NoteWidgetProvider_4x; //用于创建 4x 大小笔记应用程序小部件的类。用于创建 4x 大小笔记应用程序小部件的类。
import java.io.BufferedReader; //用于从字符输入流中读取文本的类。
import java.io.IOException; //用于处理输入输出异常的类。
import java.io.InputStream; //用于表示输入字节流的类。
import java.io.InputStreamReader; //用于从字节流到字符流的桥梁。
import java.util.HashSet; //用于表示一组不重复的元素的类。
/**
* Activity
*
*/
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;
private static final int MENU_FOLDER_DELETE = 0; //标识用户是否选择了删除选项
private static final int MENU_FOLDER_DELETE = 0;
private static final int MENU_FOLDER_VIEW = 1; //标识用户选择的外观
private static final int MENU_FOLDER_VIEW = 1;
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";
//定义一个字符串指向应用介绍
/**
*
*
*
* NOTE_LIST便SUB_FOLDER
* CALL_RECORD_FOLDER
*/
private enum ListEditState {
NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER
};
private ListEditState mState; //定义了一个标识列表编辑状态的变量
private ListEditState mState;
private BackgroundQueryHandler mBackgroundQueryHandler; //用于在后台执行数据库查询等操作以避免阻塞UI线程
private BackgroundQueryHandler mBackgroundQueryHandler;
private NotesListAdapter mNotesListAdapter; //用于管理便签列表中数据项的适配器,通常与 ListView 一起使用
private NotesListAdapter mNotesListAdapter;
private ListView mNotesListView; //它表示便签列表的视图,用于显示便签列表中的数据项,
// 并与适配器NotesListAdapter一起工作以展示数据。
private ListView mNotesListView;
/**
*
*/
private Button mAddNewNote; //声明了一个私有成员变量 mAddNewNote类型为 Button
// 用来表示一个按钮控件,通常用于用户点击以添加新的便签。
private Button mAddNewNote;
private boolean mDispatch;
private boolean mDispatch; //声明了一个私有成员变量 mDispatch类型为 boolean
// 用来表示一个标志位,可能用于控制某些事件的分发。
private int mOriginY;
private int mOriginY; //声明了两个私有成员变量 mOriginY 和 mDispatchY类型为 int
private int mDispatchY; // 可能用于记录某些位置坐标的信息。
private int mDispatchY;
private TextView mTitleBar; //声明了一个私有成员变量 mTitleBar类型为 TextView
// 用来表示一个文本视图,通常用于显示标题栏的文本信息。
private TextView mTitleBar;
private long mCurrentFolderId; //用来表示当前文件夹的ID。
private long mCurrentFolderId;
private ContentResolver mContentResolver; //用来获取应用的内容提供者,用于访问应用的数据
private ContentResolver mContentResolver;
private ModeCallback mModeCallBack; //用于处理列表的编辑模式
private ModeCallback mModeCallBack;
private static final String TAG = "NotesListActivity"; //通常用于在日志或调试信息中标识类名
private static final String TAG = "NotesListActivity";
public static final int NOTES_LISTVIEW_SCROLL_RATE = 30; //表示便签列表视图的滚动速率
public static final int NOTES_LISTVIEW_SCROLL_RATE = 30;
private NoteItemData mFocusNoteDataItem; //用于表示当前焦点的便签数据项
private NoteItemData mFocusNoteDataItem;
private static final String NORMAL_SELECTION = NoteColumns.PARENT_ID + "=?";
@ -165,10 +131,9 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
+ Notes.TYPE_SYSTEM + " AND " + NoteColumns.PARENT_ID + "=?)" + " OR ("
+ NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND "
+ NoteColumns.NOTES_COUNT + ">0)";
//分别表示正常的选择条件和根文件夹的选择条件,
//通常用于数据库查询的条件语句
private final static int REQUEST_CODE_OPEN_NODE = 102;
private final static int REQUEST_CODE_NEW_NODE = 103; //分别表示启动Activity时用到的请求码用于区分不同的启动请求
private final static int REQUEST_CODE_NEW_NODE = 103;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -182,17 +147,6 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
setAppInfoFromRawRes();
}
/**
*
* Activity
* startActivityForResultActivity
* requestCode
* resultCode
* dataIntent
* @param requestCode
* @param resultCode
* @param data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK
@ -203,12 +157,6 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
}
/**
* SharedPreferences
* SharedPreferences
* rawWorkingNote
* SharedPreferences
*/
private void setAppInfoFromRawRes() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) {
@ -255,22 +203,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
}
/**
* ActivityActivity
* onStartstartAsyncNotesListQuery
*/
@Override
protected void onStart() {
super.onStart();
startAsyncNotesListQuery();
}
/**
*
* ID便
* Activity
* 便
*/
private void initResources() {
mContentResolver = this.getContentResolver();
mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver());
@ -291,25 +229,16 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mTitleBar = (TextView) findViewById(R.id.tv_title_bar);
mState = ListEditState.NOTE_LIST;
mModeCallBack = new ModeCallback();
editText = (EditText) findViewById(R.id.note_edit_view);
textView = (TextView) findViewById(R.id.text_num);
}
/**
* ModeCallback
* ListView.MultiChoiceModeListener
* OnMenuItemClickListener
*
*/
private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener {
private DropdownMenu mDropDownMenu;
private ActionMode mActionMode;
private MenuItem mMoveMenu;
/**
*
* @param mode
* @param menu
* @return
*/
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
getMenuInflater().inflate(R.menu.note_list_options, menu);
menu.findItem(R.id.delete).setOnMenuItemClickListener(this);
@ -343,9 +272,6 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
return true;
}
/**
*
*/
private void updateMenu() {
int selectedCount = mNotesListAdapter.getSelectedCount();
// Update dropdown menu
@ -363,23 +289,11 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
}
/**
*
* @param mode
* @param menu
* @return
*/
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// TODO Auto-generated method stub
return false;
}
/**
*
* @param mode
* @param item
* @return
*/
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
// TODO Auto-generated method stub
return false;
@ -408,8 +322,8 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
return true;
}
int itemId = item.getItemId();
if (itemId == R.id.delete) {
switch (item.getItemId()) {
case R.id.delete:
AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
builder.setTitle(getString(R.string.alert_title_delete));
builder.setIcon(android.R.drawable.ic_dialog_alert);
@ -424,9 +338,11 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
});
builder.setNegativeButton(android.R.string.cancel, null);
builder.show();
} else if (itemId == R.id.move) {
break;
case R.id.move:
startQueryDestinationFolders();
} else {
break;
default:
return false;
}
return true;
@ -645,8 +561,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
public void onClick(View v) {
if (v.getId() == R.id.btn_new_note) {
switch (v.getId()) {
case R.id.btn_new_note:
createNewNote();
break;
default:
break;
}
}
@ -662,7 +582,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
private void showCreateOrModifyFolderDialog(final boolean create) {
private void showCreateOrModifyFolderDialog(final boolean create) { //新建文件夹
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
View view = LayoutInflater.from(this).inflate(R.layout.dialog_edit_text, null);
final EditText etName = (EditText) view.findViewById(R.id.et_foler_name);
@ -863,12 +783,16 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.menu_new_folder) {
switch (item.getItemId()) {
case R.id.menu_new_folder: {
showCreateOrModifyFolderDialog(true);
} else if (itemId == R.id.menu_export_text) {
break;
}
case R.id.menu_export_text: {
exportNoteToText();
} else if (itemId == R.id.menu_sync) {
break;
}
case R.id.menu_sync: {
if (isSyncMode()) {
if (TextUtils.equals(item.getTitle(), getString(R.string.menu_sync))) {
GTaskSyncService.startSync(this);
@ -878,12 +802,26 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
} else {
startPreferenceActivity();
}
} else if (itemId == R.id.menu_setting) {
break;
}
case R.id.menu_setting: {
startPreferenceActivity();
} else if (itemId == R.id.menu_new_note) {
break;
}
case R.id.menu_new_note: {
createNewNote();
} else if (itemId == R.id.menu_search) {
break;
}
case R.id.menu_search:
onSearchRequested();
break;
case R.id.menu_countallNotes:
showNumberofNotes();
break;
default:
break;
}
return true;
}
@ -1021,4 +959,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
return false;
}
private void showNumberofNotes() {
AlertDialog.Builder btr =new AlertDialog.Builder(this);
btr.setTitle("目前便签数");
btr.setMessage("目前有 "+Integer.toString(mNotesListAdapter.retCount())+"个便签");
btr.show();
}
private EditText editText;
private TextView textView;
}

@ -181,4 +181,22 @@ public class NotesListAdapter extends CursorAdapter {
}
}
}
public int retCount(){
int NotesCount=mNotesCount;
int ItemCount=getCount();
for (int i = 0; i < ItemCount; i++) {
Cursor c = (Cursor) getItem(i);
if (c != null) {
if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) {
NoteItemData NoteItem=new NoteItemData(mContext,c);
NotesCount+=NoteItem.getNotesCount();
}
} else {
Log.e(TAG, "Invalid cursor");
return -1;
}
}
return NotesCount;
}
}

@ -0,0 +1,32 @@
package net.micode.notes.ui;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowInsets;
import net.micode.notes.R;
public class SplashActivity extends AppCompatActivity {
Handler mHandler=new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); //加载启动界面
setContentView(R.layout.activity_splash); //加载启动图片
// 当计时结束时跳转至NotesListActivity
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
Intent intent=new Intent();
intent.setClass(SplashActivity.this, NotesListActivity.class);
startActivity(intent);
finish(); //销毁欢迎页面
}
}, 2000); // 2 秒后跳转
}
}
Loading…
Cancel
Save