/* * 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; // 导入用于操作 Android 应用中的 ActionBar(顶部导航栏)功能 import android.app.ActionBar; // 导入用于显示和管理弹出对话框的类 import android.app.AlertDialog; // 导入用于接收广播消息的类 import android.content.BroadcastReceiver; // 导入用于在 ContentProvider 中存储和插入数据的类 import android.content.ContentValues; // 导入 Android 应用的上下文类,用于访问全局应用信息和资源 import android.content.Context; // 导入用于显示和管理对话框按钮点击事件的接口 import android.content.DialogInterface; // 导入用于启动新活动或广播的 Intent 类 import android.content.Intent; // 导入用于过滤广播消息的 IntentFilter 类 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; // 导入常用的 UI 控件类,如按钮、文本视图和弹出提示框 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; 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); // 使用应用图标作为导航栏的“向上”按钮 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); 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(); // 如果添加了新账户,则尝试自动设置同步账户 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(); } @Override protected void onDestroy() { // 如果 mReceiver 已初始化,则注销广播接收器,防止内存泄漏 if (mReceiver != null) { unregisterReceiver(mReceiver); } // 调用父类的 onDestroy,确保正确销毁 Activity super.onDestroy(); } private void loadAccountPreference() { // 清空当前账户类别中的所有项 mAccountCategory.removeAll(); // 创建一个新的 Preference 用于账户设置 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() { // 获取同步按钮和最后同步时间的文本视图 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); 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); 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 账户列表 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) { // 选择账户后,设置同步账户,并刷新 UI 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(); // 关闭当前对话框 } }); } 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 实例,用于构建弹出的确认对话框 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) // 取消选项 }; // 为菜单选项设置点击事件监听器 dialogBuilder.setItems(menuItemArray, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (which == 0) { // 如果用户选择了 "更改账户" showSelectAccountAlertDialog(); // 显示选择账户的对话框 } else if (which == 1) { // 如果用户选择了 "删除账户" removeSyncAccount(); // 删除当前同步的账户 refreshUI(); // 刷新 UI,更新界面 } } }); // 显示对话框 dialogBuilder.show(); } // 获取所有Google账户 private Account[] getGoogleAccounts() { // 获取 AccountManager 实例,这个对象用来管理设备上的账户 AccountManager accountManager = AccountManager.get(this); // 返回所有Google账户,"com.google" 表示Google账户类型 return accountManager.getAccountsByType("com.google"); } // 设置同步账户 private void setSyncAccount(String account) { // 如果新设置的账户与当前同步账户不同 if (!getSyncAccountName(this).equals(account)) { // 获取 SharedPreferences,用于保存同步账户的配置信息 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(); // 清除上次同步时间(将其设置为0) setLastSyncTime(this, 0); // 清除与Google任务相关的本地信息 new Thread(new Runnable() { public void run() { // 创建一个 ContentValues 对象来更新 Google 任务相关的字段 ContentValues values = new ContentValues(); values.put(NoteColumns.GTASK_ID, ""); // 清除任务ID values.put(NoteColumns.SYNC_ID, 0); // 清除同步ID // 更新 Notes 内容提供者中的数据,清除与同步相关的信息 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,删除同步账户设置 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 对象来更新 Google 任务相关的字段 ContentValues values = new ContentValues(); values.put(NoteColumns.GTASK_ID, ""); // 清除任务ID values.put(NoteColumns.SYNC_ID, 0); // 清除同步ID // 更新 Notes 内容提供者中的数据,清除与同步相关的信息 getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); } }).start(); } // 获取同步账户名称 public static String getSyncAccountName(Context context) { // 获取 SharedPreferences 实例,存储同步账户名称 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 实例,存储同步信息 SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); // 获取 SharedPreferences 的编辑器,用于修改存储的数据 SharedPreferences.Editor editor = settings.edit(); // 将时间值存储到 PREFERENCE_LAST_SYNC_TIME 键中 editor.putLong(PREFERENCE_LAST_SYNC_TIME, time); // 提交更改 editor.commit(); } // 获取上次同步时间 public static long getLastSyncTime(Context context) { // 获取 SharedPreferences 实例,读取同步信息 SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); // 获取上次同步时间,如果没有保存则返回 0(表示没有同步) return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0); } // 广播接收器,用于接收来自 GTaskSyncService 的广播消息 private class GTaskReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 刷新UI显示 refreshUI(); // 检查是否正在同步 if (intent.getBooleanExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING, false)) { // 获取同步状态显示的 TextView 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()) { // 点击返回按钮,返回到 NotesListActivity case android.R.id.home: // 创建返回 Intent,设置标志位清除栈顶活动 Intent intent = new Intent(this, NotesListActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // 启动 NotesListActivity startActivity(intent); return true; default: // 如果没有匹配的菜单项,返回 false return false; } } }