<repo_name>erikterwiel/FaceLock<file_sep>/android/app/src/main/java/erikterwiel/phoneprotection/Activities/SettingsActivity.java
package erikterwiel.phoneprotection.Activities;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.SeekBar;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;

import erikterwiel.phoneprotection.R;

public class SettingsActivity extends AppCompatActivity {

    private static final String TAG = "SettingsActivity.java";

    SharedPreferences mDatabase;
    SharedPreferences.Editor mDatabaseEditor;

    private MenuItem mDone;
    private SeekBar mScanBar;
    private TextView mScanDisplay;
    private SeekBar mSafeBar;
    private TextView mSafeDisplay;
    private Switch mSirenToggle;
    private Switch mMaxToggle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "onCreate() called");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_settings);

        mDatabase = getSharedPreferences("settings", Context.MODE_PRIVATE);
        mDatabaseEditor = mDatabase.edit();

        mScanBar = findViewById(R.id.settings_scan_frequency_bar);
        mScanDisplay = findViewById(R.id.settings_scan_frequency_display);
        mSafeBar = findViewById(R.id.settings_safe_mode_duration_bar);
        mSafeDisplay = findViewById(R.id.settings_safe_mode_duration_display);
        mSirenToggle = findViewById(R.id.settings_siren_toggle);
        mMaxToggle = findViewById(R.id.settings_max_volume_toggle);

        mScanBar.setProgress((int) (Math.sqrt(mDatabase.getInt("scan_frequency", 10000) / 1000 - 10) / 0.298329));
        mScanDisplay.setText(((int) Math.pow(0.298329 * mScanBar.getProgress(), 2) + 10) + "s");
        mScanBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                int frequency = (int) (Math.pow(0.298329 * i, 2)) + 10;
                mDatabaseEditor.putInt("scan_frequency", frequency * 1000);
                mScanDisplay.setText(frequency + "s");
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {}

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {}
        });

        mSafeBar.setProgress((int) ((mDatabase.getInt("safe_duration", 60000) / 60 / 1000 - 1) / 0.59));
        mSafeDisplay.setText(((int) (0.59 * mSafeBar.getProgress()) + 1) + "m");
        mSafeBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                int frequency = (int) (0.59 * i) + 1;
                mDatabaseEditor.putInt("safe_duration", frequency * 60 * 1000);
                mSafeDisplay.setText(frequency + "m");
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {}

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {}
        });

        mSirenToggle.setChecked(mDatabase.getBoolean("siren", false));
        mSirenToggle.setOnCheckedChangeListener((compoundButton, isChecked) -> {
            mDatabaseEditor.putBoolean("siren", isChecked);
        });

        mMaxToggle.setChecked(mDatabase.getBoolean("max", false));
        mMaxToggle.setOnCheckedChangeListener((compoundButton, isChecked) -> {
            mDatabaseEditor.putBoolean("max", isChecked);
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater menuInflater = getMenuInflater();
        menuInflater.inflate(R.menu.settings_done, menu);
        mDone = menu.findItem(R.id.settings_done);
        mDone.setOnMenuItemClickListener((menuItem) -> {
            mDatabaseEditor.apply();
            Log.i(TAG, "Saved scan_frequency = " + mDatabase.getInt("scan_frequency", 0));
            Toast.makeText(SettingsActivity.this, "Settings saved", Toast.LENGTH_LONG).show();
            finish();
            return false;
        });
        return super.onCreateOptionsMenu(menu);
    }


}
<file_sep>/README.md

![face lock showcase 2](https://user-images.githubusercontent.com/29645585/40404184-7447af28-5e24-11e8-908f-b2dd2822b4d9.png)

# Face Lock

Face Lock is an Android app/service uses facial recognition to lock the device when an unauthorized face is using it. The faces of close ones can be added to the accepted list and the feature can be toggled on and off to provide our users with utmost versatility for their unique needs. Further, if the phone has been stolen and locked, the user will immediately receive an email notification and will be able to log into our companion website for further support. On the website, users will be able to access their phone's location services to track down the phone and see updated photos taken by the front camera of the potential thief. Not only does this technology protect data and increase the chances of reclaiming a stolen phone, its proliferation will discourage phone theft.

Face Lock was started at HackPrinceton Fall 2017 and can be found on Devpost [here.](https://devpost.com/software/swiper-no-swiping)

Our project represented a unique challenge of having equal importance in web and mobile development - which were integrated through Amazon Web Services. On a set background task interval, Face Lock uses the front facing camera and AWS Rekognition to check if the user is authorized to use the device. If the user is unauthorized, their photo is uploaded to AWS S3 and sent to the device's owner through text and email with AWS SNS. Simultaniously, Face Lock begins rapid location tracking and uploads the phone's coordinates to DynamoDB.

This data stored on S3 and DynamoDB is then pulled down to our Node.js + EJS web app where the user can track their devices on our embedded Bing Maps and can view all previously identified intruders.

The website is currently being updated to an Angular + Node.js app but the older version can be viewed from our previous release.
<file_sep>/android/app/src/main/java/erikterwiel/phoneprotection/Activities/ForgotActivity.java
package erikterwiel.phoneprotection.Activities;

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.amazonaws.ClientConfiguration;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUserPool;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.continuations.ForgotPasswordContinuation;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.handlers.ForgotPasswordHandler;

import erikterwiel.phoneprotection.R;

import static erikterwiel.phoneprotection.Keys.CognitoKeys.CLIENT_ID;
import static erikterwiel.phoneprotection.Keys.CognitoKeys.CLIENT_SECRET;
import static erikterwiel.phoneprotection.Keys.CognitoKeys.POOL_ID;

public class ForgotActivity extends AppCompatActivity {

    private static final String TAG = "ForgotActivity.java";

    private EditText mEmail;
    private Button mSubmit;
    private LinearLayout mCode;
    private TextView[] mCodeDigits = new TextView[6];
    private EditText mCodeInput;
    private EditText mPassword;
    private EditText mConfirm;
    private Button mSet;
    private String mResult;
    private boolean mSuccess = false;
    private CognitoUser mCognitoUser;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_forgot);
        getSupportActionBar().hide();

        mEmail = findViewById(R.id.forgot_email);
        mSubmit = findViewById(R.id.forgot_reset);
        mCode = findViewById(R.id.forgot_code);
        mCodeDigits[0] = findViewById(R.id.forgot_code0);
        mCodeDigits[1] = findViewById(R.id.forgot_code1);
        mCodeDigits[2] = findViewById(R.id.forgot_code2);
        mCodeDigits[3] = findViewById(R.id.forgot_code3);
        mCodeDigits[4] = findViewById(R.id.forgot_code4);
        mCodeDigits[5] = findViewById(R.id.forgot_code5);
        mCodeInput = findViewById(R.id.forgot_code_input);
        mPassword = findViewById(R.id.forgot_password);
        mConfirm = findViewById(R.id.forgot_confirm);
        mSet = findViewById(R.id.forgot_set);

        mSubmit.setOnClickListener(view -> new RequestNewPassword().execute());
        mCode.setOnClickListener(view -> {
            mCodeInput.requestFocus();
            InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
            imm.showSoftInput(mCodeInput, InputMethodManager.SHOW_IMPLICIT);
        });
        mCodeInput.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

            @Override
            public void onTextChanged(CharSequence input, int i, int i1, int i2) {
                if (i2 == 1) {
                    mCodeDigits[i].setText(Character.toString(mCodeInput.getText().toString().charAt(i)));
                } else {
                    mCodeDigits[i].setText("");
                }
            }

            @Override
            public void afterTextChanged(Editable editable) {}
        });
        mConfirm.setOnEditorActionListener((textView, i, keyEvent) -> {
            mSet.performClick();
            return true;
        });
        mSet.setOnClickListener(view -> {
            if (mPassword.getText().toString().equals(mConfirm.getText().toString())) {
                new SetPassword().execute();
            } else {
                Toast.makeText(
                        ForgotActivity.this,
                        "Entered password does not match confirmation.",
                        Toast.LENGTH_LONG).show();
            }
        });
    }

    private class RequestNewPassword extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... inputs) {
            ClientConfiguration clientConfiguration = new ClientConfiguration();
            CognitoUserPool userPool = new CognitoUserPool(
                    ForgotActivity.this, POOL_ID, CLIENT_ID, CLIENT_SECRET, clientConfiguration);
            mCognitoUser = userPool.getUser(mEmail.getText().toString());
            mCognitoUser.forgotPassword(new ForgotPasswordHandler() {
                @Override
                public void onSuccess() {}
                @Override
                public void getResetCode(ForgotPasswordContinuation continuation) {
                    mResult = "A verification code has been sent to your email to reset your password.";
                    mSuccess = true;

                }
                @Override
                public void onFailure(Exception exception) {
                    mResult = exception.getMessage().split("\\(")[0];
                }
            });
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            if (mSuccess) {
                mSuccess = false;
                mEmail.setVisibility(View.GONE);
                mSubmit.setVisibility(View.GONE);
                mCode.setVisibility(View.VISIBLE);
                mPassword.setVisibility(View.VISIBLE);
                mConfirm.setVisibility(View.VISIBLE);
                mSet.setVisibility(View.VISIBLE);
            }
            Toast.makeText(ForgotActivity.this, mResult, Toast.LENGTH_LONG).show();
        }
    }

    private class SetPassword extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... voids) {
            mCognitoUser.confirmPassword(
                    mCodeInput.getText().toString(),
                    mPassword.getText().toString(),
                    new ForgotPasswordHandler() {
                        @Override
                        public void onSuccess() {
                            mResult = "Your password has been reset successfully.";
                            mSuccess = true;
                        }

                        @Override
                        public void getResetCode(ForgotPasswordContinuation continuation) { }

                        @Override
                        public void onFailure(Exception exception) {
                            mResult = exception.getMessage().split("\\(")[0];
                        }
                    });
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            Toast.makeText(ForgotActivity.this, mResult, Toast.LENGTH_LONG).show();
            if (mSuccess) finish();
        }
    }
}
<file_sep>/android/app/src/main/java/erikterwiel/phoneprotection/Receivers/DetectionReceiver.java
package erikterwiel.phoneprotection.Receivers;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

import erikterwiel.phoneprotection.Services.DetectionService;

public class DetectionReceiver extends BroadcastReceiver {

    private static final String TAG = "DetectionReceiver.java";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "onReceive() called");
        Intent serviceIntent = new Intent(context, DetectionService.class);
        serviceIntent.putExtra("size", intent.getIntExtra("size", 0));
        for (int i = 0; i < intent.getIntExtra("size", 0); i++) {
            serviceIntent.putExtra("user" + i, intent.getStringExtra("user" + i));
            serviceIntent.putExtra("bucketfiles" + i, intent.getStringExtra("bucketfiles" + i));
        }
        serviceIntent.putExtra("username", intent.getStringExtra("username"));
        context.startService(serviceIntent);
    }
}
<file_sep>/android/app/src/main/java/erikterwiel/phoneprotection/Singletons/Rekognition.java
package erikterwiel.phoneprotection.Singletons;

import android.content.Context;

import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.rekognition.AmazonRekognitionClient;

import static erikterwiel.phoneprotection.Keys.DynamoDBKeys.POOL_ID_UNAUTH;
import static erikterwiel.phoneprotection.Keys.DynamoDBKeys.POOL_REGION;

public class Rekognition {

    private static Rekognition instance;
    private AmazonRekognitionClient rekognitionClient;

    private Rekognition(Context context) {
        AWSCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
                context,
                POOL_ID_UNAUTH,
                Regions.fromName(POOL_REGION));
        rekognitionClient = new AmazonRekognitionClient(credentialsProvider);
    }

    public static void init(Context context) {
        if (instance == null) {
            context = context.getApplicationContext();
            instance = new Rekognition(context);
        }
    }

    public static Rekognition getInstance() {
        return instance;
    }

    public AmazonRekognitionClient getRekognitionClient() {
        return rekognitionClient;
    }
}
<file_sep>/android/app/src/main/java/erikterwiel/phoneprotection/Activities/AddPhoneActivity.java
package erikterwiel.phoneprotection.Activities;

import android.location.Location;
import android.os.AsyncTask;
import android.provider.Settings;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBMapper;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;

import erikterwiel.phoneprotection.R;
import erikterwiel.phoneprotection.Singletons.DynamoDB;
import erikterwiel.phoneprotection.Account;

public class AddPhoneActivity extends AppCompatActivity {

    private static final String TAG = "AddPhoneActivity.java";

    private DynamoDBMapper mMapper;
    private EditText mName;
    private Button mAdd;
    private Location mLocation;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_phone);

        mMapper = DynamoDB.getInstance().getMapper();
        mName = findViewById(R.id.phone_name);
        mAdd = findViewById(R.id.phone_add_phone);

        mAdd.setOnClickListener(view -> {
            if (mName.getText().toString().equals("")) {
                Toast.makeText(this, "Your phone must have a name!", Toast.LENGTH_LONG).show();
            } else {
                new UploadPhone().execute();
            }
        });
    }

    private class UploadPhone extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... inputs) {
            try {
                FusedLocationProviderClient locationClient = LocationServices.getFusedLocationProviderClient(AddPhoneActivity.this);
                locationClient.getLastLocation().addOnSuccessListener(AddPhoneActivity.this, location -> {
                    if (location != null) {
                        mLocation = location;
                    } else {
                        mLocation = new Location("Default");
                        mLocation.setLatitude(37.421984);
                        mLocation.setLongitude(-122.084152);
                    }
                });
            } catch (SecurityException ex) {
                ex.printStackTrace();
            }

            Account account = mMapper.load(Account.class, getIntent().getStringExtra("username"));
            if (account == null) {
                account = new Account();
                account.setUsername(getIntent().getStringExtra("username"));
            }
            account.addUnique(Settings.Secure.getString(getApplicationContext().getContentResolver(), Settings.Secure.ANDROID_ID));
            account.addName(mName.getText().toString());
            account.addLatitude(mLocation.getLatitude());
            account.addLongitude(mLocation.getLongitude());
            mMapper.save(account);
            finish();
            return null;
        }
    }
}<file_sep>/android/app/src/main/java/erikterwiel/phoneprotection/Activities/LoginActivity.java
package erikterwiel.phoneprotection.Activities;

import android.Manifest;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.amazonaws.ClientConfiguration;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoDevice;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUserPool;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUserSession;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.continuations.AuthenticationContinuation;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.continuations.AuthenticationDetails;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.continuations.ChallengeContinuation;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.continuations.MultiFactorAuthenticationContinuation;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.handlers.AuthenticationHandler;

import java.util.List;

import erikterwiel.phoneprotection.MyAdminReceiver;
import erikterwiel.phoneprotection.R;

import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static erikterwiel.phoneprotection.Keys.CognitoKeys.POOL_ID;
import static erikterwiel.phoneprotection.Keys.CognitoKeys.CLIENT_ID;
import static erikterwiel.phoneprotection.Keys.CognitoKeys.CLIENT_SECRET;

public class LoginActivity extends AppCompatActivity {

    private static final String TAG = "LoginActivity.java";
    private static final int REQUEST_PERMISSION = 100;
    private static final int REQUEST_ADMIN = 105;

    private CognitoUserPool mUserPool;
    private CognitoUser mCognitoUser;
    private CognitoUserSession mUserSession;
    private EditText mEmail;
    private EditText mPassword;
    private Button mLogin;
    private Button mRegister;
    private Button mForgot;
    private SharedPreferences mMemory;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        Log.i(TAG, "onCreate() called");
        setTheme(R.style.AppTheme);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        getSupportActionBar().hide();


        Log.i(TAG, "Unique ID: " + Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID));

        DevicePolicyManager devicePolicyManager =
                (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
        List<ComponentName> admins = devicePolicyManager.getActiveAdmins();
        boolean isAdminApp = false;
        for (ComponentName name : admins) {
            if (name.getClassName().equals("erikterwiel.phoneprotection.MyAdminReceiver")) {
                isAdminApp = true;
                break;
            }
        }
        if (!isAdminApp) {
            ComponentName compName = new ComponentName(this, MyAdminReceiver.class);
            Intent adminIntent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
            adminIntent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, compName);
            adminIntent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
                    "Admin app privilege needed to lock the screen on lock down.");
            startActivityForResult(adminIntent, REQUEST_ADMIN);
        }

        mEmail = findViewById(R.id.login_email);
        mPassword = findViewById(R.id.login_password);
        mLogin = findViewById(R.id.login_login);
        mRegister = findViewById(R.id.login_register);
        mForgot = findViewById(R.id.login_forgot);

        mMemory = getSharedPreferences("memory", Context.MODE_PRIVATE);
        if (mMemory.contains("email")) {
            mEmail.setText(mMemory.getString("email", null));
            mPassword.requestFocus();
        }

        ClientConfiguration clientConfiguration = new ClientConfiguration();
        mUserPool = new CognitoUserPool(
                this, POOL_ID, CLIENT_ID, CLIENT_SECRET, clientConfiguration);
        mLogin.setOnClickListener(view -> {
            mCognitoUser = mUserPool.getUser();
            AuthenticationHandler handler = new AuthenticationHandler() {
                @Override
                public void onSuccess(CognitoUserSession userSession, CognitoDevice newDevice) {
                    ActivityCompat.requestPermissions(
                            LoginActivity.this,
                            new String[] {
                                    Manifest.permission.ACCESS_COARSE_LOCATION,
                                    Manifest.permission.ACCESS_FINE_LOCATION,
                                    Manifest.permission.READ_EXTERNAL_STORAGE,
                                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
                                    Manifest.permission.CAMERA,
                                    Manifest.permission.READ_PHONE_STATE},
                            REQUEST_PERMISSION);
                    mUserSession = userSession;
                }

                @Override
                public void onFailure(Exception exception) {
                    Toast.makeText(
                            LoginActivity.this,
                            exception.getMessage().split("\\(")[0],
                            Toast.LENGTH_LONG).show();
                }

                @Override
                public void getAuthenticationDetails(AuthenticationContinuation continuation, String userId) {
                    AuthenticationDetails authDetails = new AuthenticationDetails(
                            mEmail.getText().toString() ,
                            mPassword.getText().toString(),
                            null
                    );
                    continuation.setAuthenticationDetails(authDetails);
                    continuation.continueTask();
                }

                @Override
                public void getMFACode(MultiFactorAuthenticationContinuation continuation) {}

                @Override
                public void authenticationChallenge(ChallengeContinuation continuation) {}
            };
            mCognitoUser.getSessionInBackground(handler);
        });

        mPassword.setOnEditorActionListener((textView, actionID, keyEvent) -> {
            if (actionID == EditorInfo.IME_ACTION_SEND) {
                Log.i(TAG, "Attempting to perform a click");
                mLogin.performClick();
                return true;
            }
            return false;
        });

        mRegister.setOnClickListener(view -> {
            Intent registerIntent = new Intent(LoginActivity.this, RegisterActivity.class);
            startActivity(registerIntent);
        });

        mForgot.setOnClickListener(view -> {
            Intent forgotIntent = new Intent(LoginActivity.this, ForgotActivity.class);
            startActivity(forgotIntent);
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        for (int i = 0; i < permissions.length; i++) {
            if (!permissions[i].equals("android.permission.READ_PHONE_STATE") && grantResults[i] == PERMISSION_DENIED) {
                Toast.makeText(
                        LoginActivity.this,
                        "You must allow all permissions to use Face Lock.",
                        Toast.LENGTH_LONG).show();
                return;
            }
        }
        Toast.makeText(
                LoginActivity.this,
                "Authentication successful, loading...",
                Toast.LENGTH_LONG).show();
        Intent homeIntent = new Intent(LoginActivity.this, HomeActivity.class);
        homeIntent.putExtra("username", mUserSession.getUsername());
        homeIntent.putExtra("email", mEmail.getText().toString());
        startActivity(homeIntent);
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.i(TAG, "onStop() called");
        SharedPreferences.Editor memoryEditor = mMemory.edit();
        memoryEditor.putString("email", mEmail.getText().toString());
        memoryEditor.apply();
    }
}
<file_sep>/android/app/src/main/java/erikterwiel/phoneprotection/Services/TrackerService.java
package erikterwiel.phoneprotection.Services;


import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBMapper;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;

import java.util.Timer;

import erikterwiel.phoneprotection.R;
import erikterwiel.phoneprotection.Account;

public class TrackerService extends Service {

    private static final String TAG = "TrackerService.java";
    private static final String POOL_ID_UNAUTH = "us-east-1:d2040261-6a0f-4cba-af96-8ead1b66ec38";
    private static final int NOTIFICATION_ID = 104;

    private AmazonDynamoDBClient mDDBClient;
    private DynamoDBMapper mMapper;
    private Notification mNotification;
    private FusedLocationProviderClient mFusedLocationClient;
    private Intent mIntent;
    private Account mPhone;
    private Timer mTimer;
    private int mRunCounter;


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand() called");

        mNotification = new Notification.Builder(this)
                .setSmallIcon(R.drawable.ic_security_black_48dp)
                .setContentTitle("Phone Protection")
                .setContentText("Monitoring phone users")
                .setCategory(Notification.CATEGORY_STATUS)
                .setPriority(Notification.PRIORITY_MIN)
                .setAutoCancel(false)
                .setOngoing(true)
                .build();
        startForeground(NOTIFICATION_ID, mNotification);

        LocationServices.getFusedLocationProviderClient(this);
        CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
                getApplicationContext(),
                POOL_ID_UNAUTH,
                Regions.US_EAST_1);
        mDDBClient = new AmazonDynamoDBClient(credentialsProvider);
        mMapper = new DynamoDBMapper(mDDBClient);
        mIntent = intent;
        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

        new DownloadPhone().execute();
        try {
            Thread.sleep(1500);
        } catch (Exception ex) {}
        new UpdatePhone().execute();

        mTimer = new Timer();
//        mTimer.scheduleAtFixedRate(new TimerTask() {
//            @Override
//            public void run() {
//                try {
//                    mFusedLocationClient.getLastLocation().addOnSuccessListener(new OnSuccessListener<Location>() {
//                        @Override
//                        public void onSuccess(Location location) {
//                            if (location != null) {
//                                Log.i(TAG, "Latitude: " + location.getLatitude());
//                                Log.i(TAG, "Longitude: " + location.getLongitude());
//                                mPhone.setLatitudes(location.getLatitude());
//                                mPhone.setLongitudes(location.getLongitude());
//                            }
//                        }
//                    });
//                } catch (SecurityException ex) {
//                    ex.printStackTrace();
//                }
//                new UpdatePhone().execute();
//                mRunCounter += 1;
//                if (mRunCounter == 20) onDestroy();
//            }
//        }, 0, 15000);
        return START_STICKY;
    }

    private class DownloadPhone extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... inputs) {
            mPhone = mMapper.load(Account.class, mIntent.getStringExtra("username"));
            return null;
        }
    }

    private class UpdatePhone extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... voids) {
            Log.i(TAG, "doInBackground() called");
            mMapper.save(mPhone);
            return null;
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy() called");
        mTimer.cancel();
        mTimer.purge();
        stopForeground(true);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

}
<file_sep>/android/app/src/main/java/erikterwiel/phoneprotection/Activities/RegisterActivity.java
package erikterwiel.phoneprotection.Activities;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUserAttributes;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUserCodeDeliveryDetails;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUserPool;
import com.amazonaws.mobileconnectors.cognitoidentityprovider.handlers.SignUpHandler;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.sns.AmazonSNSClient;

import erikterwiel.phoneprotection.R;

import static erikterwiel.phoneprotection.Keys.CognitoKeys.CLIENT_ID;
import static erikterwiel.phoneprotection.Keys.CognitoKeys.CLIENT_SECRET;
import static erikterwiel.phoneprotection.Keys.CognitoKeys.POOL_ID;
import static erikterwiel.phoneprotection.Keys.DynamoDBKeys.POOL_ID_UNAUTH;
import static erikterwiel.phoneprotection.Keys.DynamoDBKeys.POOL_REGION;
import static erikterwiel.phoneprotection.Keys.SNSKeys.ACCOUNT;
import static erikterwiel.phoneprotection.Keys.SNSKeys.REGION;

public class RegisterActivity extends AppCompatActivity {

    private static final String TAG = "RegisterActivity.java";

    private CognitoUserPool mUserPool;
    private MenuItem mDone;
    private EditText mEmail;
    private EditText mPassword;
    private EditText mConfirm;
    private Button mRegister;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        Log.i(TAG, "onCreate() called");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_register);
        getSupportActionBar().hide();

        ClientConfiguration clientConfiguration = new ClientConfiguration();
        mUserPool = new CognitoUserPool(
                this, POOL_ID, CLIENT_ID, CLIENT_SECRET, clientConfiguration);

        mEmail = findViewById(R.id.register_email);
        mPassword = findViewById(R.id.register_password);
        mRegister = findViewById(R.id.register_register);
        mConfirm = findViewById(R.id.register_confirm);

        mRegister.setOnClickListener(view -> {
            if (mPassword.getText().toString().equals(mConfirm.getText().toString())) {
                SignUpHandler signupCallback = new SignUpHandler() {
                    @Override
                    public void onSuccess(CognitoUser user, boolean signUpConfirmationState, CognitoUserCodeDeliveryDetails cognitoUserCodeDeliveryDetails) {
                        new RegisterNotifications().execute();
                    }

                    @Override
                    public void onFailure(Exception exception) {
                        Toast.makeText(RegisterActivity.this,
                                exception.getClass().toString().split(" ")[1].split("\\.")[5],
                                Toast.LENGTH_LONG).show();
                    }
                };
                CognitoUserAttributes userAttributes = new CognitoUserAttributes();
                mUserPool.signUpInBackground(mEmail.getText().toString(),
                        mPassword.getText().toString(),
                        userAttributes, null, signupCallback);
            } else {
                Toast.makeText(
                        RegisterActivity.this,
                        "Entered password does not match confirmation.",
                        Toast.LENGTH_LONG).show();
            }
        });
    }

    private class RegisterNotifications extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... inputs) {
            AWSCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
                    RegisterActivity.this,
                    POOL_ID_UNAUTH,
                    Regions.fromName(POOL_REGION));
            AmazonSNSClient snsClient = new AmazonSNSClient(credentialsProvider);
            snsClient.setRegion(Region.getRegion(Regions.US_EAST_1));
            String topicName = mEmail.getText().toString();
            topicName = topicName.replaceAll("\\.", "");
            topicName = topicName.replaceAll("@", "");
            topicName = topicName.replaceAll(":", "");
            snsClient.createTopic(topicName);
            snsClient.subscribe(
                    "arn:aws:sns:" + REGION + ":" + ACCOUNT + ":" + topicName,
                    "email", mEmail.getText().toString());
            return null;
        }
        @Override
        protected void onPostExecute(Void result) {
            Toast.makeText(RegisterActivity.this,
                    "Registration successful, please check email for two verification links. " +
                            "One is to verify your email, the other is receive pictures of phone intruders",
                    Toast.LENGTH_LONG).show();
            finish();
        }
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater menuInflater = getMenuInflater();
        menuInflater.inflate(R.menu.register_done, menu);
        mDone = menu.findItem(R.id.register_done);
        mDone.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem menuItem) {
                finish();
                return false;
            }
        });
        return super.onCreateOptionsMenu(menu);
    }
}
<file_sep>/android/app/src/main/java/erikterwiel/phoneprotection/Singletons/DynamoDB.java
package erikterwiel.phoneprotection.Singletons;

import android.content.Context;

import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBMapper;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;

import static erikterwiel.phoneprotection.Keys.DynamoDBKeys.POOL_ID_UNAUTH;
import static erikterwiel.phoneprotection.Keys.DynamoDBKeys.POOL_REGION;

public class DynamoDB {

    private static DynamoDB instance;
    private DynamoDBMapper mapper;

    private DynamoDB(Context context) {
        CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
                context,
                POOL_ID_UNAUTH,
                Regions.fromName(POOL_REGION));
        AmazonDynamoDBClient DDBClient = new AmazonDynamoDBClient(credentialsProvider);
        mapper = new DynamoDBMapper(DDBClient);
    }

    public static void init(Context context) {
        if (instance == null) {
            context = context.getApplicationContext();
            instance = new DynamoDB(context);
        }
    }

    public static DynamoDB getInstance() {
        return instance;
    }

    public DynamoDBMapper getMapper() {
        return mapper;
    }
}
