You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gitProject/app/src/main/java/net/micode/notes/ui/NotesPreferenceActivity.java

411 lines
23 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 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.accounts.Account;
import android.accounts.AccountManager;
import android.app.ActionBar;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
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 {// 定义了一个常量字符串 PREFERENCE_NAME表示 SharedPreferences 的名称
public static final String PREFERENCE_NAME = "notes_preferences";// 定义了一个常量字符串 PREFERENCE_SYNC_ACCOUNT_NAME表示同步账户名称的键名
public static final String PREFERENCE_SYNC_ACCOUNT_NAME = "pref_key_account_name";// 定义了一个常量字符串 PREFERENCE_LAST_SYNC_TIME表示上一次同步时间的键名
public static final String PREFERENCE_LAST_SYNC_TIME = "pref_last_sync_time";// 定义了一个常量字符串 PREFERENCE_SET_BG_COLOR_KEY表示是否随机设置背景颜色的键名
public static final String PREFERENCE_SET_BG_COLOR_KEY = "pref_key_bg_random_appear";// 定义了一个常量字符串 PREFERENCE_SYNC_ACCOUNT_KEY表示同步账户的键名
private static final String PREFERENCE_SYNC_ACCOUNT_KEY = "pref_sync_account_key";// 定义了一个常量字符串 PREFERENCE_SYNC_ACCOUNT_KEY表示同步账户的键名
private static final String AUTHORITIES_FILTER_KEY = "authorities";// 定义了一个常量字符串 AUTHORITIES_FILTER_KEY表示过滤器的 authorities 键名
private PreferenceCategory mAccountCategory;// 声明了一个 PreferenceCategory 类型的成员变量 mAccountCategory表示账户分类
private GTaskReceiver mReceiver;// 声明了一个 GTaskReceiver 类型的成员变量 mReceiver表示 GTask 接收器
private Account[] mOriAccounts;// 声明了一个 Account 数组类型的成员变量 mOriAccounts表示原始账户
private boolean mHasAddedAccount;// 声明了一个 boolean 类型的成员变量 mHasAddedAccount表示是否已添加了账户
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
/* using the app icon for navigation */
getActionBar().setDisplayHomeAsUpEnabled(true);
addPreferencesFromResource(R.xml.preferences);// 加载 preferences.xml 文件中的 Preference
mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY);// 从 preferences.xml 中找到同步账户分类,赋值给 mAccountCategory
mReceiver = new GTaskReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME);
registerReceiver(mReceiver, filter);// 注册 GTaskReceiver 广播接收器,监听 Gtask 同步服务的消息
mOriAccounts = null;
View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null);
getListView().addHeaderView(header, null, true);//将原始账户数组 mOriAccounts 设置为 null。
}
@Override
protected void onResume() {
super.onResume();// onStart 方法,表示 Activity 启动时调用的方
// 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();
}/*1. 调用父类的 onCreate() 方法,初始化 Activity。
2. 设置应用图标作为导航按钮以便用户可以返回上一个Activity或者返回应用的主界面。
3. 加载 preferences.xml 文件中的 Preference。
4. 从 preferences.xml 中找到同步账户分类,赋值给 mAccountCategory。
5. 注册 GTaskReceiver 广播接收器,监听 GTask 同步服务的消息。
6. 将原始账户数组 mOriAccounts 设置为 null。
7. 通过 LayoutInflater 加载一个设置界面的头部布局 R.layout.settings_header。
8. 将头部布局添加到 ListView 的头部。
这段代码的作用是初始化设置界面,并设置导航按钮、注册广播接收器、加载头部布局。*/
@Override
protected void onDestroy() {
if (mReceiver != null) {
unregisterReceiver(mReceiver);
}
super.onDestroy();
}/*这段代码是 Android 中的一个 Activity 的 onDestroy() 方法,主要进行了以下操作:
1. 判断 mReceiver 是否为 null如果不为 null则解除广播接收器的注册。
2. 调用父类的 onDestroy() 方法,销毁 Activity。
这段代码的目的是在 Activity 销毁时,解除之前注册的广播接收器,以避免出现内存泄漏的情况。在 Android 中,如果不及时解除广播接收器的注册,会导致广播接收器持有 Activity 的引用而无法被垃圾回收,从而导致内存泄漏。因此,在 Activity销毁前需要手动解除广播接收器的注册以确保程序的正常运行和内存的释放。*/
private void loadAccountPreference() {
mAccountCategory.removeAll();// 清空同步账户分类中的所有设置项
Preference accountPref = new Preference(this);// 创建一个新的 Preference 对象 accountPref
final String defaultAccount = getSyncAccountName(this);// 获取当前默认的同步账户名称
accountPref.setTitle(getString(R.string.preferences_account_title));// 设置 accountPref 的标题和摘要
accountPref.setSummary(getString(R.string.preferences_account_summary)); // 设置 accountPref 的点击事件监听器
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;// 返回 true表示点击事件已被处理
}
});
mAccountCategory.addPreference(accountPref);// 将 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);
}
}
}// 如果没有正在同步任务则获取上次同步时间并根据上次同步时间是否为0来设置上次同步时间视图的可见状态和文本内容
private void refreshUI() {
loadAccountPreference();
loadSyncButton();
}/*loadAccountPreference() 方法用于加载和显示当前同步账户的信息,而 loadSyncButton() 方法则用于设置同步按钮的状态和点击事件监听器,并显示上次同步时间的信息。*/
private void showSelectAccountAlertDialog() {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);// 创建 AlertDialog.Builder 对象
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;
mHasAddedAccount = false;// 保存原始账户列表并将“已添加账户”标志设为 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;
}// 如果该账户的名称与当前同步账户的名称相同,则将其作为默认选中项
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();// 刷新 UI 界面上的账户和同步按钮状态
}
});
}
View addAccountView = LayoutInflater.from(this).inflate(R.layout.add_account_text, null);//从布局文件中加载一个视图对象并将其赋值给 addAccountView 变量
dialogBuilder.setView(addAccountView);//将 addAccountView 设置为对话框的自定义视图
final AlertDialog dialog = dialogBuilder.show();//创建一个 AlertDialog 对象,并将其显示出来
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 对象,用于启动一个系统设置界面,以便让用户添加新的帐户
startActivityForResult(intent, -1);//启动一个新的界面,等待用户添加新的账户
dialog.dismiss();//关闭对话框
}
});
}
private void showChangeAccountConfirmAlertDialog() {
// 创建一个 AlertDialog.Builder 对象
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
// 从布局文件 R.layout.account_dialog_title 中加载一个视图 titleView
View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null);
// 从 titleView 中找到一个 TextView 对象 titleTextView并设置其文本
TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title);
titleTextView.setText(getString(R.string.preferences_dialog_change_account_title,
getSyncAccountName(this)));
// 从 titleView 中找到一个 TextView 对象 subtitleTextView并设置其文本
TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle);
subtitleTextView.setText(getString(R.string.preferences_dialog_change_account_warn_msg));
// 将 titleView 设置为对话框的自定义标题
dialogBuilder.setCustomTitle(titleView);
// 创建一个 CharSequence 类型的数组 menuItemArray包含三个字符串作为选项菜单的标签文字
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() { // 创建一个 DialogInterface.OnClickListener 对象,用于处理选项菜单的点击事件
public void onClick(DialogInterface dialog, int which) {// 判断点击了哪个菜单项
if (which == 0) {
showSelectAccountAlertDialog();// 如果点击了第一个菜单项,调用 showSelectAccountAlertDialog() 方法显示“选择帐户”对话框
} else if (which == 1) {
removeSyncAccount();
refreshUI();// 如果点击了第二个菜单项,先调用 removeSyncAccount() 方法删除同步帐户,再调用 refreshUI() 方法刷新界面
}
}
});
dialogBuilder.show();// 显示对话框
}
private Account[] getGoogleAccounts() {
// 获取 AccountManager 对象
AccountManager accountManager = AccountManager.get(this);
// 调用 getAccountsByType() 方法,传入参数 "com.google",以获取所有类型为 "com.google" 的帐户
return accountManager.getAccountsByType("com.google");
}
private void setSyncAccount(String account) {
if (!getSyncAccountName(this).equals(account)) {// 判断传入的 account 是否与当前同步帐户相同
SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();// 获取 SharedPreferences 对象
if (account != null) {
editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, account); // 如果传入的 account 不为 null则将其存储到 SharedPreferences 中
} else {
editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, "");// 如果传入的 account 为 null则将空字符串存储到 SharedPreferences 中
}
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(); // 创建一个 ContentValues 对象,用于更新所有的 note
values.put(NoteColumns.GTASK_ID, "");// 清空 GTasks ID 和 sync ID
values.put(NoteColumns.SYNC_ID, 0);// 清空 GTasks ID 和 sync ID
getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); // 更新所有的 note
}
}).start();
Toast.makeText(NotesPreferenceActivity.this,
getString(R.string.preferences_toast_success_set_accout, account),
Toast.LENGTH_SHORT).show();// 显示一个 Toast提示同步帐户设置成功
}
}
private void removeSyncAccount() {
SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); // 获取 SharedPreferences 对象
SharedPreferences.Editor editor = settings.edit();// 获取 SharedPreferences 对象
if (settings.contains(PREFERENCE_SYNC_ACCOUNT_NAME)) {
editor.remove(PREFERENCE_SYNC_ACCOUNT_NAME);
}// 如果 SharedPreferences 包含同步帐户名称,则从 SharedPreferences 中删除该名称
if (settings.contains(PREFERENCE_LAST_SYNC_TIME)) {
editor.remove(PREFERENCE_LAST_SYNC_TIME); // 如果 SharedPreferences 包含上一次同步的时间,则从 SharedPreferences 中删除该时间
}
editor.commit(); // 提交修改
// clean up local gtask related info
new Thread(new Runnable() {
public void run() {
ContentValues values = new ContentValues();// 创建一个 ContentValues 对象,用于更新所有的 note
values.put(NoteColumns.GTASK_ID, "");
values.put(NoteColumns.SYNC_ID, 0); // 清空 GTasks ID 和 sync ID
getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null);
}
}).start();// 更新所有的 note
}
public static String getSyncAccountName(Context context) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,// 获取 SharedPreferences 对象
Context.MODE_PRIVATE);
return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, "");// 从 SharedPreferences 中获取同步帐户名称
}
public static void setLastSyncTime(Context context, long time) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit(); // 获取 SharedPreferences 对象
editor.putLong(PREFERENCE_LAST_SYNC_TIME, time);// 将最后一次同步的时间保存到 SharedPreferences 中
editor.commit();// 提交修改
}
public static long getLastSyncTime(Context context) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);// 获取 SharedPreferences 对象
return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0);// 从 SharedPreferences 中获取最后一次同步的时间
}
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; // 创建一个 Intent 对象,跳转到 NotesListActivity并清除之前的所有 Activity
default:
return false;// 如果选择的菜单项不是返回主页,则返回 false
}
}
}