account wizard: create account before profile

Change-Id: I02959bde98ef34e037881c255bbb70540ee80fb8
diff --git a/ring-android/app/src/main/java/cx/ring/account/AccountCreationModelImpl.java b/ring-android/app/src/main/java/cx/ring/account/AccountCreationModelImpl.java
new file mode 100644
index 0000000..72807c8
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/account/AccountCreationModelImpl.java
@@ -0,0 +1,106 @@
+/*
+ *  Copyright (C) 2004-2018 Savoir-faire Linux Inc.
+ *
+ *  Author: Hadrien De Sousa <hadrien.desousa@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package cx.ring.account;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.ByteArrayOutputStream;
+
+import cx.ring.mvp.AccountCreationModel;
+import ezvcard.VCard;
+import ezvcard.parameter.ImageType;
+import ezvcard.property.FormattedName;
+import ezvcard.property.Photo;
+import ezvcard.property.RawProperty;
+import ezvcard.property.Uid;
+import io.reactivex.Single;
+
+public class AccountCreationModelImpl extends AccountCreationModel implements Parcelable {
+
+    public static final Creator<AccountCreationModelImpl> CREATOR = new Creator<AccountCreationModelImpl>() {
+        @Override
+        public AccountCreationModelImpl createFromParcel(Parcel source) {
+            return new AccountCreationModelImpl(source);
+        }
+
+        @Override
+        public AccountCreationModelImpl[] newArray(int size) {
+            return new AccountCreationModelImpl[size];
+        }
+    };
+    private Bitmap photo;
+
+    public AccountCreationModelImpl() {
+    }
+
+    @Override
+    public Single<VCard> toVCard() {
+        return Single
+                .fromCallable(() -> {
+                    VCard vcard = new VCard();
+                    vcard.setFormattedName(new FormattedName(getFullName()));
+                    vcard.setUid(new Uid(getUsername()));
+                    ByteArrayOutputStream stream = new ByteArrayOutputStream();
+                    if (getPhoto() != null) {
+                        getPhoto().compress(Bitmap.CompressFormat.PNG, 100, stream);
+                        Photo photoVCard = new Photo(stream.toByteArray(), ImageType.PNG);
+                        vcard.removeProperties(Photo.class);
+                        vcard.addPhoto(photoVCard);
+                    }
+                    vcard.removeProperties(RawProperty.class);
+                    return vcard;
+                });
+    }
+
+    protected AccountCreationModelImpl(Parcel in) {
+        this.photo = in.readParcelable(Bitmap.class.getClassLoader());
+        this.mFullName = in.readString();
+        this.mUsername = in.readString();
+        this.mPassword = in.readString();
+        this.mPin = in.readString();
+        this.link = in.readByte() != 0;
+    }
+
+    public Bitmap getPhoto() {
+        return photo;
+    }
+
+    public void setPhoto(Bitmap photo) {
+        this.photo = photo;
+        profile.onNext(this);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(this.photo, flags);
+        dest.writeString(this.mFullName);
+        dest.writeString(this.mUsername);
+        dest.writeString(this.mPassword);
+        dest.writeString(this.mPin);
+        dest.writeByte(this.link ? (byte) 1 : (byte) 0);
+    }
+}
diff --git a/ring-android/app/src/main/java/cx/ring/account/AccountWizardActivity.java b/ring-android/app/src/main/java/cx/ring/account/AccountWizardActivity.java
index 155daff..a48d700 100644
--- a/ring-android/app/src/main/java/cx/ring/account/AccountWizardActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/account/AccountWizardActivity.java
@@ -28,10 +28,13 @@
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Bundle;
+
 import androidx.appcompat.app.AlertDialog;
+
 import android.widget.Toast;
 
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
@@ -41,9 +44,10 @@
 import cx.ring.client.HomeActivity;
 import cx.ring.fragments.AccountMigrationFragment;
 import cx.ring.fragments.SIPAccountCreationFragment;
+import cx.ring.model.Account;
 import cx.ring.model.AccountConfig;
 import cx.ring.mvp.BaseActivity;
-import cx.ring.mvp.RingAccountViewModel;
+import cx.ring.mvp.AccountCreationModel;
 import cx.ring.utils.Log;
 import cx.ring.utils.VCardUtils;
 import ezvcard.VCard;
@@ -52,6 +56,8 @@
 import ezvcard.property.Photo;
 import ezvcard.property.RawProperty;
 import ezvcard.property.Uid;
+import io.reactivex.Observable;
+import io.reactivex.Single;
 import io.reactivex.schedulers.Schedulers;
 
 public class AccountWizardActivity extends BaseActivity<AccountWizardPresenter> implements AccountWizardView {
@@ -67,6 +73,8 @@
         RingApplication.getInstance().getRingInjectionComponent().inject(this);
         super.onCreate(savedInstanceState);
 
+        RingApplication.getInstance().startDaemon();
+
         setContentView(R.layout.activity_wizard);
         ButterKnife.bind(this);
 
@@ -120,32 +128,22 @@
     }
 
     @Override
-    public void saveProfile(final String accountID, final RingAccountViewModel ringAccountViewModel) {
-        runOnUiThread(() -> {
-            RingAccountViewModelImpl ringAccountViewModelImpl = (RingAccountViewModelImpl) ringAccountViewModel;
-            VCard vcard = new VCard();
-            vcard.setFormattedName(new FormattedName(ringAccountViewModelImpl.getFullName()));
-            vcard.setUid(new Uid(ringAccountViewModelImpl.getUsername()));
-            ByteArrayOutputStream stream = new ByteArrayOutputStream();
-            if (ringAccountViewModelImpl.getPhoto() != null) {
-                ringAccountViewModelImpl.getPhoto().compress(Bitmap.CompressFormat.PNG, 100, stream);
-                Photo photoVCard = new Photo(stream.toByteArray(), ImageType.PNG);
-                vcard.removeProperties(Photo.class);
-                vcard.addPhoto(photoVCard);
-            }
-            vcard.removeProperties(RawProperty.class);
-            VCardUtils.saveLocalProfileToDisk(vcard, accountID, getFilesDir())
-                    .subscribeOn(Schedulers.io())
-                    .subscribe();
-        });
+    public Single<VCard> saveProfile(final Account account, final AccountCreationModel accountCreationModel) {
+        File filedir = getFilesDir();
+        return accountCreationModel.toVCard()
+                .flatMap(vcard -> {
+                    account.setProfile(vcard);
+                    return VCardUtils.saveLocalProfileToDisk(vcard, account.getAccountID(), filedir);
+                })
+                .subscribeOn(Schedulers.io());
     }
 
-    public void createAccount(RingAccountViewModel ringAccountViewModel) {
-        if (ringAccountViewModel.isLink()) {
-            presenter.initRingAccountLink(ringAccountViewModel,
+    public void createAccount(AccountCreationModel accountCreationModel) {
+        if (accountCreationModel.isLink()) {
+            presenter.initRingAccountLink(accountCreationModel,
                     getText(R.string.ring_account_default_name).toString());
         } else {
-            presenter.initRingAccountCreation(ringAccountViewModel,
+            presenter.initRingAccountCreation(accountCreationModel,
                     getText(R.string.ring_account_default_name).toString());
         }
     }
@@ -169,108 +167,114 @@
     }
 
     @Override
+    public void goToProfileCreation(AccountCreationModel model) {
+        Fragment fragment = ProfileCreationFragment.newInstance((AccountCreationModelImpl) model);
+        FragmentManager fragmentManager = getSupportFragmentManager();
+        fragmentManager.beginTransaction()
+                .replace(R.id.wizard_container, fragment, ProfileCreationFragment.TAG)
+                .commit();
+    }
+
+    @Override
+    public void onBackPressed() {
+        Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.wizard_container);
+        if (fragment instanceof ProfileCreationFragment)
+            finish();
+        else
+            super.onBackPressed();
+    }
+
+    @Override
     public void displayProgress(final boolean display) {
-        runOnUiThread(() -> {
-            if (display) {
-                mProgress = new ProgressDialog(AccountWizardActivity.this);
-                mProgress.setTitle(R.string.dialog_wait_create);
-                mProgress.setMessage(getString(R.string.dialog_wait_create_details));
-                mProgress.setCancelable(false);
-                mProgress.setCanceledOnTouchOutside(false);
-                mProgress.show();
-            } else {
-                if (mProgress != null) {
-                    if (mProgress.isShowing()) {
-                        mProgress.dismiss();
-                    }
-                    mProgress = null;
+        if (display) {
+            mProgress = new ProgressDialog(AccountWizardActivity.this);
+            mProgress.setTitle(R.string.dialog_wait_create);
+            mProgress.setMessage(getString(R.string.dialog_wait_create_details));
+            mProgress.setCancelable(false);
+            mProgress.setCanceledOnTouchOutside(false);
+            mProgress.show();
+        } else {
+            if (mProgress != null) {
+                if (mProgress.isShowing()) {
+                    mProgress.dismiss();
                 }
+                mProgress = null;
             }
-        });
+        }
     }
 
     @Override
     public void displayCreationError() {
-        runOnUiThread(() -> Toast.makeText(AccountWizardActivity.this, "Error creating account", Toast.LENGTH_SHORT).show());
+        Toast.makeText(AccountWizardActivity.this, "Error creating account", Toast.LENGTH_SHORT).show();
     }
 
     @Override
     public void blockOrientation() {
         //orientation is locked during the create of account to avoid the destruction of the thread
-        runOnUiThread(() -> setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED));
+        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
     }
 
     @Override
     public void finish(final boolean affinity) {
-        runOnUiThread(() -> {
-            if (affinity) {
-                startActivity(new Intent(AccountWizardActivity.this, HomeActivity.class));
-                finish();
-            } else {
-                finishAffinity();
-            }
-        });
+        if (affinity) {
+            startActivity(new Intent(AccountWizardActivity.this, HomeActivity.class));
+            finish();
+        } else {
+            finishAffinity();
+        }
     }
 
     @Override
     public void displayGenericError() {
-        runOnUiThread(() -> {
-            if (mAlertDialog != null && mAlertDialog.isShowing()) {
-                return;
-            }
-            mAlertDialog = new AlertDialog.Builder(AccountWizardActivity.this)
-                    .setPositiveButton(android.R.string.ok, null)
-                    .setTitle(R.string.account_cannot_be_found_title)
-                    .setMessage(R.string.account_cannot_be_found_message)
-                    .show();
-        });
+        if (mAlertDialog != null && mAlertDialog.isShowing()) {
+            return;
+        }
+        mAlertDialog = new AlertDialog.Builder(AccountWizardActivity.this)
+                .setPositiveButton(android.R.string.ok, null)
+                .setTitle(R.string.account_cannot_be_found_title)
+                .setMessage(R.string.account_cannot_be_found_message)
+                .show();
     }
 
     @Override
     public void displayNetworkError() {
-        runOnUiThread(() -> {
-            if (mAlertDialog != null && mAlertDialog.isShowing()) {
-                return;
-            }
-            mAlertDialog = new AlertDialog.Builder(AccountWizardActivity.this)
-                    .setPositiveButton(android.R.string.ok, null)
-                    .setTitle(R.string.account_no_network_title)
-                    .setMessage(R.string.account_no_network_message)
-                    .show();
-        });
+        if (mAlertDialog != null && mAlertDialog.isShowing()) {
+            return;
+        }
+        mAlertDialog = new AlertDialog.Builder(AccountWizardActivity.this)
+                .setPositiveButton(android.R.string.ok, null)
+                .setTitle(R.string.account_no_network_title)
+                .setMessage(R.string.account_no_network_message)
+                .show();
     }
 
     @Override
     public void displayCannotBeFoundError() {
-        runOnUiThread(() -> {
-            if (mAlertDialog != null && mAlertDialog.isShowing()) {
-                return;
-            }
-            mAlertDialog = new AlertDialog.Builder(AccountWizardActivity.this)
-                    .setPositiveButton(android.R.string.ok, null)
-                    .setTitle(R.string.account_cannot_be_found_title)
-                    .setMessage(R.string.account_cannot_be_found_message)
-                    .show();
-        });
+        if (mAlertDialog != null && mAlertDialog.isShowing()) {
+            return;
+        }
+        mAlertDialog = new AlertDialog.Builder(AccountWizardActivity.this)
+                .setPositiveButton(android.R.string.ok, null)
+                .setTitle(R.string.account_cannot_be_found_title)
+                .setMessage(R.string.account_cannot_be_found_message)
+                .setOnDismissListener(dialogInterface -> {
+                    getSupportFragmentManager().popBackStack();
+                })
+                .show();
     }
 
     @Override
     public void displaySuccessDialog() {
-        runOnUiThread(() -> {
-            if (mAlertDialog != null && mAlertDialog.isShowing()) {
-                return;
-            }
-            mAlertDialog = new AlertDialog.Builder(AccountWizardActivity.this)
-                    .setPositiveButton(android.R.string.ok, null)
-                    .setTitle(R.string.account_device_added_title)
-                    .setMessage(R.string.account_device_added_message)
-                    .setOnDismissListener(dialogInterface -> {
-                        setResult(Activity.RESULT_OK, new Intent());
-                        //unlock the screen orientation
-                        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
-                        presenter.successDialogClosed();
-                    })
-                    .show();
-        });
+        if (mAlertDialog != null && mAlertDialog.isShowing()) {
+            return;
+        }
+        setResult(Activity.RESULT_OK, new Intent());
+        //unlock the screen orientation
+        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
+        presenter.successDialogClosed();
+    }
+
+    public void profileCreated(AccountCreationModel accountCreationModel, boolean saveProfile) {
+        presenter.profileCreated(accountCreationModel, saveProfile);
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/account/HomeAccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/account/HomeAccountCreationFragment.java
index 49bc168..452d4f4 100644
--- a/ring-android/app/src/main/java/cx/ring/account/HomeAccountCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/account/HomeAccountCreationFragment.java
@@ -68,13 +68,16 @@
 
     @Override
     public void goToAccountCreation() {
-        Fragment fragment = ProfileCreationFragment.newInstance(false);
+        AccountCreationModelImpl ringAccountViewModel = new AccountCreationModelImpl();
+        Fragment fragment = RingAccountCreationFragment.newInstance(ringAccountViewModel);//ProfileCreationFragment.newInstance(false);
         replaceFragmentWithSlide(fragment, R.id.wizard_container);
     }
 
     @Override
     public void goToAccountLink() {
-        Fragment fragment = ProfileCreationFragment.newInstance(true);
+        AccountCreationModelImpl ringAccountViewModel = new AccountCreationModelImpl();
+        ringAccountViewModel.setLink(true);
+        Fragment fragment = RingLinkAccountFragment.newInstance(ringAccountViewModel);//ProfileCreationFragment.newInstance(true);
         replaceFragmentWithSlide(fragment, R.id.wizard_container);
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/account/ProfileCreationFragment.java b/ring-android/app/src/main/java/cx/ring/account/ProfileCreationFragment.java
index 35d4578..fce127a 100644
--- a/ring-android/app/src/main/java/cx/ring/account/ProfileCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/account/ProfileCreationFragment.java
@@ -2,6 +2,7 @@
  *  Copyright (C) 2004-2018 Savoir-faire Linux Inc.
  *
  *  Author: Aline Bonnet <aline.bonnet@savoirfairelinux.com>
+ *  Author: Adrien Beraud <adrien.beraud@savoirfairelinux.com>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -39,18 +40,31 @@
 import android.widget.ImageView;
 
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 
-import androidx.fragment.app.Fragment;
 import butterknife.BindView;
 import butterknife.OnClick;
 import butterknife.OnTextChanged;
 import cx.ring.R;
 import cx.ring.adapters.ContactDetailsTask;
 import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.model.Account;
+import cx.ring.mvp.AccountCreationModel;
 import cx.ring.mvp.BaseSupportFragment;
-import cx.ring.mvp.RingAccountViewModel;
-import cx.ring.utils.BitmapUtils;
+import cx.ring.utils.VCardUtils;
+import cx.ring.views.AvatarDrawable;
+import ezvcard.VCard;
+import ezvcard.parameter.ImageType;
+import ezvcard.property.FormattedName;
+import ezvcard.property.Photo;
+import ezvcard.property.RawProperty;
+import ezvcard.property.Uid;
+import io.reactivex.Observable;
+import io.reactivex.Single;
 import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+import static cx.ring.account.RingAccountCreationFragment.KEY_RING_ACCOUNT;
 
 public class ProfileCreationFragment extends BaseSupportFragment<ProfileCreationPresenter> implements ProfileCreationView, TextWatcher {
     public static final String TAG = ProfileCreationFragment.class.getSimpleName();
@@ -80,10 +94,13 @@
 
     private Bitmap mSourcePhoto;
 
-    public static ProfileCreationFragment newInstance(boolean isLink) {
+    private Observable<Account> accountObservable = null;
+
+    public static ProfileCreationFragment newInstance(AccountCreationModelImpl model) {
         Bundle bundle = new Bundle();
-        bundle.putBoolean(KEY_IS_LINK, isLink);
+        bundle.putParcelable(KEY_RING_ACCOUNT, model);
         ProfileCreationFragment fragment = new ProfileCreationFragment();
+        fragment.accountObservable = model.getAccountObservable();
         fragment.setArguments(bundle);
         return fragment;
     }
@@ -101,7 +118,6 @@
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
-
         setRetainInstance(true);
 
         if (savedInstanceState != null) {
@@ -110,23 +126,20 @@
                 mSourcePhoto = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
             }
         }
-
-        if (mPhotoView.getDrawable() == null) {
-            if (mSourcePhoto == null) {
-                mSourcePhoto = BitmapFactory.decodeResource(getActivity().getResources(), R.drawable.ic_contact_picture_fallback);
-            }
-            mPhotoView.setImageBitmap(BitmapUtils.cropImageToCircle(mSourcePhoto));
+        if (accountObservable == null) {
+            getActivity().finish();
+            return;
         }
-
-        RingAccountViewModelImpl ringAccountViewModel = new RingAccountViewModelImpl();
-        boolean isLink = getArguments().getBoolean(KEY_IS_LINK, false);
-        ringAccountViewModel.setLink(isLink);
-
+        AccountCreationModelImpl ringAccountViewModel = getArguments().getParcelable(KEY_RING_ACCOUNT);
+        ringAccountViewModel.setAccountObservable(accountObservable);
+        if (mPhotoView.getDrawable() == null) {
+            mPhotoView.setImageDrawable(new AvatarDrawable(view.getContext(), (Bitmap) null, ringAccountViewModel.getFullName(), ringAccountViewModel.getUsername(), null, true));
+        }
         presenter.initPresenter(ringAccountViewModel);
     }
 
     @Override
-    public void onSaveInstanceState(Bundle outState) {
+    public void onSaveInstanceState(@NonNull Bundle outState) {
         super.onSaveInstanceState(outState);
         if (mSourcePhoto != null) {
             ByteArrayOutputStream stream = new ByteArrayOutputStream();
@@ -181,20 +194,25 @@
     }
 
     @OnClick(R.id.gallery)
-    public void galleryClicked() {
+    void galleryClicked() {
         presenter.galleryClick();
     }
 
     @OnClick(R.id.camera)
-    public void cameraClicked() {
+    void cameraClicked() {
         presenter.cameraClick();
     }
 
     @OnClick(R.id.next_create_account)
-    public void nextClicked() {
+    void nextClicked() {
         presenter.nextClick();
     }
 
+    @OnClick(R.id.skip_create_account)
+    void skipClicked() {
+        presenter.skipClick();
+    }
+
     @Override
     public void displayProfileName(String profileName) {
         mFullnameView.setText(profileName);
@@ -223,20 +241,24 @@
     }
 
     @Override
-    public void goToNext(RingAccountViewModel ringAccountViewModel) {
-        if (ringAccountViewModel.isLink()) {
-            Fragment fragment = RingLinkAccountFragment.newInstance((RingAccountViewModelImpl) ringAccountViewModel);
-            replaceFragmentWithSlide(fragment, R.id.wizard_container);
-        } else {
-            Fragment fragment = RingAccountCreationFragment.newInstance((RingAccountViewModelImpl) ringAccountViewModel);
-            replaceFragmentWithSlide(fragment, R.id.wizard_container);
+    public void goToNext(AccountCreationModel accountCreationModel, boolean saveProfile) {
+        Activity wizardActivity = getActivity();
+        if (wizardActivity instanceof AccountWizardActivity) {
+            AccountWizardActivity wizard = (AccountWizardActivity) wizardActivity;
+            wizard.profileCreated(accountCreationModel, saveProfile);
         }
     }
 
     @Override
-    public void photoUpdate(RingAccountViewModel ringAccountViewModel) {
-        ((RingAccountViewModelImpl) ringAccountViewModel).setPhoto(mSourcePhoto);
-        mPhotoView.setImageBitmap(mSourcePhoto != null ? BitmapUtils.cropImageToCircle(mSourcePhoto) : null);
+    public void photoUpdate(AccountCreationModel accountCreationModel) {
+        ((AccountCreationModelImpl)accountCreationModel).setPhoto(mSourcePhoto);
+    }
+
+    @Override
+    public void setProfile(AccountCreationModel accountCreationModel) {
+        AccountCreationModelImpl model = ((AccountCreationModelImpl) accountCreationModel);
+        Account newAccount = model.getNewAccount();
+        mPhotoView.setImageDrawable(new AvatarDrawable(getContext(), model.getPhoto(), accountCreationModel.getFullName(), accountCreationModel.getUsername(), newAccount == null ? null : newAccount.getUsername(), true));
     }
 
     @Override
diff --git a/ring-android/app/src/main/java/cx/ring/account/RingAccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/account/RingAccountCreationFragment.java
index 493d05e..ee084ab 100644
--- a/ring-android/app/src/main/java/cx/ring/account/RingAccountCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/account/RingAccountCreationFragment.java
@@ -20,6 +20,7 @@
 package cx.ring.account;
 
 import android.app.Activity;
+import android.content.Context;
 import android.os.Bundle;
 import com.google.android.material.textfield.TextInputLayout;
 import android.text.Editable;
@@ -27,10 +28,12 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.Switch;
 
+import androidx.fragment.app.Fragment;
 import butterknife.BindView;
 import butterknife.ButterKnife;
 import butterknife.OnCheckedChanged;
@@ -39,10 +42,11 @@
 import butterknife.OnTextChanged;
 import cx.ring.R;
 import cx.ring.dependencyinjection.RingInjectionComponent;
-import cx.ring.mvp.BaseFragment;
+import cx.ring.model.Account;
 import cx.ring.mvp.BaseSupportFragment;
-import cx.ring.mvp.RingAccountViewModel;
+import cx.ring.mvp.AccountCreationModel;
 import cx.ring.utils.RegisteredNameFilter;
+import io.reactivex.Observable;
 
 public class RingAccountCreationFragment extends BaseSupportFragment<RingAccountCreationPresenter> implements RingAccountCreationView {
 
@@ -57,6 +61,12 @@
     @BindView(R.id.ring_username)
     protected EditText mUsernameTxt;
 
+    @BindView(R.id.ring_password_switch)
+    protected Switch mPasswordSwitch;
+
+    @BindView(R.id.ring_password_box)
+    protected ViewGroup mPasswordBox;
+
     @BindView(R.id.ring_password_txt_box)
     protected TextInputLayout mPasswordTxtBox;
 
@@ -69,7 +79,7 @@
     @BindView(R.id.create_account)
     protected Button mCreateAccountButton;
 
-    public static RingAccountCreationFragment newInstance(RingAccountViewModelImpl ringAccountViewModel) {
+    public static RingAccountCreationFragment newInstance(AccountCreationModelImpl ringAccountViewModel) {
         Bundle bundle = new Bundle();
         bundle.putParcelable(KEY_RING_ACCOUNT, ringAccountViewModel);
         RingAccountCreationFragment fragment = new RingAccountCreationFragment();
@@ -96,10 +106,25 @@
         ButterKnife.bind(this, view);
         mUsernameTxt.setFilters(new InputFilter[]{new RegisteredNameFilter()});
 
-        RingAccountViewModelImpl ringAccountViewModel = getArguments().getParcelable(KEY_RING_ACCOUNT);
+        AccountCreationModelImpl ringAccountViewModel = getArguments().getParcelable(KEY_RING_ACCOUNT);
         presenter.init(ringAccountViewModel);
     }
 
+    @Override
+    public void onResume() {
+        super.onResume();
+        if (mUsernameBox.getVisibility() == View.VISIBLE) {
+            mUsernameTxt.requestFocus();
+            InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+            imm.showSoftInput(mUsernameTxt, InputMethodManager.SHOW_IMPLICIT);
+        }
+    }
+
+    @OnCheckedChanged(R.id.ring_password_switch)
+    public void onPasswordCheckedChanged(boolean isChecked) {
+        mPasswordBox.setVisibility(isChecked ? View.VISIBLE : View.GONE);
+    }
+
     @OnCheckedChanged(R.id.switch_ring_username)
     public void onCheckedChanged(boolean isChecked) {
         presenter.ringCheckChanged(isChecked);
@@ -204,11 +229,11 @@
     }
 
     @Override
-    public void goToAccountCreation(RingAccountViewModel ringAccountViewModel) {
+    public void goToAccountCreation(AccountCreationModel accountCreationModel) {
         Activity wizardActivity = getActivity();
-        if (wizardActivity != null && wizardActivity instanceof AccountWizardActivity) {
+        if (wizardActivity instanceof AccountWizardActivity) {
             AccountWizardActivity wizard = (AccountWizardActivity) wizardActivity;
-            wizard.createAccount(ringAccountViewModel);
+            wizard.createAccount(accountCreationModel);
         }
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/account/RingAccountViewModelImpl.java b/ring-android/app/src/main/java/cx/ring/account/RingAccountViewModelImpl.java
deleted file mode 100644
index 85b911e..0000000
--- a/ring-android/app/src/main/java/cx/ring/account/RingAccountViewModelImpl.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *  Copyright (C) 2004-2018 Savoir-faire Linux Inc.
- *
- *  Author: Hadrien De Sousa <hadrien.desousa@savoirfairelinux.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-package cx.ring.account;
-
-import android.graphics.Bitmap;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import cx.ring.mvp.RingAccountViewModel;
-
-public class RingAccountViewModelImpl extends RingAccountViewModel implements Parcelable {
-
-    public static final Creator<RingAccountViewModelImpl> CREATOR = new Creator<RingAccountViewModelImpl>() {
-        @Override
-        public RingAccountViewModelImpl createFromParcel(Parcel source) {
-            return new RingAccountViewModelImpl(source);
-        }
-
-        @Override
-        public RingAccountViewModelImpl[] newArray(int size) {
-            return new RingAccountViewModelImpl[size];
-        }
-    };
-    private Bitmap photo;
-
-    public RingAccountViewModelImpl() {
-    }
-
-    protected RingAccountViewModelImpl(Parcel in) {
-        this.photo = in.readParcelable(Bitmap.class.getClassLoader());
-        this.mFullName = in.readString();
-        this.mUsername = in.readString();
-        this.mPassword = in.readString();
-        this.mPin = in.readString();
-        this.link = in.readByte() != 0;
-    }
-
-    public Bitmap getPhoto() {
-        return photo;
-    }
-
-    public void setPhoto(Bitmap photo) {
-        this.photo = photo;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeParcelable(this.photo, flags);
-        dest.writeString(this.mFullName);
-        dest.writeString(this.mUsername);
-        dest.writeString(this.mPassword);
-        dest.writeString(this.mPin);
-        dest.writeByte(this.link ? (byte) 1 : (byte) 0);
-    }
-}
diff --git a/ring-android/app/src/main/java/cx/ring/account/RingLinkAccountFragment.java b/ring-android/app/src/main/java/cx/ring/account/RingLinkAccountFragment.java
index 8523034..004d693 100644
--- a/ring-android/app/src/main/java/cx/ring/account/RingLinkAccountFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/account/RingLinkAccountFragment.java
@@ -32,9 +32,8 @@
 import butterknife.OnTextChanged;
 import cx.ring.R;
 import cx.ring.dependencyinjection.RingInjectionComponent;
-import cx.ring.mvp.BaseFragment;
 import cx.ring.mvp.BaseSupportFragment;
-import cx.ring.mvp.RingAccountViewModel;
+import cx.ring.mvp.AccountCreationModel;
 
 public class RingLinkAccountFragment extends BaseSupportFragment<RingLinkAccountPresenter> implements RingLinkAccountView {
 
@@ -49,7 +48,7 @@
     @BindView(R.id.link_button)
     protected Button mLinkAccountBtn;
 
-    public static RingLinkAccountFragment newInstance(RingAccountViewModelImpl ringAccountViewModel) {
+    public static RingLinkAccountFragment newInstance(AccountCreationModelImpl ringAccountViewModel) {
         Bundle bundle = new Bundle();
         bundle.putParcelable(RingAccountCreationFragment.KEY_RING_ACCOUNT, ringAccountViewModel);
         RingLinkAccountFragment fragment = new RingLinkAccountFragment();
@@ -70,7 +69,7 @@
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
-        RingAccountViewModelImpl ringAccountViewModel = getArguments().getParcelable(RingAccountCreationFragment.KEY_RING_ACCOUNT);
+        AccountCreationModelImpl ringAccountViewModel = getArguments().getParcelable(RingAccountCreationFragment.KEY_RING_ACCOUNT);
         presenter.init(ringAccountViewModel);
     }
 
@@ -103,7 +102,7 @@
     }
 
     @Override
-    public void createAccount(RingAccountViewModel ringAccountViewModel) {
-        ((AccountWizardActivity) getActivity()).createAccount(ringAccountViewModel);
+    public void createAccount(AccountCreationModel accountCreationModel) {
+        ((AccountWizardActivity) getActivity()).createAccount(accountCreationModel);
     }
 }
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/contacts/AvatarFactory.java b/ring-android/app/src/main/java/cx/ring/contacts/AvatarFactory.java
index 197f12e..21670fc 100644
--- a/ring-android/app/src/main/java/cx/ring/contacts/AvatarFactory.java
+++ b/ring-android/app/src/main/java/cx/ring/contacts/AvatarFactory.java
@@ -35,11 +35,8 @@
 import com.bumptech.glide.RequestBuilder;
 import com.bumptech.glide.RequestManager;
 import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
-import com.bumptech.glide.request.RequestOptions;
 
-import cx.ring.R;
 import cx.ring.model.CallContact;
-import cx.ring.utils.CircleTransform;
 import cx.ring.views.AvatarDrawable;
 import ezvcard.VCard;
 import ezvcard.property.FormattedName;
@@ -50,15 +47,6 @@
 
     public static final int SIZE_AB = 36;
     public static final int SIZE_NOTIF = 48;
-    
-    private static final RequestOptions GLIDE_OPTIONS = new RequestOptions()
-            .centerCrop()
-            .error(R.drawable.ic_contact_picture_fallback);
-
-    private static final RequestOptions GLIDE_OPTIONS_CIRCLE = new RequestOptions()
-            .centerCrop()
-            .error(R.drawable.ic_contact_picture_fallback)
-            .transform(new CircleTransform());
 
     private AvatarFactory() {}
 
@@ -137,10 +125,6 @@
         return getGlideRequest(context, Glide.with(context).asBitmap(), contact.getPhoto(), contact.getProfileName(), contact.getUsername(), contact.getPrimaryNumber());
     }
 
-    public static RequestOptions getGlideOptions(boolean circle) {
-        return circle ? GLIDE_OPTIONS_CIRCLE : GLIDE_OPTIONS;
-    }
-
     public static void clearCache() {
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/service/DRingService.java b/ring-android/app/src/main/java/cx/ring/service/DRingService.java
index 7a55f4e..6a66f2c 100644
--- a/ring-android/app/src/main/java/cx/ring/service/DRingService.java
+++ b/ring-android/app/src/main/java/cx/ring/service/DRingService.java
@@ -217,7 +217,7 @@
 
         @Override
         public Map<String, String> getAccountTemplate(final String accountType) throws RemoteException {
-            return mAccountService.getAccountTemplate(accountType);
+            return mAccountService.getAccountTemplate(accountType).blockingGet();
         }
 
         @SuppressWarnings("unchecked")
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountExport.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountExport.java
index 6a0fe3e..843244b 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountExport.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountExport.java
@@ -23,9 +23,11 @@
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+
 import androidx.annotation.NonNull;
 import androidx.leanback.widget.GuidanceStylist;
 import androidx.leanback.widget.GuidedAction;
+
 import android.text.Layout;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -110,56 +112,48 @@
 
     @Override
     public void showNetworkError() {
-        RingApplication.uiHandler.post(() -> {
-            mWaitDialog.dismiss();
-            new AlertDialog.Builder(getActivity())
-                    .setTitle(R.string.account_export_end_network_title)
-                    .setMessage(R.string.account_export_end_network_message)
-                    .setPositiveButton(android.R.string.ok, null)
-                    .show();
-        });
+        mWaitDialog.dismiss();
+        new AlertDialog.Builder(getActivity())
+                .setTitle(R.string.account_export_end_network_title)
+                .setMessage(R.string.account_export_end_network_message)
+                .setPositiveButton(android.R.string.ok, null)
+                .show();
     }
 
     @Override
     public void showPasswordError() {
-        RingApplication.uiHandler.post(() -> {
-            mWaitDialog.dismiss();
-            new AlertDialog.Builder(getActivity())
-                    .setTitle(R.string.account_export_end_error_title)
-                    .setMessage(R.string.account_export_end_decryption_message)
-                    .setPositiveButton(android.R.string.ok, null)
-                    .show();
-        });
+        mWaitDialog.dismiss();
+        new AlertDialog.Builder(getActivity())
+                .setTitle(R.string.account_export_end_error_title)
+                .setMessage(R.string.account_export_end_decryption_message)
+                .setPositiveButton(android.R.string.ok, null)
+                .show();
     }
 
     @Override
     public void showGenericError() {
-        RingApplication.uiHandler.post(() -> {
-            mWaitDialog.dismiss();
-            new AlertDialog.Builder(getActivity())
-                    .setTitle(R.string.account_export_end_error_title)
-                    .setMessage(R.string.account_export_end_error_message)
-                    .setPositiveButton(android.R.string.ok, null)
-                    .show();
-        });
+        mWaitDialog.dismiss();
+        new AlertDialog.Builder(getActivity())
+                .setTitle(R.string.account_export_end_error_title)
+                .setMessage(R.string.account_export_end_error_message)
+                .setPositiveButton(android.R.string.ok, null)
+                .show();
     }
 
     @Override
     public void showPIN(final String pin) {
-        RingApplication.uiHandler.post(() -> {
-            mWaitDialog.dismiss();
-            String pined = getString(R.string.account_end_export_infos).replace("%%", pin);
-            final SpannableString styledResultText = new SpannableString(pined);
-            int pos = pined.lastIndexOf(pin);
-            styledResultText.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER), pos, (pos + pin.length()), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-            styledResultText.setSpan(new StyleSpan(Typeface.BOLD), pos, (pos + pin.length()), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-            styledResultText.setSpan(new RelativeSizeSpan(2.8f), pos, (pos + pin.length()), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        mWaitDialog.dismiss();
+        String pined = getString(R.string.account_end_export_infos).replace("%%", pin);
+        final SpannableString styledResultText = new SpannableString(pined);
+        int pos = pined.lastIndexOf(pin);
+        styledResultText.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER), pos, (pos + pin.length()), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        styledResultText.setSpan(new StyleSpan(Typeface.BOLD), pos, (pos + pin.length()), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        styledResultText.setSpan(new RelativeSizeSpan(2.8f), pos, (pos + pin.length()), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
 
-            new AlertDialog.Builder(getActivity())
-                    .setMessage(styledResultText)
-                    .setPositiveButton(android.R.string.ok, (dialog, which) -> getFragmentManager().popBackStack())
-                    .show();
-        });
+        new AlertDialog.Builder(getActivity())
+                .setMessage(styledResultText)
+                .setPositiveButton(android.R.string.ok, (dialog, which) -> getFragmentManager().popBackStack())
+                .show();
     }
 
     @Override
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountWizard.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountWizard.java
index 5d8c98a..201618c 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountWizard.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountWizard.java
@@ -23,53 +23,48 @@
 import android.app.ProgressDialog;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
-import android.graphics.Bitmap;
 import android.os.Bundle;
+
 import androidx.leanback.app.GuidedStepSupportFragment;
 import androidx.appcompat.app.AlertDialog;
+
 import android.widget.Toast;
 
-import java.io.ByteArrayOutputStream;
+import java.io.File;
 
 import butterknife.ButterKnife;
 import cx.ring.R;
+import cx.ring.account.AccountCreationModelImpl;
 import cx.ring.account.AccountWizardPresenter;
 import cx.ring.account.AccountWizardView;
-import cx.ring.account.RingAccountViewModelImpl;
 import cx.ring.application.RingApplication;
+import cx.ring.model.Account;
 import cx.ring.model.AccountConfig;
+import cx.ring.mvp.AccountCreationModel;
 import cx.ring.mvp.BaseActivity;
-import cx.ring.mvp.RingAccountViewModel;
 import cx.ring.tv.main.HomeActivity;
 import cx.ring.utils.VCardUtils;
 import ezvcard.VCard;
-import ezvcard.parameter.ImageType;
-import ezvcard.property.FormattedName;
-import ezvcard.property.Photo;
-import ezvcard.property.RawProperty;
-import ezvcard.property.Uid;
+import io.reactivex.Single;
 import io.reactivex.schedulers.Schedulers;
 
 public class TVAccountWizard
         extends BaseActivity<AccountWizardPresenter>
         implements AccountWizardView {
-    public static final String PROFILE_TAG = "Profile";
     static final String TAG = TVAccountWizard.class.getName();
-    private TVProfileCreationFragment mProfileFragment = new TVProfileCreationFragment();
     private TVHomeAccountCreationFragment mHomeFragment = new TVHomeAccountCreationFragment();
 
     private ProgressDialog mProgress = null;
     private boolean mLinkAccount = false;
-    private String mFullname;
     private String mAccountType;
     private AlertDialog mAlertDialog;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        // dependency injection
         RingApplication.getInstance().getRingInjectionComponent().inject(this);
         super.onCreate(savedInstanceState);
         ButterKnife.bind(this);
+        RingApplication.getInstance().startDaemon();
 
         Intent intent = getIntent();
         if (intent != null) {
@@ -82,8 +77,6 @@
         if (savedInstanceState == null) {
             GuidedStepSupportFragment.addAsRoot(this, mHomeFragment, android.R.id.content);
         } else {
-            mProfileFragment = (TVProfileCreationFragment) getSupportFragmentManager().getFragment(savedInstanceState, PROFILE_TAG);
-            mFullname = savedInstanceState.getString("mFullname");
             mLinkAccount = savedInstanceState.getBoolean("mLinkAccount");
         }
 
@@ -93,10 +86,6 @@
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
-        if (mProfileFragment.isAdded()) {
-            getSupportFragmentManager().putFragment(outState, PROFILE_TAG, mProfileFragment);
-        }
-        outState.putString("mFullname", mFullname);
         outState.putBoolean("mLinkAccount", mLinkAccount);
     }
 
@@ -109,15 +98,12 @@
         super.onDestroy();
     }
 
-    public void createAccount(RingAccountViewModel ringAccountViewModel) {
-        if (ringAccountViewModel.getFullName() == null || ringAccountViewModel.getFullName().isEmpty()) {
-            ringAccountViewModel.setFullName(ringAccountViewModel.getUsername());
-        }
-        if (ringAccountViewModel.isLink()) {
-            presenter.initRingAccountLink(ringAccountViewModel,
+    public void createAccount(AccountCreationModel accountCreationModel) {
+        if (accountCreationModel.isLink()) {
+            presenter.initRingAccountLink(accountCreationModel,
                     getText(R.string.ring_account_default_name).toString());
         } else {
-            presenter.initRingAccountCreation(ringAccountViewModel,
+            presenter.initRingAccountCreation(accountCreationModel,
                     getText(R.string.ring_account_default_name).toString());
         }
     }
@@ -133,6 +119,20 @@
     }
 
     @Override
+    public void onBackPressed() {
+        GuidedStepSupportFragment fragment = GuidedStepSupportFragment.getCurrentGuidedStepSupportFragment(getSupportFragmentManager());
+        if (fragment instanceof TVProfileCreationFragment)
+            finish();
+        else
+            super.onBackPressed();
+    }
+
+    @Override
+    public void goToProfileCreation(AccountCreationModel accountCreationModel) {
+        GuidedStepSupportFragment.add(getSupportFragmentManager(), TVProfileCreationFragment.newInstance((AccountCreationModelImpl) accountCreationModel));
+    }
+
+    @Override
     public void displayProgress(boolean display) {
         if (display) {
             mProgress = new ProgressDialog(this);
@@ -154,7 +154,7 @@
 
     @Override
     public void displayCreationError() {
-        runOnUiThread(() -> Toast.makeText(TVAccountWizard.this, "Error creating account", Toast.LENGTH_SHORT).show());
+        Toast.makeText(TVAccountWizard.this, "Error creating account", Toast.LENGTH_SHORT).show();
     }
 
     @Override
@@ -162,108 +162,87 @@
         //Noop on TV
     }
 
-
     @Override
     public void finish(final boolean affinity) {
-        runOnUiThread(() -> {
-            if (affinity) {
-                FragmentManager fm = getFragmentManager();
-                if (fm.getBackStackEntryCount() >= 1) {
-                    fm.popBackStack();
-                } else {
-                    finish();
-                }
+        if (affinity) {
+            FragmentManager fm = getFragmentManager();
+            if (fm.getBackStackEntryCount() >= 1) {
+                fm.popBackStack();
             } else {
-                finishAffinity();
+                finish();
             }
-        });
+        } else {
+            finishAffinity();
+        }
     }
 
     @Override
-    public void saveProfile(final String accountID, final RingAccountViewModel ringAccountViewModel) {
-        runOnUiThread(() -> {
-            RingAccountViewModelImpl viewModel = (RingAccountViewModelImpl) ringAccountViewModel;
-
-            VCard vcard = new VCard();
-            vcard.setFormattedName(new FormattedName(viewModel.getFullName()));
-            vcard.setUid(new Uid(viewModel.getUsername()));
-            ByteArrayOutputStream stream = new ByteArrayOutputStream();
-            Bitmap photo = viewModel.getPhoto();
-            if (photo != null) {
-                photo.compress(Bitmap.CompressFormat.PNG, 100, stream);
-                Photo photoVCard = new Photo(stream.toByteArray(), ImageType.PNG);
-                vcard.removeProperties(Photo.class);
-                vcard.addPhoto(photoVCard);
-            }
-            vcard.removeProperties(RawProperty.class);
-            VCardUtils.saveLocalProfileToDisk(vcard, accountID, getFilesDir())
-                    .subscribeOn(Schedulers.io())
-                    .subscribe();
-        });
+    public Single<VCard> saveProfile(final Account account, final AccountCreationModel accountCreationModel) {
+        File filedir = getFilesDir();
+        return accountCreationModel.toVCard()
+                .flatMap(vcard -> {
+                    account.setProfile(vcard);
+                    return VCardUtils.saveLocalProfileToDisk(vcard, account.getAccountID(), filedir);
+                })
+                .subscribeOn(Schedulers.io());
     }
 
     @Override
     public void displayGenericError() {
-        runOnUiThread(() -> {
-
-            if (mAlertDialog != null && mAlertDialog.isShowing()) {
-                return;
-            }
-            mAlertDialog = new AlertDialog.Builder(TVAccountWizard.this)
-                    .setPositiveButton(android.R.string.ok, null)
-                    .setTitle(R.string.account_cannot_be_found_title)
-                    .setMessage(R.string.account_cannot_be_found_message)
-                    .show();
-        });
+        if (mAlertDialog != null && mAlertDialog.isShowing()) {
+            return;
+        }
+        mAlertDialog = new AlertDialog.Builder(TVAccountWizard.this)
+                .setPositiveButton(android.R.string.ok, null)
+                .setTitle(R.string.account_cannot_be_found_title)
+                .setMessage(R.string.account_cannot_be_found_message)
+                .show();
     }
 
     @Override
     public void displayNetworkError() {
-        runOnUiThread(() -> {
-
-            if (mAlertDialog != null && mAlertDialog.isShowing()) {
-                return;
-            }
-            mAlertDialog = new AlertDialog.Builder(TVAccountWizard.this)
-                    .setPositiveButton(android.R.string.ok, null)
-                    .setTitle(R.string.account_no_network_title)
-                    .setMessage(R.string.account_no_network_message)
-                    .show();
-        });
+        if (mAlertDialog != null && mAlertDialog.isShowing()) {
+            return;
+        }
+        mAlertDialog = new AlertDialog.Builder(TVAccountWizard.this)
+                .setPositiveButton(android.R.string.ok, null)
+                .setTitle(R.string.account_no_network_title)
+                .setMessage(R.string.account_no_network_message)
+                .show();
     }
 
     @Override
     public void displayCannotBeFoundError() {
-        runOnUiThread(() -> {
-            if (mAlertDialog != null && mAlertDialog.isShowing()) {
-                return;
-            }
-            mAlertDialog = new AlertDialog.Builder(TVAccountWizard.this)
-                    .setPositiveButton(android.R.string.ok, null)
-                    .setTitle(R.string.account_cannot_be_found_title)
-                    .setMessage(R.string.account_cannot_be_found_message)
-                    .show();
-        });
+        if (mAlertDialog != null && mAlertDialog.isShowing()) {
+            return;
+        }
+        mAlertDialog = new AlertDialog.Builder(TVAccountWizard.this)
+                .setPositiveButton(android.R.string.ok, null)
+                .setTitle(R.string.account_cannot_be_found_title)
+                .setMessage(R.string.account_cannot_be_found_message)
+                .show();
     }
 
     @Override
     public void displaySuccessDialog() {
-        runOnUiThread(() -> {
-            if (mAlertDialog != null && mAlertDialog.isShowing()) {
-                return;
-            }
-            mAlertDialog = new AlertDialog.Builder(TVAccountWizard.this)
-                    .setPositiveButton(android.R.string.ok, null)
-                    .setTitle(R.string.account_device_added_title)
-                    .setMessage(R.string.account_device_added_message)
-                    .setOnDismissListener(dialogInterface -> {
-                        setResult(Activity.RESULT_OK, new Intent());
-                        //unlock the screen orientation
-                        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
-                        startActivity(new Intent(TVAccountWizard.this, HomeActivity.class));
-                        finish();
-                    })
-                    .show();
-        });
+        if (mAlertDialog != null && mAlertDialog.isShowing()) {
+            return;
+        }
+        mAlertDialog = new AlertDialog.Builder(TVAccountWizard.this)
+                .setPositiveButton(android.R.string.ok, null)
+                .setTitle(R.string.account_device_added_title)
+                .setMessage(R.string.account_device_added_message)
+                .setOnDismissListener(dialogInterface -> {
+                    setResult(Activity.RESULT_OK, new Intent());
+                    //unlock the screen orientation
+                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
+                    startActivity(new Intent(TVAccountWizard.this, HomeActivity.class));
+                    finish();
+                })
+                .show();
+    }
+
+    public void profileCreated(AccountCreationModel accountCreationModel, boolean saveProfile) {
+        presenter.profileCreated(accountCreationModel, saveProfile);
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVHomeAccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVHomeAccountCreationFragment.java
index 6ad540f..efab130 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVHomeAccountCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVHomeAccountCreationFragment.java
@@ -28,9 +28,9 @@
 import java.util.List;
 
 import cx.ring.R;
+import cx.ring.account.AccountCreationModelImpl;
 import cx.ring.account.HomeAccountCreationPresenter;
 import cx.ring.account.HomeAccountCreationView;
-import cx.ring.account.RingAccountViewModelImpl;
 import cx.ring.application.RingApplication;
 
 public class TVHomeAccountCreationFragment
@@ -49,16 +49,16 @@
 
     @Override
     public void goToAccountCreation() {
-        RingAccountViewModelImpl ringAccountViewModel = new RingAccountViewModelImpl();
+        AccountCreationModelImpl ringAccountViewModel = new AccountCreationModelImpl();
         ringAccountViewModel.setLink(false);
-        GuidedStepSupportFragment.add(getFragmentManager(), TVProfileCreationFragment.newInstance(ringAccountViewModel));
+        GuidedStepSupportFragment.add(getFragmentManager(), TVRingAccountCreationFragment.newInstance(ringAccountViewModel));
     }
 
     @Override
     public void goToAccountLink() {
-        RingAccountViewModelImpl ringAccountViewModel = new RingAccountViewModelImpl();
+        AccountCreationModelImpl ringAccountViewModel = new AccountCreationModelImpl();
         ringAccountViewModel.setLink(true);
-        GuidedStepSupportFragment.add(getFragmentManager(), TVProfileCreationFragment.newInstance(ringAccountViewModel));
+        GuidedStepSupportFragment.add(getFragmentManager(), TVRingLinkAccountFragment.newInstance(ringAccountViewModel));
     }
 
     @Override
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileCreationFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileCreationFragment.java
index 163df38..cc4b418 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileCreationFragment.java
@@ -25,7 +25,6 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.MediaStore;
@@ -38,22 +37,19 @@
 import android.util.Log;
 import android.view.View;
 
-import com.bumptech.glide.Glide;
-import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
-
 import java.util.List;
 
 import cx.ring.R;
+import cx.ring.account.AccountCreationModelImpl;
 import cx.ring.account.ProfileCreationFragment;
 import cx.ring.account.ProfileCreationPresenter;
 import cx.ring.account.ProfileCreationView;
-import cx.ring.account.RingAccountCreationFragment;
-import cx.ring.account.RingAccountViewModelImpl;
 import cx.ring.adapters.ContactDetailsTask;
 import cx.ring.application.RingApplication;
-import cx.ring.contacts.AvatarFactory;
-import cx.ring.mvp.RingAccountViewModel;
+import cx.ring.model.Account;
+import cx.ring.mvp.AccountCreationModel;
 import cx.ring.tv.camera.CustomCameraActivity;
+import cx.ring.views.AvatarDrawable;
 import io.reactivex.android.schedulers.AndroidSchedulers;
 
 public class TVProfileCreationFragment extends RingGuidedStepFragment<ProfileCreationPresenter>
@@ -65,12 +61,12 @@
     private static final int NEXT = 4;
 
     private Bitmap mSourcePhoto;
+    private AccountCreationModelImpl mModel;
+    private int iconSize = -1;
 
-    public static GuidedStepSupportFragment newInstance(RingAccountViewModelImpl pRingAccountViewModel) {
-        Bundle bundle = new Bundle();
-        bundle.putParcelable(RingAccountCreationFragment.KEY_RING_ACCOUNT, pRingAccountViewModel);
+    public static GuidedStepSupportFragment newInstance(AccountCreationModelImpl ringAccountViewModel) {
         TVProfileCreationFragment fragment = new TVProfileCreationFragment();
-        fragment.setArguments(bundle);
+        fragment.mModel = ringAccountViewModel;
         return fragment;
     }
 
@@ -112,15 +108,15 @@
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
-
         super.onViewCreated(view, savedInstanceState);
 
-        RingAccountViewModelImpl ringAccountViewModel = (RingAccountViewModelImpl) getArguments().get(RingAccountCreationFragment.KEY_RING_ACCOUNT);
-        presenter.initPresenter(ringAccountViewModel);
-
-        if (ringAccountViewModel != null && ringAccountViewModel.getPhoto() != null) {
-            getGuidanceStylist().getIconView().setImageBitmap(ringAccountViewModel.getPhoto());
+        if (mModel == null) {
+            getActivity().finish();
+            return;
         }
+
+        iconSize = (int) getResources().getDimension(R.dimen.tv_avatar_size);
+        presenter.initPresenter(mModel);
     }
 
     @Override
@@ -129,8 +125,7 @@
         String title = getString(R.string.account_create_title);
         String breadcrumb = "";
         String description = getString(R.string.profile_message_warning);
-        Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_contact_picture_fallback);
-        return new GuidanceStylist.Guidance(title, description, breadcrumb, icon);
+        return new GuidanceStylist.Guidance(title, description, breadcrumb, new AvatarDrawable(getContext(), (Bitmap) null, mModel == null ? null : mModel.getFullName(), mModel == null ? null : mModel.getUsername(), null, true));
     }
 
     @Override
@@ -196,27 +191,26 @@
     }
 
     @Override
-    public void goToNext(RingAccountViewModel ringAccountViewModel) {
-        GuidedStepSupportFragment next;
-        if (ringAccountViewModel.isLink()) {
-            next = TVRingLinkAccountFragment.newInstance((RingAccountViewModelImpl) ringAccountViewModel);
-        } else {
-            next = TVRingAccountCreationFragment.newInstance((RingAccountViewModelImpl) ringAccountViewModel);
+    public void goToNext(AccountCreationModel accountCreationModel, boolean saveProfile) {
+        Activity wizardActivity = getActivity();
+        if (wizardActivity instanceof TVAccountWizard) {
+            TVAccountWizard wizard = (TVAccountWizard) wizardActivity;
+            wizard.profileCreated(accountCreationModel, saveProfile);
         }
-        GuidedStepSupportFragment.add(getFragmentManager(), next);
     }
 
     @Override
-    public void photoUpdate(RingAccountViewModel ringAccountViewModel) {
-        ((RingAccountViewModelImpl) ringAccountViewModel).setPhoto(mSourcePhoto);
+    public void photoUpdate(AccountCreationModel accountCreationModel) {
+        ((AccountCreationModelImpl) accountCreationModel).setPhoto(mSourcePhoto);
+    }
 
-        RingAccountViewModelImpl model = (RingAccountViewModelImpl) ringAccountViewModel;
-
-        Glide.with(getActivity())
-                .load(model.getPhoto())
-                .apply(AvatarFactory.getGlideOptions(true))
-                .transition(DrawableTransitionOptions.withCrossFade())
-                .into(getGuidanceStylist().getIconView());
+    @Override
+    public void setProfile(AccountCreationModel accountCreationModel) {
+        AccountCreationModelImpl model = ((AccountCreationModelImpl) accountCreationModel);
+        Account newAccount = model.getNewAccount();
+        AvatarDrawable avatar = new AvatarDrawable(getContext(), model.getPhoto(), accountCreationModel.getFullName(), accountCreationModel.getUsername(), newAccount == null ? null : newAccount.getUsername(), true);
+        avatar.setInSize(iconSize);
+        getGuidanceStylist().getIconView().setImageDrawable(avatar);
     }
 
     public long onGuidedActionEditedAndProceed(GuidedAction action) {
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java
index cab33cb..7807fdd 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java
@@ -29,19 +29,15 @@
 import android.view.ViewGroup;
 import android.widget.EditText;
 
-import com.bumptech.glide.Glide;
-import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
-
 import java.util.List;
 
 import cx.ring.R;
+import cx.ring.account.AccountCreationModelImpl;
 import cx.ring.account.RingAccountCreationFragment;
 import cx.ring.account.RingAccountCreationPresenter;
 import cx.ring.account.RingAccountCreationView;
-import cx.ring.account.RingAccountViewModelImpl;
 import cx.ring.application.RingApplication;
-import cx.ring.contacts.AvatarFactory;
-import cx.ring.mvp.RingAccountViewModel;
+import cx.ring.mvp.AccountCreationModel;
 import cx.ring.utils.Log;
 import cx.ring.utils.StringUtils;
 
@@ -76,7 +72,7 @@
     public TVRingAccountCreationFragment() {
     }
 
-    public static TVRingAccountCreationFragment newInstance(RingAccountViewModelImpl ringAccountViewModel) {
+    public static TVRingAccountCreationFragment newInstance(AccountCreationModelImpl ringAccountViewModel) {
         Bundle bundle = new Bundle();
         bundle.putParcelable(RingAccountCreationFragment.KEY_RING_ACCOUNT, ringAccountViewModel);
         TVRingAccountCreationFragment fragment = new TVRingAccountCreationFragment();
@@ -91,7 +87,7 @@
         // Bind the presenter to the view
         super.onViewCreated(view, savedInstanceState);
 
-        RingAccountViewModelImpl ringAccountViewModel = getArguments().getParcelable(RingAccountCreationFragment.KEY_RING_ACCOUNT);
+        AccountCreationModelImpl ringAccountViewModel = getArguments().getParcelable(RingAccountCreationFragment.KEY_RING_ACCOUNT);
         if (ringAccountViewModel == null) {
             Log.e(TAG, "Not able to get model");
             return;
@@ -99,12 +95,7 @@
 
         presenter.init(ringAccountViewModel);
         presenter.ringCheckChanged(false);
-
-        Glide.with(getActivity())
-                .load(ringAccountViewModel.getPhoto())
-                .apply(AvatarFactory.getGlideOptions(true))
-                .transition(DrawableTransitionOptions.withCrossFade())
-                .into(getGuidanceStylist().getIconView());
+        getGuidanceStylist().getIconView().setImageResource(R.drawable.logo_ring);
     }
 
     @Override
@@ -268,11 +259,11 @@
     }
 
     @Override
-    public void goToAccountCreation(RingAccountViewModel ringAccountViewModel) {
+    public void goToAccountCreation(AccountCreationModel accountCreationModel) {
         Activity wizardActivity = getActivity();
         if (wizardActivity instanceof TVAccountWizard) {
             TVAccountWizard wizard = (TVAccountWizard) wizardActivity;
-            wizard.createAccount(ringAccountViewModel);
+            wizard.createAccount(accountCreationModel);
         }
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVRingLinkAccountFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVRingLinkAccountFragment.java
index 48cf380..bb3a3ae 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVRingLinkAccountFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVRingLinkAccountFragment.java
@@ -28,11 +28,11 @@
 
 import cx.ring.R;
 import cx.ring.account.RingAccountCreationFragment;
-import cx.ring.account.RingAccountViewModelImpl;
+import cx.ring.account.AccountCreationModelImpl;
 import cx.ring.account.RingLinkAccountPresenter;
 import cx.ring.account.RingLinkAccountView;
 import cx.ring.application.RingApplication;
-import cx.ring.mvp.RingAccountViewModel;
+import cx.ring.mvp.AccountCreationModel;
 import cx.ring.utils.StringUtils;
 
 public class TVRingLinkAccountFragment extends RingGuidedStepFragment<RingLinkAccountPresenter>
@@ -44,7 +44,7 @@
     public TVRingLinkAccountFragment() {
     }
 
-    public static TVRingLinkAccountFragment newInstance(RingAccountViewModelImpl ringAccountViewModel) {
+    public static TVRingLinkAccountFragment newInstance(AccountCreationModelImpl ringAccountViewModel) {
         Bundle bundle = new Bundle();
         bundle.putParcelable(RingAccountCreationFragment.KEY_RING_ACCOUNT, ringAccountViewModel);
         TVRingLinkAccountFragment fragment = new TVRingLinkAccountFragment();
@@ -57,7 +57,7 @@
         ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
         super.onViewCreated(view, savedInstanceState);
 
-        RingAccountViewModelImpl ringAccountViewModel = getArguments().getParcelable(RingAccountCreationFragment.KEY_RING_ACCOUNT);
+        AccountCreationModelImpl ringAccountViewModel = getArguments().getParcelable(RingAccountCreationFragment.KEY_RING_ACCOUNT);
         presenter.init(ringAccountViewModel);
         if (ringAccountViewModel.getPhoto() != null) {
             getGuidanceStylist().getIconView().setImageBitmap(ringAccountViewModel.getPhoto());
@@ -101,8 +101,8 @@
     }
 
     @Override
-    public void createAccount(RingAccountViewModel ringAccountViewModel) {
-        ((TVAccountWizard) getActivity()).createAccount(ringAccountViewModel);
+    public void createAccount(AccountCreationModel accountCreationModel) {
+        ((TVAccountWizard) getActivity()).createAccount(accountCreationModel);
     }
 
     @Override
diff --git a/ring-android/app/src/main/java/cx/ring/tv/cards/contacts/ContactCardPresenter.java b/ring-android/app/src/main/java/cx/ring/tv/cards/contacts/ContactCardPresenter.java
index 82d94f3..e452789 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/cards/contacts/ContactCardPresenter.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/cards/contacts/ContactCardPresenter.java
@@ -34,6 +34,7 @@
 import cx.ring.model.CallContact;
 import cx.ring.tv.cards.AbstractCardPresenter;
 import cx.ring.tv.cards.Card;
+import cx.ring.views.AvatarDrawable;
 
 public class ContactCardPresenter extends AbstractCardPresenter<ImageCardView> {
 
@@ -68,11 +69,6 @@
         }
 
         cardView.setBackgroundColor(cardView.getResources().getColor(R.color.color_primary_dark));
-        AvatarFactory.getGlideAvatar(getContext(), model).into(new ViewTarget<ImageCardView, Drawable>(cardView){
-            @Override
-            public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
-                cardView.setMainImage(resource);
-            }
-        }.waitForLayout());
+        cardView.setMainImage(new AvatarDrawable(getContext(), model, false));
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.java b/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.java
index c039282..804aeb0 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.java
@@ -20,7 +20,6 @@
 package cx.ring.tv.main;
 
 import android.content.Intent;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import androidx.leanback.app.BackgroundManager;
 import androidx.leanback.app.GuidedStepSupportFragment;
@@ -32,19 +31,19 @@
 import androidx.leanback.widget.Row;
 import androidx.leanback.widget.RowPresenter;
 import androidx.core.app.ActivityOptionsCompat;
+
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
-import com.bumptech.glide.Glide;
-
 import java.util.ArrayList;
 import java.util.List;
 
 import cx.ring.R;
 import cx.ring.application.RingApplication;
-import cx.ring.contacts.AvatarFactory;
+import cx.ring.model.Account;
 import cx.ring.navigation.RingNavigationViewModel;
 import cx.ring.tv.about.AboutActivity;
 import cx.ring.tv.account.TVAccountExport;
@@ -63,8 +62,10 @@
 import cx.ring.tv.model.TVListViewModel;
 import cx.ring.tv.search.SearchActivity;
 import cx.ring.tv.views.CustomTitleView;
+import cx.ring.utils.Tuple;
+import cx.ring.utils.VCardUtils;
+import cx.ring.views.AvatarDrawable;
 import ezvcard.VCard;
-import ezvcard.property.FormattedName;
 
 public class MainFragment extends BaseBrowseFragment<MainPresenter> implements MainView {
 
@@ -252,10 +253,24 @@
         }
 
         VCard vcard = viewModel.getVcard();
-        String registeredName = viewModel.getAccount().getRegisteredName();
-        String uri = viewModel.getAccount().getUri();
+        Account account = viewModel.getAccount();
+        String registeredName = account.getRegisteredName();
+        String address = account.getDisplayUsername();
+        Tuple<String, byte[]> profile = VCardUtils.readData(vcard);
+
+        if (profile.first != null && !profile.first.isEmpty()) {
+            titleView.setAlias(profile.first);
+            if (address != null) {
+                setTitle(address);
+            } else {
+                setTitle("");
+            }
+        } else {
+            titleView.setAlias(address);
+        }
+
         titleView.getLogoView().setVisibility(View.VISIBLE);
-        AvatarFactory.getGlideAvatar(getActivity(), Glide.with(this), vcard, registeredName, uri).into(titleView.getLogoView());
+        titleView.getLogoView().setImageDrawable(new AvatarDrawable(getActivity(), profile, registeredName, account.getUsername()));
     }
 
     @Override
diff --git a/ring-android/app/src/main/java/cx/ring/utils/CircleTransform.java b/ring-android/app/src/main/java/cx/ring/utils/CircleTransform.java
deleted file mode 100644
index 04288b7..0000000
--- a/ring-android/app/src/main/java/cx/ring/utils/CircleTransform.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *  Copyright (C) 2004-2018 Savoir-faire Linux Inc.
- *
- *  Author: Hadrien De Sousa <hadrien.desousa@savoirfairelinux.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-package cx.ring.utils;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import androidx.annotation.NonNull;
-
-import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
-import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
-
-import java.security.MessageDigest;
-
-public class CircleTransform extends BitmapTransformation {
-    // Using the fully qualified class name (not {@link Class#getName()}) to avoid proguard obfuscation
-    private static final String ID = "cx.ring.utils.CircleTransform";
-    private static final byte[] ID_BYTES = ID.getBytes(CHARSET);
-
-    @Override
-    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap source, int outWidth, int outHeight) {
-        int size = Math.min(source.getWidth(), source.getHeight());
-        int x = (source.getWidth() - size) / 2;
-        int y = (source.getHeight() - size) / 2;
-        Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);
-        Bitmap result = pool.get(size, size, source.getConfig());
-
-        Canvas canvas = new Canvas(result);
-        Paint paint = new Paint();
-        paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
-        paint.setAntiAlias(true);
-        float radius = size / 2f;
-        canvas.drawCircle(radius, radius, radius, paint);
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        return o instanceof CircleTransform;
-    }
-
-    @Override
-    public int hashCode() {
-        return ID.hashCode();
-    }
-
-    @Override
-    public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
-        messageDigest.update(ID_BYTES);
-    }
-}
diff --git a/ring-android/app/src/main/res/layout/frag_acc_home_create.xml b/ring-android/app/src/main/res/layout/frag_acc_home_create.xml
index 8c47a94..b708371 100644
--- a/ring-android/app/src/main/res/layout/frag_acc_home_create.xml
+++ b/ring-android/app/src/main/res/layout/frag_acc_home_create.xml
@@ -11,7 +11,8 @@
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
         android:animateLayoutChanges="true"
-        android:orientation="vertical">
+        android:orientation="vertical"
+        android:paddingBottom="16dp">
 
         <ImageView
             android:id="@+id/imageView6"
@@ -30,38 +31,38 @@
             android:paddingLeft="16dp"
             android:paddingRight="16dp"
             android:text="@string/account_creation_home"
-            android:textSize="24sp"
-            android:textColor="@color/text_color_primary_dark"/>
+            android:textColor="@color/text_color_primary_dark"
+            android:textSize="24sp" />
 
         <TextView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:gravity="center"
-            android:paddingBottom="24dp"
             android:paddingLeft="16dp"
-            android:paddingRight="16dp"
             android:paddingTop="24dp"
+            android:paddingRight="16dp"
+            android:paddingBottom="24dp"
             android:text="@string/help_ring"
-            android:textSize="14sp"
-            android:textColor="@color/text_color_primary_dark" />
+            android:textColor="@color/text_color_primary_dark"
+            android:textSize="14sp" />
 
-        <androidx.appcompat.widget.AppCompatButton
+        <com.google.android.material.button.MaterialButton
             android:id="@+id/ring_add_account"
-            android:theme="@style/ButtonColored"
             android:layout_width="300dp"
             android:layout_height="wrap_content"
+            android:layout_gravity="center"
             android:layout_marginBottom="16dp"
-            android:layout_gravity="center"
-            android:text="@string/account_link_button" />
+            android:text="@string/account_link_button"
+            android:theme="@style/ButtonColored" />
 
 
-        <androidx.appcompat.widget.AppCompatButton
+        <com.google.android.material.button.MaterialButton
             android:id="@+id/ring_create_btn"
-            android:theme="@style/ButtonColored"
             android:layout_width="300dp"
             android:layout_height="wrap_content"
             android:layout_gravity="center"
-            android:text="@string/account_new_button" />
+            android:text="@string/account_new_button"
+            android:theme="@style/ButtonColored" />
 
     </LinearLayout>
 
diff --git a/ring-android/app/src/main/res/layout/frag_acc_profile_create.xml b/ring-android/app/src/main/res/layout/frag_acc_profile_create.xml
index 87b9595..ec0d891 100644
--- a/ring-android/app/src/main/res/layout/frag_acc_profile_create.xml
+++ b/ring-android/app/src/main/res/layout/frag_acc_profile_create.xml
@@ -8,6 +8,7 @@
     tools:background="@color/color_primary_dark">
 
     <cx.ring.views.BoundedScrollView
+        android:id="@+id/scrollview"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_above="@+id/next_create_account"
@@ -113,14 +114,29 @@
 
     </cx.ring.views.BoundedScrollView>
 
-    <Button
+    <com.google.android.material.button.MaterialButton
         android:id="@+id/next_create_account"
-        style="@style/WizardNavButton"
-        android:layout_width="match_parent"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_alignEnd="@id/scrollview"
         android:layout_alignParentBottom="true"
-        android:layout_centerHorizontal="true"
-        android:background="@color/color_primary_light"
+        android:layout_marginStart="16dp"
+        android:layout_marginTop="16dp"
+        android:layout_marginEnd="@dimen/activity_horizontal_margin"
+        android:layout_marginBottom="16dp"
         android:text="@string/wizard_next" />
 
+    <com.google.android.material.button.MaterialButton
+        android:id="@+id/skip_create_account"
+        style="@style/Widget.MaterialComponents.Button.TextButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toStartOf="@id/next_create_account"
+        android:layout_alignParentBottom="true"
+        android:layout_marginStart="16dp"
+        android:layout_marginTop="16dp"
+        android:layout_marginEnd="24dp"
+        android:layout_marginBottom="16dp"
+        android:text="@string/wizard_skip" />
+
 </RelativeLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/frag_acc_ring_create.xml b/ring-android/app/src/main/res/layout/frag_acc_ring_create.xml
index 3b259f8..8c29b5d 100644
--- a/ring-android/app/src/main/res/layout/frag_acc_ring_create.xml
+++ b/ring-android/app/src/main/res/layout/frag_acc_ring_create.xml
@@ -9,27 +9,27 @@
     tools:context="cx.ring.account.AccountWizardActivity">
 
     <cx.ring.views.BoundedScrollView
+        android:id="@+id/scrollview"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         android:layout_above="@+id/create_account"
+        android:layout_alignParentTop="true"
+        android:layout_centerHorizontal="true"
         app:bounded_width="500dp">
 
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_gravity="center"
             android:animateLayoutChanges="true"
             android:orientation="vertical"
-            android:paddingBottom="@dimen/activity_vertical_margin"
-            android:paddingLeft="@dimen/activity_horizontal_margin"
-            android:paddingRight="@dimen/activity_horizontal_margin">
+            android:paddingStart="@dimen/activity_horizontal_margin"
+            android:paddingEnd="@dimen/activity_horizontal_margin">
 
             <TextView
                 android:id="@+id/title"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_margin="24dp"
-                android:gravity="center"
                 android:text="@string/account_creation_ring"
                 android:textColor="@color/text_color_primary_dark"
                 android:textSize="24sp" />
@@ -39,7 +39,8 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:checked="true"
-                android:padding="16dp"
+                android:paddingTop="16dp"
+                android:paddingBottom="16dp"
                 android:text="@string/register_username"
                 android:textColor="@color/text_color_primary_dark" />
 
@@ -53,82 +54,112 @@
                     android:id="@+id/ring_username_txt_box"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:layout_marginBottom="16dp"
-                    android:layout_marginLeft="12dp"
-                    android:layout_marginRight="12dp">
+                    android:layout_marginBottom="16dp">
 
                     <com.google.android.material.textfield.TextInputEditText
                         android:id="@+id/ring_username"
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
                         android:autofillHints="username"
+                        android:focusable="true"
+                        android:focusableInTouchMode="true"
+                        android:focusedByDefault="true"
                         android:hint="@string/prompt_new_username"
                         android:imeOptions="actionNext"
                         android:inputType="text"
                         android:lines="1"
-                        android:maxLines="1" />
+                        android:maxLines="1">
+
+                        <requestFocus />
+                    </com.google.android.material.textfield.TextInputEditText>
                 </com.google.android.material.textfield.TextInputLayout>
 
             </LinearLayout>
 
-            <TextView
+            <Switch
+                android:id="@+id/ring_password_switch"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:paddingBottom="8dp"
-                android:paddingEnd="16dp"
-                android:paddingStart="16dp"
                 android:paddingTop="16dp"
-                android:text="@string/help_password_choose"
+                android:paddingBottom="16dp"
+                android:text="Choose a password for enhanced security"
                 android:textColor="@color/text_color_primary_dark" />
 
-            <com.google.android.material.textfield.TextInputLayout
-                android:id="@+id/ring_password_txt_box"
+            <LinearLayout
+                android:id="@+id/ring_password_box"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_marginLeft="12dp"
-                android:layout_marginRight="12dp"
-                app:passwordToggleEnabled="true">
+                android:orientation="vertical"
+                android:visibility="gone"
+                tools:visibility="visible">
 
-                <com.google.android.material.textfield.TextInputEditText
-                    android:id="@+id/ring_password"
+                <TextView
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:hint="@string/prompt_new_password"
-                    android:imeOptions="actionNext"
-                    android:inputType="textPassword" />
-            </com.google.android.material.textfield.TextInputLayout>
+                    android:layout_marginBottom="8dp"
+                    android:text="@string/help_password_choose"
+                    android:textColor="@color/text_color_primary_dark" />
 
-            <com.google.android.material.textfield.TextInputLayout
-                android:id="@+id/ring_password_repeat_txt_box"
+                <com.google.android.material.textfield.TextInputLayout
+                    android:id="@+id/ring_password_txt_box"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    app:passwordToggleEnabled="true">
+
+                    <com.google.android.material.textfield.TextInputEditText
+                        android:id="@+id/ring_password"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:hint="@string/prompt_new_password"
+                        android:imeOptions="actionNext"
+                        android:inputType="textPassword" />
+                </com.google.android.material.textfield.TextInputLayout>
+
+                <com.google.android.material.textfield.TextInputLayout
+                    android:id="@+id/ring_password_repeat_txt_box"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    app:passwordToggleEnabled="true">
+
+                    <com.google.android.material.textfield.TextInputEditText
+                        android:id="@+id/ring_password_repeat"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginBottom="16dp"
+                        android:hint="@string/prompt_new_password_repeat"
+                        android:imeActionLabel="@string/action_create_short"
+                        android:imeOptions="actionDone"
+                        android:inputType="textPassword" />
+                </com.google.android.material.textfield.TextInputLayout>
+            </LinearLayout>
+
+            <Switch
+                android:id="@+id/switch_ring_push"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_marginLeft="12dp"
-                android:layout_marginRight="12dp"
-                app:passwordToggleEnabled="true">
-
-                <com.google.android.material.textfield.TextInputEditText
-                    android:id="@+id/ring_password_repeat"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:hint="@string/prompt_new_password_repeat"
-                    android:imeActionLabel="@string/action_create_short"
-                    android:imeOptions="actionDone"
-                    android:inputType="textPassword" />
-            </com.google.android.material.textfield.TextInputLayout>
+                android:checked="true"
+                android:paddingTop="16dp"
+                android:paddingBottom="16dp"
+                android:text="Use push notifications"
+                android:textColor="@color/text_color_primary_dark" />
 
         </LinearLayout>
 
     </cx.ring.views.BoundedScrollView>
 
-    <Button
+    <com.google.android.material.button.MaterialButton
         android:id="@+id/create_account"
-        android:theme="@style/ButtonColoredInverse"
-        android:layout_width="match_parent"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_alignEnd="@id/scrollview"
         android:layout_alignParentBottom="true"
-        android:layout_centerHorizontal="true"
+        android:layout_marginStart="@dimen/activity_horizontal_margin"
+        android:layout_marginTop="8dp"
+        android:layout_marginEnd="@dimen/activity_horizontal_margin"
+        android:layout_marginBottom="24dp"
         android:background="@color/color_primary_light"
         android:enabled="false"
-        android:text="@string/account_new_button" />
+        android:text="@string/account_new_button"
+        android:theme="@style/ButtonColoredInverse" />
 
 </RelativeLayout>
diff --git a/ring-android/app/src/main/res/layout/frag_acc_ring_link.xml b/ring-android/app/src/main/res/layout/frag_acc_ring_link.xml
index 92f77de..afa667e 100644
--- a/ring-android/app/src/main/res/layout/frag_acc_ring_link.xml
+++ b/ring-android/app/src/main/res/layout/frag_acc_ring_link.xml
@@ -8,6 +8,7 @@
     tools:background="@color/color_primary_dark">
 
     <cx.ring.views.BoundedScrollView
+        android:id="@+id/scrollview"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_above="@+id/link_button"
@@ -17,11 +18,10 @@
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_gravity="center"
             android:orientation="vertical"
             android:paddingBottom="@dimen/activity_vertical_margin"
-            android:paddingLeft="@dimen/activity_horizontal_margin"
-            android:paddingRight="@dimen/activity_horizontal_margin"
+            android:paddingEnd="@dimen/activity_horizontal_margin"
+            android:paddingStart="@dimen/activity_horizontal_margin"
             android:paddingTop="@dimen/activity_vertical_margin">
 
             <TextView
@@ -95,13 +95,16 @@
 
     </cx.ring.views.BoundedScrollView>
 
-    <Button
+    <com.google.android.material.button.MaterialButton
         android:id="@+id/link_button"
-        android:layout_width="match_parent"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_alignEnd="@id/scrollview"
         android:layout_alignParentBottom="true"
-        android:layout_centerHorizontal="true"
-        android:background="@color/color_primary_light"
+        android:layout_marginStart="@dimen/activity_horizontal_margin"
+        android:layout_marginTop="8dp"
+        android:layout_marginEnd="@dimen/activity_horizontal_margin"
+        android:layout_marginBottom="24dp"
         android:enabled="false"
         android:text="@string/account_link_button"
         android:theme="@style/ButtonColoredInverse" />
diff --git a/ring-android/app/src/main/res/layout/frag_acc_sip_create.xml b/ring-android/app/src/main/res/layout/frag_acc_sip_create.xml
index 69776d0..0f255a4 100644
--- a/ring-android/app/src/main/res/layout/frag_acc_sip_create.xml
+++ b/ring-android/app/src/main/res/layout/frag_acc_sip_create.xml
@@ -19,7 +19,7 @@
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
@@ -29,25 +29,26 @@
     tools:background="@color/color_primary_dark">
 
     <cx.ring.views.BoundedScrollView
+        android:id="@+id/scrollview"
         android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_gravity="center_horizontal"
-        android:layout_weight="1"
+        android:layout_height="match_parent"
+        android:layout_centerHorizontal="true"
         app:bounded_width="500dp">
 
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_gravity="center"
             android:orientation="vertical"
+            android:paddingStart="@dimen/activity_horizontal_margin"
             android:paddingLeft="16dp"
+            android:paddingEnd="@dimen/activity_horizontal_margin"
             android:paddingRight="16dp">
 
             <TextView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
+                android:layout_margin="24dp"
                 android:gravity="center"
-                android:paddingTop="24dp"
                 android:text="@string/help_sip_title"
                 android:textSize="24sp" />
 
@@ -129,12 +130,18 @@
         </LinearLayout>
     </cx.ring.views.BoundedScrollView>
 
-    <Button
+    <com.google.android.material.button.MaterialButton
         android:id="@+id/create_sip_button"
-        android:layout_width="match_parent"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_alignEnd="@id/scrollview"
+        android:layout_alignParentBottom="true"
+        android:layout_gravity="end"
+        android:layout_marginTop="8dp"
+        android:layout_marginEnd="@dimen/activity_horizontal_margin"
+        android:layout_marginBottom="24dp"
         android:background="@color/color_primary_light"
         android:text="@string/create_sip_account"
         android:theme="@style/ButtonColoredInverse" />
 
-</LinearLayout>
+</RelativeLayout>
diff --git a/ring-android/app/src/main/res/layout/frag_navigation.xml b/ring-android/app/src/main/res/layout/frag_navigation.xml
index c36dd2d..f5ac8d7 100644
--- a/ring-android/app/src/main/res/layout/frag_navigation.xml
+++ b/ring-android/app/src/main/res/layout/frag_navigation.xml
@@ -37,7 +37,7 @@
                     android:id="@+id/anchor"
                     android:layout_width="20dp"
                     android:layout_height="20dp"
-                    android:layout_alignBottom="@+id/user_photo"
+                    android:layout_alignBottom="@id/user_photo"
                     android:layout_centerHorizontal="true" />
 
                 <com.google.android.material.floatingactionbutton.FloatingActionButton
diff --git a/ring-android/app/src/main/res/values/dimens.xml b/ring-android/app/src/main/res/values/dimens.xml
index 8b62b48..2c47836 100644
--- a/ring-android/app/src/main/res/values/dimens.xml
+++ b/ring-android/app/src/main/res/values/dimens.xml
@@ -27,7 +27,7 @@
 
     <dimen name="radius_message_input">16dp</dimen>
 
-    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_horizontal_margin">32dp</dimen>
     <dimen name="activity_vertical_margin">16dp</dimen>
 
     <dimen name="action_button_lpadding">0dp</dimen>
diff --git a/ring-android/app/src/main/res/values/strings.xml b/ring-android/app/src/main/res/values/strings.xml
index 4117ab7..7b3e1bd 100644
--- a/ring-android/app/src/main/res/values/strings.xml
+++ b/ring-android/app/src/main/res/values/strings.xml
@@ -192,6 +192,7 @@
     <string name="help_pin_enter">Enter the PIN from another configured Ring account. Use the \"export account on Ring\" feature to obtain a PIN.</string>
     <string name="wizard_next">Next</string>
     <string name="wizard_back">Back</string>
+    <string name="wizard_skip">Skip</string>
 
     <!-- MenuHeaderView -->
     <string name="profile">My profile</string>