/* * 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; // NotesPreferenceActivity类继承自PreferenceActivity,用于展示和管理应用的偏好设置相关界面及功能 public class NotesPreferenceActivity extends PreferenceActivity { // 定义偏好设置的名称常量,用于在获取和操作SharedPreferences时作为标识 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"; // 用于在偏好设置界面中对账户相关的偏好设置项进行分类管理的PreferenceCategory对象 private PreferenceCategory mAccountCategory; // 自定义的广播接收器对象,用于接收特定的广播消息(这里可能与同步服务相关的广播有关) private GTaskReceiver mReceiver; // 用于保存原始的账户列表信息,可能用于对比账户变化情况等操作 private Account[] mOriAccounts; // 用于标记是否添加了新账户的布尔变量,初始值为false private boolean mHasAddedAccount; // onCreate方法在Activity创建时被调用,用于进行初始化相关的操作 @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); // 设置ActionBar的显示属性,使得应用图标可以用于导航(通常点击图标可返回上一级界面) getActionBar().setDisplayHomeAsUpEnabled(true); // 从指定的XML资源文件(R.xml.preferences)中加载偏好设置界面的布局和配置信息,构建出偏好设置界面的初始显示内容 addPreferencesFromResource(R.xml.preferences); // 通过键(PREFERENCE_SYNC_ACCOUNT_KEY)从已加载的偏好设置中找到对应的PreferenceCategory对象,用于后续对账户相关设置项的操作 mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY); // 创建一个GTaskReceiver实例,用于接收相关广播消息 mReceiver = new GTaskReceiver(); // 创建一个IntentFilter对象,用于指定要接收的广播动作(这里只关注GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME对应的广播) IntentFilter filter = new IntentFilter(); filter.addAction(GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME); // 注册广播接收器,使得该Activity能够接收到符合过滤条件的广播消息 registerReceiver(mReceiver, filter); // 初始化原始账户列表为null,后续可能会获取并赋值实际的账户信息 mOriAccounts = null; // 通过LayoutInflater从当前上下文获取布局Inflater,并加载指定的布局资源(R.layout.settings_header)作为头部视图添加到当前Activity的列表视图中,第三个参数设置为true表示该头部视图在列表滚动时固定显示 View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null); getListView().addHeaderView(header, null, true); } // onResume方法在Activity重新回到前台可见状态时被调用,常用于恢复或更新界面相关的操作以及处理一些业务逻辑 @Override protected void onResume() { super.onResume(); // 如果已经添加了新账户(mHasAddedAccount为true) if (mHasAddedAccount) { // 获取当前的谷歌账户列表 Account[] accounts = getGoogleAccounts(); // 如果原始账户列表不为null且新获取的账户数量大于原始账户数量,说明可能添加了新账户 if (mOriAccounts!= null && accounts.length > mOriAccounts.length) { // 遍历新获取的账户列表 for (Account accountNew : accounts) { // 标记是否找到匹配的原始账户,初始化为false boolean found = false; // 遍历原始账户列表,对比账户名称是否相同 for (Account accountOld : mOriAccounts) { if (TextUtils.equals(accountOld.name, accountNew.name)) { found = true; break; } } // 如果在原始账户列表中未找到匹配的账户,说明是新添加的账户 if (!found) { // 设置同步账户为新添加的这个账户的名称,并跳出循环(只设置一个新账户作为同步账户即可,具体业务逻辑可能如此) setSyncAccount(accountNew.name); break; } } } } // 调用refreshUI方法更新界面显示内容,具体更新逻辑在该方法中实现(代码中未完整展示该方法内容) refreshUI(); } // 当Activity被销毁时调用的方法,用于释放相关资源和进行一些清理操作 @Override protected void onDestroy() { // 如果广播接收器(mReceiver)不为空,就注销该广播接收器,避免内存泄漏等问题 if (mReceiver!= null) { unregisterReceiver(mReceiver); } // 调用父类的onDestroy方法,执行父类中定义的销毁相关的默认操作 super.onDestroy(); } // 用于加载账户偏好设置相关内容的方法,例如在偏好设置界面中添加账户相关的设置项及设置其显示和点击等行为逻辑 private void loadAccountPreference() { // 先移除账户偏好设置分类(mAccountCategory)下的所有已有偏好设置项,确保后续添加的是最新的内容 mAccountCategory.removeAll(); // 创建一个新的Preference实例,用于表示账户相关的偏好设置项 Preference accountPref = new Preference(this); // 获取当前的默认同步账户名称(通过调用getSyncAccountName方法) 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) { // 如果同步服务(GTaskSyncService)当前没有正在进行同步操作 if (!GTaskSyncService.isSyncing()) { // 如果默认账户名称为空字符串,说明是第一次设置账户 if (TextUtils.isEmpty(defaultAccount)) { // 弹出选择账户的警告对话框,用于让用户选择要设置的账户(具体逻辑在showSelectAccountAlertDialog方法中) showSelectAccountAlertDialog(); } else { // 如果已经设置过账户了,弹出确认更改账户的警告对话框,提示用户更改账户可能存在的风险(具体逻辑在showChangeAccountConfirmAlertDialog方法中) showChangeAccountConfirmAlertDialog(); } } else { // 如果同步服务正在同步,通过Toast提示用户当前不能更改账户 Toast.makeText(NotesPreferenceActivity.this, R.string.preferences_toast_cannot_change_account, Toast.LENGTH_SHORT) .show(); } // 返回true表示已处理该点击事件 return true; } }); // 将创建并设置好的账户偏好设置项添加到账户偏好设置分类中 mAccountCategory.addPreference(accountPref); } // 用于加载同步按钮相关设置的方法,包括设置按钮的文本、点击事件以及同步状态相关的显示文本等内容 private void loadSyncButton() { // 通过findViewById方法找到布局中的同步按钮(Button)实例 Button syncButton = (Button) findViewById(R.id.preference_sync_button); // 通过findViewById方法找到布局中的用于显示上次同步时间的TextView实例 TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview); // 根据同步服务(GTaskSyncService)是否正在同步来设置同步按钮的文本和点击事件逻辑 // 如果正在同步 if (GTaskSyncService.isSyncing()) { // 设置按钮文本为取消同步的文本内容(通过资源字符串获取) syncButton.setText(getString(R.string.preferences_button_sync_cancel)); // 为按钮设置点击监听器,点击时调用GTaskSyncService的cancelSync方法来取消同步操作(传入当前的NotesPreferenceActivity实例作为上下文) syncButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { GTaskSyncService.cancelSync(NotesPreferenceActivity.this); } }); } else { // 如果没有正在同步 syncButton.setText(getString(R.string.preferences_button_sync_immediately)); // 为按钮设置点击监听器,点击时调用GTaskSyncService的startSync方法来立即启动同步操作(传入当前的NotesPreferenceActivity实例作为上下文) syncButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { GTaskSyncService.startSync(NotesPreferenceActivity.this); } }); } // 根据是否设置了同步账户来决定同步按钮是否可用,只有设置了同步账户(同步账户名称不为空字符串)时,按钮才可用 syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this))); // 根据同步服务的状态来设置上次同步时间显示文本及可见性 // 如果正在同步 if (GTaskSyncService.isSyncing()) { // 设置显示文本为同步服务的进度字符串(通过GTaskSyncService的getProgressString方法获取),并将该TextView设置为可见 lastSyncTimeView.setText(GTaskSyncService.getProgressString()); lastSyncTimeView.setVisibility(View.VISIBLE); } else { // 如果没有正在同步,获取上次同步的时间戳(通过调用getLastSyncTime方法) long lastSyncTime = getLastSyncTime(this); // 如果上次同步时间戳不为0,说明有上次同步记录 if (lastSyncTime!= 0) { // 设置显示文本,通过格式化字符串的方式将时间戳格式化为指定格式的日期时间字符串(先通过资源字符串获取日期时间格式,再进行格式化),并将该TextView设置为可见 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 { // 如果没有上次同步记录,将该TextView设置为不可见 lastSyncTimeView.setVisibility(View.GONE); } } } // 用于刷新整个偏好设置界面的方法,通过调用加载账户偏好设置和加载同步按钮相关的方法来更新界面显示内容 private void refreshUI() { loadAccountPreference(); loadSyncButton(); } // 用于弹出选择账户的警告对话框的方法,在该对话框中展示可供选择的账户列表以及添加账户的入口等内容 private void showSelectAccountAlertDialog() { // 创建一个AlertDialog.Builder实例,用于构建警告对话框 AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); // 通过LayoutInflater从当前上下文加载自定义的标题布局(R.layout.account_dialog_title) View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null); // 从加载的标题布局中找到对应的标题TextView实例 TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title); // 设置标题TextView的文本内容,通过资源字符串获取对应的文本 titleTextView.setText(getString(R.string.preferences_dialog_select_account_title)); // 从加载的标题布局中找到对应的副标题TextView实例 TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle); // 设置副标题TextView的文本内容,通过资源字符串获取对应的文本 subtitleTextView.setText(getString(R.string.preferences_dialog_select_account_tips)); // 将自定义的标题视图设置为对话框的标题部分 dialogBuilder.setCustomTitle(titleView); // 设置对话框的确认按钮(正按钮),这里先设置为null,后续可能会根据具体逻辑再设置(或者在某些情况下不需要点击操作) dialogBuilder.setPositiveButton(null, null); // 获取当前的谷歌账户列表(通过调用getGoogleAccounts方法) Account[] accounts = getGoogleAccounts(); // 获取当前的默认同步账户名称(通过调用getSyncAccountName方法) String defAccount = getSyncAccountName(this); // 将获取的账户列表保存到mOriAccounts变量中,用于后续可能的对比等操作 mOriAccounts = accounts; // 标记是否添加了新账户,初始化为false mHasAddedAccount = false; // 如果获取到的账户列表长度大于0,说明有可用的账户可供选择 if (accounts.length > 0) { // 创建一个字符序列数组,长度与账户列表长度相同,用于存储账户名称,作为单选列表项展示给用户 CharSequence[] items = new CharSequence[accounts.length]; // 创建一个临时的字符序列数组,用于在点击单选列表项时进行账户名称的映射操作(这里其实和items数组内容基本一致,只是为了方便后续代码逻辑理解和编写) final CharSequence[] itemMapping = items; // 用于记录默认选中的账户在列表中的索引位置,初始化为 -1,表示没有默认选中项 int checkedItem = -1; // 索引变量,用于遍历账户列表并填充items数组以及查找默认选中项的索引 int index = 0; // 遍历账户列表 for (Account account : accounts) { // 如果当前账户名称与默认同步账户名称相等,说明该账户是当前默认选中的账户,记录其索引位置 if (TextUtils.equals(account.name, defAccount)) { checkedItem = index; } // 将账户名称添加到items数组中,作为单选列表项的显示内容 items[index++] = account.name; } // 设置对话框的单选列表项内容、默认选中项索引以及点击监听器,当用户点击某个单选列表项时,调用setSyncAccount方法设置选中的账户作为同步账户,然后关闭对话框,并刷新界面(通过调用refreshUI方法) dialogBuilder.setSingleChoiceItems(items, checkedItem, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { setSyncAccount(itemMapping[which].toString()); dialog.dismiss(); refreshUI(); } }); } // 通过LayoutInflater从当前上下文加载添加账户相关的布局(R.layout.add_account_text),用于在对话框中展示添加账户的入口视图 View addAccountView = LayoutInflater.from(this).inflate(R.layout.add_account_text, null); // 将添加账户的入口视图添加到对话框中 dialogBuilder.setView(addAccountView); // 显示构建好的警告对话框,并获取对话框实例 final AlertDialog dialog = dialogBuilder.show(); // 为添加账户的入口视图设置点击监听器,当用户点击时,标记已添加新账户(mHasAddedAccount设置为true),然后启动添加账户的系统设置页面(通过意图指定相关动作和参数),最后关闭当前对话框 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); // 通过LayoutInflater从当前上下文加载自定义的标题布局(R.layout.account_dialog_title) View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null); // 从加载的标题布局中找到对应的标题TextView实例 TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title); // 设置标题TextView的文本内容,通过资源字符串获取对应的格式化文本,其中格式化参数为当前的同步账户名称(通过调用getSyncAccountName方法获取) titleTextView.setText(getString(R.string.preferences_dialog_change_account_title, getSyncAccountName(this))); // 从加载的标题布局中找到对应的副标题TextView实例 TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle); // 设置副标题TextView的文本内容,通过资源字符串获取对应的警告提示文本 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) { // 如果用户点击的是“更改账户”菜单项(索引为0) if (which == 0) { // 弹出选择账户的警告对话框(通过调用showSelectAccountAlertDialog方法),让用户重新选择账户 showSelectAccountAlertDialog(); } else if (which == 1) { // 如果用户点击的是“移除账户”菜单项(索引为1),则调用removeSyncAccount方法移除当前的同步账户,并刷新界面(通过调用refreshUI方法) removeSyncAccount(); refreshUI(); } } }); // 显示构建好的警告对话框 dialogBuilder.show(); } // 用于获取当前设备上的谷歌账户列表的方法,通过AccountManager来获取指定类型("com.google")的账户信息 private Account[] getGoogleAccounts() { // 获取AccountManager实例,传入当前上下文 AccountManager accountManager = AccountManager.get(this); // 调用AccountManager的getAccountsByType方法获取类型为"com.google"的账户数组并返回 return accountManager.getAccountsByType("com.google"); } // 用于设置同步账户的方法,根据传入的账户名称来更新偏好设置中的同步账户相关信息,并进行一些相关的数据清理和提示操作 private void setSyncAccount(String account) { // 如果传入的账户与当前获取的同步账户名称不一致(说明要进行账户更改操作) if (!getSyncAccountName(this).equals(account)) { // 获取应用的SharedPreferences实例,用于存储和读取偏好设置数据,指定偏好设置名称(PREFERENCE_NAME)和私有访问模式(Context.MODE_PRIVATE) SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); // 获取SharedPreferences的编辑器,用于修改偏好设置中的数据 SharedPreferences.Editor editor = settings.edit(); // 如果传入的账户不为null,将其存入偏好设置中对应的键(PREFERENCE_SYNC_ACCOUNT_NAME)下 if (account!= null) { editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, account); } else { // 如果传入的账户为null,将同步账户名称设置为空字符串 editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); } // 提交对偏好设置的修改,使其生效 editor.commit(); // 调用setLastSyncTime方法将上次同步时间清理(设置为0),表示重新开始同步相关的计时等逻辑 setLastSyncTime(this, 0); // 在一个新线程中执行清理本地与GTask相关信息的操作,创建一个ContentValues实例用于存储要更新的数据 new Thread(new Runnable() { public void run() { ContentValues values = new ContentValues(); // 将笔记相关列(NoteColumns.GTASK_ID)的值设置为空字符串,可能用于清除之前与该账户关联的同步任务相关标识 values.put(NoteColumns.GTASK_ID, ""); // 将同步相关列(NoteColumns.SYNC_ID)的值设置为0,可能用于重置同步相关的状态标识 values.put(NoteColumns.SYNC_ID, 0); // 通过内容解析器(getContentResolver)更新笔记相关的内容提供器(Notes.CONTENT_NOTE_URI)中的数据,使用设置好的ContentValues进行更新,这里更新条件为null(可能是更新所有符合条件的数据,具体需看内容提供器的实现逻辑) getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); } }).start(); // 通过Toast提示用户账户设置成功,显示的文本通过资源字符串获取,并传入设置的账户名称作为格式化参数 Toast.makeText(NotesPreferenceActivity.this, getString(R.string.preferences_toast_success_set_accout, account), Toast.LENGTH_SHORT).show(); } } // 用于移除同步账户的方法,从偏好设置中移除同步账户相关的信息,并清理本地与GTask相关的信息 private void removeSyncAccount() { // 获取应用的SharedPreferences实例,用于存储和读取偏好设置数据,指定偏好设置名称(PREFERENCE_NAME)和私有访问模式(Context.MODE_PRIVATE) SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); // 获取SharedPreferences的编辑器,用于修改偏好设置中的数据 SharedPreferences.Editor editor = settings.edit(); // 如果偏好设置中包含同步账户名称相关的键(PREFERENCE_SYNC_ACCOUNT_NAME),则移除该键对应的值 if (settings.contains(PREFERENCE_SYNC_ACCOUNT_NAME)) { editor.remove(PREFERENCE_SYNC_ACCOUNT_NAME); } // 如果偏好设置中包含上次同步时间相关的键(PREFERENCE_LAST_SYNC_TIME),则移除该键对应的值 if (settings.contains(PREFERENCE_LAST_SYNC_TIME)) { editor.remove(PREFERENCE_LAST_SYNC_TIME); } // 提交对偏好设置的修改,使其生效 editor.commit(); // 在一个新线程中执行清理本地与GTask相关信息的操作,创建一个ContentValues实例用于存储要更新的数据 new Thread(new Runnable() { public void run() { ContentValues values = new ContentValues(); // 将笔记相关列(NoteColumns.GTASK_ID)的值设置为空字符串,可能用于清除之前与该账户关联的同步任务相关标识 values.put(NoteColumns.GTASK_ID, ""); // 将同步相关列(NoteColumns.SYNC_ID)的值设置为0,可能用于重置同步相关的状态标识 values.put(NoteColumns.SYNC_ID, 0); // 通过内容解析器(getContentResolver)更新笔记相关的内容提供器(Notes.CONTENT_NOTE_URI)中的数据,使用设置好的ContentValues进行更新,这里更新条件为null(可能是更新所有符合条件的数据,具体需看内容提供器的实现逻辑) getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); } }).start(); } // 静态方法,用于获取当前设置的同步账户名称,从应用的SharedPreferences中读取对应键(PREFERENCE_SYNC_ACCOUNT_NAME)下存储的值,如果不存在则返回空字符串 public static String getSyncAccountName(Context context) { SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); } // 静态方法,用于设置上次同步时间,将指定的时间戳(time)存入应用的SharedPreferences中对应的键(PREFERENCE_LAST_SYNC_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(); } // 静态方法,用于获取上次同步时间,从应用的SharedPreferences中读取对应键(PREFERENCE_LAST_SYNC_TIME)下存储的时间戳,如果不存在则返回0 public static long getLastSyncTime(Context context) { SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0); } // 自定义的广播接收器类,继承自BroadcastReceiver,用于接收特定的广播消息并做出相应的响应 private class GTaskReceiver extends BroadcastReceiver { // 当接收到广播消息时调用的方法,在这里进行界面刷新以及根据广播中的同步相关信息更新界面显示内容等操作 @Override public void onReceive(Context context, Intent intent) { // 调用refreshUI方法刷新整个偏好设置界面,更新界面上的各种显示内容(如账户信息、同步按钮状态等) refreshUI(); // 如果广播消息中携带的表示是否正在同步的额外数据(通过GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING键获取)为true,说明正在同步 if (intent.getBooleanExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING, false)) { // 通过findViewById方法找到用于显示同步状态的TextView实例 TextView syncStatus = (TextView) findViewById(R.id.prefenerece_sync_status_textview); // 设置该TextView的文本内容为广播消息中携带的同步进度相关信息(通过GTaskSyncService.GTASK_SERVICE_BROADCAST_PROGRESS_MSG键获取) syncStatus.setText(intent.getStringExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_PROGRESS_MSG)); } } } // 用于处理选项菜单中菜单项被选中时的操作逻辑,例如处理返回按钮等菜单项的点击事件 public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { // 如果点击的是Home按钮(通常是左上角的返回箭头图标,用于返回上一级界面等操作) case android.R.id.home: // 创建一个意图(Intent),指定要启动的目标Activity为NotesListActivity.class,即返回笔记列表界面 Intent intent = new Intent(this, NotesListActivity.class); // 添加标志位,使得启动的Activity会清除其上的所有其他Activity,实现返回栈的清理,回到笔记列表界面并将其置于栈顶 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // 根据意图启动Activity startActivity(intent); // 返回true表示已处理该菜单项点击事件 return true; default: // 如果点击的是其他未处理的菜单项,返回false,表示未处理该事件 return false; } } }