Java tutorial
/* * Copyright (C) 2014 yvolk (Yuri Volkov), http://yurivolkov.com * * 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 org.andstatus.app.account; import android.accounts.Account; import android.accounts.AccountManager; import android.content.ContentResolver; import android.content.PeriodicSync; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import org.andstatus.app.account.MyAccount.Builder.SaveResult; import org.andstatus.app.context.MyContext; import org.andstatus.app.context.MyPreferences; import org.andstatus.app.data.MyProvider; import org.andstatus.app.util.MyLog; import org.andstatus.app.util.SharedPreferencesUtil; import org.json.JSONException; import org.json.JSONObject; import java.util.List; public class AccountData implements Parcelable, AccountDataWriter { private static final String TAG = AccountData.class.getSimpleName(); /** * The Key for the android.accounts.Account bundle; */ public static final String KEY_ACCOUNT = "account"; private final JSONObject data; private boolean persistent = false; boolean isPersistent() { return persistent; } void setPersistent(boolean persistent) { this.persistent = persistent; } public static AccountData fromAndroidAccount(MyContext myContext, Account androidAccount) { if (androidAccount == null) { throw new IllegalArgumentException(TAG + " account is null"); } android.accounts.AccountManager am = AccountManager.get(myContext.context()); AccountData accountData = fromJsonString(am.getUserData(androidAccount, KEY_ACCOUNT), true); accountData.setDataBoolean(MyAccount.KEY_IS_SYNCABLE, ContentResolver.getIsSyncable(androidAccount, MyProvider.AUTHORITY) != 0); accountData.setDataBoolean(MyAccount.KEY_SYNC_AUTOMATICALLY, ContentResolver.getSyncAutomatically(androidAccount, MyProvider.AUTHORITY)); accountData.setDataLong(MyPreferences.KEY_SYNC_FREQUENCY_SECONDS, getSyncFrequencySeconds(androidAccount)); return accountData; } private static long getSyncFrequencySeconds(Account account) { long syncFrequencySeconds = 0; List<PeriodicSync> syncs = ContentResolver.getPeriodicSyncs(account, MyProvider.AUTHORITY); if (!syncs.isEmpty()) { syncFrequencySeconds = syncs.get(0).period; } return syncFrequencySeconds; } public static AccountData fromJsonString(String userData, boolean persistent) { JSONObject jso = null; try { if (userData != null) { jso = new JSONObject(userData); } } catch (JSONException e) { MyLog.e(TAG, "fromJsonString", e); } return fromJson(jso, persistent); } public static AccountData fromJson(JSONObject jso, boolean persistent) { return new AccountData(jso, persistent); } private AccountData(JSONObject jso, boolean persistent) { if (jso == null) { data = new JSONObject(); } else { data = jso; this.persistent = persistent; } } /** * @param result * @return true if Android account changed */ void saveDataToAccount(MyContext myContext, Account androidAccount, SaveResult result) { AccountData oldData = fromAndroidAccount(myContext, androidAccount); result.changed = !this.equals(oldData); if (result.changed) { long syncFrequencySeconds = getDataLong(MyPreferences.KEY_SYNC_FREQUENCY_SECONDS, 0); if (syncFrequencySeconds > 0 && syncFrequencySeconds != getSyncFrequencySeconds(androidAccount)) { result.changed = true; setSyncFrequencySeconds(androidAccount, syncFrequencySeconds); } boolean isSyncable = getDataBoolean(MyAccount.KEY_IS_SYNCABLE, true); if (isSyncable != (ContentResolver.getIsSyncable(androidAccount, MyProvider.AUTHORITY) != 0)) { ContentResolver.setIsSyncable(androidAccount, MyProvider.AUTHORITY, isSyncable ? 1 : 0); } boolean syncAutomatically = getDataBoolean(MyAccount.KEY_SYNC_AUTOMATICALLY, true); if (syncAutomatically != ContentResolver.getSyncAutomatically(androidAccount, MyProvider.AUTHORITY)) { // We need to preserve sync on/off during backup/restore. // don't know about "network tickles"... See: // http://stackoverflow.com/questions/5013254/what-is-a-network-tickle-and-how-to-i-go-about-sending-one ContentResolver.setSyncAutomatically(androidAccount, MyProvider.AUTHORITY, syncAutomatically); } android.accounts.AccountManager am = AccountManager.get(myContext.context()); am.setUserData(androidAccount, KEY_ACCOUNT, toJsonString()); result.savedToAccountManager = true; } result.success = true; } @Override public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof AccountData)) { return false; } final AccountData other = (AccountData) o; return hashCode() == other.hashCode(); } @Override public int hashCode() { String text = Boolean.toString(isPersistent()); text += toJsonString(); return text.hashCode(); } private void setSyncFrequencySeconds(Account androidAccount, long syncFrequencySeconds) { // See // http://developer.android.com/reference/android/content/ContentResolver.html#addPeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle, long) // and // http://stackoverflow.com/questions/11090604/android-syncadapter-automatically-initialize-syncing ContentResolver.removePeriodicSync(androidAccount, MyProvider.AUTHORITY, new Bundle()); if (syncFrequencySeconds > 0) { ContentResolver.addPeriodicSync(androidAccount, MyProvider.AUTHORITY, new Bundle(), syncFrequencySeconds); } } @Override public boolean dataContains(String key) { boolean contains = false; try { String str = getDataString(key, "null"); if (str.compareTo("null") != 0) { contains = true; } } catch (Exception e) { MyLog.v(this, e); } return contains; } boolean getDataBoolean(String key, boolean defValue) { boolean value = defValue; try { String str = getDataString(key, "null"); if (str.compareTo("null") != 0) { value = SharedPreferencesUtil.isTrue(str); } } catch (Exception e) { MyLog.v(this, e); } return value; } @Override public String getDataString(String key, String defValue) { return data.optString(key, defValue); } @Override public int getDataInt(String key, int defValue) { int value = defValue; try { String str = getDataString(key, "null"); if (str.compareTo("null") != 0) { value = Integer.parseInt(str); } } catch (Exception e) { MyLog.v(this, e); } return value; } long getDataLong(String key, long defValue) { long value = defValue; try { String str = getDataString(key, "null"); if (str.compareTo("null") != 0) { value = Long.parseLong(str); } } catch (Exception e) { MyLog.v(this, e); } return value; } public void setDataBoolean(String key, boolean value) { try { setDataString(key, Boolean.toString(value)); } catch (Exception e) { MyLog.v(this, e); } } @Override public void setDataLong(String key, long value) { try { setDataString(key, Long.toString(value)); } catch (Exception e) { MyLog.v(this, e); } } @Override public void setDataInt(String key, int value) { try { setDataString(key, Integer.toString(value)); } catch (Exception e) { MyLog.v(this, e); } } @Override public void setDataString(String key, String value) { try { if (TextUtils.isEmpty(value)) { data.remove(key); } else { data.put(key, value); } } catch (Exception e) { MyLog.v(this, e); } } public static final Creator<AccountData> CREATOR = new Creator<AccountData>() { @Override public AccountData createFromParcel(Parcel source) { return AccountData.fromBundle(source.readBundle()); } @Override public AccountData[] newArray(int size) { return new AccountData[size]; } }; static AccountData fromBundle(Bundle bundle) { String jsonString = ""; if (bundle != null) { jsonString = bundle.getString(KEY_ACCOUNT); } return fromJsonString(jsonString, false); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(toJsonString()); } public String toJsonString() { try { return data.toString(2); } catch (JSONException e) { MyLog.e(this, e); return ""; } } }