|
|
|
@ -0,0 +1,801 @@
|
|
|
|
|
1.对于gtask->remote
|
|
|
|
|
/*
|
|
|
|
|
* 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.gtask.remote;
|
|
|
|
|
|
|
|
|
|
import android.app.Activity;
|
|
|
|
|
import android.app.Service;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.content.Intent;
|
|
|
|
|
import android.os.Bundle;
|
|
|
|
|
import android.os.IBinder;
|
|
|
|
|
|
|
|
|
|
public class GTaskSyncService extends Service {
|
|
|
|
|
// 用于在 Intent 中传递同步动作类型的键名
|
|
|
|
|
public final static String ACTION_STRING_NAME = "sync_action_type";
|
|
|
|
|
// 启动同步的动作类型
|
|
|
|
|
public final static int ACTION_START_SYNC = 0;
|
|
|
|
|
// 取消同步的动作类型
|
|
|
|
|
public final static int ACTION_CANCEL_SYNC = 1;
|
|
|
|
|
// 无效动作类型
|
|
|
|
|
public final static int ACTION_INVALID = 2;
|
|
|
|
|
// 广播的名称,用于发送同步状态和进度信息
|
|
|
|
|
public final static String GTASK_SERVICE_BROADCAST_NAME = "net.micode.notes.gtask.remote.gtask_sync_service";
|
|
|
|
|
// 广播中表示是否正在同步的键名
|
|
|
|
|
public final static String GTASK_SERVICE_BROADCAST_IS_SYNCING = "isSyncing";
|
|
|
|
|
// 广播中表示同步进度消息的键名
|
|
|
|
|
public final static String GTASK_SERVICE_BROADCAST_PROGRESS_MSG = "progressMsg";
|
|
|
|
|
|
|
|
|
|
// 用于执行同步任务的异步任务实例
|
|
|
|
|
private static GTaskASyncTask mSyncTask = null;
|
|
|
|
|
// 存储同步进度消息
|
|
|
|
|
private static String mSyncProgress = "";
|
|
|
|
|
|
|
|
|
|
// 启动同步的方法
|
|
|
|
|
private void startSync() {
|
|
|
|
|
// 如果同步任务未在运行
|
|
|
|
|
if (mSyncTask == null) {
|
|
|
|
|
// 创建一个新的同步任务实例,并传入上下文和完成监听器
|
|
|
|
|
mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() {
|
|
|
|
|
public void onComplete() {
|
|
|
|
|
// 同步完成后,将任务实例置为 null
|
|
|
|
|
mSyncTask = null;
|
|
|
|
|
// 发送广播,通知同步已完成
|
|
|
|
|
sendBroadcast("");
|
|
|
|
|
// 停止服务
|
|
|
|
|
stopSelf();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
// 发送广播,通知同步开始
|
|
|
|
|
sendBroadcast("");
|
|
|
|
|
// 执行同步任务
|
|
|
|
|
mSyncTask.execute();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 取消同步的方法
|
|
|
|
|
private void cancelSync() {
|
|
|
|
|
// 如果同步任务正在运行
|
|
|
|
|
if (mSyncTask != null) {
|
|
|
|
|
// 调用取消同步的方法
|
|
|
|
|
mSyncTask.cancelSync();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 服务创建时调用的方法
|
|
|
|
|
@Override
|
|
|
|
|
public void onCreate() {
|
|
|
|
|
// 初始化同步任务实例为 null
|
|
|
|
|
mSyncTask = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 服务启动时调用的方法
|
|
|
|
|
@Override
|
|
|
|
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
|
|
|
|
// 获取 Intent 中的额外数据
|
|
|
|
|
Bundle bundle = intent.getExtras();
|
|
|
|
|
if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) {
|
|
|
|
|
// 根据传入的动作类型执行相应操作
|
|
|
|
|
switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) {
|
|
|
|
|
case ACTION_START_SYNC:
|
|
|
|
|
// 启动同步
|
|
|
|
|
startSync();
|
|
|
|
|
break;
|
|
|
|
|
case ACTION_CANCEL_SYNC:
|
|
|
|
|
// 取消同步
|
|
|
|
|
cancelSync();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// 服务被杀死后会自动重启
|
|
|
|
|
return START_STICKY;
|
|
|
|
|
}
|
|
|
|
|
return super.onStartCommand(intent, flags, startId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 系统内存不足时调用的方法
|
|
|
|
|
@Override
|
|
|
|
|
public void onLowMemory() {
|
|
|
|
|
// 如果同步任务正在运行
|
|
|
|
|
if (mSyncTask != null) {
|
|
|
|
|
// 取消同步任务
|
|
|
|
|
mSyncTask.cancelSync();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 绑定服务时调用的方法,这里返回 null 表示不支持绑定
|
|
|
|
|
public IBinder onBind(Intent intent) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 发送广播的方法,用于通知同步状态和进度
|
|
|
|
|
public void sendBroadcast(String msg) {
|
|
|
|
|
// 更新同步进度消息
|
|
|
|
|
mSyncProgress = msg;
|
|
|
|
|
// 创建一个广播 Intent
|
|
|
|
|
Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME);
|
|
|
|
|
// 添加是否正在同步的信息
|
|
|
|
|
intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null);
|
|
|
|
|
// 添加同步进度消息
|
|
|
|
|
intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg);
|
|
|
|
|
// 发送广播
|
|
|
|
|
sendBroadcast(intent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 静态方法,用于启动同步服务
|
|
|
|
|
public static void startSync(Activity activity) {
|
|
|
|
|
// 设置 GTaskManager 的活动上下文
|
|
|
|
|
GTaskManager.getInstance().setActivityContext(activity);
|
|
|
|
|
// 创建一个启动服务的 Intent
|
|
|
|
|
Intent intent = new Intent(activity, GTaskSyncService.class);
|
|
|
|
|
// 添加启动同步的动作类型
|
|
|
|
|
intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC);
|
|
|
|
|
// 启动服务
|
|
|
|
|
activity.startService(intent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 静态方法,用于取消同步服务
|
|
|
|
|
public static void cancelSync(Context context) {
|
|
|
|
|
// 创建一个启动服务的 Intent
|
|
|
|
|
Intent intent = new Intent(context, GTaskSyncService.class);
|
|
|
|
|
// 添加取消同步的动作类型
|
|
|
|
|
intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC);
|
|
|
|
|
// 启动服务
|
|
|
|
|
context.startService(intent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 静态方法,用于检查是否正在同步
|
|
|
|
|
public static boolean isSyncing() {
|
|
|
|
|
return mSyncTask != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 静态方法,用于获取同步进度消息
|
|
|
|
|
public static String getProgressString() {
|
|
|
|
|
return mSyncProgress;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* 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.gtask.remote;
|
|
|
|
|
|
|
|
|
|
import android.app.Notification;
|
|
|
|
|
import android.app.NotificationManager;
|
|
|
|
|
import android.app.PendingIntent;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.content.Intent;
|
|
|
|
|
import android.os.AsyncTask;
|
|
|
|
|
|
|
|
|
|
import net.micode.notes.R;
|
|
|
|
|
import net.micode.notes.ui.NotesListActivity;
|
|
|
|
|
import net.micode.notes.ui.NotesPreferenceActivity;
|
|
|
|
|
|
|
|
|
|
public class GTaskASyncTask extends AsyncTask<Void, String, Integer> {
|
|
|
|
|
// 同步通知的 ID
|
|
|
|
|
private static int GTASK_SYNC_NOTIFICATION_ID = 5234235;
|
|
|
|
|
|
|
|
|
|
// 同步完成监听器接口
|
|
|
|
|
public interface OnCompleteListener {
|
|
|
|
|
void onComplete();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 上下文对象
|
|
|
|
|
private Context mContext;
|
|
|
|
|
// 通知管理器
|
|
|
|
|
private NotificationManager mNotifiManager;
|
|
|
|
|
// GTaskManager 实例
|
|
|
|
|
private GTaskManager mTaskManager;
|
|
|
|
|
// 同步完成监听器
|
|
|
|
|
private OnCompleteListener mOnCompleteListener;
|
|
|
|
|
|
|
|
|
|
// 构造函数,初始化上下文、监听器、通知管理器和 GTaskManager
|
|
|
|
|
public GTaskASyncTask(Context context, OnCompleteListener listener) {
|
|
|
|
|
mContext = context;
|
|
|
|
|
mOnCompleteListener = listener;
|
|
|
|
|
mNotifiManager = (NotificationManager) mContext
|
|
|
|
|
.getSystemService(Context.NOTIFICATION_SERVICE);
|
|
|
|
|
mTaskManager = GTaskManager.getInstance();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 取消同步的方法
|
|
|
|
|
public void cancelSync() {
|
|
|
|
|
// 调用 GTaskManager 的取消同步方法
|
|
|
|
|
mTaskManager.cancelSync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 发布同步进度的方法
|
|
|
|
|
public void publishProgess(String message) {
|
|
|
|
|
// 调用 AsyncTask 的 publishProgress 方法发布进度
|
|
|
|
|
publishProgress(new String[] {
|
|
|
|
|
message
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 显示通知的方法
|
|
|
|
|
private void showNotification(int tickerId, String content) {
|
|
|
|
|
PendingIntent pendingIntent;
|
|
|
|
|
// 根据通知类型设置不同的 PendingIntent
|
|
|
|
|
if (tickerId != R.string.ticker_success) {
|
|
|
|
|
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
|
|
|
|
|
NotesPreferenceActivity.class), PendingIntent.FLAG_IMMUTABLE);
|
|
|
|
|
} else {
|
|
|
|
|
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
|
|
|
|
|
NotesListActivity.class), PendingIntent.FLAG_IMMUTABLE);
|
|
|
|
|
}
|
|
|
|
|
// 创建通知构建器
|
|
|
|
|
Notification.Builder builder = new Notification.Builder(mContext)
|
|
|
|
|
.setAutoCancel(true)
|
|
|
|
|
.setContentTitle(mContext.getString(R.string.app_name))
|
|
|
|
|
.setContentText(content)
|
|
|
|
|
.setContentIntent(pendingIntent)
|
|
|
|
|
.setWhen(System.currentTimeMillis())
|
|
|
|
|
.setOngoing(true);
|
|
|
|
|
// 获取通知实例
|
|
|
|
|
Notification notification = builder.getNotification();
|
|
|
|
|
// 发送通知
|
|
|
|
|
mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 异步任务在后台执行的方法
|
|
|
|
|
@Override
|
|
|
|
|
protected Integer doInBackground(Void... unused) {
|
|
|
|
|
// 发布正在登录的进度消息
|
|
|
|
|
publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity
|
|
|
|
|
.getSyncAccountName(mContext)));
|
|
|
|
|
// 调用 GTaskManager 的同步方法进行同步
|
|
|
|
|
return mTaskManager.sync(mContext, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 异步任务进度更新时调用的方法
|
|
|
|
|
@Override
|
|
|
|
|
protected void onProgressUpdate(String... progress) {
|
|
|
|
|
// 显示同步中的通知
|
|
|
|
|
showNotification(R.string.ticker_syncing, progress[0]);
|
|
|
|
|
// 如果上下文是 GTaskSyncService 类型
|
|
|
|
|
if (mContext instanceof GTaskSyncService) {
|
|
|
|
|
// 调用 GTaskSyncService 的发送广播方法
|
|
|
|
|
((GTaskSyncService) mContext).sendBroadcast(progress[0]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 异步任务完成后调用的方法
|
|
|
|
|
@Override
|
|
|
|
|
protected void onPostExecute(Integer result) {
|
|
|
|
|
// 根据同步结果显示不同的通知
|
|
|
|
|
if (result == GTaskManager.STATE_SUCCESS) {
|
|
|
|
|
showNotification(R.string.ticker_success, mContext.getString(
|
|
|
|
|
R.string.success_sync_account, mTaskManager.getSyncAccount()));
|
|
|
|
|
// 设置最后同步时间
|
|
|
|
|
NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis());
|
|
|
|
|
} else if (result == GTaskManager.STATE_NETWORK_ERROR) {
|
|
|
|
|
showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_network));
|
|
|
|
|
} else if (result == GTaskManager.STATE_INTERNAL_ERROR) {
|
|
|
|
|
showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal));
|
|
|
|
|
} else if (result == GTaskManager.STATE_SYNC_CANCELLED) {
|
|
|
|
|
showNotification(R.string.ticker_cancel, mContext
|
|
|
|
|
.getString(R.string.error_sync_cancelled));
|
|
|
|
|
}
|
|
|
|
|
// 如果监听器不为空
|
|
|
|
|
if (mOnCompleteListener != null) {
|
|
|
|
|
// 启动一个新线程调用监听器的完成方法
|
|
|
|
|
new Thread(new Runnable() {
|
|
|
|
|
public void run() {
|
|
|
|
|
mOnCompleteListener.onComplete();
|
|
|
|
|
}
|
|
|
|
|
}).start();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* 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.gtask.remote;
|
|
|
|
|
|
|
|
|
|
import android.app.Activity;
|
|
|
|
|
import android.content.ContentResolver;
|
|
|
|
|
import android.content.ContentUris;
|
|
|
|
|
import android.content.ContentValues;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.database.Cursor;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
|
|
import net.micode.notes.R;
|
|
|
|
|
import net.micode.notes.data.Notes;
|
|
|
|
|
import net.micode.notes.data.Notes.DataColumns;
|
|
|
|
|
import net.micode.notes.data.Notes.NoteColumns;
|
|
|
|
|
import net.micode.notes.gtask.data.MetaData;
|
|
|
|
|
import net.micode.notes.gtask.data.Node;
|
|
|
|
|
import net.micode.notes.gtask.data.SqlNote;
|
|
|
|
|
import net.micode.notes.gtask.data.Task;
|
|
|
|
|
import net.micode.notes.gtask.data.TaskList;
|
|
|
|
|
import net.micode.notes.gtask.exception.ActionFailureException;
|
|
|
|
|
import net.micode.notes.gtask.exception.NetworkFailureException;
|
|
|
|
|
import net.micode.notes.tool.DataUtils;
|
|
|
|
|
import net.micode.notes.tool.GTaskStringUtils;
|
|
|
|
|
|
|
|
|
|
import org.json.JSONArray;
|
|
|
|
|
import org.json.JSONException;
|
|
|
|
|
import org.json.JSONObject;
|
|
|
|
|
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
import java.util.Iterator;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
public class GTaskManager {
|
|
|
|
|
// 日志标签
|
|
|
|
|
private static final String TAG = GTaskManager.class.getSimpleName();
|
|
|
|
|
// 同步成功状态
|
|
|
|
|
public static final int STATE_SUCCESS = 0;
|
|
|
|
|
// 网络错误状态
|
|
|
|
|
public static final int STATE_NETWORK_ERROR = 1;
|
|
|
|
|
// 内部错误状态
|
|
|
|
|
public static final int STATE_INTERNAL_ERROR = 2;
|
|
|
|
|
// 同步正在进行状态
|
|
|
|
|
public static final int STATE_SYNC_IN_PROGRESS = 3;
|
|
|
|
|
// 同步取消状态
|
|
|
|
|
public static final int STATE_SYNC_CANCELLED = 4;
|
|
|
|
|
// 单例实例
|
|
|
|
|
private static GTaskManager mInstance = null;
|
|
|
|
|
// 活动上下文
|
|
|
|
|
private Activity mActivity;
|
|
|
|
|
// 上下文
|
|
|
|
|
private Context mContext;
|
|
|
|
|
// 内容解析器
|
|
|
|
|
private ContentResolver mContentResolver;
|
|
|
|
|
// 是否正在同步的标志
|
|
|
|
|
private boolean mSyncing;
|
|
|
|
|
// 是否取消同步的标志
|
|
|
|
|
private boolean mCancelled;
|
|
|
|
|
// 存储任务列表的哈希表
|
|
|
|
|
private HashMap<String, TaskList> mGTaskListHashMap;
|
|
|
|
|
// 存储任务节点的哈希表
|
|
|
|
|
private HashMap<String, Node> mGTaskHashMap;
|
|
|
|
|
// 存储元数据的哈希表
|
|
|
|
|
private HashMap<String, MetaData> mMetaHashMap;
|
|
|
|
|
// 元数据任务列表
|
|
|
|
|
private TaskList mMetaList;
|
|
|
|
|
// 存储本地已删除笔记 ID 的集合
|
|
|
|
|
private HashSet<Long> mLocalDeleteIdMap;
|
|
|
|
|
// 存储 Google 任务 ID 到本地笔记 ID 的映射
|
|
|
|
|
private HashMap<String, Long> mGidToNid;
|
|
|
|
|
// 存储本地笔记 ID 到 Google 任务 ID 的映射
|
|
|
|
|
private HashMap<Long, String> mNidToGid;
|
|
|
|
|
|
|
|
|
|
// 私有构造函数,实现单例模式
|
|
|
|
|
private GTaskManager() {
|
|
|
|
|
mSyncing = false;
|
|
|
|
|
mCancelled = false;
|
|
|
|
|
mGTaskListHashMap = new HashMap<String, TaskList>();
|
|
|
|
|
mGTaskHashMap = new HashMap<String, Node>();
|
|
|
|
|
mMetaHashMap = new HashMap<String, MetaData>();
|
|
|
|
|
mMetaList = null;
|
|
|
|
|
mLocalDeleteIdMap = new HashSet<Long>();
|
|
|
|
|
mGidToNid = new HashMap<String, Long>();
|
|
|
|
|
mNidToGid = new HashMap<Long, String>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取单例实例的方法
|
|
|
|
|
public static synchronized GTaskManager getInstance() {
|
|
|
|
|
if (mInstance == null) {
|
|
|
|
|
mInstance = new GTaskManager();
|
|
|
|
|
}
|
|
|
|
|
return mInstance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置活动上下文的方法
|
|
|
|
|
public synchronized void setActivityContext(Activity activity) {
|
|
|
|
|
// 用于获取认证令牌
|
|
|
|
|
mActivity = activity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 同步方法
|
|
|
|
|
public int sync(Context context, GTaskASyncTask asyncTask) {
|
|
|
|
|
// 如果正在同步,返回同步进行中的状态
|
|
|
|
|
if (mSyncing) {
|
|
|
|
|
Log.d(TAG, "Sync is in progress");
|
|
|
|
|
return STATE_SYNC_IN_PROGRESS;
|
|
|
|
|
}
|
|
|
|
|
mContext = context;
|
|
|
|
|
mContentResolver = mContext.getContentResolver();
|
|
|
|
|
mSyncing = true;
|
|
|
|
|
mCancelled = false;
|
|
|
|
|
// 清空各种存储数据的集合
|
|
|
|
|
mGTaskListHashMap.clear();
|
|
|
|
|
mGTaskHashMap.clear();
|
|
|
|
|
mMetaHashMap.clear();
|
|
|
|
|
mLocalDeleteIdMap.clear();
|
|
|
|
|
mGidToNid.clear();
|
|
|
|
|
mNidTo
|
|
|
|
|
2.对于widget
|
|
|
|
|
/*
|
|
|
|
|
* 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,用于处理便签小部件的通用逻辑。
|
|
|
|
|
* 它提供了更新小部件和处理小部件删除的方法,同时定义了一些抽象方法供子类实现。
|
|
|
|
|
*/
|
|
|
|
|
public abstract class NoteWidgetProvider extends AppWidgetProvider {
|
|
|
|
|
// 查询便签信息时使用的投影,指定要查询的列
|
|
|
|
|
public static final String [] PROJECTION = new String [] {
|
|
|
|
|
NoteColumns.ID,
|
|
|
|
|
NoteColumns.BG_COLOR_ID,
|
|
|
|
|
NoteColumns.SNIPPET
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 投影中各列的索引
|
|
|
|
|
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 String TAG = "NoteWidgetProvider";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 当一个或多个小部件被删除时调用此方法。
|
|
|
|
|
* 此方法会将对应小部件 ID 的便签的 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);
|
|
|
|
|
// 遍历所有被删除的小部件 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 获取便签小部件的信息。
|
|
|
|
|
* 从数据库中查询指定小部件 ID 且不在回收站的便签信息。
|
|
|
|
|
*
|
|
|
|
|
* @param context 应用程序上下文
|
|
|
|
|
* @param widgetId 小部件的 ID
|
|
|
|
|
* @return 包含查询结果的 Cursor 对象
|
|
|
|
|
*/
|
|
|
|
|
private Cursor getNoteWidgetInfo(Context context, int widgetId) {
|
|
|
|
|
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) {
|
|
|
|
|
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) {
|
|
|
|
|
// 遍历所有要更新的小部件 ID
|
|
|
|
|
for (int i = 0; i < appWidgetIds.length; i++) {
|
|
|
|
|
if (appWidgetIds[i] != AppWidgetManager.INVALID_APPWIDGET_ID) {
|
|
|
|
|
// 默认背景颜色 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) {
|
|
|
|
|
// 记录错误日志,当出现多个相同小部件 ID 的便签时
|
|
|
|
|
Log.e(TAG, "Multiple message with same widget id:" + appWidgetIds[i]);
|
|
|
|
|
c.close();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// 获取便签摘要
|
|
|
|
|
snippet = c.getString(COLUMN_SNIPPET);
|
|
|
|
|
// 获取背景颜色 ID
|
|
|
|
|
bgId = c.getInt(COLUMN_BG_COLOR_ID);
|
|
|
|
|
// 设置意图的额外数据,包括便签的 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 (c != null) {
|
|
|
|
|
c.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建 RemoteViews 对象,用于更新小部件的视图
|
|
|
|
|
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。
|
|
|
|
|
* 此方法为抽象方法,需要子类实现。
|
|
|
|
|
*
|
|
|
|
|
* @param bgId 背景颜色 ID
|
|
|
|
|
* @return 背景资源 ID
|
|
|
|
|
*/
|
|
|
|
|
protected abstract int getBgResourceId(int bgId);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取小部件的布局资源 ID。
|
|
|
|
|
* 此方法为抽象方法,需要子类实现。
|
|
|
|
|
*
|
|
|
|
|
* @return 布局资源 ID
|
|
|
|
|
*/
|
|
|
|
|
protected abstract int getLayoutId();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取小部件的类型。
|
|
|
|
|
* 此方法为抽象方法,需要子类实现。
|
|
|
|
|
*
|
|
|
|
|
* @return 小部件的类型
|
|
|
|
|
*/
|
|
|
|
|
protected abstract int getWidgetType();
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* 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.appwidget.AppWidgetManager;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
|
|
|
|
|
import net.micode.notes.R;
|
|
|
|
|
import net.micode.notes.data.Notes;
|
|
|
|
|
import net.micode.notes.tool.ResourceParser;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* NoteWidgetProvider_2x 是 NoteWidgetProvider 的子类,用于处理 2x 大小的便签小部件。
|
|
|
|
|
*/
|
|
|
|
|
public class NoteWidgetProvider_2x extends NoteWidgetProvider {
|
|
|
|
|
/**
|
|
|
|
|
* 当小部件需要更新时调用此方法。
|
|
|
|
|
* 调用父类的 update 方法来更新小部件。
|
|
|
|
|
*
|
|
|
|
|
* @param context 应用程序上下文
|
|
|
|
|
* @param appWidgetManager 小部件管理器
|
|
|
|
|
* @param appWidgetIds 要更新的小部件的 ID 数组
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
|
|
|
|
super.update(context, appWidgetManager, appWidgetIds);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取 2x 小部件的布局资源 ID。
|
|
|
|
|
*
|
|
|
|
|
* @return 布局资源 ID
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
protected int getLayoutId() {
|
|
|
|
|
return R.layout.widget_2x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取 2x 小部件指定背景颜色 ID 对应的背景资源 ID。
|
|
|
|
|
*
|
|
|
|
|
* @param bgId 背景颜色 ID
|
|
|
|
|
* @return 背景资源 ID
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
protected int getBgResourceId(int bgId) {
|
|
|
|
|
return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取 2x 小部件的类型。
|
|
|
|
|
*
|
|
|
|
|
* @return 小部件的类型
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
protected int getWidgetType() {
|
|
|
|
|
return Notes.TYPE_WIDGET_2X;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* 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.appwidget.AppWidgetManager;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
|
|
|
|
|
import net.micode.notes.R;
|
|
|
|
|
import net.micode.notes.data.Notes;
|
|
|
|
|
import net.micode.notes.tool.ResourceParser;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* NoteWidgetProvider_4x 是 NoteWidgetProvider 的子类,用于处理 4x 大小的便签小部件。
|
|
|
|
|
*/
|
|
|
|
|
public class NoteWidgetProvider_4x extends NoteWidgetProvider {
|
|
|
|
|
/**
|
|
|
|
|
* 当小部件需要更新时调用此方法。
|
|
|
|
|
* 调用父类的 update 方法来更新小部件。
|
|
|
|
|
*
|
|
|
|
|
* @param context 应用程序上下文
|
|
|
|
|
* @param appWidgetManager 小部件管理器
|
|
|
|
|
* @param appWidgetIds 要更新的小部件的 ID 数组
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
|
|
|
|
super.update(context, appWidgetManager, appWidgetIds);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取 4x 小部件的布局资源 ID。
|
|
|
|
|
*
|
|
|
|
|
* @return 布局资源 ID
|
|
|
|
|
*/
|
|
|
|
|
protected int getLayoutId() {
|
|
|
|
|
return R.layout.widget_4x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取 4x 小部件指定背景颜色 ID 对应的背景资源 ID。
|
|
|
|
|
*
|
|
|
|
|
* @param bgId 背景颜色 ID
|
|
|
|
|
* @return 背景资源 ID
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
protected int getBgResourceId(int bgId) {
|
|
|
|
|
return ResourceParser.WidgetBgResources.getWidget4xBgResource(bgId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取 4x 小部件的类型。
|
|
|
|
|
*
|
|
|
|
|
* @return 小部件的类型
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
protected int getWidgetType() {
|
|
|
|
|
return Notes.TYPE_WIDGET_4X;
|
|
|
|
|
}
|
|
|
|
|
}
|