/**
* galaxy inc.
* meetup client for android
*/
package com.galaxy.meetup.client.android.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorException;
import android.app.Service;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SyncResult;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import com.galaxy.meetup.client.android.analytics.AnalyticsInfo;
import com.galaxy.meetup.client.android.analytics.EsAnalytics;
import com.galaxy.meetup.client.android.analytics.OzActions;
import com.galaxy.meetup.client.android.analytics.OzViews;
import com.galaxy.meetup.client.android.content.EsAccount;
import com.galaxy.meetup.client.android.content.EsAccountsData;
import com.galaxy.meetup.client.android.iu.InstantUploadSyncService;
import com.galaxy.meetup.client.android.network.http.HttpOperation;
import com.galaxy.meetup.client.android.network.http.HttpTransactionMetrics;
import com.galaxy.meetup.client.util.AccountsUtil;
import com.galaxy.meetup.client.util.EsLog;
/**
* @author sihai
*/
public class EsSyncAdapterService extends Service {
private static SyncState sCurrentSyncState;
private static SyncAdapterImpl sSyncAdapter = null;
private static final Object sSyncAdapterLock = new Object();
private static Map sSyncStates = new HashMap();
public EsSyncAdapterService() {
}
public void onCreate() {
synchronized (sSyncAdapterLock) {
if (sSyncAdapter == null)
sSyncAdapter = new SyncAdapterImpl(getApplicationContext());
}
}
@Override
public IBinder onBind(Intent arg0) {
return sSyncAdapter.getSyncAdapterBinder();
}
public static void activateAccount(Context context, String s) {
Account account = AccountsUtil.newAccount(s);
ContentResolver.setIsSyncable(account, "com.galaxy.meetup.client.android.content.EsProvider", 1);
ContentResolver.setSyncAutomatically(account, "com.galaxy.meetup.client.android.content.EsProvider", true);
ContentResolver.requestSync(account, "com.galaxy.meetup.client.android.content.EsProvider", new Bundle());
resetSyncStates(context, s);
}
public static void deactivateAccount(String s) {
Account account = AccountsUtil.newAccount(s);
ContentResolver.setIsSyncable(account, "com.galaxy.meetup.client.android.content.EsProvider", 0);
ContentResolver.cancelSync(account, "com.galaxy.meetup.client.android.content.EsProvider");
SyncState syncstate = (SyncState) sSyncStates.get(s);
if (syncstate != null)
syncstate.cancel();
}
public static SyncState getAccountSyncState(String s) {
SyncState syncstate;
synchronized (sSyncStates) {
syncstate = (SyncState) sSyncStates.get(s);
if (syncstate == null) {
syncstate = new SyncState();
sSyncStates.put(s, syncstate);
}
}
return syncstate;
}
private static void resetSyncStates(Context context, String s) {
Iterator iterator = AccountsUtil.getAccounts(context).iterator();
do {
if (!iterator.hasNext())
break;
Account account = (Account) iterator.next();
if (!TextUtils.equals(s, account.name))
deactivateAccount(account.name);
} while (true);
}
// ===========================================================================
// Inner class
// ===========================================================================
public static final class SyncOperationState {
public int count;
public long duration;
public HttpTransactionMetrics metrics;
public String operation;
public int subCount;
public SyncOperationState() {
}
}
public static class SyncState {
private boolean mCanceled;
private int mCurrentCount;
private HttpTransactionMetrics mCurrentMetrics;
private String mCurrentOperation;
private long mCurrentOperationStart;
private int mCurrentSubCount;
private boolean mFullSync;
private final ArrayList<SyncOperationState> mOperations = new ArrayList<SyncOperationState>();
private final LinkedBlockingQueue<Bundle> mRequestQueue = new LinkedBlockingQueue<Bundle>();
private long mStartTimestamp;
private String mSyncName;
public SyncState() {
}
public final synchronized void onStart(String operation) {
mCurrentOperation = operation;
mCurrentOperationStart = System.currentTimeMillis();
mCurrentCount = 0;
mCurrentSubCount = 0;
mCurrentMetrics = new HttpTransactionMetrics();
}
public final synchronized void onSyncStart(String syncName) {
if (EsLog.isLoggable("EsSyncAdapterService", 4))
Log.i("EsSyncAdapterService", (new StringBuilder()).append(syncName).append(" started.").toString());
mSyncName = syncName;
mCanceled = false;
mStartTimestamp = System.currentTimeMillis();
mOperations.clear();
}
public final synchronized void onFinish() {
onFinish(mCurrentCount, mCurrentSubCount);
}
public final synchronized void onFinish(int i) {
onFinish(i, 0);
}
private synchronized void onFinish(int count, int subCount) {
SyncOperationState syncoperationstate = new SyncOperationState();
syncoperationstate.operation = mCurrentOperation;
syncoperationstate.duration = System.currentTimeMillis() - mCurrentOperationStart;
syncoperationstate.count = count;
syncoperationstate.subCount = subCount;
syncoperationstate.metrics = mCurrentMetrics;
mCurrentMetrics = null;
mOperations.add(syncoperationstate);
}
public final synchronized void onSyncFinish()
{
logSyncStats(this);
}
public final synchronized void cancel() {
mCanceled = true;
}
public final synchronized boolean isCanceled() {
return mCanceled;
}
public final HttpTransactionMetrics getHttpTransactionMetrics() {
return mCurrentMetrics;
}
public final synchronized void incrementCount() {
mCurrentCount += 1;
}
public final synchronized void incrementCount(int count) {
mCurrentCount += count;
}
public final synchronized void incrementSubCount() {
mCurrentSubCount += 1;
}
public final Bundle pollAccountSyncRequest() {
return mRequestQueue.poll();
}
public final synchronized boolean requestAccountSync(Bundle bundle) {
boolean flag;
flag = mRequestQueue.isEmpty();
if (bundle == null)
bundle = new Bundle();
mRequestQueue.offer(bundle);
return flag;
}
public final void setFullSync(boolean flag) {
mFullSync = flag;
}
private static synchronized void logSyncStats(SyncState syncstate) {
// TODO
}
}
private class SyncListener implements HttpOperation.OperationListener {
private final SyncResult mSyncResult;
public final void onOperationComplete(HttpOperation httpoperation) {
int code = httpoperation.getErrorCode();
Exception exception = httpoperation.getException();
if (EsLog.isLoggable("EsSyncAdapterService", 3))
Log.d("EsSyncAdapterService", (new StringBuilder("Sync operation complete: ")).append(code).append('/')
.append(httpoperation.getReasonPhrase()).append('/').append(exception).toString());
if (null == exception) {
if (code == 401) {
mSyncResult.stats.numAuthExceptions += 1;
} else if (httpoperation.hasError()) {
mSyncResult.stats.numIoExceptions += 1L;
}
return;
} else if (exception instanceof AuthenticatorException) {
mSyncResult.stats.numAuthExceptions += 1;
} else {
mSyncResult.stats.numIoExceptions += 1;
}
}
public SyncListener(SyncResult syncresult) {
mSyncResult = syncresult;
}
}
private static final class SyncAdapterImpl extends AbstractThreadedSyncAdapter {
private final Context context;
public SyncAdapterImpl(Context context) {
super(context, false);
this.context = context;
}
private boolean isSubscribed(Account account, String s, String s1) {
String as[] = new String[5];
as[0] = "com.galaxy.meetup.client.android.content.EsProvider";
as[1] = s;
as[2] = account.name;
as[3] = account.type;
as[4] = s1;
Cursor cursor = null;
try {
cursor = getContext().getContentResolver().query(SubscribedFeeds.Feeds.CONTENT_URI,
new String[] { "_id" },
"authority = ? AND feed = ? AND _sync_account = ? AND _sync_account_type = ? AND service = ?",
as, null);
if (null == cursor) {
return false;
}
return cursor.moveToFirst();
} finally {
if (null != cursor) {
cursor.close();
}
}
}
private void subscribe(Account account, String s, String s1) {
if (EsLog.isLoggable("EsSyncAdapterService", 3))
Log.d("EsSyncAdapterService", " --> Subscribe all feeds");
ContentResolver contentresolver = getContext().getContentResolver();
ContentValues contentvalues = new ContentValues();
contentvalues.put("feed", s);
contentvalues.put("_sync_account", account.name);
contentvalues.put("_sync_account_type", account.type);
contentvalues.put("authority", "com.galaxy.meetup.client.android.content.EsProvider");
contentvalues.put("service", s1);
contentresolver.insert(SubscribedFeeds.Feeds.CONTENT_URI, contentvalues);
}
private void updateSubscribedFeeds(Account account) {
boolean flag;
if (ContentResolver.getMasterSyncAutomatically()
&& ContentResolver.getSyncAutomatically(account,
"com.galaxy.meetup.client.android.content.EsProvider"))
flag = true;
else
flag = false;
if (flag) {
boolean flag1 = true;
if (!isSubscribed(account,
"https://m.google.com/app/feed/notifications?authority=com.google.plus.notifications",
"webupdates")) {
subscribe(account,
"https://m.google.com/app/feed/notifications?authority=com.google.plus.notifications",
"webupdates");
flag1 = false;
}
if (!isSubscribed(account, "com.google.plus.events", "events")) {
subscribe(account, "com.google.plus.events", "events");
flag1 = false;
}
if (flag1) {
if (EsLog.isLoggable("EsSyncAdapterService", 3))
Log.d("EsSyncAdapterService", " --> Already subscribed");
String as1[] = new String[3];
as1[0] = "com.google.plus.notifications";
as1[1] = "https://m.google.com/app/feed/notifications?authority=com.google.plus.notifications";
as1[2] = account.type;
getContext().getContentResolver().delete(SubscribedFeeds.Feeds.CONTENT_URI,
"authority = ? AND feed = ? AND _sync_account_type = ?", as1);
}
} else {
if (EsLog.isLoggable("EsSyncAdapterService", 3))
Log.d("EsSyncAdapterService", " --> Unsubscribe all feeds");
ContentResolver contentresolver = getContext().getContentResolver();
StringBuilder stringbuilder = new StringBuilder();
stringbuilder.append("_sync_account=?");
stringbuilder.append(" AND _sync_account_type=?");
stringbuilder.append(" AND authority=?");
android.net.Uri uri = SubscribedFeeds.Feeds.CONTENT_URI;
String s = stringbuilder.toString();
String as[] = new String[3];
as[0] = account.name;
as[1] = account.type;
as[2] = "com.galaxy.meetup.client.android.content.EsProvider";
contentresolver.delete(uri, s, as);
}
}
public final void onPerformSync(Account account, final Bundle bundle, String s, ContentProviderClient contentproviderclient, SyncResult syncresult)
{
boolean flag;
EsAccount theAccount = EsAccountsData.getActiveAccount(context);
boolean flag1;
Account account2;
if(theAccount != null && account.name.equals(theAccount.getName()))
flag = true;
else
flag = false;
if(bundle != null && bundle.getBoolean("initialize", false))
flag1 = true;
else
flag1 = false;
if(flag1) {
account2 = AccountsUtil.newAccount(account.name);
int k;
if(flag)
k = 1;
else
k = 0;
ContentResolver.setIsSyncable(account2, "com.galaxy.meetup.client.android.content.EsProvider", k);
updateSubscribedFeeds(account);
}
String s1;
Context context1 = context;
SharedPreferences sharedpreferences = context1.getSharedPreferences("sync", 0);
if(!sharedpreferences.getBoolean("adapters_reset", false))
{
Account aaccount[] = AccountManager.get(context1).getAccountsByType(AccountsUtil.ACCOUNT_TYPE);
if(aaccount != null)
{
int i = aaccount.length;
int j = 0;
while(j < i)
{
Account account1 = aaccount[j];
boolean flag3;
if(ContentResolver.getIsSyncable(account1, "com.galaxy.meetup.client.android.content.EsProvider") == 1)
flag3 = true;
else
flag3 = false;
if(!flag3)
InstantUploadSyncService.deactivateAccount(context1, account1.name);
j++;
}
}
sharedpreferences.edit().putBoolean("adapters_reset", true).commit();
}
updateSubscribedFeeds(account);
if(!flag)
{
EsAccount esaccount = EsAccountsData.getActiveAccountUnsafe(context);
if(esaccount == null || !EsAccountsData.isAccountUpgradeRequired(context, esaccount))
return;
boolean flag2;
try
{
EsAccountsData.upgradeAccount(context, esaccount);
}
catch(Exception exception1)
{
Log.e("EsSyncAdapterService", "Failed to upgrade account", exception1);
return;
}
theAccount = EsAccountsData.getActiveAccount(context);
if(theAccount != null && account.name.equals(theAccount.getName()))
flag2 = true;
else
flag2 = false;
if(!flag2)
return;
}
if(null != bundle && bundle.containsKey("feed")) {
s1 = bundle.getString("feed");
if(EsLog.isLoggable("EsSyncAdapterService", 3))
Log.d("EsSyncAdapterService", (new StringBuilder(" --> Sync specific feed: ")).append(s1).toString());
bundle.putBoolean("sync_from_tickle", true);
if(!"https://m.google.com/app/feed/notifications?authority=com.google.plus.notifications".equals(s1)) {
if("com.google.plus.events".equals(s1)) {
bundle.putInt("sync_what", 2);
EsAnalytics.postRecordEvent(context, theAccount, new AnalyticsInfo(OzViews.NOTIFICATIONS_SYSTEM), OzActions.TICKLE_EVENT_RECEIVED, null);
} else {
Log.e("EsSyncAdapterService", (new StringBuilder("Unexpected feed: ")).append(s1).toString());
return;
}
} else {
bundle.putInt("sync_what", 1);
EsAnalytics.postRecordEvent(context, theAccount, new AnalyticsInfo(OzViews.NOTIFICATIONS_SYSTEM), OzActions.TICKLE_NOTIFICATION_RECEIVED, null);
}
}
EsSyncAdapterService.sCurrentSyncState = EsSyncAdapterService.getAccountSyncState(account.name);
EsSyncAdapterService.access$100(context, theAccount, bundle, EsSyncAdapterService.sCurrentSyncState, syncresult);
final EsAccount account3 = theAccount;
if(!EsSyncAdapterService.sCurrentSyncState.isCanceled())
(new Handler(Looper.getMainLooper())).post(new Runnable() {
public final void run()
{
Context context = SyncAdapterImpl.this.context;
String s;
if(bundle != null)
s = bundle.getString("sync_tag");
else
s = null;
EsService.syncComplete(context, account3, s);
}
});
EsSyncAdapterService.sCurrentSyncState = null;
}
public final void onSyncCanceled() {
if (EsSyncAdapterService.sCurrentSyncState != null)
EsSyncAdapterService.sCurrentSyncState.cancel();
}
}
static void access$100(Context context, EsAccount esaccount, Bundle bundle, SyncState syncstate, SyncResult syncresult)
{
if(!syncstate.requestAccountSync(bundle)) {
return;
}
// TODO
}
}