yasme/src/main/java/de/fau/cs/mad/yasme/android/encryption/PasswordEncryption.java
public class PasswordEncryption{

    private static final String SALT = "Y45M3";
    private User user;

    public PasswordEncryption(User user) {
        this.user = user;
    }

    /**
     * get a secure password (hashed and salted)
     *
     * @return user-object containing the secure password
     */
    public User securePassword(){
        String secure = getSecurePassword();
        user.setPw(secure);
        return user;
    }


    /**
     * get a secure password (hashed and salted)
     *
     * @return hashed and salted password as String
     */
    public String getSecurePassword(){
        return SHA512(salt(SALT,user.getPw()));
    }


    /**
     * hash the password using SHA-512
     *
     * @param password password that should be hashed
     * @return hashed String
     */
    private String SHA512(String password){
       try {
           MessageDigest md = MessageDigest.getInstance("SHA-512");
           md.update(password.getBytes("UTF-8"));
           byte[] hash = md.digest();
           Base64 base64 = new Base64();
           return new String(base64.base64Encode(hash));
       }
       catch (Exception e){
           Log.d(this.getClass().getSimpleName(), "Hashing Password failed");
           Log.d(this.getClass().getSimpleName(), "Error: " + e.getMessage());
       }
       return null;
    }

    /**
     * salt the password
     *
     * @param salt salt-value that should be used
     * @param password password that should be secured
     * @return salted password
     */
    private String salt(String salt, String password){
        String passwordSalted = salt+password;
        return passwordSalted;
    }
}
yasme/src/main/java/de/fau/cs/mad/yasme/android/ui/activities/ChatListActivity.java
public class ChatListActivity extends AbstractYasmeActivity {

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

        //progress bar in actionbar
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);

        setContentView(R.layout.activity_with_single_fragment);

        if (HttpClient.context == null) {
            HttpClient.context = this.getApplicationContext();
        }

        SharedPreferences devicePrefs = getSharedPreferences(DEVICE_PREFS, MODE_PRIVATE);

        // Make sure that the device has been registered. Otherwise several other tasks will fail
        long deviceId = DatabaseManager.INSTANCE.getDeviceId();
        if (deviceId <= 0) {
            Log.e(this.getClass().getSimpleName(), "Device id should not be <= 0 after login. " +
                    "Looks like the device registration failed but no one was notified about that");
        }

        if (savedInstanceState == null) {
            getFragmentManager().beginTransaction()
                    .add(R.id.singleFragmentContainer, new ChatListFragment()).commit();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.chatlist, menu);
        return true;
    }

    @Override
    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.
        int id = item.getItemId();
        if (id == R.id.action_add_chat) {
            Intent intent = new Intent(this, InviteToChatActivity.class);
            startActivity(intent);
            return true;
        }
        if (id == R.id.sign_out) {
            new LogoutTask().execute();
        }
        return super.onOptionsItemSelected(item);
    }

    protected void startLoginActivity() {
        //setSignedInFlag(false);
        DatabaseManager.INSTANCE.setAccessToken(null);
        Intent intent = new Intent(this, LoginActivity.class);
        startActivity(intent);
        finish();
    }

    private class LogoutTask extends AsyncTask<Void, Void, Boolean> {
        @Override
        protected Boolean doInBackground(Void... voids) {
            try {
                AuthorizationTask.getInstance().logoutUser();
            } catch (RestServiceException e) {
                Log.e(this.getClass().getSimpleName(), e.getMessage());
                Log.i(this.getClass().getSimpleName(), "Sign out not succesfull");
                return false;
            }
            return true;
        }

        protected void onPostExecute(Boolean success) {
            if (!success) {
                return;
            }
            startLoginActivity();
        }
    }
}
yasme/src/main/java/de/fau/cs/mad/yasme/android/entities/ServerInfo.java
public class ServerInfo {
    String message;
    boolean loginAllowed = true;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public boolean getLoginAllowed() {
        return loginAllowed;
    }

    public void setLoginAllowed(boolean loginAllowed) {
        this.loginAllowed = loginAllowed;
    }

    public boolean hasMessage() {
        return message != null && message.length() > 0;
    }
}
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/asyncTasks/server/ChangePasswordTask.java
public class ChangePasswordTask extends AsyncTask<String, Void, Boolean> {
    private User user;
    private String task;

    public ChangePasswordTask(User user) {
        this.user = user;
    }

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

    /**
     * @param params 0 is flag for preparation to change password
     *               1 is mailToken
     * @return Returns true if it was successful, otherwise false
     */
    @Override
    protected Boolean doInBackground(String... params) {
        if (user.getEmail() == null || user.getEmail().isEmpty()) {
            return false;
        }
        task = params[0];
        if (task.equals("1")) {
            try {
                UserTask.getInstance().requirePasswordToken(user);
            } catch (RestServiceException e) {
                Log.e(this.getClass().getSimpleName(), e.getMessage());
                return false;
            }
        } else {
            try {
                UserTask.getInstance().changePassword(user, params[1]);
            } catch (RestServiceException e) {
                Log.e(this.getClass().getSimpleName(), e.getMessage());
                return false;
            }
        }
        return true;
    }

    @Override
    protected void onPostExecute(final Boolean success) {
        SpinnerObservable.getInstance().removeBackgroundTask(this);
        if (success) {
            if (task.equals("1")) {
                Toaster.getInstance().toast(
                        DatabaseManager.INSTANCE.getContext().getString(R.string.sent_token_mail)
                                + " " + user.getEmail(),
                        Toast.LENGTH_SHORT);
            } else {
                Toaster.getInstance().toast(R.string.successful_changed_password, Toast.LENGTH_LONG);
            }
        } else {
            Toaster.getInstance().toast(R.string.error_change_password, Toast.LENGTH_LONG);
        }
    }
}
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/asyncTasks/server/DeviceRegistrationTask.java
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);
        } catch (RestServiceException e) {
            // if error occurs return false
            Log.e(this.getClass().getSimpleName(), e.getMessage());
            return false;
        }

        Log.d(this.getClass().getSimpleName(), "Device registered at yasme server");
        QR.init(true);
        // For Developer-Devices only
        if (DebugManager.INSTANCE.isDebugMode()) {
            Log.d(getClass().getSimpleName(), "Store keys to external storage");
            DebugManager.INSTANCE.storeDeviceId(deviceId);
        }

        return true;
    }

    @Override
    protected void onPostExecute(final Boolean success) {
        SpinnerObservable.getInstance().removeBackgroundTask(this);
        // after device registration
        ObservableRegistry.getObservable(classToNotify)
                .notifyFragments(new LoginFragment.DeviceRegistrationParam(success));
    }
}
yasme/src/main/java/de/fau/cs/mad/yasme/android/asyncTasks/server/UserLoginTask.java
public class UserLoginTask extends AsyncTask<String, Void, Boolean> {
    private Boolean plainPassword = false;
    private String email;
    private String password;
    private Class classToNotify;

    public UserLoginTask(Boolean plainPassword, Class classToNotify) {
        this.plainPassword = plainPassword;
        this.classToNotify = classToNotify;
    }

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

    /**
     * @param params 0 is email
     *               1 is password
     * @return
     */
    protected Boolean doInBackground(String... params) {
        GetInfoTask getInfoTask = new GetInfoTask(0);
        getInfoTask.execute();

        email = params[0].toLowerCase();
        password = params[1];
        try {
            // DEBUG:
            //Log.d(this.getClass().getSimpleName(), "email: " + email + " " + "password: " + password);

            if (plainPassword) {
                PasswordEncryption pwEnc = new PasswordEncryption(new User(email, password));
                password = pwEnc.getSecurePassword();
            }

            String loginReturn[] = AuthorizationTask.getInstance().loginUser(new User(email, password));
        } catch (RestServiceException e) {
            Log.e(this.getClass().getSimpleName(), e.getMessage());
            return false;
        }

        return true;
    }

    @Override
    protected void onPostExecute(final Boolean success) {
        SpinnerObservable.getInstance().removeBackgroundTask(this);
        if (success) {
            // Store email address for later use
            DatabaseManager.INSTANCE.setUserEmail(email);
        }
        ObservableRegistry.getObservable(classToNotify).notifyFragments(
                new LoginFragment.LoginProcessParam(success));
    }
}
yasme/src/main/java/de/fau/cs/mad/yasme/android/controller/FragmentObservable.java
public class FragmentObservable<T extends NotifiableFragment<P>,  P> {
    private Set<T> fragments;
    private P buffer;

    public FragmentObservable() {
        fragments = new HashSet<T>();
    }

    public void register(T fragment) {
        fragments.add(fragment);
        if (buffer != null) {
            notifyFragments(buffer);
        }
    }

    public void remove(T fragment) {
        fragments.remove(fragment);
    }

    //addIfNotExists
    public void notifyFragments(P parameter) {
        buffer = parameter;
        for (T fragment : fragments) {
            try {
                Log.d(this.getClass().getSimpleName(), "Notify fragment: " + fragment.getClass().getSimpleName());
                fragment.notifyFragment(parameter);
                buffer = null;
            } catch (Exception e) {
                Log.e(this.getClass().getSimpleName(), "Notify fragment failed: " + fragment.getClass().getSimpleName());
            }
        }
    }
}
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/controller/NotifiableFragment.java
public interface NotifiableFragment<T> {

    void notifyFragment(T value);
}
yasme/src/main/java/de/fau/cs/mad/yasme/android/controller/Toaster.java
public class Toaster {
    private static Toaster instance;
    private Context context;
    private Set<Toastable> toastables = new HashSet<>();

    private Toaster() {
        context = DatabaseManager.INSTANCE.getContext();
    }

    public static Toaster getInstance() {
        if (instance == null) {
            instance = new Toaster();
        }
        return instance;
    }

    public void register(Toastable toast) {
        toastables.add(toast);
    }

    public void remove(Toastable toast) {
        toastables.remove(toast);
    }

    public void toast(int id, int duration) {
        for (Toastable toast : toastables) {
            toast.toast(id,duration);
        }
    }

    public void toast(String text, int duration) {
        for (Toastable toast : toastables) {
            toast.toast(text, duration);
        }
    }

    public void toast(String text, int duration, int gravity) {
        for (Toastable toast : toastables) {
            toast.toast(text, duration, gravity);
        }
    }
}
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/storage/DatabaseManager.java
public enum DatabaseManager {
    INSTANCE;

    private boolean mInitialized = false;
    private boolean mDBInitialized = false;
    private DatabaseHelper mHelper;
    private Context mContext;
    private long mUserId = -1;
    private long mDeviceId = -1;
    private String mAccessToken = null;
    private long serverInfoUpdateTime = -1;
    private ServerInfo serverInfo = null;
    private SharedPreferences mSharedPreferences, mSettings;
    private String mUserEmail;
    private NewMessageNotificationManager notifier = null;

    private UserDAO userDAO;
    private ChatDAO chatDAO;
    private MessageDAO messageDAO;
    private MessageKeyDAO messageKeyDAO;
    private DeviceDAO deviceDAO;


    public void init(Context context, SharedPreferences sharedPreferences,
                     SharedPreferences settings, long userId) {
        mContext = context;
        mSharedPreferences = sharedPreferences;
        mSettings = settings;
        mUserId = userId;
        initDB(context, userId);
        initializeDAOs();
        mInitialized = true;
    }

    public void initDB(Context context, long userId) {
        mHelper = new DatabaseHelper(context, userId);
        mDBInitialized = true;
    }

    public boolean isInitialized() {
        return mInitialized;
    }

    public boolean isDBInitialized() {
        return mDBInitialized;
    }

    private DatabaseHelper getHelper() {
        return mHelper;
    }

    public SharedPreferences getSharedPreferences() {
        return mSharedPreferences;
    }

    public SharedPreferences getSettings() {
        return mSettings;
    }

    public Context getContext() {
        return mContext;
    }

    private void initializeDAOs() {
        UserDAOImpl.INSTANCE.setDatabaseHelper(mHelper);
        userDAO = UserDAOImpl.INSTANCE;

        ChatDAOImpl.INSTANCE.setDatabaseHelper(mHelper);
        chatDAO = ChatDAOImpl.INSTANCE;

        MessageDAOImpl.INSTANCE.setDatabaseHelper(mHelper);
        messageDAO = MessageDAOImpl.INSTANCE;

        MessageKeyDAOImpl.INSTANCE.setDatabaseHelper(mHelper);
        messageKeyDAO = MessageKeyDAOImpl.INSTANCE;

        DeviceDAOImpl.INSTANCE.setDatabaseHelper(mHelper);
        deviceDAO = DeviceDAOImpl.INSTANCE;
    }

    public UserDAO getUserDAO() {
        return userDAO;
    }

    public ChatDAO getChatDAO() {
        return chatDAO;
    }

    public MessageDAO getMessageDAO() {
        return messageDAO;
    }

    public MessageKeyDAO getMessageKeyDAO() {
        return messageKeyDAO;
    }

    public DeviceDAO getDeviceDAO() {
        return deviceDAO;
    }

    public long getUserId() {
        if (-1 == mUserId) {
            mUserId = getSharedPreferences().getLong(AbstractYasmeActivity.USER_ID, -1);
        }
        return mUserId;
    }

    public void setUserId(long mUserId) {
        this.mUserId = mUserId;
        SharedPreferences.Editor editor = getSharedPreferences().edit();
        editor.putLong(AbstractYasmeActivity.USER_ID, mUserId);
        editor.apply();
    }

    public long getDeviceId() {
        if (-1 == mDeviceId) {
            mDeviceId = getSharedPreferences().getLong(AbstractYasmeActivity.DEVICE_ID, -1);
        }
        return mDeviceId;
    }

    public void setDeviceId(long mDeviceId) {
        this.mDeviceId = mDeviceId;
        SharedPreferences.Editor editor = getSharedPreferences().edit();
        editor.putLong(AbstractYasmeActivity.DEVICE_ID, mDeviceId);
        editor.apply();
    }

    public String getAccessToken() {
        if (null == mAccessToken) {
            mAccessToken = getSharedPreferences().getString(AbstractYasmeActivity.ACCESSTOKEN, null);
        }
        return mAccessToken;
    }

    public void setAccessToken(String accessToken) {
        this.mAccessToken = accessToken;
        SharedPreferences.Editor editor = getSharedPreferences().edit();
        editor.putString(AbstractYasmeActivity.ACCESSTOKEN, mAccessToken);
        editor.commit();
    }

    public long getServerInfoUpdateTime() {
        if (-1 == serverInfoUpdateTime) {
            serverInfoUpdateTime = getSharedPreferences().getLong(AbstractYasmeActivity.SERVERINFOUPDATETIME, -1);
        }
        return serverInfoUpdateTime;
    }

    public void setServerInfoUpdateTime() {
        this.serverInfoUpdateTime = System.currentTimeMillis();
        SharedPreferences.Editor editor = getSharedPreferences().edit();
        editor.putLong(AbstractYasmeActivity.SERVERINFOUPDATETIME, serverInfoUpdateTime);
        editor.commit();
    }

    public ServerInfo getServerInfo() {
        return serverInfo;
    }

    public void setServerInfo(ServerInfo serverInfo) {
        this.serverInfo = serverInfo;
    }

    public String getUserEmail() {
        if (null == mUserEmail || "" == mUserEmail) {
            mUserEmail = getSharedPreferences().getString(AbstractYasmeActivity.USER_MAIL, null);
        }
        return mUserEmail;
    }

    public void setUserEmail(String mUserEmail) {
        this.mUserEmail = mUserEmail;
        SharedPreferences.Editor editor = getSharedPreferences().edit();
        editor.putString(AbstractYasmeActivity.USER_MAIL, mUserEmail);
        editor.commit();
    }

    public NewMessageNotificationManager getNotifier() {
        if (notifier == null) {
            notifier = new NewMessageNotificationManager();
        }
        return notifier;
    }
}
yasme/src/main/java/de/fau/cs/mad/yasme/android/EditTextWithX.java
public class EditTextWithX {
    private EditText et;
    private Drawable x;

    public EditTextWithX(Context context) {
        et = new EditText(context);
        x = context.getResources().getDrawable(R.drawable.ic_action_cancel);
        x.setBounds(0, 0, x.getIntrinsicWidth(), x.getIntrinsicHeight());
        et.setCompoundDrawables(null, null, et.getText().toString().equals("") ? null : x, null);
        et.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (et.getCompoundDrawables()[2] == null) {
                    return false;
                }
                if (motionEvent.getAction() != MotionEvent.ACTION_UP) {
                    return false;
                }
                if (motionEvent.getX() > et.getWidth() - et.getPaddingRight() - x.getIntrinsicWidth()) {
                    et.setText("");
                    et.setCompoundDrawables(null, null, null, null);
                }
                return false;
            }
        });
        et.addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                et.setCompoundDrawables(null, null, et.getText().toString().equals("") ? null : x, null);
            }

            @Override
            public void afterTextChanged(Editable arg0) {

            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }
        });
    }

    public EditText getEditText() {
        return et;
    }
}
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;
    }

}


Question: import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.text.InputType;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.util.regex.Pattern;
import de.fau.cs.mad.yasme.android.BuildConfig;
import de.fau.cs.mad.yasme.android.EditTextWithX;
import de.fau.cs.mad.yasme.android.R;
import de.fau.cs.mad.yasme.android.asyncTasks.server.ChangePasswordTask;
import de.fau.cs.mad.yasme.android.asyncTasks.server.DeviceRegistrationTask;
import de.fau.cs.mad.yasme.android.asyncTasks.server.UserLoginTask;
import de.fau.cs.mad.yasme.android.controller.FragmentObservable;
import de.fau.cs.mad.yasme.android.controller.Log;
import de.fau.cs.mad.yasme.android.controller.NotifiableFragment;
import de.fau.cs.mad.yasme.android.controller.ObservableRegistry;
import de.fau.cs.mad.yasme.android.controller.Toaster;
import de.fau.cs.mad.yasme.android.encryption.PasswordEncryption;
import de.fau.cs.mad.yasme.android.entities.ServerInfo;
import de.fau.cs.mad.yasme.android.entities.User;
import de.fau.cs.mad.yasme.android.storage.DatabaseManager;
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.activities.ChatListActivity;
        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");
Answer:             ServerInfo serverInfo = DatabaseManager.INSTANCE.getServerInfo();