/* * 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. */ // 包声明,表明该类属于 net.micode.notes.ui 包 package net.micode.notes.ui; // 导入用于处理账户相关操作的类 import android.accounts.Account; import android.accounts.AccountManager; // 导入用于操作 ActionBar 的类 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; // 导入用于保存和恢复 Activity 状态的类 import android.os.Bundle; // 导入偏好设置项类 import android.preference.Preference; // 导入偏好设置项点击事件监听器接口 import android.preference.Preference.OnPreferenceClickListener; // 导入偏好设置 Activity 类 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; // 导入 Google 任务同步服务类 import net.micode.notes.gtask.remote.GTaskSyncService; // 定义 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"; // 定义账户权限过滤键 private static final String AUTHORITIES_FILTER_KEY = "authorities"; // 定义同步账户偏好设置分类对象 private PreferenceCategory mAccountCategory; // 定义 Google 任务广播接收器对象 private GTaskReceiver mReceiver; // 定义原始账户数组 private Account[] mOriAccounts; // 定义是否添加了新账户的标志 private boolean mHasAddedAccount; // Activity 创建时调用的方法 @Override protected void onCreate(Bundle icicle) { // 调用父类的 onCreate 方法 super.onCreate(icicle); // 设置 ActionBar 可通过应用图标导航回上级页面 getActionBar().setDisplayHomeAsUpEnabled(true); // 从 XML 文件中加载偏好设置 addPreferencesFromResource(R.xml.preferences); // 通过键查找同步账户偏好设置分类对象 mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY); // 创建 Google 任务广播接收器对象 mReceiver = new GTaskReceiver(); // 创建意图过滤器对象 IntentFilter filter = new IntentFilter(); // 添加要接收的广播动作 filter.addAction(GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME); // 注册广播接收器 registerReceiver(mReceiver, filter); // 初始化原始账户数组为 null mOriAccounts = null; // 从布局文件中加载头部视图 View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null); // 将头部视图添加到列表视图中 getListView().addHeaderView(header, null, true); } // Activity 恢复时调用的方法 @Override protected void onResume() { // 调用父类的 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; } } } } // 刷新界面 refreshUI(); } // Activity 销毁时调用的方法 @Override protected void onDestroy() { // 如果广播接收器不为空 if (mReceiver != null) { // 注销广播接收器 unregisterReceiver(mReceiver); } // 调用父类的 onDestroy 方法 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)) { // 显示选择账户的对话框 showSelectAccountAlertDialog(); } else { // 如果账户已经设置,显示更改账户的确认对话框 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() { // 通过 ID 查找同步按钮 Button syncButton = (Button) findViewById(R.id.preference_sync_button); // 通过 ID 查找最后同步时间显示的文本视图 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); } } } // 刷新界面的方法 private void refreshUI() { // 加载同步账户偏好设置项 loadAccountPreference(); // 加载同步按钮和最后同步时间显示 loadSyncButton(); } // 显示选择账户对话框的方法 private void showSelectAccountAlertDialog() { // 创建对话框构建器对象 AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); // 从布局文件中加载对话框标题视图 View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null); // 通过 ID 查找对话框标题文本视图 TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title); // 设置对话框标题文本 titleTextView.setText(getString(R.string.preferences_dialog_select_account_title)); // 通过 ID 查找对话框副标题文本视图 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 账户数组 Account[] accounts = getGoogleAccounts(); // 获取默认同步账户名称 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 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); // 通过 ID 查找对话框标题文本视图 TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title); // 设置对话框标题文本,包含当前同步账户名称 titleTextView.setText(getString(R.string.preferences_dialog_change_account_title, getSyncAccountName(this))); // 通过 ID 查找对话框副标题文本视图 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) { // 显示选择账户对话框 showSelectAccountAlertDialog(); } else if (which == 1) { // 如果点击的是移除账户菜单项,移除同步账户 removeSyncAccount(); // 刷新界面 refreshUI(); } } }); // 显示对话框 dialogBuilder.show(); } // 获取 Google 账户数组的方法 private Account[] getGoogleAccounts() { // 获取账户管理器对象 AccountManager accountManager = AccountManager.get(this); // 通过账户类型获取 Google 账户数组 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(); // 清除最后同步时间 setLastSyncTime(this, 0); // 开启一个新线程清理本地 Google 任务相关信息 new Thread(new Runnable() { public void run() { // 创建内容值对象 ContentValues values = new ContentValues(); // 将 Google 任务 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(); // 显示设置账户成功的提示信息 Toast.makeText(NotesPreferenceActivity.this, getString(R.string.preferences_toast_success_set_accout, account), Toast.LENGTH_SHORT).show(); } } // 移除同步账户的方法 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(); // 开启一个新线程清理本地 Google 任务相关信息 new Thread(new Runnable() { public void run() { // 创建内容值对象 ContentValues values = new ContentValues(); // 将 Google 任务 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(); } // 获取同步账户名称的静态方法 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); // 从偏好设置中获取最后同步时间,默认为 0 return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0); } // 定义 Google 任务广播接收器内部类 private class GTaskReceiver extends BroadcastReceiver { // 接收到广播时调用的方法 @Override public void onReceive(Context context, Intent intent) { // 刷新界面 refreshUI(); // 如果广播中包含正在同步的标志 if (intent.getBooleanExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING, false)) { // 通过 ID 查找同步状态文本视图 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) { // 根据菜单项的 ID 进行不同处理 switch (item.getItemId()) { // 如果点击的是返回上级页面的菜单项 case android.R.id.home: // 创建启动笔记列表 Activity 的意图 Intent intent = new Intent(this, NotesListActivity.class); // 添加清除顶部 Activity 的标志 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // 启动笔记列表 Activity startActivity(intent); return true; // 默认情况 default: return false; } } }