multi-device: account migration

- detects a need for migration in Home screen
- offers a migration dialog in Account management screen

Tuleap: #955
Change-Id: Ia7bce09720fd0ad08a624aafde69e1be304c42ef
diff --git a/ring-android/app/src/main/java/cx/ring/client/AccountWizard.java b/ring-android/app/src/main/java/cx/ring/client/AccountWizard.java
index cffd9d3..d4a32ef 100644
--- a/ring-android/app/src/main/java/cx/ring/client/AccountWizard.java
+++ b/ring-android/app/src/main/java/cx/ring/client/AccountWizard.java
@@ -21,18 +21,19 @@
 
 package cx.ring.client;
 
+import android.app.Fragment;
+import android.app.FragmentManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentStatePagerAdapter;
+import android.support.v13.app.FragmentStatePagerAdapter;
 import android.support.v4.view.ViewPager;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.MenuItem;
 
@@ -41,11 +42,12 @@
 
 import cx.ring.R;
 import cx.ring.fragments.AccountCreationFragment;
+import cx.ring.fragments.AccountMigrationFragment;
 import cx.ring.service.IDRingService;
 import cx.ring.service.LocalService;
 
 public class AccountWizard extends AppCompatActivity implements LocalService.Callbacks {
-    static final String TAG = "AccountWizard";
+    static final String TAG = AccountWizard.class.getName();
     private boolean mBound = false;
     private LocalService service;
     ViewPager mViewPager;
@@ -60,7 +62,7 @@
 
         @Override
         public void onServiceDisconnected(ComponentName arg0) {
-
+            // nothing to be done here
         }
     };
 
@@ -75,8 +77,15 @@
 
         getSupportActionBar().setDisplayHomeAsUpEnabled(true);
         getSupportActionBar().setHomeButtonEnabled(true);
-        SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(AccountWizard.this, getSupportFragmentManager());
-        mViewPager.setAdapter(mSectionsPagerAdapter);
+
+        if (getIntent().getData() != null && !TextUtils.isEmpty(getIntent().getData().getLastPathSegment())) {
+            String accountId = getIntent().getData().getLastPathSegment();
+            SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(AccountWizard.this, getFragmentManager(), accountId);
+            mViewPager.setAdapter(mSectionsPagerAdapter);
+        } else {
+            SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(AccountWizard.this, getFragmentManager());
+            mViewPager.setAdapter(mSectionsPagerAdapter);
+        }
 
         if (!mBound) {
             Log.i(TAG, "onCreate: Binding service...");
@@ -99,25 +108,39 @@
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
-        case android.R.id.home:
-            finish();
-            return true;
-        default:
-            return super.onOptionsItemSelected(item);
+            case android.R.id.home:
+                finish();
+                return true;
+            default:
+                return super.onOptionsItemSelected(item);
         }
     }
 
     public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
-
-        Context mContext;
-        ArrayList<Fragment> fragments;
+        private final Context mContext;
+        private final ArrayList<Fragment> fragments;
+        private final String mAccountId;
 
         public SectionsPagerAdapter(Context c, FragmentManager fm) {
+            this(c, fm, null);
+        }
+
+        public SectionsPagerAdapter(Context c, FragmentManager fm, String accountId) {
             super(fm);
             mContext = c;
             fragments = new ArrayList<>();
-            fragments.add(new AccountCreationFragment());
+            mAccountId = accountId;
 
+            if (TextUtils.isEmpty(mAccountId)) {
+                fragments.add(new AccountCreationFragment());
+            } else {
+                AccountMigrationFragment fragment = new AccountMigrationFragment();
+                // give the installation id to display
+                Bundle bundle = new Bundle();
+                bundle.putString(AccountMigrationFragment.ACCOUNT_ID, mAccountId);
+                fragment.setArguments(bundle);
+                fragments.add(fragment);
+            }
         }
 
         @Override
@@ -129,16 +152,19 @@
             String name;
 
             switch (i) {
-            case 0:
-                name = AccountCreationFragment.class.getName();
-                break;
+                case 0:
+                    if (TextUtils.isEmpty(mAccountId)) {
+                        name = AccountCreationFragment.class.getName();
+                    } else {
+                        name = AccountMigrationFragment.class.getName();
+                    }
+                    break;
 
-            default:
-                Log.e(TAG, "getClassName: unknown fragment position " + i);
-                return null;
+                default:
+                    Log.e(TAG, "getClassName: unknown fragment position " + i);
+                    return null;
             }
 
-            // Log.w(TAG, "getClassName: name=" + name);
             return name;
         }
 
@@ -150,11 +176,11 @@
         @Override
         public CharSequence getPageTitle(int position) {
             switch (position) {
-            case 0:
-                return mContext.getString(R.string.title_section0).toUpperCase(Locale.getDefault());
-            default:
-                Log.e(TAG, "getPageTitle: unknown tab position " + position);
-                break;
+                case 0:
+                    return mContext.getString(R.string.title_section0).toUpperCase(Locale.getDefault());
+                default:
+                    Log.e(TAG, "getPageTitle: unknown tab position " + position);
+                    break;
             }
             return null;
         }
diff --git a/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java b/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
index 94d98df..eab9edc 100644
--- a/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
@@ -49,7 +49,6 @@
 import android.support.v7.app.ActionBarDrawerToggle;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
-import android.text.Layout;
 import android.transition.Explode;
 import android.transition.Fade;
 import android.util.Log;
@@ -101,6 +100,7 @@
     private LocalService service;
     private boolean mBound = false;
     private boolean mNoAccountOpened = false;
+    private boolean mIsMigrationDialogAlreadyShowed;
 
     private NavigationView fMenu;
     private MenuHeaderView fMenuHead = null;
@@ -149,8 +149,8 @@
         setSupportActionBar(mToolbar);
         actionButton = (FloatingActionButton) findViewById(R.id.action_button);
 
-        mToolbarSpacerView = (LinearLayout)findViewById(R.id.toolbar_spacer);
-        mToolbarSpacerTitle = (TextView)findViewById(R.id.toolbar_spacer_title);
+        mToolbarSpacerView = (LinearLayout) findViewById(R.id.toolbar_spacer);
+        mToolbarSpacerTitle = (TextView) findViewById(R.id.toolbar_spacer_title);
 
         fMenu = (NavigationView) findViewById(R.id.left_drawer);
         fMenu.setNavigationItemSelectedListener(this);
@@ -186,7 +186,7 @@
         if (toRequest.length > 0) {
             ActivityCompat.requestPermissions(this, toRequest, LocalService.PERMISSIONS_REQUEST);
         } else if (!mBound) {
-            Log.i(TAG, "onCreate: Binding service...");
+            Log.d(TAG, "onCreate: Binding service...");
             Intent intent = new Intent(this, LocalService.class);
             startService(intent);
             bindService(intent, mConnection, BIND_AUTO_CREATE | BIND_IMPORTANT | BIND_ABOVE_CLIENT);
@@ -217,9 +217,17 @@
     final BroadcastReceiver receiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            Log.w(TAG, "onReceive " + intent.getAction());
+            Log.d(TAG, "onReceive " + intent.getAction());
             switch (intent.getAction()) {
                 case LocalService.ACTION_ACCOUNT_UPDATE:
+
+                    for (Account account : service.getAccounts()) {
+
+                        if (account.needsMigration()) {
+                            showMigrationDialog();
+                        }
+                    }
+
                     if (!mNoAccountOpened && service.getAccounts().isEmpty()) {
                         mNoAccountOpened = true;
                         startActivityForResult(new Intent().setClass(HomeActivity.this, AccountWizard.class), AccountsManagementFragment.ACCOUNT_CREATE_REQUEST);
@@ -231,6 +239,50 @@
         }
     };
 
+    private void showMigrationDialog() {
+
+        if (mIsMigrationDialogAlreadyShowed) {
+            return;
+        }
+
+        mIsMigrationDialogAlreadyShowed = true;
+
+        AlertDialog.Builder builder = new AlertDialog.Builder(HomeActivity.this)
+                .setTitle(R.string.account_migration_title_dialog)
+                .setMessage(R.string.account_migration_message_dialog)
+                .setIcon(R.drawable.ic_warning)
+                .setCancelable(true)
+                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        dialog.dismiss();
+                        onNavigationItemSelected(fMenu.getMenu().findItem(R.id.menuitem_accounts));
+                        fMenu.getMenu().findItem(R.id.menuitem_accounts).setChecked(true);
+                    }
+                })
+                .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        dialog.dismiss();
+                    }
+                })
+                .setOnCancelListener(new DialogInterface.OnCancelListener() {
+                    @Override
+                    public void onCancel(DialogInterface dialog) {
+                        dialog.dismiss();
+                    }
+                });
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
+                @Override
+                public void onDismiss(DialogInterface dialog) {
+                    dialog.dismiss();
+                }
+            });
+        }
+        builder.show();
+    }
+
     @Override
     protected void onPostCreate(Bundle savedInstanceState) {
         super.onPostCreate(savedInstanceState);
@@ -245,7 +297,7 @@
 
     @Override
     protected void onStart() {
-        Log.i(TAG, "onStart");
+        Log.d(TAG, "onStart");
         if (!PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getBoolean("installed", false)) {
             PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).edit().putBoolean("installed", true).commit();
             copyAssetFolder(getAssets(), "ringtones", getFilesDir().getAbsolutePath() + "/ringtones");
@@ -256,7 +308,7 @@
 
     @Override
     public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
-        Log.w(TAG, "onRequestPermissionsResult");
+        Log.d(TAG, "onRequestPermissionsResult");
 
         switch (requestCode) {
             case LocalService.PERMISSIONS_REQUEST: {
@@ -318,18 +370,18 @@
         }
     }
 
-    public void setToolbarState(boolean double_h, int title_res) {
+    public void setToolbarState(boolean doubleHeight, int titleRes) {
 
         mToolbar.setMinimumHeight((int) mToolbarSize);
         ViewGroup.LayoutParams toolbarSpacerViewParams = mToolbarSpacerView.getLayoutParams();
 
-        if (double_h) {
+        if (doubleHeight) {
             // setting the height of the toolbar spacer with the same height than the toolbar
-            toolbarSpacerViewParams.height = (int)mToolbarSize;
+            toolbarSpacerViewParams.height = (int) mToolbarSize;
             mToolbarSpacerView.setLayoutParams(toolbarSpacerViewParams);
 
             // setting the toolbar spacer title (hiding the real toolbar title)
-            mToolbarSpacerTitle.setText(title_res);
+            mToolbarSpacerTitle.setText(titleRes);
             mToolbar.setTitle("");
 
             // the spacer and the action button become visible
@@ -339,7 +391,7 @@
             // hide the toolbar spacer and the action button
             mToolbarSpacerView.setVisibility(View.GONE);
             actionButton.setVisibility(View.GONE);
-            mToolbar.setTitle(title_res);
+            mToolbar.setTitle(titleRes);
 
         }
     }
@@ -352,19 +404,19 @@
         try {
             String[] files = assetManager.list(fromAssetPath);
             new File(toPath).mkdirs();
-            Log.i(TAG, "Creating :" + toPath);
+            Log.d(TAG, "Creating :" + toPath);
             boolean res = true;
             for (String file : files)
                 if (file.contains("")) {
-                    Log.i(TAG, "Copying file :" + fromAssetPath + "/" + file + " to " + toPath + "/" + file);
+                    Log.d(TAG, "Copying file :" + fromAssetPath + "/" + file + " to " + toPath + "/" + file);
                     res &= copyAsset(assetManager, fromAssetPath + "/" + file, toPath + "/" + file);
                 } else {
-                    Log.i(TAG, "Copying folder :" + fromAssetPath + "/" + file + " to " + toPath + "/" + file);
+                    Log.d(TAG, "Copying folder :" + fromAssetPath + "/" + file + " to " + toPath + "/" + file);
                     res &= copyAssetFolder(assetManager, fromAssetPath + "/" + file, toPath + "/" + file);
                 }
             return res;
         } catch (Exception e) {
-            e.printStackTrace();
+            Log.e(TAG, "Error while copying asset folder", e);
             return false;
         }
     }
@@ -384,7 +436,7 @@
             out = null;
             return true;
         } catch (Exception e) {
-            e.printStackTrace();
+            Log.e(TAG, "Error while copying asset", e);
             return false;
         }
     }
@@ -427,11 +479,11 @@
     }
 
     private void popCustomBackStack() {
-        FragmentManager fm = getFragmentManager();
-        FragmentManager.BackStackEntry entry = fm.getBackStackEntryAt(0);
-        fContent = fm.findFragmentByTag(entry.getName());
-        for (int i = 0; i < fm.getBackStackEntryCount() - 1; ++i) {
-            fm.popBackStack();
+        FragmentManager fragmentManager = getFragmentManager();
+        FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(0);
+        fContent = fragmentManager.findFragmentByTag(entry.getName());
+        for (int i = 0; i < fragmentManager.getBackStackEntryCount() - 1; ++i) {
+            fragmentManager.popBackStack();
         }
     }
 
@@ -460,7 +512,7 @@
 
         @Override
         public void onServiceConnected(ComponentName className, IBinder s) {
-            Log.i(TAG, "onServiceConnected " + className.getClassName());
+            Log.d(TAG, "onServiceConnected " + className.getClassName());
             LocalService.LocalBinder binder = (LocalService.LocalBinder) s;
             service = binder.getService();
 
@@ -480,20 +532,20 @@
                 fMenuHead.setQRCodeListener(mQRCodeClickListener);
             }
 
-            FragmentManager fm = getFragmentManager();
-            fContent = fm.findFragmentById(R.id.main_frame);
+            FragmentManager fragmentManager = getFragmentManager();
+            fContent = fragmentManager.findFragmentById(R.id.main_frame);
             if (fContent == null) {
                 fContent = new SmartListFragment();
-                fm.beginTransaction().replace(R.id.main_frame, fContent, "Home").addToBackStack("Home").commit();
+                fragmentManager.beginTransaction().replace(R.id.main_frame, fContent, "Home").addToBackStack("Home").commit();
             } else if (fContent instanceof Refreshable) {
-                fm.beginTransaction().replace(R.id.main_frame, fContent).addToBackStack("Home").commit();
+                fragmentManager.beginTransaction().replace(R.id.main_frame, fContent).addToBackStack("Home").commit();
                 ((Refreshable) fContent).refresh();
             }
         }
 
         @Override
         public void onServiceDisconnected(ComponentName className) {
-            Log.w(TAG, "onServiceDisconnected " + className.getClassName());
+            Log.d(TAG, "onServiceDisconnected " + className.getClassName());
             if (fMenuHead != null) {
                 fMenuHead.setCallbacks(null);
                 fMenuHead = null;
@@ -514,8 +566,9 @@
         switch (requestCode) {
             case REQUEST_CODE_PREFERENCES:
             case AccountsManagementFragment.ACCOUNT_EDIT_REQUEST:
-                if (fMenuHead != null)
+                if (fMenuHead != null) {
                     fMenuHead.updateAccounts(service.getAccounts());
+                }
                 break;
             case REQUEST_CODE_CALL:
                 if (resultCode == CallActivity.RESULT_FAILURE) {
@@ -544,24 +597,28 @@
         switch (pos.getItemId()) {
             case R.id.menuitem_home:
 
-                if (fContent instanceof SmartListFragment)
+                if (fContent instanceof SmartListFragment) {
                     break;
+                }
 
-                if (getFragmentManager().getBackStackEntryCount() == 1)
+                if (getFragmentManager().getBackStackEntryCount() == 1) {
                     break;
+                }
 
                 popCustomBackStack();
 
                 break;
             case R.id.menuitem_accounts:
-                if (fContent instanceof AccountsManagementFragment)
+                if (fContent instanceof AccountsManagementFragment) {
                     break;
+                }
                 fContent = new AccountsManagementFragment();
                 getFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE).replace(R.id.main_frame, fContent, "Accounts").addToBackStack("Accounts").commit();
                 break;
             case R.id.menuitem_about:
-                if (fContent instanceof AboutFragment)
+                if (fContent instanceof AboutFragment) {
                     break;
+                }
                 fContent = new AboutFragment();
                 getFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE).replace(R.id.main_frame, fContent, "About").addToBackStack("About").commit();
                 break;
@@ -585,8 +642,9 @@
         if (mNavigationDrawer != null) {
             mNavigationDrawer.closeDrawers();
         }
-        if (fContent instanceof SettingsFragment)
+        if (fContent instanceof SettingsFragment) {
             return;
+        }
         fContent = new SettingsFragment();
         getFragmentManager()
                 .beginTransaction()
@@ -598,12 +656,13 @@
 
     @Override
     public void onCallContact(final CallContact c) {
-        Log.w(TAG, "onCallContact " + c.toString() + " " + c.getId() + " " + c.getKey());
+        Log.d(TAG, "onCallContact " + c.toString() + " " + c.getId() + " " + c.getKey());
         if (c.getPhones().size() > 1) {
             final CharSequence numbers[] = new CharSequence[c.getPhones().size()];
             int i = 0;
-            for (CallContact.Phone p : c.getPhones())
+            for (CallContact.Phone p : c.getPhones()) {
                 numbers[i++] = p.getNumber().getRawUriString();
+            }
 
             AlertDialog.Builder builder = new AlertDialog.Builder(this);
             builder.setTitle(R.string.choose_number);
@@ -631,8 +690,9 @@
         if (c.getPhones().size() > 1) {
             final CharSequence numbers[] = new CharSequence[c.getPhones().size()];
             int i = 0;
-            for (CallContact.Phone p : c.getPhones())
+            for (CallContact.Phone p : c.getPhones()) {
                 numbers[i++] = p.getNumber().getRawUriString();
+            }
 
             AlertDialog.Builder builder = new AlertDialog.Builder(this);
             builder.setTitle(R.string.choose_number);
@@ -730,17 +790,17 @@
          * @return the resulting image
          */
         public static Bitmap encodeStringAsQrBitmap(String input, int qrWindowPixels) {
-            QRCodeWriter qr_writer = new QRCodeWriter();
-            BitMatrix qr_image_matrix;
+            QRCodeWriter qrWriter = new QRCodeWriter();
+            BitMatrix qrImageMatrix;
             try {
-                qr_image_matrix = qr_writer.encode(input, BarcodeFormat.QR_CODE, qrWindowPixels, qrWindowPixels);
+                qrImageMatrix = qrWriter.encode(input, BarcodeFormat.QR_CODE, qrWindowPixels, qrWindowPixels);
             } catch (WriterException e) {
-                e.printStackTrace();
+                Log.e(TAG, "Error while encoding QR", e);
                 return null;
             }
 
-            int qrImageWidth = qr_image_matrix.getWidth();
-            int qrImageHeight = qr_image_matrix.getHeight();
+            int qrImageWidth = qrImageMatrix.getWidth();
+            int qrImageHeight = qrImageMatrix.getHeight();
             int[] pixels = new int[qrImageWidth * qrImageHeight];
 
             final int BLACK = 0x00FFFFFF;
@@ -749,7 +809,7 @@
             for (int row = 0; row < qrImageHeight; row++) {
                 int offset = row * qrImageWidth;
                 for (int column = 0; column < qrImageWidth; column++) {
-                    pixels[offset + column] = qr_image_matrix.get(column, row) ? BLACK : WHITE;
+                    pixels[offset + column] = qrImageMatrix.get(column, row) ? BLACK : WHITE;
                 }
             }
 
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/AccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/AccountCreationFragment.java
index b7d3e23..af94cb2 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/AccountCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/AccountCreationFragment.java
@@ -24,6 +24,7 @@
 import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.AlertDialog;
+import android.app.Fragment;
 import android.app.ProgressDialog;
 import android.content.ContentUris;
 import android.content.Context;
@@ -41,7 +42,6 @@
 import android.provider.MediaStore;
 import android.provider.OpenableColumns;
 import android.support.annotation.NonNull;
-import android.support.v4.app.Fragment;
 import android.support.v4.content.ContextCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.text.TextUtils;
@@ -113,18 +113,18 @@
         super.onCreate(savedInstanceState);
     }
 
-    private void flipForm(boolean addacc, boolean newacc) {
-        mAddAccountLayout.setVisibility(addacc ? View.VISIBLE : View.GONE);
-        mNewAccountLayout.setVisibility(newacc ? View.VISIBLE : View.GONE);
+    private void flipForm(boolean addAccount, boolean newAccount) {
+        mAddAccountLayout.setVisibility(addAccount ? View.VISIBLE : View.GONE);
+        mNewAccountLayout.setVisibility(newAccount ? View.VISIBLE : View.GONE);
         InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
-        if (newacc) {
+        if (newAccount) {
             mRingPassword.requestFocus();
             imm.showSoftInput(mRingPassword, InputMethodManager.SHOW_IMPLICIT);
-        } else if (addacc) {
+        } else if (addAccount) {
             mRingPin.requestFocus();
             imm.showSoftInput(mRingPin, InputMethodManager.SHOW_IMPLICIT);
         }
-        if (addacc || newacc) {
+        if (addAccount || newAccount) {
             mSipFormLinearLayout.setVisibility(View.GONE);
         }
     }
@@ -137,44 +137,18 @@
         mHostnameView = (EditText) inflatedView.findViewById(R.id.hostname);
         mUsernameView = (EditText) inflatedView.findViewById(R.id.username);
         mPasswordView = (EditText) inflatedView.findViewById(R.id.password);
-        //mRingUsername = (EditText) inflatedView.findViewById(R.id.ring_alias);
         mRingPassword = (EditText) inflatedView.findViewById(R.id.ring_password);
         mRingPasswordRepeat = (EditText) inflatedView.findViewById(R.id.ring_password_repeat);
         mRingPin = (EditText) inflatedView.findViewById(R.id.ring_add_pin);
         mRingAddPassword = (EditText) inflatedView.findViewById(R.id.ring_add_password);
 
-        final Button ring_create_btn = (Button) inflatedView.findViewById(R.id.ring_create_btn);
-        final Button ring_add_btn = (Button) inflatedView.findViewById(R.id.ring_add_account);
+        final Button ringCreateBtn = (Button) inflatedView.findViewById(R.id.ring_create_btn);
+        final Button ringAddBtn = (Button) inflatedView.findViewById(R.id.ring_add_account);
 
-        /*mRingUsername.addTextChangedListener(new TextWatcher() {
-            @Override
-            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
-
-            @Override
-            public void onTextChanged(CharSequence name, int i, int i1, int i2) {
-                LocalService service = mCallbacks.getService();
-                if (service == null)
-                    return;
-                service.getNameDirectory().findAddr(name.toString(), new LocalService.NameRequest() {
-                    @Override
-                    public void onResult(String res, Object err) {
-                        Log.w(TAG, "mRingUsername onResult " + res + " " + err);
-                        if (err == null && res != null && !res.isEmpty()) {
-                            mRingUsername.setError("Username already taken");
-                        } else {
-                            mRingUsername.setError(null);
-                        }
-                    }
-                });
-            }
-
-            @Override
-            public void afterTextChanged(Editable editable) {}
-        });*/
         mRingPassword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
             @Override
             public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-                Log.w(TAG, "onEditorAction " + actionId + " " + (event == null ? null : event.toString()));
+                Log.d(TAG, "onEditorAction " + actionId + " " + (event == null ? null : event.toString()));
                 if (actionId == EditorInfo.IME_ACTION_NEXT)
                     return checkPassword(v, null);
                 return false;
@@ -186,17 +160,17 @@
                 if (!hasFocus) {
                     checkPassword((TextView) v, null);
                 } else {
-                    //alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+                    // nothing to be done here
                 }
             }
         });
         mRingPasswordRepeat.setOnEditorActionListener(new TextView.OnEditorActionListener() {
             @Override
             public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-                Log.w(TAG, "onEditorAction " + actionId + " " + (event == null ? null : event.toString()));
+                Log.d(TAG, "onEditorAction " + actionId + " " + (event == null ? null : event.toString()));
                 if (actionId == EditorInfo.IME_ACTION_DONE) {
                     if (mRingPassword.getText().length() != 0 && !checkPassword(mRingPassword, v)) {
-                        ring_create_btn.callOnClick();
+                        ringCreateBtn.callOnClick();
                         return true;
                     }
                 }
@@ -206,16 +180,16 @@
         mRingAddPassword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
             @Override
             public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-                Log.w(TAG, "onEditorAction " + actionId + " " + (event == null ? null : event.toString()));
+                Log.d(TAG, "onEditorAction " + actionId + " " + (event == null ? null : event.toString()));
                 if (actionId == EditorInfo.IME_ACTION_DONE) {
-                    ring_add_btn.callOnClick();
+                    ringAddBtn.callOnClick();
                     return true;
                 }
                 return false;
             }
         });
 
-        ring_create_btn.setOnClickListener(new View.OnClickListener() {
+        ringCreateBtn.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View view) {
                 if (mNewAccountLayout.getVisibility() == View.GONE) {
@@ -223,14 +197,13 @@
                 } else {
                     if (!checkPassword(mRingPassword, mRingPasswordRepeat)) {
                         mAccountType = AccountDetailBasic.ACCOUNT_TYPE_RING;
-                        //mAlias = mRingUsername.getText().toString();
                         mUsername = mAlias;
-                        initAccountCreation(/*mRingUsername.getText().toString()*/null, null, mRingPassword.getText().toString());
+                        initAccountCreation(null, null, mRingPassword.getText().toString());
                     }
                 }
             }
         });
-        ring_add_btn.setOnClickListener(new View.OnClickListener() {
+        ringAddBtn.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View view) {
                 if (mAddAccountLayout.getVisibility() == View.GONE) {
@@ -253,13 +226,7 @@
                 return true;
             }
         });
-        /*inflatedView.findViewById(R.id.ring_card_view).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mAccountType = AccountDetailBasic.ACCOUNT_TYPE_RING;
-                initAccountCreation();
-            }
-        });*/
+
         inflatedView.findViewById(R.id.create_sip_button).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View view) {
@@ -271,12 +238,6 @@
                 attemptCreation();
             }
         });
-        /*inflatedView.findViewById(R.id.import_card_view).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                startImport();
-            }
-        });*/
 
         mNewAccountLayout = (LinearLayout) inflatedView.findViewById(R.id.newAccountLayout);
         mAddAccountLayout = (LinearLayout) inflatedView.findViewById(R.id.addAccountLayout);
@@ -406,10 +367,11 @@
                 return cursor.getString(column_index);
             }
         } catch (Exception e) {
-            Log.w(TAG, "Can't find data column", e);
+            Log.e(TAG, "Can't find data column", e);
         } finally {
-            if (cursor != null)
+            if (cursor != null) {
                 cursor.close();
+            }
         }
         return null;
     }
@@ -484,12 +446,12 @@
                     // Technically the column stores an int, but cursor.getString()
                     // will do the conversion automatically.
                     size = cursor.getString(sizeIndex);
-                    Log.i(TAG, "Size: " + size);
+                    Log.d(TAG, "Size: " + size);
                     return cursor.getInt(sizeIndex);
                 } else {
                     size = "Unknown";
                 }
-                Log.i(TAG, "Size: " + size);
+                Log.d(TAG, "Size: " + size);
 
             }
         } finally {
@@ -500,7 +462,7 @@
 
     private void readFromUri(Uri uri, String outPath) throws IOException {
         if (getDocumentSize(uri) > 16 * 1024 * 1024) {
-            Toast.makeText(getActivity(), "File is too big", Toast.LENGTH_LONG).show();
+            Toast.makeText(getActivity(), R.string.account_creation_file_too_big, Toast.LENGTH_LONG).show();
             throw new IOException("File is too big");
         }
         copy(new InputStreamReader(getActivity().getContentResolver().openInputStream(uri)), new FileWriter(outPath));
@@ -520,11 +482,11 @@
                             showImportDialog();
                         } catch (IOException e) {
                             e.printStackTrace();
-                            Toast.makeText(getActivity(), "Can't read " + data.getData(), Toast.LENGTH_LONG).show();
+                            Toast.makeText(getActivity(), getContext().getString(R.string.account_cannot_read, data.getData()), Toast.LENGTH_LONG).show();
                         }
-                    }
-                    else
+                    } else {
                         showImportDialog();
+                    }
                 }
                 break;
         }
@@ -603,20 +565,22 @@
             try {
                 ret = mCallbacks.getRemoteService().importAccounts(args[0], args[1]);
             } catch (RemoteException e) {
-                e.printStackTrace();
+                Log.e(TAG, "Error while importing account", e);
             }
             return ret;
         }
 
         protected void onPostExecute(Integer ret) {
-            if (loading_dialog != null)
+            if (loading_dialog != null) {
                 loading_dialog.dismiss();
-            if (ret == 0)
+            }
+            if (ret == 0) {
                 getActivity().finish();
-            else
+            } else {
                 new AlertDialog.Builder(getActivity()).setTitle(R.string.import_failed_dialog_title)
                         .setMessage(R.string.import_failed_dialog_msg)
                         .setPositiveButton(android.R.string.ok, null).show();
+            }
         }
     }
 
@@ -709,7 +673,7 @@
     }
 
     @SuppressWarnings("unchecked")
-    private void initAccountCreation(String new_username, String pin, String password) {
+    private void initAccountCreation(String newUsername, String pin, String password) {
         try {
             HashMap<String, String> accountDetails = (HashMap<String, String>) mCallbacks.getRemoteService().getAccountTemplate(mAccountType);
             accountDetails.put(AccountDetailBasic.CONFIG_ACCOUNT_TYPE, mAccountType);
@@ -725,8 +689,9 @@
             if (mAccountType.equals(AccountDetailBasic.ACCOUNT_TYPE_RING)) {
                 accountDetails.put(AccountDetailBasic.CONFIG_ACCOUNT_ALIAS, "Ring");
                 accountDetails.put(AccountDetailBasic.CONFIG_ACCOUNT_HOSTNAME, "bootstrap.ring.cx");
-                if (password != null && !password.isEmpty())
+                if (password != null && !password.isEmpty()) {
                     accountDetails.put(AccountDetailBasic.CONFIG_ARCHIVE_PASSWORD, password);
+                }
                 if (pin != null && !pin.isEmpty()) {
                     accountDetails.put(AccountDetailBasic.CONFIG_ARCHIVE_PIN, pin);
                 }
@@ -742,8 +707,8 @@
             }
 
         } catch (RemoteException e) {
-            Toast.makeText(getActivity(), "Error creating account", Toast.LENGTH_SHORT).show();
-            e.printStackTrace();
+            Toast.makeText(getActivity(), R.string.account_creation_error, Toast.LENGTH_SHORT).show();
+            Log.d(TAG, "Error while creating account", e);
         }
 
     }
@@ -771,83 +736,13 @@
         return error;
     }
 
-    /*private AlertDialog showPasswordDialog() {
-        Activity ownerActivity = getActivity();
-
-        AlertDialog.Builder builder = new AlertDialog.Builder(ownerActivity);
-        LayoutInflater inflater = ownerActivity.getLayoutInflater();
-        ViewGroup v = (ViewGroup) inflater.inflate(R.layout.dialog_account_export, null);
-        final TextView pwd = (TextView) v.findViewById(R.id.newpwd_txt);
-        final TextView pwd_confirm = (TextView) v.findViewById(R.id.newpwd_confirm_txt);
-        builder.setMessage(R.string.account_export_message)
-                .setTitle(R.string.account_export_title)
-                .setPositiveButton(R.string.account_export, null)
-                .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int whichButton) {
-                    }
-                }).setView(v);
-
-
-        final AlertDialog alertDialog = builder.create();
-        pwd.setOnEditorActionListener(new TextView.OnEditorActionListener() {
-            @Override
-            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-                Log.w(TAG, "onEditorAction " + actionId + " " + (event == null ? null : event.toString()));
-                if (actionId == EditorInfo.IME_ACTION_NEXT)
-                    return checkPassword(v, null);
-                return false;
-            }
-        });
-        pwd.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                if (!hasFocus) {
-                    checkPassword((TextView) v, null);
-                } else {
-                    alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
-                }
-            }
-        });
-        pwd_confirm.setOnEditorActionListener(new TextView.OnEditorActionListener() {
-            @Override
-            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-                Log.w(TAG, "onEditorAction " + actionId + " " + (event == null ? null : event.toString()));
-                if (actionId == EditorInfo.IME_ACTION_DONE) {
-                    if (!checkPassword(pwd, v)) {
-                        alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).callOnClick();
-                        return true;
-                    }
-                }
-                return false;
-            }
-        });
-
-
-        alertDialog.setOwnerActivity(ownerActivity);
-        alertDialog.show();
-        alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                if (!checkPassword(pwd, pwd_confirm)) {
-                    final String pwd_txt = pwd.getText().toString();
-                    alertDialog.dismiss();
-                    initAccountCreation(pwd_txt);
-                }
-            }
-        });
-
-        return alertDialog;
-    }*/
-
-
     private class CreateAccountTask extends AsyncTask<HashMap<String, String>, Void, String> {
         private ProgressDialog progress = null;
         final private String username;
 
-        CreateAccountTask(String reg_username) {
-            Log.w(TAG, "CreateAccountTask ");
-            username = reg_username;
+        CreateAccountTask(String regUsername) {
+            Log.d(TAG, "CreateAccountTask ");
+            username = regUsername;
         }
 
         @Override
@@ -863,13 +758,13 @@
         @SafeVarargs
         @Override
         protected final String doInBackground(HashMap<String, String>... accs) {
-            final Account acc = mCallbacks.getService().createAccount(accs[0]);
-            acc.stateListener = new Account.OnStateChangedListener() {
+            final Account account = mCallbacks.getService().createAccount(accs[0]);
+            account.stateListener = new Account.OnStateChangedListener() {
                 @Override
                 public void stateChanged(String state, int code) {
-                    Log.w(TAG, "stateListener -> stateChanged " + state + " " + code);
+                    Log.d(TAG, "stateListener -> stateChanged " + state + " " + code);
                     if (!AccountDetailVolatile.STATE_INITIALIZING.contentEquals(state)) {
-                        acc.stateListener = null;
+                        account.stateListener = null;
                         if (progress != null) {
                             progress.dismiss();
                             progress = null;
@@ -884,17 +779,16 @@
                         boolean success = false;
                         switch (state) {
                             case AccountDetailVolatile.STATE_ERROR_GENERIC:
-                                dialog.setTitle("Can't find account")
-                                        .setMessage("Account couldn't be found on the Ring network." +
-                                                "\nMake sure it was exported on Ring from an existing device, and that provided credentials are correct.");
+                                dialog.setTitle(R.string.account_cannot_be_found_title)
+                                        .setMessage(R.string.account_cannot_be_found_message);
                                 break;
                             case AccountDetailVolatile.STATE_ERROR_NETWORK:
-                                dialog.setTitle("Can't connect to the network")
-                                        .setMessage("Could not add account because Ring coudn't connect to the distributed network. Check your device connectivity.");
+                                dialog.setTitle(R.string.account_no_network_title)
+                                        .setMessage(R.string.account_no_network_message);
                                 break;
                             default:
-                                dialog.setTitle("Account device added")
-                                        .setMessage("You have successfully setup your Ring account on this device.");
+                                dialog.setTitle(R.string.account_device_added_title)
+                                        .setMessage(R.string.account_device_added_message);
                                 success = true;
                                 break;
                         }
@@ -911,18 +805,19 @@
                     }
                 }
             };
-            Log.w(TAG, "Account created, registering " + username);
-            return acc.getAccountID();
+            Log.d(TAG, "Account created, registering " + username);
+            return account.getAccountID();
         }
     }
 
-    private void createNewAccount(HashMap<String, String> accountDetails, String register_name) {
-        if (creatingAccount)
+    private void createNewAccount(HashMap<String, String> accountDetails, String registerName) {
+        if (creatingAccount) {
             return;
+        }
         creatingAccount = true;
 
         //noinspection unchecked
-        new CreateAccountTask(register_name).execute(accountDetails);
+        new CreateAccountTask(registerName).execute(accountDetails);
     }
 
 }
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/AccountMigrationFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/AccountMigrationFragment.java
new file mode 100644
index 0000000..4dacca0
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/fragments/AccountMigrationFragment.java
@@ -0,0 +1,273 @@
+/*
+ *  Copyright (C) 2004-2016 Savoir-faire Linux Inc.
+ *
+ *  Author: Adrien Béraud <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
+ *  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.fragments;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.support.annotation.NonNull;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+import java.util.HashMap;
+
+import cx.ring.R;
+import cx.ring.model.account.Account;
+import cx.ring.model.account.AccountDetailBasic;
+import cx.ring.model.account.AccountDetailVolatile;
+import cx.ring.service.IDRingService;
+import cx.ring.service.LocalService;
+
+public class AccountMigrationFragment extends Fragment {
+    static final String TAG = AccountMigrationFragment.class.getSimpleName();
+
+    public static final String ACCOUNT_ID = "ACCOUNT_ID";
+
+    private String mAccountId;
+
+    // UI references.
+    private EditText mRingPassword;
+    private EditText mRingPasswordRepeat;
+
+    private LocalService.Callbacks mCallbacks = LocalService.DUMMY_CALLBACKS;
+    private boolean migratingAccount = false;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
+        final View inflatedView = inflater.inflate(R.layout.frag_account_migration, parent, false);
+
+        mRingPassword = (EditText) inflatedView.findViewById(R.id.ring_password);
+        mRingPasswordRepeat = (EditText) inflatedView.findViewById(R.id.ring_password_repeat);
+
+        final Button ringMigrateButton = (Button) inflatedView.findViewById(R.id.ring_migrate_btn);
+
+        mRingPassword.setOnEditorActionListener(new OnEditorActionListener() {
+            @Override
+            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+                Log.d(TAG, "onEditorAction " + actionId + " " + (event == null ? null : event.toString()));
+                return actionId == EditorInfo.IME_ACTION_NEXT && checkPassword(v, null);
+            }
+        });
+        mRingPassword.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                if (!hasFocus) {
+                    checkPassword((TextView) v, null);
+                }
+            }
+        });
+        mRingPasswordRepeat.setOnEditorActionListener(new OnEditorActionListener() {
+            @Override
+            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+                Log.d(TAG, "onEditorAction " + actionId + " " + (event == null ? null : event.toString()));
+                if (actionId == EditorInfo.IME_ACTION_DONE
+                        && mRingPassword.getText().length() != 0
+                        && !checkPassword(mRingPassword, v)) {
+                        ringMigrateButton.callOnClick();
+                        return true;
+                }
+                return false;
+            }
+        });
+
+        ringMigrateButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                if (!checkPassword(mRingPassword, mRingPasswordRepeat)) {
+                    initAccountMigration(mRingPassword.getText().toString());
+                }
+            }
+        });
+
+        return inflatedView;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        if (getArguments() != null) {
+            mAccountId = getArguments().getString(ACCOUNT_ID);
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        ((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(R.string.update_account);
+    }
+
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        if (!(activity instanceof LocalService.Callbacks)) {
+            throw new IllegalStateException("Activity must implement fragment's callbacks.");
+        }
+
+        mCallbacks = (LocalService.Callbacks) activity;
+    }
+
+    @SuppressWarnings("unchecked")
+    private void initAccountMigration(String password) {
+        if (migratingAccount) {
+            return;
+        }
+
+        migratingAccount = true;
+
+        new MigrateAccountTask(mAccountId, password).execute();
+    }
+
+    private boolean checkPassword(@NonNull TextView pwd, TextView confirm) {
+        boolean error = false;
+        if (pwd.getText().length() == 0) {
+            error = true;
+        } else {
+            if (pwd.getText().length() < 6) {
+                pwd.setError(getString(R.string.error_password_char_count));
+                pwd.requestFocus();
+                error = true;
+            } else {
+                pwd.setError(null);
+            }
+        }
+        if (confirm != null) {
+            if (!pwd.getText().toString().equals(confirm.getText().toString())) {
+                confirm.setError(getString(R.string.error_passwords_not_equals));
+                confirm.requestFocus();
+                error = true;
+            } else {
+                confirm.setError(null);
+            }
+        }
+        return error;
+    }
+
+    private class MigrateAccountTask extends AsyncTask<HashMap<String, String>, Void, String> {
+        private ProgressDialog progress = null;
+        private final String mAccountId;
+        private final String mPassword;
+
+        MigrateAccountTask(String accountId, String password) {
+            Log.d(TAG, "MigrateAccountTask");
+            mAccountId = accountId;
+            mPassword = password;
+        }
+
+        @Override
+        protected void onPreExecute() {
+            progress = new ProgressDialog(getActivity());
+            progress.setTitle(R.string.dialog_wait_update);
+            progress.setMessage(getString(R.string.dialog_wait_update_details));
+            progress.setCancelable(false);
+            progress.setCanceledOnTouchOutside(false);
+            progress.show();
+        }
+
+        @SafeVarargs
+        @Override
+        protected final String doInBackground(HashMap<String, String>... accs) {
+
+            final Account account = mCallbacks.getService().getAccount(mAccountId);
+            final IDRingService remote = mCallbacks.getService().getRemoteService();
+            if (account == null || remote == null) {
+                Log.e(TAG, "Error updating account, no account or remote service");
+                return null;
+            }
+
+            account.stateListener = new Account.OnStateChangedListener() {
+                @Override
+                public void stateChanged(String state, int code) {
+                    Log.d(TAG, "stateListener -> stateChanged " + state + " " + code);
+                    if (!AccountDetailVolatile.STATE_INITIALIZING.contentEquals(state)) {
+                        if (progress != null) {
+                            progress.dismiss();
+                            progress = null;
+                        }
+                        AlertDialog.Builder dialogBuilder = new android.support.v7.app.AlertDialog.Builder(getActivity());
+                        dialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog, int id) {
+                                //do things
+                            }
+                        });
+                        boolean success = false;
+                        switch (state) {
+                            case AccountDetailVolatile.STATE_ERROR_GENERIC:
+                                dialogBuilder.setTitle(R.string.account_cannot_be_found_title)
+                                        .setMessage(R.string.account_cannot_be_found_message);
+                                break;
+                            case AccountDetailVolatile.STATE_ERROR_NETWORK:
+                                dialogBuilder.setTitle(R.string.account_no_network_title)
+                                        .setMessage(R.string.account_no_network_message);
+                                break;
+                            default:
+                                dialogBuilder.setTitle(R.string.account_device_updated_title)
+                                        .setMessage(R.string.account_device_updated_message);
+                                success = true;
+                                account.stateListener = null;
+                                break;
+                        }
+                        AlertDialog dialogSuccess = dialogBuilder.show();
+                        if (success) {
+                            dialogSuccess.setOnDismissListener(new DialogInterface.OnDismissListener() {
+                                @Override
+                                public void onDismiss(DialogInterface dialogInterface) {
+                                    getActivity().setResult(Activity.RESULT_OK, new Intent());
+                                    getActivity().finish();
+                                }
+                            });
+                        }
+                    }
+                }
+            };
+
+            HashMap<String, String> details = account.getDetails();
+            details.put(AccountDetailBasic.CONFIG_ARCHIVE_PASSWORD, mPassword);
+
+            try {
+                remote.setAccountDetails(account.getAccountID(), details);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error while setting ARCHIVE_PASSWORD", e);
+            }
+
+            return account.getAccountID();
+        }
+    }
+}
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/AccountsManagementFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/AccountsManagementFragment.java
index 4fd1a0e..d323620 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/AccountsManagementFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/AccountsManagementFragment.java
@@ -34,10 +34,20 @@
 import android.os.RemoteException;
 import android.support.design.widget.FloatingActionButton;
 import android.util.Log;
-import android.view.*;
+import android.view.LayoutInflater;
+import android.view.View;
 import android.view.View.OnClickListener;
-import android.widget.*;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
+import android.widget.BaseAdapter;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
 
 import cx.ring.R;
 import cx.ring.client.AccountEditionActivity;
@@ -48,9 +58,6 @@
 import cx.ring.service.LocalService;
 import cx.ring.views.dragsortlv.DragSortListView;
 
-import java.util.ArrayList;
-import java.util.List;
-
 public class AccountsManagementFragment extends Fragment implements HomeActivity.Refreshable {
     static final String TAG = AccountsManagementFragment.class.getSimpleName();
 
@@ -124,7 +131,12 @@
 
             @Override
             public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long arg3) {
-                launchAccountEditActivity(mAccountsAdapter.getItem(pos));
+                Account selectedAccount = mAccountsAdapter.getItem(pos);
+                if (selectedAccount.needsMigration()) {
+                    launchAccountMigrationActivity(mAccountsAdapter.getItem(pos));
+                } else {
+                    launchAccountEditActivity(mAccountsAdapter.getItem(pos));
+                }
             }
         });
     }
@@ -150,7 +162,7 @@
     }
 
     private void launchAccountEditActivity(Account acc) {
-        Log.i(TAG, "Launch account edit activity");
+        Log.d(TAG, "Launch account edit activity");
 
         Intent intent = new Intent()
                 .setClass(getActivity(), AccountEditionActivity.class)
@@ -159,6 +171,15 @@
         startActivityForResult(intent, ACCOUNT_EDIT_REQUEST);
     }
 
+    private void launchAccountMigrationActivity(Account acc) {
+        Log.d(TAG, "Launch account migration activity");
+
+        Intent intent = new Intent()
+                .setClass(getActivity(), AccountWizard.class)
+                .setData(Uri.withAppendedPath(AccountEditionActivity.CONTENT_URI, acc.getAccountID()));
+        startActivityForResult(intent, ACCOUNT_EDIT_REQUEST);
+    }
+
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
@@ -225,12 +246,12 @@
                 entryView.handle = (ImageView) rowView.findViewById(R.id.drag_handle);
                 entryView.alias = (TextView) rowView.findViewById(R.id.account_alias);
                 entryView.host = (TextView) rowView.findViewById(R.id.account_host);
-                entryView.loading_indicator = rowView.findViewById(R.id.loading_indicator);
-                entryView.error_indicator = (ImageView) rowView.findViewById(R.id.error_indicator);
+                entryView.loadingIndicator = rowView.findViewById(R.id.loading_indicator);
+                entryView.errorIndicator = (ImageView) rowView.findViewById(R.id.error_indicator);
                 entryView.enabled = (CheckBox) rowView.findViewById(R.id.account_checked);
-                entryView.error_indicator.setColorFilter(mContext.getResources().getColor(R.color.error_red));
-                entryView.error_indicator.setVisibility(View.GONE);
-                entryView.loading_indicator.setVisibility(View.GONE);
+                entryView.errorIndicator.setColorFilter(mContext.getResources().getColor(R.color.error_red));
+                entryView.errorIndicator.setVisibility(View.GONE);
+                entryView.loadingIndicator.setVisibility(View.GONE);
                 rowView.setTag(entryView);
             } else {
                 entryView = (AccountView) rowView.getTag();
@@ -238,13 +259,15 @@
 
             final Account item = accounts.get(pos);
             entryView.alias.setText(item.getAlias());
+            entryView.host.setTextColor(getResources().getColor(R.color.text_color_secondary));
 
-            if (item.isIP2IP())
+            if (item.isIP2IP()) {
                 entryView.host.setText(item.getRegistrationState());
-            else if (item.isSip())
+            } else if (item.isSip()) {
                 entryView.host.setText(item.getHost() + " - " + item.getRegistrationState());
-            else
+            } else {
                 entryView.host.setText(item.getBasicDetails().getDetailString(AccountDetailBasic.CONFIG_ACCOUNT_USERNAME));
+            }
 
             entryView.enabled.setChecked(item.isEnabled());
             entryView.enabled.setOnClickListener(new OnClickListener() {
@@ -255,7 +278,7 @@
                     try {
                         mCallbacks.getService().getRemoteService().setAccountDetails(item.getAccountID(), item.getDetails());
                     } catch (RemoteException e) {
-                        e.printStackTrace();
+                        Log.e(TAG, "Error while getting Account details", e);
                     }
                 }
             });
@@ -263,25 +286,31 @@
 
             if (item.isEnabled()) {
                 if (item.isTrying()) {
-                    entryView.error_indicator.setVisibility(View.GONE);
-                    entryView.loading_indicator.setVisibility(View.VISIBLE);
+                    entryView.errorIndicator.setVisibility(View.GONE);
+                    entryView.loadingIndicator.setVisibility(View.VISIBLE);
+                } else if (item.needsMigration()) {
+                    entryView.host.setText(R.string.account_update_needed);
+                    entryView.host.setTextColor(Color.RED);
+                    entryView.errorIndicator.setImageResource(R.drawable.ic_warning);
+                    entryView.errorIndicator.setColorFilter(Color.RED);
+                    entryView.errorIndicator.setVisibility(View.VISIBLE);
                 } else if (item.isInError()) {
-                    entryView.error_indicator.setImageResource(R.drawable.ic_error_white_24dp);
-                    entryView.error_indicator.setColorFilter(Color.RED);
-                    entryView.error_indicator.setVisibility(View.VISIBLE);
-                    entryView.loading_indicator.setVisibility(View.GONE);
+                    entryView.errorIndicator.setImageResource(R.drawable.ic_error_white_24dp);
+                    entryView.errorIndicator.setColorFilter(Color.RED);
+                    entryView.errorIndicator.setVisibility(View.VISIBLE);
+                    entryView.loadingIndicator.setVisibility(View.GONE);
                 } else if (!item.isRegistered()) {
-                    entryView.error_indicator.setImageResource(R.drawable.ic_network_disconnect_black_24dp);
-                    entryView.error_indicator.setColorFilter(Color.BLACK);
-                    entryView.error_indicator.setVisibility(View.VISIBLE);
-                    entryView.loading_indicator.setVisibility(View.GONE);
+                    entryView.errorIndicator.setImageResource(R.drawable.ic_network_disconnect_black_24dp);
+                    entryView.errorIndicator.setColorFilter(Color.BLACK);
+                    entryView.errorIndicator.setVisibility(View.VISIBLE);
+                    entryView.loadingIndicator.setVisibility(View.GONE);
                 } else {
-                    entryView.error_indicator.setVisibility(View.GONE);
-                    entryView.loading_indicator.setVisibility(View.GONE);
+                    entryView.errorIndicator.setVisibility(View.GONE);
+                    entryView.loadingIndicator.setVisibility(View.GONE);
                 }
             } else {
-                entryView.error_indicator.setVisibility(View.GONE);
-                entryView.loading_indicator.setVisibility(View.GONE);
+                entryView.errorIndicator.setVisibility(View.GONE);
+                entryView.loadingIndicator.setVisibility(View.GONE);
             }
 
             return rowView;
@@ -296,13 +325,13 @@
             public ImageView handle;
             public TextView alias;
             public TextView host;
-            public View loading_indicator;
-            public ImageView error_indicator;
+            public View loadingIndicator;
+            public ImageView errorIndicator;
             public CheckBox enabled;
         }
 
         public void replaceAll(List<Account> results) {
-            Log.i(TAG, "AccountsAdapter replaceAll " + results.size());
+            Log.d(TAG, "AccountsAdapter replaceAll " + results.size());
             accounts.clear();
             accounts.addAll(results);
             notifyDataSetChanged();
@@ -310,8 +339,9 @@
 
         private List<String> getAccountOrder() {
             ArrayList<String> order = new ArrayList<>(accounts.size());
-            for (Account acc : accounts)
+            for (Account acc : accounts) {
                 order.add(acc.getAccountID());
+            }
             return order;
         }
 
@@ -329,8 +359,9 @@
     public void refresh() {
         LocalService service = mCallbacks.getService();
         View v = getView();
-        if (service == null || v == null)
+        if (service == null || v == null) {
             return;
+        }
         mAccountsAdapter.replaceAll(service.getAccounts());
         if (mAccountsAdapter.isEmpty()) {
             mDnDListView.setEmptyView(v.findViewById(R.id.empty_account_list));
diff --git a/ring-android/app/src/main/java/cx/ring/model/account/Account.java b/ring-android/app/src/main/java/cx/ring/model/account/Account.java
index fba2ee5..d722e00 100644
--- a/ring-android/app/src/main/java/cx/ring/model/account/Account.java
+++ b/ring-android/app/src/main/java/cx/ring/model/account/Account.java
@@ -30,7 +30,7 @@
 import java.util.Map;
 
 public class Account extends java.util.Observable {
-    private static final String TAG = "Account";
+    private static final String TAG = Account.class.getName();
 
     private final String accountID;
     private AccountDetailBasic basicDetails = null;
@@ -58,8 +58,9 @@
         advancedDetails = new AccountDetailAdvanced(details);
         srtpDetails = new AccountDetailSrtp(details);
         tlsDetails = new AccountDetailTls(details);
-        if (volatile_details != null)
+        if (volatile_details != null) {
             volatileDetails = new AccountDetailVolatile(volatile_details);
+        }
         setCredentials(credentials);
     }
 
@@ -97,9 +98,11 @@
     public interface OnDevicesChangedListener {
         void devicesChanged(Map<String, String> devices);
     }
+
     public interface OnExportEndedListener {
         void exportEnded(int code, String pin);
     }
+
     public interface OnStateChangedListener {
         void stateChanged(String state, int code);
     }
@@ -133,15 +136,17 @@
     public String getRegistrationState() {
         return volatileDetails.getDetailString(AccountDetailVolatile.CONFIG_ACCOUNT_REGISTRATION_STATUS);
     }
+
     public int getRegistrationStateCode() {
-        String code_str = volatileDetails.getDetailString(AccountDetailVolatile.CONFIG_ACCOUNT_REGISTRATION_STATE_CODE);
-        if (code_str == null || code_str.isEmpty())
+        String codeStr = volatileDetails.getDetailString(AccountDetailVolatile.CONFIG_ACCOUNT_REGISTRATION_STATE_CODE);
+        if (codeStr == null || codeStr.isEmpty()) {
             return 0;
-        return Integer.parseInt(code_str);
+        }
+        return Integer.parseInt(codeStr);
     }
 
     public void setRegistrationState(String registered_state, int code) {
-        Log.i(TAG, "setRegistrationState " + registered_state + " " + code);
+        Log.d(TAG, "setRegistrationState " + registered_state + " " + code);
         String old = getRegistrationState();
         volatileDetails.setDetailString(AccountDetailVolatile.CONFIG_ACCOUNT_REGISTRATION_STATUS, registered_state);
         volatileDetails.setDetailString(AccountDetailVolatile.CONFIG_ACCOUNT_REGISTRATION_STATE_CODE, Integer.toString(code));
@@ -179,6 +184,12 @@
         basicDetails.setDetailString(AccountDetailBasic.CONFIG_ACCOUNT_ALIAS, alias);
     }
 
+    public void setPassword(String password) {
+        Map<String, String> details = basicDetails.getDetailsHashMap();
+        details.put(AccountDetailBasic.CONFIG_ACCOUNT_PASSWORD, password);
+        setBasicDetails(details);
+    }
+
     public AccountDetailBasic getBasicDetails() {
         return basicDetails;
     }
@@ -294,13 +305,17 @@
     }
 
     public String getShareURI() {
-        String share_uri;
+        String shareUri;
         if (isRing()) {
-            share_uri = getBasicDetails().getUsername();
+            shareUri = getBasicDetails().getUsername();
         } else {
-            share_uri = getBasicDetails().getUsername() + "@" + getBasicDetails().getHostname();
+            shareUri = getBasicDetails().getUsername() + "@" + getBasicDetails().getHostname();
         }
 
-        return share_uri;
+        return shareUri;
+    }
+
+    public boolean needsMigration() {
+        return getRegistrationState().contentEquals(AccountDetailVolatile.STATE_NEED_MIGRATION);
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailVolatile.java b/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailVolatile.java
index 26718e4..a91a67e 100644
--- a/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailVolatile.java
+++ b/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailVolatile.java
@@ -1,23 +1,23 @@
 /**
  * Copyright (C) 2004-2016 Savoir-faire Linux Inc.
- *
- *  Author: Alexandre Savard <alexandre.savard@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.
- *  If you own a pjsip commercial license you can also redistribute it
- *  and/or modify it under the terms of the GNU Lesser General Public License
- *  as an android library.
- *
- *  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, see <http://www.gnu.org/licenses/>.
+ * <p>
+ * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ * <p>
+ * 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.
+ * If you own a pjsip commercial license you can also redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public License
+ * as an android library.
+ * <p>
+ * 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.
+ * <p>
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 package cx.ring.model.account;
 
@@ -35,32 +35,34 @@
     public static final String CONFIG_ACCOUNT_REGISTRATION_STATE_CODE = "Account.registrationCode";
     public static final String CONFIG_ACCOUNT_REGISTRATION_STATE_DESC = "Account.registrationDescription";
 
-    public static final String STATE_REGISTERED                 = "REGISTERED";
-    public static final String STATE_READY                      = "READY";
-    public static final String STATE_UNREGISTERED               = "UNREGISTERED";
-    public static final String STATE_TRYING                     = "TRYING";
-    public static final String STATE_ERROR                      = "ERROR";
-    public static final String STATE_ERROR_GENERIC              = "ERROR_GENERIC";
-    public static final String STATE_ERROR_AUTH                 = "ERROR_AUTH";
-    public static final String STATE_ERROR_NETWORK              = "ERROR_NETWORK";
-    public static final String STATE_ERROR_HOST                 = "ERROR_HOST";
-    public static final String STATE_ERROR_CONF_STUN            = "ERROR_CONF_STUN";
-    public static final String STATE_ERROR_EXIST_STUN           = "ERROR_EXIST_STUN";
-    public static final String STATE_ERROR_SERVICE_UNAVAILABLE  = "ERROR_SERVICE_UNAVAILABLE";
-    public static final String STATE_ERROR_NOT_ACCEPTABLE       = "ERROR_NOT_ACCEPTABLE";
-    public static final String STATE_REQUEST_TIMEOUT            = "Request Timeout";
-    public static final String STATE_INITIALIZING               = "INITIALIZING";
+    public static final String STATE_REGISTERED = "REGISTERED";
+    public static final String STATE_READY = "READY";
+    public static final String STATE_UNREGISTERED = "UNREGISTERED";
+    public static final String STATE_TRYING = "TRYING";
+    public static final String STATE_ERROR = "ERROR";
+    public static final String STATE_ERROR_GENERIC = "ERROR_GENERIC";
+    public static final String STATE_ERROR_AUTH = "ERROR_AUTH";
+    public static final String STATE_ERROR_NETWORK = "ERROR_NETWORK";
+    public static final String STATE_ERROR_HOST = "ERROR_HOST";
+    public static final String STATE_ERROR_CONF_STUN = "ERROR_CONF_STUN";
+    public static final String STATE_ERROR_EXIST_STUN = "ERROR_EXIST_STUN";
+    public static final String STATE_ERROR_SERVICE_UNAVAILABLE = "ERROR_SERVICE_UNAVAILABLE";
+    public static final String STATE_ERROR_NOT_ACCEPTABLE = "ERROR_NOT_ACCEPTABLE";
+    public static final String STATE_REQUEST_TIMEOUT = "Request Timeout";
+    public static final String STATE_INITIALIZING = "INITIALIZING";
+    public static final String STATE_NEED_MIGRATION = "ERROR_NEED_MIGRATION";
 
     private final ArrayList<PreferenceEntry> privateArray = new ArrayList<>();
 
     public AccountDetailVolatile() {
     }
+
     public AccountDetailVolatile(Map<String, String> pref) {
         for (String key : pref.keySet()) {
-            PreferenceEntry p = new PreferenceEntry(key);
-            p.mValue = pref.get(key);
+            PreferenceEntry preferenceEntry = new PreferenceEntry(key);
+            preferenceEntry.mValue = pref.get(key);
 
-            privateArray.add(p);
+            privateArray.add(preferenceEntry);
         }
     }
 
@@ -71,9 +73,9 @@
     public ArrayList<String> getValuesOnly() {
         ArrayList<String> valueList = new ArrayList<>();
 
-        for (PreferenceEntry p : privateArray) {
-            Log.i(TAG, "" + p.mValue);
-            valueList.add(p.mValue);
+        for (PreferenceEntry preferenceEntry : privateArray) {
+            Log.d(TAG, "" + preferenceEntry.mValue);
+            valueList.add(preferenceEntry.mValue);
         }
 
         return valueList;
@@ -82,8 +84,8 @@
     public HashMap<String, String> getDetailsHashMap() {
         HashMap<String, String> map = new HashMap<>();
 
-        for (PreferenceEntry p : privateArray) {
-            map.put(p.mKey, p.mValue);
+        for (PreferenceEntry preferenceEntry : privateArray) {
+            map.put(preferenceEntry.mKey, preferenceEntry.mValue);
         }
 
         return map;
@@ -92,9 +94,9 @@
     public String getDetailString(String key) {
         String value = "";
 
-        for (PreferenceEntry p : privateArray) {
-            if (p.mKey.equals(key)) {
-                value = p.mValue;
+        for (PreferenceEntry preferenceEntry : privateArray) {
+            if (preferenceEntry.mKey.equals(key)) {
+                value = preferenceEntry.mValue;
                 return value;
             }
         }
@@ -102,9 +104,9 @@
     }
 
     public void setDetailString(String key, String newValue) {
-        for (PreferenceEntry p : privateArray) {
-            if (p.mKey.equals(key)) {
-                p.mValue = newValue;
+        for (PreferenceEntry preferenceEntry : privateArray) {
+            if (preferenceEntry.mKey.equals(key)) {
+                preferenceEntry.mValue = newValue;
             }
         }
 
diff --git a/ring-android/app/src/main/res/layout/activity_wizard.xml b/ring-android/app/src/main/res/layout/activity_wizard.xml
index e4dc955..37d0c24 100644
--- a/ring-android/app/src/main/res/layout/activity_wizard.xml
+++ b/ring-android/app/src/main/res/layout/activity_wizard.xml
@@ -1,4 +1,4 @@
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -8,9 +8,6 @@
         android:id="@+id/main_toolbar"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_alignParentStart="true"
-        android:layout_alignParentTop="true"
         android:background="@color/color_primary_light"
         android:elevation="4dp"
         android:minHeight="?attr/actionBarSize"
@@ -24,7 +21,6 @@
     <android.support.v4.view.ViewPager
         android:id="@+id/pager"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_below="@id/main_toolbar" />
+        android:layout_height="match_parent" />
 
-</RelativeLayout>
\ No newline at end of file
+</LinearLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/frag_account_migration.xml b/ring-android/app/src/main/res/layout/frag_account_migration.xml
new file mode 100644
index 0000000..c4fd7d0
--- /dev/null
+++ b/ring-android/app/src/main/res/layout/frag_account_migration.xml
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+Copyright (C) 2004-2016 Savoir-faire Linux Inc.
+
+Authors:    Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+            Romain Bertozzi <romain.bertozzi@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.
+-->
+<ScrollView 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:id="@+id/login_form"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="#eeeeee"
+    tools:context=".client.AccountWizard">
+
+    <cx.ring.views.BoundedLinearLayout
+        style="@style/AccountFormContainer"
+        android:layout_gravity="center_horizontal"
+        android:animateLayoutChanges="false"
+        android:descendantFocusability="beforeDescendants"
+        android:focusableInTouchMode="true"
+        android:orientation="vertical"
+        app:bounded_width="320dp">
+
+        <android.support.v7.widget.CardView
+            android:id="@+id/ring_card_view"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            android:animateLayoutChanges="false">
+
+            <RelativeLayout
+                android:id="@+id/ring_fields"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:animateLayoutChanges="true"
+                android:orientation="vertical">
+
+                <ImageView
+                    android:id="@+id/imageView6"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignParentEnd="true"
+                    android:layout_alignParentRight="true"
+                    android:layout_alignParentTop="true"
+                    android:layout_margin="16dp"
+                    android:contentDescription="@string/app_name"
+                    android:src="@drawable/ring_logo_48dp" />
+
+                <TextView
+                    android:id="@+id/ring_acc_title_txt"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_alignParentLeft="true"
+                    android:layout_alignParentStart="true"
+                    android:layout_alignParentTop="true"
+                    android:layout_toLeftOf="@+id/imageView6"
+                    android:layout_toStartOf="@+id/imageView6"
+                    android:paddingLeft="16dp"
+                    android:paddingRight="16dp"
+                    android:paddingTop="24dp"
+                    android:text="@string/ring_account"
+                    android:textColor="@color/text_color_primary"
+                    android:textSize="24sp" />
+
+                <TextView
+                    android:id="@+id/textView"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_alignParentLeft="true"
+                    android:layout_alignParentStart="true"
+                    android:layout_below="@+id/ring_acc_title_txt"
+                    android:paddingBottom="24dp"
+                    android:paddingLeft="16dp"
+                    android:paddingRight="16dp"
+                    android:paddingTop="16dp"
+                    android:text="@string/account_migration"
+                    android:textColor="@color/text_color_primary"
+                    android:textSize="14sp" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_below="@id/textView"
+                    android:background="@color/color_primary_light"
+                    android:orientation="vertical">
+
+                    <LinearLayout
+                        android:id="@+id/newAccountLayout"
+                        android:layout_width="match_parent"
+                        android:layout_height="match_parent"
+                        android:background="@color/color_primary_light"
+                        android:orientation="vertical">
+
+                        <EditText
+                            android:id="@+id/ring_password"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_marginBottom="8dp"
+                            android:layout_marginLeft="12dp"
+                            android:layout_marginRight="12dp"
+                            android:hint="@string/prompt_new_password"
+                            android:imeOptions="actionNext"
+                            android:inputType="textPassword" />
+
+                        <EditText
+                            android:id="@+id/ring_password_repeat"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_marginBottom="8dp"
+                            android:layout_marginLeft="12dp"
+                            android:layout_marginRight="12dp"
+                            android:hint="@string/prompt_new_password_repeat"
+                            android:imeActionId="@integer/register_sip_account_actionid"
+                            android:imeActionLabel="update"
+                            android:inputType="textPassword" />
+                    </LinearLayout>
+
+                    <Button
+                        android:id="@+id/ring_migrate_btn"
+                        style="?attr/borderlessButtonStyle"
+                        android:layout_width="match_parent"
+                        android:layout_height="0dp"
+                        android:layout_weight="1"
+                        android:background="?android:attr/selectableItemBackground"
+                        android:text="@string/update_account"
+                        android:textColor="@color/text_color_primary_dark" />
+                </LinearLayout>
+
+            </RelativeLayout>
+
+        </android.support.v7.widget.CardView>
+
+    </cx.ring.views.BoundedLinearLayout>
+
+</ScrollView>
diff --git a/ring-android/app/src/main/res/values/strings.xml b/ring-android/app/src/main/res/values/strings.xml
index e762524..9149e88 100644
--- a/ring-android/app/src/main/res/values/strings.xml
+++ b/ring-android/app/src/main/res/values/strings.xml
@@ -166,5 +166,6 @@
     <string name="add_call_contact_number_to_contacts">Add %1$s ?</string>
     <string name="prompt_new_password">New password</string>
     <string name="prompt_new_password_repeat">Repeat new password</string>
+    <string name="account_device_updated_message">You have successfully updated your Ring account.</string>
 
 </resources>
diff --git a/ring-android/app/src/main/res/values/strings_account.xml b/ring-android/app/src/main/res/values/strings_account.xml
index 6231b6f..bc587f6 100644
--- a/ring-android/app/src/main/res/values/strings_account.xml
+++ b/ring-android/app/src/main/res/values/strings_account.xml
@@ -30,6 +30,8 @@
     <string name="error_field_required">This field is required</string>
     <string name="dialog_wait_create">Adding account</string>
     <string name="dialog_wait_create_details">Please wait while your new account is added…</string>
+    <string name="dialog_wait_update">Updating account</string>
+    <string name="dialog_wait_update_details">Please wait while your new account is updated…</string>
 
     <string name="dialog_warn_ip2ip_account_title">Create empty SIP account ?</string>
     <string name="dialog_warn_ip2ip_account_message">You are about to create a SIP account with no valid hostname.
@@ -168,6 +170,21 @@
     <string name="account_enter_password">Enter password</string>
     <string name="account_share_body">Contact me using %1$s on the Ring distributed communication platform: http://ring.cx</string>
     <string name="account_contact_me">Contact me on Ring !</string>
-
+    <string name="update_account">Update account</string>
+    <string name="account_migration">Your Ring account can now be shared between all your devices. All you need to do is provide a password.</string>
+    <string name="ring_account">Ring account</string>
+    <string name="account_migration_title_dialog">Account migration</string>
+    <string name="account_migration_message_dialog">In order to be usable on multiple devices, your accounts need to be updated. Do you want to go the Account management screen to perform this operation ?</string>
+    <string name="account_update_needed">Update needed</string>
+    <string name="account_creation_file_too_big">File is too big</string>
+    <string name="account_cannot_read">Can\'t read %1$s</string>
+    <string name="account_creation_error">Error creating account</string>
+    <string name="account_cannot_be_found_title">Can\'t find account</string>
+    <string name="account_cannot_be_found_message">Account couldn\'t be found on the Ring network.\nMake sure it was exported on Ring from an existing device, and that provided credentials are correct.</string>
+    <string name="account_no_network_title">Can\'t connect to the network</string>
+    <string name="account_no_network_message">Could not add account because Ring coudn\'t connect to the distributed network. Check your device connectivity.</string>
+    <string name="account_device_added_title">Account device added</string>
+    <string name="account_device_added_message">You have successfully setup your Ring account on this device.</string>
+    <string name="account_device_updated_title">Account device updated</string>
 
 </resources>