Android Open Source - RecipeBook Sync Adapter






From Project

Back to project page RecipeBook.

License

The source code is released under:

Copyright (c) 2013, Ian Lake All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Red...

If you think the Android project RecipeBook listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.ianhanniballake.recipebook.sync;
/*from  w  ww.  jav  a2 s .  co m*/
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;

import android.accounts.Account;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SyncResult;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;

import com.google.android.gms.auth.GoogleAuthException;
import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.auth.UserRecoverableNotifiedException;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.Drive.Changes;
import com.google.api.services.drive.model.Change;
import com.google.api.services.drive.model.ChangeList;
import com.google.api.services.drive.model.File;
import com.ianhanniballake.recipebook.BuildConfig;
import com.ianhanniballake.recipebook.provider.RecipeContract;

/**
 * Google Drive Sync Adapter
 */
public class SyncAdapter extends AbstractThreadedSyncAdapter
{
  private final static String APP_NAME = "RecipeBook";
  private final static String APPDATA_DEFAULT_ID = "appdata";
  /**
   * Scope for Drive AppData access
   */
  public final static String DRIVE_APPDATA = "https://www.googleapis.com/auth/drive.appdata";
  private final static String FOLDER_MIME_TYPE = "application/vnd.google-apps.folder";
  private final static String PREF_DRIVE_APPDATA_ID = "com.ianhanniballake.recipebook.DRIVE_APPDATA_ID";
  private final static String PREF_DRIVE_START_CHANGE_ID = "com.ianhanniballake.recipebook.DRIVE_START_CHANGE_ID";

  private static Drive getDriveFromAccount(final Context context, final Account account)
  {
    String accessToken = "";
    try
    {
      accessToken = GoogleAuthUtil.getTokenWithNotification(context, account.name, "oauth2:" + DRIVE_APPDATA,
          null, RecipeContract.AUTHORITY, null);
    } catch (final UserRecoverableNotifiedException e)
    {
      Log.w(SyncAdapter.class.getSimpleName(), "User recoverable error getting token", e);
      return null;
    } catch (final IOException e)
    {
      Log.e(SyncAdapter.class.getSimpleName(), "Error getting token", e);
      return null;
    } catch (final GoogleAuthException e)
    {
      Log.e(SyncAdapter.class.getSimpleName(), "Error getting token", e);
      // Disable syncing until the user relogs in
      ContentResolver.setIsSyncable(account, RecipeContract.AUTHORITY, 0);
      return null;
    }
    if (BuildConfig.DEBUG)
      Log.d(SyncAdapter.class.getSimpleName(), "Token: " + accessToken);
    final GoogleCredential credential = new GoogleCredential();
    credential.setAccessToken(accessToken);
    return new Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(), credential)
        .setApplicationName(APP_NAME).build();
  }

  /**
   * Create a new SyncAdapter
   * 
   * @param context
   *            Context to use
   * @param autoInitialize
   *            Whether this service should be auto initialized
   */
  public SyncAdapter(final Context context, final boolean autoInitialize)
  {
    super(context, autoInitialize);
  }

  @Override
  public void onPerformSync(final Account account, final Bundle extras, final String authority,
      final ContentProviderClient provider, final SyncResult syncResult)
  {
    if (BuildConfig.DEBUG)
      Log.d(SyncAdapter.class.getSimpleName(), "onPerformSync");
    final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
    final Drive driveService = getDriveFromAccount(getContext(), account);
    if (driveService == null)
      return;
    String appDataFolderId = sharedPreferences.getString(PREF_DRIVE_APPDATA_ID + "_" + account.name,
        APPDATA_DEFAULT_ID);
    if (APPDATA_DEFAULT_ID.equals(appDataFolderId))
      try
      {
        final File file = driveService.files().get(APPDATA_DEFAULT_ID).execute();
        appDataFolderId = file.getId();
        sharedPreferences.edit().putString(PREF_DRIVE_APPDATA_ID + "_" + account.name, appDataFolderId)
            .commit();
      } catch (final IOException e)
      {
        Log.e(SyncAdapter.class.getSimpleName(), "Error getting appdata folder", e);
        syncResult.stats.numIoExceptions++;
      }
    final Long startChangeId = sharedPreferences.getLong(PREF_DRIVE_START_CHANGE_ID + "_" + account.name, 0L);
    final List<Change> changeList = new ArrayList<Change>();
    Long newChangeId = -1L;
    try
    {
      final Changes.List request = driveService.changes().list();
      if (startChangeId != null && startChangeId > 0L)
        request.setStartChangeId(startChangeId);
      do
      {
        final ChangeList changes = request.execute();
        newChangeId = Math.max(newChangeId, changes.getLargestChangeId());
        changeList.addAll(changes.getItems());
        request.setPageToken(changes.getNextPageToken());
      } while (request.getPageToken() != null && request.getPageToken().length() > 0);
      final TreeSet<String> deletedFileIds = new TreeSet<String>();
      final List<File> remoteChanges = new ArrayList<File>();
      if (BuildConfig.DEBUG)
        Log.d(SyncAdapter.class.getSimpleName(), "Found " + changeList.size() + " change"
            + (changeList.size() != 1 ? "s" : "") + " on Drive");
      for (final Change change : changeList)
        if (change.getDeleted())
          deletedFileIds.add(change.getFileId());
        else
        {
          final File changedFile = change.getFile();
          if (BuildConfig.DEBUG)
            Log.d(SyncAdapter.class.getSimpleName(), "Change of file named " + changedFile.getTitle());
          final boolean isFolder = FOLDER_MIME_TYPE.equals(changedFile.getMimeType());
          if (changedFile.getAppDataContents() && !isFolder)
          {
            remoteChanges.add(changedFile);
            if (BuildConfig.DEBUG)
              Log.d(SyncAdapter.class.getSimpleName(), "File " + changedFile.getTitle()
                  + " changed in AppData folder");
          }
        }
      Log.d(SyncAdapter.class.getSimpleName(), "Found " + deletedFileIds.size() + " deleted change"
          + (deletedFileIds.size() != 1 ? "s" : ""));
    } catch (final IOException e)
    {
      Log.e(SyncAdapter.class.getSimpleName(), "Error getting changes", e);
      syncResult.stats.numIoExceptions++;
    }
  }
}




Java Source Code List

com.ianhanniballake.recipebook.auth.AuthorizedActivity.java
com.ianhanniballake.recipebook.auth.SyncDriveAsyncTask.java
com.ianhanniballake.recipebook.model.Ingredient.java
com.ianhanniballake.recipebook.model.Instruction.java
com.ianhanniballake.recipebook.model.Recipe.java
com.ianhanniballake.recipebook.provider.RecipeContract.java
com.ianhanniballake.recipebook.provider.RecipeProvider.java
com.ianhanniballake.recipebook.sync.SyncAdapter.java
com.ianhanniballake.recipebook.sync.SyncService.java
com.ianhanniballake.recipebook.ui.RecipeDetailActivity.java
com.ianhanniballake.recipebook.ui.RecipeDetailIngredientFragment.java
com.ianhanniballake.recipebook.ui.RecipeDetailInstructionFragment.java
com.ianhanniballake.recipebook.ui.RecipeDetailSummaryFragment.java
com.ianhanniballake.recipebook.ui.RecipeEditActivity.java
com.ianhanniballake.recipebook.ui.RecipeListActivity.java