Android Open Source - notes Notes Dropbox Storage






From Project

Back to project page notes.

License

The source code is released under:

DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> Everyone is permitted to copy and distribute verbatim or...

If you think the Android project notes 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.iliakplv.notes.notes.dropbox;
/* ww w . j  a va2s.  c o m*/

import android.util.Pair;

import com.dropbox.sync.android.DbxDatastore;
import com.dropbox.sync.android.DbxException;
import com.dropbox.sync.android.DbxFields;
import com.dropbox.sync.android.DbxRecord;
import com.dropbox.sync.android.DbxTable;
import com.iliakplv.notes.NotesApplication;
import com.iliakplv.notes.notes.AbstractNote;
import com.iliakplv.notes.notes.Label;
import com.iliakplv.notes.notes.LabelComparator;
import com.iliakplv.notes.notes.NoteComparator;
import com.iliakplv.notes.notes.NotesUtils;
import com.iliakplv.notes.notes.TextNote;
import com.iliakplv.notes.notes.storage.NotesStorage;
import com.iliakplv.notes.notes.storage.NotesStorageListener;
import com.iliakplv.notes.utils.AppLog;
import com.iliakplv.notes.utils.StringUtils;

import org.joda.time.DateTime;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

public class NotesDropboxStorage implements NotesStorage {

  private static final String TAG = NotesDropboxStorage.class.getSimpleName();
  private static final String INVALID_ID = "";

  private static final DbxTable.ResolutionRule RESOLUTION_RULE = DbxTable.ResolutionRule.LOCAL;
  DbxDatastore datastore;

  // tables
  private static final String NOTES_TABLE = "notes";
  private static final String NOTES_TITLE = "title";
  private static final String NOTES_TEXT = "text";
  private static final String NOTES_CREATE_TIME = "created";
  private static final String NOTES_CHANGE_TIME = "changed";
  private static final String[] NOTES_FIELDS =
      {NOTES_TITLE, NOTES_TEXT, NOTES_CREATE_TIME, NOTES_CHANGE_TIME};

  private static final String LABELS_TABLE = "labels";
  private static final String LABELS_NAME = "name";
  private static final String LABELS_COLOR = "color";
  private static final String[] LABELS_FIELDS =
      {LABELS_NAME, LABELS_COLOR};

  private static final String NOTES_LABELS_TABLE = "notes_labels";
  private static final String NOTES_LABELS_NOTE_ID = "note_id";
  private static final String NOTES_LABELS_LABEL_ID = "label_id";
  private static final String[] NOTES_LABELS_FIELDS =
      {NOTES_LABELS_NOTE_ID, NOTES_LABELS_LABEL_ID};

  private DbxTable notesTable;
  private DbxTable labelsTable;
  private DbxTable notesLabelsTable;
  
  // cache
  private static final int CACHE_NOTE = 1;
  private static final int CACHE_NOTES_LIST = 2;
  private static final int CACHE_LABELS_LIST = 4;

  // notes list cache
  private List<AbstractNote> notesListCache;
  private volatile Serializable notesListCacheLabelId = INVALID_ID;
  private volatile boolean notesListCacheActual = false;

  // list sort
  private NoteComparator noteComparator = new NoteComparator();
  private LabelComparator labelComparator = new LabelComparator();

  // note cache
  private AbstractNote noteCache;
  private volatile Serializable noteCacheNoteId = INVALID_ID;
  private volatile boolean noteCacheActual = false;

  // labels cache
  private List<Label> labelsListCache;
  private volatile boolean labelsListCacheActual = false;

  // search cache
  private List<AbstractNote> searchListCache = new ArrayList<AbstractNote>();
  private String lastSearchQuery = "";

  // listeners
  private final List<NotesStorageListener> storageListeners = new LinkedList<NotesStorageListener>();


  public NotesDropboxStorage() {
    try {
      datastore = DbxDatastore.openDefault(DropboxHelper.getAccount());
    } catch (DbxException e) {
      AppLog.e(TAG, "Error opening datastore", e);
      throw new RuntimeException("Error opening datastore");
    }

    syncDatastore();
    initTables();
  }

  private void syncDatastore() {
    try {
      datastore.sync();
    } catch (DbxException e) {
      AppLog.e(TAG, "syncDatastore()", e);
      throw new RuntimeException();
    }
  }

  @Override
  public void sync() {
    // Cache invalidation, listeners notification. Sync also called from here
    onStorageContentChanged(CACHE_NOTE | CACHE_NOTES_LIST |CACHE_LABELS_LIST);
  }

  public void initTables() {
    notesTable = datastore.getTable(NOTES_TABLE);
    labelsTable = datastore.getTable(LABELS_TABLE);
    notesLabelsTable = datastore.getTable(NOTES_LABELS_TABLE);

    for (String field : NOTES_FIELDS) {
      notesTable.setResolutionRule(field, RESOLUTION_RULE);
    }
    for (String field : LABELS_FIELDS) {
      labelsTable.setResolutionRule(field, RESOLUTION_RULE);
    }
    for (String field : NOTES_LABELS_FIELDS) {
      notesLabelsTable.setResolutionRule(field, RESOLUTION_RULE);
    }
  }


  @Override
  public boolean setNotesSortOrder(NotesUtils.NoteSortOrder notesSortOrder) {
    boolean orderChanged = noteComparator.getSortOrder() != notesSortOrder;
    if (orderChanged) {
      noteComparator.setSortOrder(notesSortOrder);
      onStorageContentChanged(CACHE_NOTES_LIST);
    }
    return orderChanged;
  }

  @Override
  public AbstractNote getNote(Serializable id) {
    final String stringId = (String) id;
    if (!DbxTable.isValidId(stringId)) {
      return null;
    }
    refreshNoteCacheIfNeeded(stringId);
    return noteCache;
  }

  private void refreshNoteCacheIfNeeded(String noteId) {
    final boolean needToRefresh = !noteCacheActual || !noteCacheNoteId.equals(noteId);
    AppLog.d(TAG, "Note entry refresh (id=" + noteId + "). Cached entry " +
        (needToRefresh ? "NOT " : "") + "actual");
    if (needToRefresh) {
      try {
        noteCache = createNoteFromRecord(notesTable.get(noteId));
      } catch (DbxException e) {
        AppLog.e(TAG, "refreshNoteCacheIfNeeded()", e);
        throw new RuntimeException();
      }

      noteCacheNoteId = noteId;
      noteCacheActual = true;
    }
  }

  private void refreshNotesListCacheIfNeeded(Serializable labelId) {
    final boolean needToRefresh = !notesListCacheActual || !notesListCacheLabelId.equals(labelId);
    AppLog.d(TAG, "Notes entries refresh (labelId=" + labelId + "). Cached entries list " +
        (needToRefresh ? "NOT " : "") + "actual");
    if (needToRefresh) {
      // query all notes records
      final DbxTable.QueryResult allNotesRecords;
      try {
        allNotesRecords = notesTable.query();
      } catch (DbxException e) {
        AppLog.e(TAG, "refreshNotesListCacheIfNeeded", e);
        throw new RuntimeException();
      }

      // find notes ids for specified label
      final boolean notesForAllLabels = labelId.equals(NOTES_FOR_ALL_LABELS);
      final Set<String> noteIdsForLabel = notesForAllLabels ?
          null :
          getNotesIdsForLabel((String) labelId);

      // add required notes to cache
      if (notesListCache != null) {
        notesListCache.clear();
      } else {
        notesListCache = new ArrayList<AbstractNote>();
      }
      for (DbxRecord noteRecord : allNotesRecords) {
        if (notesForAllLabels || noteIdsForLabel.contains(noteRecord.getId())) {
          final AbstractNote noteFromRecord = createNoteFromRecord(noteRecord);
          if (noteFromRecord != null) {
            notesListCache.add(noteFromRecord);
          }
        }
      }

      Collections.sort(notesListCache, noteComparator);

      notesListCacheLabelId = labelId;
      notesListCacheActual = true;
    }
  }

  private static AbstractNote createNoteFromRecord(DbxRecord record) {
    if (record == null) {
      return null;
    }

    final String title = record.getString(NOTES_TITLE);
    final String text = record.getString(NOTES_TEXT);
    final long createTime = record.getLong(NOTES_CREATE_TIME);
    final long changeTime = record.getLong(NOTES_CHANGE_TIME);

    final AbstractNote note = new TextNote(title, text);
    note.setCreateTime(new DateTime(createTime));
    note.setChangeTime(new DateTime(changeTime));
    note.setId(record.getId());
    return note;
  }

  @Override
  public List<AbstractNote> getNotesForLabel(Serializable labelId) {
    refreshNotesListCacheIfNeeded(labelId);
    return notesListCache;
  }

  @Override
  public List<AbstractNote> getNotesForQuery(String searchQuery) {
    if (!StringUtils.isBlank(searchQuery)) {
      searchQuery = StringUtils.normalizeString(searchQuery);
      if (!lastSearchQuery.equals(searchQuery)) {
        final DbxTable.QueryResult allNotesRecords;
        try {
          allNotesRecords = notesTable.query();
        } catch (DbxException e) {
          AppLog.e(TAG, "getNotesForQuery", e);
          throw new RuntimeException();
        }

        final List<AbstractNote> searchResult = new ArrayList<AbstractNote>();
        for (DbxRecord noteRecord : allNotesRecords) {
          final AbstractNote noteFromRecord = createNoteFromRecord(noteRecord);
          if (noteFromRecord != null) {
            final String title = StringUtils.normalizeString(noteFromRecord.getTitle());
            final String body = StringUtils.normalizeString(noteFromRecord.getBody());
            if (title.contains(searchQuery) || body.contains(searchQuery)) {
              searchResult.add(noteFromRecord);
            }
          }
        }
        Collections.sort(searchResult, noteComparator);
        searchListCache = searchResult;
        lastSearchQuery = searchQuery;
      }
      return searchListCache;
    }
    return EMPTY_NOTES_LIST;
  }

  @Override
  public Serializable insertNote(AbstractNote note) {
    final DbxRecord temp = notesTable.insert()
        .set(NOTES_TITLE, note.getTitle())
        .set(NOTES_TEXT, note.getBody())
        .set(NOTES_CREATE_TIME, note.getCreateTime().getMillis())
        .set(NOTES_CHANGE_TIME, note.getChangeTime().getMillis());

    onStorageContentChanged(CACHE_NOTES_LIST);
    return temp.getId();
  }

  @Override
  public boolean updateNote(Serializable id, AbstractNote note) {
    final DbxRecord noteRecord;
    try {
      noteRecord = notesTable.get((String) id);
    } catch (DbxException e) {
      AppLog.e(TAG, "updateNote()", e);
      throw new RuntimeException();
    }

    final boolean existingRecord = noteRecord != null;
    if (existingRecord) {
      noteRecord
          .set(NOTES_TITLE, note.getTitle())
          .set(NOTES_TEXT, note.getBody())
          .set(NOTES_CREATE_TIME, note.getCreateTime().getMillis())
          .set(NOTES_CHANGE_TIME, note.getChangeTime().getMillis());
      onStorageContentChanged((noteCacheNoteId.equals(id) ? CACHE_NOTE : 0) | CACHE_NOTES_LIST);
    }

    return existingRecord;
  }

  @Override
  public boolean deleteNote(Serializable id) {
    boolean deleted = false;
    final String stringId = (String) id;
    try {
      final DbxRecord noteRecord = notesTable.get(stringId);
      if (noteRecord != null) {
        deleteNoteLabels(true, stringId);
        noteRecord.deleteRecord();
        deleted = true;
        onStorageContentChanged((noteCacheNoteId.equals(id) ? CACHE_NOTE : 0) | CACHE_NOTES_LIST);
      }
    } catch (DbxException e) {
      AppLog.e(TAG, "deleteNote()", e);
      throw new RuntimeException();
    }

    return deleted;
  }

  private void deleteNoteLabels(boolean forNote, String id) {
    final DbxFields queryParams =
        new DbxFields().set(forNote ? NOTES_LABELS_NOTE_ID : NOTES_LABELS_LABEL_ID, id);

    final DbxTable.QueryResult notesLabelsIds;
    try {
      notesLabelsIds = notesLabelsTable.query(queryParams);
    } catch (DbxException e) {
      AppLog.e(TAG, "deleteNoteLabels()", e);
      throw new RuntimeException();
    }

    for (DbxRecord record : notesLabelsIds) {
      record.deleteRecord();
    }
  }

  @Override
  public Label getLabel(Serializable id) {
    final String stringId = (String) id;
    if (!DbxTable.isValidId(stringId)) {
      return null;
    }

    final DbxRecord labelRecord;
    try {
      labelRecord = labelsTable.get(stringId);
    } catch (DbxException e) {
      AppLog.e(TAG, "getLabel()", e);
      throw new RuntimeException();
    }
    return createLabelFromRecord(labelRecord);
  }

  @Override
  public List<Label> getAllLabels() {
    refreshLabelsListCacheIfNeeded();
    return labelsListCache;
  }

  private void refreshLabelsListCacheIfNeeded() {
    AppLog.d(TAG, "Labels entries refresh. Cached entries list " +
        (labelsListCacheActual ? "" : "NOT ") + "actual");
    if (!labelsListCacheActual) {
      // get all labels records
      final DbxTable.QueryResult allLabelsRecords;
      try {
        allLabelsRecords = labelsTable.query();
      } catch (DbxException e) {
        AppLog.e(TAG, "refreshLabelsListCacheIfNeeded()", e);
        throw new RuntimeException();
      }

      // fill cache
      if (labelsListCache != null) {
        labelsListCache.clear();
      } else {
        labelsListCache = new ArrayList<Label>();
      }
      for (DbxRecord labelRecord : allLabelsRecords) {
        final Label labelFromRecord = createLabelFromRecord(labelRecord);
        if (labelFromRecord != null) {
          labelsListCache.add(labelFromRecord);
        }
      }

      Collections.sort(labelsListCache, labelComparator);

      labelsListCacheActual = true;
    }
  }

  private static Label createLabelFromRecord(DbxRecord record) {
    if (record == null) {
      return null;
    }

    final String name = record.getString(LABELS_NAME);
    final int color = (int) record.getLong(LABELS_COLOR);
    final Label label = new Label(name, color);
    label.setId(record.getId());
    return label;
  }

  @Override
  public Serializable insertLabel(Label label) {
    final DbxRecord temp = labelsTable.insert()
        .set(LABELS_NAME, label.getName())
        .set(LABELS_COLOR, label.getColor());

    onStorageContentChanged(CACHE_NOTES_LIST | CACHE_LABELS_LIST);
    return temp.getId();
  }

  @Override
  public boolean updateLabel(Serializable id, Label label) {
    final DbxRecord labelRecord;
    try {
      labelRecord = labelsTable.get((String) id);
    } catch (DbxException e) {
      AppLog.e(TAG, "updateLabel()", e);
      throw new RuntimeException();
    }
    final boolean existingRecord = labelRecord != null;
    if (existingRecord) {
      labelRecord
          .set(LABELS_NAME, label.getName())
          .set(LABELS_COLOR, label.getColor());
      onStorageContentChanged(CACHE_NOTE | CACHE_NOTES_LIST | CACHE_LABELS_LIST);
    }
    return existingRecord;
  }

  @Override
  public boolean deleteLabel(Serializable id) {
    boolean deleted = false;
    final String stringId = (String) id;
    try {
      final DbxRecord labelRecord = labelsTable.get(stringId);
      if (labelRecord != null) {
        deleteNoteLabels(false, stringId);
        labelRecord.deleteRecord();
        deleted = true;
        onStorageContentChanged(CACHE_NOTE | CACHE_NOTES_LIST | CACHE_LABELS_LIST);
      }
    } catch (DbxException e) {
      AppLog.e(TAG, "deleteLabel()", e);
      throw new RuntimeException();
    }
    return deleted;
  }

  @Override
  public List<Label> getLabelsForNote(Serializable noteId) {
    final List<Label> allLabels = getAllLabels();
    final Set<Serializable> labelsIdsForNote = getLabelsIdsForNote(noteId);

    final List<Label> result = new ArrayList<Label>();
    for (Label label : allLabels) {
      if (labelsIdsForNote.contains(label.getId())) {
        result.add(label);
      }
    }

    return result;
  }

  @Override
  public Set<Serializable> getLabelsIdsForNote(Serializable noteId) {
    final DbxFields queryParams = new DbxFields().set(NOTES_LABELS_NOTE_ID, (String) noteId);

    final DbxTable.QueryResult notesLabelsIds;
    try {
      notesLabelsIds = notesLabelsTable.query(queryParams);
    } catch (DbxException e) {
      AppLog.e(TAG, "getLabelsIdsForNote()", e);
      throw new RuntimeException();
    }

    final Set<Serializable> result = new HashSet<Serializable>();
    for (DbxRecord record : notesLabelsIds) {
      result.add(record.getString(NOTES_LABELS_LABEL_ID));
    }
    return result;
  }

  private Set<String> getNotesIdsForLabel(String labelId) {
    final DbxFields queryParams = new DbxFields().set(NOTES_LABELS_LABEL_ID, labelId);
    final DbxTable.QueryResult notesLabelsIds;

    try {
      notesLabelsIds = notesLabelsTable.query(queryParams);
    } catch (DbxException e) {
      AppLog.e(TAG, "getNotesIdsForLabel()", e);
      throw new RuntimeException();
    }

    final Set<String> result = new HashSet<String>();
    for (DbxRecord record : notesLabelsIds) {
      result.add(record.getString(NOTES_LABELS_NOTE_ID));
    }
    return result;
  }

  @Override
  public Set<Pair<Serializable, Serializable>> getAllNotesLabelsIds() {
    final DbxTable.QueryResult allNotesLabelsIds;
    try {
      allNotesLabelsIds = notesLabelsTable.query();
    } catch (DbxException e) {
      AppLog.e(TAG, "getAllNotesLabelsIds()", e);
      throw new RuntimeException();
    }
    final HashSet<Pair<Serializable, Serializable>> result =
        new HashSet<Pair<Serializable, Serializable>>();
    for (DbxRecord record : allNotesLabelsIds) {
      result.add(new Pair<Serializable, Serializable>(
          record.getString(NOTES_LABELS_NOTE_ID),
          record.getString(NOTES_LABELS_LABEL_ID)));
    }
    return result;
  }

  @Override
  public Serializable insertLabelToNote(Serializable noteId, Serializable labelId) {
    final DbxRecord temp = notesLabelsTable.insert()
        .set(NOTES_LABELS_NOTE_ID, (String) noteId)
        .set(NOTES_LABELS_LABEL_ID, (String) labelId);

    onStorageContentChanged((noteCacheNoteId.equals(noteId) ? CACHE_NOTE : 0) | CACHE_NOTES_LIST);
    return temp.getId();
  }

  @Override
  public boolean deleteLabelFromNote(Serializable noteId, Serializable labelId) {
    final DbxFields queryParams = new DbxFields()
        .set(NOTES_LABELS_NOTE_ID, (String) noteId)
        .set(NOTES_LABELS_LABEL_ID, (String) labelId);

    final DbxTable.QueryResult notesLabels;
    try {
      notesLabels = notesLabelsTable.query(queryParams);
    } catch (DbxException e) {
      AppLog.e(TAG, "deleteLabelFromNote()", e);
      throw new RuntimeException();
    }

    boolean deleted = false;
    for (DbxRecord record : notesLabels) {
      record.deleteRecord();
      deleted = true;
    }
    if (deleted) {
      onStorageContentChanged((noteCacheNoteId.equals(noteId) ? CACHE_NOTE : 0) | CACHE_NOTES_LIST);
    }
    return deleted;
  }

  @Override
  public void clear() {
    final DbxTable[] allTables = {notesLabelsTable, labelsTable, notesTable};

    for (DbxTable table : allTables) {
      final DbxTable.QueryResult allTableRecords;
      try {
        allTableRecords = table.query();
      } catch (DbxException e) {
        AppLog.e(TAG, "clear()", e);
        throw new RuntimeException();
      }

      for (DbxRecord record : allTableRecords) {
        record.deleteRecord();
      }
    }

    onStorageContentChanged(CACHE_NOTE | CACHE_NOTES_LIST | CACHE_LABELS_LIST);
  }

  // Cache control

  private void onStorageContentChanged(final int affectedCacheType) {
    syncDatastore();

    // cache invalidation
    if ((affectedCacheType & CACHE_NOTE) != 0) {
      noteCacheActual = false;
    }
    if ((affectedCacheType & CACHE_NOTES_LIST) != 0) {
      notesListCacheActual = false;
      lastSearchQuery = "";
    }
    if ((affectedCacheType & CACHE_LABELS_LIST) != 0) {
      labelsListCacheActual = false;
    }

    notifyListeners();
  }

  // Listeners

  private void notifyListeners() {
    NotesApplication.executeInBackground(new Runnable() {
      @Override
      public void run() {
        synchronized (storageListeners) {
          for (NotesStorageListener listener : storageListeners) {
            listener.onContentChanged();
          }
        }
      }
    });
  }

  @Override
  public boolean addStorageListener(NotesStorageListener listener) {
    if (listener == null) {
      throw new NullPointerException();
    }
    synchronized (storageListeners) {
      return storageListeners.add(listener);
    }
  }

  @Override
  public boolean removeStorageListener(NotesStorageListener listener) {
    if (listener == null) {
      throw new NullPointerException();
    }
    synchronized (storageListeners) {
      return storageListeners.remove(listener);
    }
  }

  @Override
  public List<NotesStorageListener> detachAllListeners() {
    synchronized (storageListeners){
      final List<NotesStorageListener> listeners =
          new LinkedList<NotesStorageListener>(storageListeners);
      storageListeners.clear();
      return listeners;
    }
  }

  @Override
  public void attachListeners(List<NotesStorageListener> listeners) {
    synchronized (storageListeners) {
      storageListeners.addAll(listeners);
    }
    notifyListeners();
  }
}




Java Source Code List

com.iliakplv.notes.NotesApplication.java
com.iliakplv.notes.analytics.EventTracker.java
com.iliakplv.notes.analytics.Event.java
com.iliakplv.notes.gui.main.MainActivityTest.java
com.iliakplv.notes.gui.main.MainActivity.java
com.iliakplv.notes.gui.main.NavigationDrawerFragment.java
com.iliakplv.notes.gui.main.NoteDetailsFragment.java
com.iliakplv.notes.gui.main.NotesListFragment.java
com.iliakplv.notes.gui.main.dialogs.AboutDialog.java
com.iliakplv.notes.gui.main.dialogs.AbstractItemDialog.java
com.iliakplv.notes.gui.main.dialogs.DropboxAccountLinkingDialog.java
com.iliakplv.notes.gui.main.dialogs.LabelEditDialog.java
com.iliakplv.notes.gui.main.dialogs.NoteLabelsDialog.java
com.iliakplv.notes.gui.main.dialogs.SimpleItemDialog.java
com.iliakplv.notes.gui.main.dialogs.VoiceSearchInstallDialog.java
com.iliakplv.notes.gui.settings.SettingsActivity.java
com.iliakplv.notes.notes.AbstractNote.java
com.iliakplv.notes.notes.LabelComparator.java
com.iliakplv.notes.notes.Label.java
com.iliakplv.notes.notes.NoteComparator.java
com.iliakplv.notes.notes.NotesUtils.java
com.iliakplv.notes.notes.TextNote.java
com.iliakplv.notes.notes.db.NotesDatabaseAdapter.java
com.iliakplv.notes.notes.db.NotesDatabaseOpenHelper.java
com.iliakplv.notes.notes.db.NotesDatabaseStorage.java
com.iliakplv.notes.notes.dropbox.DropboxHelper.java
com.iliakplv.notes.notes.dropbox.NotesDropboxStorage.java
com.iliakplv.notes.notes.storage.NotesStorageListener.java
com.iliakplv.notes.notes.storage.NotesStorage.java
com.iliakplv.notes.notes.storage.StorageDataTransfer.java
com.iliakplv.notes.notes.storage.StorageWrapper.java
com.iliakplv.notes.notes.storage.Storage.java
com.iliakplv.notes.storage.StorageTest.java
com.iliakplv.notes.utils.AppLog.java
com.iliakplv.notes.utils.ConnectivityUtils.java
com.iliakplv.notes.utils.StringUtils.java
com.iliakplv.notes.utils.Utils.java