diff --git a/mifosng-android/src/main/AndroidManifest.xml b/mifosng-android/src/main/AndroidManifest.xml
index b3798e825bc..a669f26ebbd 100755
--- a/mifosng-android/src/main/AndroidManifest.xml
+++ b/mifosng-android/src/main/AndroidManifest.xml
@@ -132,6 +132,10 @@
android:label="@string/sync_savingsaccounttransactions"
android:screenOrientation="portrait"/>
+
diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/SplashScreenActivity.java b/mifosng-android/src/main/java/com/mifos/mifosxdroid/SplashScreenActivity.java
index dd5441745ca..1ca5db30bea 100755
--- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/SplashScreenActivity.java
+++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/SplashScreenActivity.java
@@ -12,6 +12,7 @@
import com.mifos.mifosxdroid.core.MifosBaseActivity;
import com.mifos.mifosxdroid.login.LoginActivity;
import com.mifos.mifosxdroid.online.DashboardActivity;
+import com.mifos.utils.ForegroundChecker;
import com.mifos.utils.PrefManager;
@@ -24,6 +25,7 @@ public class SplashScreenActivity extends MifosBaseActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
+ ForegroundChecker.init();
if (!PrefManager.isAuthenticated()) {
PrefManager.setInstanceUrl(BaseUrl.PROTOCOL_HTTPS
+ BaseUrl.API_ENDPOINT + BaseUrl.API_PATH);
diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/core/MifosBaseActivity.java b/mifosng-android/src/main/java/com/mifos/mifosxdroid/core/MifosBaseActivity.java
index c89b91fcf1c..40762ce3513 100755
--- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/core/MifosBaseActivity.java
+++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/core/MifosBaseActivity.java
@@ -24,13 +24,16 @@
import com.mifos.mifosxdroid.injection.component.ActivityComponent;
import com.mifos.mifosxdroid.injection.component.DaggerActivityComponent;
import com.mifos.mifosxdroid.injection.module.ActivityModule;
+import com.mifos.mifosxdroid.passcode.PassCodeActivity;
import com.mifos.utils.Constants;
+import com.mifos.utils.ForegroundChecker;
import com.mifos.utils.PrefManager;
/**
* @author fomenkoo
*/
-public class MifosBaseActivity extends AppCompatActivity implements BaseActivityCallback {
+public class MifosBaseActivity extends AppCompatActivity implements BaseActivityCallback,
+ ForegroundChecker.Listener {
protected Toolbar toolbar;
private ActivityComponent mActivityComponent;
@@ -128,8 +131,12 @@ public void hideKeyboard(View view) {
@Override
public void logout() {
- PrefManager.clearPrefs();
- startActivity(new Intent(this, SplashScreenActivity.class));
+ if (PrefManager.getPassCodeStatus()) {
+ startActivity(new Intent(this, PassCodeActivity.class));
+ } else {
+ PrefManager.clearPrefs();
+ startActivity(new Intent(this, SplashScreenActivity.class));
+ }
finish();
}
@@ -158,4 +165,24 @@ public void clearFragmentBackStack() {
fm.popBackStack(backStackId, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ ForegroundChecker.get().addListener(this);
+ ForegroundChecker.get().onActivityResumed();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ ForegroundChecker.get().onActivityPaused();
+ }
+
+ @Override
+ public void onBecameForeground() {
+ Intent intent = new Intent(this, PassCodeActivity.class);
+ intent.putExtra(Constants.INTIAL_LOGIN, false);
+ startActivity(intent);
+ }
}
diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/injection/component/ActivityComponent.java b/mifosng-android/src/main/java/com/mifos/mifosxdroid/injection/component/ActivityComponent.java
index 47a300e3382..ac8426f2a4e 100644
--- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/injection/component/ActivityComponent.java
+++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/injection/component/ActivityComponent.java
@@ -57,6 +57,7 @@
import com.mifos.mifosxdroid.online.search.SearchFragment;
import com.mifos.mifosxdroid.online.surveylist.SurveyListFragment;
import com.mifos.mifosxdroid.online.surveysubmit.SurveySubmitFragment;
+import com.mifos.mifosxdroid.passcode.PassCodeActivity;
import dagger.Component;
@@ -70,6 +71,8 @@ public interface ActivityComponent {
void inject(LoginActivity loginActivity);
+ void inject(PassCodeActivity passCodeActivity);
+
void inject(CenterListFragment centerListFragment);
void inject(ClientChargeFragment clientChargeFragment);
diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/login/LoginActivity.java b/mifosng-android/src/main/java/com/mifos/mifosxdroid/login/LoginActivity.java
index b8529aa0316..677fa051bbb 100755
--- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/login/LoginActivity.java
+++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/login/LoginActivity.java
@@ -24,7 +24,9 @@
import com.mifos.mifosxdroid.core.MifosBaseActivity;
import com.mifos.mifosxdroid.core.util.Toaster;
import com.mifos.mifosxdroid.online.DashboardActivity;
+import com.mifos.mifosxdroid.passcode.PassCodeActivity;
import com.mifos.objects.user.User;
+import com.mifos.utils.Constants;
import com.mifos.utils.Network;
import com.mifos.utils.PrefManager;
import com.mifos.utils.ValidationUtil;
@@ -180,7 +182,13 @@ public void onLoginSuccessful(User user) {
Toast.makeText(this, getString(R.string.toast_welcome) + " " + user.getUsername(),
Toast.LENGTH_SHORT).show();
- startActivity(new Intent(this, DashboardActivity.class));
+ if (PrefManager.getPassCodeStatus()) {
+ startActivity(new Intent(this, DashboardActivity.class));
+ } else {
+ Intent intent = new Intent(this, PassCodeActivity.class);
+ intent.putExtra(Constants.INTIAL_LOGIN, true);
+ startActivity(intent);
+ }
finish();
}
diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/passcode/PassCodeActivity.java b/mifosng-android/src/main/java/com/mifos/mifosxdroid/passcode/PassCodeActivity.java
new file mode 100644
index 00000000000..3754f9303f7
--- /dev/null
+++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/passcode/PassCodeActivity.java
@@ -0,0 +1,222 @@
+package com.mifos.mifosxdroid.passcode;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.widget.NestedScrollView;
+import android.support.v7.widget.AppCompatButton;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.mifos.mifosxdroid.R;
+import com.mifos.mifosxdroid.core.MifosBaseActivity;
+import com.mifos.mifosxdroid.core.util.Toaster;
+import com.mifos.mifosxdroid.login.LoginActivity;
+import com.mifos.mifosxdroid.online.DashboardActivity;
+import com.mifos.utils.Constants;
+import com.mifos.utils.EncryptionUtil;
+import com.mifos.utils.Network;
+import com.mifos.utils.PassCodeView;
+import com.mifos.utils.PrefManager;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnClick;
+
+public class PassCodeActivity extends MifosBaseActivity {
+
+ @BindView(R.id.cl_rootview)
+ NestedScrollView clRootview;
+
+ @BindView(R.id.btn_login)
+ AppCompatButton btnLogin;
+
+ @BindView(R.id.btn_forgot_passcode)
+ AppCompatButton btnForgotPasscode;
+
+ @BindView(R.id.pv_passcode)
+ PassCodeView passCodeView;
+
+ @BindView(R.id.btn_skip)
+ AppCompatButton btnSkip;
+
+ @BindView(R.id.btn_save)
+ AppCompatButton btnSave;
+
+ @BindView(R.id.tv_passcode)
+ TextView tvPasscodeIntro;
+
+ @BindView(R.id.iv_visibility)
+ ImageView ivVisibility;
+
+ private int counter = 0;
+ private boolean isInitialScreen;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_pass_code);
+ getActivityComponent().inject(this);
+ ButterKnife.bind(this);
+
+ isInitialScreen = getIntent().getBooleanExtra(Constants.INTIAL_LOGIN, false);
+
+ if (PrefManager.getPassCodeStatus()) {
+ btnSkip.setVisibility(View.GONE);
+ btnSave.setVisibility(View.GONE);
+ tvPasscodeIntro.setVisibility(View.GONE);
+ btnLogin.setVisibility(View.VISIBLE);
+ btnForgotPasscode.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @OnClick(R.id.btn_skip)
+ public void skip() {
+ startDashBoardActivity();
+ }
+
+ @OnClick(R.id.btn_save)
+ public void savePassCode() {
+ if (isPassCodeLengthCorrect()) {
+ PrefManager.setPassCode(EncryptionUtil.getHash(passCodeView.getPasscode()));
+ startDashBoardActivity();
+ }
+ }
+
+ @OnClick(R.id.btn_login)
+ public void loginUsingPassCode() {
+
+ if (!isInternetAvailable()) {
+ return;
+ }
+
+ if (counter == 3) {
+ Toaster.show(clRootview, R.string.incorrect_passcode_more_than_three);
+ PrefManager.clearPrefs();
+ startLoginActivity();
+ return;
+ }
+
+ if (isPassCodeLengthCorrect()) {
+ String passwordEntered = EncryptionUtil.getHash(passCodeView.getPasscode());
+ if (PrefManager.getPassCode().equals(passwordEntered)) {
+ startDashBoardActivity();
+ } else {
+ counter++;
+ passCodeView.clearPasscodeField();
+ Toaster.show(clRootview, R.string.incorrect_passcode);
+ }
+ }
+ }
+
+ @OnClick(R.id.btn_forgot_passcode)
+ public void forgotPassCode() {
+ PrefManager.clearPrefs();
+ startLoginActivity();
+ }
+
+ private boolean isInternetAvailable() {
+ if (Network.isOnline(this)) {
+ return true;
+ } else {
+ Toaster.show(clRootview, getString(R.string.error_not_connected_internet));
+ return false;
+ }
+ }
+
+ @OnClick(R.id.btn_one)
+ public void clickedOne() {
+ passCodeView.enterCode(getString(R.string.one));
+ }
+
+ @OnClick(R.id.btn_two)
+ public void clickedTwo() {
+ passCodeView.enterCode(getString(R.string.two));
+ }
+
+ @OnClick(R.id.btn_three)
+ public void clickedThree() {
+ passCodeView.enterCode(getString(R.string.three));
+ }
+
+ @OnClick(R.id.btn_four)
+ public void clickedFour() {
+ passCodeView.enterCode(getString(R.string.four));
+ }
+
+ @OnClick(R.id.btn_five)
+ public void clickedFive() {
+ passCodeView.enterCode(getString(R.string.five));
+ }
+
+ @OnClick(R.id.btn_six)
+ public void clickedSix() {
+ passCodeView.enterCode(getString(R.string.six));
+ }
+
+ @OnClick(R.id.btn_seven)
+ public void clickedSeven() {
+ passCodeView.enterCode(getString(R.string.seven));
+ }
+
+ @OnClick(R.id.btn_eight)
+ public void clickedEight() {
+ passCodeView.enterCode(getString(R.string.eight));
+ }
+
+ @OnClick(R.id.btn_nine)
+ public void clickedNine() {
+ passCodeView.enterCode(getString(R.string.nine));
+ }
+
+ @OnClick(R.id.btn_zero)
+ public void clickedZero() {
+ passCodeView.enterCode(getString(R.string.zero));
+ }
+
+ @OnClick(R.id.btn_back)
+ public void clickedBackSpace() {
+ passCodeView.backSpace();
+ }
+
+ @OnClick(R.id.iv_visibility)
+ public void visibilityChange() {
+ passCodeView.revertPassCodeVisibility();
+ if (!passCodeView.passcodeVisible()) {
+ ivVisibility.setColorFilter(ContextCompat.getColor(PassCodeActivity.this,
+ R.color.light_grey));
+ } else {
+ ivVisibility.setColorFilter(ContextCompat.getColor(PassCodeActivity.this,
+ R.color.gray_dark));
+ }
+ }
+ private boolean isPassCodeLengthCorrect() {
+ if (passCodeView.getPasscode().length() == 4) {
+ return true;
+ }
+ Toaster.show(clRootview, getString(R.string.error_passcode));
+ return false;
+ }
+
+ private void startDashBoardActivity() {
+ startActivity(new Intent(this, DashboardActivity.class));
+ finish();
+ }
+
+ private void startLoginActivity() {
+ Intent i = new Intent(PassCodeActivity.this, LoginActivity.class);
+ i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ startActivity(i);
+ finish();
+ }
+
+ @Override
+ public void onBackPressed() {
+ //enabling back press only for initial login.
+ if (isInitialScreen) {
+ super.onBackPressed();
+ }
+ }
+}
diff --git a/mifosng-android/src/main/java/com/mifos/utils/Constants.java b/mifosng-android/src/main/java/com/mifos/utils/Constants.java
index 6cb2403610e..6a043398066 100755
--- a/mifosng-android/src/main/java/com/mifos/utils/Constants.java
+++ b/mifosng-android/src/main/java/com/mifos/utils/Constants.java
@@ -133,6 +133,8 @@ public class Constants {
public static final String ACTIVATE_TYPE = "activation_type";
+ public static final String INTIAL_LOGIN = "initial_login";
+
//This needs to be 8 bits because validateRequestPermissionsRequestCode
// in FragmentActivity requires requestCode to be of 8 bits, meaning the range is from 0 to 255.
public static final int REQUEST_PERMISSION_SETTING = 254;
diff --git a/mifosng-android/src/main/java/com/mifos/utils/EncryptionUtil.java b/mifosng-android/src/main/java/com/mifos/utils/EncryptionUtil.java
new file mode 100644
index 00000000000..48c44d3016f
--- /dev/null
+++ b/mifosng-android/src/main/java/com/mifos/utils/EncryptionUtil.java
@@ -0,0 +1,24 @@
+package com.mifos.utils;
+
+import android.util.Log;
+
+/**
+ * Created by mayankjindal on 30/06/17.
+ */
+
+public class EncryptionUtil {
+
+ static {
+ try {
+ System.loadLibrary("encryption");
+ } catch (UnsatisfiedLinkError e) {
+ Log.e("LoadJniLib", "Error: Could not load native library: " + e.getMessage());
+ }
+ }
+
+ private static final native String getPassCodeHash(String passcode);
+
+ public static String getHash(String passCode) {
+ return getPassCodeHash(passCode);
+ }
+}
diff --git a/mifosng-android/src/main/java/com/mifos/utils/ForegroundChecker.java b/mifosng-android/src/main/java/com/mifos/utils/ForegroundChecker.java
new file mode 100644
index 00000000000..f9b175f2247
--- /dev/null
+++ b/mifosng-android/src/main/java/com/mifos/utils/ForegroundChecker.java
@@ -0,0 +1,94 @@
+package com.mifos.utils;
+
+import android.os.Handler;
+
+/**
+ * Created by mayankjindal on 18/07/17.
+ */
+
+public class ForegroundChecker {
+ public static final long CHECK_DELAY = 500;
+ public static final int MIN_BACKGROUND_THRESHOLD = 5;
+ public static final String TAG = ForegroundChecker.class.getName();
+
+ public interface Listener {
+ public void onBecameForeground();
+ }
+
+ private static ForegroundChecker instance;
+
+ private boolean foreground = false, paused = true;
+ private Handler handler = new Handler();
+ private Listener listener;
+ private Runnable check;
+ private long backgroundTimeStart;
+
+ public static ForegroundChecker init() {
+ if (instance == null) {
+ instance = new ForegroundChecker();
+ }
+ return instance;
+ }
+
+ public static ForegroundChecker get() {
+ if (instance == null) {
+ init();
+ }
+ return instance;
+ }
+
+ private ForegroundChecker() {
+ backgroundTimeStart = -1;
+ }
+
+ public boolean isForeground() {
+ return foreground;
+ }
+
+ public boolean isBackground() {
+ return !foreground;
+ }
+
+ public void addListener(Listener listener) {
+ this.listener = listener;
+ }
+
+ public void onActivityResumed() {
+ paused = false;
+ boolean wasBackground = !foreground;
+ foreground = true;
+
+ if (check != null)
+ handler.removeCallbacks(check);
+
+ if (wasBackground) {
+
+ int secondsInBackground = (int) ((System.currentTimeMillis() - backgroundTimeStart) /
+ 1000) % 60;
+
+ if (backgroundTimeStart != -1 && secondsInBackground >= MIN_BACKGROUND_THRESHOLD &&
+ listener != null) {
+ listener.onBecameForeground();
+ }
+
+ }
+ }
+
+ public void onActivityPaused() {
+ paused = true;
+
+ if (check != null)
+ handler.removeCallbacks(check);
+
+ handler.postDelayed(check = new Runnable() {
+ @Override
+ public void run() {
+ if (foreground && paused) {
+ foreground = false;
+ backgroundTimeStart = System.currentTimeMillis();
+
+ }
+ }
+ }, CHECK_DELAY);
+ }
+}
diff --git a/mifosng-android/src/main/java/com/mifos/utils/PassCodeView.java b/mifosng-android/src/main/java/com/mifos/utils/PassCodeView.java
new file mode 100644
index 00000000000..4f95a3972f5
--- /dev/null
+++ b/mifosng-android/src/main/java/com/mifos/utils/PassCodeView.java
@@ -0,0 +1,115 @@
+package com.mifos.utils;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.mifos.mifosxdroid.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by mayankjindal on 18/07/17.
+ */
+
+public class PassCodeView extends View {
+
+ private Paint emptyCirclePaint, fillCirclePaint;
+ private final int PASSWORD_LENGTH = 4;
+ private List passwordList;
+ private boolean isPasscodeVisible;
+
+ public PassCodeView(Context context) {
+ super(context);
+ init();
+ }
+
+ public PassCodeView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public PassCodeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+
+ private void init() {
+ emptyCirclePaint = new Paint();
+ emptyCirclePaint.setColor(ContextCompat.getColor(getContext(), R.color.primary));
+ emptyCirclePaint.setAntiAlias(true);
+ emptyCirclePaint.setStyle(Paint.Style.STROKE);
+ emptyCirclePaint.setStrokeWidth(1f);
+
+ fillCirclePaint = new Paint();
+ fillCirclePaint.setColor(ContextCompat.getColor(getContext(), R.color.primary));
+ fillCirclePaint.setAntiAlias(true);
+ fillCirclePaint.setTextSize(getResources().getDimension(R.dimen.text_medium));
+ fillCirclePaint.setStyle(Paint.Style.FILL);
+
+ passwordList = new ArrayList<>();
+ isPasscodeVisible = false;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ int stackSize = passwordList.size();
+ int xPosition = getWidth() / (PASSWORD_LENGTH * 2);
+ for (int i = 1; i <= PASSWORD_LENGTH; i++) {
+ if (stackSize >= i) {
+ if (!isPasscodeVisible) {
+ canvas.drawCircle(xPosition, getHeight() / 2, 8f, fillCirclePaint);
+ } else {
+ canvas.drawText(passwordList.get(i - 1), xPosition , getHeight() / 2 +
+ getHeight() / 8, fillCirclePaint);
+ }
+ } else {
+ canvas.drawCircle(xPosition , getHeight() / 2, 8f, emptyCirclePaint);
+ }
+ xPosition += getWidth() / PASSWORD_LENGTH;
+ }
+ }
+
+ public void enterCode(String character) {
+ if (passwordList.size() < PASSWORD_LENGTH) {
+ passwordList.add(character);
+ invalidate();
+ }
+ }
+
+ public String getPasscode() {
+ StringBuilder builder = new StringBuilder();
+ for (String character : passwordList) {
+ builder.append(character);
+ }
+ return builder.toString();
+ }
+
+ public void clearPasscodeField() {
+ passwordList.clear();
+ invalidate();
+ }
+
+ public void backSpace() {
+ if (passwordList.size() > 0) {
+ passwordList.remove(passwordList.size() - 1);
+ invalidate();
+ }
+ }
+
+ public void revertPassCodeVisibility() {
+ isPasscodeVisible = !isPasscodeVisible;
+ invalidate();
+ }
+
+ public boolean passcodeVisible() {
+ return isPasscodeVisible;
+ }
+}
diff --git a/mifosng-android/src/main/java/com/mifos/utils/PrefManager.java b/mifosng-android/src/main/java/com/mifos/utils/PrefManager.java
index 716f22243a4..c4b288a0556 100755
--- a/mifosng-android/src/main/java/com/mifos/utils/PrefManager.java
+++ b/mifosng-android/src/main/java/com/mifos/utils/PrefManager.java
@@ -24,6 +24,8 @@ public class PrefManager {
private static final String PORT = "preferences_port";
private static final String USER_STATUS = "user_status";
private static final String USER_DETAILS = "user_details";
+ private static final String PASSCODE = "passcode";
+ private static final String PASSCODE_STATUS = "passcode_status";
private static Gson gson = new Gson();
@@ -159,6 +161,15 @@ public static void setPort(String port) {
putString(PORT, port);
}
+ public static String getPassCode() {
+ return getString(PASSCODE, "");
+ }
+
+ public static void setPassCode(String passCode) {
+ putString(PASSCODE, passCode);
+ setPassCodeStatus(true);
+ }
+
/**
* Set User Status,
* If O then user is Online
@@ -175,6 +186,21 @@ public static void setUserStatus(int statusCode) {
public static int getUserStatus() {
return getInt(USER_STATUS, 0);
}
-}
+ /**
+ * Set Pass Code Status,
+ * If false then pass code is not set
+ * If true then pass code is set
+ */
+ public static void setPassCodeStatus(boolean statusCode) {
+ putBoolean(PASSCODE_STATUS, true);
+ }
+ /**
+ * @return the Pref value of pass code status.
+ * default is false(pass code is not set)
+ */
+ public static Boolean getPassCodeStatus() {
+ return getBoolean(PASSCODE_STATUS, false);
+ }
+}
\ No newline at end of file
diff --git a/mifosng-android/src/main/jniLibs/arm64-v8a/libencryption.so b/mifosng-android/src/main/jniLibs/arm64-v8a/libencryption.so
new file mode 100755
index 00000000000..db8c572b138
Binary files /dev/null and b/mifosng-android/src/main/jniLibs/arm64-v8a/libencryption.so differ
diff --git a/mifosng-android/src/main/jniLibs/armeabi-v7a/libencryption.so b/mifosng-android/src/main/jniLibs/armeabi-v7a/libencryption.so
new file mode 100755
index 00000000000..77063967663
Binary files /dev/null and b/mifosng-android/src/main/jniLibs/armeabi-v7a/libencryption.so differ
diff --git a/mifosng-android/src/main/jniLibs/armeabi/libencryption.so b/mifosng-android/src/main/jniLibs/armeabi/libencryption.so
new file mode 100755
index 00000000000..fbb5752b89f
Binary files /dev/null and b/mifosng-android/src/main/jniLibs/armeabi/libencryption.so differ
diff --git a/mifosng-android/src/main/jniLibs/mips/libencryption.so b/mifosng-android/src/main/jniLibs/mips/libencryption.so
new file mode 100755
index 00000000000..cf197c2961e
Binary files /dev/null and b/mifosng-android/src/main/jniLibs/mips/libencryption.so differ
diff --git a/mifosng-android/src/main/jniLibs/mips64/libencryption.so b/mifosng-android/src/main/jniLibs/mips64/libencryption.so
new file mode 100755
index 00000000000..f4b696c8afb
Binary files /dev/null and b/mifosng-android/src/main/jniLibs/mips64/libencryption.so differ
diff --git a/mifosng-android/src/main/jniLibs/x86/libencryption.so b/mifosng-android/src/main/jniLibs/x86/libencryption.so
new file mode 100755
index 00000000000..46239497675
Binary files /dev/null and b/mifosng-android/src/main/jniLibs/x86/libencryption.so differ
diff --git a/mifosng-android/src/main/jniLibs/x86_64/libencryption.so b/mifosng-android/src/main/jniLibs/x86_64/libencryption.so
new file mode 100755
index 00000000000..a60ad9d7365
Binary files /dev/null and b/mifosng-android/src/main/jniLibs/x86_64/libencryption.so differ
diff --git a/mifosng-android/src/main/res/drawable-xhdpi/ic_backspace_48px.xml b/mifosng-android/src/main/res/drawable-xhdpi/ic_backspace_48px.xml
new file mode 100644
index 00000000000..7b8ee72bc33
--- /dev/null
+++ b/mifosng-android/src/main/res/drawable-xhdpi/ic_backspace_48px.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/mifosng-android/src/main/res/drawable-xhdpi/ic_visibility_48px.xml b/mifosng-android/src/main/res/drawable-xhdpi/ic_visibility_48px.xml
new file mode 100644
index 00000000000..7bf3ea193fa
--- /dev/null
+++ b/mifosng-android/src/main/res/drawable-xhdpi/ic_visibility_48px.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/mifosng-android/src/main/res/drawable-xhdpi/mifos_logo.jpg b/mifosng-android/src/main/res/drawable-xhdpi/mifos_logo.jpg
new file mode 100644
index 00000000000..a067a3c8edb
Binary files /dev/null and b/mifosng-android/src/main/res/drawable-xhdpi/mifos_logo.jpg differ
diff --git a/mifosng-android/src/main/res/layout/activity_pass_code.xml b/mifosng-android/src/main/res/layout/activity_pass_code.xml
new file mode 100644
index 00000000000..eb945f5caa5
--- /dev/null
+++ b/mifosng-android/src/main/res/layout/activity_pass_code.xml
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mifosng-android/src/main/res/values/dimens.xml b/mifosng-android/src/main/res/values/dimens.xml
index 514d7fe4082..98a35d5b0e8 100755
--- a/mifosng-android/src/main/res/values/dimens.xml
+++ b/mifosng-android/src/main/res/values/dimens.xml
@@ -7,10 +7,17 @@
16dp
16dp
+ 24dp
+ 8dp
+ 16dp
8dp
8dp
+ 56dp
4dp
3dp
+ 72dp
+ 20sp
+ 16sp
18sp
diff --git a/mifosng-android/src/main/res/values/strings.xml b/mifosng-android/src/main/res/values/strings.xml
index b38421590ff..045fbd64297 100755
--- a/mifosng-android/src/main/res/values/strings.xml
+++ b/mifosng-android/src/main/res/values/strings.xml
@@ -686,6 +686,23 @@
Empty Notes
Failed to Fetch Notes
SyncClientPayloadActivity
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 0
+ Skip
+ Setup a passcode to login
+ Pass Code
+ Forgot passcode, login manually
+ Incorrect Passcode
+ You have entered incorrect Passcode more than 3 times
+ Passcode should be of 4 digit
\ No newline at end of file