yasme/src/main/java/de/fau/cs/mad/yasme/android/encryption/KeyEncryption.java
public class KeyEncryption {

    public static final String RSAKEY_STORAGE = "rsaKeyStorage"; //Storage for Private and Public Keys from user
    public static final String PRIVATEKEY = "privateKey";
    public static final String PUBLICKEY = "publicKey";
    private final byte CREATOR = 0;
    private final byte RECIPIENT = 1;
    private RSAEncryption rsa;
    private DatabaseManager db = DatabaseManager.INSTANCE;

    public KeyEncryption() {
        this.rsa = new RSAEncryption();
    }

    /**
     * generate a random RSA-KeyPair (Private and Public Key)
     */
    public void generateRSAKeys(){
        rsa.generateKeyPair();
    }

    /**
     * encode generated RSA-KeyPair to base64 and store it to local storage (SharedPreferences)
     * there is a own SharedPreference for every user on the device
     *
     * @param deviceId deviceId from the user logged in currently
     * @return true/false
     */
    public boolean saveRSAKeys(long deviceId){

        String RSAKEY_STORAGE_USER = RSAKEY_STORAGE + "_" + deviceId;

        try {

            Context context = DatabaseManager.INSTANCE.getContext();
            SharedPreferences privKeyStorage = context.getSharedPreferences(RSAKEY_STORAGE_USER, Context.MODE_PRIVATE);
            SharedPreferences.Editor keyeditor = privKeyStorage.edit();

            //delete existing keys
            if (privKeyStorage.getString(PRIVATEKEY, "") != ""){
                keyeditor.remove(PRIVATEKEY);
            }
            if (privKeyStorage.getString(PUBLICKEY, "") != ""){
                keyeditor.remove(PUBLICKEY);
            }

            keyeditor.putString(PRIVATEKEY, rsa.getPrivKeyinBase64());
            keyeditor.putString(PUBLICKEY, rsa.getPubKeyinBase64());

            keyeditor.commit();

            // For Developer-Devices only
            if (DebugManager.INSTANCE.isDebugMode()) {
                Log.d(getClass().getSimpleName(), "Store keys to external storage");
                DebugManager.INSTANCE.storePrivatePublicKeyToExternalStorage(rsa.getPrivKeyinBase64(),rsa.getPubKeyinBase64());
            }

            Log.d(this.getClass().getSimpleName(), "RSA Keys generated and saved");


            return true;
        } catch (Exception e){
            Log.e(this.getClass().getSimpleName(), "saving rsa keys failed");
            Log.e(this.getClass().getSimpleName(),e.getMessage());
            return false;
        }
    }

    /**
     * get the generated RSA Public Key in Base64
     * method is needed in registration when the Public Key needs to be sent to the server
     *
     * @return base64 encoded string
     */
    public String getGeneratedPubKeyInBase64(){
        return rsa.getPubKeyinBase64();
    }

    /**
     * encrypt the given messageKey using the RSA PublicKey from the recipient
     *
     * @param messageKey messageKey containing the AES-Key that should be encrypted
     * @return messageKey containing the RSA-encrypted AES-Key
     */
    public MessageKey encrypt(MessageKey messageKey){

        PublicKey pubKey = getPubKeyFromUser(messageKey, RECIPIENT);

        if (pubKey != null){
            String keyEncrypted = rsa.encrypt(messageKey.getMessageKey(), pubKey);
            messageKey.setKey(keyEncrypted);
            return messageKey;
        }

        return null;
    }

    /**
     * encrypt the given messageKey using the own RSA Private Key
     *
     * @param messageKey messageKey containing the encrypted AES-Key that should be decrypted
     * @return messageKey containing the decrypted AES-Key
     */
    public MessageKey decrypt(MessageKey messageKey){

        long selfDeviceId = messageKey.getRecipientDevice().getId();
        PrivateKey privKey = getPrivateRSAKeyFromStorage(selfDeviceId);

        if (privKey != null) {
            String key = rsa.decrypt(messageKey.getMessageKey(), privKey);
            if (key == null) {
                return null;
            }
            messageKey.setKey(key);
            return messageKey;
        }

        return null;
    }

    /**
     * sign an AES-Key using the own RSA Private Key
     *
     * @param messageKey messageKey containing the AES-Key that should be signed
     * @return  messageKey containing the signature
     */
    public MessageKey sign(MessageKey messageKey){

        long selfDeviceId = messageKey.getCreatorDevice().getId();
        PrivateKey privKey = getPrivateRSAKeyFromStorage(selfDeviceId);

        if (privKey != null) {
            String keySigned = rsa.sign(messageKey.getMessageKey(), privKey);
            messageKey.setSign(keySigned);
            return messageKey;
        }

        return null;
    }

    /**
     * verify the signature from given messageKey using the RSA Public Key from the creatorDevice
     *
     * @param messageKey messageKey containing the signature
     * @return true/false
     */
    public boolean verify(MessageKey messageKey){

        PublicKey pubKey = getPubKeyFromUser(messageKey, CREATOR);

        if (pubKey != null) {
            Log.d(getClass().getSimpleName(), "Verify key");
            return rsa.verify(messageKey.getSign(), messageKey.getMessageKey(), pubKey);
        }
        Log.d(getClass().getSimpleName(), "PubKey is null");
        return false;
    }

    /**
     * load own RSA Private Key from local storage
     *
     * @param selfDeviceId deviceId from the user logged in currently
     * @return PrivateKey
     */
    public PrivateKey getPrivateRSAKeyFromStorage(long selfDeviceId){

        String RSAKEY_STORAGE_USER = RSAKEY_STORAGE + "_" + selfDeviceId;

        Context context = DatabaseManager.INSTANCE.getContext();
        SharedPreferences privKeyStorage = context.getSharedPreferences(RSAKEY_STORAGE_USER, Context.MODE_PRIVATE);
        String privKeyInBase64 = privKeyStorage.getString(PRIVATEKEY, "");

        Log.d(this.getClass().getSimpleName(),"Load private Key from storage: " + RSAKEY_STORAGE_USER);

        //if Key is available
        if (privKeyInBase64 != "") {

            PrivateKey privKey = rsa.convertBase64toPrivKey(privKeyInBase64);

            if (privKey != null){
                Log.d(this.getClass().getSimpleName(),"Private Key was successfully loaded from storage");
                return privKey;
            }

            Log.d(this.getClass().getSimpleName(), "Getting private key from storage failed");
            return null;
        }

            Log.d(this.getClass().getSimpleName(), "Private Key could not be found.");
            return null;

    }

    /**
     * load the needed RSA Public Key from local storage/Device-Object
     *
     * @param messageKey messageKey containing the information about creatorDevice and recipientDevice
     * @param type define, the RSA Public Key from the recipient or the creator is needed
     * @return PublicKey
     */
    public PublicKey getPubKeyFromUser(MessageKey messageKey, byte type) {

        String pubKeyInBase64 = null;

        //try to extract Public Key from MessageKey
        if (type == CREATOR){
                pubKeyInBase64 = messageKey.getCreatorDevice().getPublicKey();
        }
        else if (type == RECIPIENT){
                pubKeyInBase64 = messageKey.getRecipientDevice().getPublicKey();
        }
        else{
            Log.d(this.getClass().getSimpleName(), "Wrong use of function: getPubKeyFromUser()");
            return null;
        }

        //convert Base64toPublicKey
        if (pubKeyInBase64 != null) {
            PublicKey pubKey = rsa.convertBase64toPubKey(pubKeyInBase64);
            if (pubKey != null) return pubKey;
        }

        Log.d(this.getClass().getSimpleName(), "Getting public key from storage failed");
        return null;
    }

    /*
    //get own PublicKey in Base64
    public String getPublicRSAKeyInBase64FromStorage(long selfDeviceId){

        String RSAKEY_STORAGE_USER = RSAKEY_STORAGE + "_" + selfDeviceId;

        Context context = DatabaseManager.INSTANCE.getContext();
        SharedPreferences privKeyStorage = context.getSharedPreferences(RSAKEY_STORAGE_USER, Context.MODE_PRIVATE);
        String pubKeyInBase64 = privKeyStorage.getString(PUBLICKEY, "");

        return pubKeyInBase64;
    }
    */

}
yasme/src/main/java/de/fau/cs/mad/yasme/android/ui/fragments/LoginFragment.java
public class LoginFragment extends Fragment implements NotifiableFragment<LoginFragment.LoginParam> {

    //Keep track of the login task to ensure we can cancel it if requested.
    private UserLoginTask authTask = null;

    // UI references.
    private EditText emailView;
    private EditText passwordView;
    private TextView loginStatusMessageView;
    private View mProgressView;
    private View mLoginFormView;
    // values for devices yasme server
    private String deviceProduct;
    // Values for name, email and password at the time of the login attempt.
    private String emailTmp;
    private String passwordTmp;
    // focusView for validate()
    private View focusView = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        AbstractYasmeActivity activity = (AbstractYasmeActivity) getActivity();

        // In debug app, show @yasme.net
        String defaultEmail = (BuildConfig.DEBUG) ? "@yasme.net" : "";

        // Restore preferences
        emailTmp = DatabaseManager.INSTANCE.getSharedPreferences().getString(AbstractYasmeActivity.USER_MAIL, defaultEmail);
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_login, container,
                false);

        // Set up the login form.
        emailView = (EditText) rootView.findViewById(R.id.email);
        emailView.setText(emailTmp);

        passwordView = (EditText) rootView.findViewById(R.id.password);
        if (BuildConfig.DEBUG) {
            passwordView.setText(R.string.default_password);
        }
        passwordView
                .setOnEditorActionListener(new TextView.OnEditorActionListener() {
                    @Override
                    public boolean onEditorAction(TextView textView, int id,
                                                  KeyEvent keyEvent) {
                        if (id == R.id.login || id == EditorInfo.IME_NULL) {
                            attemptLogin();
                            return true;
                        }
                        return false;
                    }
                });

        loginStatusMessageView = (TextView) rootView.findViewById(R.id.login_status_message);

        rootView.findViewById(R.id.sign_in_button).setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        Log.d(this.getClass().getSimpleName(), "SignIn-Button pushed");
                        attemptLogin();
                    }
                }
        );

        rootView.findViewById(R.id.register_button).setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        Log.d(this.getClass().getSimpleName(), "Register-Button pushed");
                        registerDialog();
                    }
                }
        );

        TextView tv = (TextView) rootView.findViewById(R.id.forgot_password);

        Pattern pattern = Pattern.compile(getString(R.string.forgot_password));
        /*
        Linkify.addLinks(tv, pattern, "", null, new Linkify.TransformFilter() {
            @Override
            public String transformUrl(Matcher matcher, String s) {
                return "";
            }
        });
        */
        tv.setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        Log.d(this.getClass().getSimpleName(), "Forgot Password-Button pushed");
                        requestMail();
                    }
                }
        );

        return rootView;
    }


    @Override
    public void onStart() {
        super.onStart();
        Log.d(this.getClass().getSimpleName(), "Try to get LoginObservableInstance");
        FragmentObservable<LoginFragment, LoginParam> obs = ObservableRegistry.getObservable(LoginFragment.class);
        Log.d(this.getClass().getSimpleName(), "... successful");

        obs.register(this);
        mProgressView = getActivity().findViewById(R.id.login_status);
        mLoginFormView = getActivity().findViewById(R.id.login);
    }

    @Override
    public void onStop() {
        super.onStop();
        FragmentObservable<LoginFragment, LoginParam> obs =
                ObservableRegistry.getObservable(LoginFragment.class);
        Log.d(this.getClass().getSimpleName(), "Remove from observer");
        obs.remove(this);
    }

    private void registerDialog() {
        getFragmentManager().beginTransaction()
                .add(R.id.singleFragmentContainer, new RegisterFragment()).commit();
    }

    /**
     * Attempts to sign in or register the account specified by the login form.
     * If there are form errors (missing fields, etc.), the errors are presented
     * and no actual login attempt is made.
     */
    public void attemptLogin() {
        if (authTask == null) {
            authTask = new UserLoginTask(true, this.getClass());
            Log.d(this.getClass().getSimpleName(), "AuthTask is null");
        }

        // Reset errors.
        emailView.setError(null);
        passwordView.setError(null);

        // Store values at the time of the login attempt.
        emailTmp = emailView.getText().toString();
        passwordTmp = passwordView.getText().toString();

        boolean cancel = false;

        // Check for a valid password.
        if (TextUtils.isEmpty(passwordTmp)) {
            passwordView.setError(getString(R.string.error_field_required));
            focusView = passwordView;
            cancel = true;
        } else if (passwordTmp.length() < 8) {
            passwordView.setError(getString(R.string.error_invalid_password));
            focusView = passwordView;
            cancel = true;
        }

        // Check for a valid mail.
        if (TextUtils.isEmpty(emailTmp)) {
            emailView.setError(getString(R.string.error_field_required));
            focusView = emailView;
            cancel = true;
        }

        if (cancel) {
            // There was an error; don't attempt login and focus the first
            // form field with an error.
            focusView.requestFocus();
        } else {
            // Show a progress spinner, and kick off a background task to
            // perform the user login attempt.
            loginStatusMessageView.setText(R.string.login_progress_signing_in);
            showProgress(true);

            // Hide the virtual keyboard
            AbstractYasmeActivity activity = (AbstractYasmeActivity) getActivity();
            View focus = activity.getCurrentFocus();
            if (null == focus) {
                focus = focusView;
            }
            if (null == focus) {
                focus = passwordView;
            }
            if (null == focus) {
                focus = emailView;
            }
            InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
            if (null != imm && null != focus)
                imm.hideSoftInputFromWindow(focus.getWindowToken(), 0);

            // Start the asynctask
            authTask.execute(emailTmp, passwordTmp);
            authTask = null;
        }
    }

    public void onPostLoginExecute(Boolean success, long userId) {
        AbstractYasmeActivity activity = (AbstractYasmeActivity) getActivity();

        activity.getSelfUser().setId(userId);

        if (success) {
            //Initialize database (once in application)
            if (!DatabaseManager.INSTANCE.isInitialized()) {
                Log.e(getClass().getSimpleName(), "DB-Manger hasn't been initialized");
            }
            DatabaseManager.INSTANCE.setUserId(userId);

            // check if there is a device in the Database
            if (yasmeDeviceCheck()) {
                Log.d(this.getClass().getSimpleName(), "Device exists in Database");

                long deviceId = DatabaseManager.INSTANCE.getSharedPreferences().getLong(AbstractYasmeActivity.DEVICE_ID, -1);
                if (deviceId < 0) {
                    // Error ocurred
                    Log.e(this.getClass().getSimpleName(), "Could not load registered device's id from shared prefs");
                    showProgress(false);
                    return;
                }

                DatabaseManager.INSTANCE.setDeviceId(deviceId);

                showProgress(false);
                Intent intent = new Intent(activity, ChatListActivity.class);
                startActivity(intent);
                getActivity().finish();
            } else {
                // register device
                Log.d(this.getClass().getSimpleName(), "Device does not exist in Database");
                Log.d(this.getClass().getSimpleName(), "Starting task to register device at yasme server");

                new DeviceRegistrationTask(activity, this.getClass())
                        .execute(Long.toString(userId), this.deviceProduct, this.getClass().getName());

            }
        } else {
            Log.d(getClass().getSimpleName(), "Login failed");
            ServerInfo serverInfo = DatabaseManager.INSTANCE.getServerInfo();
            if (serverInfo != null && !serverInfo.getLoginAllowed() && serverInfo.hasMessage()) {
                passwordView.setError(DatabaseManager.INSTANCE.getServerInfo().getMessage());
            } else {
                passwordView.setError(getString(R.string.error_incorrect_user_or_password));
            }
            passwordView.requestFocus();
            showProgress(false);
        }
    }

    public void onPostYasmeDeviceRegExecute(Boolean success, long deviceId) {
        if (!success) {
            Toaster.getInstance().toast(getResources().getString(R.string.device_registration_failed), Toast.LENGTH_LONG);
        } else {
            AbstractYasmeActivity activity = (AbstractYasmeActivity) getActivity();
            // Initialize the session a second time because the deviceId was missing
            /*SharedPreferences devicePrefs = activity.getSharedPreferences(
                    AbstractYasmeActivity.DEVICE_PREFS,
                    AbstractYasmeActivity.MODE_PRIVATE);
            long userId = devicePrefs.getLong(AbstractYasmeActivity.USER_ID, -1);
            if (userId < 0) {
                // Error ocurred
                Log.e(this.getClass().getSimpleName(), "Did not find user id in shared prefs");
                Toaster.getInstance().toast(getResources().getString(R.string.device_registration_failed), Toast.LENGTH_LONG);
                showProgress(false);
                return;
            }*/

            DatabaseManager.INSTANCE.setDeviceId(deviceId);

            Log.d(this.getClass().getSimpleName(), "Login after device registration at yasme server");
            showProgress(false);
            Intent intent = new Intent(activity, ChatListActivity.class);
            startActivity(intent);
            getActivity().finish();
        }
    }

    /**
     * This method checks if there is a device in the DB
     */
    public boolean yasmeDeviceCheck() {
        AbstractYasmeActivity activity = (AbstractYasmeActivity) getActivity();
        //set the deviceProduct
        this.deviceProduct = Build.MANUFACTURER + " " + Build.MODEL;
        Log.d(this.getClass().getSimpleName(), "MODEL is " + Build.MODEL);
        Log.d(this.getClass().getSimpleName(), "DEVICE is " + Build.DEVICE);
        Log.d(this.getClass().getSimpleName(), "PRODUCT is " + Build.PRODUCT);
        Log.d(this.getClass().getSimpleName(), "MANUFACTURER is " + Build.MANUFACTURER);
        Log.d(this.getClass().getSimpleName(), "BRAND is " + Build.BRAND);
        Log.d(this.getClass().getSimpleName(), "NOW is " + this.deviceProduct);
        //try to load device from shared preferences
        SharedPreferences devicePrefs = activity.getSharedPreferences(
                AbstractYasmeActivity.DEVICE_PREFS,
                AbstractYasmeActivity.MODE_PRIVATE);
        long deviceId = devicePrefs.getLong(AbstractYasmeActivity.DEVICE_ID, -1);

        // load regId
        SharedPreferences pushPrefs = activity.
                getSharedPreferences(AbstractYasmeActivity.PUSH_PREFS,
                        AbstractYasmeActivity.MODE_PRIVATE);

        String googleRegId = pushPrefs.getString(AbstractYasmeActivity.PROPERTY_REG_ID, null);
        // TODO proper check

        if (deviceId == -1) {
            if (DebugManager.INSTANCE.isDebugMode()) {
                return DebugManager.INSTANCE.restoreData();
            }
            return false;
        }
        // TODO devices from server
        // TODO use case : plain app + old user + old device

        Log.d(this.getClass().getSimpleName(), "deviceId is " + deviceId);
        return true;
    }

    public void requestMail() {
        AbstractYasmeActivity activity = (AbstractYasmeActivity) getActivity();
        AlertDialog.Builder alert = new AlertDialog.Builder(activity);
        alert.setTitle(getString(R.string.request_email_title));

        LinearLayout list = new LinearLayout(activity);
        list.setOrientation(LinearLayout.VERTICAL);
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.MATCH_PARENT);

        final TextView requestEmailText = new TextView(activity);
        requestEmailText.setText(R.string.request_email_body);

        final EditText mail = new EditTextWithX(activity).getEditText();
        mail.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
        mail.setHint(R.string.registration_email);
        mail.setText(emailTmp);

        list.addView(mail);
        list.addView(requestEmailText, layoutParams);

        alert.setView(list);

        // "OK" button to save the values
        alert.setPositiveButton(R.string.OK,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                        // Grab the EditText's input
                        emailTmp = mail.getText().toString();
                        Log.d(this.getClass().getSimpleName(), "Mail to send token at: " + emailTmp);
                        User user = new User();
                        user.setEmail(emailTmp);
                        new ChangePasswordTask(user).execute("1");
                        forgotPasswordDialog(emailTmp);
                    }
                }
        );

        // Skip, email was already sent
        alert.setNeutralButton(R.string.skip,
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        forgotPasswordDialog(null);
                    }
                }
        );

        // "Cancel" button
        alert.setNegativeButton(R.string.cancel,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                        dialog.cancel();
                    }
                }
        );
        alert.show();
    }

    public void forgotPasswordDialog(final String inputMail) {
        AbstractYasmeActivity activity = (AbstractYasmeActivity) getActivity();
        AlertDialog.Builder alert = new AlertDialog.Builder(activity);
        alert.setTitle(getString(R.string.password_title));

        LinearLayout list = new LinearLayout(activity);
        list.setOrientation(LinearLayout.VERTICAL);
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.MATCH_PARENT);

        final EditText token = new EditText(activity);
        token.setInputType(InputType.TYPE_CLASS_TEXT);
        token.setHint(R.string.hint_mail_token);

        final TextView tokenExplanation = new TextView(activity);
        tokenExplanation.setText(R.string.explanation_mail_token);

        final EditText password = new EditText(activity);
        password.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
        password.setHint(R.string.hint_new_password);

        final EditText passwordCheck = new EditText(activity);
        passwordCheck.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
        passwordCheck.setHint(R.string.hint_repeat_new_password);

        final EditText mail = new EditText(activity);
        mail.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
        mail.setHint(R.string.registration_email);

        if (inputMail == null || inputMail.isEmpty()) {
            list.addView(mail);
        }
        list.addView(token, layoutParams);
        list.addView(tokenExplanation, layoutParams);
        list.addView(password, layoutParams);
        list.addView(passwordCheck, layoutParams);

        alert.setView(list);

        // "OK" button to save the values
        alert.setPositiveButton(R.string.OK,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {

                        // Grab the EditText's input
                        String email;
                        if (inputMail == null || inputMail.isEmpty()) {
                            email = mail.getText().toString();
                        } else {
                            email = inputMail;
                        }
                        String mailToken = token.getText().toString();
                        String inputPassword = password.getText().toString();
                        String inputPasswordCheck = passwordCheck.getText()
                                .toString();

                        if (password.getText().length() < 8) {
                            Toaster.getInstance().toast(R.string.password_too_short,
                                    Toast.LENGTH_LONG);
                            return;
                        }
                        if (!inputPassword.equals(inputPasswordCheck)) {
                            Toaster.getInstance().toast(R.string.passwords_do_not_match,
                                    Toast.LENGTH_LONG);
                            return;
                        }
                        User user = new User(email, inputPassword);
                        PasswordEncryption pwEnc = new PasswordEncryption(user);
                        User secured = pwEnc.securePassword();
                        new ChangePasswordTask(secured).execute("0", mailToken);
                    }
                }
        );

        // "Cancel" button
        alert.setNegativeButton(R.string.cancel,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                        dialog.cancel();
                    }
                }
        );
        alert.show();
    }

    /**
     * Shows the progress UI and hides the login form.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
    public void showProgress(final boolean show) {
        // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
        // for very easy animations. If available, use these APIs to fade-in
        // the progress spinner.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
            int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);

            mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
            mLoginFormView.animate().setDuration(shortAnimTime).alpha(
                    show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
                }
            });

            mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
            mProgressView.animate().setDuration(shortAnimTime).alpha(
                    show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
                }
            });
        } else {
            // The ViewPropertyAnimator APIs are not available, so simply show
            // and hide the relevant UI components.
            mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
            mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
        }
    }

    @Override
    public void notifyFragment(LoginParam param) {
        Log.d(super.getClass().getSimpleName(), "I have been notified. Yeeha!");
        if (param instanceof LoginProcessParam) {
            notifyFragment((LoginProcessParam) param);
        } else if (param instanceof DeviceRegistrationParam) {
            notifyFragment((DeviceRegistrationParam) param);
        }
    }

    public void notifyFragment(LoginProcessParam loginParam) {
        Log.d(super.getClass().getSimpleName(), "I have been notified with loginParam");

        onPostLoginExecute(loginParam.getSuccess(), loginParam.getUserId());
        Log.d(super.getClass().getSimpleName(), "Login-Status: " + loginParam.getSuccess());
    }

    public void notifyFragment(DeviceRegistrationParam deviceRegistrationParam) {
        Log.d(super.getClass().getSimpleName(), "I have been notified with deviceRegistrationParam");

        onPostYasmeDeviceRegExecute(deviceRegistrationParam.getSuccess(),
                deviceRegistrationParam.getDeviceId());

    }

    public static class LoginParam {
        protected Boolean success;

        public Boolean getSuccess() {
            return success;
        }
    }

    public static class LoginProcessParam extends LoginParam {
        private Long userId;

        public LoginProcessParam(Boolean success) {
            this.success = success;
            this.userId = DatabaseManager.INSTANCE.getUserId();
        }

        public Long getUserId() {
            return userId;
        }
    }

    public static class DeviceRegistrationParam extends LoginParam {
        private Long deviceId;

        public DeviceRegistrationParam(Boolean success) {
            this.success = success;
            this.deviceId = DatabaseManager.INSTANCE.getDeviceId();
        }

        public Long getDeviceId() {
            return deviceId;
        }
    }
}
yasme/src/main/java/de/fau/cs/mad/yasme/android/ui/AbstractYasmeActivity.java
public abstract class AbstractYasmeActivity extends Activity implements Toastable {
    public final static String USER_ID = "de.fau.cs.mad.yasme.android.USER_ID";
    public final static String USER_NAME = "de.fau.cs.mad.yasme.android.USER_NAME";
    public final static String USER_MAIL = "de.fau.cs.mad.yasme.android.USER_MAIL";
    public final static String USER_PW = "de.fau.cs.mad.yasme.android.USER_PW";
    public final static String DEVICE_ID = "de.fau.cs.mad.yasme.android.DEVICE_ID";
    public final static String PROFILE_PICTURE = "de.fau.cs.mad.yasme.android.PROFILE_PICTURE";

    public final static String CHAT_ID = "de.fau.cs.mad.yasme.android.CHAT_ID";
    public final static String LAST_MESSAGE_ID = "de.fau.cs.mad.yasme.android.LAST_MESSAGE_ID";

    public final static String ACCESSTOKEN = "de.fau.cs.mad.yasme.android.ACCESSTOKEN";
    public final static String SIGN_IN = "de.fau.cs.mad.yasme.android.SIGN_IN";

    public final static String SERVERINFOUPDATETIME = "de.fau.cs.mad.yasme.android.SERVERINFOUPDATETIME";
    public final static String SERVERMESSAGE = "de.fau.cs.mad.yasme.android.SERVERMESSAGE";

    public final static String STORAGE_PREFS = "de.fau.cs.mad.yasme.android.STORAGE_PREFS";
    public final static String SETTINGS_PREFS = "de.fau.cs.mad.yasme.android.SETTINGS_PREFS";
    public final static String DEVICE_PREFS = "de.fau.cs.mad.yasme.android.DEVICE_PREFS";
    public final static String PUSH_PREFS = "de.fau.cs.mad.yasme.android.PUSH_PREFS";

    public final static String NOTIFICATION_VIBRATE = "de.fau.cs.mad.yasme.android.NOTIFICATION_VIBRATE";
    public final static String NOTIFICATION_SOUND = "de.fau.cs.mad.yasme.android.NOTIFICATION_SOUND";


    //GCM Properties
    public static final String PROPERTY_REG_ID = "registration_id";
    public static final String PROPERTY_APP_VERSION = "appVersion";
    public static final String SENDER_ID = "688782154540"; //"104759172131";
    public static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
    public static final String TAG = "YasmeGCM";

    protected User selfUser;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (!ConnectionTask.isInitialized()) {
            String server = getResources().getString(R.string.server_host);
            if (BuildConfig.DEBUG) {
                server = getResources().getString(R.string.server_host_debug);
            }
            Log.d(getClass().getSimpleName(), "YASME-Server: " + server);
            ConnectionTask.initParams(getResources().getString(R.string.server_scheme),
                    server,
                    getResources().getString(R.string.server_port), getResources().getString(R.string.language), getVersion());
        }

        SharedPreferences storage = getSharedPreferences(STORAGE_PREFS, MODE_PRIVATE);
        SharedPreferences settings = getSharedPreferences(SETTINGS_PREFS, MODE_PRIVATE);
        Long userId = storage.getLong(USER_ID, 0);
        String userName = storage.getString(USER_NAME, "");
        String userMail = storage.getString(USER_MAIL, "");
        String userPw = storage.getString(USER_PW, "password");

        if(selfUser==null) {
            selfUser = new User();
        }
        selfUser.setId(userId);
        selfUser.setName(userName);
        selfUser.setEmail(userMail);
        selfUser.setPw(userPw);


        //Initialize databaseManager (once in application)
        if (!DatabaseManager.INSTANCE.isInitialized()) {
            DatabaseManager.INSTANCE.init(this, storage, settings, userId);
        }
        //Init QR-Code
        QR.init(false);

        String accessToken = DatabaseManager.INSTANCE.getAccessToken();
        if ((accessToken == null || accessToken.length() <= 0) && !this.getClass().equals(LoginActivity.class)) {
            Log.i(this.getClass().getSimpleName(), "Not logged in, starting login activity");
            Intent intent = new Intent(this, LoginActivity.class);
            startActivity(intent);
            finish();
            return;
        }
    }

    @Override
    public void onStart() {
        super.onStart();
        Toaster.getInstance().register(this);
        stopSpinning();
        SpinnerObservable.getInstance().registerActivity(this);
    }

    @Override
    public void onResume() {
        super.onResume();
        String accessToken = DatabaseManager.INSTANCE.getAccessToken();
        if ((accessToken == null || accessToken.length() <= 0) && !this.getClass().equals(LoginActivity.class)) {
            Log.i(this.getClass().getSimpleName(), "Not logged in, starting login activity");
            Intent intent = new Intent(this, LoginActivity.class);
            startActivity(intent);
            finish();
            return;
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        Toaster.getInstance().remove(this);
        SpinnerObservable.getInstance().removeActivity(this);
    }

    public void setActionBarTitle(String title) {
        getActionBar().setTitle(title);
    }

    public void setActionBarTitle(String title, String subtitle) {
        getActionBar().setTitle(title);
        getActionBar().setSubtitle(subtitle);
    }

    public boolean onOptionsItemSelected(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.
        Intent intent;
        int itemId = item.getItemId();
        switch (itemId) {
            case android.R.id.home:
                if (NavUtils.getParentActivityName(this) != null) {
                    NavUtils.navigateUpFromSameTask(this);
                }
                return true;
            case R.id.action_settings:
                intent = new Intent(this, SettingsActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(intent);
                return true;
            case R.id.action_chats:
                intent = new Intent(this, ChatListActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(intent);
                return true;
            case R.id.action_add_chat:
                intent = new Intent(this, InviteToChatActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                startActivity(intent);
                return true;
            case R.id.action_contacts:
                intent = new Intent(this, ContactActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                startActivity(intent);
                return true;
            default:
                return super.onOptionsItemSelected(item);

        }
    }

    public String getSelfName() {

        if(selfUser==null) {
            SharedPreferences storage = getSharedPreferences(STORAGE_PREFS, MODE_PRIVATE);
            Long userId = storage.getLong(USER_ID, 0);
            String userName = storage.getString(USER_NAME, "");
            String userMail = storage.getString(USER_MAIL, "");
            String userPw = storage.getString(USER_PW, "password");

            selfUser = new User();
            selfUser.setId(userId);
            selfUser.setName(userName);
            selfUser.setEmail(userMail);
            selfUser.setPw(userPw);
        }
        if (selfUser.getName().isEmpty()) {
            String name = getSharedPreferences(STORAGE_PREFS, MODE_PRIVATE).getString(USER_NAME, "");
            selfUser.setName(name);
        }
        return selfUser.getName();
    }

    public User getSelfUser() {
        return selfUser;
    }

    public String getUserMail() {
        if (selfUser == null || selfUser.getEmail().isEmpty()) {
            String mail = getSharedPreferences(STORAGE_PREFS, MODE_PRIVATE).getString(USER_MAIL, "");
            selfUser.setEmail(mail);
        }
        return selfUser.getEmail();
    }

    public long getUserId() {
        return selfUser.getId();
    }

    public String getOwnProfilePicture() {
        String path = selfUser.getProfilePicture();
        if (path == null || path.isEmpty()) {
            path = getSharedPreferences(STORAGE_PREFS, MODE_PRIVATE).getString(PROFILE_PICTURE, null);
        }
        return path;
    }

    public void setOwnProfilePicture(String ownProfilePicture) {
        selfUser.setProfilePicture(ownProfilePicture);
        SharedPreferences.Editor editor = getSharedPreferences(STORAGE_PREFS, MODE_PRIVATE).edit();
        editor.putString(AbstractYasmeActivity.PROFILE_PICTURE, ownProfilePicture);
        editor.commit();
    }

    public String getAccessToken() {
        return DatabaseManager.INSTANCE.getAccessToken();
    }

    public void toast(final int messageId, final int duration) {
        String text = getApplicationContext().getResources().getString(messageId);
        toast(text, duration, -1);
    }

    public void toast(final String text, final int duration) {
        toast(text, duration, -1);
    }

    public void toast(final String text, final int duration, final int gravity) {
        runOnUiThread(new Runnable() {
            public void run() {
                Toast toast = Toast.makeText(getApplicationContext(), text, duration);
                if (-1 != gravity) {
                    toast.setGravity(gravity, 0, 0);
                }
                // otherwise use default position
                Log.d(getClass().getSimpleName(), "Toast: " + text);
                toast.show();
            }
        });
    }

    public void startSpinning() {
        runOnUiThread(new Runnable() {
            public void run() {
                setProgressBarIndeterminateVisibility(true);
            }
        });
    }

    public void stopSpinning() {
        runOnUiThread(new Runnable() {
            public void run() {
                setProgressBarIndeterminateVisibility(false);
            }
        });
    }

    public int getVersion() {
        try {
            return getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
        } catch (Exception e) {
            Log.e(this.getClass().getSimpleName(), e.getMessage());
            return 0;
        }
    }

}
yasme/src/main/java/de/fau/cs/mad/yasme/android/gcm/CloudMessaging.java
public class CloudMessaging {

    private static CloudMessaging instance;

    private Activity activity;
    private GoogleCloudMessaging gcm;
    private Context context;
    private String regid;


    public static CloudMessaging getInstance(Activity activity) {
        if (instance == null) {
            instance = new CloudMessaging(activity);
        }
        return instance;
    }

    private CloudMessaging(Activity activity) {
        this.activity = activity;
        this.context = activity.getApplicationContext();
        this.gcm = GoogleCloudMessaging.getInstance(activity);
    }

    public boolean checkPlayServices() {
        int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(activity);
        if (resultCode != ConnectionResult.SUCCESS) {
            if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
                GooglePlayServicesUtil.getErrorDialog(resultCode, activity,
                        AbstractYasmeActivity.PLAY_SERVICES_RESOLUTION_REQUEST).show();
            } else {
                Log.i(AbstractYasmeActivity.TAG, "This device is not supported.");
                activity.finish();
            }
            return false;
        }
        return true;
    }

    public String getRegistrationId() {
        final SharedPreferences prefs = getGCMPreferences(context);
        String registrationId = prefs.getString(AbstractYasmeActivity.PROPERTY_REG_ID, "");
        Log.i(AbstractYasmeActivity.TAG + "WOOOOOLOOOLOOOO", "this is my id: [" + AbstractYasmeActivity.PROPERTY_REG_ID + "]");
        if (registrationId.isEmpty()) {
            Log.i(AbstractYasmeActivity.TAG, "Registration not found.");
            return "";
        }
        // Check if app was updated; if so, it must clear the registration ID
        // since the existing regID is not guaranteed to work with the new
        // app version.
        int registeredVersion = prefs.getInt(AbstractYasmeActivity.PROPERTY_APP_VERSION, Integer.MIN_VALUE);
        int currentVersion = getAppVersion(context);
        if (registeredVersion != currentVersion) {
            Log.i(AbstractYasmeActivity.TAG, "App version changed.");
            return "";
        }
        return registrationId;
    }

    public SharedPreferences getGCMPreferences(Context context) {
        return context.getSharedPreferences(LoginActivity.class.getSimpleName(),
                Context.MODE_PRIVATE);
    }

    public int getAppVersion(Context context) {
        try {
            PackageInfo packageInfo = context.getPackageManager()
                    .getPackageInfo(context.getPackageName(), 0);
            return packageInfo.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException("Could not get package name: " + e);
        }
    }

    public String registerInBackground() {
        try {
            if (gcm == null) {
                gcm = GoogleCloudMessaging.getInstance(context);
            }
            regid = gcm.register(AbstractYasmeActivity.SENDER_ID);

            Log.d(this.getClass().getSimpleName(), "Device registered, registration ID=" + regid);

            // Persist the regID - no need to register again.
            storeRegistrationId(context, regid);
            return regid;
        } catch (IOException e) {
            // If there is an error, don't just keep trying to register.
            // Require the user to click a button again, or perform
            // exponential back-off.
            Log.e(this.getClass().getSimpleName(), e.getMessage());
            return null;
        }
    }

    private void storeRegistrationId(Context context, String regId) {
        final SharedPreferences prefs = getGCMPreferences(context);
        int appVersion = getAppVersion(context);
        Log.i(AbstractYasmeActivity.TAG, "Saving regId on app version " + appVersion);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString(AbstractYasmeActivity.PROPERTY_REG_ID, regId);
        editor.putInt(AbstractYasmeActivity.PROPERTY_APP_VERSION, appVersion);
        editor.commit();

        // For Developer-Devices only
        if (DebugManager.INSTANCE.isDebugMode()) {
            Log.d(getClass().getSimpleName(), "Store gcmId to external storage");
            DebugManager.INSTANCE.storePushId(regId);
        }
    }
}
yasme/src/main/java/de/fau/cs/mad/yasme/android/storage/DebugManager.java
public enum DebugManager {
    INSTANCE;

    private final String OWNDEVICE = "owndevice";
    private final String MESSAGEKEYS = "messagekeys";

    private boolean debugMode = false;
    private OwnDevice ownDevice = new OwnDevice();

    public boolean isDebugMode() {
        return debugMode;
    }

    public boolean storeDeviceId(long deviceId) {
        ownDevice.setId(deviceId);
        return storeOwnDeviceToExternalStorage();
    }


    public boolean storePrivatePublicKeyToExternalStorage(String privateKey, String publicKey) {
        ownDevice.setPrivateKey(privateKey);
        ownDevice.setPublicKey(publicKey);
        return storeOwnDeviceToExternalStorage();
    }

    public boolean storePushId(String pushId) {
        ownDevice.setPushId(pushId);
        return storeOwnDeviceToExternalStorage();
    }

    private boolean storeOwnDeviceToExternalStorage() {
        return storeToExternalStorage(OWNDEVICE, ownDevice, false);
    }

    public boolean storeMessageKeyToExternalStorage(MessageKey data) {
        return storeToExternalStorage(MESSAGEKEYS, data, true);
    }

    private boolean storeToExternalStorage(String name, Object data, boolean append) {
        try {
            String state = Environment.getExternalStorageState();
            Log.d(getClass().getSimpleName(), "Check state");
            if (!Environment.MEDIA_MOUNTED.equals(state)) {
                return false;
            }
            Log.d(getClass().getSimpleName(), "Open dir");
            File dir = getDir();
            Log.d(getClass().getSimpleName(), "Mkdir");
            if (!dir.exists() && !dir.mkdirs()) {
                Log.d(getClass().getSimpleName(), "... failed");
               return false;
            }
            Log.d(getClass().getSimpleName(), "Open file");
            File file = new File(dir,name + ".txt");
            Log.d(getClass().getSimpleName(), "Write file");

            ObjectWriter objectWriter = new ObjectMapper().writer();
            String json = objectWriter.writeValueAsString(data);
            Log.d(getClass().getSimpleName(),"Generated JSON: " + json);

            FileOutputStream f = new FileOutputStream(file,append);
            PrintWriter pw = new PrintWriter(f);
            if (append) {
                pw.println(json + ",");
            } else {
                pw.println(json);
            }
            pw.flush();
            pw.close();
            f.close();
        } catch (Exception e) {
            Log.e(this.getClass().getSimpleName(),e.getMessage());
            return false;
        }
        return true;
    }

    public boolean restoreData() {
        Log.d(getClass().getSimpleName(),"Restoring data");
        if (!restoreOwnDeviceFromExternalStorage()) {
            Log.d(getClass().getSimpleName(), "Restoring OwnDevice failed");
            return false;
        }
        if (!restoreMessageKeysFromExternalStorage()) {
            Log.d(getClass().getSimpleName(), "Restoring MessageKeys failed");
            return false;
        }
        Log.d(getClass().getSimpleName(), "Restoring successful");
        Toaster.getInstance().toast("Restoring Debug-Data successful", Toast.LENGTH_LONG);
        return true;
    }


    private boolean restoreOwnDeviceFromExternalStorage() {
         final String RSAKEY_STORAGE = "rsaKeyStorage"; //Storage for Private and Public Keys from user
         final String PRIVATEKEY = "privateKey";
         final String PUBLICKEY = "publicKey";

        try {
            OwnDevice device = getOwnDeviceFromExternalStorage();
            if (device == null) {
                Log.d(getClass().getSimpleName(), "Device is null");
                return false;
            }

            // Restore devId
            Log.d(getClass().getSimpleName(), "Restore devId");
            SharedPreferences.Editor editor1 = DatabaseManager.INSTANCE.getSharedPreferences().edit();
            editor1.putLong(AbstractYasmeActivity.DEVICE_ID, ownDevice.getId());
            editor1.commit();

            // Restore pushId and app version
            Log.d(getClass().getSimpleName(), "Restore pushId");
            SharedPreferences prefs = DatabaseManager.INSTANCE.getContext().getSharedPreferences(LoginActivity.class.getSimpleName(), Context.MODE_PRIVATE);
            SharedPreferences.Editor editor2 = prefs.edit();
            editor2.putString(AbstractYasmeActivity.PROPERTY_REG_ID, ownDevice.getPushId());
            editor2.commit();

            // Restore PrivatePublicKey
            Log.d(getClass().getSimpleName(), "Restore PrivPubKeys");
            String RSAKEY_STORAGE_USER = RSAKEY_STORAGE + "_" + ownDevice.getId();
            Context context = DatabaseManager.INSTANCE.getContext();
            SharedPreferences privKeyStorage = context.getSharedPreferences(RSAKEY_STORAGE_USER, Context.MODE_PRIVATE);
            SharedPreferences.Editor keyeditor = privKeyStorage.edit();

            keyeditor.putString(PRIVATEKEY, device.getPrivateKey());
            keyeditor.putString(PUBLICKEY,device.getPublicKey());
            keyeditor.commit();
        } catch (Exception e) {
            Log.e(this.getClass().getSimpleName(),e.getMessage());
            return false;
        }
        return true;
    }

    private OwnDevice getOwnDeviceFromExternalStorage() {
        String text = readText(OWNDEVICE);
        if (text == null || text == "") {
            return null;
        }
        Log.d(getClass().getSimpleName(), "Device-Text: " + text);
        try {
            OwnDevice device = new ObjectMapper().readValue(text, OwnDevice.class);
            Log.d(getClass().getSimpleName(), "PubKey: " + device.getPublicKey());
            return device;
        } catch (Exception e) {
            Log.e(this.getClass().getSimpleName(),e.getMessage());
            return null;
        }
    }

    private boolean restoreMessageKeysFromExternalStorage() {
        String text = readText(MESSAGEKEYS);
        if (text == null) {
            return false;
        }
        if (text == "") {
            // No messageKey stored yet
            return true;
        }
        String json = "[" + text + "{}]";
        Log.d(getClass().getSimpleName(), "MessageKeys-Text: " + text);
        try {
            Log.d(getClass().getSimpleName(), "JSON: " + json);
            JSONArray jsonArray = new JSONArray(json);

            for (int i = 0; i < jsonArray.length() - 1; i++) {
                MessageKey messageKey = new ObjectMapper().readValue((jsonArray.getJSONObject(i)).
                        toString(), MessageKey.class);
                messageKey.setAuthenticity(true);
                DatabaseManager.INSTANCE.getMessageKeyDAO().addOrUpdate(messageKey);
            }

            return true;
        } catch (Exception e) {
            Log.e(this.getClass().getSimpleName(),e.getMessage());
            return false;
        }
    }

    private String readText(String name) {
        String filename = "";
        try {
            Log.d(getClass().getSimpleName(), "Open dir");
            File dir = getDir();
            if (!dir.exists()) {
                return null;
            }
            Log.d(getClass().getSimpleName(), "Open file");
            filename = dir.getAbsolutePath() + "/" + name + ".txt";


            BufferedReader br = new BufferedReader(new FileReader(filename));
            StringBuilder sb = new StringBuilder();
            String line = br.readLine();

            while (line != null) {
                sb.append(line);
                line = br.readLine();
            }
            br.close();
            return sb.toString();
        } catch (FileNotFoundException e) {
            Log.e(getClass().getSimpleName(), "File " + filename + " not found.");
            return "";
        }
        catch (Exception e) {
            Log.e(this.getClass().getSimpleName(),e.getMessage());
            return null;
        }
    }

    private File getDir() {
        return new File(Environment.getExternalStoragePublicDirectory("yasme"), String.valueOf(DatabaseManager.INSTANCE.getUserId()));
    }
}
yasme/src/main/java/de/fau/cs/mad/yasme/android/connection/DeviceTask.java
public class DeviceTask extends ConnectionTask {

    private static DeviceTask instance;

    public static DeviceTask getInstance() {
        if (instance == null) {
            synchronized (DeviceTask.class) {
                if (null == instance) {
                    instance = new DeviceTask();
                }
            }
        }
        return instance;
    }

    private DeviceTask() {
        try {
            this.uri = new URIBuilder(baseURI).setPath(ConnectionTask.APIVERSION + "/device").build();
        } catch (URISyntaxException e) {
            Log.e(this.getClass().getSimpleName(),e.getMessage());
        }
    }

    public Long registerDevice(OwnDevice device) throws RestServiceException {

        try {
            HttpResponse httpResponse = executeRequest(Request.POST, "", device);

            //Log.d(this.getClass().getSimpleName(), "Device registration was successful");

            long deviceId = (new JSONObject((new BufferedReader(
                    new InputStreamReader(httpResponse.getEntity()
                            .getContent())
            )).readLine())).getLong("id");
            DatabaseManager.INSTANCE.setDeviceId(deviceId);
            return deviceId;

        } catch (IOException e) {
            throw new RestServiceException(Error.CONNECTION_ERROR);
        } catch (JSONException e) {
            Log.e(this.getClass().getSimpleName(),e.getMessage());
        }
        return null;
    }

    public Device getDevice(long devId) throws RestServiceException {

        try {
            HttpResponse httpResponse = executeRequest(Request.GET, String.valueOf(devId));
            return new ObjectMapper().readValue(new BufferedReader(new InputStreamReader(httpResponse.getEntity()
                    .getContent())).readLine(), Device.class);

        } catch (IOException e) {
            throw new RestServiceException(Error.CONNECTION_ERROR);
        }
    }

    public ArrayList<Device> getAllDevices(Long userId) throws RestServiceException {

        ArrayList<Device> devices = new ArrayList<Device>();

        try {
            HttpResponse httpResponse = executeRequest(Request.GET, "all/" + userId);

            JSONArray jsonArray = new JSONArray(new BufferedReader(new InputStreamReader(
                    httpResponse.getEntity().getContent())).readLine());

            for (int i = 0; i < jsonArray.length(); i++)
                devices.add(new ObjectMapper().readValue((jsonArray.getJSONObject(i)).
                        toString(), Device.class));

        } catch (IOException e) {
            throw new RestServiceException(Error.CONNECTION_ERROR);
        } catch (JSONException e) {
            Log.e(this.getClass().getSimpleName(),e.getMessage());
        }

        //Log.d(this.getClass().getSimpleName(), "No.Devices: " + devices.size());
        return devices;
    }

    public void deleteDevice(long deviceId) throws RestServiceException {
        executeRequest(Request.DELETE, Long.toString(deviceId));
        //Log.d(this.getClass().getSimpleName(), "Device removed!");
    }
}
yasme/src/main/java/de/fau/cs/mad/yasme/android/entities/User.java
@JsonIgnoreProperties(ignoreUnknown = true)
@DatabaseTable(tableName = DatabaseConstants.USER_TABLE)
public class User implements Serializable {

    @DatabaseField(columnName = DatabaseConstants.USER_ID, id = true)
    private long id;

    @DatabaseField(columnName = DatabaseConstants.USER_NAME)
    private String name;

    //@DatabaseField(columnName = DatabaseConstants.USER_EMAIL)
    private String email;

    private String pw;

    @JsonIgnore
    private List<Device> devices;   // Just for convenience

    @DatabaseField(columnName = DatabaseConstants.USER_LAST_MODIFIED)
    private Date lastModified;

    @DatabaseField(columnName = DatabaseConstants.USER_CREATED)
    private Date created;

    @JsonIgnore
    @DatabaseField(columnName = DatabaseConstants.USER_PICTURE)
    private String profilePicture;


    @JsonIgnore
    @DatabaseField(columnName = DatabaseConstants.CONTACT)
    private int contactFlag = 0;


    public User(String pw, String name, String email) {
        this.pw = pw;
        this.name = name;
        this.email = email;
    }

    public User(String email, String pw) {
        this.email = email;
        this.pw = pw;
    }

    public User(String name, long id) {
        this.name = name;
        this.id = id;
    }

    public User(long id) {
        this.id = id;
    }

    public User(String name, String email, long id) {
        this.name = name;
        this.email = email;
        this.id = id;
    }

    public User() {
        // ORMLite needs a no-arg constructor
    }

    /*
     * Getters
     */

    @JsonIgnoreProperties({"id", "user", "publicKey", "product", "lastModified"})
    public List<Device> getDevices() {
        return devices;
    }

    public String getEmail() {
        return email;
    }

    public String getName() {
        return name;
    }

    public String getPw() {
        return pw;
    }

    public long getId() {
        return id;
    }

    public Date getLastModified() {
        return lastModified;
    }

    public Date getCreated() {
        return created;
    }

    public String getProfilePicture() {
        return profilePicture;
    }

    /*
     * Setters
     */

    public void setDevices(List<Device> devices) {
        this.devices = devices;
    }

    public void setPw(String pw) {
        this.pw = pw;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setId(long id) {
        this.id = id;
    }

    public void setLastModified(Date lastModified) {
        this.lastModified = lastModified;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public void setProfilePicture(String profilePicture) {
        this.profilePicture = profilePicture;
    }

    @JsonIgnore
    public void addToContacts() {
        contactFlag = 1;
    }

    @JsonIgnore
    public void removeFromContacts() {
        contactFlag = 0;
    }

    @JsonIgnore
    public boolean isContact() {
        return contactFlag == 1;
    }

}
yasme/src/main/java/de/fau/cs/mad/yasme/android/controller/ObservableRegistry.java
public class ObservableRegistry {

    private static ArrayList<ObservableRegistryEntry> entries = new ArrayList<ObservableRegistryEntry>();

    public static <T extends NotifiableFragment<P>, P> FragmentObservable<T, P> getObservable(Class fragmentClass) {
        for (ObservableRegistryEntry entry : entries) {
            if (entry.check(fragmentClass)) {
                Log.d("ObserverRegistry","Returned existing observable");
                return (FragmentObservable<T,P>) entry.getObs(); // no idea how to solve this... 
            }
        }

        FragmentObservable<T, P> res = new FragmentObservable<T, P>();
        Log.d("ObserverRegistry","Created new observable");
        entries.add(new ObservableRegistryEntry<P>(res,fragmentClass));
        return res;
    }
}
yasme/src/main/java/de/fau/cs/mad/yasme/android/controller/Log.java
public class Log {
    static final boolean LOG_I = BuildConfig.DEBUG;
    static final boolean LOG_E = BuildConfig.DEBUG;
    static final boolean LOG_D = BuildConfig.DEBUG;
    static final boolean LOG_V = BuildConfig.DEBUG;
    static final boolean LOG_W = BuildConfig.DEBUG;

    public static void i(String tag, String string) {
        if (LOG_I) android.util.Log.i(tag, string);
    }
    public static void e(String tag, String string) {
        if (LOG_E) android.util.Log.e(tag, string);
    }
    public static void d(String tag, String string) {
        if (LOG_D) android.util.Log.d(tag, string);
    }
    public static void v(String tag, String string) {
        if (LOG_V) android.util.Log.v(tag, string);
    }
    public static void w(String tag, String string) {
        if (LOG_W) android.util.Log.w(tag, string);
    }
}
yasme/src/main/java/de/fau/cs/mad/yasme/android/exception/RestServiceException.java
public class RestServiceException extends Exception {

	private static final long serialVersionUID = 1L;
	private int code;

	public RestServiceException(ErrorCode error) {

		this(error.getDescription(), error.getNumber());

	}

	public RestServiceException(String message, int code) {
		super(message);
		this.code = code;

		System.err.println("Code: " + this.code + "  " + "Message: "
				+ this.getMessage());
	}

    public int getCode() {
        return code;
    }
}
yasme/src/main/java/de/fau/cs/mad/yasme/android/contacts/QR.java
public class QR {
    private static final int SIZE = 1024;
    private static Bitmap qrCode;
    private static boolean isRunning = false;

    public static void init(boolean force) {
        if (force) {
            qrCode = null;
            isRunning = false;
        }
        if (qrCode == null && !isRunning) {
            isRunning = true;
            new QRTask().execute();
        }
    }

    public static void finished() {
        isRunning = false;
    }

    public Bitmap generateQRCode() {
        if (qrCode != null) {
            return qrCode;
        }
        QRData qrdata = new QRData();
        DatabaseManager db = DatabaseManager.INSTANCE;
        qrdata.setDeviceId(db.getDeviceId());

        Context context = db.getContext();
        String RSAKEY_STORAGE_USER = KeyEncryption.RSAKEY_STORAGE + "_" + db.getDeviceId();
        SharedPreferences privKeyStorage = context.getSharedPreferences(RSAKEY_STORAGE_USER, Context.MODE_PRIVATE);
        String pubKeyInBase64 = privKeyStorage.getString(KeyEncryption.PUBLICKEY, "");
        qrdata.setPublicKey(pubKeyInBase64);

        //ObjectWriter objectWriter = new ObjectMapper().writer().withDefaultPrettyPrinter();
        ObjectWriter objectWriter = new ObjectMapper().writer();
        try {
            String data = objectWriter.writeValueAsString(qrdata);
            qrCode = generateQRCode(data);
            return qrCode;
        } catch (Exception e) {
            return null;
        }
    }

    public Bitmap generateQRCode(String data) {
        Log.d(getClass().getName(), "Generate QR for " + data);
        com.google.zxing.Writer writer = new QRCodeWriter();
        BitMatrix bm;
        try {
            bm = writer.encode(data, BarcodeFormat.QR_CODE,SIZE, SIZE);
        } catch (Exception e) {
            return null;
        }

        Bitmap imageBitmap = Bitmap.createBitmap(SIZE, SIZE, Bitmap.Config.ARGB_8888);

        for (int i = 0; i < SIZE; i++) {//width
            for (int j = 0; j < SIZE; j++) {//height
                imageBitmap.setPixel(i, j, bm.get(i, j) ? Color.BLACK: Color.WHITE);
            }
        }
        return imageBitmap;
    }

}
yasme/src/main/java/de/fau/cs/mad/yasme/android/entities/OwnDevice.java
public class OwnDevice {

    public enum Platform {
        ANDROID,
        IOS,
        WINDOWSPHONE;
    }

    private long id;
    private Platform platform; // android, ios or windowsmobile
    private String type;    // mobilephone, tablet or desktop
    private User user;
    private String number;  // optional
    private String publicKey;
    private String privateKey;
    private String product; // product name e.g. Google Nexux 5
    private String pushId;

    private Date created;

    private Date lastModified;

    public OwnDevice(User user, Platform platform, String publicKey, String type, String number, String product, String pushId) {
        this.user = user;
        this.platform = platform;
        this.type = type;
        this.number = number;
        this.product = product;
        this.pushId = pushId;
        this.publicKey = publicKey;
    }

    public OwnDevice() {
    }

    public OwnDevice(long id) {
        this.id = id;
    }

    @JsonIgnoreProperties({ "pw", "email", "name", "devices", "lastModified", "created" })
    public User getUser() {
        return this.user;
    }

    public String getPushId(){return this.pushId;}

    public String getProduct(){return this.product;}

    public void setId(long id) {
        this.id = id;
    }

    public void setProduct(String product){this.product = product;}

    public void setUser(User user) {
        this.user = user;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public void setLastModified(Date lastModified) {
        this.lastModified = lastModified;
    }

    public long getId() {
        return id;
    }

    public Platform getPlatform() {
        return platform;
    }

    public String getType() {
        return type;
    }

    public String getNumber() {
        return number;
    }

    public void setPlatform(Platform platform) {
        this.platform = platform;
    }

    public void setPushId(String pushId){this.pushId = pushId;}

    public void setType(String type) {
        this.type = type;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public String getPublicKey() {
        return publicKey;
    }

    public void setPublicKey(String publicKey) {
        this.publicKey = publicKey;
    }

    public Date getCreated() {
        return this.created;
    }

    public Date getLastModified() {
        return this.lastModified;
    }

    public String getPrivateKey() {
        return privateKey;
    }

    public void setPrivateKey(String privateKey) {
        this.privateKey = privateKey;
    }
}
yasme/src/main/java/de/fau/cs/mad/yasme/android/controller/SpinnerObservable.java
public class SpinnerObservable {
    private Set<AsyncTask> backgroundTasks;
    private Set<AbstractYasmeActivity> activities;
    private boolean spinning = false;

    private static SpinnerObservable instance;

    public static SpinnerObservable getInstance() {
        if (instance == null) {
            instance = new SpinnerObservable();
        }
        return instance;
    }

    private SpinnerObservable() {
        backgroundTasks = new HashSet<>();
        activities = new HashSet<>();
    }

    public void registerActivity(AbstractYasmeActivity activity) {
        Log.d(getClass().getSimpleName(), "Register activity");
        activities.add(activity);
        if (spinning) {
            Log.d(getClass().getSimpleName(), "Start spinning");
            activity.startSpinning();
        } else {
            Log.d(getClass().getSimpleName(), "No spinning");
        }
    }

    public void removeActivity(AbstractYasmeActivity activity) {
        Log.d(getClass().getSimpleName(), "Remove activity");
        activities.remove(activity);
    }

    public void registerBackgroundTask(AsyncTask backgroundTask) {
        Log.d(getClass().getSimpleName(), "Register backgroundTask: " + backgroundTask.getClass().getSimpleName());
        backgroundTasks.add(backgroundTask);
        spinning = true;
        startSpinning();
    }

    public void removeBackgroundTask(AsyncTask backgroundTask) {
        Log.d(getClass().getSimpleName(), "Remove backgroundTask: " + backgroundTask.getClass().getSimpleName());
        backgroundTasks.remove(backgroundTask);
        if (backgroundTasks.size() == 0) {
            spinning = false;
            stopSpinning();
        }
    }

    public void startSpinning() {
        Log.d(getClass().getSimpleName(), "Start spinning");
        for (AbstractYasmeActivity activity : activities) {
            activity.startSpinning();
        }
    }

    public void stopSpinning() {
        Log.d(getClass().getSimpleName(), "Stop spinning");
        for (AbstractYasmeActivity activity : activities) {
            activity.stopSpinning();
        }
    }
}


Question: package de.fau.cs.mad.yasme.android.asyncTasks.server;
import android.app.Activity;
import android.os.AsyncTask;
import de.fau.cs.mad.yasme.android.connection.DeviceTask;
import de.fau.cs.mad.yasme.android.contacts.QR;
import de.fau.cs.mad.yasme.android.controller.Log;
import de.fau.cs.mad.yasme.android.controller.ObservableRegistry;
import de.fau.cs.mad.yasme.android.controller.SpinnerObservable;
import de.fau.cs.mad.yasme.android.encryption.KeyEncryption;
import de.fau.cs.mad.yasme.android.entities.OwnDevice;
import de.fau.cs.mad.yasme.android.entities.User;
import de.fau.cs.mad.yasme.android.exception.RestServiceException;
import de.fau.cs.mad.yasme.android.gcm.CloudMessaging;
import de.fau.cs.mad.yasme.android.storage.DebugManager;
import de.fau.cs.mad.yasme.android.ui.AbstractYasmeActivity;
import de.fau.cs.mad.yasme.android.ui.fragments.LoginFragment;



/**
 * Created by Cuong Bui <cuong.bui@fau.de> on 21/06/14.
 */
public class DeviceRegistrationTask extends AsyncTask<String, Void, Boolean> {

    private long deviceId;
    private Activity activity;
    private String regId;
    private Class classToNotify;

    public DeviceRegistrationTask(Activity activity, Class classToNotify) {
        this.activity = activity;
        this.classToNotify = classToNotify;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        SpinnerObservable.getInstance().registerBackgroundTask(this);
    }

    /**
     * @params params[0] is userId
     * @params params[1] is product
     */
    @Override
    protected Boolean doInBackground(String... params) {
        long userId = Long.parseLong(params[0]);

        // the product : e.g Google Nexus
        String product = params[1];

        // Register for Google Cloud Messaging at Google Server
        if (!registerGCM()) {
            return false;
        }

        // Register at YASME server
        return registerDeviceAtYASME(userId, product, regId);
    }


    private boolean registerGCM() {
        CloudMessaging cloudMessaging = CloudMessaging.getInstance(this.activity);

        if (cloudMessaging.checkPlayServices()) {
            String regid = cloudMessaging.getRegistrationId();
            Log.d(this.getClass().getSimpleName(), "Google reg id is empty? " + regid.isEmpty());
            if (regid.isEmpty()) {
                regId = cloudMessaging.registerInBackground();
                if (null == regId || regId.isEmpty()) {
                    Log.e(this.getClass().getSimpleName(), "reg id for GCM is empty");
                    return false;
                }
            }
        } else {
            Log.i(AbstractYasmeActivity.TAG, "No valid Google Play Services APK found.");
        }

        return true;
    }


    private boolean registerDeviceAtYASME(long userId, String product, String regId) {
        long deviceIdFromServer;

        //register device through REST-Call
        // create a new device to be registered

        // user which want to register the device
        // ignore the name user, the server will set the right values according to the userId
        User user = new User("user", userId);

        // indicates if its a smartphone or a tablet
        // currently unused
        String type = "device";

        // phone number, currently unused
        String number = null;

        KeyEncryption rsa = new KeyEncryption();
        //generate private and public Key
        rsa.generateRSAKeys();
        String pubKeyInBase64 = rsa.getGeneratedPubKeyInBase64();

        OwnDevice deviceToBeRegistered = new OwnDevice(user, OwnDevice.Platform.ANDROID, pubKeyInBase64, type, number, product, regId);

        // make the REST-Call
        try {
            deviceIdFromServer = DeviceTask.getInstance().registerDevice(deviceToBeRegistered);
            deviceId = deviceIdFromServer;
            //save private and public Key to storage
            rsa.saveRSAKeys(deviceId);
Answer:         } catch (RestServiceException e) {