diff --git a/examples/StoreEncryptionPassword/.gitignore b/examples/StoreEncryptionPassword/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/examples/StoreEncryptionPassword/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/examples/StoreEncryptionPassword/build.gradle b/examples/StoreEncryptionPassword/build.gradle
new file mode 100644
index 0000000000..f620101080
--- /dev/null
+++ b/examples/StoreEncryptionPassword/build.gradle
@@ -0,0 +1,30 @@
+apply plugin: 'com.android.application'
+apply plugin: 'realm-android'
+
+android {
+ compileSdkVersion 23
+ buildToolsVersion "23.0.3"
+
+ defaultConfig {
+ applicationId "realm.io.storeencryptionpassword"
+ minSdkVersion 23
+ targetSdkVersion 23
+ versionCode 1
+ versionName "1.0"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ testCompile 'junit:junit:4.12'
+ //noinspection GradleDependency
+ compile 'com.android.support:appcompat-v7:23.1.1'
+ //noinspection GradleDependency
+ compile 'com.android.support:design:23.1.1'
+}
diff --git a/examples/StoreEncryptionPassword/lint.xml b/examples/StoreEncryptionPassword/lint.xml
new file mode 100644
index 0000000000..a1b63af0fd
--- /dev/null
+++ b/examples/StoreEncryptionPassword/lint.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/examples/StoreEncryptionPassword/proguard-rules.pro b/examples/StoreEncryptionPassword/proguard-rules.pro
new file mode 100644
index 0000000000..740907a636
--- /dev/null
+++ b/examples/StoreEncryptionPassword/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/Nabil/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/examples/StoreEncryptionPassword/src/androidTest/java/realm/io/storeencryptionpassword/ApplicationTest.java b/examples/StoreEncryptionPassword/src/androidTest/java/realm/io/storeencryptionpassword/ApplicationTest.java
new file mode 100644
index 0000000000..d8b6c593e0
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/androidTest/java/realm/io/storeencryptionpassword/ApplicationTest.java
@@ -0,0 +1,13 @@
+package realm.io.storeencryptionpassword;
+
+import android.app.Application;
+import android.test.ApplicationTestCase;
+
+/**
+ * Testing Fundamentals
+ */
+public class ApplicationTest extends ApplicationTestCase {
+ public ApplicationTest() {
+ super(Application.class);
+ }
+}
\ No newline at end of file
diff --git a/examples/StoreEncryptionPassword/src/main/AndroidManifest.xml b/examples/StoreEncryptionPassword/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..7074c0c425
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/MainActivity.java b/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/MainActivity.java
new file mode 100644
index 0000000000..2a5e87c890
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/MainActivity.java
@@ -0,0 +1,119 @@
+package realm.io.storeencryptionpassword;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.View;
+import android.widget.Button;
+import android.widget.Toast;
+
+import java.util.Arrays;
+
+import io.realm.Realm;
+import io.realm.RealmConfiguration;
+
+public class MainActivity extends AppCompatActivity {
+ public static final int REQ_UNLOCK = 1;
+
+ private Button mBtnUnlock;
+ private Button mBtnLock;
+ private View mBtnOpen;
+
+ private final Store store = new Store(this);
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ mBtnUnlock = (Button) findViewById(R.id.btnUnLock);
+ mBtnLock = (Button) findViewById(R.id.btnLock);
+
+ //TODO use this one RealmConfiguration realmConfig = new RealmConfiguration.Builder(this).encryptionKey(realmKey).build();
+ RealmConfiguration realmConfig = new RealmConfiguration.Builder(MainActivity.this).build();
+ Realm.setDefaultConfiguration(realmConfig);
+
+ mBtnUnlock.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ store.unlockKeyStore(REQ_UNLOCK);
+ }
+ });
+
+ mBtnLock.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mBtnLock.setEnabled(false);
+ Toast.makeText(MainActivity.this, "Locking ...", Toast.LENGTH_SHORT).show();
+ Realm.setDefaultConfiguration(new RealmConfiguration.Builder(MainActivity.this).build());
+ mBtnUnlock.setEnabled(true);
+ }
+ });
+
+ //noinspection ConstantConditions
+ mBtnOpen = findViewById(R.id.btnOpenList);
+ mBtnOpen.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ goToList();
+ }
+ });
+
+ mBtnOpen.setEnabled(store.getEncryptedRealmKey() != null && store.containsEncryptionKey());
+
+ mBtnUnlock.setEnabled(true);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case REQ_UNLOCK:
+ if (store.onUnlockKeyStoreResult(resultCode, data)) {
+ onKeystoreUnlocked();
+ }
+ break;
+ default:
+ super.onActivityResult(requestCode, resultCode, data);
+ break;
+ }
+ }
+
+ private void onKeystoreUnlocked() {
+ byte[] encryptedRealmKey = store.getEncryptedRealmKey();
+ if (encryptedRealmKey == null || !store.containsEncryptionKey()) {
+ final byte[] realmKey = store.generateKeyForRealm();
+ store.generateKeyInKeystore();
+ encryptedRealmKey = store.encryptAndSaveKeyForRealm(realmKey);
+
+ final RealmConfiguration realmConfig = new RealmConfiguration.Builder(MainActivity.this)
+ .encryptionKey(realmKey)
+ .build();
+ Arrays.fill(realmKey, (byte) 0);
+
+ // create encrypted Realm
+ Realm.deleteRealm(realmConfig);
+ Realm.getInstance(realmConfig).close();
+
+ mBtnOpen.setEnabled(true);
+ }
+
+ Toast.makeText(MainActivity.this, "Unlocking ...", Toast.LENGTH_SHORT).show();
+ mBtnUnlock.setEnabled(false);
+
+ final byte[] realmKey = store.decryptKeyForRealm(encryptedRealmKey);
+
+ RealmConfiguration realmConfig = new RealmConfiguration.Builder(MainActivity.this).encryptionKey(realmKey).build();
+ Realm.setDefaultConfiguration(realmConfig);
+
+ mBtnLock.setEnabled(true);
+ }
+
+ private void goToList () {
+ //start Todo list
+ Intent intent = new Intent(MainActivity.this, SecretTodoList.class);
+ startActivity(intent);
+ }
+}
diff --git a/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/MyAdapter.java b/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/MyAdapter.java
new file mode 100644
index 0000000000..dcfa1211f1
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/MyAdapter.java
@@ -0,0 +1,43 @@
+package realm.io.storeencryptionpassword;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+
+import io.realm.OrderedRealmCollection;
+import io.realm.RealmBaseAdapter;
+import realm.io.storeencryptionpassword.model.TodoItem;
+
+class MyAdapter extends RealmBaseAdapter implements ListAdapter {
+
+ private static class ViewHolder {
+ TextView name;
+ }
+
+ public MyAdapter(Context context, OrderedRealmCollection realmResults) {
+ super(context, realmResults, true);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ViewHolder viewHolder;
+ if (convertView == null) {
+ convertView = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
+ viewHolder = new ViewHolder();
+ viewHolder.name = (TextView) convertView.findViewById(android.R.id.text1);
+ convertView.setTag(viewHolder);
+ } else {
+ viewHolder = (ViewHolder) convertView.getTag();
+ }
+
+ TodoItem item = adapterData.get(position);
+ viewHolder.name.setText(item.getName());
+ return convertView;
+ }
+
+ public OrderedRealmCollection getAdapterData() {
+ return adapterData;
+ }
+}
diff --git a/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/SecretTodoList.java b/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/SecretTodoList.java
new file mode 100644
index 0000000000..8d4c58010e
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/SecretTodoList.java
@@ -0,0 +1,79 @@
+package realm.io.storeencryptionpassword;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Message;
+import android.support.design.widget.FloatingActionButton;
+import android.support.design.widget.Snackbar;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Toast;
+
+import java.util.Random;
+
+import io.realm.Realm;
+import io.realm.RealmResults;
+import realm.io.storeencryptionpassword.model.TodoItem;
+
+public class SecretTodoList extends ListActivity {
+
+ private Realm realm;
+ private Random random;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ random = new Random();
+
+ realm = getRealm();
+ if (realm == null) {
+ finish();
+ return;
+ }
+ RealmResults todos = realm.where(TodoItem.class).findAll();
+ setContentView(R.layout.secret_todo);
+ final MyAdapter adapter = new MyAdapter(this, todos);
+ getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
+ @Override
+ public boolean onItemLongClick(AdapterView> adapterView, View view, int i, long l) {
+ TodoItem timeStamp = adapter.getAdapterData().get(i);
+ realm.beginTransaction();
+ timeStamp.deleteFromRealm();
+ realm.commitTransaction();
+ return true;
+ }
+ });
+
+ FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
+ fab.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ realm.beginTransaction();
+ TodoItem todoItem = realm.createObject(TodoItem.class);
+ todoItem.setName("Item " + random.nextInt());
+ realm.commitTransaction();
+ }
+ });
+
+ setListAdapter(adapter);
+ }
+
+ private Realm getRealm() {
+ try {
+ return Realm.getDefaultInstance();
+ } catch (IllegalArgumentException e) {
+ Toast.makeText(this, "Please unlock Realm first.", Toast.LENGTH_SHORT).show();
+ return null;
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (realm != null) {
+ realm.close();
+ }
+ }
+}
diff --git a/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/SharedPrefUtils.java b/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/SharedPrefUtils.java
new file mode 100644
index 0000000000..c2114fc504
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/SharedPrefUtils.java
@@ -0,0 +1,45 @@
+package realm.io.storeencryptionpassword;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.Base64;
+
+public final class SharedPrefUtils {
+ private static final String PREF_NAME = "realm_key";
+ private static final String KEY = "iv_and_encrypted_key";
+
+ public static void save(Context context, byte[] ivAndEncryptedKey) {
+ getPreference(context).edit()
+ .putString(KEY, encode(ivAndEncryptedKey))
+ .apply();
+ }
+
+ public static byte[] load(Context context) {
+ final SharedPreferences pref = getPreference(context);
+
+ final String ivAndEncryptedKey = pref.getString(KEY, null);
+ if (ivAndEncryptedKey == null) {
+ return null;
+ }
+
+ return decode(ivAndEncryptedKey);
+ }
+
+ private static String encode(byte[] data) {
+ if (data == null) {
+ return null;
+ }
+ return Base64.encodeToString(data, Base64.NO_WRAP);
+ }
+
+ private static byte[] decode(String encodedData) {
+ if (encodedData == null) {
+ return null;
+ }
+ return Base64.decode(encodedData, Base64.DEFAULT);
+ }
+
+ private static SharedPreferences getPreference(Context context) {
+ return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
+ }
+}
diff --git a/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/Store.java b/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/Store.java
new file mode 100644
index 0000000000..3117ed7155
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/Store.java
@@ -0,0 +1,187 @@
+package realm.io.storeencryptionpassword;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.Intent;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+
+import io.realm.RealmConfiguration;
+
+public class Store {
+ private static final String KEYSTORE_PROVIDER_NAME = "AndroidKeyStore";
+ private static final String KEY_ALIAS = "realm_key";
+ private static final String TRANSFORMATION = KeyProperties.KEY_ALGORITHM_AES
+ + "/" + KeyProperties.BLOCK_MODE_CBC
+ + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7;
+ private static final int AUTH_VALID_DURATION_IN_SECOND = 30;
+
+ private static final ByteOrder ORDER_FOR_ENCRYPTED_DATA = ByteOrder.BIG_ENDIAN;
+
+ private final Activity context;
+ private final SecureRandom rng = new SecureRandom();
+ private final KeyStore keyStore = prepareKeyStore();
+
+ public Store(Activity context) {
+ this.context = context;
+ }
+
+ public boolean containsEncryptionKey() {
+ try {
+ return keyStore.containsAlias(KEY_ALIAS);
+ } catch (KeyStoreException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void unlockKeyStore(int requestCode) {
+ final Intent intent = getKeyguardManager().createConfirmDeviceCredentialIntent("Android Keystore System",
+ "unlock keystore to decrypt Realm database.");
+ context.startActivityForResult(intent, requestCode);
+ }
+
+ public boolean onUnlockKeyStoreResult(int result, Intent data) {
+ return result == Activity.RESULT_OK;
+ }
+
+ public byte[] generateKeyForRealm() {
+ final byte[] keyForRealm = new byte[RealmConfiguration.KEY_LENGTH];
+ rng.nextBytes(keyForRealm);
+ return keyForRealm;
+ }
+
+ public void generateKeyInKeystore() {
+ final KeyGenerator keyGenerator;
+ try {
+ keyGenerator = KeyGenerator.getInstance(
+ KeyProperties.KEY_ALGORITHM_AES,
+ KEYSTORE_PROVIDER_NAME);
+ } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
+ throw new RuntimeException(e);
+ }
+
+ final KeyGenParameterSpec keySpec = new KeyGenParameterSpec.Builder(
+ KEY_ALIAS,
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
+ .setUserAuthenticationRequired(true)
+ .setUserAuthenticationValidityDurationSeconds(
+ AUTH_VALID_DURATION_IN_SECOND)
+ .build();
+ try {
+ keyGenerator.init(keySpec);
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new RuntimeException(e);
+ }
+ keyGenerator.generateKey();
+
+ }
+
+ public byte[] encryptAndSaveKeyForRealm(byte[] keyForRealm) {
+ final KeyStore ks = prepareKeyStore();
+ final Cipher cipher = prepareCipher();
+
+ final byte[] iv;
+ final byte[] encryptedKeyForRealm;
+ try {
+ final SecretKey key = (SecretKey) ks.getKey(KEY_ALIAS, null);
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+
+ encryptedKeyForRealm = cipher.doFinal(keyForRealm);
+ iv = cipher.getIV();
+ } catch (InvalidKeyException | UnrecoverableKeyException | NoSuchAlgorithmException
+ | KeyStoreException | BadPaddingException | IllegalBlockSizeException e) {
+ throw new RuntimeException("key for encryption is invalid", e);
+ }
+ final byte[] ivAndEncryptedKey = new byte[Integer.BYTES + iv.length + encryptedKeyForRealm.length];
+
+ final ByteBuffer buffer = ByteBuffer.wrap(ivAndEncryptedKey);
+ buffer.order(ORDER_FOR_ENCRYPTED_DATA);
+ buffer.putInt(iv.length);
+ buffer.put(iv);
+ buffer.put(encryptedKeyForRealm);
+
+ SharedPrefUtils.save(context, ivAndEncryptedKey);
+
+ return ivAndEncryptedKey;
+ }
+
+ public byte[] decryptKeyForRealm(byte[] ivAndEncryptedKey) {
+ final Cipher cipher = prepareCipher();
+ final KeyStore keyStore = prepareKeyStore();
+
+ final ByteBuffer buffer = ByteBuffer.wrap(ivAndEncryptedKey);
+ buffer.order(ORDER_FOR_ENCRYPTED_DATA);
+
+ final int ivLength = buffer.getInt();
+ final byte[] iv = new byte[ivLength];
+ final byte[] encryptedKey = new byte[ivAndEncryptedKey.length - Integer.BYTES - ivLength];
+
+ buffer.get(iv);
+ buffer.get(encryptedKey);
+
+ try {
+ final SecretKey key = (SecretKey) keyStore.getKey(KEY_ALIAS, null);
+ final IvParameterSpec ivSpec = new IvParameterSpec(iv);
+ cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
+
+ return cipher.doFinal(encryptedKey);
+ } catch (InvalidKeyException e) {
+ throw new RuntimeException("key is invalid.");
+ } catch (UnrecoverableKeyException | NoSuchAlgorithmException | BadPaddingException
+ | KeyStoreException | IllegalBlockSizeException | InvalidAlgorithmParameterException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public byte[] getEncryptedRealmKey() {
+ return SharedPrefUtils.load(context);
+ }
+
+ private KeyStore prepareKeyStore() {
+ try {
+ KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER_NAME);
+ ks.load(null);
+ return ks;
+ } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Cipher prepareCipher() {
+ final Cipher cipher;
+ try {
+ cipher = Cipher.getInstance(TRANSFORMATION);
+ } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
+ throw new RuntimeException(e);
+ }
+ return cipher;
+ }
+
+ private KeyguardManager getKeyguardManager() {
+ return (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
+ }
+}
diff --git a/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/model/TodoItem.java b/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/model/TodoItem.java
new file mode 100644
index 0000000000..5bc86a86da
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/java/realm/io/storeencryptionpassword/model/TodoItem.java
@@ -0,0 +1,25 @@
+package realm.io.storeencryptionpassword.model;
+import io.realm.RealmObject;
+/**
+ * Created by Nabil on 12/04/2016.
+ */
+public class TodoItem extends RealmObject {
+ private String name;
+ private boolean isDone;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isDone() {
+ return isDone;
+ }
+
+ public void setIsDone(boolean isDone) {
+ this.isDone = isDone;
+ }
+}
diff --git a/examples/StoreEncryptionPassword/src/main/res/layout/activity_main.xml b/examples/StoreEncryptionPassword/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000000..1063c5204d
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/res/layout/activity_main.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/StoreEncryptionPassword/src/main/res/layout/content_main.xml b/examples/StoreEncryptionPassword/src/main/res/layout/content_main.xml
new file mode 100644
index 0000000000..ab44a26018
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/res/layout/content_main.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/StoreEncryptionPassword/src/main/res/layout/secret_todo.xml b/examples/StoreEncryptionPassword/src/main/res/layout/secret_todo.xml
new file mode 100644
index 0000000000..63cebb3a53
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/res/layout/secret_todo.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
diff --git a/examples/StoreEncryptionPassword/src/main/res/layout/secret_todo_list.xml b/examples/StoreEncryptionPassword/src/main/res/layout/secret_todo_list.xml
new file mode 100644
index 0000000000..674c559a22
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/res/layout/secret_todo_list.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/StoreEncryptionPassword/src/main/res/mipmap-hdpi/ic_launcher.png b/examples/StoreEncryptionPassword/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000000..cde69bccce
Binary files /dev/null and b/examples/StoreEncryptionPassword/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/examples/StoreEncryptionPassword/src/main/res/mipmap-mdpi/ic_launcher.png b/examples/StoreEncryptionPassword/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000000..c133a0cbd3
Binary files /dev/null and b/examples/StoreEncryptionPassword/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/examples/StoreEncryptionPassword/src/main/res/mipmap-xhdpi/ic_launcher.png b/examples/StoreEncryptionPassword/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000000..bfa42f0e7b
Binary files /dev/null and b/examples/StoreEncryptionPassword/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/examples/StoreEncryptionPassword/src/main/res/mipmap-xxhdpi/ic_launcher.png b/examples/StoreEncryptionPassword/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..324e72cdd7
Binary files /dev/null and b/examples/StoreEncryptionPassword/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/examples/StoreEncryptionPassword/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/examples/StoreEncryptionPassword/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..aee44e1384
Binary files /dev/null and b/examples/StoreEncryptionPassword/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/examples/StoreEncryptionPassword/src/main/res/values-v21/styles.xml b/examples/StoreEncryptionPassword/src/main/res/values-v21/styles.xml
new file mode 100644
index 0000000000..251fb9fb74
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/res/values-v21/styles.xml
@@ -0,0 +1,9 @@
+>
+
+
+
diff --git a/examples/StoreEncryptionPassword/src/main/res/values-w820dp/dimens.xml b/examples/StoreEncryptionPassword/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000000..63fc816444
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 64dp
+
diff --git a/examples/StoreEncryptionPassword/src/main/res/values/colors.xml b/examples/StoreEncryptionPassword/src/main/res/values/colors.xml
new file mode 100644
index 0000000000..3ab3e9cbce
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
diff --git a/examples/StoreEncryptionPassword/src/main/res/values/dimens.xml b/examples/StoreEncryptionPassword/src/main/res/values/dimens.xml
new file mode 100644
index 0000000000..812cb7be0a
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/res/values/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 16dp
+ 16dp
+ 16dp
+
diff --git a/examples/StoreEncryptionPassword/src/main/res/values/strings.xml b/examples/StoreEncryptionPassword/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..0202c6059a
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/res/values/strings.xml
@@ -0,0 +1,7 @@
+
+ StoreEncryptionPassword
+ No data
+ Unlock
+ Lock
+ Open List
+
diff --git a/examples/StoreEncryptionPassword/src/main/res/values/styles.xml b/examples/StoreEncryptionPassword/src/main/res/values/styles.xml
new file mode 100644
index 0000000000..545b9c6d2c
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/StoreEncryptionPassword/src/test/java/realm/io/storeencryptionpassword/ExampleUnitTest.java b/examples/StoreEncryptionPassword/src/test/java/realm/io/storeencryptionpassword/ExampleUnitTest.java
new file mode 100644
index 0000000000..33576d8df3
--- /dev/null
+++ b/examples/StoreEncryptionPassword/src/test/java/realm/io/storeencryptionpassword/ExampleUnitTest.java
@@ -0,0 +1,15 @@
+package realm.io.storeencryptionpassword;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * To work on unit tests, switch the Test Artifact in the Build Variants view.
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/examples/settings.gradle b/examples/settings.gradle
index 529a4f486c..944c7a382e 100644
--- a/examples/settings.gradle
+++ b/examples/settings.gradle
@@ -1,3 +1,4 @@
+include 'StoreEncryptionPassword'
include 'adapterExample'
include 'encryptionExample'
include 'gridViewExample'