package com.yemyatthu.moelaywatha.sync; import android.accounts.Account; import android.accounts.AccountManager; import android.content.AbstractThreadedSyncAdapter; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SyncRequest; import android.content.SyncResult; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.squareup.okhttp.OkHttpClient; import com.yemyatthu.moelaywatha.Config; import com.yemyatthu.moelaywatha.R; import com.yemyatthu.moelaywatha.model.Weather; import com.yemyatthu.moelaywatha.model.WeatherCode; import com.yemyatthu.moelaywatha.retrofitservice.WeatherRetrofitService; import io.realm.Realm; import io.realm.RealmList; import java.util.Calendar; import retrofit.RestAdapter; import retrofit.client.OkClient; import timber.log.Timber; /** * Created by yemyatthu on 3/27/15. */ public class WeatherSyncAdapter extends AbstractThreadedSyncAdapter{ // Constants // Content provider authority public static final String AUTHORITY = "com.yemyatthu.moelaywatha.provider"; // Account public static final String ACCOUNT = "thu.yemyat@gmail.com"; public static final String SYNC_FINISHED = "sync finished"; // Sync interval constants public static final int SECONDS_PER_MINUTE = 60; public static final int SYNC_INTERVAL_IN_MINUTES = 120; public static final int SYNC_INTERVAL = SYNC_INTERVAL_IN_MINUTES * SECONDS_PER_MINUTE; public static final int SYNC_FLEXTIME = SYNC_INTERVAL/2; ContentResolver mContentResolver; private RestAdapter weatherRestAdapter; private WeatherRetrofitService mWeatherRetrofitService; private SharedPreferences mSharedPreferences; private Realm mRealm; public WeatherSyncAdapter(Context context, boolean autoInitialize) { super(context, autoInitialize); mContentResolver = context.getContentResolver(); weatherRestAdapter = new RestAdapter.Builder().setClient(new OkClient(new OkHttpClient())) .setEndpoint("http://api.openweathermap.org") .build(); mWeatherRetrofitService = weatherRestAdapter.create(WeatherRetrofitService.class); mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext()); mRealm = Realm.getInstance(context.getApplicationContext()); } public WeatherSyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) { super(context, autoInitialize, allowParallelSyncs); mContentResolver = context.getContentResolver(); weatherRestAdapter = new RestAdapter.Builder().setClient(new OkClient(new OkHttpClient())) .setEndpoint("http://api.openweathermap.org") .build(); mWeatherRetrofitService = weatherRestAdapter.create(WeatherRetrofitService.class); mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext()); } public static Account getSyncAccount(Context context) { // Get an instance of the Android account manager AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); // Create the account type and default account Account newAccount = new Account(context.getString(R.string.app_name), context.getString(R.string.account_type)); // If the password doesn't exist, the account doesn't exist if (null == accountManager.getPassword(newAccount)) { /* * Add the account and account type, no password or user data * If successful, return the Account object, otherwise report an error. */ if (!accountManager.addAccountExplicitly(newAccount, "", null)) { return null; } /* * If you don't set android:syncable="true" in * in your <provider> element in the manifest, * then call ContentResolver.setIsSyncable(account, AUTHORITY, 1) * here. */ onAccountCreated(newAccount, context); } return newAccount; } private static void onAccountCreated(Account newAccount, Context context) { /* * Since we've created an account */ WeatherSyncAdapter.configurePeriodicSync(context, SYNC_INTERVAL, SYNC_FLEXTIME); /* * Without calling setSyncAutomatically, our periodic sync will not be enabled. */ ContentResolver.setSyncAutomatically(newAccount, context.getString(R.string.account_authorities), true); /* * Finally, let's do a sync to get things started */ syncImmediately(context); } public static void initializeSyncAdapter(Context context) { getSyncAccount(context); } /** * Helper method to have the sync adapter sync immediately * * @param context The context used to access the account service */ public static void syncImmediately(Context context) { Bundle bundle = new Bundle(); bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); ContentResolver.requestSync(getSyncAccount(context), context.getString(R.string.account_authorities), bundle); Timber.d("syncing"); } /** * Helper method to schedule the sync adapter periodic execution */ public static void configurePeriodicSync(Context context, int syncInterval, int flexTime) { Account account = getSyncAccount(context); String authority = context.getString(R.string.account_authorities); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // we can enable inexact timers in our periodic sync SyncRequest.Builder builder = new SyncRequest.Builder(); Bundle extras = new Bundle(); builder.setExtras(extras); SyncRequest request = builder. syncPeriodic(syncInterval, flexTime). setSyncAdapter(account, authority).build(); ContentResolver.requestSync(request); } else { ContentResolver.addPeriodicSync(account, authority, new Bundle(), syncInterval); } } @Override public void onPerformSync(Account account, Bundle bundle, String s, ContentProviderClient contentProviderClient, SyncResult syncResult) { final JsonObject jsonObject = mWeatherRetrofitService.getWeatherData(mSharedPreferences.getFloat( Config.LAST_LATITUDE, (float) 16.8),mSharedPreferences.getFloat(Config.LAST_LONGITUDE, (float) 96.15)); if(jsonObject!=null){ mRealm = Realm.getInstance(getContext().getApplicationContext()); final RealmList<WeatherCode> weatherCodes = new RealmList<>(); mRealm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { for(JsonElement element: jsonObject.get("weather").getAsJsonArray()){ WeatherCode weatherCode = realm.createObject(WeatherCode.class); weatherCode.setWeatherCode(element.getAsJsonObject().get("id").getAsInt()); weatherCodes.add(weatherCode); } } }); final Calendar calendar = Calendar.getInstance(); mRealm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Weather weather = mRealm.createObject(Weather.class); weather.setMaxTemp(jsonObject.get("main").getAsJsonObject().get("temp_max").getAsFloat()); weather.setMinTemp(jsonObject.get("main").getAsJsonObject().get("temp_min").getAsFloat()); weather.setDate(calendar.get(Calendar.DATE)); weather.setWeatherCode(weatherCodes); weather.setLastUpdatedTime(String.valueOf(calendar.get(Calendar.HOUR_OF_DAY)+":"+calendar.get(Calendar.MINUTE))); weather.setCity(jsonObject.get("name").getAsString()); } }); getContext().sendBroadcast(new Intent(SYNC_FINISHED)); } } }