package info.guardianproject.otr.app.im.app;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;
import android.widget.ViewFlipper;
import info.guardianproject.cacheword.CacheWordActivityHandler;
import info.guardianproject.cacheword.ICacheWordSubscriber;
import info.guardianproject.otr.app.im.R;
import info.guardianproject.otr.app.im.provider.Imps;
import info.guardianproject.util.BackgroundBitmapLoaderTask;
import info.guardianproject.util.Languages;
import java.security.GeneralSecurityException;
public class LockScreenActivity extends ThemeableActivity implements ICacheWordSubscriber {
private static final String TAG = "LockScreenActivity";
private final static int MIN_PASS_LENGTH = 4;
// private final static int MAX_PASS_ATTEMPTS = 3;
// private final static int PASS_RETRY_WAIT_TIMEOUT = 30000;
private EditText mEnterPassphrase;
private EditText mNewPassphrase;
private EditText mConfirmNewPassphrase;
private View mViewCreatePassphrase;
private View mViewEnterPassphrase;
private ImageButton mLanguageButton;
private CacheWordActivityHandler mCacheWord;
private String mPasswordError;
private TwoViewSlider mSlider;
private ImApp mApp;
private Button mBtnCreate;
private Button mBtnSkip;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mApp = (ImApp)getApplication();
getSupportActionBar().hide();
setContentView(R.layout.activity_lock_screen);
mCacheWord = new CacheWordActivityHandler(mApp, (ICacheWordSubscriber)this);
mViewCreatePassphrase = findViewById(R.id.llCreatePassphrase);
mViewEnterPassphrase = findViewById(R.id.llEnterPassphrase);
mEnterPassphrase = (EditText) findViewById(R.id.editEnterPassphrase);
mNewPassphrase = (EditText) findViewById(R.id.editNewPassphrase);
mConfirmNewPassphrase = (EditText) findViewById(R.id.editConfirmNewPassphrase);
ViewFlipper vf = (ViewFlipper) findViewById(R.id.viewFlipper1);
LinearLayout flipView1 = (LinearLayout) findViewById(R.id.flipView1);
LinearLayout flipView2 = (LinearLayout) findViewById(R.id.flipView2);
mSlider = new TwoViewSlider(vf, flipView1, flipView2, mNewPassphrase, mConfirmNewPassphrase);
// set up language chooser button
mLanguageButton = (ImageButton) findViewById(R.id.languageButton);
mLanguageButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Activity activity = LockScreenActivity.this;
final Languages languages = Languages.get(activity);
final ArrayAdapter<String> languagesAdapter = new ArrayAdapter<String>(activity,
android.R.layout.simple_list_item_single_choice, languages.getAllNames());
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setIcon(R.drawable.ic_settings_language);
builder.setTitle(R.string.KEY_PREF_LANGUAGE_TITLE);
builder.setAdapter(languagesAdapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int position) {
Log.i(TAG, "onItemClick: " + dialog + " " + position);
String[] languageCodes = languages.getSupportedLocales();
resetLanguage(languageCodes[position]);
dialog.dismiss();
}
});
builder.show();
}
});
}
@Override
protected void onPause() {
super.onPause();
mCacheWord.onPause();
}
@Override
protected void onResume() {
super.onResume();
mCacheWord.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
mCacheWord.disconnect();
}
@Override
public void onBackPressed() {
//do nothing!
}
private boolean newEqualsConfirmation() {
return mNewPassphrase.getText().toString()
.equals(mConfirmNewPassphrase.getText().toString());
}
private void showValidationError() {
Toast.makeText(LockScreenActivity.this, mPasswordError, Toast.LENGTH_LONG).show();
mNewPassphrase.requestFocus();
}
private void showInequalityError() {
Toast.makeText(LockScreenActivity.this,
getString(R.string.lock_screen_passphrases_not_matching),
Toast.LENGTH_SHORT).show();
clearNewFields();
}
private void clearNewFields() {
mNewPassphrase.getEditableText().clear();
mConfirmNewPassphrase.getEditableText().clear();
}
private boolean isPasswordValid() {
return validatePassword(mNewPassphrase.getText().toString().toCharArray());
}
private boolean isPasswordFieldEmpty() {
return mNewPassphrase.getText().toString().length() == 0;
}
private boolean isConfirmationFieldEmpty() {
return mConfirmNewPassphrase.getText().toString().length() == 0;
}
private void initializeWithPassphrase() {
try {
String passphrase = mNewPassphrase.getText().toString();
if (passphrase.isEmpty()) {
// Create DB with empty passphrase
if (Imps.setEmptyPassphrase(this, false)) {
try
{
ChatFileStore.initWithoutPassword(this);
// Simulate cacheword opening
afterCacheWordOpened();
}
catch (Exception e)
{
Log.d(ImApp.LOG_TAG,"unable to mount VFS store"); //but let's not crash the whole app right now
}
ChatFileStore.initWithoutPassword(this);
} else {
// TODO failed
}
} else {
mCacheWord.setPassphrase(passphrase.toCharArray());
}
} catch (Exception e) {
// TODO initialization failed
Log.e(TAG, "Cacheword pass initialization failed: " + e.getMessage());
}
}
private void initializePassphrase() {
// Passphrase is not set, so allow the user to create one
View viewCreatePassphrase = findViewById(R.id.llCreatePassphrase);
viewCreatePassphrase.setVisibility(View.VISIBLE);
mViewEnterPassphrase.setVisibility(View.GONE);
mNewPassphrase.setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event)
{
if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE)
{
if (!isPasswordValid())
showValidationError();
else if (isPasswordFieldEmpty()) {
initializeWithPassphrase();
} else
mSlider.showConfirmationField();
}
return false;
}
});
mConfirmNewPassphrase.setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event)
{
if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE)
{
if (!newEqualsConfirmation()) {
showInequalityError();
mSlider.showNewPasswordField();
}
}
return false;
}
});
mBtnCreate = (Button) findViewById(R.id.btnCreate);
mBtnCreate.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
// validate
if (!isPasswordValid()) {
showValidationError();
mSlider.showNewPasswordField();
} else if (isConfirmationFieldEmpty() && !isPasswordFieldEmpty()) {
mBtnSkip.setVisibility(View.GONE);
mSlider.showConfirmationField();
mBtnCreate.setText(R.string.lock_screen_confirm_passphrase);
}
else if (!newEqualsConfirmation()) {
showInequalityError();
}
else if (!isConfirmationFieldEmpty() && !isPasswordFieldEmpty())
{
initializeWithPassphrase();
}
}
});
mBtnSkip = (Button)findViewById(R.id.btnSkip);
mBtnSkip.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v)
{
if (isPasswordFieldEmpty())
initializeWithPassphrase();
}
});
}
private void promptPassphrase() {
mViewCreatePassphrase.setVisibility(View.GONE);
mViewEnterPassphrase.setVisibility(View.VISIBLE);
mEnterPassphrase.setOnEditorActionListener(new OnEditorActionListener()
{
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event)
{
if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_GO)
{
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
Handler threadHandler = new Handler();
imm.hideSoftInputFromWindow(v.getWindowToken(), 0, new ResultReceiver(
threadHandler)
{
@Override
protected void onReceiveResult(int resultCode, Bundle resultData)
{
super.onReceiveResult(resultCode, resultData);
if (mEnterPassphrase.getText().toString().length() == 0)
return;
// Check passphrase
try {
char[] passphrase = mEnterPassphrase.getText().toString().toCharArray();
mCacheWord.setPassphrase(passphrase);
ImApp.mUsingCacheword = true;
} catch (Exception e) {
mEnterPassphrase.setText("");
// TODO implement try again and wipe if fail
Log.e(TAG, "Cacheword pass verification failed: " + e.getMessage());
return;
}
}
});
return true;
}
return false;
}
});
}
private boolean validatePassword(char[] pass)
{
if (pass.length < MIN_PASS_LENGTH && pass.length != 0)
{
// should we support some user string message here?
mPasswordError = getString(R.string.pass_err_length);
return false;
}
return true;
}
public class TwoViewSlider {
private boolean firstIsShown = true;
private ViewFlipper flipper;
private LinearLayout container1;
private LinearLayout container2;
private View firstView;
private View secondView;
private Animation pushRightIn;
private Animation pushRightOut;
private Animation pushLeftIn;
private Animation pushLeftOut;
public TwoViewSlider(ViewFlipper flipper, LinearLayout container1, LinearLayout container2,
View view1, View view2) {
this.flipper = flipper;
this.container1 = container1;
this.container2 = container2;
this.firstView = view1;
this.secondView = view2;
pushRightIn = AnimationUtils.loadAnimation(LockScreenActivity.this, R.anim.push_right_in);
pushRightOut = AnimationUtils.loadAnimation(LockScreenActivity.this, R.anim.push_right_out);
pushLeftIn = AnimationUtils.loadAnimation(LockScreenActivity.this, R.anim.push_left_in);
pushLeftOut = AnimationUtils.loadAnimation(LockScreenActivity.this, R.anim.push_left_out);
}
public void showNewPasswordField() {
if (firstIsShown)
return;
flipper.setInAnimation(pushRightIn);
flipper.setOutAnimation(pushRightOut);
flip();
}
public void showConfirmationField() {
if (!firstIsShown)
return;
flipper.setInAnimation(pushLeftIn);
flipper.setOutAnimation(pushLeftOut);
flip();
}
private void flip() {
if (firstIsShown) {
firstIsShown = false;
container2.removeAllViews();
container2.addView(secondView);
} else {
firstIsShown = true;
container1.removeAllViews();
container1.addView(firstView);
}
flipper.showNext();
}
}
@Override
public void onCacheWordUninitialized() {
Intent intentOrig;
if ((intentOrig = getIntent().getParcelableExtra("originalIntent"))!=null)
{
if (intentOrig.getData() != null)
{
if (intentOrig.getData().getScheme().equals("immu")||
intentOrig.getData().getScheme().equals("ima"))
{
initializeWithPassphrase();
return;
}
}
}
initializePassphrase();
}
@Override
public void onCacheWordLocked() {
promptPassphrase();
}
@Override
public void onCacheWordOpened() {
afterCacheWordOpened();
ChatFileStore.init(this, mCacheWord.getEncryptionKey());
}
/**
*
*/
private void afterCacheWordOpened() {
Intent intent = (Intent) getIntent().getParcelableExtra("originalIntent");
if (intent != null)
{
getIntent().removeExtra("originalIntent");
finish();
// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
// LockScreenActivity.this.overridePendingTransition(0, 0);
}
}
private void resetLanguage(String language) {
((ImApp) getApplication()).setNewLocale(this, language);
Intent intent = getIntent();
intent.setClass(LockScreenActivity.this, LockScreenActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
overridePendingTransition(0, 0);
startActivity(intent);
overridePendingTransition(0, 0);
}
}