package com.greenaddress.greenbits.ui; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import com.dd.CircularProgressButton; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.greenaddress.greenbits.KeyStoreAES; public class PinSaveActivity extends GaActivity { private static final int ACTIVITY_REQUEST_CODE = 1; private static final String NEW_PIN_MNEMONIC = "com.greenaddress.greenbits.NewPinMnemonic"; private EditText mPinText; private Button mSkipButton; private CircularProgressButton mSaveButton; static public Intent createIntent(final Context ctx, final String mnemonic) { final Intent intent = new Intent(ctx, PinSaveActivity.class); intent.putExtra(NEW_PIN_MNEMONIC, mnemonic); return intent; } private void setPin(final String pin, final boolean isNative) { if (pin.length() < 4) { shortToast(R.string.err_pin_save_wrong_length); return; } hideKeyboardFrom(mPinText); mPinText.setEnabled(false); mSaveButton.setIndeterminateProgressMode(true); mSaveButton.setProgress(50); UI.hide(mSkipButton); final String mnemonic = getIntent().getStringExtra(NEW_PIN_MNEMONIC); Futures.addCallback(mService.setPin(mnemonic, pin), new FutureCallback<Void>() { @Override public void onSuccess(final Void result) { setResult(RESULT_OK); if (!isNative && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // The user has set a non-native PIN. // In case they already had a native PIN they are overriding, // blank the native value so future logins don't detect it. // FIXME: Requiring M or higher is required because otherwise this crashes @ android < 21 // and native is not available before M anyway // java.lang.VerifyError: com/greenaddress/greenbits/KeyStoreAES KeyStoreAES.wipePIN(mService); } finishOnUiThread(); } @Override public void onFailure(final Throwable t) { PinSaveActivity.this.runOnUiThread(new Runnable() { public void run() { mSaveButton.setProgress(0); mPinText.setEnabled(true); UI.show(mSkipButton); } }); } }, mService.getExecutor()); } @Override protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { if (requestCode == ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // Challenge completed, proceed with using cipher tryEncrypt(); } } @TargetApi(Build.VERSION_CODES.M) private void tryEncrypt() { try { setPin(KeyStoreAES.tryEncrypt(mService), true); } catch (final KeyStoreAES.RequiresAuthenticationScreen e) { KeyStoreAES.showAuthenticationScreen(this); } catch (final KeyStoreAES.KeyInvalidated e) { toast(String.format(getResources().getString(R.string.problemWithKey), e.getMessage())); } } @Override protected int getMainViewId() { return R.layout.activity_pin_save; } @Override protected void onCreateWithService(final Bundle savedInstanceState) { mPinText = UI.find(this, R.id.pinSaveText); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { try { KeyStoreAES.createKey(true); final CheckBox nativeAuthCB = UI.find(this, R.id.useNativeAuthentication); UI.show(nativeAuthCB); nativeAuthCB.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(final CompoundButton compoundButton, final boolean isChecked) { if (isChecked) tryEncrypt(); } }); } catch (final RuntimeException e) { // lock not set, simply don't show native options } } mPinText.setOnEditorActionListener( UI.getListenerRunOnEnter(new Runnable() { public void run() { setPin(UI.getText(mPinText), false); } })); mSaveButton = (CircularProgressButton) UI.mapClick(this, R.id.pinSaveButton, new View.OnClickListener() { public void onClick(final View v) { setPin(UI.getText(mPinText), false); } }); mSkipButton = (Button) UI.mapClick(this, R.id.pinSkipButton, new View.OnClickListener() { public void onClick(final View v) { setResult(RESULT_CANCELED); // Skip finish(); } }); } @Override public boolean onCreateOptionsMenu(final Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.common_menu, menu); return true; } @Override public boolean onOptionsItemSelected(final MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. return item.getItemId() == R.id.action_settings || super.onOptionsItemSelected(item); } }