Compare commits

...

5 Commits

@ -40,119 +40,175 @@ 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) {
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();
try {
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;
}
mPlayer = new MediaPlayer();
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {
showActionDialog();
playAlarmSound();
} else {
finish();
}
}
private boolean isScreenOn() {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
return pm.isScreenOn();
}
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);
} else {
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
}
try {
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);
}
dialog.show().setOnDismissListener(this);
}
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) {
stopAlarmSound();
finish();
}
private void stopAlarmSound() {
if (mPlayer != null) {
mPlayer.stop();
mPlayer.release();
mPlayer = null;
}
}
//定义一个名为AlarmAlertActivity的公共类该类继承了Activity类同时实现了OnClickListener和OnDismissListener接口。
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
// 定义一个私有长整型变量mNoteId用于存储note的ID。
private long mNoteId;
// 定义一个私有字符串变量mSnippet用于存储note的摘要信息。
private String mSnippet;
// 定义一个私有的静态最终整型常量SNIPPET_PREW_MAX_LEN其值为60用于限制mSnippet的最大长度。
private static final int SNIPPET_PREW_MAX_LEN = 60;
// 定义一个私有MediaPlayer对象mPlayer用于播放音频。
MediaPlayer mPlayer;
// 重写Activity类的onCreate方法此方法在Activity创建时被系统调用。
@Override
protected void onCreate(Bundle savedInstanceState) {
// 调用父类的onCreate方法。
super.onCreate(savedInstanceState);
// 请求获得窗口特征,此处为去除窗口的标题栏。
requestWindowFeature(Window.FEATURE_NO_TITLE);
// 获取当前Activity的窗口对象。
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);
}
// 获取启动当前Activity的Intent对象。
Intent intent = getIntent();
try {
// 尝试从Intent中获取note的ID并赋值给mNoteId。注意从Intent中获取的数据路径可能会引发异常。
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));
// 使用note的ID从ContentResolver中获取note的摘要信息并赋值给mSnippet。可能会因为ID无效而引发异常。
mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId);
// 如果摘要信息长度超过预设的最大长度就截取摘要的前面部分并添加一个提示信息然后赋值给mSnippet。
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; }
// 创建一个新的MediaPlayer对象。
mPlayer = new MediaPlayer();
// 如果note在note数据库中可见就显示一个操作对话框并播放提示音。否则结束当前Activity。 if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {
showActionDialog(); // showActionDialog方法未在代码中定义可能在其他地方定义或者需要你自己定义。
playAlarmSound(); // playAlarmSound方法未在代码中定义可能在其他地方定义或者需要你自己定义。
} else { // 如果note在数据库中不可见结束当前Activity。
finish();
}
} // @Override注解表示该方法是一个重写的方法标志着该方法可以被覆盖或重写。
} // 类定义结束。
// 定义一个私有方法playAlarmSound用于播放闹钟声音
private void playAlarmSound() {
// 使用RingtoneManager获取当前默认的闹钟铃声的URI
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);
} else {
// 如果不受影响,设置音频流类型为闹钟音频流
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
}
try {
// 设置MediaPlayer的数据源为前面获取到的闹钟铃声的URI
mPlayer.setDataSource(this, url);
// 准备MediaPlayer播放
mPlayer.prepare();
// 设置MediaPlayer为循环播放模式
mPlayer.setLooping(true);
// 开始播放MediaPlayer
mPlayer.start();
} catch (IllegalArgumentException e) {
// 如果发生非法参数异常,打印异常堆栈信息
e.printStackTrace();
} catch (SecurityException e) {
// 如果发生安全异常,打印异常堆栈信息
e.printStackTrace();
} catch (IllegalStateException e) {
// 如果发生非法状态异常,打印异常堆栈信息
e.printStackTrace();
} catch (IOException e) {
// 如果发生IO异常打印异常堆栈信息
e.printStackTrace();
}
}
//显示操作对话框的方法
private void showActionDialog() {
// 创建一个AlertDialog.Builder对象用于构建对话框
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);
}
//对话框按钮点击事件处理方法
public void onClick(DialogInterface dialog, int which) {
// 根据点击的按钮,执行不同的操作
switch (which) {
case DialogInterface.BUTTON_NEGATIVE: // 如果点击的是取消按钮
// 创建一个指向NoteEditActivity的Intent
Intent intent = new Intent(this, NoteEditActivity.class);
// 设置Intent的动作为查看
intent.setAction(Intent.ACTION_VIEW);
// 将mNoteId作为额外数据放入Intent中
intent.putExtra(Intent.EXTRA_UID, mNoteId);
// 启动NoteEditActivity
startActivity(intent);
break;
default: // 如果点击的是其他按钮,不执行任何操作
break;
}
}
//对话框关闭事件处理方法
public void onDismiss(DialogInterface dialog) {
// 停止闹钟声音播放
stopAlarmSound();
// 结束当前活动
finish();
}
//停止闹钟声音播放的方法
private void stopAlarmSound() {
// 如果mPlayer不为空则停止播放释放资源并将mPlayer设置为null
if (mPlayer != null) {
mPlayer.stop();
mPlayer.release();
mPlayer = null;
}
}

@ -26,56 +26,63 @@ 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;
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;
//声明一个名为NoteItemData的类该类不接受任何参数并且是公开的
public class NoteItemData {
// 定义一个字符串数组PROJECTION该数组包含一些列名这些列名是从NoteColumns类中获取的常量
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,
};
// 定义一组常量表示在PROJECTION数组中每个列的位置
// 这些常量后续在代码中用于索引和查找特定的列
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;
// 定义一些私有变量,用来存储便签的各种属性值
// 如ID、提醒日期、背景颜色ID、创建日期等
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; // 新增的变量未在PROJECTION中看到对应的列名
private String mPhoneNumber; // 新增的变量未在PROJECTION中看到对应的列名
// 定义一些私有布尔变量,用来标识一些特殊状态,如是否是最后一个便签、是否是第一个便签等
private boolean mIsLastItem;
private boolean mIsFirstItem;
private boolean mIsOnlyOneItem;
private boolean mIsOneNoteFollowingFolder;
private boolean mIsMultiNotesFollowingFolder;
public NoteItemData(Context context, Cursor cursor) {
mId = cursor.getLong(ID_COLUMN);
mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN);
@ -134,91 +141,89 @@ public class NoteItemData {
}
}
public boolean isOneFollowingFolder() {
return mIsOneNoteFollowingFolder;
}
public boolean isMultiFollowingFolder() {
return mIsMultiNotesFollowingFolder;
}
public boolean isLast() {
return mIsLastItem;
}
public String getCallName() {
return mName;
}
public boolean isFirst() {
return mIsFirstItem;
}
public boolean isSingle() {
return mIsOnlyOneItem;
}
public long getId() {
return mId;
}
public long getAlertDate() {
return mAlertDate;
}
public long getCreatedDate() {
return mCreatedDate;
}
public boolean hasAttachment() {
return mHasAttachment;
}
public long getModifiedDate() {
return mModifiedDate;
}
public int getBgColorId() {
return mBgColorId;
}
public long getParentId() {
return mParentId;
}
public int getNotesCount() {
return mNotesCount;
}
public long getFolderId () {
return mParentId;
}
public int getType() {
return mType;
}
public int getWidgetType() {
return mWidgetType;
}
public int getWidgetId() {
return mWidgetId;
}
public String getSnippet() {
return mSnippet;
}
public boolean hasAlert() {
return (mAlertDate > 0);
}
public boolean isCallRecord() {
return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber));
}
public static int getNoteType(Cursor cursor) {
return cursor.getInt(TYPE_COLUMN);
}
}
// 定义一个公开的布尔型方法 isOneFollowingFolder返回值是 mIsOneNoteFollowingFolder 的值
public boolean isOneFollowingFolder() {
return mIsOneNoteFollowingFolder;
}
// 定义一个公开的布尔型方法 isMultiFollowingFolder返回值是 mIsMultiNotesFollowingFolder 的值
public boolean isMultiFollowingFolder() {
return mIsMultiNotesFollowingFolder;
}
// 定义一个公开的布尔型方法 isLast返回值是 mIsLastItem 的值
public boolean isLast() {
return mIsLastItem;
}
// 定义一个公开的字符串获取方法 getCallName返回值是 mName 的值
public String getCallName() {
return mName;
}
// 定义一个公开的布尔型方法 isFirst返回值是 mIsFirstItem 的值
public boolean isFirst() {
return mIsFirstItem;
}
// 定义一个公开的布尔型方法 isSingle返回值是 mIsOnlyOneItem 的值
public boolean isSingle() {
return mIsOnlyOneItem;
}
// 定义一个公开的长整型方法 getId返回值是 mId 的值
public long getId() {
return mId;
}
// 定义一个公开的长整型方法 getAlertDate返回值是 mAlertDate 的值
public long getAlertDate() {
return mAlertDate;
}
// 定义一个公开的长整型方法 getCreatedDate返回值是 mCreatedDate 的值
public long getCreatedDate() {
return mCreatedDate;
}
// 定义一个公开的布尔型方法 hasAttachment返回值是 mHasAttachment 的值
public boolean hasAttachment() {
return mHasAttachment;
}
// 定义一个公开的长整型方法 getModifiedDate返回值是 mModifiedDate 的值
public long getModifiedDate() {
return mModifiedDate;
}
// 定义一个公开的整型方法 getBgColorId返回值是 mBgColorId 的值
public int getBgColorId() {
return mBgColorId;
}
// 定义一个公开的长整型方法 getParentId返回值是 mParentId 的值,注意这个方法名和 getFolderId 很相似,可能会有一些混淆。
public long getParentId() {
return mParentId;
}
// 定义一个公开的整型方法 getNotesCount返回值是 mNotesCount 的值,这个方法可能用于获取笔记文件夹中的笔记数量。
public int getNotesCount() {
return mNotesCount;
}
// 定义一个公开的长整型方法 getFolderId返回值也是 mParentId 的值。这个方法和上面的 getParentId 方法是完全一样的,可能是代码重复或者错误。
public long getFolderId () {
return mParentId;
}
// 定义一个公开的整型方法 getType返回值是 mType 的值,这个方法可能用于获取笔记的类型。
public int getType() {
return mType;
}
// 定义一个公开的整型方法 getWidgetType返回值是 mWidgetType 的值这个方法可能用于获取部件类型。部件可能是一个UI组件或者应用的一部分。
public int getWidgetType() {
return mWidgetType;
}
// 定义一个公开的整型方法 getWidgetId返回值是 mWidgetId 的值这个方法可能用于获取部件ID。部件可能是UI的一部分或者应用的一部分。 部件ID可能是唯一标识部件的值。 同样的部件可能在屏幕上多次出现但是每个实例都有唯一的ID。 每个部件ID都存储在部件管理器的内部数据结构中。 通过使用部件ID可以引用和操作特定的部件实例。 这可能对于在运行时对部件进行动态控制非常有用。 在Android中部件ID通常是整数类型。 例如在View类中有一个名为getId的方法它返回View的ID。 这个ID就是View的实例在屏幕上的唯一标识符。 ID可以是任何整数类型int因此你可以使用任何整数作为ID。 在Android中ID的默认范围是-1到2147483647如果使用Java。 在使用C++时,范围可能会有所不同。 ID的值在部件的生命周期中保持不变。 ID为0表示没有给部件指定ID。 在给定ID的情况下你可以通过使用findViewById或findView

@ -31,154 +31,198 @@ 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;
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new NotesListItem(context);
}
@Override
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()));
}
}
public void setCheckedItem(final int position, final boolean checked) {
mSelectedIndex.put(position, checked);
notifyDataSetChanged();
}
public boolean isInChoiceMode() {
return mChoiceMode;
}
public void setChoiceMode(boolean mode) {
mSelectedIndex.clear();
mChoiceMode = mode;
}
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 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);
}
}
}
return itemSet;
}
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;
}
}
}
return itemSet;
}
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++;
}
}
return count;
}
public boolean isAllSelected() {
int checkedCount = getSelectedCount();
return (checkedCount != 0 && checkedCount == mNotesCount);
}
public boolean isSelectedItem(final int position) {
if (null == mSelectedIndex.get(position)) {
return false;
}
return mSelectedIndex.get(position);
}
@Override
protected void onContentChanged() {
super.onContentChanged();
calcNotesCount();
}
@Override
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++;
}
} else {
Log.e(TAG, "Invalid cursor");
return;
}
}
}
//定义一个公共类NotesListAdapter它继承自CursorAdapter
public class NotesListAdapter extends CursorAdapter {
// 定义一个静态的字符串标签,用于日志记录
private static final String TAG = "NotesListAdapter";
// 定义一个Context对象用于与应用程序环境交互
private Context mContext;
// 定义一个HashMap对象用于存储选中的项目及其对应的索引
private HashMap<Integer, Boolean> mSelectedIndex;
// 定义一个变量,用于存储笔记的数量
private int mNotesCount;
// 定义一个布尔变量,表示是否处于选择模式
private boolean mChoiceMode;
// 定义一个内部类AppWidgetAttribute包含widgetId和widgetType两个成员变量
public static class AppWidgetAttribute {
public int widgetId;
public int widgetType;
};
// 定义一个构造函数接收一个Context对象作为参数
public NotesListAdapter(Context context) {
// 调用父类的构造函数传入上下文、null的游标和null的父视图
super(context, null);
// 初始化mSelectedIndex为空的HashMap对象
mSelectedIndex = new HashMap<Integer, Boolean>();
// 保存传入的上下文对象
mContext = context;
// 初始化笔记数量为0
mNotesCount = 0;
}
// 重写父类的newView方法用于创建新的视图对象
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// 返回一个新的NotesListItem对象
return new NotesListItem(context);
}
// 重写父类的bindView方法用于将数据绑定到视图上
@Override
public void bindView(View view, Context context, Cursor cursor) {
// 如果视图是NotesListItem的实例
if (view instanceof NotesListItem) {
// 从游标中获取数据并创建一个新的NoteItemData对象
NoteItemData itemData = new NoteItemData(context, cursor);
// 将数据绑定到视图中,同时传入选择模式和当前项是否被选中的信息
((NotesListItem) view).bind(context, itemData, mChoiceMode,
isSelectedItem(cursor.getPosition()));
}
}
// 定义一个方法,用于设置指定位置的项是否被选中
public void setCheckedItem(final int position, final boolean checked) {
// 在mSelectedIndex中添加或修改对应位置的选中状态
mSelectedIndex.put(position, checked);
// 通知数据集已改变,触发视图更新
notifyDataSetChanged();
}
//判断当前是否处于选择模式
public boolean isInChoiceMode() {
return mChoiceMode;
}
//设置选择模式,清空已选中的项目并改变选择模式
public void setChoiceMode(boolean mode) {
mSelectedIndex.clear(); // 清空已选中的项目
mChoiceMode = mode; // 设置新的选择模式
}
//全选或全不选
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并返回一个HashSet集合
public HashSet<Long> getSelectedItemIds() {
HashSet<Long> itemSet = new HashSet<Long>(); // 创建一个HashSet集合用于存放被选中的项目id
for (Integer position : mSelectedIndex.keySet()) { // 遍历所有被选中的项目的位置
if (mSelectedIndex.get(position) == true) { // 如果该位置的项被选中
Long id = getItemId(position); // 获取该位置的项目id
if (id == Notes.ID_ROOT_FOLDER) { // 如果获取的id是根文件夹的id则记录一个错误日志因为根文件夹不应该被选中
Log.d(TAG, "Wrong item id, should not happen");
} else {
itemSet.add(id); // 否则将该id添加到HashSet集合中
}
}
}
return itemSet; // 返回HashSet集合
}
//获取所有选中的小部件属性
public HashSet<AppWidgetAttribute> getSelectedWidget() {
HashSet<AppWidgetAttribute> itemSet = new HashSet<AppWidgetAttribute>(); // 创建一个HashSet集合用于存放选中的小部件属性
for (Integer position : mSelectedIndex.keySet()) { // 遍历所有被选中的项目的位置
if (mSelectedIndex.get(position) == true) { // 如果该位置的项被选中
Cursor c = (Cursor) getItem(position); // 获取该位置的项目以Cursor对象的形式返回
if (c != null) { // 如果Cursor不为空
AppWidgetAttribute widget = new AppWidgetAttribute(); // 创建一个新的AppWidgetAttribute对象
NoteItemData item = new NoteItemData(mContext, c); // 使用Cursor对象创建一个NoteItemData对象
widget.widgetId = item.getWidgetId(); // 从NoteItemData对象获取小部件ID并设置到AppWidgetAttribute对象中
widget.widgetType = item.getWidgetType(); // 从NoteItemData对象获取小部件类型并设置到AppWidgetAttribute对象中
itemSet.add(widget); // 将创建的AppWidgetAttribute对象添加到HashSet集合中
/**
* Cursor
*/
} else {
Log.e(TAG, "Invalid cursor"); // 如果Cursor为空记录错误日志
return null; // 返回null表示获取失败
}
}
}
return itemSet; // 返回HashSet集合包含所有选中的小部件属性
}
//获取被选中的项目数量
public int getSelectedCount() {
Collection<Boolean> values = mSelectedIndex.values(); // 获取所有被选中的项目(布尔值)的集合
if (null == values) { // 如果集合为空(没有被选中的项目)
return 0; // 返回0表示被选中的项目数量为0
}
Iterator<Boolean> iter = values.iterator(); // 创建一个迭代器来遍历布尔值的集合
int count = 0; // 初始化计数器为0
while (iter.hasNext()) { // 当还有下一个布尔值时
if (true == iter.next()) { // 如果布尔值为true表示被选中
count++; // 计数器加1
}
}
return count; // 返回被选中的项目数量
}
//检查是否所有项目都被选中
public boolean isAllSelected() {
int checkedCount = getSelectedCount(); // 获取被选中的项目数量
return (checkedCount != 0 && checkedCount == mNotesCount); // 如果被选中的项目数量不为0且等于总的项目数量则返回true表示所有项目都被选中否则返回false。
}
//定义一个方法,用于判断指定位置的项目是否被选中
public boolean isSelectedItem(final int position) {
// 如果指定位置的项目在mSelectedIndex映射中对应的值为null返回false表示未被选中
if (null == mSelectedIndex.get(position)) {
return false;
}
// 返回mSelectedIndex映射中指定位置对应的值如果为true则表示被选中为false则表示未被选中
return mSelectedIndex.get(position);
}
//重写onContentChanged方法该方法在内容发生变化时被调用
@Override
protected void onContentChanged() {
// 调用父类的onContentChanged方法执行默认的内容变化处理
super.onContentChanged();
// 调用calcNotesCount方法重新计算笔记数量
calcNotesCount();
}
//重写changeCursor方法该方法在Cursor发生变化时被调用
@Override
public void changeCursor(Cursor cursor) {
// 调用父类的changeCursor方法执行默认的Cursor变化处理
super.changeCursor(cursor);
// 调用calcNotesCount方法重新计算笔记数量
calcNotesCount();
}
//定义一个私有方法,用于计算笔记数量
private void calcNotesCount() {
// 初始化笔记数量为0
mNotesCount = 0;
// 遍历所有的项目从0到getCount()-1
for (int i = 0; i < getCount(); i++) {
// 获取指定位置的项目以Cursor对象的形式返回
Cursor c = (Cursor) getItem(i);
// 如果Cursor不为空
if (c != null) {
// 如果当前项目的类型为“笔记”TYPE_NOTE则笔记数量加1
if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) {
mNotesCount++;
}
} else {
// 如果Cursor为空记录错误日志并退出方法
Log.e(TAG, "Invalid cursor");
return;
}
}
}

@ -30,93 +30,152 @@ 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);
}
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);
}
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);
} else {
mAlert.setVisibility(View.GONE);
}
} else {
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);
} else {
mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet()));
if (data.hasAlert()) {
mAlert.setImageResource(R.drawable.clock);
mAlert.setVisibility(View.VISIBLE);
} else {
mAlert.setVisibility(View.GONE);
}
}
}
mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate()));
setBackground(data);
}
//定义一个名为NotesListItem的类它继承自LinearLayout
public class NotesListItem extends LinearLayout {
// 定义一个私有的ImageView对象用于显示警报图标
private ImageView mAlert;
// 定义一个私有的TextView对象用于显示标题
private TextView mTitle;
// 定义一个私有的TextView对象用于显示时间
private TextView mTime;
// 定义一个私有的TextView对象用于显示电话的名字
private TextView mCallName;
// 定义一个私有的NoteItemData对象用于存储与笔记相关的数据
private NoteItemData mItemData;
// 定义一个私有的CheckBox对象用于表示笔记是否被选中
private CheckBox mCheckBox;
// 定义一个公共的构造函数接收一个Context参数
public NotesListItem(Context context) {
// 调用父类的构造函数传入context参数
super(context);
// 使用inflate方法从指定的XML布局文件中创建视图并将视图添加到当前实例中
inflate(context, R.layout.note_item, this);
// 通过ID查找布局中的控件并赋值给相应的变量
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);
}
}
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);
}
// 保存传入的数据
mItemData = data;
}
//如果data的id等于Notes.ID_CALL_RECORD_FOLDER
if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
// 隐藏电话名称的显示
mCallName.setVisibility(View.GONE);
// 显示警报图标
mAlert.setVisibility(View.VISIBLE);
// 设置标题的文本样式为默认样式
mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem);
// 设置标题的文本为“通话记录文件夹名”加上data中的笔记数量
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);
// 设置电话名称的文本为data中的callName
mCallName.setText(data.getCallName());
// 设置标题的文本样式为二级样式
mTitle.setTextAppearance(context,R.style.TextAppearanceSecondaryItem);
// 设置标题的文本为DataUtils格式化后的摘要
mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet()));
// 如果data有警报
if (data.hasAlert()) {
// 设置警报图标的资源为时钟图标,并显示警报图标
mAlert.setImageResource(R.drawable.clock);
mAlert.setVisibility(View.VISIBLE);
} else {
// 否则隐藏警报图标
mAlert.setVisibility(View.GONE);
}
} else {
// 隐藏电话名称的显示
mCallName.setVisibility(View.GONE);
// 设置标题的文本样式为默认样式
mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem);
// 如果data的类型是文件夹
if (data.getType() == Notes.TYPE_FOLDER) {
// 设置标题的文本为摘要加上data中的笔记数量
mTitle.setText(data.getSnippet()
+ context.getString(R.string.format_folder_files_count,
data.getNotesCount()));
// 隐藏警报图标
mAlert.setVisibility(View.GONE);
} else {
// 设置标题的文本为DataUtils格式化后的摘要
mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet()));
// 如果data有警报
if (data.hasAlert()) {
// 设置警报图标的资源为时钟图标,并显示警报图标
mAlert.setImageResource(R.drawable.clock);
mAlert.setVisibility(View.VISIBLE);
} else {
// 否则隐藏警报图标
mAlert.setVisibility(View.GONE);
}
}
}
//设置时间文本为相对时间格式例如1小时前2分钟前等
mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate()));
//根据data设置背景色或背景图片等背景样式
setBackground(data);
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));
}
} else {
setBackgroundResource(NoteItemBgResources.getFolderBgRes());
}
}
//设置背景的方法
private void setBackground(NoteItemData data) {
// 获取data的背景颜色id
int id = data.getBgColorId();
// 如果data的类型是笔记
if (data.getType() == Notes.TYPE_NOTE) {
// 如果data是单条笔记或者是某个文件夹下的第一条笔记
if (data.isSingle() || data.isOneFollowingFolder()) {
// 设置背景资源为单条笔记的背景资源
setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id));
// 如果data是最后一条笔记
} else if (data.isLast()) {
// 设置背景资源为最后一条笔记的背景资源
setBackgroundResource(NoteItemBgResources.getNoteBgLastRes(id));
// 如果data是第一条笔记或者是某个文件夹下的第一条多条笔记
} else if (data.isFirst() || data.isMultiFollowingFolder()) {
// 设置背景资源为第一条笔记的背景资源
setBackgroundResource(NoteItemBgResources.getNoteBgFirstRes(id));
// 其他情况,默认为普通情况
} else {
// 设置背景资源为普通笔记的背景资源
setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id));
}
// 如果data的类型是文件夹
} else {
// 设置背景资源为文件夹的背景资源
setBackgroundResource(NoteItemBgResources.getFolderBgRes());
}
}
public NoteItemData getItemData() {
return mItemData;
}
}
//获取itemData的方法返回mItemData对象
public NoteItemData getItemData() {
return mItemData;
}

@ -48,228 +48,334 @@ 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";
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);
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);
mOriAccounts = null;
View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null);
getListView().addHeaderView(header, null, true);
}
@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) {
for (Account accountNew : accounts) {
boolean found = false;
for (Account accountOld : mOriAccounts) {
if (TextUtils.equals(accountOld.name, accountNew.name)) {
found = true;
break;
}
}
if (!found) {
setSyncAccount(accountNew.name);
break;
}
}
}
}
refreshUI();
}
@Override
protected void onDestroy() {
if (mReceiver != null) {
unregisterReceiver(mReceiver);
}
super.onDestroy();
}
private void loadAccountPreference() {
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));
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)
.show();
}
return true;
}
});
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);
// set button state
if (GTaskSyncService.isSyncing()) {
syncButton.setText(getString(R.string.preferences_button_sync_cancel));
syncButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
GTaskSyncService.cancelSync(NotesPreferenceActivity.this);
}
});
} else {
syncButton.setText(getString(R.string.preferences_button_sync_immediately));
syncButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
GTaskSyncService.startSync(NotesPreferenceActivity.this);
}
});
}
syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this)));
// set last sync time
if (GTaskSyncService.isSyncing()) {
lastSyncTimeView.setText(GTaskSyncService.getProgressString());
lastSyncTimeView.setVisibility(View.VISIBLE);
} else {
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);
} else {
lastSyncTimeView.setVisibility(View.GONE);
}
}
}
private void refreshUI() {
loadAccountPreference();
loadSyncButton();
}
//声明一个名为NotesPreferenceActivity的类该类继承自PreferenceActivity
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";
// 声明一个PreferenceCategory类型的成员变量mAccountCategory用于保存账户偏好设置的类别
private PreferenceCategory mAccountCategory;
// 声明一个GTaskReceiver类型的成员变量mReceiver可能用于接收和处理任务相关的广播
private GTaskReceiver mReceiver;
// 声明一个Account类型的数组mOriAccounts用于保存原始账户信息
private Account[] mOriAccounts;
// 声明一个布尔类型的成员变量mHasAddedAccount用于跟踪是否已添加账户
private boolean mHasAddedAccount;
// 重写PreferenceActivity的onCreate方法该方法在活动创建时被调用
@Override
protected void onCreate(Bundle icicle) {
// 调用父类的onCreate方法并设置导航图标为应用图标允许用户通过图标进行导航
super.onCreate(icicle);
getActionBar().setDisplayHomeAsUpEnabled(true);
// 从资源文件中加载偏好设置
addPreferencesFromResource(R.xml.preferences);
// 获取账户偏好设置的类别
mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY);
// 创建一个GTaskReceiver对象
mReceiver = new GTaskReceiver();
// 创建一个IntentFilter对象并添加一个动作过滤器该动作过滤器用于过滤来自GTaskSyncService的广播
IntentFilter filter = new IntentFilter();
filter.addAction(GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME);
// 注册广播接收器以接收与GTaskSyncService相关的广播
registerReceiver(mReceiver, filter);
// 将mOriAccounts设置为null表示尚未初始化该变量在后续代码中可能会进行初始化
mOriAccounts = null;
// 使用LayoutInflater从当前context创建一个视图并从布局文件R.layout.settings_header中获取头部视图可能包含一些标题或标头信息
View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null);
// 将头部视图添加到列表视图中允许在偏好设置列表中显示一些额外的信息或标题等。参数为null是因为我们不需要在此处创建任何新的视图层次结构。第三个参数为true表示在列表中显示头部视图。如果为false则头部视图不会显示在列表中。
getListView().addHeaderView(header, null, true);
} // 结束onCreate方法定义
} // 结束NotesPreferenceActivity类定义
@Override
protected void onResume() {
super.onResume();
// 当用户添加新账户时,需要自动设置同步账户
if (mHasAddedAccount) {
// 获取所有Google账户
Account[] accounts = getGoogleAccounts();
// 如果原始账户列表和新获取的账户列表长度不一致,说明有新账户添加
if (mOriAccounts != null && accounts.length > mOriAccounts.length) {
for (Account accountNew : accounts) {
boolean found = false;
for (Account accountOld : mOriAccounts) {
// 检查新账户是否在原始列表中
if (TextUtils.equals(accountOld.name, accountNew.name)) {
found = true;
break;
}
}
// 如果新账户不在原始列表中,则设置该账户为同步账户
if (!found) {
setSyncAccount(accountNew.name);
break;
}
}
}
}
// 刷新UI可能是为了显示同步账户的更改或其他相关UI更新
refreshUI();
}
@Override
protected void onDestroy() {
if (mReceiver != null) {
// 取消注册广播接收器,以避免内存泄漏
unregisterReceiver(mReceiver);
}
super.onDestroy();
}
private void showSelectAccountAlertDialog() {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
//加载账户偏好
private void loadAccountPreference() {
// 从账户分类中移除所有偏好
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));
// 设置账户偏好的点击监听器
accountPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
// 如果不在同步状态,则执行以下操作
if (!GTaskSyncService.isSyncing()) {
// 如果默认账户为空,表示这是第一次设置账户
if (TextUtils.isEmpty(defaultAccount)) {
// 显示选择账户的对话框
showSelectAccountAlertDialog();
} else {
// 如果账户已经被设置,需要提示用户更改账户的风险
showChangeAccountConfirmAlertDialog();
}
} else {
// 如果正在同步,则显示一个提示信息,表示不能更改账户
Toast.makeText(NotesPreferenceActivity.this,
R.string.preferences_toast_cannot_change_account, Toast.LENGTH_SHORT)
.show();
}
// 返回true表示监听器已经处理了点击事件
return true;
}
});
// 将账户偏好添加到账户分类中
mAccountCategory.addPreference(accountPref);
}
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);
//加载同步按钮
private void loadSyncButton() {
// 从布局中获取同步按钮
Button syncButton = (Button) findViewById(R.id.preference_sync_button);
// 从布局中获取最后一次同步时间文本视图
TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview);
// 设置按钮状态
// 如果正在同步
if (GTaskSyncService.isSyncing()) {
// 设置按钮文本为"取消同步"
syncButton.setText(getString(R.string.preferences_button_sync_cancel));
// 设置按钮点击监听器,点击时取消同步
syncButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
GTaskSyncService.cancelSync(NotesPreferenceActivity.this);
}
});
// 如果未同步
} else {
// 设置按钮文本为"立即同步"
syncButton.setText(getString(R.string.preferences_button_sync_immediately));
// 设置按钮点击监听器,点击时开始同步
syncButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
GTaskSyncService.startSync(NotesPreferenceActivity.this);
}
});
}
// 设置按钮是否可用,如果同步账户名不为空则启用,否则禁用
syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this)));
// 设置最后一次同步时间
// 如果正在同步
if (GTaskSyncService.isSyncing()) {
// 设置最后一次同步时间为进度字符串
lastSyncTimeView.setText(GTaskSyncService.getProgressString());
// 显示最后一次同步时间文本视图
lastSyncTimeView.setVisibility(View.VISIBLE);
// 如果未同步
} else {
// 获取最后一次同步时间
long lastSyncTime = getLastSyncTime(this);
// 如果最后一次同步时间不为0
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);
// 如果没有同步过
} else {
// 隐藏最后一次同步时间文本视图
lastSyncTimeView.setVisibility(View.GONE);
}
}
}
Account[] accounts = getGoogleAccounts();
String defAccount = getSyncAccountName(this);
mOriAccounts = accounts;
mHasAddedAccount = false;
//刷新UI可能包括加载账户偏好设置和同步按钮的状态等
private void refreshUI() {
// 加载账户偏好设置
loadAccountPreference();
// 加载同步按钮
loadSyncButton();
}
//显示选择账户的对话框提示
private void showSelectAccountAlertDialog() {
// 创建对话框构建器
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
// 从布局中加载 account_dialog_title 视图,并获取其中的 TextView 实例
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);
// 获取所有谷歌账户
Account[] accounts = getGoogleAccounts();
// 获取默认同步账户名称
String defAccount = getSyncAccountName(this);
// 保存原始账户数组
mOriAccounts = accounts;
// 标记是否已添加账户,默认为 false
mHasAddedAccount = false;
// 如果存在谷歌账户
if (accounts.length > 0) {
// 创建字符序列数组,用于存放账户名称
CharSequence[] items = new CharSequence[accounts.length];
// 用于映射原始账户数组和字符序列数组的对应关系
final CharSequence[] itemMapping = items;
int checkedItem = -1; // 默认未选中任何账户,初始值为 -1
int index = 0;
// 遍历所有账户
for (Account account : accounts) {
// 如果账户名称与默认同步账户名称相同
if (TextUtils.equals(account.name, defAccount)) {
checkedItem = index; // 将该账户设置为默认选中状态checkedItem 值为索引值
}
items[index++] = account.name; // 将账户名称存入字符序列数组中
}
// 设置单选列表项,并指定默认选中项和点击监听器
dialogBuilder.setSingleChoiceItems(items, checkedItem,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// 设置同步账户,参数为选中的账户名称
setSyncAccount(itemMapping[which].toString());
// 关闭对话框
dialog.dismiss();
// 刷新UI
refreshUI();
}
});
}
}
if (accounts.length > 0) {
CharSequence[] items = new CharSequence[accounts.length];
final CharSequence[] itemMapping = items;
int checkedItem = -1;
int index = 0;
for (Account account : accounts) {
if (TextUtils.equals(account.name, defAccount)) {
checkedItem = index;
}
items[index++] = account.name;
}
dialogBuilder.setSingleChoiceItems(items, checkedItem,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
setSyncAccount(itemMapping[which].toString());
dialog.dismiss();
refreshUI();
}
});
}
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"
});
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,
getSyncAccountName(this)));
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[] {
getString(R.string.preferences_menu_change_account),
getString(R.string.preferences_menu_remove_account),
getString(R.string.preferences_menu_cancel)
};
//加载添加账户的视图,并将其设置为对话框的内容
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");
// 添加过滤条件仅显示gmail-ls账户
intent.putExtra(AUTHORITIES_FILTER_KEY, new String[] {
"gmail-ls"
});
// 启动意图,并等待结果(-1
startActivityForResult(intent, -1);
// 关闭对话框
dialog.dismiss();
}
});
}
//显示更改账户的确认对话框
private void showChangeAccountConfirmAlertDialog() {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
//加载账户对话框的标题视图,并获取其中的 TextView 实例
View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null);
//获取标题 TextView 实例
TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title);
//设置标题文本,包含当前同步账户的名称
titleTextView.setText(getString(R.string.preferences_dialog_change_account_title,
getSyncAccountName(this)));
//获取副标题 TextView 实例
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[] {
getString(R.string.preferences_menu_change_account),
getString(R.string.preferences_menu_remove_account),
getString(R.string.preferences_menu_cancel)
};
dialogBuilder.setItems(menuItemArray, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
@ -288,101 +394,161 @@ public class NotesPreferenceActivity extends PreferenceActivity {
return accountManager.getAccountsByType("com.google");
}
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);
// clean up local gtask related info
new Thread(new Runnable() {
public void run() {
ContentValues values = new ContentValues();
values.put(NoteColumns.GTASK_ID, "");
values.put(NoteColumns.SYNC_ID, 0);
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();
}
/**
*
*
* @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();
// 清理上次同步的时间
setLastSyncTime(this, 0);
// 在新线程中清理与本地GTask相关的信息
new Thread(new Runnable() {
public void run() {
ContentValues values = new ContentValues();
values.put(NoteColumns.GTASK_ID, ""); // 将GTask ID设置为空字符串
values.put(NoteColumns.SYNC_ID, 0); // 将同步ID设置为0
getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); // 更新内容URI清理与同步相关的信息
}
}).start(); // 启动新线程来执行清理操作
// 显示一个短暂的Toast消息告知用户成功设置了账户
Toast.makeText(NotesPreferenceActivity.this,
getString(R.string.preferences_toast_success_set_accout, account), // 获取并格式化Toast消息文本
Toast.LENGTH_SHORT).show(); // 显示Toast消息持续时间短暂
}
}
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();
// clean up local gtask related info
new Thread(new Runnable() {
public void run() {
ContentValues values = new ContentValues();
values.put(NoteColumns.GTASK_ID, "");
values.put(NoteColumns.SYNC_ID, 0);
getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null);
}
}).start();
}
public static String getSyncAccountName(Context context) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, "");
}
public static void setLastSyncTime(Context context, long time) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
editor.putLong(PREFERENCE_LAST_SYNC_TIME, time);
editor.commit();
}
public static long getLastSyncTime(Context context) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0);
/**
*
*/
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相关的信息
new Thread(new Runnable() {
public void run() {
ContentValues values = new ContentValues();
// 将GTask ID设置为空字符串
values.put(NoteColumns.GTASK_ID, "");
// 将同步ID设置为0
values.put(NoteColumns.SYNC_ID, 0);
// 更新内容URI清理与同步相关的信息
getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null);
}
}).start(); // 启动新线程来执行清理操作
}
/**
*
* @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, "");
}
/**
*
* @param context
* @param time
*/
public static void setLastSyncTime(Context context, long time) {
// 获取共享偏好设置
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
// 创建一个编辑器来修改共享偏好设置
SharedPreferences.Editor editor = settings.edit();
// 保存上次同步的时间(以毫秒为单位)到共享偏好设置中
editor.putLong(PREFERENCE_LAST_SYNC_TIME, time);
// 提交编辑,使更改生效
editor.commit();
}
private class GTaskReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
refreshUI();
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));
}
}
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Intent intent = new Intent(this, NotesListActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
return true;
default:
return false;
}
}
}
// 定义一个公共静态方法名为getLastSyncTime接收一个Context对象作为参数
// 该方法用于从SharedPreferences中获取上次同步的时间以毫秒为单位如果不存在则返回0
public static long getLastSyncTime(Context context) {
// 从给定的Context对象中获取名为PREFERENCE_NAME的SharedPreferences对象同时设置其访问模式为Context.MODE_PRIVATE
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
// 从SharedPreferences对象中获取名为PREFERENCE_Last_SYNC_TIME的值如果不存在则返回0
return settings.getLong(PREFERENCE_Last_Sync_Time, 0);
}
// 定义一个私有的内部类GTaskReceiver它继承了BroadcastReceiver类
private class GTaskReceiver extends BroadcastReceiver {
// 覆盖BroadcastReceiver的onReceive方法接收两个参数Context对象和Intent对象
@Override
public void onReceive(Context context, Intent intent) {
// 调用refreshUI方法可能是为了更新用户界面
refreshUI();
// 从Intent对象中获取一个Boolean类型的额外数据键为GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING如果不存在则返回false
// 如果该额外数据存在并且为true说明正在进行同步操作
if (intent.getBooleanExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING, false)) {
// 从布局中获取id为R.id.prefenerece_sync_status_textview的TextView对象
TextView syncStatus = (TextView) findViewById(R.id.prefenerece_sync_status_textview);
// 将从Intent中获取的额外数据键为GTaskSyncService.GTASK_SERVICE_BROADCAST_PROGRESS_MSG设置为TextView的内容显示同步进度信息
syncStatus.setText(intent.getStringExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_PROGRESS_MSG));
}
}
}
// 定义一个公共的onOptionsItemSelected方法接收一个MenuItem对象作为参数返回一个boolean值
// 该方法用于处理菜单项的选择事件
public boolean onOptionsItemSelected(MenuItem item) {
// 根据选择的菜单项ID进行不同的处理
switch (item.getItemId()) {
// 如果选择的菜单项ID为android.R.id.home则执行以下操作
case android.R.id.home:
// 创建一个新的Intent对象目标Activity为NotesListActivity.class
Intent intent = new Intent(this, NotesListActivity.class);
// 向Intent对象添加一个标志位表示在启动新Activity之前先清除当前Activity的栈记录达到关闭当前Activity的效果
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// 启动目标Activity
startActivity(intent);
// 返回true表示该菜单项已被处理不再向下执行
return true;
// 如果选择的菜单项ID不属于android.R.id.home则返回false表示该菜单项未被处理继续向下执行其他菜单项的处理逻辑
default:
return false;
}
}
Loading…
Cancel
Save