diff --git a/README.md b/README.md index 4757b3d..cc0bb1f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ +<<<<<<< HEAD +# xiaominotes +======= # Notes +>>>>>>> wangmingqiang_branch diff --git a/doc/实践模板-开源软件泛读、标注和维护报告文档2.docx b/doc/实践模板-开源软件泛读、标注和维护报告文档2.docx deleted file mode 100644 index 9056bb5..0000000 Binary files a/doc/实践模板-开源软件泛读、标注和维护报告文档2.docx and /dev/null differ diff --git a/doc/实践模板-开源软件泛读、标注和维护报告文档(最终版).docx b/doc/实践模板-开源软件泛读、标注和维护报告文档(最终版).docx new file mode 100644 index 0000000..02bfa43 Binary files /dev/null and b/doc/实践模板-开源软件泛读、标注和维护报告文档(最终版).docx differ diff --git a/doc/小米便签泛读报告(包图类图的实现).docx b/doc/小米便签泛读报告(包图类图的实现).docx deleted file mode 100644 index aebb260..0000000 Binary files a/doc/小米便签泛读报告(包图类图的实现).docx and /dev/null differ diff --git a/src/GTaskASyncTask.java b/src/GTaskASyncTask.java deleted file mode 100644 index b7e17cb..0000000 --- a/src/GTaskASyncTask.java +++ /dev/null @@ -1,216 +0,0 @@ -/** - * @ProiectName:MiNote - * @Package: gtask.remote - * @ClassName: GTaskASyncTask - * @Description:GTaskASyncTask类是一个异步任务类,用于执行后台任务并在UI线程更新相关的UI组件。 - * 其功能包括1.后台任务的执行:例如从服务器获取数据、执行文件读写操作等。这些任务将在后台线程中执行,避免在UI线程中执行耗时操作而阻塞UI响应。 - * 2.进度更新和反馈:在任务执行过程中,GTaskASyncTask类可以通过调用publishProgress()方法更新任务的进度, - * 并且在UI线程中回调onProgressUpdate()方法,以便更新相关的UI组件 - * 3.结果返回和处理:当任务执行完成后,GTaskASyncTask类会将执行结果返回给UI线程,并在UI线程中回调onPostExecute()方法。 - * 在该方法中,可以根据任务执行结果更新UI组件、执行其他操作或显示提示信息。 - * @Author: wmq -*/ - -package net.micode.notes.gtask.remote; - -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.os.AsyncTask; - -import net.micode.notes.R; -import net.micode.notes.ui.NotesListActivity; -import net.micode.notes.ui.NotesPreferenceActivity; - -/** - * @功能名: 定义名为GTaskASyncTask的类,并声明了一些成员变量和内部接口 - * @参数 : - * mContext:上下文对象,用于获取系统服务。 - * mNotifiManager:通知管理器,用于发送通知。 - * mTaskManager:GTaskManager的实例,用于管理任务。 - * mOnCompleteListener:任务完成的回调接口。 - * @功能描述:通过在GTaskASyncTask类中声明这些成员变量和内部接口, - * 可以在异步任务的执行过程中使用上下文、通知管理器和任务管理器等资源, - * 并在任务完成时回调通知调用者。这样可以更好地管理和控制异步任务的执行,并提供灵活的任务完成回调机制。 - * @实现过程: - * @Author: wmq -*/ -public class GTaskASyncTask extends AsyncTask {//执行的任务可以接收Void类型的输入参数,发布String类型的进度信息,最终返回Integer类型的结果。 - - private static int GTASK_SYNC_NOTIFICATION_ID = 5234235;//静态变量,用于标识通知的ID。通常用于发送通知时唯一标识通知的标识符。 - - public interface OnCompleteListener {//内部接口,定义了一个回调方法onComplete()。当任务完成时,可以通过实现该接口,在任务完成时进行回调通知。 - void onComplete(); - } - - private Context mContext; - - private NotificationManager mNotifiManager; - - private GTaskManager mTaskManager; - - private OnCompleteListener mOnCompleteListener; - -/** - * @功能名: GTaskASyncTask - * @参数 : context/listener - * @功能描述: 是本类的构造函数,)接收一个上下文对象作为参数,并在构造函数内部进行了一些初始化操作 - * @实现过程: 见每一行后面 - * @Author: wmq -*/ - public GTaskASyncTask(Context context, OnCompleteListener listener) { - mContext = context; //将传入的OnCompleteListener接口的实例赋值给成员变量mOnCompleteListener。用于在任务完成时回调通知调用者。 - mOnCompleteListener = listener; - mNotifiManager = (NotificationManager) mContext - .getSystemService(Context.NOTIFICATION_SERVICE);//通过上下文对象获取通知管理器的实例。该通知管理器用于发送通知。 - mTaskManager = GTaskManager.getInstance();//:通过调用GTaskManager类的静态方法getInstance()获取GTaskManager的单例实例。mTaskManager用于管理任务的执行。 - } -/** - * @功能名: cancelSync() - * @参数 : - * @功能描述: 取消正在进行的同步任务 - * @实现过程: 通过调用mTaskManager的cancelSync()方法来取消同步任务 - * 某些情况下,用户需要停止或取消当前正在执行的任务,例如用户手动取消了同步操作或者发生了异常情况需要终止任务 - * @Author: wmq -*/ - - public void cancelSync() { - mTaskManager.cancelSync(); - } -/** - * @功能名: publishProgess - * @参数 :message - * @功能描述: 用于发布任务执行的进度信息,在异步任务的执行过程中,有时需要将一些进度信息反馈给用户, - * 可以通过调用publishProgress()方法来实现。该方法会在UI线程调用onProgressUpdate()方法,从而更 - * 新UI界面上的进度信息。 - * @实现过程: publishProgess方法重载了AsyncTask类中的publishProgress()方法, - * 并将传入的message作为进度信息进行发布。这样,外部调用者就可以通过调用GTaskASyncTask - * 对象的publishProgess()方法来发布任务的执行进度信息,从而实现任务进度的实时反馈。 - * @Author: wmq -*/ - public void publishProgess(String message) {// 发布进度单位,系统将会调用onProgressUpdate()方法更新这些值 - 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; - 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); - notification.contentIntent = pendingIntent; - mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); - }*/ - /** - * @功能名: showNotification - * @参数 :int tickerId / String content - * @功能描述: - * 根据传入的tickerId参数判断通知的类型: - * 使用Notification.Builder类来构建通知: - * 通过调用builder.getNotification()方法获取构建的通知对象; - * 最后使用mNotifiManager.notify()方法发送通知 - * @实现过程: 如果tickerId不等于R.string.ticker_success(即不是成功的通知),则创建一个将跳转到 - * NotesPreferenceActivity类的PendingIntent对象。如果tickerId等于R.string.ticker_success - * (即成功的通知),则创建一个将跳转到NotesListActivity类的PendingIntent对象。 - * @Author: wmq - */ - private void showNotification(int tickerId, String content) { - - 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.Builder builder = new Notification.Builder(mContext) - - .setAutoCancel(true) //设置通知点击后自动取消 - - .setContentTitle(mContext.getString(R.string.app_name))//设置通知的标题为应用名称。 - - .setContentText(content)//设置通知的内容为传入的content参数。 - - .setContentIntent(pendingIntent)//设置通知点击时的跳转意图为之前创建的PendingIntent对象。 - - .setWhen(System.currentTimeMillis())//时间设置 - - .setOngoing(true);//用户无法手动清除 - - Notification notification=builder.getNotification(); - - mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);//将通知显示在系统通知栏中。其中GTASK_SYNC_NOTIFICATION_ID作为通知的ID,可以用于标识该通知。 - - } - - /** - * @功能名: doInBackground - * @参数 : unused - * @功能描述: 用于在后台执行耗时操作,如网络请求、数据库查询等任务。 - * @实现过程: @Override注解表示该方法是对父类(AsyncTask)中的方法进行重写 - *在执行过程中可以调用publishProgress()方法来更新异步任务的执行进度。 - *最后返回同步操作的结果,通常是一个代表同步状态的整数值。 - * @Author: wmq - */ - @Override - protected void onProgressUpdate(String... progress) { - showNotification(R.string.ticker_syncing, progress[0]); - if (mContext instanceof GTaskSyncService) { - ((GTaskSyncService) mContext).sendBroadcast(progress[0]); - } - } - - /** - * @功能名: onPostExecute - * @参数 : result - * @功能描述: 用于在后台操作完成后执行一些操作,通常是更新UI界面或者执行回调函数。 - * @实现过程: 利用result进行不同状态的判断,并执行相应的方法,具体在下面标注 - * @Author: wmq - */ - @Override //表示该方法是对父类(AsyncTask)中的方法进行重写 - protected void onPostExecute(Integer result) { //这表示该方法接收一个Integer类型的参数result,表示后台操作的结果。 - if (result == GTaskManager.STATE_SUCCESS) { //表示同步操作成功,那么会显示一个通知,更新上次同步时间,并执行NotesPreferenceActivity.setLastSyncTime()方法保存最新的同步时间。 - 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) { //表示内部错误,会显示一个通知,提示同步时发生内部错误。如果result等于 - 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) { //如果存在mOnCompleteListener回调函数对象,会在新的线程中执行mOnCompleteListener.onComplete()方法。 - new Thread(new Runnable() { - - public void run() { - mOnCompleteListener.onComplete(); - } - }).start(); - } - } -} diff --git a/src/GTaskClient.java b/src/GTaskClient.java deleted file mode 100644 index ba9f188..0000000 --- a/src/GTaskClient.java +++ /dev/null @@ -1,767 +0,0 @@ -/** - * @ProiectName:MiNote - * @Package: gtask.remote - * @ClassName: GTaskAClient - * @Description: 主要实现GTask客户端,提供了与Google Tasks API进行交互的一系列方法,使得小米便签能够使用Google Tasks作为后端任务管理服务。 - * @Author: wmq -*/ - -package net.micode.notes.gtask.remote; -//以下内容为引入Android中的各个类 -import android.accounts.Account;//引入Android中的Account类,代表一个用户账户 -import android.accounts.AccountManager;//引入Android中的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 - * @功能描述: GTaskClient类的成员变量声明 - * @实现过程: 成员变量在类的方法中被使用和操作,用于存储和处理GTaskClient的状态和数据。 - * @Author: wmq -*/ -public class GTaskClient { - private static final String TAG = GTaskClient.class.getSimpleName();//TAG是一个常量字符串,用于在日志输出中标识GTaskClient类。 - - 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"; - - private static GTaskClient mInstance = null; - - private DefaultHttpClient mHttpClient; - - private String mGetUrl; - - private String mPostUrl; - - private long mClientVersion; - - private boolean mLoggedin; - - private long mLastLoginTime; - - private int mActionId; - - private Account mAccount; - - private JSONArray mUpdateArray; - -/** - * @功能名: GTaskClient() - * @功能描述: 私有的构造函数,用于创建GTaskClient类的实例 - * @实现过程: 将各个变量分别初始化,表示初始状态 - * @Author: wmq -*/ - private GTaskClient() { - mHttpClient = null; //将mHttpClient初始化为null,表示初始情况下没有可用的HTTP客户端。 - mGetUrl = GTASK_GET_URL; - mPostUrl = GTASK_POST_URL; - mClientVersion = -1; //将mClientVersion初始化为-1,表示客户端版本号未知。 - mLoggedin = false; //将mLoggedin初始化为false,表示当前未登录状态。 - mLastLoginTime = 0; //将mLastLoginTime初始化为0,表示上次登录时间为初始状态。 - mActionId = 1; - mAccount = null; - mUpdateArray = null; - } -/** - * @功能名:getInstance - * @参数 :mInstance - * @功能描述: 用来获取的实例化对象 - * @实现过程: 使用getInstance(),返回mInstance这个实例化对 - * @Author: wmq -*/ - public static synchronized GTaskClient getInstance() { - if (mInstance == null) { - mInstance = new GTaskClient(); - } - return mInstance; - } -/** - * @功能名: login - * @参数 : activity - * @功能描述: 实现了对Google Tasks服务的登录操作,包括对登录状态的判断、获取授权Token和根据账户类型选择不同的登录URL等逻辑 - * @实现过程: 定义了一个间隔时间,检查上次登录的时间加上间隔时间是否已经超过了当前时间 - * 检查如果已经登录,当前同步的账户与之前保存的账户是否一致, - * @Author: wmq -*/ - public boolean login(Activity activity) { - // we suppose that the cookie would expire after 5 minutes - // then we need to re-login - final long interval = 1000 * 60 * 5; - if (mLastLoginTime + interval < System.currentTimeMillis()) { - mLoggedin = false; - } - - // need to re-login after account switch - if (mLoggedin - && !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity - .getSyncAccountName(activity))) { - mLoggedin = false; - } - - if (mLoggedin) { - Log.d(TAG, "already logged in"); - return true; - } - - mLastLoginTime = System.currentTimeMillis(); - String authToken = loginGoogleAccount(activity, false);//进行账户登录,获取授权Token。 - if (authToken == null) { - Log.e(TAG, "login google account failed"); - return false; - } - - // login with custom domain if necessary - 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; - } - } - - // try to login with google official url - /** - *条件判断和逻辑是根据账户类型(是否是自定义域名或者google官方账户)来确定登录的URL, - *并尝试进行登录操作。如果登录成功,则将mLoggedin设置为true,表示登录成功。 - */ - if (!mLoggedin) { - mGetUrl = GTASK_GET_URL; - mPostUrl = GTASK_POST_URL; - if (!tryToLoginGtask(activity, authToken)) { - return false; - } - } - - mLoggedin = true;//将登录状态设置为true,并返回true表示登录成功。 - return true; - } - /** - * @功能名: loginGoogleAccount - * @参数 : activity(对象)/invalidateToken - * @功能描述: 用于获取Google账户的授权Token - * @实现过程: 首先,获取系统的AccountManager对象,用于管理账户信息。 - * 然后,获取所有类型为"com.google"的账户。 - * 如果没有找到任何Google账户,就会打印错误日志并返回null。 - * 接下来,从应用的偏好设置中获取要同步的账户名称。 - * 然后,遍历所有账户,找到与要同步的账户名称匹配的账户对象。 - * 如果找到了匹配的账户,将其赋值给mAccount变量;否则,打印错误日志并返回null。 - * 接着,调用getAuthToken方法获取指定账户的授权Token - * 通过调用accountManagerFuture.getResult()方法获取授权Token,并将其保存在authToken变量中。 - * 递归调用loginGoogleAccount(activity, false)方法重新获取新的授权Token。 - * 如果获取授权Token的过程中发生异常,就会打印错误日志,并将authToken设置为null。 - * 最后,返回获取到的授权Token。 - * @Author: wmq - */ - private String loginGoogleAccount(Activity activity, boolean invalidateToken) { - String authToken; - AccountManager accountManager = AccountManager.get(activity);//获取系统对象 - Account[] accounts = accountManager.getAccountsByType("com.google");//获取类型为"com.google"账户 - - 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; - } - - // get the token now - AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account, - "goanna_mobile", null, activity, null, null); - //"goanna_mobile"是用于访问Google服务的令牌类型 - 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; - } -/** - * @功能名: tryToLoginGtask - * @参数 : activity(对象) / authToken - * @功能描述: 尝试使用给定的授权Token登录Google任务(GTask)服务 - * @实现过程: tryToLoginGtask方法首先调用loginGtask方法,尝试使用给定的授权Token登录GTask服务。如果登录 - * 失败,就说明可能授权Token已经过期或无效了,此时需要尝试重新获取一个新的授权Token,并再次尝试登录GTask服务。 - * @Author: wmq -*/ - private boolean tryToLoginGtask(Activity activity, String authToken) { - if (!loginGtask(authToken)) { - // maybe the auth token is out of date, now let's invalidate the - // token and try again - authToken = loginGoogleAccount(activity, true); - if (authToken == null) { - Log.e(TAG, "login google account failed"); - return false; - } - - if (!loginGtask(authToken)) { - Log.e(TAG, "login gtask failed"); - return false; - } - } - return true; - } -/** - * @功能名: loginGtask - * @参数 : authToken - * @功能描述: 登录Google任务(GTask)服务的逻辑 - * @实现过程: 首先,代码设置了连接和套接字的超时时间 - * 然后,通过拼接授权Token到登录URL上, - * 接下来,代码从响应中获取Cookie,检查是否存在名为"GTL"的认证Cookie - * 最后代码从响应内容中提取客户端版本信息 - * @Author: wmq -*/ - -//创建了一个DefaultHttpClient对象,并设置了一些Http参数 - private boolean loginGtask(String authToken) { - int timeoutConnection = 10000; - int timeoutSocket = 15000; - HttpParams httpParameters = new BasicHttpParams(); - HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); - HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); - mHttpClient = new DefaultHttpClient(httpParameters); - BasicCookieStore localBasicCookieStore = new BasicCookieStore(); - mHttpClient.setCookieStore(localBasicCookieStore); - HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); - - // login gtask - //创建一个HttpGet对象,并使用mHttpClient.execute(httpGet)发送请求,获取响应 - try { - String loginUrl = mGetUrl + "?auth=" + authToken; - HttpGet httpGet = new HttpGet(loginUrl); - HttpResponse response = null; - response = mHttpClient.execute(httpGet); - - // get the cookie now - List cookies = mHttpClient.getCookieStore().getCookies(); - boolean hasAuthCookie = false; - for (Cookie cookie : cookies) { - if (cookie.getName().contains("GTL")) { - hasAuthCookie = true; - } - } - if (!hasAuthCookie) { //检查是否存在名为"GTL"的认证Cookie - Log.w(TAG, "it seems that there is no auth cookie"); - } - - // get the client version - //查找特定字符串来获取JavaScript代码块,并将其解析为JSON对象,从中提取客户端版本号 - 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); - mClientVersion = js.getLong("v"); - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - return false; //执行过程出现了异常 - } catch (Exception e) { - // simply catch all exceptions - Log.e(TAG, "httpget gtask_url failed");//打印错误信息 - return false; //执行过程出现了异常 - } - - return true; //返回true表示登录成功 - } -/** - * @功能名: getActionId - * @功能描述: 获取一个序列号,为每个操作分配一个唯一的标识符 - * @实现过程: 每次调用getActionId()方法时,都会将内部成员变量mActionId的值加1,并返回增加后的值 - * @Author: wmq -*/ - private int getActionId() { - return mActionId++; - } - - /** - * @功能名: createHttpPost - * @功能描述: 创建HttpPost对象,并设置一些请求头 - * @实现过程: 将HttpPost的构造方法中传递的URL设置为成员变量mPostUrl - * 然后,设置了一个名为Content-Type的请求头,最后返回httpPost - * @Author: wmq - */ - private HttpPost createHttpPost() { - HttpPost httpPost = new HttpPost(mPostUrl); - httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); - httpPost.setHeader("AT", "1"); //设置了一个名为AT的请求头,并将值设置为1 - return httpPost; - } - -/** - * @功能名: getResponseContent - * @参数 : HttpEntity entity - * @功能描述: 从HttpEntity对象中获取响应内容,并将其转换为字符串格式。 - * @实现过程: 检查HttpEntity的内容编码,创建了一个InputStreamReader和一个BufferedReader,用于逐行读取响应内容。 - * 逐行读取响应内容并拼接成完整的字符串。最后,返回拼接后的字符串作为响应内容 - * @Author: wmq -*/ - private String getResponseContent(HttpEntity entity) throws IOException { - String contentEncoding = null; - if (entity.getContentEncoding() != null) { - contentEncoding = entity.getContentEncoding().getValue(); - Log.d(TAG, "encoding: " + contentEncoding); - } -/** - * 如果存在内容编码,则根据内容编码的值创建相应的输入流。如果内容编码是"gzip",则使用GZIPInputStream来解压缩输入流; - * 如果内容编码是"deflate",则使用InflaterInputStream来解压缩输入流。 - */ - 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();//在处理完响应内容后,确保关闭了输入流,以释放资源。 - } - } -/** - * @功能名: postRequest - * @参数 : JSONObject js - * @功能描述: 向服务器发送POST请求并获取响应,返回一个JSONObject对象,从而进一步处理或显示给用户 - * @实现过程: 首先,检查用户是否已登录;接着,创建一个HttpPost对象,然后,它将JSON格式的数据放入一个 - * 0BasicNameValuePair列表中,最后执行POST请求,获取服务器返回的响应实体 - * @Author: wmq -*/ - private JSONObject postRequest(JSONObject js) throws NetworkFailureException { - if (!mLoggedin) { - Log.e(TAG, "please login first");//如果没有登录,则抛出ActionFailureException异常,并提示用户需要先登录 - throw new ActionFailureException("not logged in"); - } - HttpPost httpPost = createHttpPost();//创建一个HttpPost对象 - try {//设置请求头等参数 - LinkedList list = new LinkedList(); - list.add(new BasicNameValuePair("r", js.toString())); - UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); - httpPost.setEntity(entity); - //将JSON格式的数据放入一个BasicNameValuePair列表中,并将列表转换为UrlEncodedFormEntity实体。 - // execute the 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"); - } - } -/** - * @功能名: createTask - * @参数 : Task task - * @功能描述: 创建一个任务并将其发送到服务器进行处理 - * @实现过程: 调用commitUpdate()方法,创建一个JSONObject对象,然后,它调用postRequest(jsPost)方法向服务器发送POST请求, - * 并获取服务器返回的响应。最后,从响应中获取结果,并将结果中的新任务ID设置到task对象中 - * @Author: wmq -*/ - public void createTask(Task task) throws NetworkFailureException { - commitUpdate(); - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - - // action_list - actionList.put(task.getCreateAction(getActionId())); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // client_version - //将actionList放入jsPost中,并添加客户端版本信息 - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - // post - JSONObject jsResponse = postRequest(jsPost);//向服务器发送POST请求,并获取服务器返回的响应 - JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( - GTaskStringUtils.GTASK_JSON_RESULTS).get(0); - task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); - - } catch (JSONException e) { //如果在处理过程中出现JSONException异常,则会捕获并打印日志 - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("create task: handing jsonobject failed"); - } - } -/** - * @功能名: createTaskList.NetworkFailureException - * @参数 : TaskList tasklist - * @功能描述: 创建一个任务列表并将其发送到服务器进行处理 - * @实现过程: 调用commitUpdate()方法, 创建一个JSONObject对象, 然后,调用tasklist.getCreateAction(getActionId()) - * 方法获取任务列表的创建操作,并添加客户端版本信息。最后,从响应中获取结果,并将结果中的新任务ID设置到tasklist中 - * @Author: wmq -*/ - public void createTaskList(TaskList tasklist) throws NetworkFailureException { - commitUpdate(); - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - - // action_list - actionList.put(tasklist.getCreateAction(getActionId())); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // client version - //将actionList放入jsPost中,并添加客户端版本信息 - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - // post - //调用postRequest(jsPost)方法向服务器发送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) { //处理过程中出现JSONException异常,则会捕获并打印日志,并抛出ActionFailureException异常,表示处理JSON对象失败 - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("create tasklist: handing jsonobject failed"); - } - } - - /** - * @功能名: NetworkFailureException - * @功能描述: 提交之前的任务更新操作 - * @Author: wmq - */ - - - public void commitUpdate() throws NetworkFailureException { - if (mUpdateArray != null) { - try { - JSONObject jsPost = new JSONObject(); - /** - * 如果mUpdateArray不为空,表示有待提交的任务更新操作,那么它会创建一个JSONObject对象jsPost, - * 用于存储要发送给服务器的数据,然后将mUpdateArray放入jsPost中,并添加客户端版本信息 - */ - // action_list - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); - - // client_version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - postRequest(jsPost);//向服务器发送POST请求,将更新的任务数据提交到服务器进行处理 - mUpdateArray = null;//mUpdateArray设置为null,表示已经提交了所有的任务更新操作 - } catch (JSONException e) { //处理过程中出现JSONException异常,则会捕获并打印日志 - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("commit update: handing jsonobject failed"); - } - } - } - /** - * @功能名: NetworkFailureException - * @参数 : Node node - * @功能描述: 添加待提交的任务更新操作 - * @Author: wmq - */ - public void addUpdateNode(Node node) throws NetworkFailureException { - if (node != null) { - // too many update items may result in an error - // set max to 10 items - /** - * 如果传入的node不为空,它首先检查mUpdateArray是否为空,并且其中的任务更新操作数量是否超过了最大值, - * 如果超过了最大值,那么它会调用commitUpdate()方法提交之前的任务更新操作。 - */ - if (mUpdateArray != null && mUpdateArray.length() > 10) { - commitUpdate(); - } - - if (mUpdateArray == null)//如果mUpdateArray仍然为空,那么它会创建一个JSONArray对象mUpdateArray,用于存储任务更新操作 - mUpdateArray = new JSONArray(); - mUpdateArray.put(node.getUpdateAction(getActionId()));//获取节点的更新操作,并将其添加到mUpdateArray中 - } - } - - /** - * @功能名: moveTask - * @参数 : task, preParent, curParent - * @功能描述: 将一个任务从一个任务列表移动到另一个任务列表 - * @实现过程: 保存修改,然后存储要发送给服务器的数据,最后,它将客户端版本信息添加到jsPost中 - * @Author: wmq - */ - /** - * 它调用commitUpdate()方法提交之前的任务更新操作,以确保之前未提交的更新操作被保存 - */ - public void moveTask(Task task, TaskList preParent, TaskList curParent) - throws NetworkFailureException { - commitUpdate(); - /** - * 创建一个JSONArray对象actionList,用于存储要执行的操作 - * 创建一个JSONObject对象action,表示要执行的移动操作 - */ - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - JSONObject action = new JSONObject(); - - // action_list - //在action中,它设置了以下属性 - 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()); - if (preParent == curParent && task.getPriorSibling() != null) { - // put prioring_sibing_id only if moving within the tasklist and - // it is not the first one - 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()); - if (preParent != curParent) { - // put the dest_list only if moving between tasklists - action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); - } - //将action添加到actionList中,并将actionList添加到jsPost中 - actionList.put(action); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // client_version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - postRequest(jsPost); - - } catch (JSONException e) { //如果在处理过程中出现JSONException异常,则会捕获并打印日志 - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("move task: handing jsonobject failed"); - } - } -/** - * @功能名: deleteNode - * @参数 : node - * @功能描述: 删除一个节点(Node) - * @实现过程: 首先,确保之前未提交的更新操作被保存,然后,创建一个JSONObject对象,存储要发送给服务器的数据 - * 然后,它将客户端版本信息添加到jsPost中,最后,它将mUpdateArray设置为null,清空之前的更新操作列表 - * @Author: wmq -*/ - public void deleteNode(Node node) throws NetworkFailureException { - commitUpdate(); - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - - // action_list - /** - * 它将node对象的deleted属性设置为true,表示该节点将被删除。 - * 调用node.getUpdateAction(getActionId())方法获取表示删除节点操作的JSONObject对象,并将该对象添加到actionList中 - */ - node.setDeleted(true); - actionList.put(node.getUpdateAction(getActionId())); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // client_version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); -/** - * 将客户端版本信息添加到jsPost中,并调用postRequest(jsPost)方法向服务器发送POST请求, - * 将删除节点的操作提交到服务器进行处理。如果在处理过程中出现JSONException异常,则会捕获并 - * 打印日志,并抛出ActionFailureException异常,表示处理JSON对象失败 - */ - postRequest(jsPost); - mUpdateArray = null; - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("delete node: handing jsonobject failed"); - } - } -/** - * @功能名: getTaskLists - * @参数 : mLoggedin - * @功能描述: 获取任务列表(Task Lists) - * @实现过程: 首先,检查是否已经登录。接下来,它创建一个HttpGet对象,用于发送GET请求,并将响应结果存储在HttpResponse对象中 - * 然后,它从响应结果中提取任务列表的相关信息。它通过字符串的处理,找到包含任务列表信息的部分,并将其转换为一个JSONObject对象js - * 最后,它从js对象中获取键为"t"的子对象,再从该子对象中获取键为GTaskStringUtils.GTASK_JSON_LISTS的子数组,并将其作为结果返回 - * @Author: wmq -*/ - 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 = null; - response = mHttpClient.execute(httpGet); - - // get the task list - 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"); - } - } -/** - * @功能名: getTaskList - * @参数 :listGid - * @功能描述: 获取指定任务列表(Task List)的任务信息 - * @实现过程: 首先保存更新操作,存储要发送给服务器的数据,接着,它将客户端版本信息添加到jsPost中,发送POST请求 - * 最后,它从服务器返回的响应结果中获取键为"tasks"的子数组,并将其作为结果返回 - * @Author: wmq -*/ - public JSONArray getTaskList(String listGid) throws NetworkFailureException { - commitUpdate(); - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - JSONObject action = new JSONObject(); - - // action_list - 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); - - // client_version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - JSONObject jsResponse = postRequest(jsPost);//将actionList添加到jsPost中 - return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS); - //将客户端版本信息添加到jsPost中,并调用postRequest(jsPost)方法向服务器发送POST请求,将获取任务列表的操作提交到服务器进行处理。 - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("get task list: handing jsonobject failed"); - } - } - - /** - * @功能名: getSyncAccount - * @功能描述:返回当前同步帐户 - * @Author: wmq - */ - public Account getSyncAccount() { - return mAccount; - } - - /** - * @功能名: resetUpdateArray - * @功能描述: 重置更新数组 - * @实现过程: resetUpdateArray()方法将类中的mUpdateArray成员变量设置为null,以清空已有的更新数组内容。 - * 这样做可以确保在处理下一批更新操作时,不会受到之前更新的影响,从而保持更新操作的独立性和准确性。 - * @Author: wmq - */ - public void resetUpdateArray() { - mUpdateArray = null; - } -} diff --git a/src/GTaskSyncService.java b/src/GTaskSyncService.java new file mode 100644 index 0000000..c619dcc --- /dev/null +++ b/src/GTaskSyncService.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.gtask.remote; + +import android.app.Activity; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.IBinder; + /** + * + * @ProjectName: xiaomi + * @Package: GTaskSyncService + * @ClassName: + * @Description: GTask同步服务,用于提供同步服务(开始,取消同步服务),发送广播 + * @Author: wsk + * @CreateDate: 23.12.24 + * @Version: 1.0 + */ +public class GTaskSyncService extends Service { + public final static String ACTION_STRING_NAME = "sync_action_type"; + + public final static int ACTION_START_SYNC = 0; + + public final static int ACTION_CANCEL_SYNC = 1; + + public final static int ACTION_INVALID = 2; + + public final static String GTASK_SERVICE_BROADCAST_NAME = "net.micode.notes.gtask.remote.gtask_sync_service"; + + public final static String GTASK_SERVICE_BROADCAST_IS_SYNCING = "isSyncing"; + + public final static String GTASK_SERVICE_BROADCAST_PROGRESS_MSG = "progressMsg"; + + private static GTaskASyncTask mSyncTask = null; + + private static String mSyncProgress = ""; + + private void startSync() { + if (mSyncTask == null) { + mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() { + public void onComplete() { + mSyncTask = null; + sendBroadcast(""); + stopSelf(); + } + }); + sendBroadcast(""); + mSyncTask.execute();//这个函数让任务是以单线程队列方式或线程池队列方式运行 + } + } + /** + * @method startSync + * @description 开始一个同步工作 + * @date: + * @author: wsk + * @param + * @return null + */ + private void cancelSync() { + if (mSyncTask != null) { + mSyncTask.cancelSync(); + } + } + + @Override + public void onCreate() { + mSyncTask = null; + } + /** + * @method onCreate + * @description 初始化一个service + * @date: + * @author: wsk + * @param + * @return null + */ + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Bundle bundle = intent.getExtras(); + if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) { + switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) { + case ACTION_START_SYNC: + startSync(); + break; + case ACTION_CANCEL_SYNC: + cancelSync(); + break; + default: + break; + } + return START_STICKY;//等待新的intent来是这个service继续运行 + } + return super.onStartCommand(intent, flags, startId); + } + /** + * @method onStartCommand + * @description 判断情况,开始同步还是取消同步 + * @date: + * @author: wsk + * @param + * @return onStartCommand + */ + @Override + public void onLowMemory() { + if (mSyncTask != null) { + mSyncTask.cancelSync(); + } + } + + public IBinder onBind(Intent intent) { + return null; + } + + public void sendBroadcast(String msg) { + mSyncProgress = msg; + 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); + } + /** + * @method sendBroadcast + * @description 创建一个新的Intent,并填入各个参数,发送通知 + * @date: + * @author: wsk + * @param + * @return msg + */ + public static void startSync(Activity activity) { + GTaskManager.getInstance().setActivityContext(activity); + Intent intent = new Intent(activity, GTaskSyncService.class); + intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC); + activity.startService(intent); + } + /** + * @method startSync + * @description 执行一个service,service的内容里的同步动作就是开始同步 + * @date: + * @author: wsk + * @param + * @return activity + */ + public static void cancelSync(Context context) { + Intent intent = new Intent(context, GTaskSyncService.class); + intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC); + context.startService(intent); + } + /** + * @method cancelSync + * @description 执行一个service,service的内容里的同步动作就是取消同步 + * @date: + * @author: wsk + * @param + * @return context + */ + public static boolean isSyncing() { + return mSyncTask != null; + } + + public static String getProgressString() { + return mSyncProgress; + } +} diff --git a/src/MetaData.java b/src/MetaData.java deleted file mode 100644 index 277ea2e..0000000 --- a/src/MetaData.java +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @ProiectName:MiNote - * @Package: gtask.remote - * @ClassName: MetaData - * @Description:用于存储便签的元数据信息 - * @Author: wmq -*/ -package net.micode.notes.gtask.data; - -import android.database.Cursor; -import android.util.Log; - -import net.micode.notes.tool.GTaskStringUtils; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * @功能名: MetaData extends Task - * @参数 : - * @功能描述: 得到类的简写名称存入字符串TAG中 - * @实现过程: 调用getSimpleName ()函数 - * @Author: wmq - */ -public class MetaData extends Task { - - - private final static String TAG = MetaData.class.getSimpleName(); - - private String mRelatedGid = null; - /** - * @功能名: setMeta - * @参数 : gid / metaInfo - * @功能描述: 设置数据,即生成元数据库 - * @实现过程: 调用JSONObject库函数put (),Task类中的setNotes ()和setName ()函数 - * @Author: wmq - */ - public void setMeta(String gid, JSONObject metaInfo) { - try { - metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);//将这对键值放入metaInfo这个jsonobject对象中 - - } catch (JSONException e) { - Log.e(TAG, "failed to put related gid");//输出错误信息 - } - setNotes(metaInfo.toString()); - setName(GTaskStringUtils.META_NOTE_NAME); - } - //功能描述:获取相关联的Gid - public String getRelatedGid() { - return mRelatedGid; - }//判断当前数据是否为空,若为空则返回真即值得保存 - @Override - public boolean isWorthSaving() { - return getNotes() != null; - } - /** - * @功能名: setContentByRemoteJSON - * @参数 : JOSN - * @功能描述: 使用远程json数据对象设置元数据内容 - * @实现过程: 调用父类Task中的setContentByRemoteJSON ()函数 - * @Author: wmq - */ - @Override - public void setContentByRemoteJSON(JSONObject js) { - super.setContentByRemoteJSON(js); - if (getNotes() != null) { - try { - 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) { - // this function should not be called - throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); - //传递非法参数异常 - } - - /** - * 功能描述:获取同步动作状态,一般不会用到,若用到,则抛出异常 - */ - @Override - public JSONObject getLocalJSONFromContent() { - throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); - //传递非法参数异常 - } - - /** - * 功能描述:获取同步动作状态,一般不会用到,若用到,则抛出异常 - */ - @Override - public int getSyncAction(Cursor c) { - throw new IllegalAccessError("MetaData:getSyncAction should not be called"); - } - //传递非法参数异常 -} diff --git a/src/NetworkFailureException.java b/src/NetworkFailureException.java new file mode 100644 index 0000000..5cb0ccd --- /dev/null +++ b/src/NetworkFailureException.java @@ -0,0 +1,42 @@ +/* + * 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.exception; +/** + * + * @ProjectName: xiaomi + * @Package: NetworkFailureException + * @ClassName: + * @Description: 网络失败异常 + * @Author: wsk + * @CreateDate: 23.12.24 + * @Version: 1.0 + */ +public class NetworkFailureException extends Exception { + private static final long serialVersionUID = 2107610287180234136L; + + public NetworkFailureException() { + super(); + } + + public NetworkFailureException(String paramString) { + super(paramString); + } + + public NetworkFailureException(String paramString, Throwable paramThrowable) { + super(paramString, paramThrowable); + } +} diff --git a/src/SqlData.java b/src/SqlData.java deleted file mode 100644 index 0e33e1b..0000000 --- a/src/SqlData.java +++ /dev/null @@ -1,269 +0,0 @@ -/** - * @ProiectName:MiNote - * @Package: gtask.data - * @ClassName: SqlData - * @Description:用于支持小米便签最底层的数据库相关操作,和sqlnote的关系上是子集关系,即data是note的子集(节点),SqlData其实就是也就是所谓数据中的数据 - * @Author: wmq -*/ - - -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; - -public class SqlData { - /** - * @功能描述: 得到类的简写名称存入字符串TAG中 - * @实现过程: 调用getSimpleName ()函数 - * @Author: wmq - */ - private static final String TAG = SqlData.class.getSimpleName(); - - private static final int INVALID_ID = -99999; - /* - * 来自Notes类中定义的DataColumn中的一些常量 - */ - - // 集合了interface DataColumns中所有SF常量 - public static final String[] PROJECTION_DATA = new String[] { - DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1, - DataColumns.DATA3 - }; - // 以下五个变量作为sql表中5列的编号 - 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; - //以下定义了8个内部的变量 - private ContentResolver mContentResolver; - //判断是否直接用Content生成,是为true,否则为false - private boolean mIsCreate; - - private long mDataId; - - private String mDataMimeType; - - private String mDataContent; - - private long mDataContentData1; - - private String mDataContentData3; - - private ContentValues mDiffDataValues; - - /** - * @功能名: SqlData - * @参数 :context - * @功能描述: 构造函数,初始化数据 - * @Author: wmq - */ - public SqlData(Context context) { - //mContentResolver用于获取ContentProvider提供的数据 - mContentResolver = context.getContentResolver(); - //IsCreate表征当前数据是用哪种方式创建(两种构造函数的参数不同) - mIsCreate = true; - mDataId = INVALID_ID;//mDataId置初始值-99999 - mDataMimeType = DataConstants.NOTE; - mDataContent = ""; - mDataContentData1 = 0; - mDataContentData3 = ""; - mDiffDataValues = new ContentValues(); - } - -/** - * @功能名: SqlData - * @参数 :context / Cursor c - * @功能描述: 初始化一个SqlData对象 - * @Author: wmq -*/ - public SqlData(Context context, Cursor c) { - /** - * 通过传入的Context对象获取内容解析器,用于访问应用程序的数据。这个内容解析器可以用来查询、插入、更新和删除数据等操作。 - */ - mContentResolver = context.getContentResolver(); - mIsCreate = false;//用于表示是否新建了数据 - /** - * 根据传入的Cursor对象加载数据。该方法会从Cursor对象中读取便签内容和元数据, - * 并将它们存储到SqlData对象中对应的成员变量中 - */ - loadFromCursor(c); - /** - * 建一个ContentValues对象mDiffDataValues,用于存储差异化的数据内容。在后续的操作中, - * 如果需要更新便签的数据,就可以将更新的内容存储到这个ContentValues对象中,然后再通过内容解析器进 - * 行相应的更新操作。 - */ - mDiffDataValues = new ContentValues(); - } - /** - * @功能名: loadFromCursor - * @参数 : Cursor c - * @功能描述: 从传入的Cursor对象中读取数据,并将这些数据存储到SqlData对象的相应成员变量中。 - * @实现过程: - * 从Cursor对象中获取一条记录的数据ID - * 从Cursor对象中获取一条记录的MIME类型 - * 从Cursor对象中获取一条记录的内容 - * 从Cursor对象中获取一条记录的附加数据1,并将其赋值给SqlData对象的mDataContentData1成员变量。 - * @Author: wmq - */ - 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); - } -/** - * @功能名: setContent - * @参数 : JSONObject js - * @功能描述: 根据该JSONObject中的数据设置SqlData对象的内容(更新) - * @Author: wmq -*/ - public void setContent(JSONObject js) throws JSONException { - long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;//从JSONObject中获取并设置数据ID - if (mIsCreate || mDataId != dataId) { - mDiffDataValues.put(DataColumns.ID, dataId); - } - mDataId = dataId; - - 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; - - long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0; - /** - * 如果处于创建状态或者数据内容有变化,则将新的数据内容记录到mDiffDataValues中,并更新SqlData对象的mDataContent成员变量。 - */ - if (mIsCreate || mDataContentData1 != dataContentData1) { - mDiffDataValues.put(DataColumns.DATA1, dataContentData1); - } - mDataContentData1 = dataContentData1;//获取并设置附加数据1(dataContentData1) - - String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : ""; - /** - * 如果处于创建状态或者附加数据1有变化,则将新的附加数据1记录到mDiffDataValues中,并更新SqlData对象的mDataContentData1成员变量。 - */ - if (mIsCreate || !mDataContentData3.equals(dataContentData3)) { - mDiffDataValues.put(DataColumns.DATA3, dataContentData3); - } - mDataContentData3 = dataContentData3;//取并设置附加数据3(dataContentData3) - } -/** - * @功能名: getContent - * @功能描述: getContent()方法,它返回一个JSONObject对象,其中包含了SqlData对象的内容 - * @实现过程: - * 首先检查是否处于创建状态(mIsCreate为true),如果是,则输出错误日志并返回null。 - * 然后,创建一个新的JSONObject对象,并将SqlData对象的数据ID(mDataId)、MIME类型(mDataMimeType)、 - * 数据内容(mDataContent)、附加数据1(mDataContentData1)和附加数据3(mDataContentData3)放入其中。 - * 最后,返回这个包含了SqlData对象内容的JSONObject对象 - * @Author: wmq -*/ - public JSONObject getContent() throws JSONException { - if (mIsCreate) { - Log.e(TAG, "it seems that we haven't created this in database yet"); - return null; - } - //创建JSONObject对象。并将相关数据放入其中,并返回。 - 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; - } - // 功能描述: - /** - * @功能名: commit - * @参数 : noteId / validateVersion / version - * @功能描述: commit函数用于把当前造作所做的修改保存到数据库 - * @实现过程: 首先检查SqlData对象是否处于创建状态,然后将笔记ID(noteId)放入mDiffDataValues中,然后再调用ContentResolver的update()方法进行更新。 - * @Author: wmq - */ - 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 { - /** - * 首先判断mDiffDataValues的大小,如果大于0,则表示有需要更新的字段。接下来,根据validateVersion参数的值, - * 决定使用不同的更新方式。 - */ - if (mDiffDataValues.size() > 0) { - int result = 0; - //如果validateVersion为false,表示不需要验证版本,直接调用ContentResolver的update()方法更新数据库中对应数据的字段值 - if (!validateVersion) {//构造字符串 - result = mContentResolver.update(ContentUris.withAppendedId( - Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null); - } else { - /** - * 如果validateVersion为true,表示需要验证版本,构造一个SQL语句,使用NoteColumns.ID和NoteColumns.VERSION字段 - * 进行查询,以确保要更新的数据ID和版本号与笔记表中的对应记录匹配。然后再调用ContentResolver的update()方法进行更新 - */ - 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) - }); - } - //检查返回的更新结果result是否为0,如果是,表示没有进行更新操作 - if (result == 0) { - Log.w(TAG, "there is no update. maybe user updates note when syncing"); - } - } - } - - mDiffDataValues.clear(); - mIsCreate = false; - } -/** - * @功能名: getId - * @功能描述: 获取当前id - * @Author: wmq -*/ - public long getId() { - return mDataId; - } -} diff --git a/src/Task.java b/src/Task.java new file mode 100644 index 0000000..bd63f96 --- /dev/null +++ b/src/Task.java @@ -0,0 +1,441 @@ +/* + * 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; +/** + * + * @ProjectName: Notes-master + * @Package: gtask + * @ClassName: Task + * @Description: 同步任务,将创建、更新和同步动作包装成JSON对象,用本地和远程的JSON对节点内容进行设置,获取同步信息 + * @Author: wsk + * @CreateDate: 23.12.23 + * @Version: 1.0 + */ +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; +import net.micode.notes.tool.GTaskStringUtils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +//同步操作 +public class Task extends Node { + private static final String TAG = Task.class.getSimpleName(); + + private boolean mCompleted;//是否完成 + + private String mNotes; + + private JSONObject mMetaInfo;//将在实例中存储数据的类型 + + private Task mPriorSibling;//对应的优先兄弟Task的指针(待完善) + + private TaskList mParent;//所在的任务列表的指针 + /** + * @method Task + * @description 初始化变量 ,进行赋值操作 + * @date: + * @author: wsk + * @param + * @return null + */ + public Task() { + super(); + mCompleted = false; + mNotes = null; + mPriorSibling = null;//TaskList中当前Task前面的Task的指针 + mParent = null;//当前Task所在的TaskList + mMetaInfo = null; + } + /** + * @method getCreateAction + * @description 创建动作,根据参数js创建动作的形式,id等 + * @date: + * @author: wsk + * @param + * @return JSON对象js + */ + 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; + } + /** + * @method getUpdateAction + * @description 更新动作 + * @date: + * @author: wsk + * @param + * @return js + */ + 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; + } + /** + * @method setContentByRemoteJSON + * @description 根据传入的动作对象js,设置任务内容 + * @date: + * @author: wsk + * @param + * @return js + */ + 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)); + } + + // notes + if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) { + setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES)); + } + + // deleted + if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) { + setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED)); + } + + // 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"); + } + } + } + + 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 avaiable"); + } + + 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(); + } + }//放到本地local库 + + public JSONObject getLocalJSONFromContent() { + String name = getName(); + try { + if (mMetaInfo == null) { + // new task created from web + 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 { + // synced task + 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; + } + }//这段代码是一个Java方法,用于根据任务对象的内容生成对应的JSONObject对象。方法会根据任务的来源(新建的任务或已同步的任务)以及任务的属性值来生成相应的JSONObject对象。 + + // 在方法内部,首先获取任务的名称,并进行空值检查。如果名称为空,则输出一条警告日志并返回null。 + + // 然后根据任务的来源进行处理。如果任务是新建的(mMetaInfo为null),则创建一个新的JSONObject对象js,并依次创建note和dataArray两个JSONObject对象,并设置其对应的键值对。其中,note表示任务的备注信息,dataArray表示任务的详细信息。接着,创建一个data对象,并将任务的名称name作为DataColumns.CONTENT的值,并将data对象添加到dataArray数组中。最后将dataArray和note对象分别设置到js对象中,并返回js对象。 + + // 如果任务是已同步的(mMetaInfo不为null),则从mMetaInfo中获取note和dataArray两个JSONObject对象。接着,遍历dataArray数组中的每个JSONObject对象,查找MIME_TYPE为DataConstants.NOTE的对象,并将其CONTENT属性设置为任务的名称。最后,将note对象的TYPE属性设置为Notes.TYPE_NOTE,并返回mMetaInfo对象。 + + // 在解析过程中,如果发生了JSONException异常,则会捕获该异常并输出错误日志,并返回null。 + + // 总之,该方法的作用是根据任务对象的内容生成对应的JSONObject对象。 + + + 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; + } + } + }//用于设置任务对象的元数据信息。 + + 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; + } + + // validate the note id now + 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) { + // there is no local update + if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { + // no update both side + return SYNC_ACTION_NONE; + } else { + // apply remote to local + return SYNC_ACTION_UPDATE_LOCAL; + } + } else { + // validate 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()) { + // local modification only + 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; + }//根据传入的Cursor对象c判断当前任务对象需要执行哪种同步行为(更新本地、更新远程、不进行同步等)。是否要更新,更新哪里 + + public boolean isWorthSaving() { + return mMetaInfo != null || (getName() != null && getName().trim().length() > 0) + || (getNotes() != null && getNotes().trim().length() > 0); + }//是否值得保存 + + public void setCompleted(boolean completed) { + this.mCompleted = completed; + } + //设置任务完成状态 + public void setNotes(String notes) { + this.mNotes = notes; + }//设置属性 + /** + * @method + * @description 设置属性 + * @date: + * @author: wsk + * @param + * @return + */ + public void setPriorSibling(Task priorSibling) { + this.mPriorSibling = priorSibling; + } + /** + * @method + * @description 设置当前任务节点的前一个兄弟节点 + * @date: + * @author: wsk + * @param + * @return + */ + public void setParent(TaskList parent) { + this.mParent = parent; + } + /** + * @method getCompleted + * @description 获取一个名为mCompleted的布尔类型成员变量的数值。根据你提供的代码,这个方法返回mCompleted的当前数值。 + * @date: + * @author: wsk + * @param + * @return mCompleted + */ + public boolean getCompleted() { + return this.mCompleted; + } + /** + * @method getNotes + * @description 获取一个名为mNotes的字符串类型成员变量的数值 + * @date: + * @author: wsk + * @param + * @return mNotes字符串或空 + */ + public String getNotes() { + return this.mNotes; + } + /** + * @method getPriorSibling + * @description 获取一个名为mPriorSibling的Task对象成员变量的数值 + * @date: + * @author: wsk + * @param + * @return this.mPriorSibling + */ + public Task getPriorSibling() { + return this.mPriorSibling; + } + /** + * @method getParent + * @description 获取一个名为mParent的TaskList对象成员变量的数值 + * @date: + * @author: wsk + * @param + * @return this.mParent + */ + public TaskList getParent() { + return this.mParent; + } + +} diff --git a/src/TaskList.java b/src/TaskList.java new file mode 100644 index 0000000..d32db0c --- /dev/null +++ b/src/TaskList.java @@ -0,0 +1,387 @@ +/* + * 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.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; +import net.micode.notes.tool.GTaskStringUtils; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; + + +public class TaskList extends Node { + private static final String TAG = TaskList.class.getSimpleName();//tag标记 + + private int mIndex;//当前TaskList的指针 + + private ArrayList mChildren;//类中主要的保存数据的单元,用来实现一个以Task为元素的ArrayList + + public TaskList() { + super(); + mChildren = new ArrayList(); + mIndex = 1; + }//链表 + /* (non-Javadoc) + * @see net.micode.notes.gtask.data.Node#getCreateAction(int) + * 生成并返回一个包含了一定数据的JSONObject实体 + */ + 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; + }//创建动作 + /* (non-Javadoc) + * @see net.micode.notes.gtask.data.Node#getUpdateAction(int) + * 生成并返回一个包含了一定数据的JSONObject实体 + */ + 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; + } + + 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"); + } + } + } + + public void setContentByLocalJSON(JSONObject js) { + if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) { + Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); + } + + 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(); + } + } + + public JSONObject getLocalJSONFromContent() { + try { + JSONObject js = new JSONObject(); + JSONObject folder = new JSONObject(); + + String folderName = getName(); + if (getName().startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX)) + folderName = folderName.substring(GTaskStringUtils.MIUI_FOLDER_PREFFIX.length(), + folderName.length()); + 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); + + js.put(GTaskStringUtils.META_HEAD_NOTE, folder); + + return js; + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + return null; + } + } + + public int getSyncAction(Cursor c) { + try { + if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { + // there is no local update + if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { + // no update both side + return SYNC_ACTION_NONE; + } else { + // apply remote to local + return SYNC_ACTION_UPDATE_LOCAL; + } + } else { + // validate 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()) { + // local modification only + return SYNC_ACTION_UPDATE_REMOTE; + } else { + // for folder conflicts, just apply local modification + return SYNC_ACTION_UPDATE_REMOTE; + } + } + } catch (Exception e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + } + + return SYNC_ACTION_ERROR; + }//判断需要执行哪种同步操作 + + 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) { + // need to set prior sibling and parent + task.setPriorSibling(mChildren.isEmpty() ? null : mChildren + .get(mChildren.size() - 1)); + task.setParent(this); + //注意:每一次ArrayList的变化都要紧跟相关Task中PriorSibling的更改 + //,接下来几个函数都有相关操作 + } + } + return ret; + } + /** + * @param task + * @param index + * @return + * 功能:在当前任务表的指定位置添加新的任务。 + */ + public boolean addChildTask(Task task, int index) { + 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); + + // update the task list + 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 返回删除是否成功 + * 功能:删除TaskList中的一个Task + */ + public boolean removeChildTask(Task task) { + boolean ret = false; + int index = mChildren.indexOf(task); + if (index != -1) { + ret = mChildren.remove(task); + + if (ret) { + // reset prior sibling and parent + task.setPriorSibling(null); + task.setParent(null); + + // update the task list + if (index != mChildren.size()) { + mChildren.get(index).setPriorSibling( + index == 0 ? null : mChildren.get(index - 1)); + } + } + } + return ret; + } + /** + * @param task + * @param index + * @return + * 功能:将当前TaskList中含有的某个Task移到index位置 + */ + public boolean moveChildTask(Task task, int index) { + + if (index < 0 || index >= mChildren.size()) { + Log.e(TAG, "move child task: invalid index"); + return false; + } + + int pos = mChildren.indexOf(task); + if (pos == -1) { + Log.e(TAG, "move child task: the task should in the list"); + return false; + } + + if (pos == index) + return true; + return (removeChildTask(task) && addChildTask(task, index)); + //利用已经实现好的功能完成当下功能 + } + /** + * @param gid + * @return返回寻找结果 + * 功能:按gid寻找Task + */ + public Task findChildTaskByGid(String gid) { + for (int i = 0; i < mChildren.size(); i++) { + Task t = mChildren.get(i); + if (t.getGid().equals(gid)) { + return t; + } + } + return null; + } + /** + * @param task + * @return + * 功能:返回指定Task的index + */ + public int getChildTaskIndex(Task task) { + return mChildren.indexOf(task); + } + /** + * @param index + * @return + * 功能:返回指定index的Task + */ + public Task getChildTaskByIndex(int index) { + if (index < 0 || index >= mChildren.size()) { + Log.e(TAG, "getTaskByIndex: invalid index"); + return null; + } + return mChildren.get(index); + } + /** + * @param gid + * @return + * 功能:返回指定gid的Task + */ + public Task getChilTaskByGid(String gid) { + for (Task task : mChildren) { + if (task.getGid().equals(gid)) + return task; + } + return null; + } + + public ArrayList getChildTaskList() { + return this.mChildren; + } + + public void setIndex(int index) { + this.mIndex = index; + } + + public int getIndex() { + return this.mIndex; + } +} diff --git a/src/新建 文文档.txt b/src/新建 文文档.txt deleted file mode 100644 index e5c7d47..0000000 --- a/src/新建 文文档.txt +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -