Android Open Source - lastpass-android Soft Keyboard






From Project

Back to project page lastpass-android.

License

The source code is released under:

Copyright (c) 2013 Nicholas Hinds Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Sof...

If you think the Android project lastpass-android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.nhinds.lastpass.android;
//  ww  w  . jav a 2  s  .c  o  m
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.inputmethodservice.InputMethodService;
import android.text.InputType;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;

import com.nhinds.lastpass.PasswordInfo;
import com.nhinds.lastpass.PasswordStore;
import com.nhinds.lastpass.android.UserLoginTaskFactory.LoginFailureReason;
import com.nhinds.lastpass.android.UserLoginTaskFactory.UserLoginListener;
import com.nhinds.lastpass.android.UserLoginTaskFactory.UserLoginResult;

public class SoftKeyboard extends InputMethodService {
  private static final Logger LOGGER = LoggerFactory.getLogger(SoftKeyboard.class);
  
  private static final int AFTER_INSERTED_TEXT = 1;

  private InputMethodManager mInputMethodManager;

  private View mInputView;
  private Preferences preferences;

  private static PasswordStore passwordStore;

  static void setPasswordStore(PasswordStore passwordStore) {
    // TODO This sucks, why is this so difficult to accomplish in android?
    SoftKeyboard.passwordStore = passwordStore;
  }

  static void logout() {
    assert passwordStore != null;
    // TODO call a method to kill the session once this is implemented in lastpass-java
    passwordStore = null;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    this.mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
    this.preferences = new Preferences(this);
  }

  @Override
  public View onCreateInputView() {
    // This is freaking ugly, but the only way I can see to make the code
    // wait until its input token is valid...
    this.mInputView = new View(this);
    this.mInputView.post(new Runnable() {
      @Override
      public void run() {
        LOGGER.trace("Input view token is now valid");
        bing();
      }
    });
    return this.mInputView;
  }

  @Override
  public void onStartInputView(EditorInfo info, boolean restarting) {
    final String applicationPackage = getPackageName();
    final String editorPackage = getCurrentInputEditorInfo().packageName;
    if (applicationPackage.equals(editorPackage)) {
      LOGGER.debug("Detected an editor from this application's package {}, switching to last input method", applicationPackage);
      switchToLastInputMethod();
    } else {
      LOGGER.debug("This editor seems to be fine: {}", editorPackage);
    }
  }

  private void bing() {
    if (passwordStore == null) {
      String rememberedEmail = preferences.getRememberedEmail();
      String rememberedPassword = preferences.getRememberedPassword();
      if (rememberedEmail != null && rememberedPassword != null) {
        UserLoginTaskFactory.create(rememberedEmail, rememberedPassword, getApplicationContext(), new UserLoginListener() {
          
          @Override
          public void loginCompleted(UserLoginResult result) {
            if (result.passwordStore != null) {
              setPasswordStore(result.passwordStore);
              bing();
            } else {
              LOGGER.debug("Error logging in: {} ({})", result.failureReason, result.reasonString);
              if (result.failureReason == LoginFailureReason.OTP)
                switchToLoginActivity(LoginActivity.CACHED_OTP_LOGIN, null);
              else
                switchToLoginActivity(null, result.reasonString);
            }
          }
          
          @Override
          public void progressDialogCreated(ProgressDialog dialog) {
            makeDialogWork(dialog);
          }
        }).loginWithoutOtp();
      } else {
        switchToLoginActivity(null, null);
      }
    } else {
      final String hostname = getHostname();
      final PasswordInfoListAdapter listAdapter = new PasswordInfoListAdapter(this, passwordStore.getPasswords(),
          passwordStore.getPasswordsByHostname(hostname));

      final AlertDialog dialog = new AlertDialog.Builder(this).setAdapter(listAdapter, new OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {
          PasswordInfo passwordInfo = listAdapter.getItem(which);
          final String text = isPasswordInput() ? passwordInfo.getPassword() : passwordInfo.getUsername();
          getCurrentInputConnection().commitText(text, AFTER_INSERTED_TEXT);
        }
      }).create();
      dialog.setCustomTitle(getTitleBar(dialog));
      dialog.setOnDismissListener(new OnDismissListener() {

        @Override
        public void onDismiss(DialogInterface dialog) {
          switchToLastInputMethod();
        }
      });
      makeDialogWork(dialog);
      dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
      dialog.show();
    }
  }

  private void switchToLoginActivity(String action, String errorString) {
    startActivity(new Intent(action, null, this, LoginActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).putExtra(LoginActivity.ERROR_EXTRA_KEY, errorString));
  }
  
  private View getTitleBar(final AlertDialog dialog) {
    final View titleBar = getLayoutInflater().inflate(R.layout.password_titlebar, null);
    if (!isPasswordInput()) {
      final TextView titleText = (TextView) titleBar.findViewById(R.id.popup_title);
      titleText.setText(R.string.choose_username);
    }

    final View logoutButton = titleBar.findViewById(R.id.logout_button);
    logoutButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        logout();
        SoftKeyboard.this.preferences.setRememberedPassword(null);
        dialog.cancel();
      }
    });
    return titleBar;
  }

  private String getHostname() {
    return StringUtils.reverseDelimited(getCurrentInputEditorInfo().packageName, '.');
  }

  private void makeDialogWork(AlertDialog dialog) {
    // http://stackoverflow.com/questions/5698700/how-to-launch-a-popupwindow-or-dialog-from-an-input-method-service
    LayoutParams attributes = dialog.getWindow().getAttributes();
    attributes.token = this.mInputView.getWindowToken();
    attributes.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
    dialog.getWindow().setAttributes(attributes);
  }

  protected static boolean isPassword(int inputType) {
    int variation = inputType & InputType.TYPE_MASK_VARIATION;
    return variation == InputType.TYPE_TEXT_VARIATION_PASSWORD || variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
        || variation == InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
  }

  private void switchToLastInputMethod() {
    this.mInputMethodManager.switchToLastInputMethod(getWindow().getWindow().getAttributes().token);
  }

  private boolean isPasswordInput() {
    return isPassword(getCurrentInputEditorInfo().inputType);
  }
}




Java Source Code List

com.nhinds.lastpass.android.LastPassDeviceId.java
com.nhinds.lastpass.android.LoginActivity.java
com.nhinds.lastpass.android.PasswordInfoListAdapter.java
com.nhinds.lastpass.android.Preferences.java
com.nhinds.lastpass.android.SoftKeyboard.java
com.nhinds.lastpass.android.UserLoginTaskFactory.java