package com.github.andlyticsproject.sync;
import android.accounts.Account;
import android.accounts.OperationCanceledException;
import android.app.Service;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.Context;
import android.content.Intent;
import android.content.SyncResult;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import com.github.andlyticsproject.AndlyticsApp;
import com.github.andlyticsproject.AppStatsDiff;
import com.github.andlyticsproject.ContentAdapter;
import com.github.andlyticsproject.DeveloperAccountManager;
import com.github.andlyticsproject.admob.AdmobException;
import com.github.andlyticsproject.adsense.AdSenseClient;
import com.github.andlyticsproject.console.DevConsoleException;
import com.github.andlyticsproject.console.v2.DevConsoleRegistry;
import com.github.andlyticsproject.console.v2.DevConsoleV2;
import com.github.andlyticsproject.db.AndlyticsDb;
import com.github.andlyticsproject.model.AppInfo;
import com.github.andlyticsproject.model.DeveloperAccount;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class SyncAdapterService extends Service {
private static final String TAG = SyncAdapterService.class.getSimpleName();
private static SyncAdapterImpl sSyncAdapter = null;
private static ContentAdapter db;
public SyncAdapterService() {
super();
}
private static class SyncAdapterImpl extends AbstractThreadedSyncAdapter {
private Context mContext;
public SyncAdapterImpl(Context context) {
super(context, true);
mContext = context;
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
// If the account is hidden and the user enables syncing for it via system
// then this could get called. Check account state and only sync
// if not hidden.
DeveloperAccount developerAccount = DeveloperAccountManager.getInstance(mContext)
.findDeveloperAccountByName(account.name);
if (developerAccount != null && developerAccount.isVisible()) {
try {
SyncAdapterService.performSync(mContext, account, extras, authority, provider,
syncResult);
} catch (OperationCanceledException e) {
Log.w(TAG, "operation canceled", e);
}
}
}
}
@Override
public IBinder onBind(Intent intent) {
IBinder ret = null;
ret = getSyncAdapter().getSyncAdapterBinder();
return ret;
}
private SyncAdapterImpl getSyncAdapter() {
if (sSyncAdapter == null)
sSyncAdapter = new SyncAdapterImpl(this);
return sSyncAdapter;
}
private static void performSync(Context context, Account account, Bundle extras,
String authority, ContentProviderClient provider, SyncResult syncResult)
throws OperationCanceledException {
try {
DevConsoleV2 console = DevConsoleRegistry.getInstance().get(account.name);
if (console != null) {
List<AppInfo> appDownloadInfos = console.getAppInfo(null);
// this can also happen if authentication fails and the user
// need to click on a notification to confirm or re-enter
// password (e.g., if password changed or 2FA enabled)
if (appDownloadInfos.isEmpty()) {
return;
}
Log.d(TAG, "andlytics from sync adapter, size: " + appDownloadInfos.size());
List<AppStatsDiff> diffs = new ArrayList<AppStatsDiff>();
Map<String, List<String>> admobAccountSiteMap = new HashMap<String, List<String>>();
db = ContentAdapter.getInstance(AndlyticsApp.getInstance());
for (AppInfo appDownloadInfo : appDownloadInfos) {
// update in database
diffs.add(db.insertOrUpdateStats(appDownloadInfo));
String[] admobDetails = AndlyticsDb.getInstance(context).getAdmobDetails(
appDownloadInfo.getPackageName());
if (admobDetails != null) {
String admobAccount = admobDetails[0];
String admobSiteId = admobDetails[1];
String adUnitId = admobDetails[2];
// only sync legacy data if not migrated
if (admobAccount != null && adUnitId == null) {
List<String> siteList = admobAccountSiteMap.get(admobAccount);
if (siteList == null) {
siteList = new ArrayList<String>();
}
siteList.add(admobSiteId);
admobAccountSiteMap.put(admobAccount, siteList);
} else {
List<String> siteList = admobAccountSiteMap.get(admobAccount);
if (siteList == null) {
siteList = new ArrayList<String>();
}
siteList.add(adUnitId);
admobAccountSiteMap.put(admobAccount, siteList);
}
}
// update app details
AndlyticsDb.getInstance(context).insertOrUpdateAppDetails(appDownloadInfo);
}
Log.d(TAG, "sucessfully synced andlytics");
// check for notifications
NotificationHandler.handleNotificaions(context, diffs, account.name);
if (!admobAccountSiteMap.isEmpty()) {
Log.d(TAG, "Syncing AdMob stats");
// sync admob accounts
Set<String> admobAccuntKeySet = admobAccountSiteMap.keySet();
for (String admobAccount : admobAccuntKeySet) {
AdSenseClient.backgroundSyncStats(context, admobAccount,
admobAccountSiteMap.get(admobAccount), extras, authority, null);
}
Log.d(TAG, "Sucessfully synced AdMob stats");
}
DeveloperAccountManager.getInstance(context).saveLastStatsRemoteUpdateTime(
account.name, System.currentTimeMillis());
}
} catch (DevConsoleException e) {
Log.e(TAG, "error during dev console stats sync", e);
} catch (AdmobException e) {
Log.e(TAG, "error during Admob sync", e);
} catch (Exception e) {
Log.e(TAG, "error during sync", e);
}
}
}