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.

239 lines
9.5 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.
*/
/**
* 文件: NoteWidgetProvider.java
* 描述: 便签小部件提供者的抽象基类,定义了小部件的基本功能和行为
* 作用: 管理便签小部件的创建、更新和删除,处理小部件与便签数据的交互
*/
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;
/**
* 便签小部件提供者抽象基类
*
* 该类继承自AppWidgetProvider提供了便签小部件的基本功能实现
* 包括小部件的更新、删除等操作,以及与便签数据的交互逻辑。
* 具体的小部件类型如2x和4x需要继承此类并实现抽象方法。
*/
public abstract class NoteWidgetProvider extends AppWidgetProvider {
/**
* 查询便签数据的投影列
* 定义了从数据库查询便签时需要获取的列
*/
public static final String [] PROJECTION = new String [] {
NoteColumns.ID, // 便签ID
NoteColumns.BG_COLOR_ID, // 背景颜色ID
NoteColumns.SNIPPET // 便签内容摘要
};
/**
* 查询结果列索引常量
*/
public static final int COLUMN_ID = 0; // ID列索引
public static final int COLUMN_BG_COLOR_ID = 1; // 背景颜色ID列索引
public static final int COLUMN_SNIPPET = 2; // 内容摘要列索引
/**
* 日志标签
*/
private static final String TAG = "NoteWidgetProvider";
/**
* 当小部件被删除时调用
*
* 从数据库中清除被删除小部件的关联信息
*
* @param context 上下文环境
* @param appWidgetIds 被删除的小部件ID数组
*/
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
// 创建更新数据
ContentValues values = new ContentValues();
// 将小部件ID设置为无效值表示该便签不再与任何小部件关联
values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
// 遍历所有被删除的小部件ID
for (int i = 0; i < appWidgetIds.length; i++) {
// 更新数据库清除小部件ID与便签的关联
context.getContentResolver().update(Notes.CONTENT_NOTE_URI,
values,
NoteColumns.WIDGET_ID + "=?",
new String[] { String.valueOf(appWidgetIds[i])});
}
}
/**
* 获取与指定小部件ID关联的便签信息
*
* @param context 上下文环境
* @param widgetId 小部件ID
* @return 包含便签信息的Cursor对象如果没有找到则返回空Cursor
*/
private Cursor getNoteWidgetInfo(Context context, int widgetId) {
// 查询与指定小部件ID关联的便签数据
// 条件匹配小部件ID且不在回收站中
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);
}
/**
* 更新小部件
*
* 供子类调用的公共更新方法,默认非隐私模式
*
* @param context 上下文环境
* @param appWidgetManager 小部件管理器
* @param appWidgetIds 需要更新的小部件ID数组
*/
protected void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// 调用私有更新方法隐私模式设为false
update(context, appWidgetManager, appWidgetIds, false);
}
/**
* 更新小部件的私有实现
*
* 根据小部件ID更新对应的小部件显示内容和点击行为
*
* @param context 上下文环境
* @param appWidgetManager 小部件管理器
* @param appWidgetIds 需要更新的小部件ID数组
* @param privacyMode 是否为隐私模式,隐私模式下不显示便签内容
*/
private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds,
boolean privacyMode) {
// 遍历所有需要更新的小部件
for (int i = 0; i < appWidgetIds.length; i++) {
// 检查小部件ID是否有效
if (appWidgetIds[i] != AppWidgetManager.INVALID_APPWIDGET_ID) {
// 设置默认背景ID和空内容
int bgId = ResourceParser.getDefaultBgId(context);
String snippet = "";
// 创建打开便签编辑界面的Intent
Intent intent = new Intent(context, NoteEditActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_ID, appWidgetIds[i]);
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, getWidgetType());
// 获取与小部件关联的便签信息
Cursor c = getNoteWidgetInfo(context, appWidgetIds[i]);
if (c != null && c.moveToFirst()) {
// 检查是否有多个便签关联到同一个小部件ID异常情况
if (c.getCount() > 1) {
Log.e(TAG, "Multiple message with same widget id:" + appWidgetIds[i]);
c.close();
return;
}
// 提取便签内容和背景颜色
snippet = c.getString(COLUMN_SNIPPET);
bgId = c.getInt(COLUMN_BG_COLOR_ID);
// 设置Intent参数用于打开现有便签
intent.putExtra(Intent.EXTRA_UID, c.getLong(COLUMN_ID));
intent.setAction(Intent.ACTION_VIEW);
} else {
// 没有关联便签,设置默认提示文本
snippet = context.getResources().getString(R.string.widget_havenot_content);
// 设置Intent参数用于创建新便签
intent.setAction(Intent.ACTION_INSERT_OR_EDIT);
}
// 关闭游标
if (c != null) {
c.close();
}
// 创建远程视图并设置背景
RemoteViews rv = new RemoteViews(context.getPackageName(), getLayoutId());
rv.setImageViewResource(R.id.widget_bg_image, getBgResourceId(bgId));
intent.putExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, bgId);
/**
* 为小部件生成点击事件的PendingIntent
*/
PendingIntent pendingIntent = null;
if (privacyMode) {
// 隐私模式下,显示提示文本,点击打开便签列表
rv.setTextViewText(R.id.widget_text,
context.getString(R.string.widget_under_visit_mode));
pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], new Intent(
context, NotesListActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
} else {
// 正常模式下,显示便签内容,点击打开便签编辑界面
rv.setTextViewText(R.id.widget_text, snippet);
pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
// 设置点击事件
rv.setOnClickPendingIntent(R.id.widget_text, pendingIntent);
// 更新小部件
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
}
}
}
/**
* 获取背景资源ID
*
* 根据背景颜色ID获取对应的背景资源ID
* 子类需要实现此方法以提供不同尺寸小部件的背景资源
*
* @param bgId 背景颜色ID
* @return 对应的背景资源ID
*/
protected abstract int getBgResourceId(int bgId);
/**
* 获取布局ID
*
* 子类需要实现此方法以提供不同尺寸小部件的布局资源
*
* @return 小部件布局资源ID
*/
protected abstract int getLayoutId();
/**
* 获取小部件类型
*
* 子类需要实现此方法以提供小部件类型标识
*
* @return 小部件类型常量
*/
protected abstract int getWidgetType();
}