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.
2Q1/widget/NoteWidgetProvider.java

178 lines
13 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.widget;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.util.Log;
import android.widget.RemoteViews;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.tool.ResourceParser;
import net.micode.notes.ui.NoteEditActivity;
import net.micode.notes.ui.NotesListActivity;
// NoteWidgetProvider类是一个抽象类继承自AppWidgetProvider用于作为桌面小部件App Widget相关功能的基础类提供了一些通用的小部件操作逻辑以及定义了抽象方法供具体子类实现特定功能
public abstract class NoteWidgetProvider extends AppWidgetProvider {
// 定义一个字符串数组用于指定查询数据库时要获取的列信息这里包含笔记的ID、背景颜色ID以及摘要信息等列
public static final String [] PROJECTION = new String [] {
NoteColumns.ID,
NoteColumns.BG_COLOR_ID,
NoteColumns.SNIPPET
};
// 定义常量用于表示在查询结果中笔记ID所在的列索引位置方便后续从游标Cursor中获取对应的数据
public static final int COLUMN_ID = 0;
// 定义常量用于表示在查询结果中背景颜色ID所在的列索引位置方便后续从游标Cursor中获取对应的数据
public static final int COLUMN_BG_COLOR_ID = 1;
// 定义常量用于表示在查询结果中摘要信息所在的列索引位置方便后续从游标Cursor中获取对应的数据
public static final int COLUMN_SNIPPET = 2;
// 定义用于日志记录的标签,方便在日志输出中识别该类相关的日志信息
private static final String TAG = "NoteWidgetProvider";
// 当桌面小部件被删除时调用的方法,用于处理相关的数据清理等操作
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
// 创建一个ContentValues实例用于存储要更新到数据库中的数据
ContentValues values = new ContentValues();
// 将笔记相关列NoteColumns.WIDGET_ID的值设置为无效的小部件IDAppWidgetManager.INVALID_APPWIDGET_ID表示该笔记不再关联被删除的小部件
values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
// 遍历被删除的小部件ID数组
for (int i = 0; i < appWidgetIds.length; i++) {
// 通过内容解析器context.getContentResolver()更新笔记相关的内容提供器Notes.CONTENT_NOTE_URI中的数据使用设置好的ContentValues进行更新更新条件为笔记的小部件ID列等于当前遍历到的被删除小部件的ID
context.getContentResolver().update(Notes.CONTENT_NOTE_URI,
values,
NoteColumns.WIDGET_ID + "=?",
new String[] { String.valueOf(appWidgetIds[i])});
}
}
// 私有方法用于获取与指定小部件ID相关的笔记小部件信息通过查询数据库来获取相应的数据
private Cursor getNoteWidgetInfo(Context context, int widgetId) {
// 使用内容解析器发起查询操作查询的内容提供器为Notes.CONTENT_NOTE_URI指定要获取的列信息为之前定义的PROJECTION数组中的列查询条件为笔记的小部件ID等于传入的小部件ID且父ID不等于回收站文件夹的IDNotes.ID_TRASH_FOLER查询条件的参数通过字符串数组传入最后一个参数null表示不指定排序方式等额外条件
return context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION,
NoteColumns.WIDGET_ID + "=? AND " + NoteColumns.PARENT_ID + "<>?",
new String[] { String.valueOf(widgetId), String.valueOf(Notes.ID_TRASH_FOLER) },
null);
}
// 受保护的方法用于更新桌面小部件的显示内容等信息调用了另一个重载的update方法并传入默认参数false
protected void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
update(context, appWidgetManager, appWidgetIds, false);
}
// 私有方法用于实际更新桌面小部件的显示内容等信息根据传入的小部件ID数组对每个小部件进行相应的更新操作
private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds,
boolean privacyMode) {
// 遍历传入的小部件ID数组
for (int i = 0; i < appWidgetIds.length; i++) {
// 如果小部件ID不是无效的小部件IDAppWidgetManager.INVALID_APPWIDGET_ID才进行更新操作
if (appWidgetIds[i]!= AppWidgetManager.INVALID_APPWIDGET_ID) {
// 获取默认的背景颜色ID通过ResourceParser工具类的方法获取具体获取逻辑在该工具类中实现
int bgId = ResourceParser.getDefaultBgId(context);
// 初始化摘要信息为空字符串,后续会根据实际查询结果进行赋值
String snippet = "";
// 创建一个意图Intent指定要启动的目标Activity为NoteEditActivity.class即点击小部件后可能会跳转到的编辑笔记的Activity
Intent intent = new Intent(context, NoteEditActivity.class);
// 设置意图的标志位使得如果该Activity已经在栈顶则不会重新创建实例而是复用已有的实例例如避免重复打开同一个编辑页面等情况
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
// 将小部件的ID作为额外数据添加到意图中方便在目标Activity中获取并使用通过Notes.INTENT_EXTRA_WIDGET_ID键进行传递
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_ID, appWidgetIds[i]);
// 将小部件的类型作为额外数据添加到意图中具体的小部件类型由子类实现的getWidgetType方法获取并传入通过Notes.INTENT_EXTRA_WIDGET_TYPE键进行传递
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, getWidgetType());
// 获取与当前小部件ID相关的笔记小部件信息的游标Cursor通过调用getNoteWidgetInfo方法查询数据库获取
Cursor c = getNoteWidgetInfo(context, appWidgetIds[i]);
// 如果游标不为空且游标可以移动到第一条数据(表示查询到了相关数据)
if (c!= null && c.moveToFirst()) {
// 如果查询结果的数量大于1说明出现了同一个小部件ID关联多条消息的异常情况记录错误日志并关闭游标然后直接返回不进行后续更新操作
if (c.getCount() > 1) {
Log.e(TAG, "Multiple message with same widget id:" + appWidgetIds[i]);
c.close();
return;
}
// 获取摘要信息列的值赋值给snippet变量用于后续在小部件上显示
snippet = c.getString(COLUMN_SNIPPET);
// 获取背景颜色ID列的值赋值给bgId变量用于设置小部件的背景相关显示
bgId = c.getInt(COLUMN_BG_COLOR_ID);
// 将笔记的ID作为额外数据添加到意图中通过Intent.EXTRA_UID键传递方便在目标Activity中根据ID进行相应操作
intent.putExtra(Intent.EXTRA_UID, c.getLong(COLUMN_ID));
// 设置意图的动作Action为查看Intent.ACTION_VIEW表示点击小部件可能执行查看笔记的操作具体行为由目标Activity根据该动作进一步处理
intent.setAction(Intent.ACTION_VIEW);
} else {
// 如果游标为空或者没有查询到相关数据,设置摘要信息为资源字符串中对应的提示文本(表示小部件没有关联内容)
snippet = context.getResources().getString(R.string.widget_havenot_content);
// 设置意图的动作Action为插入或编辑Intent.ACTION_INSERT_OR_EDIT表示点击小部件可能执行新建或编辑笔记的操作具体行为由目标Activity根据该动作进一步处理
intent.setAction(Intent.ACTION_INSERT_OR_EDIT);
}
// 如果游标不为空,关闭游标,释放相关资源
if (c!= null) {
c.close();
}
// 创建一个RemoteViews实例用于构建桌面小部件的远程视图传入当前上下文的包名和具体的布局ID由子类实现的getLayoutId方法获取
RemoteViews rv = new RemoteViews(context.getPackageName(), getLayoutId());
// 设置小部件中背景图片资源的ID通过调用抽象方法getBgResourceId传入背景颜色ID来获取对应的资源ID进行设置
rv.setImageViewResource(R.id.widget_bg_image, getBgResourceId(bgId));
// 将背景颜色ID作为额外数据添加到意图中通过Notes.INTENT_EXTRA_BACKGROUND_ID键传递方便在目标Activity中根据背景颜色进行相应操作可能涉及界面显示等方面的适配
intent.putExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, bgId);
// 根据是否处于隐私模式privacyMode来生成不同的PendingIntent实例用于设置小部件点击事件的响应逻辑
PendingIntent pendingIntent = null;
if (privacyMode) {
// 如果处于隐私模式,设置小部件上文本显示为隐私模式相关的提示文本(通过资源字符串获取)
rv.setTextViewText(R.id.widget_text,
context.getString(R.string.widget_under_visit_mode));
// 创建一个PendingIntent用于启动NotesListActivity可能是进入某种隐私模式下的列表页面等操作传入当前上下文、小部件ID以及要启动的意图等参数并设置标志位为PendingIntent.FLAG_UPDATE_CURRENT表示如果已存在相同的PendingIntent则更新其额外数据等内容
pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], new Intent(
context, NotesListActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
} else {
// 如果不处于隐私模式设置小部件上文本显示为之前获取或设置的摘要信息snippet
rv.setTextViewText(R.id.widget_text, snippet);
// 创建一个PendingIntent用于启动之前设置的意图intent可能是跳转到编辑笔记等相关Activity传入当前上下文、小部件ID以及要启动的意图等参数并设置标志位为PendingIntent.FLAG_UPDATE_CURRENT表示如果已存在相同的PendingIntent则更新其额外数据等内容
pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
// 设置小部件中文本视图R.id.widget_text的点击事件响应PendingIntent即点击小部件上的文本区域时会触发相应的意图操作
rv.setOnClickPendingIntent(R.id.widget_text, pendingIntent);
// 通过AppWidgetManager更新指定小部件ID对应的小部件的远程视图实现小部件显示内容的更新
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
}
}
}
// 抽象方法用于获取与指定背景颜色ID对应的背景资源ID由具体的子类根据实际的资源映射关系来实现该方法以设置小部件的背景图片等显示相关资源
protected abstract int getBgResourceId(int bgId);
// 抽象方法用于获取小部件对应的布局资源ID由具体的子类根据不同类型小部件的布局需求来实现该方法以确定小部件的整体布局样式
protected abstract int getLayoutId();
// 抽象方法,用于获取小部件的类型,由具体的子类根据实际小部件的类型定义来实现该方法,以便在更新等操作中传递准确的小部件类型信息
protected abstract int getWidgetType();
}