pull/13/head
			
			
		
		
							parent
							
								
									49f90c91d5
								
							
						
					
					
						commit
						abfa3096e7
					
				| @ -0,0 +1,33 @@ | |||||||
|  | /* | ||||||
|  |  * 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; | ||||||
|  | 
 | ||||||
|  | public class ActionFailureException extends RuntimeException { | ||||||
|  |     private static final long serialVersionUID = 4425249765923293627L; | ||||||
|  | 
 | ||||||
|  |     public ActionFailureException() { | ||||||
|  |         super(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public ActionFailureException(String paramString) { | ||||||
|  |         super(paramString); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public ActionFailureException(String paramString, Throwable paramThrowable) { | ||||||
|  |         super(paramString, paramThrowable); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,123 @@ | |||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *        http://www.apache.org/licenses/LICENSE-2.0
 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package net.micode.notes.gtask.remote; | ||||||
|  | 
 | ||||||
|  | import android.app.Notification; | ||||||
|  | import android.app.NotificationManager; | ||||||
|  | import android.app.PendingIntent; | ||||||
|  | import android.content.Context; | ||||||
|  | import android.content.Intent; | ||||||
|  | import android.os.AsyncTask; | ||||||
|  | 
 | ||||||
|  | import net.micode.notes.R; | ||||||
|  | import net.micode.notes.ui.NotesListActivity; | ||||||
|  | import net.micode.notes.ui.NotesPreferenceActivity; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | public class GTaskASyncTask extends AsyncTask<Void, String, Integer> { | ||||||
|  | 
 | ||||||
|  |     private static int GTASK_SYNC_NOTIFICATION_ID = 5234235; | ||||||
|  | 
 | ||||||
|  |     public interface OnCompleteListener { | ||||||
|  |         void onComplete(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private Context mContext; | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |         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(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,585 @@ | |||||||
|  | /* | ||||||
|  |  * 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.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; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | public class GTaskClient { | ||||||
|  |     private static final String TAG = GTaskClient.class.getSimpleName(); | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  | 
 | ||||||
|  |     private GTaskClient() { | ||||||
|  |         mHttpClient = null; | ||||||
|  |         mGetUrl = GTASK_GET_URL; | ||||||
|  |         mPostUrl = GTASK_POST_URL; | ||||||
|  |         mClientVersion = -1; | ||||||
|  |         mLoggedin = false; | ||||||
|  |         mLastLoginTime = 0; | ||||||
|  |         mActionId = 1; | ||||||
|  |         mAccount = null; | ||||||
|  |         mUpdateArray = null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static synchronized GTaskClient getInstance() { | ||||||
|  |         if (mInstance == null) { | ||||||
|  |             mInstance = new GTaskClient(); | ||||||
|  |         } | ||||||
|  |         return mInstance; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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); | ||||||
|  |         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
 | ||||||
|  |         if (!mLoggedin) { | ||||||
|  |             mGetUrl = GTASK_GET_URL; | ||||||
|  |             mPostUrl = GTASK_POST_URL; | ||||||
|  |             if (!tryToLoginGtask(activity, authToken)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         mLoggedin = true; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private String loginGoogleAccount(Activity activity, boolean invalidateToken) { | ||||||
|  |         String authToken; | ||||||
|  |         AccountManager accountManager = AccountManager.get(activity); | ||||||
|  |         Account[] accounts = accountManager.getAccountsByType("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<Bundle> 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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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
 | ||||||
|  |         try { | ||||||
|  |             String loginUrl = mGetUrl + "?auth=" + authToken; | ||||||
|  |             HttpGet httpGet = new HttpGet(loginUrl); | ||||||
|  |             HttpResponse response = null; | ||||||
|  |             response = mHttpClient.execute(httpGet); | ||||||
|  | 
 | ||||||
|  |             // get the cookie now
 | ||||||
|  |             List<Cookie> cookies = mHttpClient.getCookieStore().getCookies(); | ||||||
|  |             boolean hasAuthCookie = false; | ||||||
|  |             for (Cookie cookie : cookies) { | ||||||
|  |                 if (cookie.getName().contains("GTL")) { | ||||||
|  |                     hasAuthCookie = true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if (!hasAuthCookie) { | ||||||
|  |                 Log.w(TAG, "it seems that there is no auth cookie"); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // get the client version
 | ||||||
|  |             String resString = getResponseContent(response.getEntity()); | ||||||
|  |             String jsBegin = "_setup("; | ||||||
|  |             String jsEnd = ")}</script>"; | ||||||
|  |             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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private int getActionId() { | ||||||
|  |         return mActionId++; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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<BasicNameValuePair> list = new LinkedList<BasicNameValuePair>(); | ||||||
|  |             list.add(new BasicNameValuePair("r", js.toString())); | ||||||
|  |             UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); | ||||||
|  |             httpPost.setEntity(entity); | ||||||
|  | 
 | ||||||
|  |             // 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"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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
 | ||||||
|  |             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"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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
 | ||||||
|  |             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"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void commitUpdate() throws NetworkFailureException { | ||||||
|  |         if (mUpdateArray != null) { | ||||||
|  |             try { | ||||||
|  |                 JSONObject jsPost = new JSONObject(); | ||||||
|  | 
 | ||||||
|  |                 // action_list
 | ||||||
|  |                 jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); | ||||||
|  | 
 | ||||||
|  |                 // client_version
 | ||||||
|  |                 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); | ||||||
|  | 
 | ||||||
|  |                 postRequest(jsPost); | ||||||
|  |                 mUpdateArray = null; | ||||||
|  |             } catch (JSONException e) { | ||||||
|  |                 Log.e(TAG, e.toString()); | ||||||
|  |                 e.printStackTrace(); | ||||||
|  |                 throw new ActionFailureException("commit update: handing jsonobject failed"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void addUpdateNode(Node node) throws NetworkFailureException { | ||||||
|  |         if (node != null) { | ||||||
|  |             // too many update items may result in an error
 | ||||||
|  |             // set max to 10 items
 | ||||||
|  |             if (mUpdateArray != null && mUpdateArray.length() > 10) { | ||||||
|  |                 commitUpdate(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (mUpdateArray == null) | ||||||
|  |                 mUpdateArray = new JSONArray(); | ||||||
|  |             mUpdateArray.put(node.getUpdateAction(getActionId())); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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_list
 | ||||||
|  |             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()); | ||||||
|  |             } | ||||||
|  |             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) { | ||||||
|  |             Log.e(TAG, e.toString()); | ||||||
|  |             e.printStackTrace(); | ||||||
|  |             throw new ActionFailureException("move task: handing jsonobject failed"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void deleteNode(Node node) throws NetworkFailureException { | ||||||
|  |         commitUpdate(); | ||||||
|  |         try { | ||||||
|  |             JSONObject jsPost = new JSONObject(); | ||||||
|  |             JSONArray actionList = new JSONArray(); | ||||||
|  | 
 | ||||||
|  |             // action_list
 | ||||||
|  |             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); | ||||||
|  | 
 | ||||||
|  |             postRequest(jsPost); | ||||||
|  |             mUpdateArray = null; | ||||||
|  |         } catch (JSONException e) { | ||||||
|  |             Log.e(TAG, e.toString()); | ||||||
|  |             e.printStackTrace(); | ||||||
|  |             throw new ActionFailureException("delete node: handing jsonobject failed"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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 = ")}</script>"; | ||||||
|  |             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"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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); | ||||||
|  |             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"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Account getSyncAccount() { | ||||||
|  |         return mAccount; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void resetUpdateArray() { | ||||||
|  |         mUpdateArray = null; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,33 @@ | |||||||
|  | /* | ||||||
|  |  * 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; | ||||||
|  | 
 | ||||||
|  | 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); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,505 @@ | |||||||
|  | /* | ||||||
|  |  * 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; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | public class SqlNote { | ||||||
|  |     private static final String TAG = SqlNote.class.getSimpleName(); | ||||||
|  | 
 | ||||||
|  |     private static final int INVALID_ID = -99999; | ||||||
|  | 
 | ||||||
|  |     public static final String[] PROJECTION_NOTE = new String[] { | ||||||
|  |             NoteColumns.ID, NoteColumns.ALERTED_DATE, NoteColumns.BG_COLOR_ID, | ||||||
|  |             NoteColumns.CREATED_DATE, NoteColumns.HAS_ATTACHMENT, NoteColumns.MODIFIED_DATE, | ||||||
|  |             NoteColumns.NOTES_COUNT, NoteColumns.PARENT_ID, NoteColumns.SNIPPET, NoteColumns.TYPE, | ||||||
|  |             NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE, NoteColumns.SYNC_ID, | ||||||
|  |             NoteColumns.LOCAL_MODIFIED, NoteColumns.ORIGIN_PARENT_ID, NoteColumns.GTASK_ID, | ||||||
|  |             NoteColumns.VERSION | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     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<SqlData> mDataList; | ||||||
|  | 
 | ||||||
|  |     public SqlNote(Context context) { | ||||||
|  |         mContext = context; | ||||||
|  |         mContentResolver = context.getContentResolver(); | ||||||
|  |         mIsCreate = true; | ||||||
|  |         mId = INVALID_ID; | ||||||
|  |         mAlertDate = 0; | ||||||
|  |         mBgColorId = ResourceParser.getDefaultBgId(context); | ||||||
|  |         mCreatedDate = System.currentTimeMillis(); | ||||||
|  |         mHasAttachment = 0; | ||||||
|  |         mModifiedDate = System.currentTimeMillis(); | ||||||
|  |         mParentId = 0; | ||||||
|  |         mSnippet = ""; | ||||||
|  |         mType = Notes.TYPE_NOTE; | ||||||
|  |         mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; | ||||||
|  |         mWidgetType = Notes.TYPE_WIDGET_INVALIDE; | ||||||
|  |         mOriginParent = 0; | ||||||
|  |         mVersion = 0; | ||||||
|  |         mDiffNoteValues = new ContentValues(); | ||||||
|  |         mDataList = new ArrayList<SqlData>(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public SqlNote(Context context, Cursor c) { | ||||||
|  |         mContext = context; | ||||||
|  |         mContentResolver = context.getContentResolver(); | ||||||
|  |         mIsCreate = false; | ||||||
|  |         loadFromCursor(c); | ||||||
|  |         mDataList = new ArrayList<SqlData>(); | ||||||
|  |         if (mType == Notes.TYPE_NOTE) | ||||||
|  |             loadDataContent(); | ||||||
|  |         mDiffNoteValues = new ContentValues(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public SqlNote(Context context, long id) { | ||||||
|  |         mContext = context; | ||||||
|  |         mContentResolver = context.getContentResolver(); | ||||||
|  |         mIsCreate = false; | ||||||
|  |         loadFromCursor(id); | ||||||
|  |         mDataList = new ArrayList<SqlData>(); | ||||||
|  |         if (mType == Notes.TYPE_NOTE) | ||||||
|  |             loadDataContent(); | ||||||
|  |         mDiffNoteValues = new ContentValues(); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void loadFromCursor(long id) { | ||||||
|  |         Cursor c = null; | ||||||
|  |         try { | ||||||
|  |             c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)", | ||||||
|  |                     new String[] { | ||||||
|  |                         String.valueOf(id) | ||||||
|  |                     }, null); | ||||||
|  |             if (c != null) { | ||||||
|  |                 c.moveToNext(); | ||||||
|  |                 loadFromCursor(c); | ||||||
|  |             } else { | ||||||
|  |                 Log.w(TAG, "loadFromCursor: cursor = null"); | ||||||
|  |             } | ||||||
|  |         } finally { | ||||||
|  |             if (c != null) | ||||||
|  |                 c.close(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void loadFromCursor(Cursor c) { | ||||||
|  |         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); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void loadDataContent() { | ||||||
|  |         Cursor c = null; | ||||||
|  |         mDataList.clear(); | ||||||
|  |         try { | ||||||
|  |             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"); | ||||||
|  |             } | ||||||
|  |         } finally { | ||||||
|  |             if (c != null) | ||||||
|  |                 c.close(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public boolean setContent(JSONObject js) { | ||||||
|  |         try { | ||||||
|  |             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) { | ||||||
|  |                 // for folder we can only update the snnipet and type
 | ||||||
|  |                 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; | ||||||
|  |                 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; | ||||||
|  | 
 | ||||||
|  |                 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; | ||||||
|  | 
 | ||||||
|  |                 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; | ||||||
|  | 
 | ||||||
|  |                 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; | ||||||
|  | 
 | ||||||
|  |                 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) { | ||||||
|  |                 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) { | ||||||
|  |                 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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setParentId(long id) { | ||||||
|  |         mParentId = id; | ||||||
|  |         mDiffNoteValues.put(NoteColumns.PARENT_ID, id); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setGtaskId(String gid) { | ||||||
|  |         mDiffNoteValues.put(NoteColumns.GTASK_ID, gid); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setSyncId(long syncId) { | ||||||
|  |         mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void resetLocalModified() { | ||||||
|  |         mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public long getId() { | ||||||
|  |         return mId; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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) { | ||||||
|  |             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 { | ||||||
|  |             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); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // refresh local info
 | ||||||
|  |         loadFromCursor(mId); | ||||||
|  |         if (mType == Notes.TYPE_NOTE) | ||||||
|  |             loadDataContent(); | ||||||
|  | 
 | ||||||
|  |         mDiffNoteValues.clear(); | ||||||
|  |         mIsCreate = false; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,351 @@ | |||||||
|  | /* | ||||||
|  |  * 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.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; | ||||||
|  | 
 | ||||||
|  |     private TaskList mParent; | ||||||
|  | 
 | ||||||
|  |     public Task() { | ||||||
|  |         super(); | ||||||
|  |         mCompleted = false; | ||||||
|  |         mNotes = null; | ||||||
|  |         mPriorSibling = null; | ||||||
|  |         mParent = null; | ||||||
|  |         mMetaInfo = null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setPriorSibling(Task priorSibling) { | ||||||
|  |         this.mPriorSibling = priorSibling; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setParent(TaskList parent) { | ||||||
|  |         this.mParent = parent; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public boolean getCompleted() { | ||||||
|  |         return this.mCompleted; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getNotes() { | ||||||
|  |         return this.mNotes; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Task getPriorSibling() { | ||||||
|  |         return this.mPriorSibling; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public TaskList getParent() { | ||||||
|  |         return this.mParent; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -0,0 +1,343 @@ | |||||||
|  | /* | ||||||
|  |  * 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(); | ||||||
|  | 
 | ||||||
|  |     private int mIndex; | ||||||
|  | 
 | ||||||
|  |     private ArrayList<Task> mChildren; | ||||||
|  | 
 | ||||||
|  |     public TaskList() { | ||||||
|  |         super(); | ||||||
|  |         mChildren = new ArrayList<Task>(); | ||||||
|  |         mIndex = 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public int getChildTaskIndex(Task task) { | ||||||
|  |         return mChildren.indexOf(task); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Task getChildTaskByIndex(int index) { | ||||||
|  |         if (index < 0 || index >= mChildren.size()) { | ||||||
|  |             Log.e(TAG, "getTaskByIndex: invalid index"); | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         return mChildren.get(index); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Task getChilTaskByGid(String gid) { | ||||||
|  |         for (Task task : mChildren) { | ||||||
|  |             if (task.getGid().equals(gid)) | ||||||
|  |                 return task; | ||||||
|  |         } | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public ArrayList<Task> getChildTaskList() { | ||||||
|  |         return this.mChildren; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setIndex(int index) { | ||||||
|  |         this.mIndex = index; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public int getIndex() { | ||||||
|  |         return this.mIndex; | ||||||
|  |     } | ||||||
|  | } | ||||||
					Loading…
					
					
				
		Reference in new issue