/**
   * Load {@link Bookmark} instance, creating it if it does not exist.
   *
   * @param title the {@link Bookmark}'s title to load.
   * @return the {@link Bookmark} for the given <code>title</code>, or null if <code>title</code> is
   *     null.
   */
  protected Bookmark loadBookmark(final String title) {
    Debug.enter(title);

    Bookmark bookmark = null;
    final String titleValue = (title != null) ? title.trim() : "";
    if (0 < titleValue.length()) {
      synchronized (AbstractProfileCRUD.LOCK) {
        String basename = AbstractUserProfileStorage.getBasename(titleValue);
        final boolean adding = (basename == null);

        if (adding) {
          basename = AbstractUserProfileStorage.getBasename();
        }

        final SharedPreferences prefs = AbstractProfile.getSharedPreferences(basename);
        bookmark = readBookmark(prefs, basename, titleValue);

        if (adding) {
          writeBookmark(prefs, bookmark);
        }
      }
    }

    Debug.leave("loaded", titleValue, (bookmark != null) ? bookmark.title : null);
    return bookmark;
  }
 /**
  * Initialize and return this.database object.
  *
  * @return SQLiteDatabase properly initialized.
  * @throws IOException on error.
  */
 @Override
 protected SQLiteDatabase getDatabase() throws IOException {
   Debug.enter();
   final SQLiteDatabase database = DatabaseSession.getDatabase(Android.App.INSTANCE);
   Debug.leave();
   return database;
 }
 /**
  * Initialize and return path, relative from the "home" directory.
  *
  * @param path inside $HOME
  * @return File($HOME, path) properly initialized
  * @throws IOException on error
  */
 @Override
 protected File getHome(final String path) throws IOException {
   // @see http://en.wikipedia.org/wiki/Double-checked_locking. The use of local variable
   // 'directory' seems
   // unnecessary. It will make the code 25% faster for some Java VM, and it won't hurt for others
   File directory = home;
   if (directory != null) {
     Debug.print("home", directory.getAbsolutePath());
     return ((path == null) || (path.length() <= 0)) ? directory : new File(directory, path);
   }
   Debug.enter();
   synchronized (LOCK) {
     directory = home;
     if (directory != null) {
       Debug.print("lost getHome singleton race");
     } else {
       // initialize home
       directory = new File(Android.App.DATA_DIRECTORY_NAME);
       // next will be very slow
       restoreMissingFiles(directory);
       // finally, home
       home = directory;
     }
   }
   Debug.leave(directory.getAbsolutePath());
   return ((path == null) || (path.length() <= 0)) ? directory : new File(directory, path);
 }
 /** {@inheritDoc} */
 @Override
 public void flash(final String message) {
   Debug.enter(tag, message);
   if (message != null) {
     Toast.makeText(this, message, Toast.LENGTH_LONG).show();
   }
   Debug.leave(tag);
 }
 /** {@inheritDoc} */
 @Override
 public boolean isTerminated() {
   Debug.enter(tag);
   boolean terminated = false;
   if (wasDestroyed || isFinishing()) {
     Debug.print(tag, "activity terminated");
     terminated = wasDestroyed = true;
   }
   Debug.leave(tag, terminated);
   return terminated;
 }
 /** {@inheritDoc} */
 @Override
 public void onConfigurationChanged(final Configuration newConfig) {
   super.onConfigurationChanged(newConfig);
   {
     Debug.enter();
     try {
       Debug.print(tag, "configurationChanged", newConfig.locale);
       Android.App.setLocale(newConfig.locale);
     } catch (final IOException ex) {
       Debug.error(ex, tag, "unable to set new locale", newConfig.locale);
     }
     Debug.leave();
   }
 }
  /**
   * Save {@link Bookmark} instance.
   *
   * @param bookmark to save.
   * @return true on success, false otherwise.
   */
  protected boolean saveBookmark(final Bookmark bookmark) {
    Debug.enter();

    boolean success = false;
    if (bookmark != null && bookmark.title != null) {
      synchronized (AbstractProfileCRUD.LOCK) {
        final SharedPreferences prefs = bookmark.getSharedPreferences();
        success = writeBookmark(prefs, bookmark);
      }
    }

    Debug.leave("saved?", success, (bookmark != null) ? bookmark.title : null);
    return success;
  }
 /**
  * Setup missing application files into the "home directory".
  *
  * @param targetDir
  * @throws IOException
  * @return true on success
  */
 private boolean restoreMissingFiles(final File targetDir) throws IOException {
   Debug.enter();
   boolean success = false;
   final SharedPreferences prefs = Settings.INSTANCE.getSharedPreferences();
   final String oldTarball = prefs.getString(SettingsStorage.FIELD_TARBALL, null);
   final String newTarball = getString(R.string.build_tarball);
   final boolean keepOldFiles = newTarball.equals(oldTarball);
   try {
     // extract the tar-ball to recover any missing file, if any
     final TarArchive tarball = new TarArchive(new GZIPInputStream(tarballFile()));
     tarball.keepOldFiles = keepOldFiles;
     tarball.extract(targetDir);
     tarball.close();
     // once the restore is completed successfully,
     // we need to update the shared preference, if necessary
     if (!keepOldFiles) {
       final SharedPreferences.Editor edit = prefs.edit();
       edit.putString(SettingsStorage.FIELD_TARBALL, newTarball);
       success = edit.commit();
     } else {
       success = true;
     }
   } catch (final Resources.NotFoundException ex) {
     // this exception usually would happen from the unit-tests
     Debug.error(ex, "tarball resources not found", keepOldFiles);
     // not really a fatal error if keepOldFiles is true
     if (!keepOldFiles) {
       Debug.leave();
       throw new IOException("Tarball resources missing");
     }
   } catch (final TarArchive.TarHeaderException ex) {
     Debug.error(ex, "invalid tarball header", keepOldFiles);
     Debug.leave();
     throw new IOException("Invalid tarball format");
   } catch (final IOException ex) {
     Debug.error(ex, "unable to install tarball", keepOldFiles);
     // not really a fatal error if keepOldFiles is true
     if (!keepOldFiles) {
       Debug.leave();
       throw ex;
     }
   }
   Debug.leave(success);
   return success;
 }
 /**
  * Setter - set {@link AbstractController}.
  *
  * @param controller to setup.
  */
 protected void setController(final AbstractController controller) {
   Debug.enter(tag, controller);
   this.controller = controller;
   Debug.leave(tag);
 }
 /**
  * Change language for this application only (not system-wide).
  *
  * @param locale the new {@link Locale} instance.
  * @throws IOException on error.
  */
 @Override
 protected void setLocale(final Locale locale) throws IOException {
   Debug.enter(locale);
   DatabaseSession.setLocale(Android.App.INSTANCE, locale);
   Debug.leave(locale);
 }