Android Open Source - encrypted-camera App Preference Fragment






From Project

Back to project page encrypted-camera.

License

The source code is released under:

Apache License

If you think the Android project encrypted-camera 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

/*
 * Copyright (C) 2014 Andrew Reitz// w ww  .j av a  2 s.  c  om
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.andrewreitz.encryptedcamera.ui.fragment;

import android.app.FragmentManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceFragment;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.andrewreitz.encryptedcamera.BuildConfig;
import com.andrewreitz.encryptedcamera.EncryptedCameraApp;
import com.andrewreitz.encryptedcamera.R;
import com.andrewreitz.encryptedcamera.bus.EncryptionEvent;
import com.andrewreitz.encryptedcamera.di.annotation.EncryptedDirectory;
import com.andrewreitz.encryptedcamera.di.annotation.ForActivity;
import com.andrewreitz.encryptedcamera.di.annotation.InternalDecryptedDirectory;
import com.andrewreitz.encryptedcamera.di.annotation.UnlockNotification;
import com.andrewreitz.encryptedcamera.encryption.EncryptionProvider;
import com.andrewreitz.encryptedcamera.encryption.KeyManager;
import com.andrewreitz.encryptedcamera.externalstoreage.ExternalStorageManager;
import com.andrewreitz.encryptedcamera.filesystem.SecureDelete;
import com.andrewreitz.encryptedcamera.sharedpreference.AppPreferenceManager;
import com.andrewreitz.encryptedcamera.ui.activity.BaseActivity;
import com.andrewreitz.encryptedcamera.ui.activity.AboutActivity;
import com.andrewreitz.encryptedcamera.ui.activity.GalleryActivity;
import com.andrewreitz.encryptedcamera.ui.dialog.ErrorDialog;
import com.andrewreitz.encryptedcamera.ui.dialog.FirstRunDialog;
import com.andrewreitz.encryptedcamera.ui.dialog.PasswordDialog;
import com.andrewreitz.encryptedcamera.ui.dialog.SetPasswordDialog;
import com.google.common.collect.ImmutableList;
import com.google.common.io.Files;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;

import org.jraf.android.backport.switchwidget.SwitchPreference;
import org.mindrot.jbcrypt.BCrypt;

import java.io.File;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.spec.InvalidKeySpecException;
import java.util.List;

import javax.crypto.SecretKey;
import javax.inject.Inject;

import timber.log.Timber;

import static com.andrewreitz.encryptedcamera.bus.EncryptionEvent.EncryptionState.NONE;

public class AppPreferenceFragment extends PreferenceFragment
    implements SetPasswordDialog.SetPasswordDialogListener, Preference.OnPreferenceChangeListener,
    PasswordDialog.PasswordDialogListener, ErrorDialog.ErrorDialogCallback {

  private static final int NOTIFICATION_ID = 1337;

  @Inject NotificationManager notificationManager;
  @Inject KeyManager keyManager;
  @Inject AppPreferenceManager preferenceManager;
  @Inject @UnlockNotification Notification unlockNotification;
  @Inject @EncryptedDirectory File encryptedDirectory;
  @Inject @InternalDecryptedDirectory File unencryptedInternalDirectory;
  @Inject ExternalStorageManager externalStorageManager;
  @Inject EncryptionProvider encryptionProvider;
  @Inject FragmentManager fragmentManager;
  @Inject Bus bus;
  @Inject SecureDelete secureDelete;
  @Inject SecureRandom secureRandom;
  @Inject @ForActivity Context context;

  private SwitchPreference switchPreferenceDecrypt;
  private SwitchPreference switchPreferencePassword;
  private FileCryptographyTask runningTask;
  private EncryptionEvent.EncryptionState encryptionState = NONE;

  @Override public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    BaseActivity.get(this).inject(this);

    if (!preferenceManager.hasSeenFirstRunFragment()) {
      FirstRunDialog dialog = FirstRunDialog.newInstance();
      dialog.show(fragmentManager, "dialog_first_run");
      preferenceManager.setHasSeenFirstLaunchFragment(true);
    }
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.app_preference_screen);
  }

  @Override @SuppressWarnings("ConstantConditions")
  public void onResume() {
    super.onResume();

    bus.register(this);

    switchPreferenceDecrypt =
        (SwitchPreference) findPreference(getString(R.string.pref_key_decrypt));
    switchPreferenceDecrypt.setOnPreferenceChangeListener(this);
    switchPreferencePassword =
        (SwitchPreference) findPreference(getString(R.string.pref_key_use_password));
    switchPreferencePassword.setOnPreferenceChangeListener(this);

    findPreference(getString(R.string.pref_key_version)).setSummary(BuildConfig.VERSION_NAME);
    findPreference(getString(R.string.pref_key_about)).setIntent(
        new Intent(context, AboutActivity.class));

    findPreference(getString(R.string.pref_key_gallery)).setIntent(
        new Intent(context, GalleryActivity.class));
  }

  @Override public void onPause() {
    super.onPause();
    if (runningTask != null) {
      runningTask.getProgressDialog().dismiss();
      runningTask.cancel(false);
    }
    bus.unregister(this);
  }

  @Override public void onPasswordSet(final String password) {
    File appExternalDirectory = getAppExternalDirectory();
    if (appExternalDirectory == null) return;
    executeDecryptFileTask(appExternalDirectory, new FileCryptographyTask.TaskFinishedCallback() {
      @Override public void onSuccess() {
        if (setNewPassword(password)) return;
        File appExternalDirectory = getAppExternalDirectory();
        if (appExternalDirectory == null) return;
        encryptSdDirectory(appExternalDirectory);
      }

      @Override public void onError() {
        Timber.e("error encrypting images after password was set");
      }
    });
  }

  private boolean setNewPassword(String password) {
    byte[] salt = new byte[10];
    secureRandom.nextBytes(salt);
    try {
      SecretKey secretKey = keyManager.generateKeyWithPassword(password.toCharArray(), salt);
      encryptionProvider.setSecretKey(secretKey);
      keyManager.saveKey(EncryptedCameraApp.KEY_STORE_ALIAS, secretKey);
      keyManager.saveKeyStore();
    } catch (NoSuchAlgorithmException | InvalidKeySpecException | CertificateException | KeyStoreException | IOException e) {
      Timber.e(e, "Error saving encryption key with password");
      ErrorDialog.newInstance(getString(R.string.encryption_error),
          getString(R.string.error_saving_encryption_key));
      return true;
    }
    preferenceManager.setPassword(password);
    preferenceManager.setSalt(salt);
    preferenceManager.setHasPassword(true);
    switchPreferencePassword.setChecked(true);
    return false;
  }

  @Override public void onPasswordEntered(String password) {
    if (!doPasswordCheck(password)) {
      showIncorrectPasswordDialog();
      return;
    }
    if (!setSecretKey(password)) return;
    decryptToSdDirectory(externalStorageManager.getAppExternalDirectory());
  }

  @Override public void onPasswordCancel() {
    switchPreferenceDecrypt.setChecked(false);
  }

  @Override public void onPasswordSetCancel() {
  }

  @Override public void onErrorDialogDismissed() {
    // TODO Remove All Get Activities and make a manager
    //noinspection ConstantConditions
    getActivity().finish();
  }

  @Override public boolean onPreferenceChange(Preference preference, Object newValue) {
    if (checkNotCurrentlyEncrypting()) return false;

    //newValue should always be a boolean but just to be sure
    if (!Boolean.class.isInstance(newValue)) {
      throw new IllegalArgumentException("newValue is not a boolean");
    }

    boolean value = (boolean) newValue;

    //noinspection ConstantConditions
    if (preference.getKey().equals(getString(R.string.pref_key_use_password))) {
      return handleUsePasswordPreference(value);
    } else if (preference.getKey().equals(getString(R.string.pref_key_decrypt))) {
      return handleDecryptedPreference(value);
    }

    throw new RuntimeException("Unknown preference passed in preference == " + preference.getKey());
  }

  private boolean checkNotCurrentlyEncrypting() {
    if (!encryptionState.equals(NONE)) {
      showErrorDialog(getString(R.string.error),
          EncryptionEvent.EncryptionState.DECRYPTING == encryptionState ? getString(
              R.string.error_currently_decrypting) : getString(R.string.error_currently_encrypting),
          "error_decrypting_in_progress");
      return true;
    }
    return false;
  }

  @SuppressWarnings("UnusedDeclaration") @Subscribe public void handleEncryptionEvent(
      EncryptionEvent event) {
    if (event.state.equals(NONE)) {
      getActivity().setProgressBarIndeterminateVisibility(false);
    } else {
      getActivity().setProgressBarIndeterminateVisibility(true);
    }
    encryptionState = event.state;
  }

  private boolean handleDecryptedPreference(boolean value) {
    handleEncryption(value);
    return false;
  }

  private boolean handleUsePasswordPreference(boolean checked) {
    if (preferenceManager.isDecrypted()) {
      // don't allow changing password while photos are decrypted
      showErrorDialog(getString(R.string.error),
          getString(R.string.error_change_password_while_decrypted),
          "error_change_password_while_decrypted");
      return false;
    } else if (checked
        && !preferenceManager.hasPassword()) { // check if a password has already been set do to the filtering done for passwords
      SetPasswordDialog.newInstance(this).show(fragmentManager, "password_dialog");
      return false;
    } else {
      if (preferenceManager.hasPassword()) {
        turnOffPassword();
        return false;
      } else {
        createKeyNoPassword();
        return true;
      }
    }
  }

  private void turnOffPassword() {
    PasswordDialog.newInstance(new PasswordDialog.PasswordDialogListener() {
      // Create custom because one in activity does not meet our needs
      @Override public void onPasswordEntered(String password) {
        if (!doPasswordCheck(password)) {
          showIncorrectPasswordDialog();
          return;
        }
        if (!setSecretKey(password)) return;
        if (decryptFilesInternally(password)) return;
        reEncryptFilesInternally();
      }

      @Override public void onPasswordCancel() {
      }
    }).show(fragmentManager, "get_password_dialog");
  }

  private void reEncryptFilesInternally() {
    try {
      //noinspection ConstantConditions
      for (File in : encryptedDirectory.listFiles()) {
        File out = new File(in.getPath().replace(".tmp", ""));
        encryptionProvider.encrypt(in, out);
        //noinspection ResultOfMethodCallIgnored
        in.delete();
      }
      switchPreferencePassword.setChecked(false);
    } catch (InvalidKeyException | IOException | InvalidAlgorithmParameterException e) {
      Timber.w(e, "Error encrypting files without a password");
      // if this exception really happens the application won't work
      // We should really crash.
      throw new RuntimeException(e);
    }
  }

  private boolean decryptFilesInternally(@NonNull String password) {
    if (!doPasswordCheck(password)) {
      if (!doPasswordCheck(password)) {
        showIncorrectPasswordDialog();
        return false;
      }
    }

    try {
      //noinspection ConstantConditions
      for (File in : encryptedDirectory.listFiles()) {
        File out = new File(encryptedDirectory, in.getName() + ".tmp");
        encryptionProvider.decrypt(in, out);
        //noinspection ResultOfMethodCallIgnored
        in.delete();
      }
    } catch (InvalidKeyException | IOException | InvalidAlgorithmParameterException e) {
      Timber.w(e, "error unencrypting internally");
      showErrorDialog(getString(R.string.error), getString(R.string.error_incorrect_password),
          "error_dialog_removing_password");
      return true;
    }

    return false;
  }

  private boolean createKeyNoPassword() {
    // Create a keystore for encryption that does not require a password
    try {
      SecretKey secretKey = keyManager.generateKeyNoPassword();
      encryptionProvider.setSecretKey(secretKey);
      keyManager.saveKey(EncryptedCameraApp.KEY_STORE_ALIAS, secretKey);
      keyManager.saveKeyStore();
      return true;
    } catch (NoSuchAlgorithmException | KeyStoreException | IOException | CertificateException e) {
      // The app really wouldn't work at this point
      Timber.e(e, "Error saving encryption key, no password");
      showErrorDialog(getString(R.string.encryption_error),
          getString(R.string.error_saving_encryption_key), "error_dialog_generate_key_no_password");
    }

    return false;
  }

  /** true for decrypt, false for encrypt */
  private void handleEncryption(boolean decrypt) {
    File appExternalDirectory = getAppExternalDirectory();
    if (appExternalDirectory == null) return;

    if (decrypt) {
      if (preferenceManager.hasPassword()) {
        PasswordDialog passwordDialog = PasswordDialog.newInstance(this);
        //noinspection ConstantConditions
        passwordDialog.show(fragmentManager, "dialog_get_password");
      } else {
        decryptToSdDirectory(appExternalDirectory);
      }
    } else {
      encryptSdDirectory(appExternalDirectory);
    }
  }

  /**
   * Would pull this out and just set once, but we need to constantly check due to possibility of
   * changing state
   */
  private File getAppExternalDirectory() {
    File appExternalDirectory = externalStorageManager.getAppExternalDirectory();

    if (appExternalDirectory == null
        || !externalStorageManager.checkSdCardIsInReadAndWriteState()) {
      //noinspection ConstantConditions
      showErrorDialog(getString(R.string.error), getString(R.string.error_sdcard_message),
          "error_dialog_sdcard");
      return null;
    }
    return appExternalDirectory;
  }

  private void decryptToSdDirectory(@NonNull File appExternalDirectory) {
    this.decryptToSdDirectory(appExternalDirectory, null);
  }

  private void decryptToSdDirectory(@NonNull File appExternalDirectory, @Nullable String password) {
    if (password != null && !doPasswordCheck(password)) {
      showIncorrectPasswordDialog();
      return;
    }

    executeDecryptFileTask(appExternalDirectory, new FileCryptographyTask.TaskFinishedCallback() {
      @Override public void onSuccess() {
        notificationManager.notify(NOTIFICATION_ID, unlockNotification);
        switchPreferenceDecrypt.setChecked(true);
      }

      @Override public void onError() {
        // there was an error reset the switch preferences
        switchPreferenceDecrypt.setChecked(false);
      }
    });
  }

  private void executeDecryptFileTask(@NonNull File appExternalDirectory,
      FileCryptographyTask.TaskFinishedCallback callback) {
    //noinspection ConstantConditions
    runningTask = new DecryptFilesTask(appExternalDirectory, encryptionProvider, context,
        ImmutableList.copyOf(encryptedDirectory.listFiles()), callback,
        getString(R.string.decrypting_files), bus);
    //noinspection unchecked
    runningTask.execute();
  }

  private void showIncorrectPasswordDialog() {
    showErrorDialog(getString(R.string.error), getString(R.string.error_incorrect_password),
        "error_dialog_encrypt_pw");
  }

  private void encryptSdDirectory(File appExternalDirectory) {
    executeEncryptFileTask(appExternalDirectory, new FileCryptographyTask.TaskFinishedCallback() {
      @Override public void onSuccess() {
        notificationManager.cancel(NOTIFICATION_ID);
        switchPreferenceDecrypt.setChecked(false);
      }

      @Override public void onError() {
        switchPreferenceDecrypt.setChecked(true);
      }
    });
  }

  private void executeEncryptFileTask(File appExternalDirectory,
      FileCryptographyTask.TaskFinishedCallback callback) {
    //noinspection ConstantConditions
    runningTask =
        new EncryptFilesTask(unencryptedInternalDirectory, encryptedDirectory, secureDelete,
            context, ImmutableList.copyOf(appExternalDirectory.listFiles()), encryptionProvider,
            callback, getString(R.string.encrypting_files), bus);

    runningTask.execute();
  }

  private boolean setSecretKey(String password) {
    try {
      // recreate the secret key and give it to the encryption provider
      SecretKey key =
          keyManager.generateKeyWithPassword(password.toCharArray(), preferenceManager.getSalt());
      encryptionProvider.setSecretKey(key);
      return true;
    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
      Timber.w(e, "Error recreating secret key.  This probably should never happen");
      showErrorDialog(getString(R.string.error), getString(R.string.error_terrible),
          "error_dialog_recreate_key");
    }

    return false;
  }

  private void showErrorDialog(String error, String message, String tag) {
    showErrorDialog(error, message, tag, null);
  }

  private void showErrorDialog(@Nullable String error, @Nullable String message,
      @Nullable String tag, @Nullable ErrorDialog.ErrorDialogCallback callback) {
    ErrorDialog errorDialog = ErrorDialog.newInstance(error, message);

    if (callback != null) {
      errorDialog.setCallback(callback);
    }

    errorDialog.show(fragmentManager, tag);
  }

  private boolean doPasswordCheck(@NonNull String password) {
    String passwordHash = preferenceManager.getPasswordHash();
    return BCrypt.checkpw(password, passwordHash);
  }

  private static abstract class FileCryptographyTask extends AsyncTask<Void, Void, Boolean> {

    private final Context context;
    private final List<File> files;
    private final TaskFinishedCallback callback;
    private final String progressMessage;
    private final Bus bus;

    private ProgressDialog progressDialog;

    FileCryptographyTask(@NonNull Context context, @NonNull List<File> files,
        @NonNull TaskFinishedCallback callback, @NonNull String progressMessage, @NonNull Bus bus) {
      this.context = context;
      this.files = files;
      this.callback = callback;
      this.progressMessage = progressMessage;
      this.bus = bus;
    }

    @Override final protected void onPreExecute() {
      progressDialog = new ProgressDialog(context);
      progressDialog.setCancelable(true);
      progressDialog.setMessage(progressMessage);
      progressDialog.setCanceledOnTouchOutside(false);
      progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
      progressDialog.setProgress(0);
      progressDialog.setMax(getFiles().size());
      progressDialog.show();
    }

    @Override final protected void onProgressUpdate(Void... values) {
      getProgressDialog().setProgress(1 + getProgressDialog().getProgress());
    }

    @Override protected void onCancelled(Boolean success) {
      finishedExecuting(success);
    }

    @Override protected void onPostExecute(Boolean success) {
      if (!isCancelled()) {
        progressDialog.dismiss();
      }
      finishedExecuting(success);
    }

    protected Context getContext() {
      return context;
    }

    protected List<File> getFiles() {
      return files;
    }

    protected ProgressDialog getProgressDialog() {
      return progressDialog;
    }

    protected Bus getBus() {
      return bus;
    }

    private void finishedExecuting(boolean success) {
      getBus().post(new EncryptionEvent(NONE));
      if (success) {
        callback.onSuccess();
      } else {
        callback.onError();
      }
    }

    public interface TaskFinishedCallback {
      void onSuccess();

      void onError();
    }
  }

  private static final class DecryptFilesTask extends FileCryptographyTask {

    private final File appExternalDirectory;
    private final EncryptionProvider encryptionProvider;

    DecryptFilesTask(@NonNull File appExternalDirectory,
        @NonNull EncryptionProvider encryptionProvider, @NonNull Context context,
        @NonNull List<File> files, @NonNull TaskFinishedCallback callback,
        @NonNull String progressMessage, @NonNull Bus bus) {
      super(context, files, callback, progressMessage, bus);
      this.appExternalDirectory = appExternalDirectory;
      this.encryptionProvider = encryptionProvider;
      bus.post(new EncryptionEvent(EncryptionEvent.EncryptionState.DECRYPTING));
    }

    @Override protected Boolean doInBackground(Void... params) {

      boolean success = true;

      for (File encrypted : getFiles()) {
        File unencrypted = new File(appExternalDirectory, encrypted.getName());
        try {
          encryptionProvider.decrypt(encrypted, unencrypted);
          //noinspection ResultOfMethodCallIgnored
          encrypted.delete();
        } catch (InvalidKeyException | IOException | InvalidAlgorithmParameterException e) {
          Timber.d(e, "unable to decrypt and move file %s to sdcard", encrypted.getPath());
          // Deleted the file that was put on the sdcard and was not the full file
          //noinspection ResultOfMethodCallIgnored
          unencrypted.delete();
          success = false;
        }
        publishProgress();
      }

      return success;
    }
  }

  private final static class EncryptFilesTask extends FileCryptographyTask {
    private final File appInternalUnencryptedDirectory;
    private final File appInternalEncryptedDirectory;
    private final SecureDelete secureDelete;
    private final EncryptionProvider encryptionProvider;

    EncryptFilesTask(@NonNull File appInternalUnencryptedDirectory,
        @NonNull File appInternalEncryptedDirectory, @NonNull SecureDelete secureDelete,
        @NonNull Context context, @NonNull List<File> files,
        @NonNull EncryptionProvider encryptionProvider, @NonNull TaskFinishedCallback callback,
        @NonNull String progressMessage, @NonNull Bus bus) {
      super(context, files, callback, progressMessage, bus);
      this.appInternalEncryptedDirectory = appInternalEncryptedDirectory;
      this.appInternalUnencryptedDirectory = appInternalUnencryptedDirectory;
      this.secureDelete = secureDelete;
      this.encryptionProvider = encryptionProvider;
      bus.post(new EncryptionEvent(EncryptionEvent.EncryptionState.ENCRYPTING));
    }

    @Override protected Boolean doInBackground(Void... params) {
      boolean success = true;

      for (File unencryptedFile : getFiles()) {
        File unencryptedInternal =
            new File(appInternalUnencryptedDirectory, unencryptedFile.getName());
        File encryptedFile = new File(appInternalEncryptedDirectory, unencryptedFile.getName());

        try {
          // Copy the file internally so the user can't mess with it while we are encrypting
          Files.copy(unencryptedFile, unencryptedInternal);

          // File moved internally now delete the original
          secureDelete.secureDelete(unencryptedFile);

          //noinspection ResultOfMethodCallIgnored
          encryptedFile.createNewFile();
          encryptionProvider.encrypt(unencryptedInternal, encryptedFile);

          //noinspection ResultOfMethodCallIgnored
          unencryptedInternal.delete();
        } catch (IOException | InvalidKeyException | InvalidAlgorithmParameterException e) {
          Timber.e(e, "Error encrypting and saving image");
          success = false;
        }

        publishProgress();
      }

      return success;
    }
  }
}




Java Source Code List

com.andrewreitz.encryptedcamera.EncryptedCameraApp.java
com.andrewreitz.encryptedcamera.bus.EncryptionEvent.java
com.andrewreitz.encryptedcamera.cache.ThumbnailCache.java
com.andrewreitz.encryptedcamera.di.annotation.CameraIntent.java
com.andrewreitz.encryptedcamera.di.annotation.EncryptedDirectory.java
com.andrewreitz.encryptedcamera.di.annotation.EncryptionErrorNotification.java
com.andrewreitz.encryptedcamera.di.annotation.EncryptionNotification.java
com.andrewreitz.encryptedcamera.di.annotation.ForActivity.java
com.andrewreitz.encryptedcamera.di.annotation.ForApplication.java
com.andrewreitz.encryptedcamera.di.annotation.InternalDecryptedDirectory.java
com.andrewreitz.encryptedcamera.di.annotation.MediaFormat.java
com.andrewreitz.encryptedcamera.di.annotation.UnlockNotification.java
com.andrewreitz.encryptedcamera.di.module.ActivityModule.java
com.andrewreitz.encryptedcamera.di.module.AndroidModule.java
com.andrewreitz.encryptedcamera.di.module.EncryptedCameraAppModule.java
com.andrewreitz.encryptedcamera.di.module.EncryptionModule.java
com.andrewreitz.encryptedcamera.di.module.FileSystemModule.java
com.andrewreitz.encryptedcamera.di.module.SharedPrefsModule.java
com.andrewreitz.encryptedcamera.encryption.EncryptionProviderImplTest.java
com.andrewreitz.encryptedcamera.encryption.EncryptionProviderImpl.java
com.andrewreitz.encryptedcamera.encryption.EncryptionProvider.java
com.andrewreitz.encryptedcamera.encryption.FullEncryptionTest.java
com.andrewreitz.encryptedcamera.encryption.KeyManagerImplTest.java
com.andrewreitz.encryptedcamera.encryption.KeyManagerImpl.java
com.andrewreitz.encryptedcamera.encryption.KeyManager.java
com.andrewreitz.encryptedcamera.exception.SDCardException.java
com.andrewreitz.encryptedcamera.externalstoreage.ExternalStorageManagerImpl.java
com.andrewreitz.encryptedcamera.externalstoreage.ExternalStorageManager.java
com.andrewreitz.encryptedcamera.filesystem.SecureDeleteImplTest.java
com.andrewreitz.encryptedcamera.filesystem.SecureDeleteImpl.java
com.andrewreitz.encryptedcamera.filesystem.SecureDelete.java
com.andrewreitz.encryptedcamera.image.ImageRotation.java
com.andrewreitz.encryptedcamera.logging.CrashlyticsTree.java
com.andrewreitz.encryptedcamera.service.EncryptionIntentService.java
com.andrewreitz.encryptedcamera.sharedpreference.AppPreferenceManagerTest.java
com.andrewreitz.encryptedcamera.sharedpreference.AppPreferenceManager.java
com.andrewreitz.encryptedcamera.sharedpreference.DefaultSharedPreferenceService.java
com.andrewreitz.encryptedcamera.sharedpreference.SharedPreferenceService.java
com.andrewreitz.encryptedcamera.ui.activity.AboutActivity.java
com.andrewreitz.encryptedcamera.ui.activity.BaseActivity.java
com.andrewreitz.encryptedcamera.ui.activity.CameraActivity.java
com.andrewreitz.encryptedcamera.ui.activity.GalleryActivity.java
com.andrewreitz.encryptedcamera.ui.activity.SettingsActivity.java
com.andrewreitz.encryptedcamera.ui.adapter.BindableAdapter.java
com.andrewreitz.encryptedcamera.ui.adapter.GalleryAdapter.java
com.andrewreitz.encryptedcamera.ui.controller.ActivityController.java
com.andrewreitz.encryptedcamera.ui.dialog.ErrorDialog.java
com.andrewreitz.encryptedcamera.ui.dialog.FirstRunDialog.java
com.andrewreitz.encryptedcamera.ui.dialog.PasswordDialog.java
com.andrewreitz.encryptedcamera.ui.dialog.SetPasswordDialog.java
com.andrewreitz.encryptedcamera.ui.fragment.AppPreferenceFragment.java
com.andrewreitz.encryptedcamera.ui.fragment.BaseFragment.java
com.andrewreitz.encryptedcamera.ui.fragment.GalleryFragment.java