Update NoteWidgetProvider.java

main
mxvwfs5gq 2 months ago
parent 8f98bc42b8
commit fb895eb777

@ -15,6 +15,7 @@
*/
package net.micode.notes.widget;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
@ -22,6 +23,7 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
import android.widget.RemoteViews;
@ -32,101 +34,344 @@ import net.micode.notes.tool.ResourceParser;
import net.micode.notes.ui.NoteEditActivity;
import net.micode.notes.ui.NotesListActivity;
/**
*
*
* :
* 1.
* 2.
* 3.
* 4.
*
*
* - getBgResourceId() : ID
* - getLayoutId() : ID
* - getWidgetType() :
*/
public abstract class NoteWidgetProvider extends AppWidgetProvider {
public static final String [] PROJECTION = new String [] {
// 数据库查询字段
private static final String[] PROJECTION = new String[] {
NoteColumns.ID,
NoteColumns.BG_COLOR_ID,
NoteColumns.SNIPPET
NoteColumns.SNIPPET,
NoteColumns.WIDGET_ID // 添加字段用于数据一致性检查
};
public static final int COLUMN_ID = 0;
public static final int COLUMN_BG_COLOR_ID = 1;
public static final int COLUMN_SNIPPET = 2;
// 查询字段索引
private static final int COLUMN_ID = 0;
private static final int COLUMN_BG_COLOR_ID = 1;
private static final int COLUMN_SNIPPET = 2;
private static final int COLUMN_WIDGET_ID = 3; // 添加的索引
private static final String TAG = "NoteWidgetProvider";
// ========================== 生命周期方法 ==========================
/**
* - widget_id
*
* @param context
* @param appWidgetIds ID
*/
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
ContentValues values = new ContentValues();
values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
for (int i = 0; i < appWidgetIds.length; i++) {
context.getContentResolver().update(Notes.CONTENT_NOTE_URI,
values,
NoteColumns.WIDGET_ID + "=?",
new String[] { String.valueOf(appWidgetIds[i])});
try {
// 防止空指针异常
if (context == null || appWidgetIds == null || appWidgetIds.length == 0) {
Log.w(TAG, "无效的小部件删除请求");
return;
}
ContentValues values = new ContentValues();
values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
for (int widgetId : appWidgetIds) {
// 使用try-catch防止个别更新失败中断整个操作
try {
int rowsUpdated = context.getContentResolver().update(
Notes.CONTENT_NOTE_URI,
values,
NoteColumns.WIDGET_ID + "=?",
new String[] { String.valueOf(widgetId) }
);
Log.d(TAG, "已清理小部件 " + widgetId + " 关联的笔记引用,影响行数: " + rowsUpdated);
} catch (Exception e) {
Log.e(TAG, "清理小部件 " + widgetId + " 关联的笔记引用时出错", e);
}
}
} catch (Exception e) {
Log.e(TAG, "小部件删除处理发生未预期错误", e);
}
}
private Cursor getNoteWidgetInfo(Context context, int widgetId) {
return context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
// ========================== 核心功能方法 ==========================
/**
*
*
* @param context
* @param widgetId ID
* @return Cursor
*/
protected Cursor getNoteWidgetInfo(Context context, int widgetId) {
if (context == null || widgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
return null;
}
String selection = NoteColumns.WIDGET_ID + "=? AND " + NoteColumns.PARENT_ID + "<>?";
String[] selectionArgs = new String[] {
String.valueOf(widgetId),
String.valueOf(Notes.ID_TRASH_FOLDER) // 修正: TRASH_FOLER -> TRASH_FOLDER
};
try {
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);
selection,
selectionArgs,
null
);
} catch (Exception e) {
Log.e(TAG, "查询小部件 " + widgetId + " 关联笔记信息时出错", e);
return null;
}
}
/**
* -
*
* @param context
* @param appWidgetManager
* @param appWidgetIds ID
*/
protected void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
update(context, appWidgetManager, appWidgetIds, false);
}
/**
* -
*
* @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++) {
if (appWidgetIds[i] != AppWidgetManager.INVALID_APPWIDGET_ID) {
int bgId = ResourceParser.getDefaultBgId(context);
String snippet = "";
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()) {
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.putExtra(Intent.EXTRA_UID, c.getLong(COLUMN_ID));
intent.setAction(Intent.ACTION_VIEW);
} else {
snippet = context.getResources().getString(R.string.widget_havenot_content);
intent.setAction(Intent.ACTION_INSERT_OR_EDIT);
}
if (context == null || appWidgetManager == null || appWidgetIds == null) {
Log.w(TAG, "无效的更新请求参数");
return;
}
for (int widgetId : appWidgetIds) {
// 跳过无效小部件ID
if (widgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
continue;
}
if (c != null) {
c.close();
}
// 初始化默认值
int bgId = ResourceParser.NoteColor.YELLOW.id;
String snippet = "";
long noteId = Notes.DEFAULT_NOTE_ID;
// 准备笔记编辑意图
Intent noteIntent = new Intent(context, NoteEditActivity.class);
noteIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
noteIntent.putExtra(Notes.INTENT_EXTRA_WIDGET_ID, widgetId);
noteIntent.putExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, getWidgetType());
RemoteViews rv = new RemoteViews(context.getPackageName(), getLayoutId());
rv.setImageViewResource(R.id.widget_bg_image, getBgResourceId(bgId));
intent.putExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, bgId);
/**
* Generate the pending intent to start host for the widget
*/
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);
// 查询数据库获取笔记信息
try (Cursor cursor = getNoteWidgetInfo(context, widgetId)) {
if (cursor != null && cursor.moveToFirst()) {
// 安全检查确保一个WidgetID只关联一个笔记
if (cursor.getCount() > 1) {
Log.w(TAG, "小部件 " + widgetId + " 关联多个笔记,请检查数据一致性");
// 清除异常关联的笔记
cleanInvalidWidgetLinks(context, widgetId, cursor);
// 只处理第一条记录
}
// 获取笔记数据
noteId = cursor.getLong(COLUMN_ID);
snippet = cursor.getString(COLUMN_SNIPPET);
bgId = cursor.getInt(COLUMN_BG_COLOR_ID);
noteIntent.putExtra(Intent.EXTRA_UID, noteId);
noteIntent.setAction(Intent.ACTION_VIEW);
// 检查数据一致性
int storedWidgetId = cursor.getInt(COLUMN_WIDGET_ID);
if (storedWidgetId != widgetId) {
Log.w(TAG, String.format(
"笔记%d的小部件ID不一致: 数据库=%d, 请求=%d",
noteId, storedWidgetId, widgetId
));
}
} else {
rv.setTextViewText(R.id.widget_text, snippet);
pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// 未找到关联笔记
snippet = context.getString(R.string.widget_no_content);
noteIntent.setAction(Intent.ACTION_INSERT_OR_EDIT);
}
} catch (Exception e) {
Log.e(TAG, "处理小部件 " + widgetId + " 时发生错误", e);
snippet = context.getString(R.string.widget_error_loading);
}
rv.setOnClickPendingIntent(R.id.widget_text, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
// 创建小部件视图
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), getLayoutId());
// 设置背景
int bgResId = getBgResourceId(bgId);
remoteViews.setImageViewResource(R.id.widget_bg_image, bgResId);
noteIntent.putExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, bgId);
// 创建点击意图
PendingIntent pendingIntent;
if (privacyMode) {
// 隐私模式:显示提示文本,点击进入主列表
remoteViews.setTextViewText(R.id.widget_text,
context.getString(R.string.widget_privacy_mode));
Intent listIntent = new Intent(context, NotesListActivity.class);
pendingIntent = PendingIntent.getActivity(
context, widgetId, listIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
} else {
// 正常模式:显示笔记摘要,点击进入笔记编辑
remoteViews.setTextViewText(R.id.widget_text, snippet);
pendingIntent = PendingIntent.getActivity(
context, widgetId, noteIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
}
// 设置点击事件
remoteViews.setOnClickPendingIntent(R.id.widget_text, pendingIntent);
// 应用更新
try {
appWidgetManager.updateAppWidget(widgetId, remoteViews);
Log.d(TAG, "成功更新小部件: " + widgetId);
} catch (Exception e) {
Log.e(TAG, "更新小部件 " + widgetId + " 失败", e);
}
}
}
// ========================== 抽象方法 ==========================
/**
* ID
*
* @param bgId ID
* @return drawableID
*/
protected abstract int getBgResourceId(int bgId);
/**
* ID
*
* @return ID
*/
protected abstract int getLayoutId();
/**
*
*
* @return
*/
protected abstract int getWidgetType();
}
// ========================== 新增功能方法 ==========================
/**
*
*
* @param context
* @param widgetId ID
* @param cursor
*/
private void cleanInvalidWidgetLinks(Context context, int widgetId, Cursor cursor) {
if (cursor == null) return;
ContentValues values = new ContentValues();
values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
try {
// 遍历所有关联笔记
cursor.moveToPosition(-1); // 移动到开始位置
while (cursor.moveToNext()) {
long currentNoteId = cursor.getLong(COLUMN_ID);
int currentWidgetId = cursor.getInt(COLUMN_WIDGET_ID);
// 只保留最新关联的笔记
if (currentWidgetId == widgetId) {
Log.i(TAG, "保留笔记 " + currentNoteId + " 关联的小部件 " + widgetId);
continue;
}
// 解除其他笔记的关联
Uri noteUri = ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, currentNoteId);
int rows = context.getContentResolver().update(
noteUri, values, null, null);
if (rows > 0) {
Log.w(TAG, "已清理笔记 " + currentNoteId + " 上的小部件关联");
}
}
} catch (Exception e) {
Log.e(TAG, "清理无效小部件关联时出错", e);
}
}
// ========================== 新增功能:定时刷新支持 ==========================
/**
*
*
* @param context
* @param appWidgetId ID
* @param intervalMinutes
*/
public static void setUpdateInterval(Context context, int appWidgetId, int intervalMinutes) {
// 最小间隔限制
if (intervalMinutes < 15) {
Log.w(TAG, "刷新间隔不能小于15分钟");
intervalMinutes = 60; // 默认1小时
}
// TODO: 实现AlarmManager定时刷新逻辑
}
// ========================== 新增功能:多尺寸小部件支持 ==========================
/**
*
*/
public enum WidgetSize {
SIZE_1X1,
SIZE_2X1,
SIZE_2X2,
SIZE_3X3
}
/**
*
*
* @param context
* @param appWidgetId ID
* @return
*/
protected WidgetSize getWidgetSize(Context context, int appWidgetId) {
// TODO: 实现小部件尺寸检测逻辑
return WidgetSize.SIZE_2X1; // 默认返回2x1
}
}
Loading…
Cancel
Save