From 524227a603c3b04d08675cb89acccafbe696fd51 Mon Sep 17 00:00:00 2001 From: zzy <2858538334@qq,com> Date: Mon, 30 Dec 2024 21:44:47 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ActionFailureException.java | 41 -- Contact.java | 87 ---- GTaskASyncTask.java | 138 ------ GTaskClient.java | 688 ----------------------------- GTaskManager.java | 830 ----------------------------------- GTaskSyncService.java | 178 -------- MetaData.java | 120 ----- NetworkFailureException.java | 42 -- Node.java | 126 ------ Note.java | 301 ------------- Notes.java | 212 --------- NotesDatabaseHelper.java | 363 --------------- NotesProvider.java | 377 ---------------- SqlData.java | 197 --------- SqlNote.java | 581 ------------------------ Task.java | 424 ------------------ TaskList.java | 482 -------------------- WorkingNote.java | 401 ----------------- 18 files changed, 5588 deletions(-) delete mode 100644 ActionFailureException.java delete mode 100644 Contact.java delete mode 100644 GTaskASyncTask.java delete mode 100644 GTaskClient.java delete mode 100644 GTaskManager.java delete mode 100644 GTaskSyncService.java delete mode 100644 MetaData.java delete mode 100644 NetworkFailureException.java delete mode 100644 Node.java delete mode 100644 Note.java delete mode 100644 Notes.java delete mode 100644 NotesDatabaseHelper.java delete mode 100644 NotesProvider.java delete mode 100644 SqlData.java delete mode 100644 SqlNote.java delete mode 100644 Task.java delete mode 100644 TaskList.java delete mode 100644 WorkingNote.java diff --git a/ActionFailureException.java b/ActionFailureException.java deleted file mode 100644 index 72cad56..0000000 --- a/ActionFailureException.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - */ - -// 定义包名,表示这个类属于net.micode.notes.gtask.exception包 -package net.micode.notes.gtask.exception; - -// 定义一个名为ActionFailureException的类,它继承自RuntimeException -public class ActionFailureException extends RuntimeException { - // 定义一个静态常量serialVersionUID,用于序列化时的版本控制 - private static final long serialVersionUID = 4425249765923293627L; - - // 构造函数,无参数,调用父类RuntimeException的无参数构造函数 - public ActionFailureException() { - super(); - } - - // 构造函数,接收一个字符串参数,调用父类RuntimeException的构造函数,并传入该字符串 - public ActionFailureException(String paramString) { - super(paramString); - } - - // 构造函数,接收一个字符串和一个Throwable对象作为参数 - // 调用父类RuntimeException的构造函数,传入这两个参数 - // 这个构造函数通常用于在抛出异常时提供额外的错误信息和原因 - public ActionFailureException(String paramString, Throwable paramThrowable) { - super(paramString, paramThrowable); - } -} diff --git a/Contact.java b/Contact.java deleted file mode 100644 index 68303e8..0000000 --- a/Contact.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.data; - -import android.content.Context; -import android.database.Cursor; -import android.provider.ContactsContract.CommonDataKinds.Phone; -import android.provider.ContactsContract.Data; -import android.telephony.PhoneNumberUtils; -import android.util.Log; - -import java.util.HashMap; - -public class Contact { - // 用于缓存联系人信息,避免多次查询同一个号码 - private static HashMap sContactCache; - private static final String TAG = "Contact"; // 用于Log输出的TAG - - // 用于查询联系人名称的SQL条件,依赖于手机号的最小匹配格式 - private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER - + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" - + " AND " + Data.RAW_CONTACT_ID + " IN " - + "(SELECT raw_contact_id " - + " FROM phone_lookup" - + " WHERE min_match = '+')"; - - // 获取某个电话号对应的联系人名称 - public static String getContact(Context context, String phoneNumber) { - // 如果缓存为空,初始化缓存 - if(sContactCache == null) { - sContactCache = new HashMap(); - } - - // 如果缓存中已有该电话号码的联系人信息,直接返回 - if(sContactCache.containsKey(phoneNumber)) { - return sContactCache.get(phoneNumber); - } - - // 通过PhoneNumberUtils将电话号码转为符合最小匹配格式的号码 - String selection = CALLER_ID_SELECTION.replace("+", - PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); - - // 查询联系人数据库,根据号码查找联系人名称 - Cursor cursor = context.getContentResolver().query( - Data.CONTENT_URI, // 数据源:联系人数据 - new String[] { Phone.DISPLAY_NAME }, // 查询字段:联系人名称 - selection, // 查询条件:号码与条件匹配 - new String[] { phoneNumber }, // 查询参数:电话号码 - null); // 排序 - - // 如果查询成功,处理返回结果 - if (cursor != null && cursor.moveToFirst()) { - try { - // 获取查询到的联系人名称 - String name = cursor.getString(0); - // 将查询到的联系人名称缓存起来 - sContactCache.put(phoneNumber, name); - return name; - } catch (IndexOutOfBoundsException e) { - // 如果查询结果异常,记录日志 - Log.e(TAG, " Cursor get string error " + e.toString()); - return null; - } finally { - // 最后关闭游标,释放资源 - cursor.close(); - } - } else { - // 如果没有找到匹配的联系人,记录日志并返回null - Log.d(TAG, "No contact matched with number:" + phoneNumber); - return null; - } - } -} \ No newline at end of file diff --git a/GTaskASyncTask.java b/GTaskASyncTask.java deleted file mode 100644 index 3453bc9..0000000 --- a/GTaskASyncTask.java +++ /dev/null @@ -1,138 +0,0 @@ - -/* - * 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. - */ - -// 定义包名,表示这个类属于net.micode.notes.remote包 -package net.micode.notes.remote; - -// 导入所需的Android类和接口 -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; - -// 定义GTaskASyncTask类,它继承自AsyncTask -// 该类的参数分别为:参数类型Void,进度更新的参数类型String,返回结果的类型Integer -public class GTaskASyncTask extends AsyncTask { - - // 定义一个常量,用于通知的ID - private static int GTASK_SYNC_NOTIFICATION_ID = 5234235; - - // 定义一个接口,用于在任务完成时回调 - public interface OnCompleteListener { - void onComplete(); - } - - // 定义成员变量 - private Context mContext; // Android上下文 - private NotificationManager mNotifiManager; // 通知管理器 - private GTaskManager mTaskManager; // 任务管理器 - private OnCompleteListener mOnCompleteListener; // 完成时的回调接口 - - // 构造函数,接收上下文和完成时的回调接口 - public GTaskASyncTask(Context context, OnCompleteListener listener) { - mContext = context; - mOnCompleteListener = listener; - mNotifiManager = (NotificationManager) mContext - .getSystemService(Context.NOTIFICATION_SERVICE); // 获取通知管理器 - mTaskManager = GTaskManager.getInstance(); // 获取任务管理器的实例 - } - - // 取消同步的方法 - public void cancelSync() { - mTaskManager.cancelSync(); - } - - // 发布进度更新的方法 - public void publishProgess(String message) { - publishProgress(new String[] { message }); // 发布进度更新 - } - - // 显示通知的方法 - private void showNotification(int tickerId, String content) { - // 创建通知对象 - Notification notification = new Notification(R.drawable.notification, mContext - .getString(tickerId), System.currentTimeMillis()); - notification.defaults = Notification.DEFAULT_LIGHTS; // 设置默认的灯光 - notification.flags = Notification.FLAG_AUTO_CANCEL; // 设置通知自动取消 - - // 根据tickerId创建PendingIntent - PendingIntent pendingIntent; - if (tickerId != R.string.ticker_success) { - pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesPreferenceActivity.class), 0); - } else { - pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesListActivity.class), 0); - } - - // 设置通知的详细信息 - notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content, - pendingIntent); - // 发布通知 - mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); - } - - // 后台任务执行的方法 - @Override - protected Integer doInBackground(Void... unused) { - publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity - .getSyncAccountName(mContext))); // 发布进度更新 - return mTaskManager.sync(mContext, this); // 执行同步操作并返回结果 - } - - // 进度更新的方法 - @Override - protected void onProgressUpdate(String... progress) { - showNotification(R.string.ticker_syncing, progress[0]); // 显示进度通知 - if (mContext instanceof 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(); - } - } -} diff --git a/GTaskClient.java b/GTaskClient.java deleted file mode 100644 index 6d1c82a..0000000 --- a/GTaskClient.java +++ /dev/null @@ -1,688 +0,0 @@ -/* - * 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. - */ - -// 导入所需的Android库和类 -package net.micode.notes.gtask.remote; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AccountManagerFuture; -import android.app.Activity; -import android.os.Bundle; -import android.text.TextUtils; -import android.util.Log; - -import net.micode.notes.gtask.data.Node; -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.GTaskStringUtils; -import net.micode.notes.ui.NotesPreferenceActivity; - -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.cookie.Cookie; -import org.apache.http.impl.client.BasicCookieStore; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; -import org.apache.http.params.HttpProtocolParams; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.LinkedList; -import java.util.List; -import java.util.zip.GZIPInputStream; -import java.util.zip.Inflater; -import java.util.zip.InflaterInputStream; - -// GTaskClient类是用于与Google Tasks服务进行交互的客户端 -public class GTaskClient { - // 定义日志标签 - private static final String TAG = GTaskClient.class.getSimpleName(); - - // 定义Google Tasks的URL - private static final String GTASK_URL = "https://mail.google.com/tasks/"; - private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig"; - private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig"; - - // 单例模式,确保GTaskClient只有一个实例 - private static GTaskClient mInstance = null; - - // HTTP客户端,用于发送请求 - private DefaultHttpClient mHttpClient; - - // GET和POST请求的URL - private String mGetUrl; - private String mPostUrl; - - // 客户端版本号 - private long mClientVersion; - - // 登录状态 - private boolean mLoggedin; - - // 最后登录时间 - private long mLastLoginTime; - - // 操作ID - private int mActionId; - - // 当前账户 - private Account mAccount; - - // 更新数组 - private JSONArray mUpdateArray; - - // 私有构造函数,防止外部直接创建实例 - private GTaskClient() { - mHttpClient = null; - mGetUrl = GTASK_GET_URL; - mPostUrl = GTASK_POST_URL; - mClientVersion = -1; - mLoggedin = false; - mLastLoginTime = 0; - mActionId = 1; - mAccount = null; - mUpdateArray = null; - } - - // 提供获取GTaskClient实例的方法,确保单例模式 - public static synchronized GTaskClient getInstance() { - if (mInstance == null) { - mInstance = new GTaskClient(); - } - return mInstance; - } - - // 登录方法,用于登录Google Tasks服务 - public boolean login(Activity activity) { - // 如果登录间隔超过5分钟,则需要重新登录 - final long interval = 1000 * 60 * 5; - if (mLastLoginTime + interval < System.currentTimeMillis()) { - mLoggedin = false; - } - - // 如果账户切换,则需要重新登录 - if (mLoggedin - && !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity - .getSyncAccountName(activity))) { - mLoggedin = false; - } - - // 如果已经登录,则直接返回true - if (mLoggedin) { - Log.d(TAG, "already logged in"); - return true; - } - - // 更新最后登录时间 - mLastLoginTime = System.currentTimeMillis(); - String authToken = loginGoogleAccount(activity, false); - if (authToken == null) { - Log.e(TAG, "login google account failed"); - return false; - } - - // 如果账户不是gmail.com或googlemail.com,则需要使用自定义域名 - if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase() - .endsWith("googlemail.com"))) { - StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); - int index = mAccount.name.indexOf('@') + 1; - String suffix = mAccount.name.substring(index); - url.append(suffix + "/"); - mGetUrl = url.toString() + "ig"; - mPostUrl = url.toString() + "r/ig"; - - if (tryToLoginGtask(activity, authToken)) { - mLoggedin = true; - } - } - - // 如果使用Google官方URL登录失败,则返回false - if (!mLoggedin) { - mGetUrl = GTASK_GET_URL; - mPostUrl = GTASK_POST_URL; - if (!tryToLoginGtask(activity, authToken)) { - return false; - } - } - - // 登录成功,设置登录状态为true - mLoggedin = true; - return true; - } - - // 登录Google账户的方法 - private String loginGoogleAccount(Activity activity, boolean invalidateToken) { - String authToken; - AccountManager accountManager = AccountManager.get(activity); - Account[] accounts = accountManager.getAccountsByType("com.google"); - - // 如果没有Google账户,则返回null - if (accounts.length == 0) { - Log.e(TAG, "there is no available google account"); - return null; - } - - // 获取同步账户名称 - String accountName = NotesPreferenceActivity.getSyncAccountName(activity); - Account account = null; - for (Account a : accounts) { - if (a.name.equals(accountName)) { - account = a; - break; - } - } - if (account != null) { - mAccount = account; - } else { - Log.e(TAG, "unable to get an account with the same name in the settings"); - return null; - } - - // 获取授权令牌 - AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account, - "goanna_mobile", null, activity, null, null); - try { - Bundle authTokenBundle = accountManagerFuture.getResult(); - authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); - if (invalidateToken) { - accountManager.invalidateAuthToken("com.google", authToken); - loginGoogleAccount(activity, false); - } - } catch (Exception e) { - Log.e(TAG, "get auth token failed"); - authToken = null; - } - - return authToken; - } - - // 尝试使用提供的授权令牌登录Google Tasks -private boolean tryToLoginGtask(Activity activity, String authToken) { - // 首先尝试登录 - if (!loginGtask(authToken)) { - // 如果登录失败,可能是授权令牌过期,因此使令牌失效并尝试重新获取 - authToken = loginGoogleAccount(activity, true); - // 如果重新获取授权令牌失败,则记录错误并返回false - if (authToken == null) { - Log.e(TAG, "login google account failed"); - return false; - } - - // 使用新的授权令牌再次尝试登录 - if (!loginGtask(authToken)) { - Log.e(TAG, "login gtask failed"); - return false; - } - } - // 登录成功,返回true - return true; -} - -// 使用授权令牌登录Google Tasks -private boolean loginGtask(String authToken) { - // 设置连接超时和socket超时参数 - int timeoutConnection = 10000; - int timeoutSocket = 15000; - HttpParams httpParameters = new BasicHttpParams(); - HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); - HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); - // 创建HttpClient实例并设置超时参数 - mHttpClient = new DefaultHttpClient(httpParameters); - BasicCookieStore localBasicCookieStore = new BasicCookieStore(); - mHttpClient.setCookieStore(localBasicCookieStore); - // 设置HTTP协议参数,禁用Expect-Continue - HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); - - try { - // 构造登录URL并发起GET请求 - String loginUrl = mGetUrl + "?auth=" + authToken; - HttpGet httpGet = new HttpGet(loginUrl); - HttpResponse response = mHttpClient.execute(httpGet); - - // 获取响应中的Cookie - List cookies = mHttpClient.getCookieStore().getCookies(); - boolean hasAuthCookie = false; - for (Cookie cookie : cookies) { - // 检查是否存在名为"GTL"的授权Cookie - if (cookie.getName().contains("GTL")) { - hasAuthCookie = true; - } - } - // 如果没有找到授权Cookie,则记录警告 - if (!hasAuthCookie) { - Log.w(TAG, "it seems that there is no auth cookie"); - } - - // 从响应内容中提取客户端版本号 - String resString = getResponseContent(response.getEntity()); - String jsBegin = "_setup("; - String jsEnd = ")}"; - int begin = resString.indexOf(jsBegin); - int end = resString.lastIndexOf(jsEnd); - String jsString = null; - if (begin != -1 && end != -1 && begin < end) { - // 提取JavaScript代码中的客户端版本信息 - jsString = resString.substring(begin + jsBegin.length(), end); - } - JSONObject js = new JSONObject(jsString); - mClientVersion = js.getLong("v"); - } catch (JSONException e) { - // 如果JSON解析失败,则记录错误并返回false - Log.e(TAG, e.toString()); - e.printStackTrace(); - return false; - } catch (Exception e) { - // 捕获所有其他异常,并记录错误,返回false - Log.e(TAG, "httpget gtask_url failed"); - return false; - } - - // 登录成功,返回true - return true; -} - -// 获取下一个操作ID,用于标识请求 -private int getActionId() { - return mActionId++; -} - -// 创建一个HttpPost请求对象,设置必要的头部信息 -private HttpPost createHttpPost() { - HttpPost httpPost = new HttpPost(mPostUrl); - httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); - httpPost.setHeader("AT", "1"); - return httpPost; -} - - /** - * 从HttpEntity中获取响应内容的方法。 - * @param entity HttpEntity对象,包含响应数据。 - * @return 响应内容的字符串表示。 - * @throws IOException 如果读取输入流时发生I/O错误。 - */ -private String getResponseContent(HttpEntity entity) throws IOException { - String contentEncoding = null; - if (entity.getContentEncoding() != null) { - contentEncoding = entity.getContentEncoding().getValue(); - Log.d(TAG, "encoding: " + contentEncoding); - } - - InputStream input = entity.getContent(); - // 根据内容编码类型,包装输入流 - if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) { - input = new GZIPInputStream(entity.getContent()); - } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) { - Inflater inflater = new Inflater(true); - input = new InflaterInputStream(entity.getContent(), inflater); - } - - try { - InputStreamReader isr = new InputStreamReader(input); - BufferedReader br = new BufferedReader(isr); - StringBuilder sb = new StringBuilder(); - - // 读取响应内容直到结束 - while (true) { - String buff = br.readLine(); - if (buff == null) { - return sb.toString(); - } - sb = sb.append(buff); - } - } finally { - // 确保输入流被关闭 - input.close(); - } -} - -/** - * 发送POST请求并返回响应的JSONObject。 - * @param js 包含请求数据的JSONObject。 - * @return 响应内容的JSONObject。 - * @throws NetworkFailureException 如果网络请求失败。 - */ -private JSONObject postRequest(JSONObject js) throws NetworkFailureException { - if (!mLoggedin) { - Log.e(TAG, "please login first"); - throw new ActionFailureException("not logged in"); - } - - HttpPost httpPost = createHttpPost(); - try { - // 构造请求参数 - LinkedList list = new LinkedList(); - list.add(new BasicNameValuePair("r", js.toString())); - UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); - httpPost.setEntity(entity); - - // 执行POST请求 - HttpResponse response = mHttpClient.execute(httpPost); - String jsString = getResponseContent(response.getEntity()); - return new JSONObject(jsString); - - } catch (ClientProtocolException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new NetworkFailureException("postRequest failed"); - } catch (IOException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new NetworkFailureException("postRequest failed"); - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("unable to convert response content to jsonobject"); - } catch (Exception e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("error occurs when posting request"); - } -} - -/** - * 创建新任务的方法。 - * @param task 要创建的任务对象。 - * @throws NetworkFailureException 如果网络请求失败。 - */ -public void createTask(Task task) throws NetworkFailureException { - commitUpdate(); - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - - // 构造创建任务的行动列表 - actionList.put(task.getCreateAction(getActionId())); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // 设置客户端版本 - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - // 发送POST请求 - JSONObject jsResponse = postRequest(jsPost); - JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( - GTaskStringUtils.GTASK_JSON_RESULTS).get(0); - task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("create task: handing jsonobject failed"); - } -} - -/** - * 创建新任务列表的方法。 - * @param tasklist 要创建的任务列表对象。 - * @throws NetworkFailureException 如果网络请求失败。 - */ -public void createTaskList(TaskList tasklist) throws NetworkFailureException { - commitUpdate(); - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - - // 构造创建任务列表的行动列表 - actionList.put(tasklist.getCreateAction(getActionId())); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // 设置客户端版本 - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - // 发送POST请求 - JSONObject jsResponse = postRequest(jsPost); - JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( - GTaskStringUtils.GTASK_JSON_RESULTS).get(0); - tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("create tasklist: handing jsonobject failed"); - } -} - - /** - * 提交更新到服务器。 - * 如果有待更新的节点,将它们打包成一个JSON对象并发送到服务器。 - * @throws NetworkFailureException 如果网络请求失败。 - */ -public void commitUpdate() throws NetworkFailureException { - if (mUpdateArray != null) { - try { - JSONObject jsPost = new JSONObject(); - - // 将待更新的节点数组添加到JSON对象中 - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); - - // 添加客户端版本号 - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - // 发送POST请求 - postRequest(jsPost); - // 清空更新数组 - mUpdateArray = null; - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("commit update: handing jsonobject failed"); - } - } -} - -/** - * 向更新数组中添加一个新的更新节点。 - * 如果更新数组已满(超过10个项目),则先提交当前的更新数组。 - * @param node 要添加的更新节点。 - * @throws NetworkFailureException 如果网络请求失败。 - */ -public void addUpdateNode(Node node) throws NetworkFailureException { - if (node != null) { - // 如果更新数组已满,则先提交更新 - if (mUpdateArray != null && mUpdateArray.length() > 10) { - commitUpdate(); - } - - // 如果更新数组为空,则创建一个新的JSONArray - if (mUpdateArray == null) - mUpdateArray = new JSONArray(); - // 将节点的更新动作添加到更新数组中 - mUpdateArray.put(node.getUpdateAction(getActionId())); - } -} - -/** - * 移动任务到不同的任务列表。 - * @param task 要移动的任务。 - * @param preParent 任务原来所在的任务列表。 - * @param curParent 任务移动到的新任务列表。 - * @throws NetworkFailureException 如果网络请求失败。 - */ -public void moveTask(Task task, TaskList preParent, TaskList curParent) - throws NetworkFailureException { - commitUpdate(); - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - JSONObject action = new JSONObject(); - - // 构造移动任务的动作 - action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, - GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE); - action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); - action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid()); - // 如果任务在同一个任务列表内移动,并且不是第一个任务,则添加前一个兄弟任务的ID - if (preParent == curParent && task.getPriorSibling() != null) { - action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling()); - } - action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); - action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); - // 如果任务移动到不同的任务列表,则添加目标任务列表的ID - if (preParent != curParent) { - action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); - } - actionList.put(action); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // 添加客户端版本号 - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - // 发送POST请求 - postRequest(jsPost); - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("move task: handing jsonobject failed"); - } -} - -/** - * 删除节点。 - * @param node 要删除的节点。 - * @throws NetworkFailureException 如果网络请求失败。 - */ -public void deleteNode(Node node) throws NetworkFailureException { - commitUpdate(); - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - - // 标记节点为已删除 - node.setDeleted(true); - // 构造删除节点的动作 - actionList.put(node.getUpdateAction(getActionId())); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // 添加客户端版本号 - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - // 发送POST请求 - postRequest(jsPost); - // 清空更新数组 - mUpdateArray = null; - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("delete node: handing jsonobject failed"); - } -} - -/** - * 获取所有任务列表。 - * @return 任务列表的JSONArray。 - * @throws NetworkFailureException 如果网络请求失败。 - */ -public JSONArray getTaskLists() throws NetworkFailureException { - if (!mLoggedin) { - Log.e(TAG, "please login first"); - throw new ActionFailureException("not logged in"); - } - - try { - HttpGet httpGet = new HttpGet(mGetUrl); - HttpResponse response = mHttpClient.execute(httpGet); - - // 提取响应内容中的JavaScript代码,并解析出任务列表 - String resString = getResponseContent(response.getEntity()); - String jsBegin = "_setup("; - String jsEnd = ")}"; - int begin = resString.indexOf(jsBegin); - int end = resString.lastIndexOf(jsEnd); - String jsString = null; - if (begin != -1 && end != -1 && begin < end) { - jsString = resString.substring(begin + jsBegin.length(), end); - } - JSONObject js = new JSONObject(jsString); - return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS); - } catch (ClientProtocolException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new NetworkFailureException("gettasklists: httpget failed"); - } catch (IOException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new NetworkFailureException("gettasklists: httpget failed"); - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("get task lists: handing jasonobject failed"); - } -} - -/** - * 获取指定任务列表下的所有任务。 - * @param listGid 任务列表的ID。 - * @return 任务的JSONArray。 - * @throws NetworkFailureException 如果网络请求失败。 - */ -public JSONArray getTaskList(String listGid) throws NetworkFailureException { - commitUpdate(); - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - JSONObject action = new JSONObject(); - - // 构造获取任务的动作 - action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, - GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); - action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); - action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); - action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); - actionList.put(action); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // 添加客户端版本号 - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - // 发送POST请求 - JSONObject jsResponse = postRequest(jsPost); - return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS); - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("get task list: handing jsonobject failed"); - } -} - -/** - * 获取当前同步的账户。 - * @return 当前同步的账户对象。 - */ -public Account getSyncAccount() { - return mAccount; -} - -/** - * 重置更新数组。 - */ -public void resetUpdateArray() { - mUpdateArray = null; -} diff --git a/GTaskManager.java b/GTaskManager.java deleted file mode 100644 index f56a717..0000000 --- a/GTaskManager.java +++ /dev/null @@ -1,830 +0,0 @@ -/* - * 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; - -// 导入所需的Android类和自定义类 - -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; - -// GTaskManager类用于管理与Google Tasks的同步操作 -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; - - // 单例模式,GTaskManager的实例 - private static GTaskManager mInstance = null; - - // Activity和Context引用,用于访问Android系统服务 - private Activity mActivity; - private Context mContext; - - // ContentResolver用于访问和修改内容提供者中的数据 - private ContentResolver mContentResolver; - - // 同步状态标志 - private boolean mSyncing; - private boolean mCancelled; - - // 用于存储任务列表、任务和元数据的哈希映射 - private HashMap mGTaskListHashMap; - private HashMap mGTaskHashMap; - private HashMap mMetaHashMap; - - // 元数据列表 - private TaskList mMetaList; - - // 本地删除ID映射 - private HashSet mLocalDeleteIdMap; - - // GID到NID的映射 - private HashMap mGidToNid; - - // NID到GID的映射 - private HashMap mNidToGid; - - // 私有构造函数,确保单例模式 - private GTaskManager() { - mSyncing = false; - mCancelled = false; - mGTaskListHashMap = new HashMap(); - mGTaskHashMap = new HashMap(); - mMetaHashMap = new HashMap(); - mMetaList = null; - mLocalDeleteIdMap = new HashSet(); - mGidToNid = new HashMap(); - mNidToGid = new HashMap(); - } - - // 获取GTaskManager的实例 - public static synchronized GTaskManager getInstance() { - if (mInstance == null) { - mInstance = new GTaskManager(); - } - return mInstance; - } - - // 设置Activity上下文 - 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(); - mNidToGid.clear(); - - try { - // 获取GTaskClient实例 - GTaskClient client = GTaskClient.getInstance(); - client.resetUpdateArray(); - - // 登录Google Tasks - if (!mCancelled) { - if (!client.login(mActivity)) { - throw new NetworkFailureException("login google task failed"); - } - } - - // 从Google获取任务列表 - asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list)); - initGTaskList(); - - // 执行内容同步工作 - asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing)); - syncContent(); - } catch (NetworkFailureException e) { - Log.e(TAG, e.toString()); - return STATE_NETWORK_ERROR; - } catch (ActionFailureException e) { - Log.e(TAG, e.toString()); - return STATE_INTERNAL_ERROR; - } catch (Exception e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - return STATE_INTERNAL_ERROR; - } finally { - // 清空哈希映射和集合 - mGTaskListHashMap.clear(); - mGTaskHashMap.clear(); - mMetaHashMap.clear(); - mLocalDeleteIdMap.clear(); - mGidToNid.clear(); - mNidToGid.clear(); - mSyncing = false; - } - - // 返回同步状态 - return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; - } - - // 初始化GTask列表 - private void initGTaskList() throws NetworkFailureException { - if (mCancelled) - return; - GTaskClient client = GTaskClient.getInstance(); - try { - // 获取任务列表JSON数组 - JSONArray jsTaskLists = client.getTaskLists(); - - // 首先初始化元数据列表 - mMetaList = null; - for (int i = 0; i < jsTaskLists.length(); i++) { - JSONObject object = jsTaskLists.getJSONObject(i); - String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); - String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME); - - // 检查是否是元数据列表 - if (name - .equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { - mMetaList = new TaskList(); - mMetaList.setContentByRemoteJSON(object); - - // 加载元数据 - JSONArray jsMetas = client.getTaskList(gid); - for (int j = 0; j < jsMetas.length(); j++) { - object = (JSONObject) jsMetas.getJSONObject(j); - MetaData metaData = new MetaData(); - metaData.setContentByRemoteJSON(object); - if (metaData.isWorthSaving()) { - mMetaList.addChildTask(metaData); - if (metaData.getGid() != null) { - mMetaHashMap.put(metaData.getRelatedGid(), metaData); - } - } - } - } - } - - // 如果元数据列表不存在,则创建 - if (mMetaList == null) { - mMetaList = new TaskList(); - mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_META); - GTaskClient.getInstance().createTaskList(mMetaList); - } - - // 初始化任务列表 - for (int i = 0; i < jsTaskLists.length(); i++) { - JSONObject object = jsTaskLists.getJSONObject(i); - String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); - String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME); - - // 检查是否是任务列表 - if (name.startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX) - && !name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_META)) { - TaskList tasklist = new TaskList(); - tasklist.setContentByRemoteJSON(object); - mGTaskListHashMap.put(gid, tasklist); - mGTaskHashMap.put(gid, tasklist); - - // 加载任务 - JSONArray jsTasks = client.getTaskList(gid); - for (int j = 0; j < jsTasks.length(); j++) { - object = (JSONObject) jsTasks.getJSONObject(j); - gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); - Task task = new Task(); - task.setContentByRemoteJSON(object); - if (task.isWorthSaving()) { - task.setMetaInfo(mMetaHashMap.get(gid)); - tasklist.addChildTask(task); - mGTaskHashMap.put(gid, task); - } - } - } - } - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("initGTaskList: handing JSONObject failed"); - } - } - - // 私有方法,用于同步内容,可能会抛出网络故障异常 -private void syncContent() throws NetworkFailureException { - int syncType; // 同步类型 - Cursor c = null; // 数据库游标 - String gid; // 用于存储全局ID - Node node; // 节点对象 - - mLocalDeleteIdMap.clear(); // 清除本地删除ID映射 - - if (mCancelled) { - return; // 如果取消同步,则直接返回 - } - - // 处理本地已删除的笔记 - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type<>? AND parent_id=?)", new String[] { - String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER) - }, null); - if (c != null) { - while (c.moveToNext()) { - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - doContentSync(Node.SYNC_ACTION_DEL_REMOTE, node, c); - } - - mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); - } - } else { - Log.w(TAG, "failed to query trash folder"); - } - } finally { - if (c != null) { - c.close(); - c = null; - } - } - - // 首先同步文件夹 - syncFolder(); - - // 处理数据库中存在的笔记 - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type=? AND parent_id<>?)", new String[] { - String.valueOf(Notes.TYPE_NOTE), String.valueOf(Notes.ID_TRASH_FOLER) - }, NoteColumns.TYPE + " DESC"); - if (c != null) { - while (c.moveToNext()) { - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); - mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); - syncType = node.getSyncAction(c); - } else { - if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // 本地添加 - syncType = Node.SYNC_ACTION_ADD_REMOTE; - } else { - // 远程删除 - syncType = Node.SYNC_ACTION_DEL_LOCAL; - } - } - doContentSync(syncType, node, c); - } - } else { - Log.w(TAG, "failed to query existing note in database"); - } - - } finally { - if (c != null) { - c.close(); - c = null; - } - } - - // 处理剩余项 - Iterator> iter = mGTaskHashMap.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - node = entry.getValue(); - doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); - } - - // 如果没有被取消,则清除本地删除表 - if (!mCancelled) { - if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) { - throw new ActionFailureException("failed to batch-delete local deleted notes"); - } - } - - // 如果没有被取消,则刷新本地同步ID - if (!mCancelled) { - GTaskClient.getInstance().commitUpdate(); - refreshLocalSyncId(); - } -} - -// 私有方法,用于同步文件夹,可能会抛出网络故障异常 -private void syncFolder() throws NetworkFailureException { - Cursor c = null; // 数据库游标 - String gid; // 用于存储全局ID - Node node; // 节点对象 - int syncType; // 同步类型 - - if (mCancelled) { - return; // 如果取消同步,则直接返回 - } - - // 处理根文件夹 - try { - c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, - Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null); - if (c != null) { - c.moveToNext(); - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - mGidToNid.put(gid, (long) Notes.ID_ROOT_FOLDER); - mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid); - // 对于系统文件夹,只有在必要时才更新远程名称 - if (!node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) - doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); - } else { - doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); - } - } else { - Log.w(TAG, "failed to query root folder"); - } - } finally { - if (c != null) { - c.close(); - c = null; - } - } - - // 处理通话记录文件夹 - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)", - new String[] { - String.valueOf(Notes.ID_CALL_RECORD_FOLDER) - }, null); - if (c != null) { - if (c.moveToNext()) { - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - mGidToNid.put(gid, (long) Notes.ID_CALL_RECORD_FOLDER); - mNidToGid.put((long) Notes.ID_CALL_RECORD_FOLDER, gid); - // 对于系统文件夹,只有在必要时才更新远程名称 - if (!node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_CALL_NOTE)) - doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); - } else { - doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); - } - } - } else { - Log.w(TAG, "failed to query call note folder"); - } - } finally { - if (c != null) { - c.close(); - c = null; - } - } - - // 处理本地存在的文件夹 - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type=? AND parent_id<>?)", new String[] { - String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER) - }, NoteColumns.TYPE + " DESC"); - if (c != null) { - while (c.moveToNext()) { - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); - mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); - syncType = node.getSyncAction(c); - } else { - if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // 本地添加 - syncType = Node.SYNC_ACTION_ADD_REMOTE; - } else { - // 远程删除 - syncType = Node.SYNC_ACTION_DEL_LOCAL; - } - } - doContentSync(syncType, node, c); - } - } else { - Log.w(TAG, "failed to query existing folder"); - } - } finally { - if (c != null) { - c.close(); - c = null; - } - } - - // 处理远程添加的文件夹 - Iterator> iter = mGTaskListHashMap.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - gid = entry.getKey(); - node = entry.getValue(); - if (mGTaskHashMap.containsKey(gid)) { - mGTaskHashMap.remove(gid); - doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); - } - } - - if (!mCancelled) - GTaskClient.getInstance().commitUpdate(); -} - - // 同步内容的方法,根据同步类型(syncType)、节点(node)和游标(c)执行不同的同步操作 -private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException { - // 如果同步被取消,则直接返回 - if (mCancelled) { - return; - } - - // 根据不同的同步类型执行不同的操作 - MetaData meta; // 用于存储元数据 - switch (syncType) { - case Node.SYNC_ACTION_ADD_LOCAL: // 本地添加节点 - addLocalNode(node); - break; - case Node.SYNC_ACTION_ADD_REMOTE: // 远程添加节点 - addRemoteNode(node, c); - break; - case Node.SYNC_ACTION_DEL_LOCAL: // 本地删除节点 - meta = mMetaHashMap.get(c.getString(SqlNote.GTASK_ID_COLUMN)); // 获取元数据 - if (meta != null) { - GTaskClient.getInstance().deleteNode(meta); // 删除节点 - } - mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); // 添加到本地删除ID映射 - break; - case Node.SYNC_ACTION_DEL_REMOTE: // 远程删除节点 - meta = mMetaHashMap.get(node.getGid()); // 获取元数据 - if (meta != null) { - GTaskClient.getInstance().deleteNode(meta); // 删除节点 - } - GTaskClient.getInstance().deleteNode(node); // 删除节点 - break; - case Node.SYNC_ACTION_UPDATE_LOCAL: // 本地更新节点 - updateLocalNode(node, c); - break; - case Node.SYNC_ACTION_UPDATE_REMOTE: // 远程更新节点 - updateRemoteNode(node, c); - break; - case Node.SYNC_ACTION_UPDATE_CONFLICT: // 更新冲突,目前使用本地更新 - updateRemoteNode(node, c); - break; - case Node.SYNC_ACTION_NONE: // 无操作 - break; - case Node.SYNC_ACTION_ERROR: // 错误处理 - default: - throw new ActionFailureException("unknown sync action type"); // 抛出异常 - } -} - -// 本地添加节点的方法 -private void addLocalNode(Node node) throws NetworkFailureException { - // 如果同步被取消,则直接返回 - if (mCancelled) { - return; - } - - SqlNote sqlNote; // SQL笔记对象 - // 根据节点类型创建不同的SQL笔记对象 - if (node instanceof TaskList) { - // 处理任务列表 - if (node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) { - sqlNote = new SqlNote(mContext, Notes.ID_ROOT_FOLDER); - } else if (node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) { - sqlNote = new SqlNote(mContext, Notes.ID_CALL_RECORD_FOLDER); - } else { - sqlNote = new SqlNote(mContext); - sqlNote.setContent(node.getLocalJSONFromContent()); // 设置内容 - sqlNote.setParentId(Notes.ID_ROOT_FOLDER); // 设置父ID - } - } else { - // 处理任务 - sqlNote = new SqlNote(mContext); - JSONObject js = node.getLocalJSONFromContent(); - try { - // 处理ID冲突 - if (js.has(GTaskStringUtils.META_HEAD_NOTE)) { - JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - if (note.has(NoteColumns.ID)) { - long id = note.getLong(NoteColumns.ID); - if (DataUtils.existInNoteDatabase(mContentResolver, id)) { - note.remove(NoteColumns.ID); - } - } - } - - if (js.has(GTaskStringUtils.META_HEAD_DATA)) { - JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); - for (int i = 0; i < dataArray.length(); i++) { - JSONObject data = dataArray.getJSONObject(i); - if (data.has(DataColumns.ID)) { - long dataId = data.getLong(DataColumns.ID); - if (DataUtils.existInDataDatabase(mContentResolver, dataId)) { - data.remove(DataColumns.ID); - } - } - } - } - } catch (JSONException e) { - Log.w(TAG, e.toString()); - e.printStackTrace(); - } - sqlNote.setContent(js); // 设置内容 - - Long parentId = mGidToNid.get(((Task) node).getParent().getGid()); // 获取父ID - if (parentId == null) { - Log.e(TAG, "cannot find task's parent id locally"); - throw new ActionFailureException("cannot add local node"); - } - sqlNote.setParentId(parentId.longValue()); // 设置父ID - } - - // 创建本地节点 - sqlNote.setGtaskId(node.getGid()); // 设置GTask ID - sqlNote.commit(false); // 提交 - - // 更新GID-NID映射 - mGidToNid.put(node.getGid(), sqlNote.getId()); - mNidToGid.put(sqlNote.getId(), node.getGid()); - - // 更新元数据 - updateRemoteMeta(node.getGid(), sqlNote); -} - -// 本地更新节点的方法 -private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException { - // 如果同步被取消,则直接返回 - if (mCancelled) { - return; - } - - SqlNote sqlNote; // SQL笔记对象 - // 更新本地笔记 - sqlNote = new SqlNote(mContext, c); - sqlNote.setContent(node.getLocalJSONFromContent()); // 设置内容 - - Long parentId = (node instanceof Task) ? mGidToNid.get(((Task) node).getParent().getGid()) - : new Long(Notes.ID_ROOT_FOLDER); - if (parentId == null) { - Log.e(TAG, "cannot find task's parent id locally"); - throw new ActionFailureException("cannot update local node"); - } - sqlNote.setParentId(parentId.longValue()); // 设置父ID - sqlNote.commit(true); // 提交 - - // 更新元数据信息 - updateRemoteMeta(node.getGid(), sqlNote); -} - -// 远程添加节点的方法 -private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { - // 如果同步被取消,则直接返回 - if (mCancelled) { - return; - } - - SqlNote sqlNote = new SqlNote(mContext, c); // SQL笔记对象 - Node n; // 节点对象 - - // 远程更新 - if (sqlNote.isNoteType()) { - Task task = new Task(); // 任务对象 - task.setContentByLocalJSON(sqlNote.getContent()); // 设置内容 - - String parentGid = mNidToGid.get(sqlNote.getParentId()); // 获取父GID - if (parentGid == null) { - Log.e(TAG, "cannot find task's parent tasklist"); - throw new ActionFailureException("cannot add remote task"); - } - mGTaskListHashMap.get(parentGid).addChildTask(task); // 添加任务到任务列表 - - GTaskClient.getInstance().createTask(task); // 创建任务 - n = (Node) task; // 转换为节点 - - // 添加元数据 - updateRemoteMeta(task.getGid(), sqlNote); - } else { - TaskList tasklist = null; // 任务列表对象 - - // 如果文件夹已存在,则跳过 - String folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX; - if (sqlNote.getId() == Notes.ID_ROOT_FOLDER) - folderName += GTaskStringUtils.FOLDER_DEFAULT; - else if (sqlNote.getId() == Notes.ID_CALL_RECORD_FOLDER) - folderName += GTaskStringUtils.FOLDER_CALL_NOTE; - else - folderName += sqlNote.getSnippet(); - - Iterator> iter = mGTaskListHashMap.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - String gid = entry.getKey(); - TaskList list = entry.getValue(); - - if (list.getName().equals(folderName)) { - tasklist = list; - if (mGTaskHashMap.containsKey(gid)) { - mGTaskHashMap.remove(gid); - } - break; - } - } - - // 如果没有匹配,则添加 - if (tasklist == null) { - tasklist = new TaskList(); // 创建任务列表 - tasklist.setContentByLocalJSON(sqlNote.getContent()); // 设置内容 - GTaskClient.getInstance().createTaskList(tasklist); // 创建任务列表 - mGTaskListHashMap.put(tasklist.getGid(), tasklist); // 添加到映射 - } - n = (Node) tasklist; // 转换为节点 - } - - // 更新本地笔记 - sqlNote.setGtaskId(n.getGid()); // 设置GTask ID - sqlNote.commit(false); // 提交 - sqlNote.resetLocalModified(); // 重置本地修改标志 - sqlNote.commit(true); // 提交 - - // GID-ID映射 - mGidToNid.put(n.getGid(), sqlNote.getId()); - mNidToGid.put(sqlNote.getId(), n.getGid()); -} - -// 远程更新节点的方法 -private void updateRemoteNode(Node node, Cursor c) throws - -NetworkFailureException { -// 如果同步被取消,则直接返回 -if (mCancelled) { -return; -} - -SqlNote sqlNote = new SqlNote(mContext, c); // SQL笔记对象 - -// 远程更新 -node.setContentByLocalJSON(sqlNote.getContent()); // 设置内容 -GTaskClient.getInstance().addUpdateNode(node); // 更新节点 - -// 更新元数据 -updateRemoteMeta(node.getGid(), sqlNote); - -// 如果需要,移动任务 -if (sqlNote.isNoteType()) { - Task task = (Task) node; // 任务对象 - TaskList preParentList = task.getParent(); // 之前的父任务列表 - - String curParentGid = mNidToGid.get(sqlNote.getParentId()); // 当前的父GID - if (curParentGid == null) { - Log.e(TAG, "cannot find task's parent tasklist"); - throw new ActionFailureException("cannot update remote task"); - } - TaskList curParentList = mGTaskListHashMap.get(curParentGid); // 当前的父任务列表 - - if (preParentList != curParentList) { - preParentList.removeChildTask(task); // 从之前的父任务列表中移除任务 - curParentList.addChildTask(task); // 添加到当前的父任务列表 - GTaskClient.getInstance().moveTask(task, preParentList, curParentList); // 移动任务 - } -} - -// 清除本地修改标志 -sqlNote.resetLocalModified(); -sqlNote.commit(true); -} - -// 更新远程元数据的方法 -private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException { -if (sqlNote != null && sqlNote.isNoteType()) { -MetaData metaData = mMetaHashMap.get(gid); // 获取元数据 -if (metaData != null) { -metaData.setMeta(gid, sqlNote.getContent()); // 设置元数据 -GTaskClient.getInstance().addUpdateNode(metaData); // 更新元数据 -} else { -metaData = new MetaData(); // 创建元数据对象 -metaData.setMeta(gid, sqlNote.getContent()); // 设置元数据 -mMetaList.addChildTask(metaData); // 添加到元数据列表 -mMetaHashMap.put(gid, metaData); // 添加到映射 -GTaskClient.getInstance().createTask(metaData); // 创建元数据 -} -} -} - -// 刷新本地同步ID的方法 -private void refreshLocalSyncId() throws NetworkFailureException { -if (mCancelled) { -return; -} - -// 获取最新的gtask列表 -mGTaskHashMap.clear(); -mGTaskListHashMap.clear(); -mMetaHashMap.clear(); -initGTaskList(); - -Cursor c = null; -try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type<>? AND parent_id<>?)", new String[] { - String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER) - }, NoteColumns.TYPE + " DESC"); - if (c != null) { - while (c.moveToNext()) { - String gid = c.getString(SqlNote.GTASK_ID_COLUMN); - Node node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - ContentValues values = new ContentValues(); - values.put(NoteColumns.SYNC_ID, node.getLastModified()); - mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, - c.getLong(SqlNote.ID_COLUMN)), values, null, null); - } else { - Log.e(TAG, "something is missed"); - throw new ActionFailureException( - "some local items don't have gid after sync"); - } - } - } else { - Log.w(TAG, "failed to query local note to refresh sync id"); - } -} finally { - if (c != null) { - c.close(); - c = null; - } -} -} - -// 获取同步账户的方法 -public String getSyncAccount() { -return GTaskClient.getInstance().getSyncAccount().name; -} - -// 取消同步的方法 -public void cancelSync() { -mCancelled = true; -} diff --git a/GTaskSyncService.java b/GTaskSyncService.java deleted file mode 100644 index fe51c6c..0000000 --- a/GTaskSyncService.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * 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. - */ - -// 定义了一个名为GTaskSyncService的类,它继承自Service类,用于处理同步任务。 -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 { - // 定义同步操作的Action字符串名称常量 - public final static String ACTION_STRING_NAME = "sync_action_type"; - - // 定义开始同步的Action常量 - public final static int ACTION_START_SYNC = 0; - - // 定义取消同步的Action常量 - public final static int ACTION_CANCEL_SYNC = 1; - - // 定义无效的Action常量 - 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(); - } - } - - // Service创建时调用的方法 - @Override - public void onCreate() { - // 初始化同步任务为null - mSyncTask = null; - } - - // 处理启动命令的方法 - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - // 获取Intent的额外数据 - Bundle bundle = intent.getExtras(); - // 如果额外数据不为空且包含ACTION_STRING_NAME键 - if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) { - // 根据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; - } - // 返回START_STICKY,表示如果服务被系统杀死,会尝试重新创建服务 - return START_STICKY; - } - // 如果Intent没有额外数据,调用父类的onStartCommand方法 - 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); - } - - // 静态方法,用于从Activity启动同步 - public static void startSync(Activity activity) { - // 设置Activity上下文 - 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); - } - - // 静态方法,用于从Context取消同步 - 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() { - // 返回同步任务是否为null的相反值 - return mSyncTask != null; - } - - // 静态方法,用于获取同步进度字符串 - public static String getProgressString() { - // 返回同步进度字符串 - return mSyncProgress; - } -} \ No newline at end of file diff --git a/MetaData.java b/MetaData.java deleted file mode 100644 index 47bdfe7..0000000 --- a/MetaData.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 版权声明:2010-2011年,MiCode开源社区(www.micode.net) - * - * 根据Apache License 2.0(以下简称“许可证”)授权; - * 除非遵守许可证,否则不得使用此文件。 - * 你可以在以下网址获得许可证的副本: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 除非适用法律要求或书面同意,否则根据许可证分发的软件 - * 按“原样”分发,不附带任何明示或暗示的保证或条件。 - * 请参阅许可证,了解许可证下的权利和限制的具体语言。 - */ - -package net.micode.notes.gtask.data; - -// 导入Android框架中用于数据库操作和日志输出的相关类 -import android.database.Cursor; -import android.util.Log; - -// 导入应用内部定义的工具类,用于处理GTask相关的字符串 -import net.micode.notes.tool.GTaskStringUtils; - -// 导入JSON处理的相关类 -import org.json.JSONException; -import org.json.JSONObject; - -// 继承Task类,创建MetaData类,用于处理元数据 -public class MetaData extends Task { - // 日志标签,用于Log日志输出 - private final static String TAG = MetaData.class.getSimpleName(); - - // 相关GTask ID - private String mRelatedGid = null; - - /** - * 设置元数据。 - * @param gid 任务ID。 - * @param metaInfo 元数据信息的JSON对象。 - */ - public void setMeta(String gid, JSONObject metaInfo) { - try { - // 在元数据中添加任务ID - metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); - } catch (JSONException e) { - Log.e(TAG, "failed to put related gid"); - } - // 设置笔记内容为元数据的字符串形式 - setNotes(metaInfo.toString()); - // 设置笔记名称为元数据的特定名称 - setName(GTaskStringUtils.META_NOTE_NAME); - } - - /** - * 获取相关GTask ID。 - * @return 相关GTask ID。 - */ - public String getRelatedGid() { - return mRelatedGid; - } - - /** - * 判断任务是否值得保存。 - * 如果笔记内容不为空,则返回true。 - * @return 任务是否值得保存。 - */ - @Override - public boolean isWorthSaving() { - return getNotes() != null; - } - - /** - * 根据远程JSON设置内容。 - * @param js 远程JSON对象。 - */ - @Override - public void setContentByRemoteJSON(JSONObject js) { - super.setContentByRemoteJSON(js); - if (getNotes() != null) { - try { - // 解析笔记内容为JSON对象,并获取相关GTask ID - JSONObject metaInfo = new JSONObject(getNotes().trim()); - mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); - } catch (JSONException e) { - Log.w(TAG, "failed to get related gid"); - mRelatedGid = null; - } - } - } - - /** - * 根据本地JSON设置内容,此方法不应被调用。 - */ - @Override - public void setContentByLocalJSON(JSONObject js) { - // 抛出异常,表示此方法不应被调用 - throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); - } - - /** - * 从内容中获取本地JSON,此方法不应被调用。 - * @return 本地JSON对象。 - */ - @Override - public JSONObject getLocalJSONFromContent() { - // 抛出异常,表示此方法不应被调用 - throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); - } - - /** - * 获取同步操作,此方法不应被调用。 - * @param c 数据库游标。 - * @return 同步操作。 - */ - @Override - public int getSyncAction(Cursor c) { - // 抛出异常,表示此方法不应被调用 - throw new IllegalAccessError("MetaData:getSyncAction should not be called"); - } -} diff --git a/NetworkFailureException.java b/NetworkFailureException.java deleted file mode 100644 index 7d4820a..0000000 --- a/NetworkFailureException.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - */ - -// 定义包名,表示这个类属于net.micode.notes.gtask.exception包 -package net.micode.notes.gtask.exception; - -// 定义一个名为NetworkFailureException的类,它继承自Exception -public class NetworkFailureException extends Exception { - // 定义一个静态常量serialVersionUID,用于序列化时的版本控制 - private static final long serialVersionUID = 2107610287180234136L; - - // 构造函数,无参数,调用父类Exception的无参数构造函数 - public NetworkFailureException() { - super(); - } - - // 构造函数,接收一个字符串参数,调用父类Exception的构造函数,并传入该字符串 - // 这个字符串通常用于描述异常发生的原因或上下文 - public NetworkFailureException(String paramString) { - super(paramString); - } - - // 构造函数,接收一个字符串和一个Throwable对象作为参数 - // 调用父类Exception的构造函数,传入这两个参数 - // 这个构造函数通常用于在抛出异常时提供额外的错误信息和原因 - public NetworkFailureException(String paramString, Throwable paramThrowable) { - super(paramString, paramThrowable); - } -} \ No newline at end of file diff --git a/Node.java b/Node.java deleted file mode 100644 index 3de06bf..0000000 --- a/Node.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 版权声明:2010-2011年,MiCode开源社区(www.micode.net) - * - * 根据Apache License 2.0(以下简称“许可证”)授权; - * 除非遵守许可证,否则不得使用此文件。 - * 你可以在以下网址获得许可证的副本: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 除非适用法律要求或书面同意,否则根据许可证分发的软件 - * 按“原样”分发,不附带任何明示或暗示的保证或条件。 - * 请参阅许可证,了解许可证下的权利和限制的具体语言。 - */ - -package net.micode.notes.gtask.data; - -import android.database.Cursor; - -import org.json.JSONObject; - -/** - * 定义一个抽象类Node,代表GTask数据模型中的一个节点。 - */ -public abstract class Node { - // 定义同步操作的常量 - public static final int SYNC_ACTION_NONE = 0; - public static final int SYNC_ACTION_ADD_REMOTE = 1; - public static final int SYNC_ACTION_ADD_LOCAL = 2; - public static final int SYNC_ACTION_DEL_REMOTE = 3; - public static final int SYNC_ACTION_DEL_LOCAL = 4; - public static final int SYNC_ACTION_UPDATE_REMOTE = 5; - public static final int SYNC_ACTION_UPDATE_LOCAL = 6; - public static final int SYNC_ACTION_UPDATE_CONFLICT = 7; - public static final int SYNC_ACTION_ERROR = 8; - - // GTask的ID - private String mGid; - // 节点名称 - private String mName; - // 最后修改时间 - private long mLastModified; - // 是否被删除 - private boolean mDeleted; - - /** - * Node类的构造函数。 - */ - public Node() { - mGid = null; - mName = ""; - mLastModified = 0; - mDeleted = false; - } - - /** - * 获取创建操作的JSON对象。 - * @param actionId 操作ID。 - * @return 创建操作的JSON对象。 - */ - public abstract JSONObject getCreateAction(int actionId); - - /** - * 获取更新操作的JSON对象。 - * @param actionId 操作ID。 - * @return 更新操作的JSON对象。 - */ - public abstract JSONObject getUpdateAction(int actionId); - - /** - * 根据远程JSON设置内容。 - * @param js 远程JSON对象。 - */ - public abstract void setContentByRemoteJSON(JSONObject js); - - /** - * 根据本地JSON设置内容。 - * @param js 本地JSON对象。 - */ - public abstract void setContentByLocalJSON(JSONObject js); - - /** - * 从内容中获取本地JSON对象。 - * @return 本地JSON对象。 - */ - public abstract JSONObject getLocalJSONFromContent(); - - /** - * 根据游标获取同步操作。 - * @param c 数据库游标。 - * @return 同步操作。 - */ - public abstract int getSyncAction(Cursor c); - - // Setter和Getter方法 - public void setGid(String gid) { - this.mGid = gid; - } - - public void setName(String name) { - this.mName = name; - } - - public void setLastModified(long lastModified) { - this.mLastModified = lastModified; - } - - public void setDeleted(boolean deleted) { - this.mDeleted = deleted; - } - - public String getGid() { - return this.mGid; - } - - public String getName() { - return this.mName; - } - - public long getLastModified() { - return this.mLastModified; - } - - public boolean getDeleted() { - return this.mDeleted; - } -} \ No newline at end of file diff --git a/Note.java b/Note.java deleted file mode 100644 index 980ac06..0000000 --- a/Note.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * 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. - */ - -// 定义了一个名为Note的类,用于表示笔记数据模型,并提供与数据库交互的方法。 -package net.micode.notes.model; -import android.content.ContentProviderOperation; -import android.content.ContentProviderResult; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.content.OperationApplicationException; -import android.net.Uri; -import android.os.RemoteException; -import android.util.Log; - -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.CallNote; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.data.Notes.TextNote; - -import java.util.ArrayList; - -public class Note { - // 用于存储笔记的差异值,即需要更新到数据库的字段 - private ContentValues mNoteDiffValues; - // 存储笔记数据的内部类实例 - private NoteData mNoteData; - // 用于日志记录的标签 - private static final String TAG = "Note"; - - /** - * 创建一个新的笔记ID,用于将新笔记添加到数据库 - * @param context 上下文对象 - * @param folderId 笔记所属文件夹的ID - * @return 新创建的笔记ID - */ - public static synchronized long getNewNoteId(Context context, long folderId) { - // 创建一个新的ContentValues对象,用于存储笔记的初始数据 - ContentValues values = new ContentValues(); - long createdTime = System.currentTimeMillis(); - values.put(NoteColumns.CREATED_DATE, createdTime); - values.put(NoteColumns.MODIFIED_DATE, createdTime); - values.put(NoteColumns.TYPE, Notes.TYPE_NOTE); - values.put(NoteColumns.LOCAL_MODIFIED, 1); - values.put(NoteColumns.PARENT_ID, folderId); - // 将新笔记插入到数据库,并获取返回的URI - Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values); - - long noteId = 0; - try { - // 从URI中解析出新创建的笔记ID - noteId = Long.valueOf(uri.getPathSegments().get(1)); - } catch (NumberFormatException e) { - Log.e(TAG, "Get note id error :" + e.toString()); - noteId = 0; - } - // 如果解析出的笔记ID不正确,则抛出异常 - if (noteId == -1) { - throw new IllegalStateException("Wrong note id:" + noteId); - } - return noteId; - } - - // Note类的构造函数 - public Note() { - mNoteDiffValues = new ContentValues(); - mNoteData = new NoteData(); - } - - // 设置笔记的值 - public void setNoteValue(String key, String value) { - mNoteDiffValues.put(key, value); - mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); - mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); - } - - // 设置文本数据 - public void setTextData(String key, String value) { - mNoteData.setTextData(key, value); - } - - // 设置文本数据的ID - public void setTextDataId(long id) { - mNoteData.setTextDataId(id); - } - - // 获取文本数据的ID - public long getTextDataId() { - return mNoteData.mTextDataId; - } - - // 设置通话数据的ID - public void setCallDataId(long id) { - mNoteData.setCallDataId(id); - } - - // 设置通话数据 - public void setCallData(String key, String value) { - mNoteData.setCallData(key, value); - } - - // 检查笔记是否在本地被修改过 - public boolean isLocalModified() { - return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified(); - } - - // 同步笔记到数据库 - public boolean syncNote(Context context, long noteId) { - if (noteId <= 0) { - throw new IllegalArgumentException("Wrong note id:" + noteId); - } - - if (!isLocalModified()) { - return true; - } - - /** - * 理论上,一旦数据发生变化,就应该更新笔记的LOCAL_MODIFIED和MODIFIED_DATE字段。 - * 为了数据安全,即使更新笔记失败,我们也应该更新笔记数据信息。 - */ - if (context.getContentResolver().update( - ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null, - null) == 0) { - Log.e(TAG, "Update note error, should not happen"); - // 不要返回,继续执行 - } - mNoteDiffValues.clear(); - - if (mNoteData.isLocalModified() - && (mNoteData.pushIntoContentResolver(context, noteId) == null)) { - return false; - } - - return true; - } - - // 笔记数据的内部类 - private class NoteData { - // 存储文本数据的ID - private long mTextDataId; - // 存储文本数据的ContentValues对象 - private ContentValues mTextDataValues; - // 存储通话数据的ID - private long mCallDataId; - // 存储通话数据的ContentValues对象 - private ContentValues mCallDataValues; - // 用于日志记录的标签 - private static final String TAG = "NoteData"; - - // NoteData类的构造函数 - public NoteData() { - mTextDataValues = new ContentValues(); - mCallDataValues = new ContentValues(); - mTextDataId = 0; - mCallDataId = 0; - } - - // 检查笔记数据是否在本地被修改过 - boolean isLocalModified() { - return mTextDataValues.size() > 0 || mCallDataValues.size() > 0; - } - - // 设置文本数据的ID - void setTextDataId(long id) { - if(id <= 0) { - throw new IllegalArgumentException("Text data id should larger than 0"); - } - mTextDataId = id; - } - - // 设置通话数据的ID - void setCallDataId(long id) { - if (id <= 0) { - throw new IllegalArgumentException("Call data id should larger than 0"); - } - mCallDataId = id; - } - - // 设置通话数据 - void setCallData(String key, String value) { - mCallDataValues.put(key, value); - mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); - mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); - } - - // 设置文本数据 - void setTextData(String key, String value) { - mTextDataValues.put(key, value); - mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); - mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); - } - - // 将笔记数据推送到内容解析器 - Uri pushIntoContentResolver(Context context, long noteId) { - /** - * 检查参数的安全性 - */ - // 检查传入的笔记ID是否有效,如果笔记ID小于或等于0,则抛出IllegalArgumentException异常 -if (noteId <= 0) { - throw new IllegalArgumentException("Wrong note id:" + noteId); -} - -// 创建一个ArrayList来存储ContentProviderOperation对象,这些对象代表要执行的数据库操作 -ArrayList operationList = new ArrayList(); -// 初始化一个ContentProviderOperation.Builder对象,用于构建数据库操作 -ContentProviderOperation.Builder builder = null; - -// 如果文本数据的ContentValues对象中有数据 -if(mTextDataValues.size() > 0) { - // 将笔记ID放入文本数据的ContentValues对象中 - mTextDataValues.put(DataColumns.NOTE_ID, noteId); - // 如果文本数据ID为0,表示这是一个新的文本数据,需要插入新的数据项 - if (mTextDataId == 0) { - // 设置文本数据的MIME类型 - mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE); - // 将文本数据插入到数据库,并获取返回的URI - Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, mTextDataValues); - // 尝试从URI中解析出新插入的文本数据ID - try { - setTextDataId(Long.valueOf(uri.getPathSegments().get(1))); - } catch (NumberFormatException e) { - // 如果解析失败,记录错误日志,并清除文本数据的ContentValues对象,返回null - Log.e(TAG, "Insert new text data fail with noteId" + noteId); - mTextDataValues.clear(); - return null; - } - } else { - // 如果文本数据ID不为0,表示这是更新现有文本数据 - builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, mTextDataId)); - builder.withValues(mTextDataValues); - operationList.add(builder.build()); - } - // 清空文本数据的ContentValues对象,准备下一次操作 - mTextDataValues.clear(); -} - -// 如果通话数据的ContentValues对象中有数据 -if(mCallDataValues.size() > 0) { - // 将笔记ID放入通话数据的ContentValues对象中 - mCallDataValues.put(DataColumns.NOTE_ID, noteId); - // 如果通话数据ID为0,表示这是一个新的通话数据,需要插入新的数据项 - if (mCallDataId == 0) { - // 设置通话数据的MIME类型 - mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE); - // 将通话数据插入到数据库,并获取返回的URI - Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, mCallDataValues); - // 尝试从URI中解析出新插入的通话数据ID - try { - setCallDataId(Long.valueOf(uri.getPathSegments().get(1))); - } catch (NumberFormatException e) { - // 如果解析失败,记录错误日志,并清除通话数据的ContentValues对象,返回null - Log.e(TAG, "Insert new call data fail with noteId" + noteId); - mCallDataValues.clear(); - return null; - } - } else { - // 如果通话数据ID不为0,表示这是更新现有通话数据 - builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, mCallDataId)); - builder.withValues(mCallDataValues); - operationList.add(builder.build()); - } - // 清空通话数据的ContentValues对象,准备下一次操作 - mCallDataValues.clear(); -} - -// 如果有数据库操作需要执行 -if (operationList.size() > 0) { - try { - // 执行批量数据库操作 - ContentProviderResult[] results = context.getContentResolver().applyBatch(Notes.AUTHORITY, operationList); - // 如果操作成功,返回更新的笔记URI,否则返回null - return (results == null || results.length == 0 || results[0] == null) ? null : ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId); - } catch (RemoteException e) { - // 如果发生远程异常,记录错误日志,并返回null - Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); - return null; - } catch (OperationApplicationException e) { - // 如果发生操作应用异常,记录错误日志,并返回null - Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); - return null; - } -} -// 如果没有数据库操作需要执行,返回null -return null; - } - } -} \ No newline at end of file diff --git a/Notes.java b/Notes.java deleted file mode 100644 index 44da6bb..0000000 --- a/Notes.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * 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.data; // 定义了包名,表示这个类属于 net.micode.notes.data 包 - -import android.net.Uri; // 导入 Android 的 Uri 类,用于处理内容提供者的 URI - -public class Notes { // Notes 类,主要用于定义与笔记相关的常量和 URI 配置 - - // 内容提供者的 authority 字符串,用于唯一标识此内容提供者 - public static final String AUTHORITY = "micode_notes"; - - // 用于日志输出的标签 - public static final String TAG = "Notes"; - - // 定义了笔记、文件夹、系统三种类型的常量 - public static final int TYPE_NOTE = 0; // 笔记类型 - public static final int TYPE_FOLDER = 1; // 文件夹类型 - public static final int TYPE_SYSTEM = 2; // 系统类型 - - /** - * 以下常量是系统文件夹的标识符 - * {@link Notes#ID_ROOT_FOLDER} 是默认文件夹 - * {@link Notes#ID_TEMPARAY_FOLDER} 是存储不属于任何文件夹的笔记 - * {@link Notes#ID_CALL_RECORD_FOLDER} 用于存储通话记录 - */ - public static final int ID_ROOT_FOLDER = 0; // 根文件夹的 ID - public static final int ID_TEMPARAY_FOLDER = -1; // 临时文件夹的 ID - public static final int ID_CALL_RECORD_FOLDER = -2; // 通话记录文件夹的 ID - public static final int ID_TRASH_FOLER = -3; // 垃圾桶文件夹的 ID - - // Intent 中传递的额外参数常量,用于与笔记相关的操作 - public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date"; // 提醒日期 - public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id"; // 背景颜色 ID - public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id"; // 小部件 ID - public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type"; // 小部件类型 - public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id"; // 文件夹 ID - public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date"; // 通话日期 - - // 定义了不同类型的小部件常量 - public static final int TYPE_WIDGET_INVALIDE = -1; // 无效小部件类型 - public static final int TYPE_WIDGET_2X = 0; // 2x 小部件类型 - public static final int TYPE_WIDGET_4X = 1; // 4x 小部件类型 - - // 数据常量类,定义了笔记和通话记录的内容类型 - public static class DataConstants { - public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; // 笔记的内容类型 - public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; // 通话记录的内容类型 - } - - /** - * 用于查询所有笔记和文件夹的 URI - */ - public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note"); // 查询笔记的 URI - - /** - * 用于查询数据的 URI - */ - public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); // 查询数据的 URI - - // 笔记相关的列定义接口,包含笔记的数据列 - public interface NoteColumns { - - /** - * 每一行的唯一 ID - *

类型: INTEGER (long)

- */ - public static final String ID = "_id"; // 唯一标识符 - - /** - * 笔记或文件夹的父 ID - *

类型: INTEGER (long)

- */ - public static final String PARENT_ID = "parent_id"; // 父级 ID - - /** - * 笔记或文件夹的创建日期 - *

类型: INTEGER (long)

- */ - public static final String CREATED_DATE = "created_date"; // 创建日期 - - /** - * 笔记或文件夹的最后修改日期 - *

类型: INTEGER (long)

- */ - public static final String MODIFIED_DATE = "modified_date"; // 最后修改日期 - } -} - - - /** - * The constant fields represent various columns of a note-taking application database. - * These constants are used to define column names and their data types within the database schema. - */ -public static final String ALERTED_DATE = "alert_date"; // 记录提醒日期,数据类型:INTEGER(长整型) - -public static final String SNIPPET = "snippet"; // 记录文件夹名称或笔记的文本内容,数据类型:TEXT(字符串) - -public static final String WIDGET_ID = "widget_id"; // 记录笔记的小部件ID,数据类型:INTEGER(长整型) - -public static final String WIDGET_TYPE = "widget_type"; // 记录笔记的小部件类型,数据类型:INTEGER(长整型) - -public static final String BG_COLOR_ID = "bg_color_id"; // 记录笔记的背景颜色ID,数据类型:INTEGER(长整型) - -public static final String HAS_ATTACHMENT = "has_attachment"; // 标记笔记是否有附件,文本笔记没有附件,多媒体笔记至少有一个附件,数据类型:INTEGER(整型) - -public static final String NOTES_COUNT = "notes_count"; // 文件夹中笔记的数量,数据类型:INTEGER(长整型) - -public static final String TYPE = "type"; // 文件类型,标识为文件夹或笔记,数据类型:INTEGER(整型) - -public static final String SYNC_ID = "sync_id"; // 记录上次同步的ID,数据类型:INTEGER(长整型) - -public static final String LOCAL_MODIFIED = "local_modified"; // 本地修改标识,用来表示该项是否被本地修改过,数据类型:INTEGER(整型) - -public static final String ORIGIN_PARENT_ID = "origin_parent_id"; // 记录笔记或文件夹在移动到临时文件夹之前的原始父级ID,数据类型:INTEGER(整型) - -public static final String GTASK_ID = "gtask_id"; // 记录Google任务的ID,数据类型:TEXT(字符串) - -public static final String VERSION = "version"; // 记录笔记或文件夹的版本号,数据类型:INTEGER(长整型) - -/** - * DataColumns接口用于定义存储在数据表中的列字段,通常用于数据相关的记录。 - */ -public interface DataColumns { - public static final String ID = "_id"; // 记录行的唯一标识符,数据类型:INTEGER(长整型) - - public static final String MIME_TYPE = "mime_type"; // 记录数据项的MIME类型,数据类型:TEXT(字符串) - - public static final String NOTE_ID = "note_id"; // 记录数据所对应的笔记ID,数据类型:INTEGER(长整型) - - public static final String CREATED_DATE = "created_date"; // 记录数据创建的日期,数据类型:INTEGER(长整型) - - public static final String MODIFIED_DATE = "modified_date"; // 记录数据最后修改的日期,数据类型:INTEGER(长整型) - - public static final String CONTENT = "content"; // 记录数据的具体内容,数据类型:TEXT(字符串) - - public static final String DATA1 = "data1"; // 一个通用数据列,具体意义根据MIME类型而定,数据类型:INTEGER(整型) - - public static final String DATA2 = "data2"; // 另一个通用数据列,具体意义根据MIME类型而定,数据类型:INTEGER(整型) -} - /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * TEXT data type - *

Type: TEXT

- */ - public static final String DATA3 = "data3"; - - /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * TEXT data type - *

Type: TEXT

- */ - public static final String DATA4 = "data4"; - - /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * TEXT data type - *

Type: TEXT

- */ - public static final String DATA5 = "data5"; - } - - public static final class TextNote implements DataColumns { - /** - * Mode to indicate the text in check list mode or not - *

Type: Integer 1:check list mode 0: normal mode

- */ - public static final String MODE = DATA1; - - public static final int MODE_CHECK_LIST = 1; - - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; - - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; - - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); - } - - public static final class CallNote implements DataColumns { - /** - * Call date for this record - *

Type: INTEGER (long)

- */ - public static final String CALL_DATE = DATA1; - - /** - * Phone number for this record - *

Type: TEXT

- */ - public static final String PHONE_NUMBER = DATA3; - - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note"; - - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note"; - - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note"); - } -} - diff --git a/NotesDatabaseHelper.java b/NotesDatabaseHelper.java deleted file mode 100644 index 5b8ec06..0000000 --- a/NotesDatabaseHelper.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * 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.data; - -import android.content.ContentValues; -import android.content.Context; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.util.Log; - -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.DataConstants; -import net.micode.notes.data.Notes.NoteColumns; - -/** - * NotesDatabaseHelper 类用于管理应用中的SQLite数据库。 - * 这个类继承自 SQLiteOpenHelper,负责创建、升级数据库和管理数据表。 - */ -public class NotesDatabaseHelper extends SQLiteOpenHelper { - - // 数据库文件的名称 - private static final String DB_NAME = "note.db"; - - // 数据库的版本号,当前为4 - private static final int DB_VERSION = 4; - - /** - * 用于存储表名常量的接口。 - */ - public interface TABLE { - public static final String NOTE = "note"; // 存储笔记的表名 - public static final String DATA = "data"; // 存储笔记内容的表名 - } - - // 日志标签,用于调试和记录日志 - private static final String TAG = "NotesDatabaseHelper"; - - // 单例模式的实例 - private static NotesDatabaseHelper mInstance; - - /** - * 创建笔记表(note)的SQL语句。 - * 该表包含多个列,分别用于存储笔记的各类信息(例如ID、创建时间、修改时间等)。 - */ - private static final String CREATE_NOTE_TABLE_SQL = - "CREATE TABLE " + TABLE.NOTE + "(" + - NoteColumns.ID + " INTEGER PRIMARY KEY," + // 笔记的唯一ID - NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + // 父级笔记ID - NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + // 提醒时间 - NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + // 背景色ID - NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 创建时间,默认当前时间 - NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," + // 是否有附件 - NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 修改时间,默认当前时间 - NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + // 笔记包含的条目数 - NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + // 笔记的摘要或片段 - NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + // 笔记类型(例如普通笔记、待办事项等) - NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + // 小部件ID - NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + // 小部件类型 - NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + // 同步ID - NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," + // 本地修改标识 - NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + // 原始父级ID - NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + // Google任务ID - NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + // 笔记版本 - ")"; - - /** - * 创建数据表(data)的SQL语句。 - * 该表存储与笔记相关的附加数据,例如附件、图片等。 - */ - private static final String CREATE_DATA_TABLE_SQL = - "CREATE TABLE " + TABLE.DATA + "(" + - DataColumns.ID + " INTEGER PRIMARY KEY," + // 数据的唯一ID - DataColumns.MIME_TYPE + " TEXT NOT NULL," + // 数据的MIME类型(例如text, image等) - DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + // 关联的笔记ID - NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 创建时间,默认当前时间 - NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 修改时间,默认当前时间 - DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," + // 数据的内容 - DataColumns.DATA1 + " INTEGER," + // 附加数据字段1 - DataColumns.DATA2 + " INTEGER," + // 附加数据字段2 - DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + // 附加数据字段3 - DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + // 附加数据字段4 - DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + // 附加数据字段5 - ")"; - - /** - * 构造函数,传入上下文和数据库的名称与版本号,初始化父类。 - */ - public NotesDatabaseHelper(Context context) { - super(context, DB_NAME, null, DB_VERSION); - } - - /** - * 当数据库第一次创建时调用,执行创建表的SQL语句。 - * - * @param db SQLiteDatabase对象 - */ - @Override - public void onCreate(SQLiteDatabase db) { - // 创建笔记表 - db.execSQL(CREATE_NOTE_TABLE_SQL); - // 创建数据表 - db.execSQL(CREATE_DATA_TABLE_SQL); - } - - /** - * 当数据库版本号升级时调用,负责处理数据库结构的变更。 - * - * @param db SQLiteDatabase对象 - * @param oldVersion 旧的数据库版本 - * @param newVersion 新的数据库版本 - */ - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - // 在此可以根据版本号差异执行数据库升级的操作 - Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion); - // 例如,可以添加一些ALTER TABLE语句来迁移数据 - } - - /** - * 获取NotesDatabaseHelper的单例实例。 - */ -/** - * 获取NotesDatabaseHelper的单例对象。 - * 这个方法确保了整个应用中只有一个NotesDatabaseHelper实例被创建,并且是线程安全的。 - * @param context 上下文对象,用于获取应用程序的上下文环境。 - * @return NotesDatabaseHelper的单例对象。 - */ -public static synchronized NotesDatabaseHelper getInstance(Context context) { - // 如果mInstance是null,说明还没有创建实例,那么创建一个新的实例 - if (mInstance == null) { - mInstance = new NotesDatabaseHelper(context.getApplicationContext()); - } - // 返回单例对象 - return mInstance; -} - -// SQL语句,用于创建一个索引,提高根据note_id查询数据的效率。 -private static final String CREATE_DATA_NOTE_ID_INDEX_SQL = - "CREATE INDEX IF NOT EXISTS note_id_index ON " + - TABLE.DATA + "(" + DataColumns.NOTE_ID + ");"; - -/** - * 当笔记移动到文件夹时,增加文件夹的笔记计数。 - * 这个触发器在更新笔记的PARENT_ID字段后执行,用于更新文件夹的笔记计数。 - */ -private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = - "CREATE TRIGGER increase_folder_count_on_update "+ - " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + - " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + - " END"; - -/** - * 当笔记从文件夹移动出去时,减少文件夹的笔记计数。 - * 这个触发器在更新笔记的PARENT_ID字段后执行,用于更新文件夹的笔记计数。 - * 注意,只有当笔记计数大于0时才会减少,防止计数变为负数。 - */ -private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = - "CREATE TRIGGER decrease_folder_count_on_update " + - " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + - " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + - " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + - " END"; - -/** - * 当向文件夹中插入新笔记时,增加文件夹的笔记计数。 - * 这个触发器在插入新笔记后执行,用于更新文件夹的笔记计数。 - */ -private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER = - "CREATE TRIGGER increase_folder_count_on_insert " + - " AFTER INSERT ON " + TABLE.NOTE + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + - " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + - " END"; - -/** - * 当从文件夹中删除笔记时,减少文件夹的笔记计数。 - * 这个触发器在删除笔记后执行,用于更新文件夹的笔记计数。 - * 注意,只有当笔记计数大于0时才会减少,防止计数变为负数。 - */ -private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = - "CREATE TRIGGER decrease_folder_count_on_delete " + - " AFTER DELETE ON " + TABLE.NOTE + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + - " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + - " AND " + NoteColumns.NOTES_COUNT + ">0;" + - " END"; - - /** - * 当插入数据类型为{@link DataConstants#NOTE}时,更新笔记内容的触发器。 - * 这个触发器在数据表(DATA)插入新数据后执行,如果新数据的MIME_TYPE是NOTE,则更新笔记表(NOTE)中对应笔记的摘要(SNIPPET)。 - */ -private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER = - "CREATE TRIGGER update_note_content_on_insert " + - " AFTER INSERT ON " + TABLE.DATA + - " WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + - " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + - " END"; - -/** - * 当数据类型为{@link DataConstants#NOTE}的数据发生变化时,更新笔记内容的触发器。 - * 这个触发器在数据表(DATA)的数据更新后执行,如果旧数据的MIME_TYPE是NOTE,则更新笔记表(NOTE)中对应笔记的摘要(SNIPPET)。 - */ -private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER = - "CREATE TRIGGER update_note_content_on_update " + - " AFTER UPDATE ON " + TABLE.DATA + - " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + - " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + - " END"; - -/** - * 当数据类型为{@link DataConstants#NOTE}的数据被删除时,更新笔记内容的触发器。 - * 这个触发器在数据表(DATA)的数据删除后执行,如果旧数据的MIME_TYPE是NOTE,则将笔记表(NOTE)中对应笔记的摘要(SNIPPET)设置为空。 - */ -private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER = - "CREATE TRIGGER update_note_content_on_delete " + - " AFTER DELETE ON " + TABLE.DATA + - " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=''" + - " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + - " END"; - -/** - * 当笔记被删除时,删除属于该笔记的数据的触发器。 - * 这个触发器在笔记表(NOTE)的数据删除后执行,删除数据表(DATA)中所有属于被删除笔记的数据。 - */ -private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER = - "CREATE TRIGGER delete_data_on_delete " + - " AFTER DELETE ON " + TABLE.NOTE + - " BEGIN" + - " DELETE FROM " + TABLE.DATA + - " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + - " END"; - -/** - * 当文件夹被删除时,删除属于该文件夹的笔记的触发器。 - * 这个触发器在笔记表(NOTE)的数据删除后执行,删除笔记表(NOTE)中所有属于被删除文件夹的笔记。 - */ -private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER = - "CREATE TRIGGER folder_delete_notes_on_delete " + - " AFTER DELETE ON " + TABLE.NOTE + - " BEGIN" + - " DELETE FROM " + TABLE.NOTE + - " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + - " END"; - -/** - * 当文件夹被移动到垃圾文件夹时,移动属于该文件夹的笔记的触发器。 - * 这个触发器在笔记表(NOTE)的PARENT_ID字段更新后执行,如果新PARENT_ID是垃圾文件夹的ID,则将所有属于旧文件夹ID的笔记移动到垃圾文件夹。 - */ -private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER = - "CREATE TRIGGER folder_move_notes_on_trash " + - " AFTER UPDATE ON " + TABLE.NOTE + - " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + - " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + - " END"; - -// 构造函数,初始化数据库帮助类 -public NotesDatabaseHelper(Context context) { - super(context, DB_NAME, null, DB_VERSION); -} - -// 创建笔记表 -public void createNoteTable(SQLiteDatabase db) { - db.execSQL(CREATE_NOTE_TABLE_SQL); - reCreateNoteTableTriggers(db); - createSystemFolder(db); - Log.d(TAG, "note table has been created"); -} - -// 重新创建笔记表的触发器 -private void reCreateNoteTableTriggers(SQLiteDatabase db) { - // 省略了触发器的删除和创建代码,具体逻辑见上文注释 -} - -// 创建系统文件夹 -private void createSystemFolder(SQLiteDatabase db) { - // 省略了系统文件夹的创建代码,具体逻辑见上文注释 -} - -// 创建数据表 -public void createDataTable(SQLiteDatabase db) { - db.execSQL(CREATE_DATA_TABLE_SQL); - reCreateDataTableTriggers(db); - db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); - Log.d(TAG, "data table has been created"); -} - -// 重新创建数据表的触发器 -private void reCreateDataTableTriggers(SQLiteDatabase db) { - // 省略了触发器的删除和创建代码,具体逻辑见上文注释 -} - -// 获取数据库帮助类的单例对象 -static synchronized NotesDatabaseHelper getInstance(Context context) { - if (mInstance == null) { - mInstance = new NotesDatabaseHelper(context); - } - return mInstance; -} - -// 当数据库创建时,创建笔记表和数据表 -@Override -public void onCreate(SQLiteDatabase db) { - createNoteTable(db); - createDataTable(db); -} - -// 当数据库升级时,执行数据库升级操作 -@Override -public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - // 省略了数据库升级的具体代码,具体逻辑见上文注释 -} - -// 数据库升级到版本2 -private void upgradeToV2(SQLiteDatabase db) { - // 省略了升级到版本2的具体代码,具体逻辑见上文注释 -} - -// 数据库升级到版本3 -private void upgradeToV3(SQLiteDatabase db) { - // 省略了升级到版本3的具体代码,具体逻辑见上文注释 -} - -// 数据库升级到版本4 -private void upgradeToV4(SQLiteDatabase db) { - db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION - + " INTEGER NOT NULL DEFAULT 0"); -} diff --git a/NotesProvider.java b/NotesProvider.java deleted file mode 100644 index befa91c..0000000 --- a/NotesProvider.java +++ /dev/null @@ -1,377 +0,0 @@ -/* - * 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.data; - -// 导入Android框架中用于ContentProvider的相关类 -import android.app.SearchManager; -import android.content.ContentProvider; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Intent; -import android.content.UriMatcher; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.text.TextUtils; -import android.util.Log; - -// 导入应用内部定义的类和接口 -import net.micode.notes.R; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.data.NotesDatabaseHelper.TABLE; - -// 继承ContentProvider类,创建NotesProvider类,用于管理笔记数据 -public class NotesProvider extends ContentProvider { - // Uri匹配器,用于识别不同的URI路径 - private static final UriMatcher mMatcher; - - // 数据库帮助类实例,用于操作数据库 - private NotesDatabaseHelper mHelper; - - // 日志标签,用于Log日志输出 - private static final String TAG = "NotesProvider"; - - // 定义不同的URI代码,用于匹配不同的URI路径 - private static final int URI_NOTE = 1; - private static final int URI_NOTE_ITEM = 2; - private static final int URI_DATA = 3; - private static final int URI_DATA_ITEM = 4; - private static final int URI_SEARCH = 5; - private static final int URI_SEARCH_SUGGEST = 6; - - // 静态初始化块,初始化Uri匹配器 - static { - mMatcher = new UriMatcher(UriMatcher.NO_MATCH); - mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); - mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); - mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); - mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM); - mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH); - mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST); - mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST); - } - - // 定义搜索结果的投影,包括ID、摘要等信息 - /** - * x'0A'代表sqlite中的'\n'字符。为了在搜索结果中显示更多信息, - * 我们将截取标题和内容中的'\n'和空白。 - */ - private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," - + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," - + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + "," - + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + "," - + R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + "," - + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," - + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; - - // 定义笔记摘要搜索查询 - private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION - + " FROM " + TABLE.NOTE - + " WHERE " + NoteColumns.SNIPPET + " LIKE ?" - + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER - + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; - - // onCreate方法,初始化数据库帮助类实例 - @Override - public boolean onCreate() { - mHelper = NotesDatabaseHelper.getInstance(getContext()); - return true; - } - - // query方法,处理查询请求 - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - Cursor c = null; - SQLiteDatabase db = mHelper.getReadableDatabase(); - String id = null; - // 根据URI匹配结果,执行不同的查询操作 - switch (mMatcher.match(uri)) { - case URI_NOTE: - // 查询笔记表 - c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, - sortOrder); - break; - case URI_NOTE_ITEM: - // 查询单个笔记项 - id = uri.getPathSegments().get(1); - c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id - + parseSelection(selection), selectionArgs, null, null, sortOrder); - break; - case URI_DATA: - // 查询数据表 - c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null, - sortOrder); - break; - case URI_DATA_ITEM: - // 查询单个数据项 - id = uri.getPathSegments().get(1); - c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id - + parseSelection(selection), selectionArgs, null, null, sortOrder); - break; - case URI_SEARCH: - case URI_SEARCH_SUGGEST: - // 处理搜索请求 - if (sortOrder != null || projection != null) { - throw new IllegalArgumentException( - "do not specify sortOrder, selection, selectionArgs, or projection" + "with this query"); - } - - String searchString = null; - if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { - if (uri.getPathSegments().size() > 1) { - searchString = uri.getPathSegments().get(1); - } - } else { - searchString = uri.getQueryParameter("pattern"); - } - - if (TextUtils.isEmpty(searchString)) { - return null; - } - - try { - searchString = String.format("%%%s%%", searchString); - c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, - new String[] { searchString }); - } catch (IllegalStateException ex) { - Log.e(TAG, "got exception: " + ex.toString()); - } - break; - default: - throw new IllegalArgumentException("Unknown URI " + uri); - } - // 设置通知URI,以便在数据变化时通知外界 - if (c != null) { - c.setNotificationUri(getContext().getContentResolver(), uri); - } - return c; - } -} - - -以下是对代码中关键部分的注释: - -java -/** - * 实现ContentProvider接口的insert方法,用于插入新的数据。 - * @param uri 请求的URI,用于确定插入数据的表。 - * @param values 包含要插入数据的ContentValues。 - * @return 插入数据的URI,包括ID。 - */ -@Override -public Uri insert(Uri uri, ContentValues values) { - // 获取可写数据库实例 - SQLiteDatabase db = mHelper.getWritableDatabase(); - long dataId = 0, noteId = 0, insertedId = 0; - // 使用UriMatcher匹配URI,确定插入哪个表 - switch (mMatcher.match(uri)) { - case URI_NOTE: - // 插入笔记数据 - insertedId = noteId = db.insert(TABLE.NOTE, null, values); - break; - case URI_DATA: - // 插入数据,如果包含笔记ID,则记录 - if (values.containsKey(DataColumns.NOTE_ID)) { - noteId = values.getAsLong(DataColumns.NOTE_ID); - } else { - Log.d(TAG, "Wrong data format without note id:" + values.toString()); - } - insertedId = dataId = db.insert(TABLE.DATA, null, values); - break; - default: - // 如果URI不匹配,则抛出异常 - throw new IllegalArgumentException("Unknown URI " + uri); - } - // 如果插入笔记ID大于0,通知变化 - if (noteId > 0) { - getContext().getContentResolver().notifyChange( - ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); - } - // 如果插入数据ID大于0,通知变化 - if (dataId > 0) { - getContext().getContentResolver().notifyChange( - ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); - } - // 返回插入数据的URI - return ContentUris.withAppendedId(uri, insertedId); -} - -/** - * 实现ContentProvider接口的delete方法,用于删除数据。 - * @param uri 请求的URI,用于确定删除数据的表。 - * @param selection 删除条件。 - * @param selectionArgs 删除条件的参数。 - * @return 删除的行数。 - */ -@Override -public int delete(Uri uri, String selection, String[] selectionArgs) { - int count = 0; - String id = null; - SQLiteDatabase db = mHelper.getWritableDatabase(); - boolean deleteData = false; - // 使用UriMatcher匹配URI,确定删除哪个表 - switch (mMatcher.match(uri)) { - case URI_NOTE: - // 删除笔记数据,限制删除ID大于0的记录 - selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; - count = db.delete(TABLE.NOTE, selection, selectionArgs); - break; - case URI_NOTE_ITEM: - // 删除单个笔记项 - id = uri.getPathSegments().get(1); - long noteId = Long.valueOf(id); - if (noteId <= 0) { - break; - } - count = db.delete(TABLE.NOTE, - NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs); - break; - case URI_DATA: - // 删除数据表中的记录 - count = db.delete(TABLE.DATA, selection, selectionArgs); - deleteData = true; - break; - case URI_DATA_ITEM: - // 删除单个数据项 - id = uri.getPathSegments().get(1); - count = db.delete(TABLE.DATA, - DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); - deleteData = true; - break; - default: - // 如果URI不匹配,则抛出异常 - throw new IllegalArgumentException("Unknown URI " + uri); - } - // 如果删除了记录,通知变化 - if (count > 0) { - if (deleteData) { - getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); - } - getContext().getContentResolver().notifyChange(uri, null); - } - return count; -} - -/** - * 实现ContentProvider接口的update方法,用于更新数据。 - * @param uri 请求的URI,用于确定更新数据的表。 - * @param values 包含要更新数据的ContentValues。 - * @param selection 更新条件。 - * @param selectionArgs 更新条件的参数。 - * @return 更新的行数。 - */ -@Override -public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - int count = 0; - String id = null; - SQLiteDatabase db = mHelper.getWritableDatabase(); - boolean updateData = false; - // 使用UriMatcher匹配URI,确定更新哪个表 - switch (mMatcher.match(uri)) { - case URI_NOTE: - // 更新笔记数据,增加版本号 - increaseNoteVersion(-1, selection, selectionArgs); - count = db.update(TABLE.NOTE, values, selection, selectionArgs); - break; - case URI_NOTE_ITEM: - // 更新单个笔记项 - id = uri.getPathSegments().get(1); - increaseNoteVersion(Long.valueOf(id), selection, selectionArgs); - count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id - + parseSelection(selection), selectionArgs); - break; - case URI_DATA: - // 更新数据表中的记录 - count = db.update(TABLE.DATA, values, selection, selectionArgs); - updateData = true; - break; - case URI_DATA_ITEM: - // 更新单个数据项 - id = uri.getPathSegments().get(1); - count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id - + parseSelection(selection), selectionArgs); - updateData = true; - break; - default: - // 如果URI不匹配,则抛出异常 - throw new IllegalArgumentException("Unknown URI " + uri); - } - // 如果更新了记录,通知变化 - if (count > 0) { - if (updateData) { - getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); - } - getContext().getContentResolver().notifyChange(uri, null); - } - return count; -} - -/** - * 解析选择条件,添加AND前缀。 - * @param selection 选择条件。 - * @return 处理后的选择条件。 - */ -private String parseSelection(String selection) { - return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); -} - -/** - * 增加笔记的版本号。 - * @param id 笔记ID,-1表示更新所有匹配的记录。 - * @param selection 更新条件。 - * @param selectionArgs 更新条件的参数。 - */ -private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { - // 构建SQL语句,增加版本号 - StringBuilder sql = new StringBuilder(120); - sql.append("UPDATE "); - sql.append(TABLE.NOTE); - sql.append(" SET "); - sql.append(NoteColumns.VERSION); - sql.append("=" + NoteColumns.VERSION + "+1 "); - - if (id > 0 || !TextUtils.isEmpty(selection)) { - sql.append(" WHERE "); - } - if (id > 0) { - sql.append(NoteColumns.ID + "=" + String.valueOf(id)); - } - if (!TextUtils.isEmpty(selection)) { - String selectString = id > 0 ? parseSelection(selection) : selection; - for (String args : selectionArgs) { - selectString = selectString.replaceFirst("\\?", args); - } - sql.append(selectString); - } - - // 执行SQL语句 - mHelper.getWritableDatabase().execSQL(sql.toString()); -} - -/** - * 实现ContentProvider接口的getType方法,用于获取数据类型。 - * @param uri 请求的URI。 - * @return 数据类型,此方法未实现返回null。 - */ -@Override -public String getType(Uri uri) { - // TODO Auto-generated method stub - return null; - } -} diff --git a/SqlData.java b/SqlData.java deleted file mode 100644 index fb8aa23..0000000 --- a/SqlData.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * 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.data; - -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.util.Log; - -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.DataConstants; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.data.NotesDatabaseHelper.TABLE; -import net.micode.notes.gtask.exception.ActionFailureException; - -import org.json.JSONException; -import org.json.JSONObject; - -// SqlData 类用于处理与数据库相关的操作,特别是与笔记数据相关的操作。 -public class SqlData { - // 类的标签,用于日志记录。 - private static final String TAG = SqlData.class.getSimpleName(); - - // 一个无效的ID值,用于初始化或表示没有ID。 - private static final int INVALID_ID = -99999; - - // 数据库查询时使用的列投影。 - public static final String[] PROJECTION_DATA = new String[] { - DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1, - DataColumns.DATA3 - }; - - // 列索引常量。 - public static final int DATA_ID_COLUMN = 0; - public static final int DATA_MIME_TYPE_COLUMN = 1; - public static final int DATA_CONTENT_COLUMN = 2; - public static final int DATA_CONTENT_DATA_1_COLUMN = 3; - public static final int DATA_CONTENT_DATA_3_COLUMN = 4; - - // 数据库操作相关的成员变量。 - private ContentResolver mContentResolver; - private boolean mIsCreate; - private long mDataId; - private String mDataMimeType; - private String mDataContent; - private long mDataContentData1; - private String mDataContentData3; - private ContentValues mDiffDataValues; - - // SqlData 的构造函数,用于创建一个新的SqlData实例。 - public SqlData(Context context) { - mContentResolver = context.getContentResolver(); - mIsCreate = true; - mDataId = INVALID_ID; - mDataMimeType = DataConstants.NOTE; - mDataContent = ""; - mDataContentData1 = 0; - mDataContentData3 = ""; - mDiffDataValues = new ContentValues(); - } - - // SqlData 的另一个构造函数,用于从数据库游标中加载数据。 - public SqlData(Context context, Cursor c) { - mContentResolver = context.getContentResolver(); - mIsCreate = false; - loadFromCursor(c); - mDiffDataValues = new ContentValues(); - } - - // 从游标中加载数据的方法。 - private void loadFromCursor(Cursor c) { - mDataId = c.getLong(DATA_ID_COLUMN); - mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); - mDataContent = c.getString(DATA_CONTENT_COLUMN); - mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN); - mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); - } - - // 从JSONObject中设置内容的方法。 - public void setContent(JSONObject js) throws JSONException { - long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; - // 如果是新建或者ID不匹配,则更新ID。 - if (mIsCreate || mDataId != dataId) { - mDiffDataValues.put(DataColumns.ID, dataId); - } - mDataId = dataId; - - // 设置MIME类型,如果发生变化则更新。 - String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE) - : DataConstants.NOTE; - if (mIsCreate || !mDataMimeType.equals(dataMimeType)) { - mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType); - } - mDataMimeType = dataMimeType; - - // 设置内容,如果发生变化则更新。 - String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : ""; - if (mIsCreate || !mDataContent.equals(dataContent)) { - mDiffDataValues.put(DataColumns.CONTENT, dataContent); - } - mDataContent = dataContent; - - // 设置DATA1,如果发生变化则更新。 - long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0; - if (mIsCreate || mDataContentData1 != dataContentData1) { - mDiffDataValues.put(DataColumns.DATA1, dataContentData1); - } - mDataContentData1 = dataContentData1; - - // 设置DATA3,如果发生变化则更新。 - String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : ""; - if (mIsCreate || !mDataContentData3.equals(dataContentData3)) { - mDiffDataValues.put(DataColumns.DATA3, dataContentData3); - } - mDataContentData3 = dataContentData3; - } - - // 获取内容并返回JSONObject的方法。 - public JSONObject getContent() throws JSONException { - if (mIsCreate) { - Log.e(TAG, "it seems that we haven't created this in database yet"); - return null; - } - JSONObject js = new JSONObject(); - js.put(DataColumns.ID, mDataId); - js.put(DataColumns.MIME_TYPE, mDataMimeType); - js.put(DataColumns.CONTENT, mDataContent); - js.put(DataColumns.DATA1, mDataContentData1); - js.put(DataColumns.DATA3, mDataContentData3); - return js; - } - - // 提交数据到数据库的方法。 - public void commit(long noteId, boolean validateVersion, long version) { - if (mIsCreate) { - // 如果是新建数据,插入到数据库中。 - if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) { - mDiffDataValues.remove(DataColumns.ID); - } - - mDiffDataValues.put(DataColumns.NOTE_ID, noteId); - Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues); - try { - mDataId = Long.valueOf(uri.getPathSegments().get(1)); - } catch (NumberFormatException e) { - Log.e(TAG, "Get note id error :" + e.toString()); - throw new ActionFailureException("create note failed"); - } - } else { - // 如果是更新数据,根据版本号更新数据库中的记录。 - if (mDiffDataValues.size() > 0) { - int result = 0; - if (!validateVersion) { - result = mContentResolver.update(ContentUris.withAppendedId( - Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null); - } else { - result = mContentResolver.update(ContentUris.withAppendedId( - Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, - " ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE - + " WHERE " + NoteColumns.VERSION + "=?)", new String[] { - String.valueOf(noteId), String.valueOf(version) - }); - } - if (result == 0) { - Log.w(TAG, "there is no update. maybe user updates note when syncing"); - } - } - } - - // 清除差异值并标记为非新建状态。 - mDiffDataValues.clear(); - mIsCreate = false; - } - - // 获取数据ID的方法。 - public long getId() { - return mDataId; - } -} \ No newline at end of file diff --git a/SqlNote.java b/SqlNote.java deleted file mode 100644 index eef8f9c..0000000 --- a/SqlNote.java +++ /dev/null @@ -1,581 +0,0 @@ -/* - * 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.data; - -import android.appwidget.AppWidgetManager; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.util.Log; - -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.exception.ActionFailureException; -import net.micode.notes.tool.GTaskStringUtils; -import net.micode.notes.tool.ResourceParser; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; - -/** - * SqlNote 类用于管理与 Notes 数据库相关的操作, - * 提供对笔记数据的增、删、查、改操作。 - * 该类将与 GTask 等数据交互,使用 SQLite 数据库与 ContentProvider 进行数据存取。 - */ -public class SqlNote { - - // 日志标签,用于输出调试信息 - private static final String TAG = SqlNote.class.getSimpleName(); - - // 定义一个无效的 ID 值,用于初始化或标识错误的 ID - private static final int INVALID_ID = -99999; - - // 定义一个 Notes 表的列名数组,用于查询操作中获取不同的列数据 - public static final String[] PROJECTION_NOTE = new String[] { - NoteColumns.ID, // 笔记的 ID - NoteColumns.ALERTED_DATE, // 提醒日期 - NoteColumns.BG_COLOR_ID, // 背景颜色 ID - NoteColumns.CREATED_DATE, // 创建日期 - NoteColumns.HAS_ATTACHMENT, // 是否有附件 - NoteColumns.MODIFIED_DATE, // 修改日期 - NoteColumns.NOTES_COUNT, // 笔记内容数量 - NoteColumns.PARENT_ID, // 父笔记 ID - NoteColumns.SNIPPET, // 笔记内容的摘录 - NoteColumns.TYPE, // 笔记类型 - NoteColumns.WIDGET_ID, // 小部件 ID - NoteColumns.WIDGET_TYPE, // 小部件类型 - NoteColumns.SYNC_ID, // 同步 ID - NoteColumns.LOCAL_MODIFIED, // 本地修改标记 - NoteColumns.ORIGIN_PARENT_ID, // 原始父笔记 ID - NoteColumns.GTASK_ID, // Google 任务 ID - NoteColumns.VERSION // 笔记版本 - }; - - // 每一列在查询返回的 Cursor 中的索引 - public static final int ID_COLUMN = 0; - public static final int ALERTED_DATE_COLUMN = 1; - public static final int BG_COLOR_ID_COLUMN = 2; - public static final int CREATED_DATE_COLUMN = 3; - public static final int HAS_ATTACHMENT_COLUMN = 4; - public static final int MODIFIED_DATE_COLUMN = 5; - public static final int NOTES_COUNT_COLUMN = 6; - public static final int PARENT_ID_COLUMN = 7; - public static final int SNIPPET_COLUMN = 8; - public static final int TYPE_COLUMN = 9; - public static final int WIDGET_ID_COLUMN = 10; - public static final int WIDGET_TYPE_COLUMN = 11; - public static final int SYNC_ID_COLUMN = 12; - public static final int LOCAL_MODIFIED_COLUMN = 13; - public static final int ORIGIN_PARENT_ID_COLUMN = 14; - public static final int GTASK_ID_COLUMN = 15; - public static final int VERSION_COLUMN = 16; - - // 上下文和内容解析器,提供与系统服务的交互接口 - private Context mContext; - private ContentResolver mContentResolver; - - // 是否是新创建的笔记 - private boolean mIsCreate; - - // 笔记的各类数据成员 - private long mId; - private long mAlertDate; - private int mBgColorId; - private long mCreatedDate; - private int mHasAttachment; - private long mModifiedDate; - private long mParentId; - private String mSnippet; - private int mType; - private int mWidgetId; - private int mWidgetType; - private long mOriginParent; - private long mVersion; - - // 保存笔记的差异数据 - private ContentValues mDiffNoteValues; - - // 存储与笔记相关的数据列表 - private ArrayList mDataList; -} - -// 构造函数:用于创建一个新笔记对象,初始化其成员变量 -public SqlNote(Context context) { - // 初始化上下文和内容解析器,用于访问应用的内容提供者 - mContext = context; - mContentResolver = context.getContentResolver(); - - // 标记这是一个新创建的笔记 - mIsCreate = true; - - // 初始化各个成员变量,设置默认值 - mId = INVALID_ID; // 默认的无效ID - mAlertDate = 0; // 默认没有提醒 - mBgColorId = ResourceParser.getDefaultBgId(context); // 获取默认背景颜色 - mCreatedDate = System.currentTimeMillis(); // 设置为当前时间戳 - mHasAttachment = 0; // 默认没有附件 - mModifiedDate = System.currentTimeMillis(); // 设置为当前时间戳 - mParentId = 0; // 默认父ID为0 - mSnippet = ""; // 默认笔记摘录为空字符串 - mType = Notes.TYPE_NOTE; // 默认笔记类型为普通笔记 - mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; // 默认小部件ID无效 - mWidgetType = Notes.TYPE_WIDGET_INVALIDE; // 默认小部件类型无效 - mOriginParent = 0; // 默认原始父ID为0 - mVersion = 0; // 默认版本为0 - mDiffNoteValues = new ContentValues(); // 用于存储笔记差异的ContentValues - mDataList = new ArrayList(); // 初始化数据列表,用于存储与笔记相关的数据 -} - -// 构造函数:用于从数据库中的Cursor加载现有笔记对象 -public SqlNote(Context context, Cursor c) { - // 初始化上下文和内容解析器 - mContext = context; - mContentResolver = context.getContentResolver(); - - // 标记这是一个已存在的笔记 - mIsCreate = false; - - // 从Cursor中加载数据 - loadFromCursor(c); - - // 初始化数据列表 - mDataList = new ArrayList(); - - // 如果是普通笔记,加载相关的数据内容 - if (mType == Notes.TYPE_NOTE) { - loadDataContent(); - } - - // 初始化差异数据的ContentValues - mDiffNoteValues = new ContentValues(); -} - -// 构造函数:用于根据笔记ID从数据库加载笔记数据 -public SqlNote(Context context, long id) { - // 初始化上下文和内容解析器 - mContext = context; - mContentResolver = context.getContentResolver(); - - // 标记这是一个已存在的笔记 - mIsCreate = false; - - // 根据ID加载数据 - loadFromCursor(id); - - // 初始化数据列表 - mDataList = new ArrayList(); - - // 如果是普通笔记,加载相关的数据内容 - if (mType == Notes.TYPE_NOTE) { - loadDataContent(); - } - - // 初始化差异数据的ContentValues - mDiffNoteValues = new ContentValues(); -} - -// 私有方法:根据笔记ID加载数据,执行数据库查询,返回指定笔记的Cursor -private void loadFromCursor(long id) { - Cursor c = null; - try { - // 通过ID查询笔记数据 - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)", - new String[] { - String.valueOf(id) - }, null); - - // 如果查询结果不为空,移动Cursor到下一行并加载数据 - if (c != null) { - c.moveToNext(); - loadFromCursor(c); // 从Cursor加载数据到当前对象 - } else { - Log.w(TAG, "loadFromCursor: cursor = null"); // 如果Cursor为空,打印警告 - } - } finally { - // 查询完成后关闭Cursor - if (c != null) - c.close(); - } -} - -// 私有方法:从Cursor中加载数据,将数据映射到当前对象的成员变量 -private void loadFromCursor(Cursor c) { - // 根据列的索引从Cursor中获取数据并赋值给相应的成员变量 - mId = c.getLong(ID_COLUMN); - mAlertDate = c.getLong(ALERTED_DATE_COLUMN); - mBgColorId = c.getInt(BG_COLOR_ID_COLUMN); - mCreatedDate = c.getLong(CREATED_DATE_COLUMN); - mHasAttachment = c.getInt(HAS_ATTACHMENT_COLUMN); - mModifiedDate = c.getLong(MODIFIED_DATE_COLUMN); - mParentId = c.getLong(PARENT_ID_COLUMN); - mSnippet = c.getString(SNIPPET_COLUMN); - mType = c.getInt(TYPE_COLUMN); - mWidgetId = c.getInt(WIDGET_ID_COLUMN); - mWidgetType = c.getInt(WIDGET_TYPE_COLUMN); - mVersion = c.getLong(VERSION_COLUMN); -} - -// 私有方法:加载与笔记相关的数据内容,查询笔记的附加数据并存储在 mDataList 中 -private void loadDataContent() { - Cursor c = null; - mDataList.clear(); // 清空当前数据列表 - try { - // 根据笔记ID查询相关的数据内容 - c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA, - "(note_id=?)", new String[] { - String.valueOf(mId) - }, null); - - // 如果查询结果不为空,处理数据 - if (c != null) { - if (c.getCount() == 0) { - Log.w(TAG, "it seems that the note has not data"); // 如果没有数据,打印警告 - return; - } - - // 遍历查询结果,将每一条数据加入到数据列表 - while (c.moveToNext()) { - SqlData data = new SqlData(mContext, c); - mDataList.add(data); - } - } else { - Log.w(TAG, "loadDataContent: cursor = null"); // 如果Cursor为空,打印警告 - } - } finally { - // 查询完成后关闭Cursor - if (c != null) - c.close(); - } -} - // 设置笔记内容的方法 -public boolean setContent(JSONObject js) { - try { - // 从传入的JSONObject中获取笔记对象 - JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - // 检查笔记类型是否为系统笔记,如果是,则打印警告日志 - if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { - Log.w(TAG, "cannot set system folder"); - } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { - // 如果是文件夹类型,只能更新摘要和类型 - // 更新摘要 - String snippet = note.has(NoteColumns.SNIPPET) ? note - .getString(NoteColumns.SNIPPET) : ""; - if (mIsCreate || !mSnippet.equals(snippet)) { - mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); - } - mSnippet = snippet; - - // 更新类型 - int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) - : Notes.TYPE_NOTE; - if (mIsCreate || mType != type) { - mDiffNoteValues.put(NoteColumns.TYPE, type); - } - mType = type; - } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) { - // 如果是普通笔记类型,更新笔记的各种属性 - JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); - long id = note.has(NoteColumns.ID) ? note.getLong(NoteColumns.ID) : INVALID_ID; - // 更新ID - if (mIsCreate || mId != id) { - mDiffNoteValues.put(NoteColumns.ID, id); - } - mId = id; - - // 更新提醒日期 - long alertDate = note.has(NoteColumns.ALERTED_DATE) ? note - .getLong(NoteColumns.ALERTED_DATE) : 0; - if (mIsCreate || mAlertDate != alertDate) { - mDiffNoteValues.put(NoteColumns.ALERTED_DATE, alertDate); - } - mAlertDate = alertDate; - - // 更新背景颜色ID - int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note - .getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext); - if (mIsCreate || mBgColorId != bgColorId) { - mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId); - } - mBgColorId = bgColorId; - - // 更新创建日期 - long createDate = note.has(NoteColumns.CREATED_DATE) ? note - .getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis(); - if (mIsCreate || mCreatedDate != createDate) { - mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate); - } - mCreatedDate = createDate; - - // 更新是否有附件 - int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note - .getInt(NoteColumns.HAS_ATTACHMENT) : 0; - if (mIsCreate || mHasAttachment != hasAttachment) { - mDiffNoteValues.put(NoteColumns.HAS_ATTACHMENT, hasAttachment); - } - mHasAttachment = hasAttachment; - - // 更新修改日期 - long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note - .getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis(); - if (mIsCreate || mModifiedDate != modifiedDate) { - mDiffNoteValues.put(NoteColumns.MODIFIED_DATE, modifiedDate); - } - mModifiedDate = modifiedDate; - - // 更新父ID - long parentId = note.has(NoteColumns.PARENT_ID) ? note - .getLong(NoteColumns.PARENT_ID) : 0; - if (mIsCreate || mParentId != parentId) { - mDiffNoteValues.put(NoteColumns.PARENT_ID, parentId); - } - mParentId = parentId; - - // 更新摘要 - String snippet = note.has(NoteColumns.SNIPPET) ? note - .getString(NoteColumns.SNIPPET) : ""; - if (mIsCreate || !mSnippet.equals(snippet)) { - mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); - } - mSnippet = snippet; - - // 更新类型 - int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) - : Notes.TYPE_NOTE; - if (mIsCreate || mType != type) { - mDiffNoteValues.put(NoteColumns.TYPE, type); - } - mType = type; - - // 更新小部件ID - int widgetId = note.has(NoteColumns.WIDGET_ID) ? note.getInt(NoteColumns.WIDGET_ID) - : AppWidgetManager.INVALID_APPWIDGET_ID; - if (mIsCreate || mWidgetId != widgetId) { - mDiffNoteValues.put(NoteColumns.WIDGET_ID, widgetId); - } - mWidgetId = widgetId; - - // 更新小部件类型 - int widgetType = note.has(NoteColumns.WIDGET_TYPE) ? note - .getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE; - if (mIsCreate || mWidgetType != widgetType) { - mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType); - } - mWidgetType = widgetType; - - // 更新原始父ID - long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note - .getLong(NoteColumns.ORIGIN_PARENT_ID) : 0; - if (mIsCreate || mOriginParent != originParent) { - mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent); - } - mOriginParent = originParent; - - // 更新数据内容 - for (int i = 0; i < dataArray.length(); i++) { - JSONObject data = dataArray.getJSONObject(i); - SqlData sqlData = null; - if (data.has(DataColumns.ID)) { - long dataId = data.getLong(DataColumns.ID); - for (SqlData temp : mDataList) { - if (dataId == temp.getId()) { - sqlData = temp; - } - } - } - - if (sqlData == null) { - sqlData = new SqlData(mContext); - mDataList.add(sqlData); - } - - sqlData.setContent(data); - } - } - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - return false; - } - return true; -} - -// 获取笔记内容的方法 -public JSONObject getContent() { - try { - JSONObject js = new JSONObject(); - - if (mIsCreate) { - Log.e(TAG, "it seems that we haven't created this in database yet"); - return null; - } - - JSONObject note = new JSONObject(); - if (mType == Notes.TYPE_NOTE) { - // 如果是普通笔记类型,构建包含所有属性的JSONObject - note.put(NoteColumns.ID, mId); - note.put(NoteColumns.ALERTED_DATE, mAlertDate); - note.put(NoteColumns.BG_COLOR_ID, mBgColorId); - note.put(NoteColumns.CREATED_DATE, mCreatedDate); - note.put(NoteColumns.HAS_ATTACHMENT, mHasAttachment); - note.put(NoteColumns.MODIFIED_DATE, mModifiedDate); - note.put(NoteColumns.PARENT_ID, mParentId); - note.put(NoteColumns.SNIPPET, mSnippet); - note.put(NoteColumns.TYPE, mType); - note.put(NoteColumns.WIDGET_ID, mWidgetId); - note.put(NoteColumns.WIDGET_TYPE, mWidgetType); - note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent); - js.put(GTaskStringUtils.META_HEAD_NOTE, note); - - JSONArray dataArray = new JSONArray(); - for (SqlData sqlData : mDataList) { - JSONObject data = sqlData.getContent(); - if (data != null) { - dataArray.put(data); - } - } - js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); - } else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) { - // 如果是文件夹或系统笔记类型,构建包含ID、类型和摘要的JSONObject - note.put(NoteColumns.ID, mId); - note.put(NoteColumns.TYPE, mType); - note.put(NoteColumns.SNIPPET, mSnippet); - js.put(GTaskStringUtils.META_HEAD_NOTE, note); - } - - return js; - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - } - return null; -} - -// 设置笔记的父ID -public void setParentId(long id) { - mParentId = id; - mDiffNoteValues.put(NoteColumns.PARENT_ID, id); -} - -// 设置笔记的GTask ID -public void setGtaskId(String gid) { - mDiffNoteValues.put(NoteColumns.GTASK_ID, gid); -} - -// 设置笔记的同步ID -public void setSyncId(long syncId) { - mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId); -} - -// 重置本地修改标记 -public void resetLocalModified() { - mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0); -} - -// 获取笔记的ID -public long getId() { - return mId; -} - -// 获取笔记的父ID -public long getParentId() { - return mParentId; -} - -// 获取笔记的摘要 -public String getSnippet() { - return mSnippet; -} - -// 检查笔记是否为普通笔记类型 -public boolean isNoteType() { - return mType == Notes.TYPE_NOTE; -} - -// 提交笔记数据,包括创建和更新 -public void commit(boolean validateVersion) { -if (mIsCreate) { -// 如果是创建笔记,插入数据到数据库并获取新创建的笔记ID -if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) { -mDiffNoteValues.remove(NoteColumns.ID); -} - - Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues); - try { - mId = Long.valueOf(uri.getPathSegments().get(1)); - } catch (NumberFormatException e) { - Log.e(TAG, "Get note id error :" + e.toString()); - throw new ActionFailureException("create note failed"); - } - if (mId == 0) { - throw new IllegalStateException("Create thread id failed"); - } - - if (mType == Notes.TYPE_NOTE) { - // 如果是普通笔记类型,提交关联的数据内容 - for (SqlData sqlData : mDataList) { - sqlData.commit(mId, false, -1); - } - } -} else { - // 如果是更新笔记,检查ID是否有效 - if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) { - Log.e(TAG, "No such note"); - throw new IllegalStateException("Try to update note with invalid id"); - } - if (mDiffNoteValues.size() > 0) { - mVersion ++; - // 更新数据库中的笔记数据 - int result = 0; - if (!validateVersion) { - result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" - + NoteColumns.ID + "=?)", new String[] { - String.valueOf(mId) - }); - } else { - result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" - + NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)", - new String[] { - String.valueOf(mId), String.valueOf(mVersion) - }); - } - if (result == 0) { - Log.w(TAG, "there is no update. maybe user updates note when syncing"); - } - } - - if (mType == Notes.TYPE_NOTE) { - // 如果是普通笔记类型,提交关联的数据内容 - for (SqlData sqlData : mDataList) { - sqlData.commit(mId, validateVersion, mVersion); - } - } -} - -// 刷新本地信息 -loadFromCursor(mId); -if (mType == Notes.TYPE_NOTE) - loadDataContent(); - -mDiffNoteValues.clear(); -mIsCreate = false; -} diff --git a/Task.java b/Task.java deleted file mode 100644 index a3ce644..0000000 --- a/Task.java +++ /dev/null @@ -1,424 +0,0 @@ -/* - * 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.data; - -// 导入Android SDK中用于数据库操作、文本处理、日志记录的类 -import android.database.Cursor; -import android.text.TextUtils; -import android.util.Log; - -// 导入项目中用于笔记数据操作的类 -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.DataConstants; -import net.micode.notes.data.Notes.NoteColumns; -// 导入项目中定义的异常类 -import net.micode.notes.gtask.exception.ActionFailureException; -// 导入项目中的工具类,用于处理GTask相关的字符串常量 -import net.micode.notes.tool.GTaskStringUtils; - -// 导入JSON处理相关的类 -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -// Task类继承自Node类,表示一个任务 -public class Task extends Node { - // 类的标签,用于日志记录 - private static final String TAG = Task.class.getSimpleName(); - - // 任务的完成状态 - private boolean mCompleted; - - // 任务的备注信息 - private String mNotes; - - // 任务的元信息,以JSON对象形式存储 - private JSONObject mMetaInfo; - - // 任务的前一个兄弟任务 - private Task mPriorSibling; - - // 任务所在的任务列表 - private TaskList mParent; - - // 构造函数,初始化任务的属性 - public Task() { - super(); - mCompleted = false; - mNotes = null; - mPriorSibling = null; - mParent = null; - mMetaInfo = null; - } - - // 生成创建任务的JSON对象 - public JSONObject getCreateAction(int actionId) { - JSONObject js = new JSONObject(); - - try { - // action_type - js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, - GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE); - - // action_id - js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - - // index - js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this)); - - // entity_delta - JSONObject entity = new JSONObject(); - entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); - entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); - entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE, - GTaskStringUtils.GTASK_JSON_TYPE_TASK); - if (getNotes() != null) { - entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); - } - js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); - - // parent_id - js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid()); - - // dest_parent_type - js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE, - GTaskStringUtils.GTASK_JSON_TYPE_GROUP); - - // list_id - js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid()); - - // prior_sibling_id - if (mPriorSibling != null) { - js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid()); - } - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("fail to generate task-create jsonobject"); - } - - return js; - } - - // 生成更新任务的JSON对象 - public JSONObject getUpdateAction(int actionId) { - JSONObject js = new JSONObject(); - - try { - // action_type - js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, - GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); - - // action_id - js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - - // id - js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); - - // entity_delta - JSONObject entity = new JSONObject(); - entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); - if (getNotes() != null) { - entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); - } - entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); - js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("fail to generate task-update jsonobject"); - } - - return js; - } - /** - * 使用远程JSON对象设置任务内容。 - * @param js 远程JSON对象,包含任务的数据。 - */ -public void setContentByRemoteJSON(JSONObject js) { - if (js != null) { - try { - // 如果JSON对象中有id字段,则设置任务的全局标识符 - if (js.has(GTaskStringUtils.GTASK_JSON_ID)) { - setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); - } - - // 如果JSON对象中有last_modified字段,则设置任务的最后修改时间 - if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { - setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); - } - - // 如果JSON对象中有name字段,则设置任务的名称 - if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { - setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); - } - - // 如果JSON对象中有notes字段,则设置任务的备注 - if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) { - setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES)); - } - - // 如果JSON对象中有deleted字段,则设置任务的删除状态 - if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) { - setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED)); - } - - // 如果JSON对象中有completed字段,则设置任务的完成状态 - if (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) { - setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED)); - } - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("fail to get task content from jsonobject"); - } - } -} - -/** - * 使用本地JSON对象设置任务内容。 - * @param js 本地JSON对象,包含任务的数据。 - */ -public void setContentByLocalJSON(JSONObject js) { - if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE) - || !js.has(GTaskStringUtils.META_HEAD_DATA)) { - Log.w(TAG, "setContentByLocalJSON: nothing is available"); - } - - try { - JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); - - // 验证笔记类型是否正确 - if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) { - Log.e(TAG, "invalid type"); - return; - } - - // 遍历数据数组,查找并设置任务的名称 - for (int i = 0; i < dataArray.length(); i++) { - JSONObject data = dataArray.getJSONObject(i); - if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) { - setName(data.getString(DataColumns.CONTENT)); - break; - } - } - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - } -} - -/** - * 从任务内容生成本地JSON对象。 - * @return 本地JSON对象。 - */ -public JSONObject getLocalJSONFromContent() { - String name = getName(); - try { - if (mMetaInfo == null) { - // 新任务从网页创建 - if (name == null) { - Log.w(TAG, "the note seems to be an empty one"); - return null; - } - - JSONObject js = new JSONObject(); - JSONObject note = new JSONObject(); - JSONArray dataArray = new JSONArray(); - JSONObject data = new JSONObject(); - data.put(DataColumns.CONTENT, name); - dataArray.put(data); - js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); - note.put(NoteColumns.TYPE, Notes.TYPE_NOTE); - js.put(GTaskStringUtils.META_HEAD_NOTE, note); - return js; - } else { - // 已同步的任务 - JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA); - - // 更新任务名称 - for (int i = 0; i < dataArray.length(); i++) { - JSONObject data = dataArray.getJSONObject(i); - if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) { - data.put(DataColumns.CONTENT, getName()); - break; - } - } - - note.put(NoteColumns.TYPE, Notes.TYPE_NOTE); - return mMetaInfo; - } - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - return null; - } -} - -/** - * 设置任务的元信息。 - * @param metaData 包含元信息的数据对象。 - */ -public void setMetaInfo(MetaData metaData) { - if (metaData != null && metaData.getNotes() != null) { - try { - mMetaInfo = new JSONObject(metaData.getNotes()); - } catch (JSONException e) { - Log.w(TAG, e.toString()); - mMetaInfo = null; - } - } -} - -/** - * 根据数据库游标和任务的元信息确定同步操作。 - * @param c 数据库游标。 - * @return 同步操作的类型。 - */ -public int getSyncAction(Cursor c) { - try { - JSONObject noteInfo = null; - if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) { - noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - } - - if (noteInfo == null) { - Log.w(TAG, "it seems that note meta has been deleted"); - return SYNC_ACTION_UPDATE_REMOTE; - } - - if (!noteInfo.has(NoteColumns.ID)) { - Log.w(TAG, "remote note id seems to be deleted"); - return SYNC_ACTION_UPDATE_LOCAL; - } - - // 验证笔记id是否匹配 - if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) { - Log.w(TAG, "note id doesn't match"); - return SYNC_ACTION_UPDATE_LOCAL; - } - - if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { - // 没有本地更新 - if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // 双方都没有更新 - return SYNC_ACTION_NONE; - } else { - // 应用远程更新到本地 - return SYNC_ACTION_UPDATE_LOCAL; - } - } else { - // 验证gtask id - if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { - Log.e(TAG, "gtask id doesn't match"); - return SYNC_ACTION_ERROR; - } - if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // 只有本地修改 - return SYNC_ACTION_UPDATE_REMOTE; - } else { - return SYNC_ACTION_UPDATE_CONFLICT; - } - } - } catch (Exception e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - } - - return SYNC_ACTION_ERROR; -} - -/** - * 判断任务是否值得保存。 - * @return 如果任务有元信息、名称或备注,则返回true。 - */ -public boolean isWorthSaving() { - return mMetaInfo != null || (getName() != null && getName().trim().length() > 0) - || (getNotes() != null && getNotes().trim().length() > 0); -} - -/** - * 设置任务的完成状态。 - * @param completed 完成状态。 - */ -public void setCompleted(boolean completed) { - this.mCompleted = completed; -} - -/** - * 设置任务的备注。 - * @param notes 备注信息。 - */ -public void setNotes(String notes) { - this.mNotes = notes; -} - -/** - * 设置任务的前一个兄弟任务。 - * @param priorSibling 前一个兄弟任务。 - */ -public void setPriorSibling(Task priorSibling) { - this.mPriorSibling = priorSibling; -} - -/** - * 设置任务所在的任务列表。 - * @param parent 任务列表。 - */ -public void setParent(TaskList parent) { - this.mParent = parent; -} - -/** - * 获取任务的完成状态。 - * @return 完成状态。 - */ -public boolean getCompleted() { - return this.mCompleted; -} - -/** - * 获取任务的备注。 - * @return 备注信息。 - */ -public String getNotes() { - return this.mNotes; -} - -/** - * 获取任务的前一个兄弟任务。 - * @return 前一个兄弟任务。 - */ -public Task getPriorSibling() { - return this.mPriorSibling; -} - -/** - * 获取任务所在的任务列表。 - * @return 任务列表。 - */ -public TaskList getParent() { - return this.mParent; -} -} diff --git a/TaskList.java b/TaskList.java deleted file mode 100644 index 9e83ebe..0000000 --- a/TaskList.java +++ /dev/null @@ -1,482 +0,0 @@ -/* - * 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.data; - -// 导入Android SDK中用于数据库操作、日志记录的类 -import android.database.Cursor; -import android.util.Log; - -// 导入项目中用于笔记数据操作的类 -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.NoteColumns; -// 导入项目中定义的异常类 -import net.micode.notes.gtask.exception.ActionFailureException; -// 导入项目中的工具类,用于处理GTask相关的字符串常量 -import net.micode.notes.tool.GTaskStringUtils; - -// 导入JSON处理相关的类 -import org.json.JSONException; -import org.json.JSONObject; - -// 导入Java的ArrayList,用于存储任务列表 -import java.util.ArrayList; - -/** - * TaskList类继承自Node类,表示一个任务列表 - */ -public class TaskList extends Node { - // 类的标签,用于日志记录 - private static final String TAG = TaskList.class.getSimpleName(); - - // 任务列表的索引 - private int mIndex; - - // 任务列表中的子任务集合 - private ArrayList mChildren; - - /** - * 构造函数,初始化任务列表的属性 - */ - public TaskList() { - super(); - mChildren = new ArrayList(); - mIndex = 1; - } - - /** - * 生成创建任务列表的JSON对象 - * @param actionId 动作ID - * @return 创建任务列表的JSON对象 - */ - public JSONObject getCreateAction(int actionId) { - JSONObject js = new JSONObject(); - - try { - // action_type - js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, - GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE); - - // action_id - js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - - // index - js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex); - - // entity_delta - JSONObject entity = new JSONObject(); - entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); - entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); - entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE, - GTaskStringUtils.GTASK_JSON_TYPE_GROUP); - js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("fail to generate tasklist-create jsonobject"); - } - - return js; - } - - /** - * 生成更新任务列表的JSON对象 - * @param actionId 动作ID - * @return 更新任务列表的JSON对象 - */ - public JSONObject getUpdateAction(int actionId) { - JSONObject js = new JSONObject(); - - try { - // action_type - js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, - GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); - - // action_id - js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - - // id - js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); - - // entity_delta - JSONObject entity = new JSONObject(); - entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); - entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); - js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("fail to generate tasklist-update jsonobject"); - } - - return js; - } - - /** - * 使用远程JSON对象设置任务列表内容 - * @param js 远程JSON对象,包含任务列表的数据 - */ - public void setContentByRemoteJSON(JSONObject js) { - if (js != null) { - try { - // id - if (js.has(GTaskStringUtils.GTASK_JSON_ID)) { - setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); - } - - // last_modified - if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { - setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); - } - - // name - if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { - setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); - } - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("fail to get tasklist content from jsonobject"); - } - } - } - - /** - * 使用本地JSON对象设置任务列表内容 - * @param js 本地JSON对象,包含任务列表的数据 - */ - public void setContentByLocalJSON(JSONObject js) { - if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) { - Log.w(TAG, "setContentByLocalJSON: nothing is available"); - } - - try { - JSONObject folder = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - - // 根据笔记类型设置任务列表名称 - if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { - String name = folder.getString(NoteColumns.SNIPPET); - setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name); - } else if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { - if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER) - setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT); - else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER) - setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_CALL_NOTE); - else - Log.e(TAG, "invalid system folder"); - } else { - Log.e(TAG, "error type"); - } - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - } - } - /** - * 获取本地JSON对象,从内容中创建。 - * - * @return 返回一个JSONObject,其中包含了文件夹信息。 - */ -public JSONObject getLocalJSONFromContent() { - // 尝试创建一个新的JSONObject - try { - JSONObject js = new JSONObject(); - JSONObject folder = new JSONObject(); - - // 获取文件夹名称 - String folderName = getName(); - // 如果文件夹名称以MIUI_FOLDER_PREFFIX开头,则去掉这个前缀 - if (getName().startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX)) - folderName = folderName.substring(GTaskStringUtils.MIUI_FOLDER_PREFFIX.length(), - folderName.length()); - // 将文件夹名称放入folder对象中 - folder.put(NoteColumns.SNIPPET, folderName); - // 根据文件夹名称设置文件夹类型 - if (folderName.equals(GTaskStringUtils.FOLDER_DEFAULT) - || folderName.equals(GTaskStringUtils.FOLDER_CALL_NOTE)) - folder.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - else - folder.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); - - // 将folder对象放入js对象中 - js.put(GTaskStringUtils.META_HEAD_NOTE, folder); - - // 返回js对象 - return js; - } catch (JSONException e) { - // 如果发生异常,记录错误并打印堆栈跟踪,然后返回null - Log.e(TAG, e.toString()); - e.printStackTrace(); - return null; - } -} - -/** - * 根据游标(Cursor)确定同步操作。 - * - * @param c 游标对象,包含数据库列信息。 - * @return 返回一个整数,表示同步操作类型。 - */ -public int getSyncAction(Cursor c) { - try { - // 如果本地修改列为0,表示没有本地更新 - if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { - // 如果同步ID与最后修改时间相同,表示两边都没有更新 - if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - return SYNC_ACTION_NONE; - } else { - // 应用远程更新到本地 - return SYNC_ACTION_UPDATE_LOCAL; - } - } else { - // 验证gtask id是否匹配 - if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { - Log.e(TAG, "gtask id doesn't match"); - return SYNC_ACTION_ERROR; - } - // 如果同步ID与最后修改时间相同,表示只有本地修改 - if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - return SYNC_ACTION_UPDATE_REMOTE; - } else { - // 对于文件夹冲突,只应用本地修改 - return SYNC_ACTION_UPDATE_REMOTE; - } - } - } catch (Exception e) { - // 如果发生异常,记录错误并打印堆栈跟踪 - Log.e(TAG, e.toString()); - e.printStackTrace(); - } - - // 发生错误时返回错误代码 - return SYNC_ACTION_ERROR; -} - -/** - * 获取子任务的数量。 - * - * @return 返回子任务列表的大小。 - */ -public int getChildTaskCount() { - return mChildren.size(); -} - -/** - * 添加一个子任务。 - * - * @param task 要添加的子任务对象。 - * @return 返回是否成功添加。 - */ -public boolean addChildTask(Task task) { - boolean ret = false; - // 如果任务不为空且不在子任务列表中,则添加它 - if (task != null && !mChildren.contains(task)) { - ret = mChildren.add(task); - // 如果添加成功,设置前一个兄弟节点和父节点 - if (ret) { - task.setPriorSibling(mChildren.isEmpty() ? null : mChildren - .get(mChildren.size() - 1)); - task.setParent(this); - } - } - return ret; -} - -/** - * 在指定位置添加一个子任务。 - * - * @param task 要添加的子任务对象。 - * @param index 要插入的索引位置。 - * @return 返回是否成功添加。 - */ -public boolean addChildTask(Task task, int index) { - // 如果索引无效,则记录错误并返回false - if (index < 0 || index > mChildren.size()) { - Log.e(TAG, "add child task: invalid index"); - return false; - } - - // 尝试在子任务列表中找到任务的位置 - int pos = mChildren.indexOf(task); - // 如果任务不为空且不在子任务列表中,则添加它 - if (task != null && pos == -1) { - mChildren.add(index, task); - - // 更新任务列表 - Task preTask = null; - Task afterTask = null; - if (index != 0) - preTask = mChildren.get(index - 1); - if (index != mChildren.size() - 1) - afterTask = mChildren.get(index + 1); - - task.setPriorSibling(preTask); - if (afterTask != null) - afterTask.setPriorSibling(task); - } - - return true; -} - -/** - * 移除一个子任务。 - * - * @param task 要移除的子任务对象。 - * @return 返回是否成功移除。 - */ -public boolean removeChildTask(Task task) { - boolean ret = false; - // 尝试在子任务列表中找到任务的索引 - int index = mChildren.indexOf(task); - // 如果找到了任务,则移除它 - if (index != -1) { - ret = mChildren.remove(task); - - // 如果移除成功,重置前一个兄弟节点和父节点 - if (ret) { - task.setPriorSibling(null); - task.setParent(null); - - // 更新任务列表 - if (index != mChildren.size()) { - mChildren.get(index).setPriorSibling( - index == 0 ? null : mChildren.get(index - 1)); - } - } - } - return ret; -} - -/** - * 移动一个子任务到指定位置。 - * - * @param task 要移动的子任务对象。 - * @param index 要移动到的索引位置。 - * @return 返回是否成功移动。 - */ -public boolean moveChildTask(Task task, int index) { - - // 如果索引无效,则记录错误并返回false - if (index < 0 || index >= mChildren.size()) { - Log.e(TAG, "move child task: invalid index"); - return false; - } - - // 尝试在子任务列表中找到任务的位置 - int pos = mChildren.indexOf(task); - // 如果任务不在列表中,则记录错误并返回false - if (pos == -1) { - Log.e(TAG, "move child task: the task should in the list"); - return false; - } - - // 如果任务已经在指定位置,则直接返回true - if (pos == index) - return true; - // 先移除任务,然后添加到新位置 - return (removeChildTask(task) && addChildTask(task, index)); -} - -/** - * 根据GID查找子任务。 - * - * @param gid 子任务的GID。 - * @return 返回找到的子任务对象,如果没有找到则返回null。 - */ -public Task findChildTaskByGid(String gid) { - for (int i = 0; i < mChildren.size(); i++) { - Task t = mChildren.get(i); - // 如果找到匹配的GID,则返回对应的子任务 - if (t.getGid().equals(gid)) { - return t; - } - } - return null; -} - -/** - * 根据索引获取子任务。 - * - * @param index 子任务的索引。 - * @return 返回子任务对象,如果索引无效则返回null。 - */ -public int getChildTaskIndex(Task task) { - return mChildren.indexOf(task); -} - -/** - * 根据索引获取子任务。 - * - * @param index 子任务的索引。 - * @return 返回子任务对象,如果索引无效则返回null。 - */ -public Task getChildTaskByIndex(int index) { - // 如果索引无效,则记录错误并返回null - if (index < 0 || index >= mChildren.size()) { - Log.e(TAG, "getTaskByIndex: invalid index"); - return null; - } - return mChildren.get(index); -} - -/** - * 根据GID获取子任务。 - * - * @param gid 子任务的GID。 - * @return 返回找到的子任务对象,如果没有找到则返回null。 - */ -public Task getChilTaskByGid(String gid) { - for (Task task : mChildren) { - // 如果找到匹配的GID,则返回对应的子任务 - if (task.getGid().equals(gid)) - return task; - } - return null; -} - -/** - * 获取所有子任务的列表。 - * - * @return 返回子任务列表。 - */ -public ArrayList getChildTaskList() { - return this.mChildren; -} - -/** - * 设置任务的索引。 - * - * @param index 任务的索引。 - */ -public void setIndex(int index) { - this.mIndex = index; -} - -/** - * 获取任务的索引。 - * - * @return 返回任务的索引。 - */ -public int getIndex() { - return this.mIndex; -} diff --git a/WorkingNote.java b/WorkingNote.java deleted file mode 100644 index 88b5afb..0000000 --- a/WorkingNote.java +++ /dev/null @@ -1,401 +0,0 @@ -/* - * 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.model; - -import android.appwidget.AppWidgetManager; -import android.content.ContentUris; -import android.content.Context; -import android.database.Cursor; -import android.text.TextUtils; -import android.util.Log; - -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.CallNote; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.DataConstants; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.data.Notes.TextNote; -import net.micode.notes.tool.ResourceParser.NoteBgResources; - -// 表示一个工作笔记的类 -public class WorkingNote { - // 笔记对象 - private Note mNote; - // 笔记ID - private long mNoteId; - // 笔记内容 - private String mContent; - // 笔记模式 - private int mMode; - - // 笔记提醒日期 - private long mAlertDate; - - // 笔记修改日期 - private long mModifiedDate; - - // 笔记背景颜色ID - private int mBgColorId; - - // 笔记小部件ID - private int mWidgetId; - - // 笔记小部件类型 - private int mWidgetType; - - // 笔记文件夹ID - private long mFolderId; - - // 上下文对象 - private Context mContext; - - // 日志标签 - private static final String TAG = "WorkingNote"; - - // 笔记是否被删除 - private boolean mIsDeleted; - - // 笔记设置改变监听器 - private NoteSettingChangedListener mNoteSettingStatusListener; - - // 数据库查询使用的字段数组 - public static final String[] DATA_PROJECTION = new String[] { - DataColumns.ID, - DataColumns.CONTENT, - DataColumns.MIME_TYPE, - DataColumns.DATA1, - DataColumns.DATA2, - DataColumns.DATA3, - DataColumns.DATA4, - }; - - // 笔记查询使用的字段数组 - public static final String[] NOTE_PROJECTION = new String[] { - NoteColumns.PARENT_ID, - NoteColumns.ALERTED_DATE, - NoteColumns.BG_COLOR_ID, - NoteColumns.WIDGET_ID, - NoteColumns.WIDGET_TYPE, - NoteColumns.MODIFIED_DATE - }; - - // 数据库查询结果的列索引 - private static final int DATA_ID_COLUMN = 0; - private static final int DATA_CONTENT_COLUMN = 1; - private static final int DATA_MIME_TYPE_COLUMN = 2; - private static final int DATA_MODE_COLUMN = 3; - private static final int NOTE_PARENT_ID_COLUMN = 0; - private static final int NOTE_ALERTED_DATE_COLUMN = 1; - private static final int NOTE_BG_COLOR_ID_COLUMN = 2; - private static final int NOTE_WIDGET_ID_COLUMN = 3; - private static final int NOTE_WIDGET_TYPE_COLUMN = 4; - private static final int NOTE_MODIFIED_DATE_COLUMN = 5; - - // 创建一个新的工作笔记 - private WorkingNote(Context context, long folderId) { - mContext = context; - mAlertDate = 0; - mModifiedDate = System.currentTimeMillis(); - mFolderId = folderId; - mNote = new Note(); - mNoteId = 0; - mIsDeleted = false; - mMode = 0; - mWidgetType = Notes.TYPE_WIDGET_INVALIDE; - } - - // 根据ID加载一个已存在的工作笔记 - private WorkingNote(Context context, long noteId, long folderId) { - mContext = context; - mNoteId = noteId; - mFolderId = folderId; - mIsDeleted = false; - mNote = new Note(); - loadNote(); - } - - // 加载笔记数据 - private void loadNote() { - Cursor cursor = mContext.getContentResolver().query( - ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null, - null, null); - - if (cursor != null) { - if (cursor.moveToFirst()) { - mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); - mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN); - mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN); - mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN); - mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN); - mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); - } - cursor.close(); - } else { - Log.e(TAG, "No note with id:" + mNoteId); - throw new IllegalArgumentException("Unable to find note with id " + mNoteId); - } - loadNoteData(); - } - - // 加载笔记的具体内容数据 - private void loadNoteData() { - Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, - DataColumns.NOTE_ID + "=?", new String[] { - String.valueOf(mNoteId) - }, null); - - if (cursor != null) { - if (cursor.moveToFirst()) { - do { - String type = cursor.getString(DATA_MIME_TYPE_COLUMN); - if (DataConstants.NOTE.equals(type)) { - mContent = cursor.getString(DATA_CONTENT_COLUMN); - mMode = cursor.getInt(DATA_MODE_COLUMN); - mNote.setTextDataId(cursor.getLong(DATA_ID_COLUMN)); - } else if (DataConstants.CALL_NOTE.equals(type)) { - mNote.setCallDataId(cursor.getLong(DATA_ID_COLUMN)); - } else { - Log.d(TAG, "Wrong note type with type:" + type); - } - } while (cursor.moveToNext()); - } - cursor.close(); - } else { - Log.e(TAG, "No data with id:" + mNoteId); - throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId); - } - } - - // 创建一个空的工作笔记 - public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, - int widgetType, int defaultBgColorId) { - WorkingNote note = new WorkingNote(context, folderId); - note.setBgColorId(defaultBgColorId); - note.setWidgetId(widgetId); - note.setWidgetType(widgetType); - return note; - } - - // 根据ID加载工作笔记 - public static WorkingNote load(Context context, long id) { - return new WorkingNote(context, id, 0); - } - - // 保存笔记到数据库 - public synchronized boolean saveNote() { - if (isWorthSaving()) { - if (!existInDatabase()) { - if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) { - Log.e(TAG, "Create new note fail with id:" + mNoteId); - return false; - } - } - - mNote.syncNote(mContext, mNoteId); - - /** - * 如果存在任何小部件,则更新小部件内容 - */ - if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID - && mWidgetType != Notes.TYPE_WIDGET_INVALIDE - && mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onWidgetChanged(); - } - return true; - } else { - return false; - } - } - - // 检查笔记是否在数据库中存在 - public boolean existInDatabase() { - return mNoteId > 0; - } - - // 检查笔记是否值得保存 - private boolean isWorthSaving() { - if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent)) - || (existInDatabase() && !mNote.isLocalModified())) { - return false; - } else { - return true; - } - } - - // 设置笔记设置状态改变的监听器 -public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) { - mNoteSettingStatusListener = l; -} - -// 设置提醒日期,并根据参数决定是否设置提醒 -public void setAlertDate(long date, boolean set) { - if (date != mAlertDate) { - mAlertDate = date; - mNote.setNoteValue(NoteColumns.ALERTED_DATE, String.valueOf(mAlertDate)); - } - if (mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onClockAlertChanged(date, set); - } -} - -// 标记笔记为删除或未删除状态 -public void markDeleted(boolean mark) { - mIsDeleted = mark; - if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID - && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onWidgetChanged(); - } -} - -// 设置笔记的背景颜色ID -public void setBgColorId(int id) { - if (id != mBgColorId) { - mBgColorId = id; - if (mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onBackgroundColorChanged(); - } - mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id)); - } -} - -// 设置笔记的 checklist 模式 -public void setCheckListMode(int mode) { - if (mMode != mode) { - if (mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode); - } - mMode = mode; - mNote.setTextData(TextNote.MODE, String.valueOf(mMode)); - } -} - -// 设置笔记的小部件类型 -public void setWidgetType(int type) { - if (type != mWidgetType) { - mWidgetType = type; - mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType)); - } -} - -// 设置笔记的小部件ID -public void setWidgetId(int id) { - if (id != mWidgetId) { - mWidgetId = id; - mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId)); - } -} - -// 设置笔记的工作文本 -public void setWorkingText(String text) { - if (!TextUtils.equals(mContent, text)) { - mContent = text; - mNote.setTextData(DataColumns.CONTENT, mContent); - } -} - -// 将笔记转换为通话记录笔记 -public void convertToCallNote(String phoneNumber, long callDate) { - mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate)); - mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber); - mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(Notes.ID_CALL_RECORD_FOLDER)); -} - -// 检查笔记是否有闹钟提醒 -public boolean hasClockAlert() { - return (mAlertDate > 0 ? true : false); -} - -// 获取笔记内容 -public String getContent() { - return mContent; -} - -// 获取提醒日期 -public long getAlertDate() { - return mAlertDate; -} - -// 获取修改日期 -public long getModifiedDate() { - return mModifiedDate; -} - -// 获取背景颜色资源ID -public int getBgColorResId() { - return NoteBgResources.getNoteBgResource(mBgColorId); -} - -// 获取背景颜色ID -public int getBgColorId() { - return mBgColorId; -} - -// 获取标题背景资源ID -public int getTitleBgResId() { - return NoteBgResources.getNoteTitleBgResource(mBgColorId); -} - -// 获取checklist模式 -public int getCheckListMode() { - return mMode; -} - -// 获取笔记ID -public long getNoteId() { - return mNoteId; -} - -// 获取文件夹ID -public long getFolderId() { - return mFolderId; -} - -// 获取小部件ID -public int getWidgetId() { - return mWidgetId; -} - -// 获取小部件类型 -public int getWidgetType() { - return mWidgetType; -} - -// 笔记设置改变监听器接口 -public interface NoteSettingChangedListener { - /** - * 当前笔记的背景颜色刚刚改变时调用 - */ - void onBackgroundColorChanged(); - - /** - * 用户设置闹钟时调用 - */ - void onClockAlertChanged(long date, boolean set); - - /** - * 用户从小部件创建笔记时调用 - */ - void onWidgetChanged(); - - /** - * 在checklist模式和普通模式之间切换时调用 - * @param oldMode 改变前的模式 - * @param newMode 新的模式 - */ - void onCheckListModeChanged(int oldMode, int newMode); - } -}