@ -1,43 +0,0 @@
 | 
				
			||||
import numpy as np
 | 
				
			||||
import scipy.stats as stats
 | 
				
			||||
 | 
				
			||||
# 假设数据
 | 
				
			||||
# 老龄化程度较高的群体数据
 | 
				
			||||
high_aging_data = {
 | 
				
			||||
    '老龄化给社会带来的主要问题': np.array([75.47, 85.85, 84.91, 53.77, 83.96]),
 | 
				
			||||
    '政府应该采取哪些措施': np.array([62.26, 16.04, 91.51, 88.68, 51.89,0.94]),
 | 
				
			||||
    'life_expectancy': np.array([75, 76, 74, 77, 75]),
 | 
				
			||||
    # 其他可能的因素...
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
# 老龄化程度较低的群体数据
 | 
				
			||||
low_aging_data = {
 | 
				
			||||
    '老龄化给社会带来的主要问题': np.array([84.62, 69.23, 69.23, 15.38, 84.62]),
 | 
				
			||||
    '政府应该采取哪些措施': np.array([46.15, 7.69, 69.23, 76.92, 30.77,7.69]),
 | 
				
			||||
    'life_expectancy': np.array([70, 71, 69, 72, 70]),
 | 
				
			||||
    # 其他可能的因素...
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
# 进行t检验并分析结果
 | 
				
			||||
factors = ['老龄化给社会带来的主要问题', '政府应该采取哪些措施', 'life_expectancy']
 | 
				
			||||
system_evaluation = {}
 | 
				
			||||
 | 
				
			||||
for factor in factors:
 | 
				
			||||
    high_group = high_aging_data[factor]
 | 
				
			||||
    low_group = low_aging_data[factor]
 | 
				
			||||
    t_stat, p_value = stats.ttest_ind(high_group, low_group)
 | 
				
			||||
    system_evaluation[factor] = {
 | 
				
			||||
        't_statistic': t_stat,
 | 
				
			||||
        'p_value': p_value,
 | 
				
			||||
        'effect_size': np.abs(t_stat) * np.sqrt((len(high_group) + len(low_group)) / (len(high_group) * len(low_group)))
 | 
				
			||||
    }
 | 
				
			||||
    print(f"{factor}的t统计量: {t_stat}, P值: {p_value}")
 | 
				
			||||
    if p_value < 0.05:
 | 
				
			||||
        print(f"{factor}在两个群体之间存在显著差异。\n")
 | 
				
			||||
    else:
 | 
				
			||||
        print(f"{factor}在两个群体之间没有显著差异。\n")
 | 
				
			||||
 | 
				
			||||
# 打印系统评价
 | 
				
			||||
print("系统评价:")
 | 
				
			||||
for factor, evaluation in system_evaluation.items():
 | 
				
			||||
    print(f"{factor}: t统计量={evaluation['t_statistic']}, P值={evaluation['p_value']}, 影响大小={evaluation['effect_size']}")
 | 
				
			||||
@ -0,0 +1,82 @@
 | 
				
			||||
/*
 | 
				
			||||
 * 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.tool.GTaskStringUtils;
 | 
				
			||||
 | 
				
			||||
import org.json.JSONException;
 | 
				
			||||
import org.json.JSONObject;
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
public class MetaData extends Task {
 | 
				
			||||
    private final static String TAG = MetaData.class.getSimpleName();
 | 
				
			||||
 | 
				
			||||
    private String mRelatedGid = null;
 | 
				
			||||
 | 
				
			||||
    public void setMeta(String gid, JSONObject metaInfo) {
 | 
				
			||||
        try {
 | 
				
			||||
            metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);
 | 
				
			||||
        } catch (JSONException e) {
 | 
				
			||||
            Log.e(TAG, "failed to put related gid");
 | 
				
			||||
        }
 | 
				
			||||
        setNotes(metaInfo.toString());
 | 
				
			||||
        setName(GTaskStringUtils.META_NOTE_NAME);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public String getRelatedGid() {
 | 
				
			||||
        return mRelatedGid;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public boolean isWorthSaving() {
 | 
				
			||||
        return getNotes() != null;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public void setContentByRemoteJSON(JSONObject js) {
 | 
				
			||||
        super.setContentByRemoteJSON(js);
 | 
				
			||||
        if (getNotes() != null) {
 | 
				
			||||
            try {
 | 
				
			||||
                JSONObject metaInfo = new JSONObject(getNotes().trim());
 | 
				
			||||
                mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID);
 | 
				
			||||
            } catch (JSONException e) {
 | 
				
			||||
                Log.w(TAG, "failed to get related gid");
 | 
				
			||||
                mRelatedGid = null;
 | 
				
			||||
            }
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public void setContentByLocalJSON(JSONObject js) {
 | 
				
			||||
        // this function should not be called
 | 
				
			||||
        throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public JSONObject getLocalJSONFromContent() {
 | 
				
			||||
        throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called");
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public int getSyncAction(Cursor c) {
 | 
				
			||||
        throw new IllegalAccessError("MetaData:getSyncAction should not be called");
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
}
 | 
				
			||||
@ -0,0 +1,101 @@
 | 
				
			||||
/*
 | 
				
			||||
 * 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 org.json.JSONObject;
 | 
				
			||||
 | 
				
			||||
public abstract class Node {
 | 
				
			||||
    public static final int SYNC_ACTION_NONE = 0;
 | 
				
			||||
 | 
				
			||||
    public static final int SYNC_ACTION_ADD_REMOTE = 1;
 | 
				
			||||
 | 
				
			||||
    public static final int SYNC_ACTION_ADD_LOCAL = 2;
 | 
				
			||||
 | 
				
			||||
    public static final int SYNC_ACTION_DEL_REMOTE = 3;
 | 
				
			||||
 | 
				
			||||
    public static final int SYNC_ACTION_DEL_LOCAL = 4;
 | 
				
			||||
 | 
				
			||||
    public static final int SYNC_ACTION_UPDATE_REMOTE = 5;
 | 
				
			||||
 | 
				
			||||
    public static final int SYNC_ACTION_UPDATE_LOCAL = 6;
 | 
				
			||||
 | 
				
			||||
    public static final int SYNC_ACTION_UPDATE_CONFLICT = 7;
 | 
				
			||||
 | 
				
			||||
    public static final int SYNC_ACTION_ERROR = 8;
 | 
				
			||||
 | 
				
			||||
    private String mGid;
 | 
				
			||||
 | 
				
			||||
    private String mName;
 | 
				
			||||
 | 
				
			||||
    private long mLastModified;
 | 
				
			||||
 | 
				
			||||
    private boolean mDeleted;
 | 
				
			||||
 | 
				
			||||
    public Node() {
 | 
				
			||||
        mGid = null;
 | 
				
			||||
        mName = "";
 | 
				
			||||
        mLastModified = 0;
 | 
				
			||||
        mDeleted = false;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public abstract JSONObject getCreateAction(int actionId);
 | 
				
			||||
 | 
				
			||||
    public abstract JSONObject getUpdateAction(int actionId);
 | 
				
			||||
 | 
				
			||||
    public abstract void setContentByRemoteJSON(JSONObject js);
 | 
				
			||||
 | 
				
			||||
    public abstract void setContentByLocalJSON(JSONObject js);
 | 
				
			||||
 | 
				
			||||
    public abstract JSONObject getLocalJSONFromContent();
 | 
				
			||||
 | 
				
			||||
    public abstract int getSyncAction(Cursor c);
 | 
				
			||||
 | 
				
			||||
    public void setGid(String gid) {
 | 
				
			||||
        this.mGid = gid;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public void setName(String name) {
 | 
				
			||||
        this.mName = name;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public void setLastModified(long lastModified) {
 | 
				
			||||
        this.mLastModified = lastModified;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public void setDeleted(boolean deleted) {
 | 
				
			||||
        this.mDeleted = deleted;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public String getGid() {
 | 
				
			||||
        return this.mGid;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public String getName() {
 | 
				
			||||
        return this.mName;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public long getLastModified() {
 | 
				
			||||
        return this.mLastModified;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public boolean getDeleted() {
 | 
				
			||||
        return this.mDeleted;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
}
 | 
				
			||||
@ -0,0 +1,189 @@
 | 
				
			||||
/*
 | 
				
			||||
 * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
 | 
				
			||||
 *
 | 
				
			||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||
 * you may not use this file except in compliance with the License.
 | 
				
			||||
 * You may obtain a copy of the License at
 | 
				
			||||
 *
 | 
				
			||||
 *        http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||
 *
 | 
				
			||||
 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||
 * See the License for the specific language governing permissions and
 | 
				
			||||
 * limitations under the License.
 | 
				
			||||
 */
 | 
				
			||||
 | 
				
			||||
package net.micode.notes.gtask.data;
 | 
				
			||||
 | 
				
			||||
import android.content.ContentResolver;
 | 
				
			||||
import android.content.ContentUris;
 | 
				
			||||
import android.content.ContentValues;
 | 
				
			||||
import android.content.Context;
 | 
				
			||||
import android.database.Cursor;
 | 
				
			||||
import android.net.Uri;
 | 
				
			||||
import android.util.Log;
 | 
				
			||||
 | 
				
			||||
import net.micode.notes.data.Notes;
 | 
				
			||||
import net.micode.notes.data.Notes.DataColumns;
 | 
				
			||||
import net.micode.notes.data.Notes.DataConstants;
 | 
				
			||||
import net.micode.notes.data.Notes.NoteColumns;
 | 
				
			||||
import net.micode.notes.data.NotesDatabaseHelper.TABLE;
 | 
				
			||||
import net.micode.notes.gtask.exception.ActionFailureException;
 | 
				
			||||
 | 
				
			||||
import org.json.JSONException;
 | 
				
			||||
import org.json.JSONObject;
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
public class SqlData {
 | 
				
			||||
    private static final String TAG = SqlData.class.getSimpleName();
 | 
				
			||||
 | 
				
			||||
    private static final int INVALID_ID = -99999;
 | 
				
			||||
 | 
				
			||||
    public static final String[] PROJECTION_DATA = new String[] {
 | 
				
			||||
            DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1,
 | 
				
			||||
            DataColumns.DATA3
 | 
				
			||||
    };
 | 
				
			||||
 | 
				
			||||
    public static final int DATA_ID_COLUMN = 0;
 | 
				
			||||
 | 
				
			||||
    public static final int DATA_MIME_TYPE_COLUMN = 1;
 | 
				
			||||
 | 
				
			||||
    public static final int DATA_CONTENT_COLUMN = 2;
 | 
				
			||||
 | 
				
			||||
    public static final int DATA_CONTENT_DATA_1_COLUMN = 3;
 | 
				
			||||
 | 
				
			||||
    public static final int DATA_CONTENT_DATA_3_COLUMN = 4;
 | 
				
			||||
 | 
				
			||||
    private ContentResolver mContentResolver;
 | 
				
			||||
 | 
				
			||||
    private boolean mIsCreate;
 | 
				
			||||
 | 
				
			||||
    private long mDataId;
 | 
				
			||||
 | 
				
			||||
    private String mDataMimeType;
 | 
				
			||||
 | 
				
			||||
    private String mDataContent;
 | 
				
			||||
 | 
				
			||||
    private long mDataContentData1;
 | 
				
			||||
 | 
				
			||||
    private String mDataContentData3;
 | 
				
			||||
 | 
				
			||||
    private ContentValues mDiffDataValues;
 | 
				
			||||
 | 
				
			||||
    public SqlData(Context context) {
 | 
				
			||||
        mContentResolver = context.getContentResolver();
 | 
				
			||||
        mIsCreate = true;
 | 
				
			||||
        mDataId = INVALID_ID;
 | 
				
			||||
        mDataMimeType = DataConstants.NOTE;
 | 
				
			||||
        mDataContent = "";
 | 
				
			||||
        mDataContentData1 = 0;
 | 
				
			||||
        mDataContentData3 = "";
 | 
				
			||||
        mDiffDataValues = new ContentValues();
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public SqlData(Context context, Cursor c) {
 | 
				
			||||
        mContentResolver = context.getContentResolver();
 | 
				
			||||
        mIsCreate = false;
 | 
				
			||||
        loadFromCursor(c);
 | 
				
			||||
        mDiffDataValues = new ContentValues();
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    private void loadFromCursor(Cursor c) {
 | 
				
			||||
        mDataId = c.getLong(DATA_ID_COLUMN);
 | 
				
			||||
        mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN);
 | 
				
			||||
        mDataContent = c.getString(DATA_CONTENT_COLUMN);
 | 
				
			||||
        mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN);
 | 
				
			||||
        mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public void setContent(JSONObject js) throws JSONException {
 | 
				
			||||
        long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;
 | 
				
			||||
        if (mIsCreate || mDataId != dataId) {
 | 
				
			||||
            mDiffDataValues.put(DataColumns.ID, dataId);
 | 
				
			||||
        }
 | 
				
			||||
        mDataId = dataId;
 | 
				
			||||
 | 
				
			||||
        String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE)
 | 
				
			||||
                : DataConstants.NOTE;
 | 
				
			||||
        if (mIsCreate || !mDataMimeType.equals(dataMimeType)) {
 | 
				
			||||
            mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType);
 | 
				
			||||
        }
 | 
				
			||||
        mDataMimeType = dataMimeType;
 | 
				
			||||
 | 
				
			||||
        String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : "";
 | 
				
			||||
        if (mIsCreate || !mDataContent.equals(dataContent)) {
 | 
				
			||||
            mDiffDataValues.put(DataColumns.CONTENT, dataContent);
 | 
				
			||||
        }
 | 
				
			||||
        mDataContent = dataContent;
 | 
				
			||||
 | 
				
			||||
        long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0;
 | 
				
			||||
        if (mIsCreate || mDataContentData1 != dataContentData1) {
 | 
				
			||||
            mDiffDataValues.put(DataColumns.DATA1, dataContentData1);
 | 
				
			||||
        }
 | 
				
			||||
        mDataContentData1 = dataContentData1;
 | 
				
			||||
 | 
				
			||||
        String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : "";
 | 
				
			||||
        if (mIsCreate || !mDataContentData3.equals(dataContentData3)) {
 | 
				
			||||
            mDiffDataValues.put(DataColumns.DATA3, dataContentData3);
 | 
				
			||||
        }
 | 
				
			||||
        mDataContentData3 = dataContentData3;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public JSONObject getContent() throws JSONException {
 | 
				
			||||
        if (mIsCreate) {
 | 
				
			||||
            Log.e(TAG, "it seems that we haven't created this in database yet");
 | 
				
			||||
            return null;
 | 
				
			||||
        }
 | 
				
			||||
        JSONObject js = new JSONObject();
 | 
				
			||||
        js.put(DataColumns.ID, mDataId);
 | 
				
			||||
        js.put(DataColumns.MIME_TYPE, mDataMimeType);
 | 
				
			||||
        js.put(DataColumns.CONTENT, mDataContent);
 | 
				
			||||
        js.put(DataColumns.DATA1, mDataContentData1);
 | 
				
			||||
        js.put(DataColumns.DATA3, mDataContentData3);
 | 
				
			||||
        return js;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public void commit(long noteId, boolean validateVersion, long version) {
 | 
				
			||||
 | 
				
			||||
        if (mIsCreate) {
 | 
				
			||||
            if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) {
 | 
				
			||||
                mDiffDataValues.remove(DataColumns.ID);
 | 
				
			||||
            }
 | 
				
			||||
 | 
				
			||||
            mDiffDataValues.put(DataColumns.NOTE_ID, noteId);
 | 
				
			||||
            Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues);
 | 
				
			||||
            try {
 | 
				
			||||
                mDataId = Long.valueOf(uri.getPathSegments().get(1));
 | 
				
			||||
            } catch (NumberFormatException e) {
 | 
				
			||||
                Log.e(TAG, "Get note id error :" + e.toString());
 | 
				
			||||
                throw new ActionFailureException("create note failed");
 | 
				
			||||
            }
 | 
				
			||||
        } else {
 | 
				
			||||
            if (mDiffDataValues.size() > 0) {
 | 
				
			||||
                int result = 0;
 | 
				
			||||
                if (!validateVersion) {
 | 
				
			||||
                    result = mContentResolver.update(ContentUris.withAppendedId(
 | 
				
			||||
                            Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null);
 | 
				
			||||
                } else {
 | 
				
			||||
                    result = mContentResolver.update(ContentUris.withAppendedId(
 | 
				
			||||
                            Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues,
 | 
				
			||||
                            " ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE
 | 
				
			||||
                                    + " WHERE " + NoteColumns.VERSION + "=?)", new String[] {
 | 
				
			||||
                                    String.valueOf(noteId), String.valueOf(version)
 | 
				
			||||
                            });
 | 
				
			||||
                }
 | 
				
			||||
                if (result == 0) {
 | 
				
			||||
                    Log.w(TAG, "there is no update. maybe user updates note when syncing");
 | 
				
			||||
                }
 | 
				
			||||
            }
 | 
				
			||||
        }
 | 
				
			||||
 | 
				
			||||
        mDiffDataValues.clear();
 | 
				
			||||
        mIsCreate = false;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public long getId() {
 | 
				
			||||
        return mDataId;
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
@ -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,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,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,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,128 @@
 | 
				
			||||
/*
 | 
				
			||||
 * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
 | 
				
			||||
 *
 | 
				
			||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||
 * you may not use this file except in compliance with the License.
 | 
				
			||||
 * You may obtain a copy of the License at
 | 
				
			||||
 *
 | 
				
			||||
 *        http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||
 *
 | 
				
			||||
 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||
 * See the License for the specific language governing permissions and
 | 
				
			||||
 * limitations under the License.
 | 
				
			||||
 */
 | 
				
			||||
 | 
				
			||||
package net.micode.notes.gtask.remote;
 | 
				
			||||
 | 
				
			||||
import android.app.Activity;
 | 
				
			||||
import android.app.Service;
 | 
				
			||||
import android.content.Context;
 | 
				
			||||
import android.content.Intent;
 | 
				
			||||
import android.os.Bundle;
 | 
				
			||||
import android.os.IBinder;
 | 
				
			||||
 | 
				
			||||
public class GTaskSyncService extends Service {
 | 
				
			||||
    public final static String ACTION_STRING_NAME = "sync_action_type";
 | 
				
			||||
 | 
				
			||||
    public final static int ACTION_START_SYNC = 0;
 | 
				
			||||
 | 
				
			||||
    public final static int ACTION_CANCEL_SYNC = 1;
 | 
				
			||||
 | 
				
			||||
    public final static int ACTION_INVALID = 2;
 | 
				
			||||
 | 
				
			||||
    public final static String GTASK_SERVICE_BROADCAST_NAME = "net.micode.notes.gtask.remote.gtask_sync_service";
 | 
				
			||||
 | 
				
			||||
    public final static String GTASK_SERVICE_BROADCAST_IS_SYNCING = "isSyncing";
 | 
				
			||||
 | 
				
			||||
    public final static String GTASK_SERVICE_BROADCAST_PROGRESS_MSG = "progressMsg";
 | 
				
			||||
 | 
				
			||||
    private static GTaskASyncTask mSyncTask = null;
 | 
				
			||||
 | 
				
			||||
    private static String mSyncProgress = "";
 | 
				
			||||
 | 
				
			||||
    private void startSync() {
 | 
				
			||||
        if (mSyncTask == null) {
 | 
				
			||||
            mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() {
 | 
				
			||||
                public void onComplete() {
 | 
				
			||||
                    mSyncTask = null;
 | 
				
			||||
                    sendBroadcast("");
 | 
				
			||||
                    stopSelf();
 | 
				
			||||
                }
 | 
				
			||||
            });
 | 
				
			||||
            sendBroadcast("");
 | 
				
			||||
            mSyncTask.execute();
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    private void cancelSync() {
 | 
				
			||||
        if (mSyncTask != null) {
 | 
				
			||||
            mSyncTask.cancelSync();
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public void onCreate() {
 | 
				
			||||
        mSyncTask = null;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public int onStartCommand(Intent intent, int flags, int startId) {
 | 
				
			||||
        Bundle bundle = intent.getExtras();
 | 
				
			||||
        if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) {
 | 
				
			||||
            switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) {
 | 
				
			||||
                case ACTION_START_SYNC:
 | 
				
			||||
                    startSync();
 | 
				
			||||
                    break;
 | 
				
			||||
                case ACTION_CANCEL_SYNC:
 | 
				
			||||
                    cancelSync();
 | 
				
			||||
                    break;
 | 
				
			||||
                default:
 | 
				
			||||
                    break;
 | 
				
			||||
            }
 | 
				
			||||
            return START_STICKY;
 | 
				
			||||
        }
 | 
				
			||||
        return super.onStartCommand(intent, flags, startId);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    @Override
 | 
				
			||||
    public void onLowMemory() {
 | 
				
			||||
        if (mSyncTask != null) {
 | 
				
			||||
            mSyncTask.cancelSync();
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public IBinder onBind(Intent intent) {
 | 
				
			||||
        return null;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public void sendBroadcast(String msg) {
 | 
				
			||||
        mSyncProgress = msg;
 | 
				
			||||
        Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME);
 | 
				
			||||
        intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null);
 | 
				
			||||
        intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg);
 | 
				
			||||
        sendBroadcast(intent);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public static void startSync(Activity activity) {
 | 
				
			||||
        GTaskManager.getInstance().setActivityContext(activity);
 | 
				
			||||
        Intent intent = new Intent(activity, GTaskSyncService.class);
 | 
				
			||||
        intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC);
 | 
				
			||||
        activity.startService(intent);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public static void cancelSync(Context context) {
 | 
				
			||||
        Intent intent = new Intent(context, GTaskSyncService.class);
 | 
				
			||||
        intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC);
 | 
				
			||||
        context.startService(intent);
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public static boolean isSyncing() {
 | 
				
			||||
        return mSyncTask != null;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    public static String getProgressString() {
 | 
				
			||||
        return mSyncProgress;
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
@ -1,9 +0,0 @@
 | 
				
			||||
# generated files
 | 
				
			||||
bin/
 | 
				
			||||
gen/
 | 
				
			||||
 | 
				
			||||
# Local configuration file (sdk path, etc)
 | 
				
			||||
project.properties
 | 
				
			||||
.settings/
 | 
				
			||||
.classpath
 | 
				
			||||
.project
 | 
				
			||||
@ -1,150 +0,0 @@
 | 
				
			||||
<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||
 | 
				
			||||
<!-- 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.
 | 
				
			||||
-->
 | 
				
			||||
 | 
				
			||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||
    package="net.micode.notes"
 | 
				
			||||
    android:versionCode="1"
 | 
				
			||||
    android:versionName="0.1" >
 | 
				
			||||
 | 
				
			||||
    <uses-sdk android:minSdkVersion="14" />
 | 
				
			||||
 | 
				
			||||
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 | 
				
			||||
    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
 | 
				
			||||
    <uses-permission android:name="android.permission.INTERNET" />
 | 
				
			||||
    <uses-permission android:name="android.permission.READ_CONTACTS" />
 | 
				
			||||
    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
 | 
				
			||||
    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
 | 
				
			||||
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
 | 
				
			||||
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
 | 
				
			||||
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
 | 
				
			||||
 | 
				
			||||
    <application
 | 
				
			||||
        android:icon="@drawable/icon_app"
 | 
				
			||||
        android:label="@string/app_name" >
 | 
				
			||||
        <activity
 | 
				
			||||
            android:name=".ui.NotesListActivity"
 | 
				
			||||
            android:configChanges="keyboardHidden|orientation|screenSize"
 | 
				
			||||
            android:label="@string/app_name"
 | 
				
			||||
            android:launchMode="singleTop"
 | 
				
			||||
            android:theme="@style/NoteTheme"
 | 
				
			||||
            android:uiOptions="splitActionBarWhenNarrow"
 | 
				
			||||
            android:windowSoftInputMode="adjustPan" >
 | 
				
			||||
 | 
				
			||||
            <intent-filter>
 | 
				
			||||
                <action android:name="android.intent.action.MAIN" />
 | 
				
			||||
                <category android:name="android.intent.category.LAUNCHER" />
 | 
				
			||||
            </intent-filter>
 | 
				
			||||
        </activity>
 | 
				
			||||
 | 
				
			||||
        <activity
 | 
				
			||||
            android:name=".ui.NoteEditActivity"
 | 
				
			||||
            android:configChanges="keyboardHidden|orientation|screenSize"
 | 
				
			||||
            android:launchMode="singleTop"
 | 
				
			||||
            android:theme="@style/NoteTheme" >
 | 
				
			||||
 | 
				
			||||
            <intent-filter>
 | 
				
			||||
                <action android:name="android.intent.action.VIEW" />
 | 
				
			||||
                <category android:name="android.intent.category.DEFAULT" />
 | 
				
			||||
                <data android:mimeType="vnd.android.cursor.item/text_note" />
 | 
				
			||||
                <data android:mimeType="vnd.android.cursor.item/call_note" />
 | 
				
			||||
            </intent-filter>
 | 
				
			||||
 | 
				
			||||
            <intent-filter>
 | 
				
			||||
                <action android:name="android.intent.action.INSERT_OR_EDIT" />
 | 
				
			||||
                <category android:name="android.intent.category.DEFAULT" />
 | 
				
			||||
                <data android:mimeType="vnd.android.cursor.item/text_note" />
 | 
				
			||||
                <data android:mimeType="vnd.android.cursor.item/call_note" />
 | 
				
			||||
            </intent-filter>
 | 
				
			||||
 | 
				
			||||
            <intent-filter>
 | 
				
			||||
                <action android:name="android.intent.action.SEARCH" />
 | 
				
			||||
                <category android:name="android.intent.category.DEFAULT" />
 | 
				
			||||
            </intent-filter>
 | 
				
			||||
 | 
				
			||||
            <meta-data
 | 
				
			||||
                android:name="android.app.searchable"
 | 
				
			||||
                android:resource="@xml/searchable" />
 | 
				
			||||
        </activity>
 | 
				
			||||
 | 
				
			||||
        <provider
 | 
				
			||||
            android:name="net.micode.notes.data.NotesProvider"
 | 
				
			||||
            android:authorities="micode_notes"
 | 
				
			||||
            android:multiprocess="true" />
 | 
				
			||||
 | 
				
			||||
        <receiver
 | 
				
			||||
            android:name=".widget.NoteWidgetProvider_2x"
 | 
				
			||||
            android:label="@string/app_widget2x2" >
 | 
				
			||||
            <intent-filter>
 | 
				
			||||
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
 | 
				
			||||
                <action android:name="android.appwidget.action.APPWIDGET_DELETED" />
 | 
				
			||||
                <action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
 | 
				
			||||
            </intent-filter>
 | 
				
			||||
 | 
				
			||||
            <meta-data
 | 
				
			||||
                android:name="android.appwidget.provider"
 | 
				
			||||
                android:resource="@xml/widget_2x_info" />
 | 
				
			||||
        </receiver>
 | 
				
			||||
        <receiver
 | 
				
			||||
            android:name=".widget.NoteWidgetProvider_4x"
 | 
				
			||||
            android:label="@string/app_widget4x4" >
 | 
				
			||||
 | 
				
			||||
            <intent-filter>
 | 
				
			||||
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
 | 
				
			||||
                <action android:name="android.appwidget.action.APPWIDGET_DELETED" />
 | 
				
			||||
                <action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
 | 
				
			||||
            </intent-filter>
 | 
				
			||||
 | 
				
			||||
            <meta-data
 | 
				
			||||
                android:name="android.appwidget.provider"
 | 
				
			||||
                android:resource="@xml/widget_4x_info" />
 | 
				
			||||
        </receiver>
 | 
				
			||||
 | 
				
			||||
        <receiver android:name=".ui.AlarmInitReceiver" >
 | 
				
			||||
            <intent-filter>
 | 
				
			||||
                <action android:name="android.intent.action.BOOT_COMPLETED" />
 | 
				
			||||
            </intent-filter>
 | 
				
			||||
        </receiver>
 | 
				
			||||
 | 
				
			||||
        <receiver
 | 
				
			||||
            android:name="net.micode.notes.ui.AlarmReceiver"
 | 
				
			||||
            android:process=":remote" >
 | 
				
			||||
        </receiver>
 | 
				
			||||
 | 
				
			||||
        <activity
 | 
				
			||||
            android:name=".ui.AlarmAlertActivity"
 | 
				
			||||
            android:label="@string/app_name"
 | 
				
			||||
            android:launchMode="singleInstance"
 | 
				
			||||
            android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar" >
 | 
				
			||||
        </activity>
 | 
				
			||||
 | 
				
			||||
        <activity
 | 
				
			||||
            android:name="net.micode.notes.ui.NotesPreferenceActivity"
 | 
				
			||||
            android:label="@string/preferences_title"
 | 
				
			||||
            android:launchMode="singleTop"
 | 
				
			||||
            android:theme="@android:style/Theme.Holo.Light" >
 | 
				
			||||
        </activity>
 | 
				
			||||
 | 
				
			||||
        <service
 | 
				
			||||
            android:name="net.micode.notes.gtask.remote.GTaskSyncService"
 | 
				
			||||
            android:exported="false" >
 | 
				
			||||
        </service>
 | 
				
			||||
 | 
				
			||||
        <meta-data
 | 
				
			||||
            android:name="android.app.default_searchable"
 | 
				
			||||
            android:value=".ui.NoteEditActivity" />
 | 
				
			||||
    </application>
 | 
				
			||||
</manifest>
 | 
				
			||||
@ -1,190 +0,0 @@
 | 
				
			||||
 | 
				
			||||
   Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
 | 
				
			||||
 | 
				
			||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||
   you may not use this file except in compliance with the License.
 | 
				
			||||
 | 
				
			||||
   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.
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
                                 Apache License
 | 
				
			||||
                           Version 2.0, January 2004
 | 
				
			||||
                        http://www.apache.org/licenses/
 | 
				
			||||
 | 
				
			||||
   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
				
			||||
 | 
				
			||||
   1. Definitions.
 | 
				
			||||
 | 
				
			||||
      "License" shall mean the terms and conditions for use, reproduction,
 | 
				
			||||
      and distribution as defined by Sections 1 through 9 of this document.
 | 
				
			||||
 | 
				
			||||
      "Licensor" shall mean the copyright owner or entity authorized by
 | 
				
			||||
      the copyright owner that is granting the License.
 | 
				
			||||
 | 
				
			||||
      "Legal Entity" shall mean the union of the acting entity and all
 | 
				
			||||
      other entities that control, are controlled by, or are under common
 | 
				
			||||
      control with that entity. For the purposes of this definition,
 | 
				
			||||
      "control" means (i) the power, direct or indirect, to cause the
 | 
				
			||||
      direction or management of such entity, whether by contract or
 | 
				
			||||
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
				
			||||
      outstanding shares, or (iii) beneficial ownership of such entity.
 | 
				
			||||
 | 
				
			||||
      "You" (or "Your") shall mean an individual or Legal Entity
 | 
				
			||||
      exercising permissions granted by this License.
 | 
				
			||||
 | 
				
			||||
      "Source" form shall mean the preferred form for making modifications,
 | 
				
			||||
      including but not limited to software source code, documentation
 | 
				
			||||
      source, and configuration files.
 | 
				
			||||
 | 
				
			||||
      "Object" form shall mean any form resulting from mechanical
 | 
				
			||||
      transformation or translation of a Source form, including but
 | 
				
			||||
      not limited to compiled object code, generated documentation,
 | 
				
			||||
      and conversions to other media types.
 | 
				
			||||
 | 
				
			||||
      "Work" shall mean the work of authorship, whether in Source or
 | 
				
			||||
      Object form, made available under the License, as indicated by a
 | 
				
			||||
      copyright notice that is included in or attached to the work
 | 
				
			||||
      (an example is provided in the Appendix below).
 | 
				
			||||
 | 
				
			||||
      "Derivative Works" shall mean any work, whether in Source or Object
 | 
				
			||||
      form, that is based on (or derived from) the Work and for which the
 | 
				
			||||
      editorial revisions, annotations, elaborations, or other modifications
 | 
				
			||||
      represent, as a whole, an original work of authorship. For the purposes
 | 
				
			||||
      of this License, Derivative Works shall not include works that remain
 | 
				
			||||
      separable from, or merely link (or bind by name) to the interfaces of,
 | 
				
			||||
      the Work and Derivative Works thereof.
 | 
				
			||||
 | 
				
			||||
      "Contribution" shall mean any work of authorship, including
 | 
				
			||||
      the original version of the Work and any modifications or additions
 | 
				
			||||
      to that Work or Derivative Works thereof, that is intentionally
 | 
				
			||||
      submitted to Licensor for inclusion in the Work by the copyright owner
 | 
				
			||||
      or by an individual or Legal Entity authorized to submit on behalf of
 | 
				
			||||
      the copyright owner. For the purposes of this definition, "submitted"
 | 
				
			||||
      means any form of electronic, verbal, or written communication sent
 | 
				
			||||
      to the Licensor or its representatives, including but not limited to
 | 
				
			||||
      communication on electronic mailing lists, source code control systems,
 | 
				
			||||
      and issue tracking systems that are managed by, or on behalf of, the
 | 
				
			||||
      Licensor for the purpose of discussing and improving the Work, but
 | 
				
			||||
      excluding communication that is conspicuously marked or otherwise
 | 
				
			||||
      designated in writing by the copyright owner as "Not a Contribution."
 | 
				
			||||
 | 
				
			||||
      "Contributor" shall mean Licensor and any individual or Legal Entity
 | 
				
			||||
      on behalf of whom a Contribution has been received by Licensor and
 | 
				
			||||
      subsequently incorporated within the Work.
 | 
				
			||||
 | 
				
			||||
   2. Grant of Copyright License. Subject to the terms and conditions of
 | 
				
			||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
				
			||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
				
			||||
      copyright license to reproduce, prepare Derivative Works of,
 | 
				
			||||
      publicly display, publicly perform, sublicense, and distribute the
 | 
				
			||||
      Work and such Derivative Works in Source or Object form.
 | 
				
			||||
 | 
				
			||||
   3. Grant of Patent License. Subject to the terms and conditions of
 | 
				
			||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
				
			||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
				
			||||
      (except as stated in this section) patent license to make, have made,
 | 
				
			||||
      use, offer to sell, sell, import, and otherwise transfer the Work,
 | 
				
			||||
      where such license applies only to those patent claims licensable
 | 
				
			||||
      by such Contributor that are necessarily infringed by their
 | 
				
			||||
      Contribution(s) alone or by combination of their Contribution(s)
 | 
				
			||||
      with the Work to which such Contribution(s) was submitted. If You
 | 
				
			||||
      institute patent litigation against any entity (including a
 | 
				
			||||
      cross-claim or counterclaim in a lawsuit) alleging that the Work
 | 
				
			||||
      or a Contribution incorporated within the Work constitutes direct
 | 
				
			||||
      or contributory patent infringement, then any patent licenses
 | 
				
			||||
      granted to You under this License for that Work shall terminate
 | 
				
			||||
      as of the date such litigation is filed.
 | 
				
			||||
 | 
				
			||||
   4. Redistribution. You may reproduce and distribute copies of the
 | 
				
			||||
      Work or Derivative Works thereof in any medium, with or without
 | 
				
			||||
      modifications, and in Source or Object form, provided that You
 | 
				
			||||
      meet the following conditions:
 | 
				
			||||
 | 
				
			||||
      (a) You must give any other recipients of the Work or
 | 
				
			||||
          Derivative Works a copy of this License; and
 | 
				
			||||
 | 
				
			||||
      (b) You must cause any modified files to carry prominent notices
 | 
				
			||||
          stating that You changed the files; and
 | 
				
			||||
 | 
				
			||||
      (c) You must retain, in the Source form of any Derivative Works
 | 
				
			||||
          that You distribute, all copyright, patent, trademark, and
 | 
				
			||||
          attribution notices from the Source form of the Work,
 | 
				
			||||
          excluding those notices that do not pertain to any part of
 | 
				
			||||
          the Derivative Works; and
 | 
				
			||||
 | 
				
			||||
      (d) If the Work includes a "NOTICE" text file as part of its
 | 
				
			||||
          distribution, then any Derivative Works that You distribute must
 | 
				
			||||
          include a readable copy of the attribution notices contained
 | 
				
			||||
          within such NOTICE file, excluding those notices that do not
 | 
				
			||||
          pertain to any part of the Derivative Works, in at least one
 | 
				
			||||
          of the following places: within a NOTICE text file distributed
 | 
				
			||||
          as part of the Derivative Works; within the Source form or
 | 
				
			||||
          documentation, if provided along with the Derivative Works; or,
 | 
				
			||||
          within a display generated by the Derivative Works, if and
 | 
				
			||||
          wherever such third-party notices normally appear. The contents
 | 
				
			||||
          of the NOTICE file are for informational purposes only and
 | 
				
			||||
          do not modify the License. You may add Your own attribution
 | 
				
			||||
          notices within Derivative Works that You distribute, alongside
 | 
				
			||||
          or as an addendum to the NOTICE text from the Work, provided
 | 
				
			||||
          that such additional attribution notices cannot be construed
 | 
				
			||||
          as modifying the License.
 | 
				
			||||
 | 
				
			||||
      You may add Your own copyright statement to Your modifications and
 | 
				
			||||
      may provide additional or different license terms and conditions
 | 
				
			||||
      for use, reproduction, or distribution of Your modifications, or
 | 
				
			||||
      for any such Derivative Works as a whole, provided Your use,
 | 
				
			||||
      reproduction, and distribution of the Work otherwise complies with
 | 
				
			||||
      the conditions stated in this License.
 | 
				
			||||
 | 
				
			||||
   5. Submission of Contributions. Unless You explicitly state otherwise,
 | 
				
			||||
      any Contribution intentionally submitted for inclusion in the Work
 | 
				
			||||
      by You to the Licensor shall be under the terms and conditions of
 | 
				
			||||
      this License, without any additional terms or conditions.
 | 
				
			||||
      Notwithstanding the above, nothing herein shall supersede or modify
 | 
				
			||||
      the terms of any separate license agreement you may have executed
 | 
				
			||||
      with Licensor regarding such Contributions.
 | 
				
			||||
 | 
				
			||||
   6. Trademarks. This License does not grant permission to use the trade
 | 
				
			||||
      names, trademarks, service marks, or product names of the Licensor,
 | 
				
			||||
      except as required for reasonable and customary use in describing the
 | 
				
			||||
      origin of the Work and reproducing the content of the NOTICE file.
 | 
				
			||||
 | 
				
			||||
   7. Disclaimer of Warranty. Unless required by applicable law or
 | 
				
			||||
      agreed to in writing, Licensor provides the Work (and each
 | 
				
			||||
      Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
				
			||||
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
				
			||||
      implied, including, without limitation, any warranties or conditions
 | 
				
			||||
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 | 
				
			||||
      PARTICULAR PURPOSE. You are solely responsible for determining the
 | 
				
			||||
      appropriateness of using or redistributing the Work and assume any
 | 
				
			||||
      risks associated with Your exercise of permissions under this License.
 | 
				
			||||
 | 
				
			||||
   8. Limitation of Liability. In no event and under no legal theory,
 | 
				
			||||
      whether in tort (including negligence), contract, or otherwise,
 | 
				
			||||
      unless required by applicable law (such as deliberate and grossly
 | 
				
			||||
      negligent acts) or agreed to in writing, shall any Contributor be
 | 
				
			||||
      liable to You for damages, including any direct, indirect, special,
 | 
				
			||||
      incidental, or consequential damages of any character arising as a
 | 
				
			||||
      result of this License or out of the use or inability to use the
 | 
				
			||||
      Work (including but not limited to damages for loss of goodwill,
 | 
				
			||||
      work stoppage, computer failure or malfunction, or any and all
 | 
				
			||||
      other commercial damages or losses), even if such Contributor
 | 
				
			||||
      has been advised of the possibility of such damages.
 | 
				
			||||
 | 
				
			||||
   9. Accepting Warranty or Additional Liability. While redistributing
 | 
				
			||||
      the Work or Derivative Works thereof, You may choose to offer,
 | 
				
			||||
      and charge a fee for, acceptance of support, warranty, indemnity,
 | 
				
			||||
      or other liability obligations and/or rights consistent with this
 | 
				
			||||
      License. However, in accepting such obligations, You may act only
 | 
				
			||||
      on Your own behalf and on Your sole responsibility, not on behalf
 | 
				
			||||
      of any other Contributor, and only if You agree to indemnify,
 | 
				
			||||
      defend, and hold each Contributor harmless for any liability
 | 
				
			||||
      incurred by, or claims asserted against, such Contributor by reason
 | 
				
			||||
      of your accepting any such warranty or additional liability.
 | 
				
			||||
 | 
				
			||||
   END OF TERMS AND CONDITIONS
 | 
				
			||||
 | 
				
			||||
@ -1,22 +0,0 @@
 | 
				
			||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||
 | 
				
			||||
<!-- 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.
 | 
				
			||||
-->
 | 
				
			||||
 | 
				
			||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
 | 
				
			||||
  <item android:state_pressed="true" android:color="#88555555" />
 | 
				
			||||
  <item android:state_selected="true" android:color="#ff999999" />
 | 
				
			||||
  <item android:color="#ff000000" />
 | 
				
			||||
</selector>
 | 
				
			||||
@ -1,20 +0,0 @@
 | 
				
			||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||
 | 
				
			||||
<!-- 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.
 | 
				
			||||
-->
 | 
				
			||||
 | 
				
			||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
 | 
				
			||||
  <item android:color="#50000000" />
 | 
				
			||||
</selector>
 | 
				
			||||
| 
		 Before Width: | Height: | Size: 3.5 KiB  | 
| 
		 Before Width: | Height: | Size: 245 B  | 
| 
		 Before Width: | Height: | Size: 3.5 KiB  | 
| 
		 Before Width: | Height: | Size: 3.9 KiB  | 
| 
		 Before Width: | Height: | Size: 3.4 KiB  | 
| 
		 Before Width: | Height: | Size: 443 B  | 
| 
		 Before Width: | Height: | Size: 3.4 KiB  | 
| 
		 Before Width: | Height: | Size: 3.5 KiB  | 
| 
		 Before Width: | Height: | Size: 3.4 KiB  | 
| 
		 Before Width: | Height: | Size: 5.0 KiB  | 
| 
		 Before Width: | Height: | Size: 5.5 KiB  | 
| 
		 Before Width: | Height: | Size: 4.9 KiB  | 
| 
		 Before Width: | Height: | Size: 3.8 KiB  | 
| 
		 Before Width: | Height: | Size: 5.9 KiB  | 
| 
		 Before Width: | Height: | Size: 3.4 KiB  | 
| 
		 Before Width: | Height: | Size: 3.5 KiB  | 
| 
		 Before Width: | Height: | Size: 3.1 KiB  | 
| 
		 Before Width: | Height: | Size: 3.0 KiB  | 
| 
		 Before Width: | Height: | Size: 4.0 KiB  | 
| 
		 Before Width: | Height: | Size: 3.0 KiB  | 
| 
		 Before Width: | Height: | Size: 3.1 KiB  | 
| 
		 Before Width: | Height: | Size: 6.7 KiB  | 
| 
		 Before Width: | Height: | Size: 554 KiB  | 
| 
		 Before Width: | Height: | Size: 4.3 KiB  | 
| 
		 Before Width: | Height: | Size: 3.0 KiB  | 
| 
		 Before Width: | Height: | Size: 4.5 KiB  | 
| 
		 Before Width: | Height: | Size: 3.2 KiB  | 
| 
		 Before Width: | Height: | Size: 5.5 KiB  | 
| 
		 Before Width: | Height: | Size: 2.8 KiB  | 
| 
		 Before Width: | Height: | Size: 4.4 KiB  | 
| 
		 Before Width: | Height: | Size: 3.1 KiB  | 
| 
		 Before Width: | Height: | Size: 4.6 KiB  | 
| 
		 Before Width: | Height: | Size: 3.3 KiB  | 
| 
		 Before Width: | Height: | Size: 4.2 KiB  | 
| 
		 Before Width: | Height: | Size: 3.0 KiB  | 
| 
		 Before Width: | Height: | Size: 4.5 KiB  | 
| 
		 Before Width: | Height: | Size: 3.2 KiB  | 
| 
		 Before Width: | Height: | Size: 4.2 KiB  | 
| 
		 Before Width: | Height: | Size: 3.0 KiB  | 
| 
		 Before Width: | Height: | Size: 4.4 KiB  | 
| 
		 Before Width: | Height: | Size: 3.1 KiB  | 
| 
		 Before Width: | Height: | Size: 4.3 KiB  | 
| 
		 Before Width: | Height: | Size: 3.1 KiB  | 
| 
		 Before Width: | Height: | Size: 4.6 KiB  | 
| 
		 Before Width: | Height: | Size: 3.3 KiB  | 
| 
		 Before Width: | Height: | Size: 3.3 KiB  | 
| 
		 Before Width: | Height: | Size: 3.2 KiB  | 
| 
		 Before Width: | Height: | Size: 87 KiB  | 
| 
		 Before Width: | Height: | Size: 88 KiB  | 
| 
		 Before Width: | Height: | Size: 6.9 KiB  | 
| 
		 Before Width: | Height: | Size: 3.0 KiB  | 
| 
		 Before Width: | Height: | Size: 3.0 KiB  | 
| 
		 Before Width: | Height: | Size: 4.8 KiB  | 
| 
		 Before Width: | Height: | Size: 3.6 KiB  | 
| 
		 Before Width: | Height: | Size: 5.8 KiB  | 
| 
		 Before Width: | Height: | Size: 1.9 KiB  | 
| 
		 Before Width: | Height: | Size: 1.9 KiB  | 
| 
		 Before Width: | Height: | Size: 1.8 KiB  | 
| 
		 Before Width: | Height: | Size: 1.9 KiB  | 
| 
		 Before Width: | Height: | Size: 1.9 KiB  | 
| 
		 Before Width: | Height: | Size: 4.1 KiB  | 
| 
		 Before Width: | Height: | Size: 4.1 KiB  | 
| 
		 Before Width: | Height: | Size: 4.1 KiB  | 
| 
		 Before Width: | Height: | Size: 4.0 KiB  | 
| 
		 Before Width: | Height: | Size: 4.1 KiB  | 
@ -1,23 +0,0 @@
 | 
				
			||||
<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||
 | 
				
			||||
<!-- 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.
 | 
				
			||||
-->
 | 
				
			||||
 | 
				
			||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
 | 
				
			||||
    <item android:state_pressed="true"
 | 
				
			||||
        android:drawable="@drawable/new_note_pressed" />
 | 
				
			||||
    <item
 | 
				
			||||
        android:drawable="@drawable/new_note_normal" />
 | 
				
			||||
</selector>
 | 
				
			||||
@ -1,43 +0,0 @@
 | 
				
			||||
<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||
 | 
				
			||||
<!-- 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.
 | 
				
			||||
-->
 | 
				
			||||
 | 
				
			||||
<LinearLayout
 | 
				
			||||
        android:layout_width="fill_parent"
 | 
				
			||||
        android:layout_height="fill_parent"
 | 
				
			||||
        android:orientation="vertical"
 | 
				
			||||
        xmlns:android="http://schemas.android.com/apk/res/android">
 | 
				
			||||
 | 
				
			||||
    <TextView
 | 
				
			||||
        android:id="@+id/account_dialog_title"
 | 
				
			||||
        style="?android:attr/textAppearanceMedium"
 | 
				
			||||
        android:singleLine="true"
 | 
				
			||||
        android:ellipsize="end"
 | 
				
			||||
        android:gravity="center"
 | 
				
			||||
        android:layout_marginTop="-2.7dip"
 | 
				
			||||
        android:layout_marginBottom="-2.7dip"
 | 
				
			||||
        android:layout_width="fill_parent"
 | 
				
			||||
        android:layout_height="wrap_content"/>
 | 
				
			||||
 | 
				
			||||
    <TextView
 | 
				
			||||
        android:id="@+id/account_dialog_subtitle"
 | 
				
			||||
        android:layout_width="fill_parent"
 | 
				
			||||
        android:layout_height="wrap_content"
 | 
				
			||||
        android:layout_marginTop="5dip"
 | 
				
			||||
        android:layout_marginBottom="1dip"
 | 
				
			||||
        android:gravity="center"/>
 | 
				
			||||
 | 
				
			||||
</LinearLayout>
 | 
				
			||||
@ -1,32 +0,0 @@
 | 
				
			||||
<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||
 | 
				
			||||
<!-- 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.
 | 
				
			||||
-->
 | 
				
			||||
 | 
				
			||||
<LinearLayout
 | 
				
			||||
    xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||
    android:layout_width="match_parent"
 | 
				
			||||
    android:layout_height="wrap_content"
 | 
				
			||||
    android:minHeight="50dip"
 | 
				
			||||
    android:gravity="center_vertical"
 | 
				
			||||
    android:orientation="vertical">
 | 
				
			||||
 | 
				
			||||
    <TextView
 | 
				
			||||
        android:layout_width="wrap_content"
 | 
				
			||||
        android:layout_height="wrap_content"
 | 
				
			||||
        android:layout_gravity="center"
 | 
				
			||||
        android:textAppearance="?android:attr/textAppearanceMedium"
 | 
				
			||||
        android:text="@string/preferences_add_account" />
 | 
				
			||||
</LinearLayout>
 | 
				
			||||
@ -1,56 +0,0 @@
 | 
				
			||||
<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||
<!-- 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.
 | 
				
			||||
-->
 | 
				
			||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||
    android:orientation="horizontal"
 | 
				
			||||
    android:layout_gravity="center_horizontal"
 | 
				
			||||
    android:layout_width="wrap_content"
 | 
				
			||||
    android:layout_height="wrap_content">
 | 
				
			||||
 | 
				
			||||
    <NumberPicker
 | 
				
			||||
        android:id="@+id/date"
 | 
				
			||||
        android:layout_width="120dip"
 | 
				
			||||
        android:layout_height="wrap_content"
 | 
				
			||||
        android:focusable="true"
 | 
				
			||||
        android:focusableInTouchMode="true"
 | 
				
			||||
        />
 | 
				
			||||
 | 
				
			||||
    <NumberPicker
 | 
				
			||||
        android:id="@+id/hour"
 | 
				
			||||
        android:layout_width="50dip"
 | 
				
			||||
        android:layout_height="wrap_content"
 | 
				
			||||
        android:layout_marginLeft="5dip"
 | 
				
			||||
        android:focusable="true"
 | 
				
			||||
        android:focusableInTouchMode="true"
 | 
				
			||||
        />
 | 
				
			||||
 | 
				
			||||
    <NumberPicker
 | 
				
			||||
        android:id="@+id/minute"
 | 
				
			||||
        android:layout_width="50dip"
 | 
				
			||||
        android:layout_height="wrap_content"
 | 
				
			||||
        android:layout_marginLeft="5dip"
 | 
				
			||||
        android:focusable="true"
 | 
				
			||||
        android:focusableInTouchMode="true"
 | 
				
			||||
        />
 | 
				
			||||
 | 
				
			||||
    <NumberPicker
 | 
				
			||||
        android:id="@+id/amPm"
 | 
				
			||||
        android:layout_width="50dip"
 | 
				
			||||
        android:layout_height="wrap_content"
 | 
				
			||||
        android:layout_marginLeft="5dip"
 | 
				
			||||
        android:focusable="true"
 | 
				
			||||
        android:focusableInTouchMode="true"
 | 
				
			||||
        />
 | 
				
			||||
</LinearLayout>
 | 
				
			||||
@ -1,23 +0,0 @@
 | 
				
			||||
<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||
 | 
				
			||||
<!-- 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.
 | 
				
			||||
-->
 | 
				
			||||
 | 
				
			||||
<EditText
 | 
				
			||||
    xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||
    android:id="@+id/et_foler_name"
 | 
				
			||||
    android:layout_width="fill_parent"
 | 
				
			||||
    android:hint="@string/hint_foler_name"
 | 
				
			||||
    android:layout_height="fill_parent" />
 | 
				
			||||