张钊注释工作 #1

Open
pauq2fcwv wants to merge 0 commits from zz into develop

1
.gitignore vendored

@ -7,3 +7,4 @@ project.properties
.settings/
.classpath
.project
/.idea/

@ -1,21 +1,43 @@
/*
* 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;
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;//输出日志,比如说出错、警告等
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;
public class Note {
// private ContentValues mNoteDiffValues;
ContentValues mNoteDiffValues;//
private ContentValues mNoteDiffValues;
private NoteData mNoteData;
private static final String TAG = "Note";
/**
* Create a new note id for adding a new note to databases
*/
@ -27,67 +49,66 @@ public class Note {
values.put(NoteColumns.MODIFIED_DATE, createdTime);
values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
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);
//ContentResolver()主要是实现外部应用对ContentProvider中的数据
//进行添加、删除、修改和查询操作
long noteId = 0;
try {
noteId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
noteId = 0;
}//try-catch异常处理
}
if (noteId == -1) {
throw new IllegalStateException("Wrong note id:" + noteId);
}
return noteId;
}
public Note() {
mNoteDiffValues = new ContentValues();
mNoteData = new NoteData();
}//定义两个变量用来存储便签的数据,一个是存储便签属性、一个是存储便签内容
}
public void setNoteValue(String key, String value) {
mNoteDiffValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}//设置数据库表格的标签属性数据
}
public void setTextData(String key, String value) {
mNoteData.setTextData(key, value);
}//设置数据库表格的标签文本内容的数据
}
public void setTextDataId(long id) {
mNoteData.setTextDataId(id);
}//设置文本数据的ID
}
public long getTextDataId() {
return mNoteData.mTextDataId;
}//得到文本数据的ID
}
public void setCallDataId(long id) {
mNoteData.setCallDataId(id);
}//设置电话号码数据的ID
}
public void setCallData(String key, String value) {
mNoteData.setCallData(key, value);
}//得到电话号码数据的ID
}
public boolean isLocalModified() {
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
}//判断是否是本地修改
}
public boolean syncNote(Context context, long noteId) {
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
if (!isLocalModified()) {
return true;
}
/**
* In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and
* {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the
@ -100,74 +121,74 @@ public class Note {
// Do not return, fall through
}
mNoteDiffValues.clear();
if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
return false;
}
return true;
}//判断数据是否同步
private class NoteData {//定义一个基本的便签内容的数据类,主要包含文本数据和电话号码数据
}
private class NoteData {
private long mTextDataId;
private ContentValues mTextDataValues;//文本数据
private ContentValues mTextDataValues;
private long mCallDataId;
private ContentValues mCallDataValues;//电话号码数据
private ContentValues mCallDataValues;
private static final String TAG = "NoteData";
public NoteData() {
mTextDataValues = new ContentValues();
mCallDataValues = new ContentValues();
mTextDataId = 0;
mCallDataId = 0;
}
//下面是上述几个函数的具体实现
boolean isLocalModified() {
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
}
void setTextDataId(long id) {
if(id <= 0) {
throw new IllegalArgumentException("Text data id should larger than 0");
}
mTextDataId = id;
}
void setCallDataId(long id) {
if (id <= 0) {
throw new IllegalArgumentException("Call data id should larger than 0");
}
mCallDataId = id;
}
void setCallData(String key, String value) {
mCallDataValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
void setTextData(String key, String value) {
mTextDataValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
//下面函数的作用是将新的数据通过Uri的操作存储到数据库
Uri pushIntoContentResolver(Context context, long noteId) {
/**
* Check for safety
*/
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
}//判断数据是否合法
}
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
ContentProviderOperation.Builder builder = null;//数据库的操作列表
ContentProviderOperation.Builder builder = null;
if(mTextDataValues.size() > 0) {
mTextDataValues.put(DataColumns.NOTE_ID, noteId);
if (mTextDataId == 0) {
@ -188,8 +209,8 @@ public class Note {
operationList.add(builder.build());
}
mTextDataValues.clear();
}//把文本数据存入DataColumns
}
if(mCallDataValues.size() > 0) {
mCallDataValues.put(DataColumns.NOTE_ID, noteId);
if (mCallDataId == 0) {
@ -210,8 +231,8 @@ public class Note {
operationList.add(builder.build());
}
mCallDataValues.clear();
}//把电话号码数据存入DataColumns
}
if (operationList.size() > 0) {
try {
ContentProviderResult[] results = context.getContentResolver().applyBatch(
@ -225,8 +246,8 @@ public class Note {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
return null;
}
}//存储过程中的异常处理
}
return null;
}
}
}
}

@ -1,5 +1,37 @@
/*
* 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;
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 {
// Note for the working note
private Note mNote;
@ -9,22 +41,27 @@ public class WorkingNote {
private String mContent;
// Note mode
private int mMode;
private long mAlertDate;
private long mModifiedDate;
private int mBgColorId;
private int mWidgetId;
private int mWidgetType;
private long mFolderId;
private Context mContext;
private static final String TAG = "WorkingNote";
private boolean mIsDeleted;
private NoteSettingChangedListener mNoteSettingStatusListener;
// 声明 DATA_PROJECTION字符串数组
public static final String[] DATA_PROJECTION = new String[] {
DataColumns.ID,
DataColumns.CONTENT,
@ -34,8 +71,7 @@ public class WorkingNote {
DataColumns.DATA3,
DataColumns.DATA4,
};
// 声明 NOTE_PROJECTION字符串数组
public static final String[] NOTE_PROJECTION = new String[] {
NoteColumns.PARENT_ID,
NoteColumns.ALERTED_DATE,
@ -44,20 +80,29 @@ public class WorkingNote {
NoteColumns.WIDGET_TYPE,
NoteColumns.MODIFIED_DATE
};
private static final int DATA_ID_COLUMN = 0;
private static final int DATA_CONTENT_COLUMN = 1;
private static final int DATA_MIME_TYPE_COLUMN = 2;
private static final int DATA_MODE_COLUMN = 3;
private static final int NOTE_PARENT_ID_COLUMN = 0;
private static final int NOTE_ALERTED_DATE_COLUMN = 1;
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_TYPE_COLUMN = 4;
private static final int NOTE_MODIFIED_DATE_COLUMN = 5;
// New note construct
public WorkingNote(Context context, long folderId) {
private WorkingNote(Context context, long folderId) {
mContext = context;
mAlertDate = 0;
mModifiedDate = System.currentTimeMillis();
@ -68,8 +113,7 @@ public class WorkingNote {
mMode = 0;
mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
}
// WorkingNote的构造函数
// Existing note construct
private WorkingNote(Context context, long noteId, long folderId) {
mContext = context;
@ -79,15 +123,12 @@ public class WorkingNote {
mNote = new Note();
loadNote();
}
// 加载Note
// 通过数据库调用query函数找到第一个条目
private void loadNote() {
Cursor cursor = mContext.getContentResolver().query(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null,
null, null);
// 若存在,储存相应信息
if (cursor != null) {
if (cursor.moveToFirst()) {
mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN);
@ -98,24 +139,21 @@ public class WorkingNote {
mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN);
}
cursor.close();
// 若不存在,报错
} else {
Log.e(TAG, "No note with id:" + mNoteId);
throw new IllegalArgumentException("Unable to find note with id " + mNoteId);
}
loadNoteData();
}
// 加载NoteData
private void loadNoteData() {
Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION,
DataColumns.NOTE_ID + "=?", new String[] {
String.valueOf(mNoteId)
}, null);
if (cursor != null) {
// 查到信息不为空
if (cursor.moveToFirst()) { // 查看第一项是否存在
if (cursor.moveToFirst()) {
do {
String type = cursor.getString(DATA_MIME_TYPE_COLUMN);
if (DataConstants.NOTE.equals(type)) {
@ -127,7 +165,7 @@ public class WorkingNote {
} else {
Log.d(TAG, "Wrong note type with type:" + type);
}
} while (cursor.moveToNext());//查阅所有项,直到为空
} while (cursor.moveToNext());
}
cursor.close();
} else {
@ -135,35 +173,31 @@ public class WorkingNote {
throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId);
}
}
// 创建空的Note
// 传参context文件夹idwidget背景颜色
public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId,
int widgetType, int defaultBgColorId) {
WorkingNote note = new WorkingNote(context, folderId);
// 设定相关属性
note.setBgColorId(defaultBgColorId);
note.setWidgetId(widgetId);
note.setWidgetType(widgetType);
return note;
}
public static WorkingNote load(Context context, long id) {
return new WorkingNote(context, id, 0);
}
// 保存Note
public synchronized boolean saveNote() {
if (isWorthSaving()) { //是否值得保存
if (!existInDatabase()) { // 是否存在数据库中
if (isWorthSaving()) {
if (!existInDatabase()) {
if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) {
Log.e(TAG, "Create new note fail with id:" + mNoteId);
return false;
}
}
mNote.syncNote(mContext, mNoteId);
/**
* Update widget content if there exist any widget of this note
*/
@ -177,15 +211,12 @@ public class WorkingNote {
return false;
}
}
// 是否在数据库中存在
public boolean existInDatabase() {
return mNoteId > 0;
}
// 是否值得保存
private boolean isWorthSaving() {
// 被删除,或(不在数据库中 内容为空),或 本地已保存过
if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent))
|| (existInDatabase() && !mNote.isLocalModified())) {
return false;
@ -193,15 +224,11 @@ public class WorkingNote {
return true;
}
}
// 设置mNoteSettingStatusListener
public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) {
mNoteSettingStatusListener = l;
}
// 设置AlertDate
// 若 mAlertDate与data不同则更改mAlertDate并设定NoteValue
public void setAlertDate(long date, boolean set) {
if (date != mAlertDate) {
mAlertDate = date;
@ -211,21 +238,17 @@ public class WorkingNote {
mNoteSettingStatusListener.onClockAlertChanged(date, set);
}
}
// 设定删除标记
public void markDeleted(boolean mark) {
// 设定标记
mIsDeleted = mark;
if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onWidgetChanged();
// 调用mNoteSettingStatusListener的 onWidgetChanged方法
}
}
// 设定背景颜色
public void setBgColorId(int id) {
if (id != mBgColorId) { //设定条件 id != mBgColorId
if (id != mBgColorId) {
mBgColorId = id;
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onBackgroundColorChanged();
@ -233,11 +256,9 @@ public class WorkingNote {
mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id));
}
}
// 设定检查列表模式
// 参数mode
public void setCheckListMode(int mode) {
if (mMode != mode) { //设定条件 mMode != mode
if (mMode != mode) {
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode);
}
@ -245,125 +266,98 @@ public class WorkingNote {
mNote.setTextData(TextNote.MODE, String.valueOf(mMode));
}
}
// 设定WidgetType
// 参数type
public void setWidgetType(int type) {
if (type != mWidgetType) {//设定条件 type != mWidgetType
if (type != mWidgetType) {
mWidgetType = type;
mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType));
// 调用Note的setNoteValue方法更改WidgetType
}
}
// 设定WidgetId
// 参数id
public void setWidgetId(int id) {
if (id != mWidgetId) {//设定条件 id != mWidgetId
if (id != mWidgetId) {
mWidgetId = id;
mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId));
// 调用Note的setNoteValue方法更改WidgetId
}
}
// 设定WorkingTex
// 参数更改的text
public void setWorkingText(String text) {
if (!TextUtils.equals(mContent, text)) {//设定条件 mContent, text内容不同
if (!TextUtils.equals(mContent, text)) {
mContent = text;
mNote.setTextData(DataColumns.CONTENT, mContent);
// 调用Note的setTextData方法更改WorkingText
}
}
// 转变mNote的CallData及CallNote信息
// 参数String phoneNumber, long callDate
public void convertToCallNote(String phoneNumber, long callDate) {
mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate));
mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber);
mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(Notes.ID_CALL_RECORD_FOLDER));
}
// 判断是否有时钟题型
public boolean hasClockAlert() {
return (mAlertDate > 0 ? true : false);
}
// 获取Content
public String getContent() {
return mContent;
}
// 获取AlertDate
public long getAlertDate() {
return mAlertDate;
}
// 获取ModifiedDate
public long getModifiedDate() {
return mModifiedDate;
}
// 获取背景颜色来源id
public int getBgColorResId() {
return NoteBgResources.getNoteBgResource(mBgColorId);
}
// 获取背景颜色id
public int getBgColorId() {
return mBgColorId;
}
// 获取标题背景颜色id
public int getTitleBgResId() {
return NoteBgResources.getNoteTitleBgResource(mBgColorId);
}
// 获取CheckListMode
public int getCheckListMode() {
return mMode;
}
// 获取便签id
public long getNoteId() {
return mNoteId;
}
// 获取文件夹id
public long getFolderId() {
return mFolderId;
}
// 获取WidgetId
public int getWidgetId() {
return mWidgetId;
}
// 获取WidgetType
public int getWidgetType() {
return mWidgetType;
}
// 创建接口 NoteSettingChangedListener,便签更新监视
// 为NoteEditActivity提供接口
// 提供函数有
public interface NoteSettingChangedListener {
public interface NoteSettingChangedListener {
/**
* Called when the background color of current note has just changed
*/
void onBackgroundColorChanged();
/**
* Called when user set clock
*/
void onClockAlertChanged(long date, boolean set);
/**
* Call when user create note from widget
*/
void onWidgetChanged();
/**
* Call when switch between check list mode and normal mode
* @param oldMode is previous mode before change
@ -371,4 +365,4 @@ public class WorkingNote {
*/
void onCheckListModeChanged(int oldMode, int newMode);
}
}
}

@ -1,58 +1,90 @@
/*
* 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;
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 {
private static final String TAG = "BackupUtils";
private static final String TAG = "BackupUtils";
// Singleton stuff
private static BackupUtils sInstance; //类里面为什么可以定义自身类的对象?
private static BackupUtils sInstance;
public static synchronized BackupUtils getInstance(Context context) {
//ynchronized 关键字,代表这个方法加锁,相当于不管哪一个线程例如线程A
//运行到这个方法时,都要检查有没有其它线程B或者C、 D等正在用这个方法(或者该类的其他同步方法)有的话要等正在使用synchronized方法的线程B或者C 、D运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。
//它包括两种用法synchronized 方法和 synchronized 块。
if (sInstance == null) {
//如果当前备份不存在,则新声明一个
sInstance = new BackupUtils(context);
}
return sInstance;
}
/**
* Following states are signs to represents backup or restore
* status
*/
// Currently, the sdcard is not mounted SD卡没有被装入手机
public static final int STATE_SD_CARD_UNMOUONTED = 0;
// The backup file not exist 备份文件夹不存在
// Currently, the sdcard is not mounted
public static final int STATE_SD_CARD_UNMOUONTED = 0;
// The backup file not exist
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;
// 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;
// Backup or restore success 成功存储
// Backup or restore success
public static final int STATE_SUCCESS = 4;
private TextExport mTextExport;
private BackupUtils(Context context) { //初始化函数
private BackupUtils(Context context) {
mTextExport = new TextExport(context);
}
private static boolean externalStorageAvailable() { //外部存储功能是否可用
private static boolean externalStorageAvailable() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
public int exportToText() {
return mTextExport.exportToText();
}
public String getExportedTextFileName() {
return mTextExport.mFileName;
}
public String getExportedTextFileDir() {
return mTextExport.mFileDirectory;
}
private static class TextExport {
private static final String[] NOTE_PROJECTION = {
NoteColumns.ID,
@ -60,13 +92,13 @@ public class BackupUtils {
NoteColumns.SNIPPET,
NoteColumns.TYPE
};
private static final int NOTE_COLUMN_ID = 0;
private static final int NOTE_COLUMN_MODIFIED_DATE = 1;
private static final int NOTE_COLUMN_SNIPPET = 2;
private static final String[] DATA_PROJECTION = {
DataColumns.CONTENT,
DataColumns.MIME_TYPE,
@ -75,71 +107,71 @@ public class BackupUtils {
DataColumns.DATA3,
DataColumns.DATA4,
};
private static final int DATA_COLUMN_CONTENT = 0;
private static final int DATA_COLUMN_MIME_TYPE = 1;
private static final int DATA_COLUMN_CALL_DATE = 2;
private static final int DATA_COLUMN_PHONE_NUMBER = 4;
private final String [] TEXT_FORMAT;
private static final int FORMAT_FOLDER_NAME = 0;
private static final int FORMAT_NOTE_DATE = 1;
private static final int FORMAT_NOTE_CONTENT = 2;
private Context mContext;
private String mFileName;
private String mFileDirectory;
public TextExport(Context context) {
TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note);
mContext = context;
mFileName = ""; //为什么为空?
mFileName = "";
mFileDirectory = "";
}
private String getFormat(int id) { //获取文本的组成部分
private String getFormat(int id) {
return TEXT_FORMAT[id];
}
/**
* Export the folder identified by folder id to text
*/
private void exportFolderToText(String folderId, PrintStream ps) {
// Query notes belong to this folder 通过查询parent id是文件夹id的note来选出制定ID文件夹下的Note
private void exportFolderToText(String folderId, PrintStream ps) {
// Query notes belong to this folder
Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] {
folderId
}, null);
if (notesCursor != null) {
if (notesCursor != null) {
if (notesCursor.moveToFirst()) {
do {
// Print note's last modified date ps里面保存有这份note的日期
// Print note's last modified date
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
mContext.getString(R.string.format_datetime_mdhm),
notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
// Query data belong to this note
String noteId = notesCursor.getString(NOTE_COLUMN_ID);
exportNoteToText(noteId, ps); //将文件导出到text
exportNoteToText(noteId, ps);
} while (notesCursor.moveToNext());
}
notesCursor.close();
}
}
/**
* Export note identified by id to a print stream
*/
private void exportNoteToText(String noteId, PrintStream ps) {
private void exportNoteToText(String noteId, PrintStream ps) {
Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI,
DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] {
noteId
}, null);
if (dataCursor != null) { //利用光标来扫描内容区别为callnote和note两种靠ps.printline输出
if (dataCursor != null) {
if (dataCursor.moveToFirst()) {
do {
String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE);
@ -148,8 +180,8 @@ public class BackupUtils {
String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER);
long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE);
String location = dataCursor.getString(DATA_COLUMN_CONTENT);
if (!TextUtils.isEmpty(phoneNumber)) { //判断是否为空字符
if (!TextUtils.isEmpty(phoneNumber)) {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
phoneNumber));
}
@ -182,29 +214,29 @@ public class BackupUtils {
Log.e(TAG, e.toString());
}
}
/**
* Note will be exported as text which is user readable
*/
public int exportToText() { //总函数调用上面的exportFolder和exportNote
public int exportToText() {
if (!externalStorageAvailable()) {
Log.d(TAG, "Media was not mounted");
return STATE_SD_CARD_UNMOUONTED;
}
PrintStream ps = getExportToTextPrintStream();
if (ps == null) {
Log.e(TAG, "get print stream error");
return STATE_SYSTEM_ERROR;
}
// First export folder and its notes 导出文件夹,就是导出里面包含的便签
// First export folder and its notes
Cursor folderCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION,
"(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND "
+ NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR "
+ NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null);
if (folderCursor != null) {
if (folderCursor.moveToFirst()) {
do {
@ -224,14 +256,14 @@ public class BackupUtils {
}
folderCursor.close();
}
// Export notes in root's folder 将根目录里的便签导出(由于不属于任何文件夹,因此无法通过文件夹导出来实现这一部分便签的导出)
// Export notes in root's folder
Cursor noteCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION,
NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID
+ "=0", null, null);
if (noteCursor != null) {
if (noteCursor.moveToFirst()) {
do {
@ -246,14 +278,14 @@ public class BackupUtils {
noteCursor.close();
}
ps.close();
return STATE_SUCCESS;
}
/**
* Get a print stream pointed to the file {@generateExportedTextFile}
*/
private PrintStream getExportToTextPrintStream() {
private PrintStream getExportToTextPrintStream() {
File file = generateFileMountedOnSDcard(mContext, R.string.file_path,
R.string.file_name_txt_format);
if (file == null) {
@ -265,7 +297,7 @@ public class BackupUtils {
PrintStream ps = null;
try {
FileOutputStream fos = new FileOutputStream(file);
ps = new PrintStream(fos); //将ps输出流输出到特定的文件目的就是导出到文件而不是直接输出
ps = new PrintStream(fos);
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
@ -276,22 +308,22 @@ public class BackupUtils {
return ps;
}
}
/**
* Generate the text file to store imported data
*/
private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) {
StringBuilder sb = new StringBuilder();
sb.append(Environment.getExternalStorageDirectory()); //外部SD卡的存储路径
sb.append(context.getString(filePathResId)); //文件的存储路径
File filedir = new File(sb.toString()); //filedir应该就是用来存储路径信息
sb.append(Environment.getExternalStorageDirectory());
sb.append(context.getString(filePathResId));
File filedir = new File(sb.toString());
sb.append(context.getString(
fileNameFormatResId,
DateFormat.format(context.getString(R.string.format_date_ymd),
System.currentTimeMillis())));
File file = new File(sb.toString());
try { //如果这些文件不存在,则新建
try {
if (!filedir.exists()) {
filedir.mkdir();
}
@ -304,9 +336,9 @@ public class BackupUtils {
} catch (IOException e) {
e.printStackTrace();
}
// try catch 异常处理
return null;
}
}

@ -1,8 +1,43 @@
/*
* 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;
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 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;
@ -11,20 +46,19 @@ public class DataUtils {
Log.d(TAG, "no id is in the hashset");
return true;
}
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>(); //提供一个任务列表
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
for (long id : ids) {
if(id == Notes.ID_ROOT_FOLDER) {
Log.e(TAG, "Don't delete system folder root");
continue;
} //如果发现是根文件夹,则不删除
}
ContentProviderOperation.Builder builder = ContentProviderOperation
.newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); //用newDelete实现删除功能
operationList.add(builder.build()); //
.newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
operationList.add(builder.build());
}
try {
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);//主机名或叫Authority用于唯一标识这个ContentProvider外部调用者可以根据这个标识来找到它。
//数据库事务,数据库事务是由一组数据库操作序列组成,事务作为一个整体被执行
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
if (results == null || results.length == 0 || results[0] == null) {
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
return false;
@ -37,33 +71,33 @@ public class DataUtils {
}
return false;
}
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
ContentValues values = new ContentValues();
values.put(NoteColumns.PARENT_ID, desFolderId);
values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId);
values.put(NoteColumns.LOCAL_MODIFIED, 1);
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); //对需要移动的便签进行数据更新然后用update实现
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null);
}
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,
long folderId) {
if (ids == null) {
Log.d(TAG, "the ids is null");
return true;
}
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
for (long id : ids) {
ContentProviderOperation.Builder builder = ContentProviderOperation
.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); //通过withAppendedId方法为该Uri加上ID
.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
builder.withValue(NoteColumns.PARENT_ID, folderId);
builder.withValue(NoteColumns.LOCAL_MODIFIED, 1);
operationList.add(builder.build());
}//将ids里包含的每一列的数据逐次加入到operationList中等待最后的批量处理
}
try {
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); //applyBatch一次性处理一个操作列表
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
if (results == null || results.length == 0 || results[0] == null) {
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
return false;
@ -76,7 +110,7 @@ public class DataUtils {
}
return false;
}
/**
* Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}}
*/
@ -85,13 +119,13 @@ public class DataUtils {
new String[] { "COUNT(*)" },
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?",
new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)},
null); //筛选条件源文件不为trash folder
null);
int count = 0;
if(cursor != null) {
if(cursor.moveToFirst()) {
try {
count = cursor.getInt(0);
count = cursor.getInt(0);
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, "get folder count failed:" + e.toString());
} finally {
@ -100,29 +134,29 @@ 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), //通过withAppendedId方法为该Uri加上ID
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null,
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER,
new String [] {String.valueOf(type)},
null); //查询条件type符合且不属于垃圾文件夹
new String [] {String.valueOf(type)},
null);
boolean exist = false;
if (cursor != null) {
if (cursor.getCount() > 0) {//用getcount函数判断cursor是否为空
if (cursor.getCount() > 0) {
exist = true;
}
cursor.close();
}
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);
boolean exist = false;
if (cursor != null) {
if (cursor.getCount() > 0) {
@ -132,11 +166,11 @@ 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);
boolean exist = false;
if (cursor != null) {
if (cursor.getCount() > 0) {
@ -146,14 +180,13 @@ 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 +
" AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +
" AND " + NoteColumns.SNIPPET + "=?",
new String[] { name }, null);
//通过名字查询文件是否存在
boolean exist = false;
if(cursor != null) {
if(cursor.getCount() > 0) {
@ -163,14 +196,14 @@ public class DataUtils {
}
return exist;
}
public static HashSet<AppWidgetAttribute> getFolderNoteWidget(ContentResolver resolver, long folderId) {
Cursor c = resolver.query(Notes.CONTENT_NOTE_URI,
new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE },
NoteColumns.PARENT_ID + "=?",
new String[] { String.valueOf(folderId) },
null); //查询条件父ID是传入的folderId;
null);
HashSet<AppWidgetAttribute> set = null;
if (c != null) {
if (c.moveToFirst()) {
@ -178,26 +211,26 @@ public class DataUtils {
do {
try {
AppWidgetAttribute widget = new AppWidgetAttribute();
widget.widgetId = c.getInt(0); //0对应的NoteColumns.WIDGET_ID
widget.widgetType = c.getInt(1); //1对应的NoteColumns.WIDGET_TYPE
widget.widgetId = c.getInt(0);
widget.widgetType = c.getInt(1);
set.add(widget);
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, e.toString());
}
} while (c.moveToNext()); //查询下一条
} while (c.moveToNext());
}
c.close();
}
return set;
}
public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) {
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.PHONE_NUMBER },
CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?",
new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE },
null);
if (cursor != null && cursor.moveToFirst()) {
try {
return cursor.getString(0);
@ -209,7 +242,7 @@ public class DataUtils {
}
return "";
}
public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) {
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.NOTE_ID },
@ -217,12 +250,11 @@ public class DataUtils {
+ CallNote.PHONE_NUMBER + ",?)",
new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber },
null);
//通过数据库操作查询条件是callDate和phoneNumber匹配传入参数的值
if (cursor != null) {
if (cursor.moveToFirst()) {
try {
return cursor.getLong(0); //0对应的CallNote.NOTE_ID
return cursor.getLong(0);
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, "Get call note id fails " + e.toString());
}
@ -231,14 +263,14 @@ public class DataUtils {
}
return 0;
}
public static String getSnippetById(ContentResolver resolver, long noteId) {
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,
new String [] { NoteColumns.SNIPPET },
NoteColumns.ID + "=?",
new String [] { String.valueOf(noteId)},
null);//查询条件noteId
null);
if (cursor != null) {
String snippet = "";
if (cursor.moveToFirst()) {
@ -249,7 +281,8 @@ public class DataUtils {
}
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) {
snippet = snippet.trim();
int index = snippet.indexOf('\n');
@ -259,5 +292,4 @@ public class DataUtils {
}
return snippet;
}
}
}

@ -1,99 +1,113 @@
//简介定义了很多的静态字符串目的就是为了提供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;
//这个类就是定义了一堆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_LIST = "action_list";
public final static String GTASK_JSON_ACTION_TYPE = "action_type";
public final static String GTASK_JSON_ACTION_TYPE_CREATE = "create";
public final static String GTASK_JSON_ACTION_TYPE_GETALL = "get_all";
public final static String GTASK_JSON_ACTION_TYPE_MOVE = "move";
public final static String GTASK_JSON_ACTION_TYPE_UPDATE = "update";
public final static String GTASK_JSON_CREATOR_ID = "creator_id";
public final static String GTASK_JSON_CHILD_ENTITY = "child_entity";
public final static String GTASK_JSON_CLIENT_VERSION = "client_version";
public final static String GTASK_JSON_COMPLETED = "completed";
public final static String GTASK_JSON_CURRENT_LIST_ID = "current_list_id";
public final static String GTASK_JSON_DEFAULT_LIST_ID = "default_list_id";
public final static String GTASK_JSON_DELETED = "deleted";
public final static String GTASK_JSON_DEST_LIST = "dest_list";
public final static String GTASK_JSON_DEST_PARENT = "dest_parent";
public final static String GTASK_JSON_DEST_PARENT_TYPE = "dest_parent_type";
public final static String GTASK_JSON_ENTITY_DELTA = "entity_delta";
public final static String GTASK_JSON_ENTITY_TYPE = "entity_type";
public final static String GTASK_JSON_GET_DELETED = "get_deleted";
public final static String GTASK_JSON_ID = "id";
public final static String GTASK_JSON_INDEX = "index";
public final static String GTASK_JSON_LAST_MODIFIED = "last_modified";
public final static String GTASK_JSON_LATEST_SYNC_POINT = "latest_sync_point";
public final static String GTASK_JSON_LIST_ID = "list_id";
public final static String GTASK_JSON_LISTS = "lists";
public final static String GTASK_JSON_NAME = "name";
public final static String GTASK_JSON_NEW_ID = "new_id";
public final static String GTASK_JSON_NOTES = "notes";
public final static String GTASK_JSON_PARENT_ID = "parent_id";
public final static String GTASK_JSON_PRIOR_SIBLING_ID = "prior_sibling_id";
public final static String GTASK_JSON_RESULTS = "results";
public final static String GTASK_JSON_SOURCE_LIST = "source_list";
public final static String GTASK_JSON_TASKS = "tasks";
public final static String GTASK_JSON_TYPE = "type";
public final static String GTASK_JSON_TYPE_GROUP = "GROUP";
public final static String GTASK_JSON_TYPE_TASK = "TASK";
public final static String GTASK_JSON_USER = "user";
public final static String MIUI_FOLDER_PREFFIX = "[MIUI_Notes]";
public final static String FOLDER_DEFAULT = "Default";
public final static String FOLDER_CALL_NOTE = "Call_Note";
public final static String FOLDER_META = "METADATA";
public final static String META_HEAD_GTASK_ID = "meta_gid";
public final static String META_HEAD_NOTE = "meta_note";
public final static String META_HEAD_DATA = "meta_data";
public final static String META_NOTE_NAME = "[META INFO] DON'T UPDATE AND DELETE";
}
}

@ -1,35 +1,44 @@
package net.micode.notes.tool;/*使
* R.java
* R.id
* R.drawable 使
* R.layout
* R.menu
* R.String
* R.style 使
* idgetXXX
*
*
* @BG_DEFAULT_COLOR
* BG_DEFAULT_FONT_SIZE
/*
* 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;
import android.content.Context;
import android.preference.PreferenceManager;
import net.micode.notes.R;
import net.micode.notes.ui.NotesPreferenceActivity;
public class ResourceParser {
public static final int YELLOW = 0;
public static final int BLUE = 1;
public static final int WHITE = 2;
public static final int GREEN = 3;
public static final int RED = 4;
public static final int BG_DEFAULT_COLOR = YELLOW;
public static final int TEXT_SMALL = 0;
public static final int TEXT_MEDIUM = 1;
public static final int TEXT_LARGE = 2;
public static final int TEXT_SUPER = 3;
public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM;
public static class NoteBgResources {
private final static int [] BG_EDIT_RESOURCES = new int [] {
R.drawable.edit_yellow,
@ -38,7 +47,7 @@ public class ResourceParser {
R.drawable.edit_green,
R.drawable.edit_red
};
private final static int [] BG_EDIT_TITLE_RESOURCES = new int [] {
R.drawable.edit_title_yellow,
R.drawable.edit_title_blue,
@ -46,17 +55,17 @@ public class ResourceParser {
R.drawable.edit_title_green,
R.drawable.edit_title_red
};
public static int getNoteBgResource(int id) {
return BG_EDIT_RESOURCES[id];
}
public static int getNoteTitleBgResource(int 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(
NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) {
return (int) (Math.random() * NoteBgResources.BG_EDIT_RESOURCES.length);
@ -64,7 +73,7 @@ public class ResourceParser {
return BG_DEFAULT_COLOR;
}
}
public static class NoteItemBgResources {
private final static int [] BG_FIRST_RESOURCES = new int [] {
R.drawable.list_yellow_up,
@ -73,7 +82,7 @@ public class ResourceParser {
R.drawable.list_green_up,
R.drawable.list_red_up
};
private final static int [] BG_NORMAL_RESOURCES = new int [] {
R.drawable.list_yellow_middle,
R.drawable.list_blue_middle,
@ -81,7 +90,7 @@ public class ResourceParser {
R.drawable.list_green_middle,
R.drawable.list_red_middle
};
private final static int [] BG_LAST_RESOURCES = new int [] {
R.drawable.list_yellow_down,
R.drawable.list_blue_down,
@ -89,7 +98,7 @@ public class ResourceParser {
R.drawable.list_green_down,
R.drawable.list_red_down,
};
private final static int [] BG_SINGLE_RESOURCES = new int [] {
R.drawable.list_yellow_single,
R.drawable.list_blue_single,
@ -97,28 +106,28 @@ public class ResourceParser {
R.drawable.list_green_single,
R.drawable.list_red_single
};
public static int getNoteBgFirstRes(int id) {
return BG_FIRST_RESOURCES[id];
}
public static int getNoteBgLastRes(int id) {
return BG_LAST_RESOURCES[id];
}
public static int getNoteBgSingleRes(int id) {
return BG_SINGLE_RESOURCES[id];
}
public static int getNoteBgNormalRes(int id) {
return BG_NORMAL_RESOURCES[id];
}
public static int getFolderBgRes() {
return R.drawable.list_folder;
}
}
public static class WidgetBgResources {
private final static int [] BG_2X_RESOURCES = new int [] {
R.drawable.widget_2x_yellow,
@ -127,11 +136,11 @@ public class ResourceParser {
R.drawable.widget_2x_green,
R.drawable.widget_2x_red,
};
public static int getWidget2xBgResource(int id) {
return BG_2X_RESOURCES[id];
}
private final static int [] BG_4X_RESOURCES = new int [] {
R.drawable.widget_4x_yellow,
R.drawable.widget_4x_blue,
@ -139,12 +148,12 @@ public class ResourceParser {
R.drawable.widget_4x_green,
R.drawable.widget_4x_red
};
public static int getWidget4xBgResource(int id) {
return BG_4X_RESOURCES[id];
}
}
public static class TextAppearanceResources {
private final static int [] TEXTAPPEARANCE_RESOURCES = new int [] {
R.style.TextAppearanceNormal,
@ -152,8 +161,7 @@ public class ResourceParser {
R.style.TextAppearanceLarge,
R.style.TextAppearanceSuper
};
//这里有一个容错的函数防止输入的id大于资源总量若如此则自动返回默认的设置结果
public static int getTexAppearanceResource(int id) {
/**
* HACKME: Fix bug of store the resource id in shared preference.
@ -165,9 +173,9 @@ public class ResourceParser {
}
return TEXTAPPEARANCE_RESOURCES[id];
}
public static int getResourcesSize() {
return TEXTAPPEARANCE_RESOURCES.length;
}
}
}
}

@ -14,138 +14,145 @@
* limitations under the License.
*/
package net.micode.notes.ui; // 定义了该类的包路径
import android.app.Activity; // 导入Activity类用于创建Android活动
import android.app.AlertDialog; // 导入AlertDialog类用于创建对话框
import android.content.Context; // 导入Context类用于获取应用程序环境
import android.content.DialogInterface; // 导入DialogInterface类用于处理对话框事件
import android.content.DialogInterface.OnClickListener; // 导入OnClickListener接口用于处理对话框按钮点击事件
import android.content.DialogInterface.OnDismissListener; // 导入OnDismissListener接口用于处理对话框关闭事件
import android.content.Intent; // 导入Intent类用于启动活动和传递数据
import android.media.AudioManager; // 导入AudioManager类用于管理音频设置
import android.media.MediaPlayer; // 导入MediaPlayer类用于播放音频
import android.media.RingtoneManager; // 导入RingtoneManager类用于获取铃声
import android.net.Uri; // 导入Uri类用于表示资源路径
import android.os.Bundle; // 导入Bundle类用于保存活动状态
import android.os.PowerManager; // 导入PowerManager类用于管理电源设置
import android.provider.Settings; // 导入Settings类用于获取系统设置
import android.view.Window; // 导入Window类用于管理窗口
import android.view.WindowManager; // 导入WindowManager类用于管理窗口标志
import net.micode.notes.R; // 导入应用内部定义的资源类
import net.micode.notes.data.Notes; // 导入应用内部定义的笔记数据类
import net.micode.notes.tool.DataUtils; // 导入应用内部定义的数据工具类
import java.io.IOException; // 导入IOException类用于处理输入输出异常
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener { // 定义AlarmAlertActivity类继承自Activity并实现OnClickListener和OnDismissListener接口
private long mNoteId; // 定义笔记的ID
private String mSnippet; // 定义笔记内容的简短预览
private static final int SNIPPET_PREW_MAX_LEN = 60; // 定义预览文本的最大长度
private MediaPlayer mPlayer; // 定义用于播放提醒声音的MediaPlayer对象
package net.micode.notes.ui;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.PowerManager;
import android.provider.Settings;
import android.view.Window;
import android.view.WindowManager;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.tool.DataUtils;
import java.io.IOException;
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
private long mNoteId;
private String mSnippet;
private static final int SNIPPET_PREW_MAX_LEN = 60;
MediaPlayer mPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) { // 重写onCreate方法在活动创建时调用
super.onCreate(savedInstanceState); // 调用父类的onCreate方法
requestWindowFeature(Window.FEATURE_NO_TITLE); // 请求无标题的窗口
final Window win = getWindow(); // 获取当前窗口
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); // 设置窗口在锁屏时显示
if (!isScreenOn()) { // 检查屏幕是否处于打开状态
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON // 保持屏幕唤醒
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON // 打开屏幕
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON // 允许在屏幕打开时锁定
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); // 布局插入装饰
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
if (!isScreenOn()) {
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
}
Intent intent = getIntent(); // 获取启动该活动的意图
Intent intent = getIntent();
try {
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1)); // 从意图中获取笔记ID
mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId); // 获取笔记内容的简短预览
mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0, // 如果预览文本长度超过最大长度,则截取
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));
mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId);
mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0,
SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info)
: mSnippet; // 否则使用原始预览文本
} catch (IllegalArgumentException e) { // 捕获非法参数异常
e.printStackTrace(); // 打印异常信息
return; // 返回
: mSnippet;
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
}
mPlayer = new MediaPlayer(); // 创建MediaPlayer对象
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) { // 检查笔记在数据库中是否可见
showActionDialog(); // 显示动作对话框
playAlarmSound(); // 播放提醒声音
mPlayer = new MediaPlayer();
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {
showActionDialog();
playAlarmSound();
} else {
finish(); // 结束活动
finish();
}
}
private boolean isScreenOn() { // 定义检查屏幕是否处于打开状态的方法
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); // 获取电源管理服务
return pm.isScreenOn(); // 返回屏幕是否处于打开状态
private boolean isScreenOn() {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
return pm.isScreenOn();
}
private void playAlarmSound() { // 定义播放提醒声音的方法
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM); // 获取默认的闹钟铃声URI
int silentModeStreams = Settings.System.getInt(getContentResolver(), // 获取静音模式下影响的音频流
private void playAlarmSound() {
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM);
int silentModeStreams = Settings.System.getInt(getContentResolver(),
Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) { // 检查闹钟音频流是否受静音模式影响
mPlayer.setAudioStreamType(silentModeStreams); // 设置音频流类型
if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) {
mPlayer.setAudioStreamType(silentModeStreams);
} else {
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM); // 设置音频流类型为闹钟
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
}
try {
mPlayer.setDataSource(this, url); // 设置数据源
mPlayer.prepare(); // 准备播放
mPlayer.setLooping(true); // 设置循环播放
mPlayer.start(); // 开始播放
} catch (IllegalArgumentException e) { // 捕获非法参数异常
e.printStackTrace(); // 打印异常信息
} catch (SecurityException e) { // 捕获安全异常
e.printStackTrace(); // 打印异常信息
} catch (IllegalStateException e) { // 捕获非法状态异常
e.printStackTrace(); // 打印异常信息
} catch (IOException e) { // 捕获输入输出异常
e.printStackTrace(); // 打印异常信息
mPlayer.setDataSource(this, url);
mPlayer.prepare();
mPlayer.setLooping(true);
mPlayer.start();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void showActionDialog() { // 定义显示动作对话框的方法
AlertDialog.Builder dialog = new AlertDialog.Builder(this); // 创建对话框构建器
dialog.setTitle(R.string.app_name); // 设置对话框标题
dialog.setMessage(mSnippet); // 设置对话框消息
dialog.setPositiveButton(R.string.notealert_ok, this); // 设置正面按钮
if (isScreenOn()) { // 检查屏幕是否处于打开状态
dialog.setNegativeButton(R.string.notealert_enter, this); // 设置负面按钮
private void showActionDialog() {
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setTitle(R.string.app_name);
dialog.setMessage(mSnippet);
dialog.setPositiveButton(R.string.notealert_ok, this);
if (isScreenOn()) {
dialog.setNegativeButton(R.string.notealert_enter, this);
}
dialog.show().setOnDismissListener(this); // 显示对话框并设置关闭监听器
dialog.show().setOnDismissListener(this);
}
public void onClick(DialogInterface dialog, int which) { // 实现OnClickListener接口的onClick方法处理对话框按钮点击事件
switch (which) { // 根据按钮类型进行处理
case DialogInterface.BUTTON_NEGATIVE: // 如果是负面按钮
Intent intent = new Intent(this, NoteEditActivity.class); // 创建启动笔记编辑活动的意图
intent.setAction(Intent.ACTION_VIEW); // 设置动作
intent.putExtra(Intent.EXTRA_UID, mNoteId); // 传递笔记ID
startActivity(intent); // 启动活动
break; // 结束处理
default: // 默认情况
break; // 结束处理
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_NEGATIVE:
Intent intent = new Intent(this, NoteEditActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(Intent.EXTRA_UID, mNoteId);
startActivity(intent);
break;
default:
break;
}
}
public void onDismiss(DialogInterface dialog) { // 实现OnDismissListener接口的onDismiss方法处理对话框关闭事件
stopAlarmSound(); // 停止播放提醒声音
finish(); // 结束活动
public void onDismiss(DialogInterface dialog) {
stopAlarmSound();
finish();
}
private void stopAlarmSound() { // 定义停止播放提醒声音的方法
if (mPlayer != null) { // 检查MediaPlayer对象是否为空
mPlayer.stop(); // 停止播放
mPlayer.release(); // 释放资源
mPlayer = null; // 将MediaPlayer对象设置为空
private void stopAlarmSound() {
if (mPlayer != null) {
mPlayer.stop();
mPlayer.release();
mPlayer = null;
}
}
}
}

@ -14,72 +14,52 @@
* limitations under the License.
*/
/*
* 广
*
*/
package net.micode.notes.ui; // 定义该类的包路径
import android.app.AlarmManager; // 导入AlarmManager类用于设置提醒
import android.app.PendingIntent; // 导入PendingIntent类用于延迟执行意图
import android.content.BroadcastReceiver; // 导入BroadcastReceiver类用于接收广播
import android.content.ContentUris; // 导入ContentUris类用于处理URI
import android.content.Context; // 导入Context类用于获取应用环境
import android.content.Intent; // 导入Intent类用于启动活动和传递数据
import android.database.Cursor; // 导入Cursor类用于查询数据库
import net.micode.notes.data.Notes; // 导入应用内部定义的笔记数据类
import net.micode.notes.data.Notes.NoteColumns; // 导入笔记数据类的列定义
public class AlarmInitReceiver extends BroadcastReceiver { // 定义AlarmInitReceiver类继承自BroadcastReceiver
// 查询笔记时需要的列
private static final String[] PROJECTION = new String[]{
NoteColumns.ID, // 笔记ID
NoteColumns.ALERTED_DATE // 提醒日期
package net.micode.notes.ui;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
public class AlarmInitReceiver extends BroadcastReceiver {
private static final String [] PROJECTION = new String [] {
NoteColumns.ID,
NoteColumns.ALERTED_DATE
};
// 列的索引
private static final int COLUMN_ID = 0; // ID列的索引
private static final int COLUMN_ALERTED_DATE = 1; // 提醒日期列的索引
/**
* 广
*
* @param context 访
* @param intent 广
*/
private static final int COLUMN_ID = 0;
private static final int COLUMN_ALERTED_DATE = 1;
@Override
public void onReceive(Context context, Intent intent) { // 重写onReceive方法当接收到广播时执行
// 获取当前日期和时间
long currentDate = System.currentTimeMillis(); // 获取当前时间戳
// 查询数据库中所有需要提醒的笔记
Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI, // 查询笔记内容的URI
PROJECTION, // 查询的列
NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE, // 查询条件
new String[]{String.valueOf(currentDate)}, // 查询参数
null); // 排序方式
if (c != null) { // 检查Cursor是否为空
// 遍历查询结果,为每个需要提醒的笔记设置提醒
if (c.moveToFirst()) { // 移动到第一行
public void onReceive(Context context, Intent intent) {
long currentDate = System.currentTimeMillis();
Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION,
NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE,
new String[] { String.valueOf(currentDate) },
null);
if (c != null) {
if (c.moveToFirst()) {
do {
// 获取提醒日期
long alertDate = c.getLong(COLUMN_ALERTED_DATE); // 获取提醒日期
// 创建Intent用于在提醒时间触发AlarmReceiver
Intent sender = new Intent(context, AlarmReceiver.class); // 创建启动AlarmReceiver的意图
sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID))); // 设置意图的数据URI
// 创建PendingIntent它是一个延迟的意图可以在特定时间由系统触发
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0); // 创建PendingIntent
// 获取AlarmManager服务用于设置提醒
long alertDate = c.getLong(COLUMN_ALERTED_DATE);
Intent sender = new Intent(context, AlarmReceiver.class);
sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID)));
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0);
AlarmManager alermManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE); // 获取AlarmManager服务
// 设置提醒
alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent); // 设置提醒时间
} while (c.moveToNext()); // 移动到下一行
.getSystemService(Context.ALARM_SERVICE);
alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent);
} while (c.moveToNext());
}
// 关闭Cursor释放资源
c.close(); // 关闭Cursor
c.close();
}
}
}
}

@ -14,33 +14,17 @@
* limitations under the License.
*/
/*
* AlarmReceiver - 广
* 广Activity
*
* extends BroadcastReceiver: AndroidBroadcastReceiver
*/
package net.micode.notes.ui; // 定义该类的包路径
import android.content.BroadcastReceiver; // 导入BroadcastReceiver类用于接收广播
import android.content.Context; // 导入Context类用于获取应用环境
import android.content.Intent; // 导入Intent类用于启动活动和传递数据
public class AlarmReceiver extends BroadcastReceiver { // 定义AlarmReceiver类继承自BroadcastReceiver
/*
* onReceive - 广
* 广AlarmAlertActivity
*
* @param context
* @param intent 广
*/
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) { // 重写onReceive方法当接收到广播时执行
// 设置Intent的类以便启动AlarmAlertActivity
intent.setClass(context, AlarmAlertActivity.class); // 设置Intent的目标Activity为AlarmAlertActivity
// 添加标志表示在一个新的任务中启动Activity
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 添加标志确保Activity在一个新的任务中启动
// 根据设置的Intent启动Activity
context.startActivity(intent); // 启动AlarmAlertActivity
public void onReceive(Context context, Intent intent) {
intent.setClass(context, AlarmAlertActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
}

@ -14,103 +14,71 @@
* limitations under the License.
*/
package net.micode.notes.ui;
import java.text.DateFormatSymbols;
import java.util.Calendar;
import net.micode.notes.R;
import android.content.Context;
import android.text.format.DateFormat;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.NumberPicker;
public class DateTimePicker extends FrameLayout {
// 默认启用状态
private static final boolean DEFAULT_ENABLE_STATE = true;
// 半天的小时数
private static final int HOURS_IN_HALF_DAY = 12;
// 一整天的小时数
private static final int HOURS_IN_ALL_DAY = 24;
// 一周的天数
private static final int DAYS_IN_ALL_WEEK = 7;
// 日期选择器的最小值
private static final int DATE_SPINNER_MIN_VAL = 0;
// 日期选择器的最大值
private static final int DATE_SPINNER_MAX_VAL = DAYS_IN_ALL_WEEK - 1;
// 24小时制小时选择器的最小值
private static final int HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW = 0;
// 24小时制小时选择器的最大值
private static final int HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW = 23;
// 12小时制小时选择器的最小值
private static final int HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW = 1;
// 12小时制小时选择器的最大值
private static final int HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW = 12;
// 分钟选择器的最小值
private static final int MINUT_SPINNER_MIN_VAL = 0;
// 分钟选择器的最大值
private static final int MINUT_SPINNER_MAX_VAL = 59;
// 上下午选择器的最小值
private static final int AMPM_SPINNER_MIN_VAL = 0;
// 上下午选择器的最大值
private static final int AMPM_SPINNER_MAX_VAL = 1;
// 日期选择器
private final NumberPicker mDateSpinner;
// 小时选择器
private final NumberPicker mHourSpinner;
// 分钟选择器
private final NumberPicker mMinuteSpinner;
// 上下午选择器
private final NumberPicker mAmPmSpinner;
// 当前日期
private Calendar mDate;
// 用于显示日期的字符串数组
private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK];
// 当前是否为上午
private boolean mIsAm;
// 当前是否为24小时制视图
private boolean mIs24HourView;
// 控件是否启用
private boolean mIsEnabled = DEFAULT_ENABLE_STATE;
// 是否正在初始化
private boolean mInitialising;
// 日期时间改变监听器
private OnDateTimeChangedListener mOnDateTimeChangedListener;
// 日期选择器的值改变监听器
private NumberPicker.OnValueChangeListener mOnDateChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// 根据新旧值的差异更新日期
mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal);
updateDateControl();
onDateTimeChanged();
}
};
// 小时选择器的值改变监听器
private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// 根据小时的变化更新日期和上下午状态
boolean isDateChanged = false;
Calendar cal = Calendar.getInstance();
if (!mIs24HourView) {
// 处理12小时制下的日期变化和上下午切换
if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
@ -126,7 +94,6 @@ public class DateTimePicker extends FrameLayout {
updateAmPmControl();
}
} else {
// 处理24小时制下的日期变化
if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
@ -137,11 +104,9 @@ public class DateTimePicker extends FrameLayout {
isDateChanged = true;
}
}
// 更新小时并触发日期时间改变事件
int newHour = mHourSpinner.getValue() % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY);
mDate.set(Calendar.HOUR_OF_DAY, newHour);
onDateTimeChanged();
// 如果日期有变化,则更新年月日
if (isDateChanged) {
setCurrentYear(cal.get(Calendar.YEAR));
setCurrentMonth(cal.get(Calendar.MONTH));
@ -149,13 +114,10 @@ public class DateTimePicker extends FrameLayout {
}
}
};
// 分别为分钟和AM/PM选择器监听器设置匿名内部类实现数值变化时的处理逻辑。
private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// 计算小时的偏移量,当从最大值变为最小值或从最小值变为最大值时调整
int minValue = mMinuteSpinner.getMinValue();
int maxValue = mMinuteSpinner.getMaxValue();
int offset = 0;
@ -164,7 +126,6 @@ public class DateTimePicker extends FrameLayout {
} else if (oldVal == minValue && newVal == maxValue) {
offset -= 1;
}
// 根据偏移量更新日期和小时选择器并检查是否需要切换AM/PM
if (offset != 0) {
mDate.add(Calendar.HOUR_OF_DAY, offset);
mHourSpinner.setValue(getCurrentHour());
@ -178,16 +139,14 @@ public class DateTimePicker extends FrameLayout {
updateAmPmControl();
}
}
// 更新分钟值并触发日期变化的回调
mDate.set(Calendar.MINUTE, newVal);
onDateTimeChanged();
}
};
private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// 切换AM/PM状态并更新日期和AM/PM选择器
mIsAm = !mIsAm;
if (mIsAm) {
mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY);
@ -198,238 +157,202 @@ public class DateTimePicker extends FrameLayout {
onDateTimeChanged();
}
};
// 定义日期时间变化的回调接口
public interface OnDateTimeChangedListener {
void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute);
int dayOfMonth, int hourOfDay, int minute);
}
// 构造函数:初始化日期时间选择器
public DateTimePicker(Context context) {
this(context, System.currentTimeMillis());
}
// 构造函数:指定初始日期时间
public DateTimePicker(Context context, long date) {
this(context, date, DateFormat.is24HourFormat(context));
}
// 构造函数指定是否使用24小时制视图
public DateTimePicker(Context context, long date, boolean is24HourView) {
super(context);
mDate = Calendar.getInstance();
mInitialising = true;
mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY;
inflate(context, R.layout.datetime_picker, this);
// 初始化日期、小时、分钟和AM/PM选择器并设置相应的监听器
mDateSpinner = (NumberPicker) findViewById(R.id.date);
mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL);
mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL);
mDateSpinner.setOnValueChangedListener(mOnDateChangedListener);
mHourSpinner = (NumberPicker) findViewById(R.id.hour);
mHourSpinner.setOnValueChangedListener(mOnHourChangedListener);
mMinuteSpinner = (NumberPicker) findViewById(R.id.minute);
mMinuteSpinner = (NumberPicker) findViewById(R.id.minute);
mMinuteSpinner.setMinValue(MINUT_SPINNER_MIN_VAL);
mMinuteSpinner.setMaxValue(MINUT_SPINNER_MAX_VAL);
mMinuteSpinner.setOnLongPressUpdateInterval(100);
mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener);
String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings();
mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm);
mAmPmSpinner.setMinValue(AMPM_SPINNER_MIN_VAL);
mAmPmSpinner.setMaxValue(AMPM_SPINNER_MAX_VAL);
mAmPmSpinner.setDisplayedValues(stringsForAmPm);
mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener);
// 更新控件至初始状态
// update controls to initial state
updateDateControl();
updateHourControl();
updateAmPmControl();
set24HourView(is24HourView);
// 设置为当前时间
// set to current time
setCurrentDate(date);
setEnabled(isEnabled());
// 设置内容描述
// set the content descriptions
mInitialising = false;
}
/**
*
*
*
*
* @param enabled
*/
@Override
public void setEnabled(boolean enabled) {
if (mIsEnabled == enabled) {
return;
}
super.setEnabled(enabled);
// 同时启用或禁用日期和时间选择器
mDateSpinner.setEnabled(enabled);
mMinuteSpinner.setEnabled(enabled);
mHourSpinner.setEnabled(enabled);
mAmPmSpinner.setEnabled(enabled);
mIsEnabled = enabled;
}
/**
*
*
* @return
*/
@Override
public boolean isEnabled() {
return mIsEnabled;
}
/**
*
* Get the current date in millis
*
* @return
* @return the current date in millis
*/
public long getCurrentDateInTimeMillis() {
return mDate.getTimeInMillis();
}
/**
*
*
* Set the current date
*
* @param date The current date in millis
*/
public void setCurrentDate(long date) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(date);
// 通过日历实例的详细字段设置当前日期和时间
setCurrentDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH),
cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE));
}
/**
*
*
* Set the current date
*
* @param year
* @param month
* @param dayOfMonth
* @param hourOfDay
* @param minute
* @param year The current year
* @param month The current month
* @param dayOfMonth The current dayOfMonth
* @param hourOfDay The current hourOfDay
* @param minute The current minute
*/
public void setCurrentDate(int year, int month,
int dayOfMonth, int hourOfDay, int minute) {
// 分别设置年、月、日、时和分
int dayOfMonth, int hourOfDay, int minute) {
setCurrentYear(year);
setCurrentMonth(month);
setCurrentDay(dayOfMonth);
setCurrentHour(hourOfDay);
setCurrentMinute(minute);
}
/**
*
* Get current year
*
* @return
* @return The current year
*/
public int getCurrentYear() {
return mDate.get(Calendar.YEAR);
}
/**
*
* Set current year
*
* @param year
* @param year The current year
*/
public void setCurrentYear(int year) {
// 如果不是初始化状态并且设置的年份与当前年份相同,则直接返回
if (!mInitialising && year == getCurrentYear()) {
return;
}
mDate.set(Calendar.YEAR, year);
updateDateControl(); // 更新日期控件
onDateTimeChanged(); // 触发日期时间改变事件
updateDateControl();
onDateTimeChanged();
}
/**
*
* Get current month in the year
*
* @return 0
* @return The current month in the year
*/
public int getCurrentMonth() {
return mDate.get(Calendar.MONTH);
}
/**
*
* Set current month in the year
*
* @param month 0
* @param month The month in the year
*/
public void setCurrentMonth(int month) {
// 如果不是初始化状态并且设置的月份与当前月份相同,则直接返回
if (!mInitialising && month == getCurrentMonth()) {
return;
}
mDate.set(Calendar.MONTH, month);
updateDateControl(); // 更新日期控件
onDateTimeChanged(); // 触发日期时间改变事件
updateDateControl();
onDateTimeChanged();
}
/**
*
* Get current day of the month
*
* @return
* @return The day of the month
*/
public int getCurrentDay() {
return mDate.get(Calendar.DAY_OF_MONTH);
}
/**
*
* Set current day of the month
*
* @param dayOfMonth
* @param dayOfMonth The day of the month
*/
public void setCurrentDay(int dayOfMonth) {
// 如果不是初始化状态并且设置的日期与当前日期相同,则直接返回
if (!mInitialising && dayOfMonth == getCurrentDay()) {
return;
}
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
updateDateControl(); // 更新日期控件
onDateTimeChanged(); // 触发日期时间改变事件
updateDateControl();
onDateTimeChanged();
}
/**
* 24(0~23)
*
* @return 24
* Get current hour in 24 hour mode, in the range (0~23)
* @return The current hour in 24 hour mode
*/
public int getCurrentHourOfDay() {
return mDate.get(Calendar.HOUR_OF_DAY);
}
/**
* 24
* 24{@link #getCurrentHourOfDay()}
* 12/
*
* @return 12
*/
private int getCurrentHour() {
if (mIs24HourView) {
if (mIs24HourView){
return getCurrentHourOfDay();
} else {
int hour = getCurrentHourOfDay();
// 转换为12小时制
if (hour > HOURS_IN_HALF_DAY) {
return hour - HOURS_IN_HALF_DAY;
} else {
@ -437,20 +360,17 @@ public class DateTimePicker extends FrameLayout {
}
}
}
/**
* 24(0~23)
* Set current hour in 24 hour mode, in the range (0~23)
*
* @param hourOfDay
* @param hourOfDay
*/
public void setCurrentHour(int hourOfDay) {
// 如果在初始化中或者小时未改变,则直接返回
if (!mInitialising && hourOfDay == getCurrentHourOfDay()) {
return;
}
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
// 如果不是24小时视图则调整小时数并更新AM/PM控制
if (!mIs24HourView) {
if (hourOfDay >= HOURS_IN_HALF_DAY) {
mIsAm = false;
@ -468,23 +388,20 @@ public class DateTimePicker extends FrameLayout {
mHourSpinner.setValue(hourOfDay);
onDateTimeChanged();
}
/**
*
* Get currentMinute
*
* @return
* @return The Current Minute
*/
public int getCurrentMinute() {
return mDate.get(Calendar.MINUTE);
}
/**
*
*
* @param minute
* Set current minute
*/
public void setCurrentMinute(int minute) {
// 如果在初始化中或者分钟数未改变,则直接返回
if (!mInitialising && minute == getCurrentMinute()) {
return;
}
@ -492,23 +409,20 @@ public class DateTimePicker extends FrameLayout {
mDate.set(Calendar.MINUTE, minute);
onDateTimeChanged();
}
/**
* 24
*
* @return 24truefalse
* @return true if this is in 24 hour view else false.
*/
public boolean is24HourView() {
public boolean is24HourView () {
return mIs24HourView;
}
/**
* 24AM/PM
* Set whether in 24 hour or AM/PM mode.
*
* @param is24HourView true24falseAM/PM
* @param is24HourView True for 24 hour mode. False for AM/PM mode.
*/
public void set24HourView(boolean is24HourView) {
// 如果视图模式未改变,则直接返回
if (mIs24HourView == is24HourView) {
return;
}
@ -519,16 +433,12 @@ public class DateTimePicker extends FrameLayout {
setCurrentHour(hour);
updateAmPmControl();
}
/**
*
*/
private void updateDateControl() {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -DAYS_IN_ALL_WEEK / 2 - 1);
mDateSpinner.setDisplayedValues(null);
// 循环设置一周内每一天的显示文本
for (int i = 0; i < DAYS_IN_ALL_WEEK; ++i) {
cal.add(Calendar.DAY_OF_YEAR, 1);
mDateDisplayValues[i] = (String) DateFormat.format("MM.dd EEEE", cal);
@ -537,10 +447,7 @@ public class DateTimePicker extends FrameLayout {
mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2);
mDateSpinner.invalidate();
}
/**
* 24AM/PM
*/
private void updateAmPmControl() {
if (mIs24HourView) {
mAmPmSpinner.setVisibility(View.GONE);
@ -550,10 +457,7 @@ public class DateTimePicker extends FrameLayout {
mAmPmSpinner.setVisibility(View.VISIBLE);
}
}
/**
* 24
*/
private void updateHourControl() {
if (mIs24HourView) {
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW);
@ -563,19 +467,15 @@ public class DateTimePicker extends FrameLayout {
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW);
}
}
/**
*
*
* @param callback null
* Set the callback that indicates the 'Set' button has been pressed.
* @param callback the callback, if null will do nothing
*/
public void setOnDateTimeChangedListener(OnDateTimeChangedListener callback) {
mOnDateTimeChangedListener = callback;
}
/**
*
*/
private void onDateTimeChanged() {
if (mOnDateTimeChangedListener != null) {
mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(),

@ -14,124 +14,77 @@
* limitations under the License.
*/
/*
* DateTimePickerDialog
*
*/
package net.micode.notes.ui; // 定义包名
import java.util.Calendar; // 导入Calendar类用于处理日期和时间
import net.micode.notes.R; // 导入资源类,用于访问资源
import net.micode.notes.ui.DateTimePicker; // 导入DateTimePicker类用于日期时间选择器视图
import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener; // 导入日期时间改变监听器接口
import android.app.AlertDialog; // 导入AlertDialog类用于创建对话框
import android.content.Context; // 导入Context类用于获取上下文
import android.content.DialogInterface; // 导入DialogInterface类用于处理对话框事件
import android.content.DialogInterface.OnClickListener; // 导入OnClickListener接口用于处理按钮点击事件
import android.text.format.DateFormat; // 导入DateFormat类用于日期时间格式化
import android.text.format.DateUtils; // 导入DateUtils类用于日期时间格式化
public class DateTimePickerDialog extends AlertDialog implements OnClickListener { // 定义DateTimePickerDialog类继承自AlertDialog并实现OnClickListener接口
// 当前选择的日期和时间
package net.micode.notes.ui;
import java.util.Calendar;
import net.micode.notes.R;
import net.micode.notes.ui.DateTimePicker;
import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
public class DateTimePickerDialog extends AlertDialog implements OnClickListener {
private Calendar mDate = Calendar.getInstance();
// 用于指示日期时间选择器是否使用24小时制
private boolean mIs24HourView;
// 日期时间设置监听器,用于处理日期时间选择后的回调
private OnDateTimeSetListener mOnDateTimeSetListener;
// 日期时间选择器视图
private DateTimePicker mDateTimePicker;
/**
*
* OnDateTimeSet
*/
public interface OnDateTimeSetListener {
void OnDateTimeSet(AlertDialog dialog, long date);
}
/**
*
*
* @param context Activity
* @param date
*/
public DateTimePickerDialog(Context context, long date) {
super(context); // 调用父类构造函数
mDateTimePicker = new DateTimePicker(context); // 创建DateTimePicker实例
setView(mDateTimePicker); // 设置对话框视图为DateTimePicker
// 设置日期时间改变的监听器
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) {
// 更新内部日期时间值
int dayOfMonth, int hourOfDay, int minute) {
mDate.set(Calendar.YEAR, year);
mDate.set(Calendar.MONTH, month);
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()); // 设置DateTimePicker的当前日期时间
// 设置对话框的确认和取消按钮
mDate.setTimeInMillis(date);
mDate.set(Calendar.SECOND, 0);
mDateTimePicker.setCurrentDate(mDate.getTimeInMillis());
setButton(context.getString(R.string.datetime_dialog_ok), this);
setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener) null);
// 根据系统设置决定是否使用24小时制
setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null);
set24HourView(DateFormat.is24HourFormat(this.getContext()));
// 更新标题以显示当前选择的日期和时间
updateTitle(mDate.getTimeInMillis());
}
/**
* 使24
*
* @param is24HourView 使24
*/
public void set24HourView(boolean is24HourView) {
mIs24HourView = is24HourView;
}
/**
*
*
* @param callBack
*/
public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) {
mOnDateTimeSetListener = callBack;
}
/**
*
*
* @param date
*/
private void updateTitle(long date) {
// 根据是否使用24小时制来格式化日期时间显示
int flag =
DateUtils.FORMAT_SHOW_YEAR |
DateUtils.FORMAT_SHOW_DATE |
DateUtils.FORMAT_SHOW_TIME;
DateUtils.FORMAT_SHOW_YEAR |
DateUtils.FORMAT_SHOW_DATE |
DateUtils.FORMAT_SHOW_TIME;
flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR;
setTitle(DateUtils.formatDateTime(this.getContext(), date, flag));
}
/**
*
* OnDateTimeSet
*
* @param arg0
* @param arg1
*/
public void onClick(DialogInterface arg0, int arg1) {
if (mOnDateTimeSetListener != null) {
mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis());
}
}
}

@ -14,76 +14,48 @@
* limitations under the License.
*/
/*
* DropdownMenu
* ButtonPopupMenuButton
*/
package net.micode.notes.ui; // 定义包名
import android.content.Context; // 导入Context类用于获取上下文
import android.view.Menu; // 导入Menu类用于管理菜单项
import android.view.MenuItem; // 导入MenuItem类用于表示菜单项
import android.view.View; // 导入View类用于处理视图
import android.view.View.OnClickListener; // 导入OnClickListener接口用于处理点击事件
import android.widget.Button; // 导入Button类用于创建按钮
import android.widget.PopupMenu; // 导入PopupMenu类用于创建弹出菜单
import android.widget.PopupMenu.OnMenuItemClickListener; // 导入OnMenuItemClickListener接口用于处理菜单项点击事件
import net.micode.notes.R; // 导入资源类,用于访问资源
public class DropdownMenu { // 定义DropdownMenu类
private Button mButton; // 弹出下拉菜单的按钮
private PopupMenu mPopupMenu; // 弹出的下拉菜单
private Menu mMenu; // 下拉菜单的项目集合
/**
* DropdownMenu
*
* @param context Activity
* @param button
* @param menuId ID
*/
package net.micode.notes.ui;
import android.content.Context;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener;
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); // 设置按钮背景为下拉图标
mPopupMenu = new PopupMenu(context, mButton); // 创建PopupMenu实例锚点为按钮
mMenu = mPopupMenu.getMenu(); // 获取菜单项的集合
mPopupMenu.getMenuInflater().inflate(menuId, mMenu); // 加载菜单项
// 设置按钮点击事件,点击后显示下拉菜单
mButton = button;
mButton.setBackgroundResource(R.drawable.dropdown_icon);
mPopupMenu = new PopupMenu(context, mButton);
mMenu = mPopupMenu.getMenu();
mPopupMenu.getMenuInflater().inflate(menuId, mMenu);
mButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mPopupMenu.show(); // 显示下拉菜单
mPopupMenu.show();
}
});
}
/**
*
*
* @param listener PopupMenuOnMenuItemClickListener
*/
public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) {
if (mPopupMenu != null) {
mPopupMenu.setOnMenuItemClickListener(listener); // 设置菜单项点击监听器
mPopupMenu.setOnMenuItemClickListener(listener);
}
}
/**
* ID
*
* @param id ID
* @return MenuItemnull
*/
public MenuItem findItem(int id) {
return mMenu.findItem(id); // 根据ID查找菜单项
return mMenu.findItem(id);
}
/**
*
*
* @param title
*/
public void setTitle(CharSequence title) {
mButton.setText(title); // 设置按钮显示的文本
mButton.setText(title);
}
}

@ -14,111 +14,67 @@
* limitations under the License.
*/
/*
* FoldersListAdapter
* CursorAdapter
*/
package net.micode.notes.ui; // 定义包名
// 导入相关类
import android.content.Context; // 导入Context类用于获取上下文
import android.database.Cursor; // 导入Cursor类用于数据源游标
import android.view.View; // 导入View类用于视图
import android.view.ViewGroup; // 导入ViewGroup类用于视图的父容器
import android.widget.CursorAdapter; // 导入CursorAdapter类用于适配器
import android.widget.LinearLayout; // 导入LinearLayout类用于布局
import android.widget.TextView; // 导入TextView类用于文本显示
import net.micode.notes.R; // 导入资源类,用于访问资源
import net.micode.notes.data.Notes; // 导入Notes类用于数据操作
import net.micode.notes.data.Notes.NoteColumns; // 导入NoteColumns类用于数据列名
public class FoldersListAdapter extends CursorAdapter { // 定义FoldersListAdapter类继承自CursorAdapter
// 查询时使用的列名数组
public static final String[] PROJECTION = {
NoteColumns.ID, // 文件夹ID列
NoteColumns.SNIPPET // 文件夹名称列
package net.micode.notes.ui;
import android.content.Context;
import android.database.Cursor;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
public class FoldersListAdapter extends CursorAdapter {
public static final String [] PROJECTION = {
NoteColumns.ID,
NoteColumns.SNIPPET
};
// 列名数组中的索引常量
public static final int ID_COLUMN = 0; // ID列索引
public static final int NAME_COLUMN = 1; // 名称列索引
/*
*
* @param context ActivityApplication
* @param c Cursor
*/
public static final int ID_COLUMN = 0;
public static final int NAME_COLUMN = 1;
public FoldersListAdapter(Context context, Cursor c) {
super(context, c); // 调用父类构造函数
super(context, c);
// TODO Auto-generated constructor stub
}
/*
* View
* @param context
* @param cursor
* @param parent
* @return View
*/
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new FolderListItem(context); // 返回新的FolderListItem实例
return new FolderListItem(context);
}
/*
* View
* @param view
* @param context
* @param cursor
*/
@Override
public void bindView(View view, Context context, Cursor cursor) {
if (view instanceof FolderListItem) { // 判断视图是否为FolderListItem类型
// 根据文件夹ID判断是根文件夹还是普通文件夹并设置文件夹名称
if (view instanceof FolderListItem) {
String folderName = (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
((FolderListItem) view).bind(folderName); // 绑定文件夹名称到视图
((FolderListItem) view).bind(folderName);
}
}
/*
*
* @param context
* @param position
* @return
*/
public String getFolderName(Context context, int position) {
Cursor cursor = (Cursor) getItem(position); // 获取指定位置的游标
Cursor cursor = (Cursor) getItem(position);
return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN); // 返回文件夹名称
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
}
/*
* FolderListItem
*
*/
private class FolderListItem extends LinearLayout { // 定义FolderListItem内部类继承自LinearLayout
private TextView mName; // 文件夹名称的文本视图
/*
*
* @param context
*/
private class FolderListItem extends LinearLayout {
private TextView mName;
public FolderListItem(Context context) {
super(context); // 调用父类构造函数
// 加载布局文件,并将自己作为根视图
super(context);
inflate(context, R.layout.folder_list_item, this);
mName = (TextView) findViewById(R.id.tv_folder_name); // 获取文件夹名称的视图
mName = (TextView) findViewById(R.id.tv_folder_name);
}
/*
*
* @param name
*/
public void bind(String name) {
mName.setText(name); // 设置文件夹名称
mName.setText(name);
}
}
}

File diff suppressed because it is too large Load Diff

@ -14,24 +14,8 @@
* limitations under the License.
*/
/*
* 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.Context;
import android.graphics.Rect;
import android.text.Layout;
@ -47,143 +31,105 @@ import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.MotionEvent;
import android.widget.EditText;
import net.micode.notes.R;
import java.util.HashMap;
import java.util.Map;
/**
*
*/
public class NoteEditText extends EditText {
private static final String TAG = "NoteEditText";
private int mIndex; // 当前文本视图的索引
private int mSelectionStartBeforeDelete; // 删除操作前的选择起始位置
private static final String SCHEME_TEL = "tel:";
private static final String SCHEME_HTTP = "http:";
private static final String SCHEME_EMAIL = "mailto:";
// URL方案与对应操作资源ID的映射
private int mIndex;
private int mSelectionStartBeforeDelete;
private static final String SCHEME_TEL = "tel:" ;
private static final String SCHEME_HTTP = "http:" ;
private static final String SCHEME_EMAIL = "mailto:" ;
private static final Map<String, Integer> sSchemaActionResMap = new HashMap<String, Integer>();
static {
sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel);
sSchemaActionResMap.put(SCHEME_HTTP, R.string.note_link_web);
sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email);
}
/**
*
* Call by the {@link NoteEditActivity} to delete or add edit text
*/
public interface OnTextViewChangeListener {
/**
*
* Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens
* and the text is null
*/
void onEditTextDelete(int index, String text);
/**
*
* Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER}
* happen
*/
void onEditTextEnter(int index, String text);
/**
*
* Hide or show item option when text change
*/
void onTextChange(int index, boolean hasText);
}
private OnTextViewChangeListener mOnTextViewChangeListener;
/**
*
*
* @param context
*/
public NoteEditText(Context context) {
super(context, null);
mIndex = 0;
}
/**
*
*
* @param index
*/
public void setIndex(int index) {
mIndex = index;
}
/**
*
*
* @param listener
*/
public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
mOnTextViewChangeListener = listener;
}
/**
*
*
* @param context
* @param attrs
*/
public NoteEditText(Context context, AttributeSet attrs) {
super(context, attrs, android.R.attr.editTextStyle);
}
/**
*
*
* @param context
* @param attrs
* @param defStyle
*/
public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
/**
*
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 计算触摸位置相对于文本的偏移量,并调整光标位置
int x = (int) event.getX();
int y = (int) event.getY();
x -= getTotalPaddingLeft();
y -= getTotalPaddingTop();
x += getScrollX();
y += getScrollY();
Layout layout = getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
Selection.setSelection(getText(), off);
break;
}
return super.onTouchEvent(event);
}
/**
*
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
// 处理回车键事件,准备新增文本视图
if (mOnTextViewChangeListener != null) {
return false;
}
break;
case KeyEvent.KEYCODE_DEL:
// 记录删除操作前的选择位置
mSelectionStartBeforeDelete = getSelectionStart();
break;
default:
@ -191,15 +137,11 @@ public class NoteEditText extends EditText {
}
return super.onKeyDown(keyCode, event);
}
/**
*
*/
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
switch(keyCode) {
case KeyEvent.KEYCODE_DEL:
// 处理删除键事件,若为首个文本且非空,则删除当前文本
if (mOnTextViewChangeListener != null) {
if (0 == mSelectionStartBeforeDelete && mIndex != 0) {
mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString());
@ -210,7 +152,6 @@ public class NoteEditText extends EditText {
}
break;
case KeyEvent.KEYCODE_ENTER:
// 处理回车键事件,新增文本视图
if (mOnTextViewChangeListener != null) {
int selectionStart = getSelectionStart();
String text = getText().subSequence(selectionStart, length()).toString();
@ -225,10 +166,7 @@ public class NoteEditText extends EditText {
}
return super.onKeyUp(keyCode, event);
}
/**
*
*/
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
if (mOnTextViewChangeListener != null) {
@ -240,37 +178,34 @@ public class NoteEditText extends EditText {
}
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
/**
* URL
*/
@Override
protected void onCreateContextMenu(ContextMenu menu) {
if (getText() instanceof Spanned) {
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
int min = Math.min(selStart, selEnd);
int max = Math.max(selStart, selEnd);
final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class);
if (urls.length == 1) {
int defaultResId = 0;
for (String schema : sSchemaActionResMap.keySet()) {
if (urls[0].getURL().indexOf(schema) >= 0) {
for(String schema: sSchemaActionResMap.keySet()) {
if(urls[0].getURL().indexOf(schema) >= 0) {
defaultResId = sSchemaActionResMap.get(schema);
break;
}
}
if (defaultResId == 0) {
defaultResId = R.string.note_link_other;
}
menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener(
new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
// 跳转到URL指向的页面
// goto a new intent
urls[0].onClick(NoteEditText.this);
return true;
}
@ -280,4 +215,3 @@ public class NoteEditText extends EditText {
super.onCreateContextMenu(menu);
}
}

@ -14,242 +14,211 @@
* limitations under the License.
*/
package net.micode.notes.ui; // 定义包名
import android.content.Context; // 导入Context类用于获取上下文
import android.database.Cursor; // 导入Cursor类用于数据源游标
import android.text.TextUtils; // 导入TextUtils类用于字符串操作
import net.micode.notes.data.Contact; // 导入Contact类用于联系人数据操作
import net.micode.notes.data.Notes; // 导入Notes类用于笔记数据操作
import net.micode.notes.data.Notes.NoteColumns; // 导入NoteColumns类用于笔记数据列名
import net.micode.notes.tool.DataUtils; // 导入DataUtils类用于数据工具操作
/**
*
*/
public class NoteItemData { // 定义NoteItemData类
// 定义查询时要投影的列
static final String[] PROJECTION = new String[]{
NoteColumns.ID, // 笔记ID
NoteColumns.ALERTED_DATE, // 提醒日期
NoteColumns.BG_COLOR_ID, // 背景颜色ID
NoteColumns.CREATED_DATE, // 创建日期
NoteColumns.HAS_ATTACHMENT, // 是否有附件
NoteColumns.MODIFIED_DATE, // 修改日期
NoteColumns.NOTES_COUNT, // 笔记数量
NoteColumns.PARENT_ID, // 父ID
NoteColumns.SNIPPET, // 摘要
NoteColumns.TYPE, // 类型
NoteColumns.WIDGET_ID, // 小部件ID
NoteColumns.WIDGET_TYPE, // 小部件类型
package net.micode.notes.ui;
import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils;
import net.micode.notes.data.Contact;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.tool.DataUtils;
public class NoteItemData {
static final String [] PROJECTION = new String [] {
NoteColumns.ID,
NoteColumns.ALERTED_DATE,
NoteColumns.BG_COLOR_ID,
NoteColumns.CREATED_DATE,
NoteColumns.HAS_ATTACHMENT,
NoteColumns.MODIFIED_DATE,
NoteColumns.NOTES_COUNT,
NoteColumns.PARENT_ID,
NoteColumns.SNIPPET,
NoteColumns.TYPE,
NoteColumns.WIDGET_ID,
NoteColumns.WIDGET_TYPE,
};
// 各列数据的索引
private static final int ID_COLUMN = 0; // ID列索引
private static final int ALERTED_DATE_COLUMN = 1; // 提醒日期列索引
private static final int BG_COLOR_ID_COLUMN = 2; // 背景颜色ID列索引
private static final int CREATED_DATE_COLUMN = 3; // 创建日期列索引
private static final int HAS_ATTACHMENT_COLUMN = 4; // 是否有附件列索引
private static final int MODIFIED_DATE_COLUMN = 5; // 修改日期列索引
private static final int NOTES_COUNT_COLUMN = 6; // 笔记数量列索引
private static final int PARENT_ID_COLUMN = 7; // 父ID列索引
private static final int SNIPPET_COLUMN = 8; // 摘要列索引
private static final int TYPE_COLUMN = 9; // 类型列索引
private static final int WIDGET_ID_COLUMN = 10; // 小部件ID列索引
private static final int WIDGET_TYPE_COLUMN = 11; // 小部件类型列索引
// 笔记的各项数据
private long mId; // 笔记ID
private long mAlertDate; // 提醒日期
private int mBgColorId; // 背景颜色ID
private long mCreatedDate; // 创建日期
private boolean mHasAttachment; // 是否有附件
private long mModifiedDate; // 修改日期
private int mNotesCount; // 笔记数量
private long mParentId; // 父ID
private String mSnippet; // 摘要
private int mType; // 类型
private int mWidgetId; // 小部件ID
private int mWidgetType; // 小部件类型
private String mName; // 联系人名称
private String mPhoneNumber; // 电话号码
// 用于标识笔记在列表中的位置状态
private boolean mIsLastItem; // 是否为最后一个项目
private boolean mIsFirstItem; // 是否为第一个项目
private boolean mIsOnlyOneItem; // 是否为唯一一个项目
private boolean mIsOneNoteFollowingFolder; // 是否为一个笔记跟随文件夹
private boolean mIsMultiNotesFollowingFolder; // 是否为多个笔记跟随文件夹
/**
* CursorNoteItemData
*
* @param context 访
* @param cursor Cursor
*/
private static final int ID_COLUMN = 0;
private static final int ALERTED_DATE_COLUMN = 1;
private static final int BG_COLOR_ID_COLUMN = 2;
private static final int CREATED_DATE_COLUMN = 3;
private static final int HAS_ATTACHMENT_COLUMN = 4;
private static final int MODIFIED_DATE_COLUMN = 5;
private static final int NOTES_COUNT_COLUMN = 6;
private static final int PARENT_ID_COLUMN = 7;
private static final int SNIPPET_COLUMN = 8;
private static final int TYPE_COLUMN = 9;
private static final int WIDGET_ID_COLUMN = 10;
private static final int WIDGET_TYPE_COLUMN = 11;
private long mId;
private long mAlertDate;
private int mBgColorId;
private long mCreatedDate;
private boolean mHasAttachment;
private long mModifiedDate;
private int mNotesCount;
private long mParentId;
private String mSnippet;
private int mType;
private int mWidgetId;
private int mWidgetType;
private String mName;
private String mPhoneNumber;
private boolean mIsLastItem;
private boolean mIsFirstItem;
private boolean mIsOnlyOneItem;
private boolean mIsOneNoteFollowingFolder;
private boolean mIsMultiNotesFollowingFolder;
public NoteItemData(Context context, Cursor cursor) {
// 从Cursor中提取各项数据并赋值
mId = cursor.getLong(ID_COLUMN); // 获取笔记ID
mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN); // 获取提醒日期
mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN); // 获取背景颜色ID
mCreatedDate = cursor.getLong(CREATED_DATE_COLUMN); // 获取创建日期
mHasAttachment = (cursor.getInt(HAS_ATTACHMENT_COLUMN) > 0) ? true : false; // 获取是否有附件
mModifiedDate = cursor.getLong(MODIFIED_DATE_COLUMN); // 获取修改日期
mNotesCount = cursor.getInt(NOTES_COUNT_COLUMN); // 获取笔记数量
mParentId = cursor.getLong(PARENT_ID_COLUMN); // 获取父ID
mSnippet = cursor.getString(SNIPPET_COLUMN); // 获取摘要
mId = cursor.getLong(ID_COLUMN);
mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN);
mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN);
mCreatedDate = cursor.getLong(CREATED_DATE_COLUMN);
mHasAttachment = (cursor.getInt(HAS_ATTACHMENT_COLUMN) > 0) ? true : false;
mModifiedDate = cursor.getLong(MODIFIED_DATE_COLUMN);
mNotesCount = cursor.getInt(NOTES_COUNT_COLUMN);
mParentId = cursor.getLong(PARENT_ID_COLUMN);
mSnippet = cursor.getString(SNIPPET_COLUMN);
mSnippet = mSnippet.replace(NoteEditActivity.TAG_CHECKED, "").replace(
NoteEditActivity.TAG_UNCHECKED, ""); // 清理摘要中的特殊标记
mType = cursor.getInt(TYPE_COLUMN); // 获取类型
mWidgetId = cursor.getInt(WIDGET_ID_COLUMN); // 获取小部件ID
mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN); // 获取小部件类型
// 如果是通话记录笔记,尝试获取通话号码和联系人名称
mPhoneNumber = ""; // 初始化电话号码
if (mParentId == Notes.ID_CALL_RECORD_FOLDER) { // 判断是否为通话记录笔记
mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId); // 获取电话号码
if (!TextUtils.isEmpty(mPhoneNumber)) { // 判断电话号码是否为空
mName = Contact.getContact(context, mPhoneNumber); // 获取联系人名称
if (mName == null) { // 判断联系人名称是否为空
mName = mPhoneNumber; // 如果为空,则使用电话号码作为名称
NoteEditActivity.TAG_UNCHECKED, "");
mType = cursor.getInt(TYPE_COLUMN);
mWidgetId = cursor.getInt(WIDGET_ID_COLUMN);
mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN);
mPhoneNumber = "";
if (mParentId == Notes.ID_CALL_RECORD_FOLDER) {
mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId);
if (!TextUtils.isEmpty(mPhoneNumber)) {
mName = Contact.getContact(context, mPhoneNumber);
if (mName == null) {
mName = mPhoneNumber;
}
}
}
// 如果没有获取到联系人名称,则默认为空字符串
if (mName == null) { // 判断联系人名称是否为空
mName = ""; // 如果为空,则默认为空字符串
if (mName == null) {
mName = "";
}
checkPostion(cursor); // 检查笔记在列表中的位置
}
/**
* CursorNoteItemData
*
* @param cursor Cursor
*/
checkPostion(cursor);
}
private void checkPostion(Cursor cursor) {
// 更新位置状态信息
mIsLastItem = cursor.isLast(); // 判断是否为最后一个项目
mIsFirstItem = cursor.isFirst(); // 判断是否为第一个项目
mIsOnlyOneItem = (cursor.getCount() == 1); // 判断是否为唯一一个项目
mIsMultiNotesFollowingFolder = false; // 初始化多个笔记跟随文件夹状态
mIsOneNoteFollowingFolder = false; // 初始化一个笔记跟随文件夹状态
// 检查当前笔记是否跟随文件夹,并更新相应状态
if (mType == Notes.TYPE_NOTE && !mIsFirstItem) { // 判断是否为笔记且不是第一个项目
int position = cursor.getPosition(); // 获取当前位置
if (cursor.moveToPrevious()) { // 移动到前一个位置
mIsLastItem = cursor.isLast() ? true : false;
mIsFirstItem = cursor.isFirst() ? true : false;
mIsOnlyOneItem = (cursor.getCount() == 1);
mIsMultiNotesFollowingFolder = false;
mIsOneNoteFollowingFolder = false;
if (mType == Notes.TYPE_NOTE && !mIsFirstItem) {
int position = cursor.getPosition();
if (cursor.moveToPrevious()) {
if (cursor.getInt(TYPE_COLUMN) == Notes.TYPE_FOLDER
|| cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) { // 判断前一个项目是否为文件夹或系统类型
if (cursor.getCount() > (position + 1)) { // 判断是否有多于一个项目
mIsMultiNotesFollowingFolder = true; // 设置多个笔记跟随文件夹状态
|| cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) {
if (cursor.getCount() > (position + 1)) {
mIsMultiNotesFollowingFolder = true;
} else {
mIsOneNoteFollowingFolder = true; // 设置一个笔记跟随文件夹状态
mIsOneNoteFollowingFolder = true;
}
}
// 确保Cursor能够回到原来的位置
if (!cursor.moveToNext()) { // 移动回原来的位置
throw new IllegalStateException("cursor move to previous but can't move back"); // 抛出异常
if (!cursor.moveToNext()) {
throw new IllegalStateException("cursor move to previous but can't move back");
}
}
}
}
// 以下为获取NoteItemData各项属性的方法
public boolean isOneFollowingFolder() {
return mIsOneNoteFollowingFolder; // 返回一个笔记跟随文件夹状态
return mIsOneNoteFollowingFolder;
}
public boolean isMultiFollowingFolder() {
return mIsMultiNotesFollowingFolder; // 返回多个笔记跟随文件夹状态
return mIsMultiNotesFollowingFolder;
}
public boolean isLast() {
return mIsLastItem; // 返回是否为最后一个项目
return mIsLastItem;
}
public String getCallName() {
return mName; // 返回联系人名称
return mName;
}
public boolean isFirst() {
return mIsFirstItem; // 返回是否为第一个项目
return mIsFirstItem;
}
public boolean isSingle() {
return mIsOnlyOneItem; // 返回是否为唯一一个项目
return mIsOnlyOneItem;
}
public long getId() {
return mId; // 返回笔记ID
return mId;
}
public long getAlertDate() {
return mAlertDate; // 返回提醒日期
return mAlertDate;
}
public long getCreatedDate() {
return mCreatedDate; // 返回创建日期
return mCreatedDate;
}
public boolean hasAttachment() {
return mHasAttachment; // 返回是否有附件
return mHasAttachment;
}
public long getModifiedDate() {
return mModifiedDate; // 返回修改日期
return mModifiedDate;
}
public int getBgColorId() {
return mBgColorId; // 返回背景颜色ID
return mBgColorId;
}
public long getParentId() {
return mParentId; // 返回父ID
return mParentId;
}
public int getNotesCount() {
return mNotesCount; // 返回笔记数量
return mNotesCount;
}
public long getFolderId() {
return mParentId; // 返回文件夹ID
public long getFolderId () {
return mParentId;
}
public int getType() {
return mType; // 返回类型
return mType;
}
public int getWidgetType() {
return mWidgetType; // 返回小部件类型
return mWidgetType;
}
public int getWidgetId() {
return mWidgetId; // 返回小部件ID
return mWidgetId;
}
public String getSnippet() {
return mSnippet; // 返回摘要
return mSnippet;
}
public boolean hasAlert() {
return (mAlertDate > 0); // 返回是否有提醒
return (mAlertDate > 0);
}
public boolean isCallRecord() {
return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber)); // 返回是否为通话记录笔记
}
/**
* Cursor
*
* @param cursor Cursor
* @return
*/
return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber));
}
public static int getNoteType(Cursor cursor) {
return cursor.getInt(TYPE_COLUMN); // 返回笔记类型
return cursor.getInt(TYPE_COLUMN);
}
}

File diff suppressed because it is too large Load Diff

@ -14,253 +14,170 @@
* limitations under the License.
*/
package net.micode.notes.ui; // 定义包名
import android.content.Context; // 导入Context类用于获取上下文
import android.database.Cursor; // 导入Cursor类用于数据源游标
import android.util.Log; // 导入Log类用于日志输出
import android.view.View; // 导入View类用于视图操作
import android.view.ViewGroup; // 导入ViewGroup类用于视图组操作
import android.widget.CursorAdapter; // 导入CursorAdapter类用于游标适配器
import net.micode.notes.data.Notes; // 导入Notes类用于笔记数据操作
import java.util.Collection; // 导入Collection类用于集合操作
import java.util.HashMap; // 导入HashMap类用于哈希映射
import java.util.HashSet; // 导入HashSet类用于哈希集合
import java.util.Iterator; // 导入Iterator类用于迭代器
/**
* CursorAdapter
*/
public class NotesListAdapter extends CursorAdapter { // 定义NotesListAdapter类继承自CursorAdapter
private static final String TAG = "NotesListAdapter"; // 定义日志标签
private Context mContext; // 上下文对象
// 用于存储选中项的索引和状态
private HashMap<Integer, Boolean> mSelectedIndex; // 选中项索引和状态的哈希映射
private int mNotesCount; // 笔记总数
private boolean mChoiceMode; // 选择模式标志
/**
* AppWidget
*/
public static class AppWidgetAttribute { // 定义AppWidgetAttribute类
public int widgetId; // 小部件ID
public int widgetType; // 小部件类型
}
/**
*
*
* @param context
*/
public NotesListAdapter(Context context) { // 构造函数
super(context, null); // 调用父类构造函数
mSelectedIndex = new HashMap<Integer, Boolean>(); // 初始化选中项索引和状态的哈希映射
mContext = context; // 赋值上下文对象
mNotesCount = 0; // 初始化笔记总数
package net.micode.notes.ui;
import android.content.Context;
import android.database.Cursor;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import net.micode.notes.data.Notes;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
public class NotesListAdapter extends CursorAdapter {
private static final String TAG = "NotesListAdapter";
private Context mContext;
private HashMap<Integer, Boolean> mSelectedIndex;
private int mNotesCount;
private boolean mChoiceMode;
public static class AppWidgetAttribute {
public int widgetId;
public int widgetType;
};
public NotesListAdapter(Context context) {
super(context, null);
mSelectedIndex = new HashMap<Integer, Boolean>();
mContext = context;
mNotesCount = 0;
}
/**
*
*
* @param context
* @param cursor
* @param parent
* @return
*/
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) { // 重写newView方法
return new NotesListItem(context); // 返回新的列表项视图
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new NotesListItem(context);
}
/**
*
*
* @param view
* @param context
* @param cursor
*/
@Override
public void bindView(View view, Context context, Cursor cursor) { // 重写bindView方法
if (view instanceof NotesListItem) { // 判断视图是否为NotesListItem类型
NoteItemData itemData = new NoteItemData(context, cursor); // 创建NoteItemData对象
public void bindView(View view, Context context, Cursor cursor) {
if (view instanceof NotesListItem) {
NoteItemData itemData = new NoteItemData(context, cursor);
((NotesListItem) view).bind(context, itemData, mChoiceMode,
isSelectedItem(cursor.getPosition())); // 绑定数据到视图
isSelectedItem(cursor.getPosition()));
}
}
/**
*
*
* @param position
* @param checked
*/
public void setCheckedItem(final int position, final boolean checked) { // 设置选中项方法
mSelectedIndex.put(position, checked); // 更新选中项索引和状态
notifyDataSetChanged(); // 通知数据集改变
public void setCheckedItem(final int position, final boolean checked) {
mSelectedIndex.put(position, checked);
notifyDataSetChanged();
}
/**
*
*
* @return
*/
public boolean isInChoiceMode() { // 获取选择模式方法
return mChoiceMode; // 返回选择模式状态
public boolean isInChoiceMode() {
return mChoiceMode;
}
/**
*
*
* @param mode
*/
public void setChoiceMode(boolean mode) { // 设置选择模式方法
mSelectedIndex.clear(); // 清空选中项索引和状态
mChoiceMode = mode; // 更新选择模式状态
public void setChoiceMode(boolean mode) {
mSelectedIndex.clear();
mChoiceMode = mode;
}
/**
*
*
* @param checked
*/
public void selectAll(boolean checked) { // 全选或全不选方法
Cursor cursor = getCursor(); // 获取游标
for (int i = 0; i < getCount(); i++) { // 遍历所有项
if (cursor.moveToPosition(i)) { // 移动到指定位置
if (NoteItemData.getNoteType(cursor) == Notes.TYPE_NOTE) { // 判断是否为笔记类型
setCheckedItem(i, checked); // 设置选中状态
public void selectAll(boolean checked) {
Cursor cursor = getCursor();
for (int i = 0; i < getCount(); i++) {
if (cursor.moveToPosition(i)) {
if (NoteItemData.getNoteType(cursor) == Notes.TYPE_NOTE) {
setCheckedItem(i, checked);
}
}
}
}
/**
* ID
*
* @return IDHashSet
*/
public HashSet<Long> getSelectedItemIds() { // 获取选中项ID集合方法
HashSet<Long> itemSet = new HashSet<Long>(); // 创建哈希集合
for (Integer position : mSelectedIndex.keySet()) { // 遍历选中项索引
if (mSelectedIndex.get(position) == true) { // 判断是否为选中状态
Long id = getItemId(position); // 获取项ID
if (id == Notes.ID_ROOT_FOLDER) { // 判断是否为根文件夹
Log.d(TAG, "Wrong item id, should not happen"); // 输出日志
public HashSet<Long> getSelectedItemIds() {
HashSet<Long> itemSet = new HashSet<Long>();
for (Integer position : mSelectedIndex.keySet()) {
if (mSelectedIndex.get(position) == true) {
Long id = getItemId(position);
if (id == Notes.ID_ROOT_FOLDER) {
Log.d(TAG, "Wrong item id, should not happen");
} else {
itemSet.add(id); // 添加到哈希集合
itemSet.add(id);
}
}
}
return itemSet; // 返回哈希集合
return itemSet;
}
/**
*
*
* @return HashSet
*/
public HashSet<AppWidgetAttribute> getSelectedWidget() { // 获取选中小部件属性集合方法
HashSet<AppWidgetAttribute> itemSet = new HashSet<AppWidgetAttribute>(); // 创建哈希集合
for (Integer position : mSelectedIndex.keySet()) { // 遍历选中项索引
if (mSelectedIndex.get(position) == true) { // 判断是否为选中状态
Cursor c = (Cursor) getItem(position); // 获取游标
if (c != null) { // 判断游标是否为空
AppWidgetAttribute widget = new AppWidgetAttribute(); // 创建AppWidgetAttribute对象
NoteItemData item = new NoteItemData(mContext, c); // 创建NoteItemData对象
widget.widgetId = item.getWidgetId(); // 获取小部件ID
widget.widgetType = item.getWidgetType(); // 获取小部件类型
itemSet.add(widget); // 添加到哈希集合
public HashSet<AppWidgetAttribute> getSelectedWidget() {
HashSet<AppWidgetAttribute> itemSet = new HashSet<AppWidgetAttribute>();
for (Integer position : mSelectedIndex.keySet()) {
if (mSelectedIndex.get(position) == true) {
Cursor c = (Cursor) getItem(position);
if (c != null) {
AppWidgetAttribute widget = new AppWidgetAttribute();
NoteItemData item = new NoteItemData(mContext, c);
widget.widgetId = item.getWidgetId();
widget.widgetType = item.getWidgetType();
itemSet.add(widget);
/**
* Don't close cursor here, only the adapter could close it
*/
} else {
Log.e(TAG, "Invalid cursor"); // 输出日志
return null; // 返回空
Log.e(TAG, "Invalid cursor");
return null;
}
}
}
return itemSet; // 返回哈希集合
return itemSet;
}
/**
*
*
* @return
*/
public int getSelectedCount() { // 获取选中项数量方法
Collection<Boolean> values = mSelectedIndex.values(); // 获取选中项状态集合
if (null == values) { // 判断集合是否为空
return 0; // 返回0
public int getSelectedCount() {
Collection<Boolean> values = mSelectedIndex.values();
if (null == values) {
return 0;
}
Iterator<Boolean> iter = values.iterator(); // 获取迭代器
int count = 0; // 初始化计数器
while (iter.hasNext()) { // 遍历集合
if (true == iter.next()) { // 判断是否为选中状态
count++; // 计数器加1
Iterator<Boolean> iter = values.iterator();
int count = 0;
while (iter.hasNext()) {
if (true == iter.next()) {
count++;
}
}
return count; // 返回计数器
return count;
}
/**
*
*
* @return
*/
public boolean isAllSelected() { // 判断是否全部选中方法
int checkedCount = getSelectedCount(); // 获取选中项数量
return (checkedCount != 0 && checkedCount == mNotesCount); // 判断是否全部选中
public boolean isAllSelected() {
int checkedCount = getSelectedCount();
return (checkedCount != 0 && checkedCount == mNotesCount);
}
/**
*
*
* @param position
* @return
*/
public boolean isSelectedItem(final int position) { // 检查选中项方法
if (null == mSelectedIndex.get(position)) { // 判断是否为空
return false; // 返回未选中状态
public boolean isSelectedItem(final int position) {
if (null == mSelectedIndex.get(position)) {
return false;
}
return mSelectedIndex.get(position); // 返回选中状态
return mSelectedIndex.get(position);
}
/**
*
*/
@Override
protected void onContentChanged() { // 重写onContentChanged方法
super.onContentChanged(); // 调用父类方法
calcNotesCount(); // 计算笔记数量
protected void onContentChanged() {
super.onContentChanged();
calcNotesCount();
}
/**
*
*
* @param cursor
*/
@Override
public void changeCursor(Cursor cursor) { // 重写changeCursor方法
super.changeCursor(cursor); // 调用父类方法
calcNotesCount(); // 计算笔记数量
public void changeCursor(Cursor cursor) {
super.changeCursor(cursor);
calcNotesCount();
}
/**
*
*/
private void calcNotesCount() { // 计算笔记数量方法
mNotesCount = 0; // 初始化笔记总数
for (int i = 0; i < getCount(); i++) { // 遍历所有项
Cursor c = (Cursor) getItem(i); // 获取游标
if (c != null) { // 判断游标是否为空
if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) { // 判断是否为笔记类型
mNotesCount++; // 笔记总数加1
private void calcNotesCount() {
mNotesCount = 0;
for (int i = 0; i < getCount(); i++) {
Cursor c = (Cursor) getItem(i);
if (c != null) {
if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) {
mNotesCount++;
}
} else {
Log.e(TAG, "Invalid cursor"); // 输出日志
return; // 返回
Log.e(TAG, "Invalid cursor");
return;
}
}
}

@ -14,143 +14,109 @@
* limitations under the License.
*/
package net.micode.notes.ui; // 定义包名
import android.content.Context; // 导入Context类用于获取上下文
import android.text.format.DateUtils; // 导入DateUtils类用于日期格式化
import android.view.View; // 导入View类用于视图操作
import android.widget.CheckBox; // 导入CheckBox类用于复选框
import android.widget.ImageView; // 导入ImageView类用于图像显示
import android.widget.LinearLayout; // 导入LinearLayout类用于线性布局
import android.widget.TextView; // 导入TextView类用于文本显示
import net.micode.notes.R; // 导入R类用于资源引用
import net.micode.notes.data.Notes; // 导入Notes类用于笔记数据操作
import net.micode.notes.tool.DataUtils; // 导入DataUtils类用于数据处理
import net.micode.notes.tool.ResourceParser.NoteItemBgResources; // 导入NoteItemBgResources类用于背景资源解析
/*
* LinearLayout
* UI
*/
public class NotesListItem extends LinearLayout { // 定义NotesListItem类继承自LinearLayout
private ImageView mAlert; // 用于显示提醒图标
private TextView mTitle; // 显示笔记标题
private TextView mTime; // 显示修改时间
private TextView mCallName; // 在通话记录笔记中显示通话名称
private NoteItemData mItemData; // 绑定的笔记数据
private CheckBox mCheckBox; // 选择框,用于多选模式
/*
*
*/
public NotesListItem(Context context) { // 构造函数
super(context); // 调用父类构造函数
inflate(context, R.layout.note_item, this); // 填充布局
// 初始化视图组件
mAlert = (ImageView) findViewById(R.id.iv_alert_icon); // 初始化提醒图标
mTitle = (TextView) findViewById(R.id.tv_title); // 初始化标题
mTime = (TextView) findViewById(R.id.tv_time); // 初始化时间
mCallName = (TextView) findViewById(R.id.tv_name); // 初始化通话名称
mCheckBox = (CheckBox) findViewById(android.R.id.checkbox); // 初始化复选框
package net.micode.notes.ui;
import android.content.Context;
import android.text.format.DateUtils;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.tool.DataUtils;
import net.micode.notes.tool.ResourceParser.NoteItemBgResources;
public class NotesListItem extends LinearLayout {
private ImageView mAlert;
private TextView mTitle;
private TextView mTime;
private TextView mCallName;
private NoteItemData mItemData;
private CheckBox mCheckBox;
public NotesListItem(Context context) {
super(context);
inflate(context, R.layout.note_item, this);
mAlert = (ImageView) findViewById(R.id.iv_alert_icon);
mTitle = (TextView) findViewById(R.id.tv_title);
mTime = (TextView) findViewById(R.id.tv_time);
mCallName = (TextView) findViewById(R.id.tv_name);
mCheckBox = (CheckBox) findViewById(android.R.id.checkbox);
}
/*
*
*
* @param context
* @param data
* @param choiceMode
* @param checked
*/
public void bind(Context context, NoteItemData data, boolean choiceMode, boolean checked) { // 绑定数据方法
// 根据是否为选择模式和笔记类型,控制复选框的可见性和选中状态
if (choiceMode && data.getType() == Notes.TYPE_NOTE) { // 判断是否为选择模式且为笔记类型
mCheckBox.setVisibility(View.VISIBLE); // 显示复选框
mCheckBox.setChecked(checked); // 设置复选框选中状态
public void bind(Context context, NoteItemData data, boolean choiceMode, boolean checked) {
if (choiceMode && data.getType() == Notes.TYPE_NOTE) {
mCheckBox.setVisibility(View.VISIBLE);
mCheckBox.setChecked(checked);
} else {
mCheckBox.setVisibility(View.GONE); // 隐藏复选框
mCheckBox.setVisibility(View.GONE);
}
mItemData = data; // 赋值笔记数据
// 根据笔记类型和状态,设置标题、提醒图标和背景
if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { // 判断是否为通话记录文件夹
// 通话记录文件夹
mCallName.setVisibility(View.GONE); // 隐藏通话名称
mAlert.setVisibility(View.VISIBLE); // 显示提醒图标
mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); // 设置标题样式
mItemData = data;
if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
mCallName.setVisibility(View.GONE);
mAlert.setVisibility(View.VISIBLE);
mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem);
mTitle.setText(context.getString(R.string.call_record_folder_name)
+ context.getString(R.string.format_folder_files_count, data.getNotesCount())); // 设置标题文本
mAlert.setImageResource(R.drawable.call_record); // 设置提醒图标
} else if (data.getParentId() == Notes.ID_CALL_RECORD_FOLDER) { // 判断是否为通话记录笔记
// 通话记录笔记
mCallName.setVisibility(View.VISIBLE); // 显示通话名称
mCallName.setText(data.getCallName()); // 设置通话名称
mTitle.setTextAppearance(context, R.style.TextAppearanceSecondaryItem); // 设置标题样式
mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); // 设置标题文本
if (data.hasAlert()) { // 判断是否有提醒
mAlert.setImageResource(R.drawable.clock); // 设置提醒图标
mAlert.setVisibility(View.VISIBLE); // 显示提醒图标
+ context.getString(R.string.format_folder_files_count, data.getNotesCount()));
mAlert.setImageResource(R.drawable.call_record);
} else if (data.getParentId() == Notes.ID_CALL_RECORD_FOLDER) {
mCallName.setVisibility(View.VISIBLE);
mCallName.setText(data.getCallName());
mTitle.setTextAppearance(context,R.style.TextAppearanceSecondaryItem);
mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet()));
if (data.hasAlert()) {
mAlert.setImageResource(R.drawable.clock);
mAlert.setVisibility(View.VISIBLE);
} else {
mAlert.setVisibility(View.GONE); // 隐藏提醒图标
mAlert.setVisibility(View.GONE);
}
} else {
// 其他类型的笔记或文件夹
mCallName.setVisibility(View.GONE); // 隐藏通话名称
mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); // 设置标题样式
if (data.getType() == Notes.TYPE_FOLDER) { // 判断是否为文件夹
mCallName.setVisibility(View.GONE);
mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem);
if (data.getType() == Notes.TYPE_FOLDER) {
mTitle.setText(data.getSnippet()
+ context.getString(R.string.format_folder_files_count,
data.getNotesCount())); // 设置标题文本
mAlert.setVisibility(View.GONE); // 隐藏提醒图标
data.getNotesCount()));
mAlert.setVisibility(View.GONE);
} else {
mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); // 设置标题文本
if (data.hasAlert()) { // 判断是否有提醒
mAlert.setImageResource(R.drawable.clock); // 设置提醒图标
mAlert.setVisibility(View.VISIBLE); // 显示提醒图标
mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet()));
if (data.hasAlert()) {
mAlert.setImageResource(R.drawable.clock);
mAlert.setVisibility(View.VISIBLE);
} else {
mAlert.setVisibility(View.GONE); // 隐藏提醒图标
mAlert.setVisibility(View.GONE);
}
}
}
// 设置时间显示
mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate())); // 设置时间文本
// 设置背景资源
setBackground(data); // 设置背景
mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate()));
setBackground(data);
}
/*
*
*/
private void setBackground(NoteItemData data) { // 设置背景方法
int id = data.getBgColorId(); // 获取背景颜色ID
if (data.getType() == Notes.TYPE_NOTE) { // 判断是否为笔记类型
// 根据笔记的状态设置不同的背景资源
if (data.isSingle() || data.isOneFollowingFolder()) { // 判断是否为单个笔记或紧跟文件夹的笔记
setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id)); // 设置单个笔记背景
} else if (data.isLast()) { // 判断是否为最后一个笔记
setBackgroundResource(NoteItemBgResources.getNoteBgLastRes(id)); // 设置最后一个笔记背景
} else if (data.isFirst() || data.isMultiFollowingFolder()) { // 判断是否为第一个笔记或多个紧跟文件夹的笔记
setBackgroundResource(NoteItemBgResources.getNoteBgFirstRes(id)); // 设置第一个笔记背景
private void setBackground(NoteItemData data) {
int id = data.getBgColorId();
if (data.getType() == Notes.TYPE_NOTE) {
if (data.isSingle() || data.isOneFollowingFolder()) {
setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id));
} else if (data.isLast()) {
setBackgroundResource(NoteItemBgResources.getNoteBgLastRes(id));
} else if (data.isFirst() || data.isMultiFollowingFolder()) {
setBackgroundResource(NoteItemBgResources.getNoteBgFirstRes(id));
} else {
setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id)); // 设置普通笔记背景
setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id));
}
} else {
// 文件夹背景资源
setBackgroundResource(NoteItemBgResources.getFolderBgRes()); // 设置文件夹背景
setBackgroundResource(NoteItemBgResources.getFolderBgRes());
}
}
/*
*
*
* @return NoteItemData
*/
public NoteItemData getItemData() { // 获取笔记数据方法
return mItemData; // 返回笔记数据
public NoteItemData getItemData() {
return mItemData;
}
}

@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.ActionBar;
@ -41,64 +41,59 @@ import android.view.View;
import android.widget.Button;
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;
public class NotesPreferenceActivity extends PreferenceActivity {
// 常量定义部分:主要用于设置和同步相关的偏好设置键
public static final String PREFERENCE_NAME = "notes_preferences"; // 偏好设置的名称
public static final String PREFERENCE_SYNC_ACCOUNT_NAME = "pref_key_account_name"; // 同步账户名称的键
public static final String PREFERENCE_LAST_SYNC_TIME = "pref_last_sync_time"; // 上次同步时间的键
public static final String PREFERENCE_SET_BG_COLOR_KEY = "pref_key_bg_random_appear"; // 设置背景颜色的键
private static final String PREFERENCE_SYNC_ACCOUNT_KEY = "pref_sync_account_key"; // 同步账户的键
private static final String AUTHORITIES_FILTER_KEY = "authorities"; // 权限过滤键
// 类成员变量定义部分主要用于账户同步和UI更新
private PreferenceCategory mAccountCategory; // 账户分类偏好项
private GTaskReceiver mReceiver; // 接收同步任务的广播接收器
private Account[] mOriAccounts; // 原始账户数组
private boolean mHasAddedAccount; // 标记是否已添加新账户
/**
* Activity
*
*
* @param icicle ActivityBundle
*/
public static final String PREFERENCE_NAME = "notes_preferences";
public static final String PREFERENCE_SYNC_ACCOUNT_NAME = "pref_key_account_name";
public static final String PREFERENCE_LAST_SYNC_TIME = "pref_last_sync_time";
public static final String PREFERENCE_SET_BG_COLOR_KEY = "pref_key_bg_random_appear";
private static final String PREFERENCE_SYNC_ACCOUNT_KEY = "pref_sync_account_key";
private static final String AUTHORITIES_FILTER_KEY = "authorities";
private PreferenceCategory mAccountCategory;
private GTaskReceiver mReceiver;
private Account[] mOriAccounts;
private boolean mHasAddedAccount;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
// 设置返回按钮
/* using the app icon for navigation */
getActionBar().setDisplayHomeAsUpEnabled(true);
// 从XML加载偏好设置
addPreferencesFromResource(R.xml.preferences);
mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY);
mReceiver = new GTaskReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME);
registerReceiver(mReceiver, filter); // 注册广播接收器以监听同步服务
registerReceiver(mReceiver, filter);
mOriAccounts = null;
// 添加设置头部视图
View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null);
getListView().addHeaderView(header, null, true);
}
/**
* Activity
*
*/
@Override
protected void onResume() {
super.onResume();
// 自动设置新添加的账户进行同步
// need to set sync account automatically if user has added a new
// account
if (mHasAddedAccount) {
Account[] accounts = getGoogleAccounts();
if (mOriAccounts != null && accounts.length > mOriAccounts.length) {
@ -111,144 +106,120 @@ public class NotesPreferenceActivity extends PreferenceActivity {
}
}
if (!found) {
setSyncAccount(accountNew.name); // 设置新账户进行同步
setSyncAccount(accountNew.name);
break;
}
}
}
}
// 刷新UI
refreshUI();
}
/**
* Activity广
*/
@Override
protected void onDestroy() {
if (mReceiver != null) {
unregisterReceiver(mReceiver); // 注销广播接收器,避免内存泄漏
unregisterReceiver(mReceiver);
}
super.onDestroy();
}
/**
*
*/
private void loadAccountPreference() {
mAccountCategory.removeAll(); // 清空账户分类下的所有条目
// 创建并配置账户偏好项
mAccountCategory.removeAll();
Preference accountPref = new Preference(this);
final String defaultAccount = getSyncAccountName(this); // 获取默认同步账户名称
accountPref.setTitle(getString(R.string.preferences_account_title)); // 设置标题
accountPref.setSummary(getString(R.string.preferences_account_summary)); // 设置摘要
final String defaultAccount = getSyncAccountName(this);
accountPref.setTitle(getString(R.string.preferences_account_title));
accountPref.setSummary(getString(R.string.preferences_account_summary));
accountPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
// 处理账户点击事件
if (!GTaskSyncService.isSyncing()) {
if (TextUtils.isEmpty(defaultAccount)) {
// 如果尚未设置账户,则展示选择账户对话框
// the first time to set account
showSelectAccountAlertDialog();
} else {
// 如果已经设置账户,则展示更改账户确认对话框
// if the account has already been set, we need to promp
// user about the risk
showChangeAccountConfirmAlertDialog();
}
} else {
// 如果正在同步中,则展示无法更改账户的提示
Toast.makeText(NotesPreferenceActivity.this,
R.string.preferences_toast_cannot_change_account, Toast.LENGTH_SHORT)
R.string.preferences_toast_cannot_change_account, Toast.LENGTH_SHORT)
.show();
}
return true;
}
});
mAccountCategory.addPreference(accountPref); // 将账户偏好项添加到账户分类下
mAccountCategory.addPreference(accountPref);
}
/**
*
*/
private void loadSyncButton() {
Button syncButton = (Button) findViewById(R.id.preference_sync_button); // 获取同步按钮
TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview); // 获取上次同步时间视图
// 根据同步状态设置按钮文本和点击事件
Button syncButton = (Button) findViewById(R.id.preference_sync_button);
TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview);
// set button state
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() {
public void onClick(View v) {
GTaskSyncService.cancelSync(NotesPreferenceActivity.this); // 设置点击事件为取消同步
GTaskSyncService.cancelSync(NotesPreferenceActivity.this);
}
});
} else {
syncButton.setText(getString(R.string.preferences_button_sync_immediately)); // 设置为立即同步文本
syncButton.setText(getString(R.string.preferences_button_sync_immediately));
syncButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
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()) {
lastSyncTimeView.setText(GTaskSyncService.getProgressString()); // 如果正在同步,显示进度信息
lastSyncTimeView.setVisibility(View.VISIBLE); // 显示上次同步时间视图
lastSyncTimeView.setText(GTaskSyncService.getProgressString());
lastSyncTimeView.setVisibility(View.VISIBLE);
} else {
long lastSyncTime = getLastSyncTime(this); // 获取上次同步时间
long lastSyncTime = getLastSyncTime(this);
if (lastSyncTime != 0) {
lastSyncTimeView.setText(getString(R.string.preferences_last_sync_time,
DateFormat.format(getString(R.string.preferences_last_sync_time_format),
lastSyncTime))); // 格式化并显示上次同步时间
lastSyncTimeView.setVisibility(View.VISIBLE); // 显示上次同步时间视图
lastSyncTime)));
lastSyncTimeView.setVisibility(View.VISIBLE);
} else {
lastSyncTimeView.setVisibility(View.GONE); // 如果未同步过,则隐藏上次同步时间视图
lastSyncTimeView.setVisibility(View.GONE);
}
}
}
/**
*
*/
private void refreshUI() {
loadAccountPreference(); // 加载账户偏好设置
loadSyncButton(); // 加载同步按钮
loadAccountPreference();
loadSyncButton();
}
/**
*
* Google
*
*/
private void showSelectAccountAlertDialog() {
// 创建对话框构建器并设置自定义标题
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null);
TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title);
titleTextView.setText(getString(R.string.preferences_dialog_select_account_title));
TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle);
subtitleTextView.setText(getString(R.string.preferences_dialog_select_account_tips));
dialogBuilder.setCustomTitle(titleView);
dialogBuilder.setPositiveButton(null, null); // 移除默认的确定按钮
// 获取当前设备上的Google账户
dialogBuilder.setPositiveButton(null, null);
Account[] accounts = getGoogleAccounts();
String defAccount = getSyncAccountName(this); // 获取当前同步的账户名称
mOriAccounts = accounts; // 保存原始账户列表
mHasAddedAccount = false; // 标记是否已添加新账户
String defAccount = getSyncAccountName(this);
mOriAccounts = accounts;
mHasAddedAccount = false;
if (accounts.length > 0) {
// 创建账户选项并设置选中项
CharSequence[] items = new CharSequence[accounts.length];
final CharSequence[] itemMapping = items;
int checkedItem = -1; // 记录默认选中的账户
int checkedItem = -1;
int index = 0;
for (Account account : accounts) {
if (TextUtils.equals(account.name, defAccount)) {
@ -256,7 +227,6 @@ public class NotesPreferenceActivity extends PreferenceActivity {
}
items[index++] = account.name;
}
// 设置单选列表,并为选中的账户执行同步操作
dialogBuilder.setSingleChoiceItems(items, checkedItem,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
@ -266,34 +236,27 @@ public class NotesPreferenceActivity extends PreferenceActivity {
}
});
}
// 添加“添加账户”选项
View addAccountView = LayoutInflater.from(this).inflate(R.layout.add_account_text, null);
dialogBuilder.setView(addAccountView);
final AlertDialog dialog = dialogBuilder.show();
// 点击“添加账户”执行添加账户操作
addAccountView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mHasAddedAccount = true;
Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");
intent.putExtra(AUTHORITIES_FILTER_KEY, new String[]{
"gmail-ls"
intent.putExtra(AUTHORITIES_FILTER_KEY, new String[] {
"gmail-ls"
});
startActivityForResult(intent, -1);
dialog.dismiss();
}
});
}
/**
*
*
*/
private void showChangeAccountConfirmAlertDialog() {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
// 设置自定义标题,包含当前同步账户名称
View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null);
TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title);
titleTextView.setText(getString(R.string.preferences_dialog_change_account_title,
@ -301,9 +264,8 @@ public class NotesPreferenceActivity extends PreferenceActivity {
TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle);
subtitleTextView.setText(getString(R.string.preferences_dialog_change_account_warn_msg));
dialogBuilder.setCustomTitle(titleView);
// 创建菜单项并设置点击事件
CharSequence[] menuItemArray = new CharSequence[]{
CharSequence[] menuItemArray = new CharSequence[] {
getString(R.string.preferences_menu_change_account),
getString(R.string.preferences_menu_remove_account),
getString(R.string.preferences_menu_cancel)
@ -311,10 +273,8 @@ public class NotesPreferenceActivity extends PreferenceActivity {
dialogBuilder.setItems(menuItemArray, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
// 选择更改账户,显示账户选择对话框
showSelectAccountAlertDialog();
} else if (which == 1) {
// 选择移除账户执行移除操作并刷新UI
removeSyncAccount();
refreshUI();
}
@ -322,41 +282,27 @@ public class NotesPreferenceActivity extends PreferenceActivity {
});
dialogBuilder.show();
}
/**
* Google
*
* @return Account[] com.google
*/
private Account[] getGoogleAccounts() {
AccountManager accountManager = AccountManager.get(this);
return accountManager.getAccountsByType("com.google");
}
/**
*
* SharedPreferencesgtask
*
* @param account
*/
private void setSyncAccount(String account) {
// 检查当前账户是否与传入账户名一致,不一致则更新账户信息
if (!getSyncAccountName(this).equals(account)) {
SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
// 如果账户名非空,则保存账户名,否则清除账户名
if (account != null) {
editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, account);
} else {
editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, "");
}
editor.commit();
// 清理上次同步时间
// clean up last sync time
setLastSyncTime(this, 0);
// 清理本地相关的gtask信息
// clean up local gtask related info
new Thread(new Runnable() {
public void run() {
ContentValues values = new ContentValues();
@ -365,32 +311,25 @@ public class NotesPreferenceActivity extends PreferenceActivity {
getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null);
}
}).start();
// 显示设置成功的提示信息
Toast.makeText(NotesPreferenceActivity.this,
getString(R.string.preferences_toast_success_set_accout, account),
Toast.LENGTH_SHORT).show();
}
}
/**
*
* SharedPreferencesgtask
*/
private void removeSyncAccount() {
SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
// 如果存在账户信息,则移除
if (settings.contains(PREFERENCE_SYNC_ACCOUNT_NAME)) {
editor.remove(PREFERENCE_SYNC_ACCOUNT_NAME);
}
// 如果存在上次同步时间信息,则移除
if (settings.contains(PREFERENCE_LAST_SYNC_TIME)) {
editor.remove(PREFERENCE_LAST_SYNC_TIME);
}
editor.commit();
// 清理本地相关的gtask信息
// clean up local gtask related info
new Thread(new Runnable() {
public void run() {
ContentValues values = new ContentValues();
@ -400,27 +339,13 @@ public class NotesPreferenceActivity extends PreferenceActivity {
}
}).start();
}
/**
*
* SharedPreferences
*
* @param context
* @return
*/
public static String getSyncAccountName(Context context) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, "");
}
/**
*
* SharedPreferences
*
* @param context
* @param time
*/
public static void setLastSyncTime(Context context, long time) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
@ -428,48 +353,30 @@ public class NotesPreferenceActivity extends PreferenceActivity {
editor.putLong(PREFERENCE_LAST_SYNC_TIME, time);
editor.commit();
}
/**
*
* SharedPreferences0
*
* @param context
* @return
*/
public static long getLastSyncTime(Context context) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0);
}
/**
* 广gtask广UI
*/
private class GTaskReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
refreshUI();
// 如果广播消息表明正在同步则更新UI显示的同步状态信息
if (intent.getBooleanExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING, false)) {
TextView syncStatus = (TextView) findViewById(R.id.prefenerece_sync_status_textview);
syncStatus.setText(intent
.getStringExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_PROGRESS_MSG));
}
}
}
/**
*
*
* @param item
* @return truefalse
*/
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// 当选择返回按钮时启动NotesListActivity并清除当前活动栈顶以上的所有活动
Intent intent = new Intent(this, NotesListActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//桌面挂件//
package net.micode.notes.widget;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//二倍大小的桌面挂件//
package net.micode.notes.widget;
import android.appwidget.AppWidgetManager;

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//四倍大小的桌面挂件//
package net.micode.notes.widget;
import android.appwidget.AppWidgetManager;

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="#88555555" />
<item android:state_selected="true" android:color="#ff999999" />
<item android:color="#ff000000" />
</selector>

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#50000000" />
</selector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 554 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/new_note_pressed" />
<item
android:drawable="@drawable/new_note_normal" />
</selector>

@ -1,43 +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.
-->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="@+id/account_dialog_title"
style="?android:attr/textAppearanceMedium"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center"
android:layout_marginTop="-2.7dip"
android:layout_marginBottom="-2.7dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/account_dialog_subtitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dip"
android:layout_marginBottom="1dip"
android:gravity="center"/>
</LinearLayout>

@ -1,32 +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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="50dip"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/preferences_add_account" />
</LinearLayout>

@ -1,56 +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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<NumberPicker
android:id="@+id/date"
android:layout_width="120dip"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
/>
<NumberPicker
android:id="@+id/hour"
android:layout_width="50dip"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
<NumberPicker
android:id="@+id/minute"
android:layout_width="50dip"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
<NumberPicker
android:id="@+id/amPm"
android:layout_width="50dip"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
</LinearLayout>

@ -1,23 +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.
-->
<EditText
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/et_foler_name"
android:layout_width="fill_parent"
android:hint="@string/hint_foler_name"
android:layout_height="fill_parent" />

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

Loading…
Cancel
Save