Quellcode durchsuchen

Simple signup

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>

cleanup

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
tobiasKaminsky vor 6 Jahren
Ursprung
Commit
eae43cf464
31 geänderte Dateien mit 3290 neuen und 2791 gelöschten Zeilen
  1. 1 0
      build.gradle
  2. 56 0
      drawable_resources/first_run_files.svg
  3. 56 0
      drawable_resources/first_run_groupware.svg
  4. 66 0
      drawable_resources/first_run_talk.svg
  5. 4 0
      src/main/AndroidManifest.xml
  6. 5 0
      src/main/java/com/owncloud/android/MainApp.java
  7. 2307 2288
      src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java
  8. 115 0
      src/main/java/com/owncloud/android/features/FeatureItem.java
  9. 0 194
      src/main/java/com/owncloud/android/features/FeatureList.java
  10. 1 1
      src/main/java/com/owncloud/android/ui/activity/BaseActivity.java
  11. 3 1
      src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java
  12. 228 0
      src/main/java/com/owncloud/android/ui/activity/FirstRunActivity.java
  13. 10 3
      src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java
  14. 30 232
      src/main/java/com/owncloud/android/ui/activity/WhatsNewActivity.java
  15. 2 2
      src/main/java/com/owncloud/android/ui/adapter/AccountListAdapter.java
  16. 28 0
      src/main/java/com/owncloud/android/ui/adapter/FeaturesViewAdapter.java
  17. 26 0
      src/main/java/com/owncloud/android/ui/adapter/FeaturesWebViewAdapter.java
  18. 119 0
      src/main/java/com/owncloud/android/ui/fragment/FeatureFragment.java
  19. 49 0
      src/main/java/com/owncloud/android/ui/fragment/FeatureWebFragment.java
  20. 1 2
      src/main/java/com/owncloud/android/ui/whatsnew/ProgressIndicator.java
  21. 8 0
      src/main/java/com/owncloud/android/utils/DisplayUtils.java
  22. 11 0
      src/main/res/drawable/first_run_files.xml
  23. 11 0
      src/main/res/drawable/first_run_groupware.xml
  24. 16 0
      src/main/res/drawable/first_run_talk.xml
  25. 0 20
      src/main/res/layout-land/account_setup.xml
  26. 0 19
      src/main/res/layout/account_setup.xml
  27. 100 0
      src/main/res/layout/first_run_activity.xml
  28. 4 2
      src/main/res/layout/whats_new_activity.xml
  29. 24 24
      src/main/res/layout/whats_new_element.xml
  30. 2 2
      src/main/res/values/setup.xml
  31. 7 1
      src/main/res/values/strings.xml

+ 1 - 0
build.gradle

@@ -91,6 +91,7 @@ android {
         testInstrumentationRunnerArgument "TEST_SERVER_URL", "\"$System.env.OCTEST_SERVER_BASE_URL\""
 
         multiDexEnabled true
+        vectorDrawables.useSupportLibrary = true
 
         versionCode versionMajor * 10000000 + versionMinor * 10000 + versionPatch * 100 + versionBuild
 

+ 56 - 0
drawable_resources/first_run_files.svg

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+    xmlns:dc="http://purl.org/dc/elements/1.1/"
+    xmlns:cc="http://creativecommons.org/ns#"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns="http://www.w3.org/2000/svg"
+    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+    height="16"
+    viewBox="0 0 16 16"
+    width="16"
+    version="1.1"
+    id="svg4"
+    sodipodi:docname="first_run_files.svg"
+    inkscape:version="0.92.2 2405546, 2018-03-11">
+    <metadata
+        id="metadata10">
+        <rdf:RDF>
+            <cc:Work
+                rdf:about="">
+                <dc:format>image/svg+xml</dc:format>
+                <dc:type
+                    rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+                <dc:title></dc:title>
+            </cc:Work>
+        </rdf:RDF>
+    </metadata>
+    <defs
+        id="defs8"/>
+    <sodipodi:namedview
+        pagecolor="#ffffff"
+        bordercolor="#666666"
+        borderopacity="1"
+        objecttolerance="10"
+        gridtolerance="10"
+        guidetolerance="10"
+        inkscape:pageopacity="0"
+        inkscape:pageshadow="2"
+        inkscape:window-width="1600"
+        inkscape:window-height="835"
+        id="namedview6"
+        showgrid="false"
+        inkscape:pagecheckerboard="true"
+        inkscape:zoom="14.75"
+        inkscape:cx="-3.8305085"
+        inkscape:cy="8"
+        inkscape:window-x="0"
+        inkscape:window-y="0"
+        inkscape:window-maximized="1"
+        inkscape:current-layer="svg4"/>
+    <path
+        fill="#0082c9"
+        d="m1.5 2c-0.25 0-0.5 0.25-0.5 0.5v11c0 0.26 0.24 0.5 0.5 0.5h13c0.26 0 0.5-0.241 0.5-0.5v-9c0-0.25-0.25-0.5-0.5-0.5h-6.5l-2-2h-4.5zm8.75 3.5a1.25 1.25 0 0 1 1.25 1.25 1.25 1.25 0 0 1 -1.25 1.25 1.25 1.25 0 0 1 -0.8008 -0.291l-2.4512 1.2265a1.25 1.25 0 0 1 0.002 0.0645 1.25 1.25 0 0 1 -0.0039 0.0645l2.4531 1.2265a1.25 1.25 0 0 1 0.8008 -0.291 1.25 1.25 0 0 1 1.25 1.25 1.25 1.25 0 0 1 -1.25 1.25 1.25 1.25 0 0 1 -1.25 -1.25 1.25 1.25 0 0 1 0.0039 -0.064l-2.4531-1.227a1.25 1.25 0 0 1 -0.8008 0.291 1.25 1.25 0 0 1 -1.25 -1.25 1.25 1.25 0 0 1 1.25 -1.25 1.25 1.25 0 0 1 0.8008 0.291l2.4512-1.2265a1.25 1.25 0 0 1 -0.002 -0.0645 1.25 1.25 0 0 1 1.25 -1.25z"
+        id="path2"
+        style="fill:#ffffff;fill-opacity:1"/>
+</svg>

+ 56 - 0
drawable_resources/first_run_groupware.svg

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+    xmlns:dc="http://purl.org/dc/elements/1.1/"
+    xmlns:cc="http://creativecommons.org/ns#"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns="http://www.w3.org/2000/svg"
+    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+    viewbox="0 0 16 16"
+    height="16"
+    width="16"
+    version="1.1"
+    id="svg4"
+    sodipodi:docname="first_run_groupware.svg"
+    inkscape:version="0.92.2 2405546, 2018-03-11">
+    <metadata
+        id="metadata10">
+        <rdf:RDF>
+            <cc:Work
+                rdf:about="">
+                <dc:format>image/svg+xml</dc:format>
+                <dc:type
+                    rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+                <dc:title></dc:title>
+            </cc:Work>
+        </rdf:RDF>
+    </metadata>
+    <defs
+        id="defs8"/>
+    <sodipodi:namedview
+        pagecolor="#ffffff"
+        bordercolor="#666666"
+        borderopacity="1"
+        objecttolerance="10"
+        gridtolerance="10"
+        guidetolerance="10"
+        inkscape:pageopacity="0"
+        inkscape:pageshadow="2"
+        inkscape:window-width="1600"
+        inkscape:window-height="835"
+        id="namedview6"
+        showgrid="false"
+        inkscape:pagecheckerboard="true"
+        inkscape:zoom="14.75"
+        inkscape:cx="0.54237288"
+        inkscape:cy="8"
+        inkscape:window-x="0"
+        inkscape:window-y="0"
+        inkscape:window-maximized="1"
+        inkscape:current-layer="svg4"/>
+    <path
+        fill="#0082c9"
+        d="m9 1c-1.746 0-3 1.43-3 2.8 0 1.4 0.1 2.4 0.8 3.5 0.224 0.29 0.485 0.35 0.7 0.6 0.135 0.5 0.24 1 0.1 1.5-0.436 0.153-0.85 0.332-1.27 0.5-0.51-0.273-1.1-0.5-1.61-0.7-0.07-0.28-0.02-0.487 0.05-0.75 0.12-0.125 0.23-0.18 0.36-0.3 0.37-0.45 0.39-1.21 0.39-1.75 0-0.8-0.72-1.4-1.5-1.4-0.87 0-1.5 0.72-1.5 1.4h-0.02c0 0.7 0.05 1.2 0.4 1.75 0.1 0.15 0.242 0.175 0.35 0.3 0.0674 0.25 0.121 0.5 0.05 0.75-0.64 0.223-1.244 0.5-1.8 0.8-0.42 0.3-0.233 0.182-0.5 1.15-0.124 0.5 1.3 0.73 2.32 0.81-0.05 0.275-0.12 0.64-0.32 1.34-0.32 1.25 4.353 1.7 6 1.7 2.43 0 6.313-0.456 5.98-1.7-0.52-1.94-0.208-1.71-0.98-2.3-1.09-0.654-2.452-1.167-3.6-1.6-0.15-0.557-0.04-0.97 0.1-1.5 0.235-0.25 0.5-0.36 0.72-0.6 0.69-0.884 0.78-2.424 0.78-3.5 0-1.586-1.43-2.8-3-2.8z"
+        id="path2"
+        style="fill:#ffffff;fill-opacity:1"/>
+</svg>

+ 66 - 0
drawable_resources/first_run_talk.svg

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+    xmlns:dc="http://purl.org/dc/elements/1.1/"
+    xmlns:cc="http://creativecommons.org/ns#"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns="http://www.w3.org/2000/svg"
+    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+    width="16mm"
+    height="16mm"
+    viewBox="0 0 16 16"
+    version="1.1"
+    id="svg829"
+    inkscape:version="0.92.2 2405546, 2018-03-11"
+    sodipodi:docname="first_run_talk.svg">
+    <defs
+        id="defs823"/>
+    <sodipodi:namedview
+        id="base"
+        pagecolor="#ffffff"
+        bordercolor="#666666"
+        borderopacity="1.0"
+        inkscape:pageopacity="0.0"
+        inkscape:pageshadow="2"
+        inkscape:zoom="5.6"
+        inkscape:cx="-19.200952"
+        inkscape:cy="38.084396"
+        inkscape:document-units="mm"
+        inkscape:current-layer="layer1"
+        showgrid="false"
+        inkscape:pagecheckerboard="true"
+        fit-margin-top="2"
+        fit-margin-left="2"
+        fit-margin-right="2"
+        fit-margin-bottom="2"
+        inkscape:window-width="1600"
+        inkscape:window-height="835"
+        inkscape:window-x="0"
+        inkscape:window-y="0"
+        inkscape:window-maximized="1"/>
+    <metadata
+        id="metadata826">
+        <rdf:RDF>
+            <cc:Work
+                rdf:about="">
+                <dc:format>image/svg+xml</dc:format>
+                <dc:type
+                    rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+                <dc:title></dc:title>
+            </cc:Work>
+        </rdf:RDF>
+    </metadata>
+    <g
+        inkscape:label="Layer 1"
+        inkscape:groupmode="layer"
+        id="layer1"
+        transform="translate(-15.580506,-164.12649)">
+        <path
+            inkscape:connector-curvature="0"
+            style="fill:#ffffff;stroke-width:0.13229023"
+            d="m 23.579679,165.51155 a 6.6138496,6.6139445 0 0 0 -6.613756,6.61414 6.6138496,6.6139445 0 0 0 6.613756,6.61394 6.6138496,6.6139445 0 0 0 3.430853,-0.96761 c 0.812866,0.32302 2.633614,1.28133 3.066959,0.86739 0.452829,-0.43245 -0.531627,-2.46778 -0.767642,-3.2241 a 6.6138496,6.6139445 0 0 0 0.88351,-3.28968 6.6138496,6.6139445 0 0 0 -6.613662,-6.61385 z m 7.69e-4,2.51456 a 4.1009972,4.1010914 0 0 1 4.100984,4.10109 4.1009972,4.1010914 0 0 1 -4.100997,4.10081 4.1009972,4.1010914 0 0 1 -4.100997,-4.10081 4.1009972,4.1010914 0 0 1 4.100997,-4.10109 z"
+            id="path2"/>
+    </g>
+</svg>

+ 4 - 0
src/main/AndroidManifest.xml

@@ -254,6 +254,10 @@
             android:configChanges="orientation|screenSize|keyboardHidden"/>
         <activity android:name=".ui.activity.WhatsNewActivity"
                   android:theme="@style/Theme.ownCloud.noActionBar.Login" />
+        <activity
+            android:name=".ui.activity.FirstRunActivity"
+            android:theme="@style/Theme.ownCloud.noActionBar.Login"
+            android:configChanges="orientation|screenSize"/>
 
         <receiver android:name=".files.BootupBroadcastReceiver" >
             <intent-filter>

+ 5 - 0
src/main/java/com/owncloud/android/MainApp.java

@@ -662,4 +662,9 @@ public class MainApp extends MultiDexApplication {
             }
         }
     }
+
+    static public int getLastSeenVersionCode(Context context) {
+        SharedPreferences pref = android.preference.PreferenceManager.getDefaultSharedPreferences(context);
+        return pref.getInt(WhatsNewActivity.KEY_LAST_SEEN_VERSION_CODE, 0);
+    }
 }

+ 2307 - 2288
src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java

@@ -1,2288 +1,2307 @@
-/*
- * ownCloud Android client application
- *
- * @author Bartek Przybylski
- * @author David A. Velasco
- * @author masensio
- * @author Mario Danic
- * Copyright (C) 2012  Bartek Przybylski
- * Copyright (C) 2015 ownCloud Inc.
- * Copyright (C) 2017 Mario Danic
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- *
- * 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/>.
- *
- * All changes by Mario Danic are distributed under the following terms:
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.authentication;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.annotation.SuppressLint;
-import android.app.Dialog;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.net.http.SslError;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.preference.PreferenceManager;
-import android.support.annotation.Nullable;
-import android.support.design.widget.Snackbar;
-import android.support.design.widget.TextInputLayout;
-import android.support.v4.app.DialogFragment;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
-import android.text.Editable;
-import android.text.InputType;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.util.AndroidRuntimeException;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnFocusChangeListener;
-import android.view.View.OnTouchListener;
-import android.view.inputmethod.EditorInfo;
-import android.webkit.CookieManager;
-import android.webkit.CookieSyncManager;
-import android.webkit.HttpAuthHandler;
-import android.webkit.SslErrorHandler;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-import android.widget.TextView.OnEditorActionListener;
-
-import com.owncloud.android.MainApp;
-import com.owncloud.android.R;
-import com.owncloud.android.authentication.SsoWebViewClient.SsoWebViewClientListener;
-import com.owncloud.android.lib.common.OwnCloudAccount;
-import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
-import com.owncloud.android.lib.common.OwnCloudCredentials;
-import com.owncloud.android.lib.common.OwnCloudCredentialsFactory;
-import com.owncloud.android.lib.common.UserInfo;
-import com.owncloud.android.lib.common.accounts.AccountTypeUtils;
-import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
-import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
-import com.owncloud.android.lib.common.network.CertificateCombinedException;
-import com.owncloud.android.lib.common.network.NetworkUtils;
-import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
-import com.owncloud.android.lib.common.operations.RemoteOperation;
-import com.owncloud.android.lib.common.operations.RemoteOperationResult;
-import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
-import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.lib.resources.status.OwnCloudVersion;
-import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation;
-import com.owncloud.android.operations.DetectAuthenticationMethodOperation.AuthenticationMethod;
-import com.owncloud.android.operations.GetServerInfoOperation;
-import com.owncloud.android.operations.OAuth2GetAccessToken;
-import com.owncloud.android.services.OperationsService;
-import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
-import com.owncloud.android.ui.components.CustomEditText;
-import com.owncloud.android.ui.dialog.CredentialsDialogFragment;
-import com.owncloud.android.ui.dialog.IndeterminateProgressDialog;
-import com.owncloud.android.ui.dialog.SamlWebViewDialog;
-import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
-import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener;
-import com.owncloud.android.utils.DisplayUtils;
-import com.owncloud.android.utils.ErrorMessageAdapter;
-
-import java.io.InputStream;
-import java.net.URLDecoder;
-import java.security.cert.X509Certificate;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
-/**
- * This Activity is used to add an ownCloud account to the App
- */
-public class AuthenticatorActivity extends AccountAuthenticatorActivity
-        implements OnRemoteOperationListener, OnFocusChangeListener, OnEditorActionListener,
-        SsoWebViewClientListener, OnSslUntrustedCertListener,
-        AuthenticatorAsyncTask.OnAuthenticatorTaskListener {
-
-    private static final String TAG = AuthenticatorActivity.class.getSimpleName();
-
-    public static final String EXTRA_ACTION = "ACTION";
-    public static final String EXTRA_ACCOUNT = "ACCOUNT";
-
-    private static final String KEY_AUTH_TOKEN_TYPE = "AUTH_TOKEN_TYPE";
-
-    private static final String KEY_HOST_URL_TEXT = "HOST_URL_TEXT";
-    private static final String KEY_OC_VERSION = "OC_VERSION";
-    private static final String KEY_SERVER_VALID = "SERVER_VALID";
-    private static final String KEY_SERVER_CHECKED = "SERVER_CHECKED";
-    private static final String KEY_SERVER_STATUS_TEXT = "SERVER_STATUS_TEXT";
-    private static final String KEY_SERVER_STATUS_ICON = "SERVER_STATUS_ICON";
-    private static final String KEY_IS_SSL_CONN = "IS_SSL_CONN";
-    private static final String KEY_PASSWORD_EXPOSED = "PASSWORD_VISIBLE";
-    private static final String KEY_AUTH_STATUS_TEXT = "AUTH_STATUS_TEXT";
-    private static final String KEY_AUTH_STATUS_ICON = "AUTH_STATUS_ICON";
-    private static final String KEY_SERVER_AUTH_METHOD = "SERVER_AUTH_METHOD";
-    private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";
-    private static final String KEY_AUTH_TOKEN = "AUTH_TOKEN";
-
-    private static final String AUTH_ON = "on";
-    private static final String AUTH_OPTIONAL = "optional";
-
-    public static final byte ACTION_CREATE = 0;
-    public static final byte ACTION_UPDATE_EXPIRED_TOKEN = 2;       // detected by the app
-
-    private static final String UNTRUSTED_CERT_DIALOG_TAG = "UNTRUSTED_CERT_DIALOG";
-    private static final String SAML_DIALOG_TAG = "SAML_DIALOG";
-    private static final String WAIT_DIALOG_TAG = "WAIT_DIALOG";
-    private static final String CREDENTIALS_DIALOG_TAG = "CREDENTIALS_DIALOG";
-    private static final String KEY_AUTH_IS_FIRST_ATTEMPT_TAG = "KEY_AUTH_IS_FIRST_ATTEMPT";
-
-    private static final String KEY_USERNAME = "USERNAME";
-    private static final String KEY_PASSWORD = "PASSWORD";
-    private static final String KEY_ASYNC_TASK_IN_PROGRESS = "AUTH_IN_PROGRESS";
-    private static final String WEB_LOGIN = "/index.php/login/flow";
-    public static final String PROTOCOL_SUFFIX = "://";
-    public static final String LOGIN_URL_DATA_KEY_VALUE_SEPARATOR = ":";
-    public static final String HTTPS_PROTOCOL = "https://";
-    public static final String HTTP_PROTOCOL = "http://";
-
-    public static final String REGULAR_SERVER_INPUT_TYPE = "regular";
-    public static final String SUBDOMAIN_SERVER_INPUT_TYPE = "prefix";
-    public static final String DIRECTORY_SERVER_INPUT_TYPE = "suffix";
-
-    /// parameters from EXTRAs in starter Intent
-    private byte mAction;
-    private Account mAccount;
-    private String mAuthTokenType;
-
-    /// activity-level references / state
-    private final Handler mHandler = new Handler();
-    private ServiceConnection mOperationsServiceConnection = null;
-    private OperationsServiceBinder mOperationsServiceBinder = null;
-    private AccountManager mAccountMgr;
-    private Uri mNewCapturedUriFromOAuth2Redirection;
-
-    /// Server PRE-Fragment elements 
-    private CustomEditText mHostUrlInput;
-    private View mRefreshButton;
-    private TextView mServerStatusView;
-
-    private TextWatcher mHostUrlInputWatcher;
-    private String mServerStatusText = "";
-    private int mServerStatusIcon;
-
-    private boolean mServerIsChecked;
-    private boolean mServerIsValid;
-
-    private GetServerInfoOperation.ServerInfo mServerInfo = new GetServerInfoOperation.ServerInfo();
-
-    /// Authentication PRE-Fragment elements 
-    private CheckBox mOAuth2Check;
-    private TextView mOAuthAuthEndpointText;
-    private TextView mOAuthTokenEndpointText;
-    private EditText mUsernameInput;
-    private EditText mPasswordInput;
-    private View mOkButton;
-    private TextView mAuthStatusView;
-    private ImageButton mTestServerButton;
-
-    private WebView mLoginWebView;
-
-    private String mAuthStatusText = "";
-    private int mAuthStatusIcon;
-
-    private String mAuthToken = "";
-    private AuthenticatorAsyncTask mAsyncTask;
-
-    private boolean mIsFirstAuthAttempt;
-
-    /// Identifier of operation in progress which result shouldn't be lost 
-    private long mWaitingForOpId = Long.MAX_VALUE;
-
-    private String basicTokenType;
-    private String oauthTokenType;
-    private String samlTokenType;
-
-    private boolean webViewLoginMethod;
-    private String webViewUser;
-    private String webViewPassword;
-    private TextInputLayout mUsernameInputLayout;
-    private TextInputLayout mPasswordInputLayout;
-    private boolean forceOldLoginMethod;
-
-    /**
-     * {@inheritDoc}
-     *
-     * IMPORTANT ENTRY POINT 1: activity is shown to the user
-     */
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        //Log_OC.e(TAG,  "onCreate init");
-        super.onCreate(savedInstanceState);
-
-        basicTokenType = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType(this));
-        oauthTokenType = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType(this));
-        samlTokenType = AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType(this));
-
-        // delete cookies for webView
-        deleteCookies();
-
-        // Workaround, for fixing a problem with Android Library Suppor v7 19
-        //getWindow().requestFeature(Window.FEATURE_NO_TITLE);
-        if (getSupportActionBar() != null) {
-            getSupportActionBar().hide();
-            getSupportActionBar().setDisplayHomeAsUpEnabled(false);
-            getSupportActionBar().setDisplayShowHomeEnabled(false);
-            getSupportActionBar().setDisplayShowTitleEnabled(false);
-        }
-
-        mIsFirstAuthAttempt = true;
-
-        /// init activity state
-        mAccountMgr = AccountManager.get(this);
-        mNewCapturedUriFromOAuth2Redirection = null;
-
-        /// get input values
-        mAction = getIntent().getByteExtra(EXTRA_ACTION, ACTION_CREATE);
-        mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT);
-        if (savedInstanceState == null) {
-            initAuthTokenType();
-        } else {
-            mAuthTokenType = savedInstanceState.getString(KEY_AUTH_TOKEN_TYPE);
-            mWaitingForOpId = savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID);
-            mIsFirstAuthAttempt = savedInstanceState.getBoolean(KEY_AUTH_IS_FIRST_ATTEMPT_TAG);
-        }
-
-        webViewLoginMethod = !TextUtils.isEmpty(getResources().getString(R.string.webview_login_url));
-
-        if (webViewLoginMethod) {
-            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
-        }
-
-        /// load user interface
-        if (!webViewLoginMethod) {
-            setContentView(R.layout.account_setup);
-
-            /// initialize general UI elements
-            initOverallUi();
-
-            findViewById(R.id.centeredRefreshButton).setOnClickListener(new View.OnClickListener() {
-
-                @Override
-                public void onClick(View v) {
-                    checkOcServer();
-                }
-            });
-
-            findViewById(R.id.embeddedRefreshButton).setOnClickListener(new View.OnClickListener() {
-
-                @Override
-                public void onClick(View v) {
-                    checkOcServer();
-                }
-            });
-
-            /// initialize block to be moved to single Fragment to check server and get info about it
-
-            /// initialize block to be moved to single Fragment to retrieve and validate credentials
-            initAuthorizationPreFragment(savedInstanceState);
-
-        } else {
-            setContentView(R.layout.account_setup_webview);
-            mLoginWebView = findViewById(R.id.login_webview);
-            initWebViewLogin(null);
-        }
-
-        initServerPreFragment(savedInstanceState);
-    }
-
-    private void deleteCookies() {
-        try {
-            CookieSyncManager.createInstance(this);
-            CookieManager cookieManager = CookieManager.getInstance();
-
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-                cookieManager.removeAllCookies(null);
-            } else {
-                cookieManager.removeAllCookie();
-            }
-        } catch (AndroidRuntimeException e) {
-            Log_OC.e(TAG, e.getMessage());
-        }
-    }
-
-    private static String getWebLoginUserAgent() {
-        return Build.MANUFACTURER.substring(0, 1).toUpperCase(Locale.getDefault()) +
-                Build.MANUFACTURER.substring(1).toLowerCase(Locale.getDefault()) + " " + Build.MODEL;
-    }
-
-    @SuppressLint("SetJavaScriptEnabled")
-    private void initWebViewLogin(String baseURL) {
-        mLoginWebView.setVisibility(View.GONE);
-
-        final ProgressBar progressBar = findViewById(R.id.login_webview_progress_bar);
-
-        mLoginWebView.getSettings().setAllowFileAccess(false);
-        mLoginWebView.getSettings().setJavaScriptEnabled(true);
-        mLoginWebView.getSettings().setDomStorageEnabled(true);
-        mLoginWebView.getSettings().setUserAgentString(getWebLoginUserAgent());
-        mLoginWebView.getSettings().setSaveFormData(false);
-        mLoginWebView.getSettings().setSavePassword(false);
-
-        Map<String, String> headers = new HashMap<>();
-        headers.put(RemoteOperation.OCS_API_HEADER, RemoteOperation.OCS_API_HEADER_VALUE);
-
-        String url;
-        if (baseURL != null && !baseURL.isEmpty()) {
-            url = baseURL + WEB_LOGIN;
-        } else {
-            url = getResources().getString(R.string.webview_login_url);
-        }
-
-        mLoginWebView.loadUrl(url, headers);
-
-        setClient(progressBar);
-
-        // show snackbar after 60s to switch back to old login method
-        new Handler().postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                DisplayUtils.createSnackbar(mLoginWebView, R.string.fallback_weblogin_text, Snackbar.LENGTH_INDEFINITE)
-                        .setActionTextColor(getResources().getColor(R.color.primary_dark))
-                        .setAction(R.string.fallback_weblogin_back, new View.OnClickListener() {
-                            @Override
-                            public void onClick(View v) {
-                                mLoginWebView.setVisibility(View.INVISIBLE);
-                                webViewLoginMethod = false;
-
-                                setContentView(R.layout.account_setup);
-
-                                // initialize general UI elements
-                                initOverallUi();
-
-                                mPasswordInputLayout.setVisibility(View.VISIBLE);
-                                mUsernameInputLayout.setVisibility(View.VISIBLE);
-                                mUsernameInput.requestFocus();
-                                mOAuth2Check.setVisibility(View.INVISIBLE);
-                                mAuthStatusView.setVisibility(View.INVISIBLE);
-                                mServerStatusView.setVisibility(View.INVISIBLE);
-                                mTestServerButton.setVisibility(View.INVISIBLE);
-                                forceOldLoginMethod = true;
-                                mOkButton.setVisibility(View.VISIBLE);
-
-                                initServerPreFragment(null);
-
-                                mHostUrlInput.setText(baseURL);
-
-                                checkOcServer();
-                            }
-                        }).show();
-            }
-        }, 60000);
-    }
-
-    private void setClient(ProgressBar progressBar) {
-        mLoginWebView.setWebViewClient(new WebViewClient() {
-            @Override
-            public boolean shouldOverrideUrlLoading(WebView view, String url) {
-                if (url.startsWith(getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/")) {
-                    parseAndLoginFromWebView(url);
-                    return true;
-                }
-                return false;
-            }
-
-            @Override
-            public void onPageFinished(WebView view, String url) {
-                super.onPageFinished(view, url);
-
-                progressBar.setVisibility(View.GONE);
-                mLoginWebView.setVisibility(View.VISIBLE);
-            }
-
-            @Override
-            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
-                X509Certificate cert = SsoWebViewClient.getX509CertificateFromError(error);
-
-                try {
-                    if (cert != null && NetworkUtils.isCertInKnownServersStore(cert, getApplicationContext())) {
-                        handler.proceed();
-                    } else {
-                        showUntrustedCertDialog(cert, error, handler);
-                    }
-                } catch (Exception e) {
-                    Log_OC.e(TAG, "Cert could not be verified");
-                }
-            }
-
-            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
-                progressBar.setVisibility(View.GONE);
-                mLoginWebView.setVisibility(View.VISIBLE);
-
-                InputStream resources = getResources().openRawResource(R.raw.custom_error);
-                String customError = DisplayUtils.getData(resources);
-
-                if (!customError.isEmpty()) {
-                    mLoginWebView.loadData(customError, "text/html; charset=UTF-8", null);
-                }
-            }
-        });
-    }
-
-    private void parseAndLoginFromWebView(String dataString) {
-        String prefix = getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/";
-        LoginUrlInfo loginUrlInfo = parseLoginDataUrl(prefix, dataString);
-
-        if (loginUrlInfo != null) {
-            mServerInfo.mBaseUrl = AuthenticatorUrlUtils.normalizeUrlSuffix(loginUrlInfo.serverAddress);
-            webViewUser = loginUrlInfo.username;
-            webViewPassword = loginUrlInfo.password;
-            checkOcServer();
-        }
-    }
-
-    private void populateLoginFields(String dataString) throws IllegalArgumentException {
-        // check if it is cloud://login/
-        if (dataString.startsWith(getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/")) {
-            String prefix = getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/";
-            LoginUrlInfo loginUrlInfo = parseLoginDataUrl(prefix, dataString);
-
-            if (loginUrlInfo != null) {
-                mHostUrlInput.setText(loginUrlInfo.serverAddress);
-                mUsernameInput.setText(loginUrlInfo.username);
-                mPasswordInput.setText(loginUrlInfo.password);
-
-                if (loginUrlInfo.serverAddress != null && !mServerIsChecked) {
-                    onUrlInputFocusLost();
-                }
-            }
-        }
-    }
-
-    /**
-     * parses a URI string and returns a login data object with the information from the URI string.
-     *
-     * @param prefix     URI beginning, e.g. cloud://login/
-     * @param dataString the complete URI
-     * @return login data
-     * @throws IllegalArgumentException when
-     */
-    public static LoginUrlInfo parseLoginDataUrl(String prefix, String dataString) throws IllegalArgumentException {
-        if (dataString.length() < prefix.length()) {
-            throw new IllegalArgumentException("Invalid login URL detected");
-        }
-        LoginUrlInfo loginUrlInfo = new LoginUrlInfo();
-
-        // format is basically xxx://login/server:xxx&user:xxx&password while all variables are optional
-        String data = dataString.substring(prefix.length());
-
-        // parse data
-        String[] values = data.split("&");
-
-        if (values.length < 1 || values.length > 3) {
-            // error illegal number of URL elements detected
-            throw new IllegalArgumentException("Illegal number of login URL elements detected: " + values.length);
-        }
-
-        for (String value : values) {
-            if (value.startsWith("user" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) {
-                loginUrlInfo.username = URLDecoder.decode(
-                        value.substring(("user" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length()));
-            } else if (value.startsWith("password" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) {
-                loginUrlInfo.password = URLDecoder.decode(
-                        value.substring(("password" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length()));
-            } else if (value.startsWith("server" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) {
-                loginUrlInfo.serverAddress = URLDecoder.decode(
-                        value.substring(("server" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length()));
-            } else {
-                // error illegal URL element detected
-                throw new IllegalArgumentException("Illegal magic login URL element detected: " + value);
-            }
-        }
-
-        return loginUrlInfo;
-    }
-
-    private void initAuthTokenType() {
-        mAuthTokenType = getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);
-        if (mAuthTokenType == null) {
-            if (mAccount != null) {
-                boolean oAuthRequired = mAccountMgr.getUserData(mAccount, Constants.KEY_SUPPORTS_OAUTH2) != null;
-                boolean samlWebSsoRequired = (
-                        mAccountMgr.getUserData
-                                (mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null
-                );
-                mAuthTokenType = chooseAuthTokenType(oAuthRequired, samlWebSsoRequired);
-
-            } else {
-                boolean oAuthSupported = AUTH_ON.equals(getString(R.string.auth_method_oauth2));
-                boolean samlWebSsoSupported = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso));
-                mAuthTokenType = chooseAuthTokenType(oAuthSupported, samlWebSsoSupported);
-            }
-        }
-    }
-
-    private String chooseAuthTokenType(boolean oauth, boolean saml) {
-        if (saml) {
-            return samlTokenType;
-        } else if (oauth) {
-            return oauthTokenType;
-        } else {
-            return basicTokenType;
-        }
-    }
-
-
-    /**
-     * Configures elements in the user interface under direct control of the Activity.
-     */
-    private void initOverallUi() {
-        mHostUrlInput = findViewById(R.id.hostUrlInput);
-        mUsernameInputLayout = findViewById(R.id.input_layout_account_username);
-        mPasswordInputLayout = findViewById(R.id.input_layout_account_password);
-        mPasswordInput = findViewById(R.id.account_password);
-        mUsernameInput = findViewById(R.id.account_username);
-        mAuthStatusView = findViewById(R.id.auth_status_text);
-        mOAuth2Check = findViewById(R.id.oauth_onOff_check);
-        mServerStatusView = findViewById(R.id.server_status_text);
-        mTestServerButton = findViewById(R.id.testServerButton);
-
-        mOkButton = findViewById(R.id.buttonOK);
-        mOkButton.setOnClickListener(v -> onOkClick());
-
-        setupWelcomeLink();
-        setupInstructionMessage();
-
-        mTestServerButton.setVisibility(mAction == ACTION_CREATE ? View.VISIBLE : View.GONE);
-    }
-
-    private void setupWelcomeLink() {
-        Button welcomeLink = findViewById(R.id.welcome_link);
-        welcomeLink.setVisibility(mAction == ACTION_CREATE &&
-                getResources().getBoolean(R.bool.show_welcome_link) ? View.VISIBLE : View.GONE);
-        welcomeLink.setText(getString(R.string.auth_register));
-    }
-
-    private void setupInstructionMessage() {
-        String instructionsMessageText = calculateInstructionMessageText(mAction, mAuthTokenType);
-        TextView instructionsView = findViewById(R.id.instructions_message);
-
-        if (instructionsMessageText != null) {
-            instructionsView.setVisibility(View.VISIBLE);
-            instructionsView.setText(instructionsMessageText);
-        } else {
-            instructionsView.setVisibility(View.GONE);
-        }
-    }
-
-    @Nullable
-    private String calculateInstructionMessageText(byte action, String authTokenType) {
-        if (action == ACTION_UPDATE_EXPIRED_TOKEN) {
-            if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType(this)).equals(authTokenType)) {
-                return getString(R.string.auth_expired_oauth_token_toast);
-
-            } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType(this))
-                    .equals(authTokenType)) {
-                return getString(R.string.auth_expired_saml_sso_token_toast);
-
-            } else {
-                return getString(R.string.auth_expired_basic_auth_toast);
-            }
-        }
-
-        return null;
-    }
-
-    public void onTestServerConnectionClick(View v) {
-        checkOcServer();
-    }
-
-
-    /**
-     * @param savedInstanceState Saved activity state, as in {{@link #onCreate(Bundle)}
-     */
-    private void initServerPreFragment(Bundle savedInstanceState) {
-
-        /// step 1 - load and process relevant inputs (resources, intent, savedInstanceState)
-        boolean isUrlInputAllowed = getResources().getBoolean(R.bool.show_server_url_input);
-        if (savedInstanceState == null) {
-            if (mAccount != null) {
-                mServerInfo.mBaseUrl = mAccountMgr.getUserData(mAccount, Constants.KEY_OC_BASE_URL);
-                // TODO do next in a setter for mBaseUrl
-                mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith(HTTPS_PROTOCOL);
-                mServerInfo.mVersion = AccountUtils.getServerVersion(mAccount);
-            } else {
-                if (!webViewLoginMethod) {
-                    mServerInfo.mBaseUrl = getString(R.string.server_url).trim();
-                } else {
-                    mServerInfo.mBaseUrl = getString(R.string.webview_login_url).trim();
-                }
-                mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith(HTTPS_PROTOCOL);
-            }
-        } else {
-            mServerStatusText = savedInstanceState.getString(KEY_SERVER_STATUS_TEXT);
-            mServerStatusIcon = savedInstanceState.getInt(KEY_SERVER_STATUS_ICON);
-
-            mServerIsValid = savedInstanceState.getBoolean(KEY_SERVER_VALID);
-            mServerIsChecked = savedInstanceState.getBoolean(KEY_SERVER_CHECKED);
-
-            // TODO parcelable
-            mServerInfo.mIsSslConn = savedInstanceState.getBoolean(KEY_IS_SSL_CONN);
-            mServerInfo.mBaseUrl = savedInstanceState.getString(KEY_HOST_URL_TEXT);
-            String ocVersion = savedInstanceState.getString(KEY_OC_VERSION);
-            if (ocVersion != null) {
-                mServerInfo.mVersion = new OwnCloudVersion(ocVersion);
-            }
-            mServerInfo.mAuthMethod = AuthenticationMethod.valueOf(
-                    savedInstanceState.getString(KEY_SERVER_AUTH_METHOD));
-
-        }
-
-        if (!webViewLoginMethod) {
-            /// step 2 - set properties of UI elements (text, visibility, enabled...)
-            mHostUrlInput = findViewById(R.id.hostUrlInput);
-            // Convert IDN to Unicode
-            mHostUrlInput.setText(DisplayUtils.convertIdn(mServerInfo.mBaseUrl, false));
-            if (mAction != ACTION_CREATE) {
-                /// lock things that should not change
-                mHostUrlInput.setEnabled(false);
-                mHostUrlInput.setFocusable(false);
-            }
-            if (isUrlInputAllowed) {
-                mRefreshButton = findViewById(R.id.embeddedRefreshButton);
-            } else {
-                findViewById(R.id.hostUrlFrame).setVisibility(View.GONE);
-                mRefreshButton = findViewById(R.id.centeredRefreshButton);
-            }
-            showRefreshButton(mServerIsChecked && !mServerIsValid &&
-                    mWaitingForOpId > Integer.MAX_VALUE);
-            mServerStatusView = findViewById(R.id.server_status_text);
-            showServerStatus();
-
-            /// step 3 - bind some listeners and options
-            mHostUrlInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
-            mHostUrlInput.setOnEditorActionListener(this);
-
-            /// step 4 - create listeners that will be bound at onResume
-            mHostUrlInputWatcher = new TextWatcher() {
-
-                @Override
-                public void afterTextChanged(Editable s) {
-                    if (mOkButton.isEnabled() &&
-                            !mServerInfo.mBaseUrl.equals(
-                                    AuthenticatorUrlUtils.normalizeUrl(s.toString(), mServerInfo.mIsSslConn))) {
-                        mOkButton.setEnabled(false);
-                    }
-                }
-
-                @Override
-                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-                    // not used at the moment
-                }
-
-                @Override
-                public void onTextChanged(CharSequence s, int start, int before, int count) {
-                    if (mAuthStatusIcon != 0) {
-                        Log_OC.d(TAG, "onTextChanged: hiding authentication status");
-                        mAuthStatusIcon = 0;
-                        mAuthStatusText = "";
-                        showAuthStatus();
-                    }
-                }
-            };
-
-
-            // TODO find out if this is really necessary, or if it can done in a different way
-            findViewById(R.id.scroll).setOnTouchListener(new OnTouchListener() {
-                @Override
-                public boolean onTouch(View view, MotionEvent event) {
-                    if (event.getAction() == MotionEvent.ACTION_DOWN &&
-                            AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(
-                                    MainApp.getAccountType(getBaseContext())).equals(mAuthTokenType) &&
-                            mHostUrlInput.hasFocus()) {
-                        checkOcServer();
-                    }
-                    return false;
-                }
-            });
-        }
-    }
-
-
-    /**
-     * @param savedInstanceState Saved activity state, as in {{@link #onCreate(Bundle)}
-     */
-    private void initAuthorizationPreFragment(Bundle savedInstanceState) {
-
-        /// step 0 - get UI elements in layout
-        mOAuth2Check = findViewById(R.id.oauth_onOff_check);
-        mOAuthAuthEndpointText = findViewById(R.id.oAuthEntryPoint_1);
-        mOAuthTokenEndpointText = findViewById(R.id.oAuthEntryPoint_2);
-        mUsernameInput = findViewById(R.id.account_username);
-        mPasswordInput = findViewById(R.id.account_password);
-        mAuthStatusView = findViewById(R.id.auth_status_text);
-
-        /// step 1 - load and process relevant inputs (resources, intent, savedInstanceState)
-        String presetUserName = null;
-        boolean isPasswordExposed = false;
-        if (savedInstanceState == null) {
-            if (mAccount != null) {
-                presetUserName = com.owncloud.android.lib.common.accounts.AccountUtils.getUsernameForAccount(mAccount);
-            }
-        } else {
-            isPasswordExposed = savedInstanceState.getBoolean(KEY_PASSWORD_EXPOSED, false);
-            mAuthStatusText = savedInstanceState.getString(KEY_AUTH_STATUS_TEXT);
-            mAuthStatusIcon = savedInstanceState.getInt(KEY_AUTH_STATUS_ICON);
-            mAuthToken = savedInstanceState.getString(KEY_AUTH_TOKEN);
-        }
-
-        /// step 2 - set properties of UI elements (text, visibility, enabled...)
-        mOAuth2Check.setChecked(
-                AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType(this)).equals(mAuthTokenType));
-        if (presetUserName != null) {
-            mUsernameInput.setText(presetUserName);
-        }
-        if (mAction != ACTION_CREATE) {
-            mUsernameInput.setEnabled(false);
-            mUsernameInput.setFocusable(false);
-        }
-        mPasswordInput.setText(""); // clean password to avoid social hacking
-        if (isPasswordExposed) {
-            showPassword();
-        }
-        updateAuthenticationPreFragmentVisibility();
-        showAuthStatus();
-        mOkButton.setEnabled(mServerIsValid);
-
-
-        /// step 3 - bind listeners
-        // bindings for password input field
-        mPasswordInput.setOnFocusChangeListener(this);
-        mPasswordInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
-        mPasswordInput.setOnEditorActionListener(this);
-        mPasswordInput.setOnTouchListener(new RightDrawableOnTouchListener() {
-            @Override
-            public boolean onDrawableTouch(final MotionEvent event) {
-                if (event.getAction() == MotionEvent.ACTION_UP) {
-                    AuthenticatorActivity.this.onViewPasswordClick();
-                }
-                return true;
-            }
-        });
-
-    }
-
-
-    /**
-     * Changes the visibility of input elements depending on
-     * the current authorization method.
-     */
-    private void updateAuthenticationPreFragmentVisibility() {
-        if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType(this)).equals(mAuthTokenType)) {
-            // SAML-based web Single Sign On
-            mOAuth2Check.setVisibility(View.GONE);
-            mOAuthAuthEndpointText.setVisibility(View.GONE);
-            mOAuthTokenEndpointText.setVisibility(View.GONE);
-            mUsernameInput.setVisibility(View.GONE);
-            mPasswordInput.setVisibility(View.GONE);
-
-        } else {
-            if (mAction == ACTION_CREATE &&
-                    AUTH_OPTIONAL.equals(getString(R.string.auth_method_oauth2))) {
-                mOAuth2Check.setVisibility(View.VISIBLE);
-            } else {
-                mOAuth2Check.setVisibility(View.GONE);
-            }
-
-            if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType(this)).equals(mAuthTokenType)) {
-                // OAuth 2 authorization
-                mOAuthAuthEndpointText.setVisibility(View.VISIBLE);
-                mOAuthTokenEndpointText.setVisibility(View.VISIBLE);
-                mUsernameInput.setVisibility(View.GONE);
-                mPasswordInput.setVisibility(View.GONE);
-
-            } else {
-                // basic HTTP authorization
-                mOAuthAuthEndpointText.setVisibility(View.GONE);
-                mOAuthTokenEndpointText.setVisibility(View.GONE);
-                mUsernameInput.setVisibility(View.VISIBLE);
-                mPasswordInput.setVisibility(View.VISIBLE);
-            }
-        }
-    }
-
-
-    /**
-     * Saves relevant state before {@link #onPause()}
-     *
-     * Do NOT save {@link #mNewCapturedUriFromOAuth2Redirection}; it keeps a temporal flag,
-     * intended to defer the processing of the redirection caught in
-     * {@link #onNewIntent(Intent)} until {@link #onResume()}
-     *
-     * See {@link super#onSaveInstanceState(Bundle)}
-     */
-    @Override
-    protected void onSaveInstanceState(Bundle outState) {
-        //Log_OC.e(TAG, "onSaveInstanceState init" );
-        super.onSaveInstanceState(outState);
-
-        /// global state
-        outState.putString(KEY_AUTH_TOKEN_TYPE, mAuthTokenType);
-        outState.putLong(KEY_WAITING_FOR_OP_ID, mWaitingForOpId);
-
-        if (!webViewLoginMethod) {
-            /// Server PRE-fragment state
-            outState.putString(KEY_SERVER_STATUS_TEXT, mServerStatusText);
-            outState.putInt(KEY_SERVER_STATUS_ICON, mServerStatusIcon);
-            outState.putBoolean(KEY_SERVER_CHECKED, mServerIsChecked);
-            outState.putBoolean(KEY_SERVER_VALID, mServerIsValid);
-
-            /// Authentication PRE-fragment state
-            outState.putBoolean(KEY_PASSWORD_EXPOSED, isPasswordVisible());
-            outState.putInt(KEY_AUTH_STATUS_ICON, mAuthStatusIcon);
-            outState.putString(KEY_AUTH_STATUS_TEXT, mAuthStatusText);
-            outState.putString(KEY_AUTH_TOKEN, mAuthToken);
-        }
-
-        outState.putBoolean(KEY_IS_SSL_CONN, mServerInfo.mIsSslConn);
-        outState.putString(KEY_HOST_URL_TEXT, mServerInfo.mBaseUrl);
-        if (mServerInfo.mVersion != null) {
-            outState.putString(KEY_OC_VERSION, mServerInfo.mVersion.getVersion());
-        }
-        outState.putString(KEY_SERVER_AUTH_METHOD, mServerInfo.mAuthMethod.name());
-
-        /// authentication
-        outState.putBoolean(KEY_AUTH_IS_FIRST_ATTEMPT_TAG, mIsFirstAuthAttempt);
-
-        /// AsyncTask (User and password)
-        if (!webViewLoginMethod) {
-            outState.putString(KEY_USERNAME, mUsernameInput.getText().toString().trim());
-            outState.putString(KEY_PASSWORD, mPasswordInput.getText().toString());
-        }
-
-        if (mAsyncTask != null) {
-            mAsyncTask.cancel(true);
-            outState.putBoolean(KEY_ASYNC_TASK_IN_PROGRESS, true);
-        } else {
-            outState.putBoolean(KEY_ASYNC_TASK_IN_PROGRESS, false);
-        }
-        mAsyncTask = null;
-
-        //Log_OC.e(TAG, "onSaveInstanceState end" );
-    }
-
-    @Override
-    public void onRestoreInstanceState(Bundle savedInstanceState) {
-        super.onRestoreInstanceState(savedInstanceState);
-
-        mServerIsChecked = savedInstanceState.getBoolean(KEY_SERVER_CHECKED, false);
-
-        // AsyncTask
-        boolean inProgress = savedInstanceState.getBoolean(KEY_ASYNC_TASK_IN_PROGRESS);
-        if (inProgress) {
-            String username = savedInstanceState.getString(KEY_USERNAME);
-            String password = savedInstanceState.getString(KEY_PASSWORD);
-
-            OwnCloudCredentials credentials = null;
-            if (basicTokenType.equals(mAuthTokenType)) {
-                credentials = OwnCloudCredentialsFactory.newBasicCredentials(username, password);
-
-            } else if (oauthTokenType.equals(mAuthTokenType)) {
-                credentials = OwnCloudCredentialsFactory.newBearerCredentials(mAuthToken);
-
-            }
-            accessRootFolder(credentials);
-        }
-    }
-
-    /**
-     * The redirection triggered by the OAuth authentication server as response to the
-     * GET AUTHORIZATION request is caught here.
-     *
-     * To make this possible, this activity needs to be qualified with android:launchMode =
-     * "singleTask" in the AndroidManifest.xml file.
-     */
-    @Override
-    protected void onNewIntent(Intent intent) {
-        Log_OC.d(TAG, "onNewIntent()");
-        Uri data = intent.getData();
-        if (data != null && data.toString().startsWith(getString(R.string.oauth2_redirect_uri))) {
-            mNewCapturedUriFromOAuth2Redirection = data;
-        }
-    }
-
-
-    /**
-     * The redirection triggered by the OAuth authentication server as response to the
-     * GET AUTHORIZATION, and deferred in {@link #onNewIntent(Intent)}, is processed here.
-     */
-    @Override
-    protected void onResume() {
-        super.onResume();
-
-        if (!webViewLoginMethod) {
-            // bound here to avoid spurious changes triggered by Android on device rotations
-            mHostUrlInput.setOnFocusChangeListener(this);
-            mHostUrlInput.addTextChangedListener(mHostUrlInputWatcher);
-
-            if (mNewCapturedUriFromOAuth2Redirection != null) {
-                getOAuth2AccessTokenFromCapturedRedirection();
-            }
-
-            String dataString = getIntent().getDataString();
-            if (dataString != null) {
-                try {
-                    populateLoginFields(dataString);
-                } catch (IllegalArgumentException e) {
-                    DisplayUtils.showSnackMessage(findViewById(R.id.scroll), R.string.auth_illegal_login_used);
-                    Log_OC.e(TAG, "Illegal login data URL used, no Login pre-fill!", e);
-                }
-            }
-        }
-
-        // bind to Operations Service
-        mOperationsServiceConnection = new OperationsServiceConnection();
-        if (!bindService(new Intent(this, OperationsService.class),
-                mOperationsServiceConnection,
-                Context.BIND_AUTO_CREATE)) {
-            DisplayUtils.showSnackMessage(findViewById(R.id.scroll), R.string.error_cant_bind_to_operations_service);
-            finish();
-        }
-
-        if (mOperationsServiceBinder != null) {
-            doOnResumeAndBound();
-        }
-    }
-
-
-    @Override
-    protected void onPause() {
-        if (mOperationsServiceBinder != null) {
-            mOperationsServiceBinder.removeOperationListener(this);
-        }
-
-        if (!webViewLoginMethod) {
-            mHostUrlInput.removeTextChangedListener(mHostUrlInputWatcher);
-            mHostUrlInput.setOnFocusChangeListener(null);
-        }
-
-        super.onPause();
-    }
-
-    @Override
-    protected void onDestroy() {
-
-        mHostUrlInputWatcher = null;
-
-        if (mOperationsServiceConnection != null) {
-            unbindService(mOperationsServiceConnection);
-            mOperationsServiceBinder = null;
-        }
-
-        if (webViewLoginMethod) {
-            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
-        }
-
-        super.onDestroy();
-    }
-
-    /**
-     * Parses the redirection with the response to the GET AUTHORIZATION request to the
-     * oAuth server and requests for the access token (GET ACCESS TOKEN)
-     */
-    private void getOAuth2AccessTokenFromCapturedRedirection() {
-        /// Parse data from OAuth redirection
-        String queryParameters = mNewCapturedUriFromOAuth2Redirection.getQuery();
-        mNewCapturedUriFromOAuth2Redirection = null;
-
-        /// Showing the dialog with instructions for the user.
-        IndeterminateProgressDialog dialog =
-                IndeterminateProgressDialog.newInstance(R.string.auth_getting_authorization, true);
-        dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);
-
-        /// GET ACCESS TOKEN to the oAuth server
-        Intent getServerInfoIntent = new Intent();
-        getServerInfoIntent.setAction(OperationsService.ACTION_OAUTH2_GET_ACCESS_TOKEN);
-
-        getServerInfoIntent.putExtra(
-                OperationsService.EXTRA_SERVER_URL,
-                mOAuthTokenEndpointText.getText().toString().trim());
-
-        getServerInfoIntent.putExtra(
-                OperationsService.EXTRA_OAUTH2_QUERY_PARAMETERS,
-                queryParameters);
-
-        if (mOperationsServiceBinder != null) {
-            //Log_OC.e(TAG, "getting access token..." );
-            mWaitingForOpId = mOperationsServiceBinder.queueNewOperation(getServerInfoIntent);
-        }
-    }
-
-
-    /**
-     * Handles the change of focus on the text inputs for the server URL and the password
-     */
-    public void onFocusChange(View view, boolean hasFocus) {
-        if (view.getId() == R.id.hostUrlInput) {
-            if (!hasFocus) {
-                onUrlInputFocusLost();
-            } else {
-                showRefreshButton(false);
-            }
-
-        } else if (view.getId() == R.id.account_password) {
-            onPasswordFocusChanged(hasFocus);
-        }
-    }
-
-
-    /**
-     * Handles changes in focus on the text input for the server URL.
-     *
-     * IMPORTANT ENTRY POINT 2: When (!hasFocus), user wrote the server URL and changed to
-     * other field. The operation to check the existence of the server in the entered URL is
-     * started.
-     *
-     * When hasFocus:    user 'comes back' to write again the server URL.
-     */
-    private void onUrlInputFocusLost() {
-        if (!mServerInfo.mBaseUrl.equals(
-                AuthenticatorUrlUtils.normalizeUrl(mHostUrlInput.getText().toString(), mServerInfo.mIsSslConn))) {
-            // check server again only if the user changed something in the field
-            checkOcServer();
-        } else {
-            mOkButton.setEnabled(mServerIsValid);
-            showRefreshButton(!mServerIsValid);
-        }
-    }
-
-
-    private void checkOcServer() {
-        String uri;
-        if (mHostUrlInput != null) {
-            uri = mHostUrlInput.getText().toString().trim();
-            mOkButton.setEnabled(false);
-            showRefreshButton(false);
-        } else {
-            uri = mServerInfo.mBaseUrl;
-        }
-
-        mServerIsValid = false;
-        mServerIsChecked = false;
-        mServerInfo = new GetServerInfoOperation.ServerInfo();
-
-        if (uri.length() != 0) {
-            if (mHostUrlInput != null) {
-                uri = AuthenticatorUrlUtils.stripIndexPhpOrAppsFiles(uri);
-                mHostUrlInput.setText(uri);
-            }
-
-            // Handle internationalized domain names
-            try {
-                uri = DisplayUtils.convertIdn(uri, true);
-            } catch (IllegalArgumentException ex) {
-                // Let Owncloud library check the error of the malformed URI
-                Log_OC.e(TAG, "Error converting internationalized domain name " + uri, ex);
-            }
-
-            if (mHostUrlInput != null) {
-                mServerStatusText = getResources().getString(R.string.auth_testing_connection);
-                mServerStatusIcon = R.drawable.progress_small;
-                showServerStatus();
-            }
-
-            Intent getServerInfoIntent = new Intent();
-            getServerInfoIntent.setAction(OperationsService.ACTION_GET_SERVER_INFO);
-            getServerInfoIntent.putExtra(OperationsService.EXTRA_SERVER_URL,
-                    AuthenticatorUrlUtils.normalizeUrlSuffix(uri));
-
-            if (mOperationsServiceBinder != null) {
-                mWaitingForOpId = mOperationsServiceBinder.queueNewOperation(getServerInfoIntent);
-            } else {
-                Log_OC.e(TAG, "Server check tried with OperationService unbound!");
-            }
-
-        } else {
-            mServerStatusText = "";
-            mServerStatusIcon = 0;
-            if (!webViewLoginMethod) {
-                showServerStatus();
-            }
-        }
-    }
-
-
-    /**
-     * Handles changes in focus on the text input for the password (basic authorization).
-     *
-     * When (hasFocus), the button to toggle password visibility is shown.
-     *
-     * When (!hasFocus), the button is made invisible and the password is hidden.
-     *
-     * @param hasFocus 'True' if focus is received, 'false' if is lost
-     */
-
-    private void onPasswordFocusChanged(boolean hasFocus) {
-        if (hasFocus) {
-            showViewPasswordButton();
-        } else {
-            hidePassword();
-            hidePasswordButton();
-        }
-    }
-
-
-    private void showViewPasswordButton() {
-        int drawable = R.drawable.ic_view;
-        if (isPasswordVisible()) {
-            drawable = R.drawable.ic_hide;
-        }
-        mPasswordInput.setCompoundDrawablesWithIntrinsicBounds(0, 0, drawable, 0);
-    }
-
-    private boolean isPasswordVisible() {
-        return ((mPasswordInput.getInputType() & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) ==
-                InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
-    }
-
-    private void hidePasswordButton() {
-        mPasswordInput.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
-    }
-
-    private void showPassword() {
-        mPasswordInput.setInputType(
-                InputType.TYPE_CLASS_TEXT |
-                        InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD |
-                        InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
-        );
-        showViewPasswordButton();
-    }
-
-    private void hidePassword() {
-        mPasswordInput.setInputType(
-                InputType.TYPE_CLASS_TEXT |
-                        InputType.TYPE_TEXT_VARIATION_PASSWORD |
-                        InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
-        );
-        showViewPasswordButton();
-    }
-
-    /**
-     * Checks the credentials of the user in the root of the ownCloud server
-     * before creating a new local account.
-     *
-     * For basic authorization, a check of existence of the root folder is
-     * performed.
-     *
-     * For OAuth, starts the flow to get an access token; the credentials test
-     * is postponed until it is available.
-     *
-     * IMPORTANT ENTRY POINT 4
-     */
-    public void onOkClick() {
-        // this check should be unnecessary
-        if (mServerInfo.mVersion == null ||
-                !mServerInfo.mVersion.isVersionValid() ||
-                mServerInfo.mBaseUrl == null ||
-                mServerInfo.mBaseUrl.length() == 0) {
-            mServerStatusIcon = R.drawable.ic_alert;
-            mServerStatusText = getResources().getString(R.string.auth_wtf_reenter_URL);
-            showServerStatus();
-            mOkButton.setEnabled(false);
-            return;
-        }
-
-        if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType(this)).equals(mAuthTokenType)) {
-            startOauthorization();
-        } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType(this))
-                .equals(mAuthTokenType)) {
-            startSamlBasedFederatedSingleSignOnAuthorization();
-        } else {
-            checkBasicAuthorization(null, null);
-        }
-    }
-
-
-    /**
-     * Tests the credentials entered by the user performing a check of existence on
-     * the root folder of the ownCloud server.
-     */
-    private void checkBasicAuthorization(@Nullable String webViewUsername, @Nullable String webViewPassword) {
-        /// get basic credentials entered by user
-        String username;
-        String password;
-        if (!webViewLoginMethod) {
-            username = mUsernameInput.getText().toString().trim();
-            password = mPasswordInput.getText().toString();
-        } else {
-            username = webViewUsername;
-            password = webViewPassword;
-        }
-
-        /// be gentle with the user
-        IndeterminateProgressDialog dialog =
-                IndeterminateProgressDialog.newInstance(R.string.auth_trying_to_login, true);
-        dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);
-
-        /// validate credentials accessing the root folder
-        OwnCloudCredentials credentials = OwnCloudCredentialsFactory.newBasicCredentials(username, password);
-        accessRootFolder(credentials);
-    }
-
-    private void accessRootFolder(OwnCloudCredentials credentials) {
-        mAsyncTask = new AuthenticatorAsyncTask(this);
-        Object[] params = {mServerInfo.mBaseUrl, credentials};
-        mAsyncTask.execute(params);
-    }
-
-
-    /**
-     * Starts the OAuth 'grant type' flow to get an access token, with
-     * a GET AUTHORIZATION request to the BUILT-IN authorization server.
-     */
-    private void startOauthorization() {
-        // be gentle with the user
-        mAuthStatusIcon = R.drawable.progress_small;
-        mAuthStatusText = getResources().getString(R.string.oauth_login_connection);
-        showAuthStatus();
-
-        // GET AUTHORIZATION request
-        Uri uri = Uri.parse(mOAuthAuthEndpointText.getText().toString().trim());
-        Uri.Builder uriBuilder = uri.buildUpon();
-        uriBuilder.appendQueryParameter(
-                OAuth2Constants.KEY_RESPONSE_TYPE, getString(R.string.oauth2_response_type)
-        );
-        uriBuilder.appendQueryParameter(
-                OAuth2Constants.KEY_REDIRECT_URI, getString(R.string.oauth2_redirect_uri)
-        );
-        uriBuilder.appendQueryParameter(
-                OAuth2Constants.KEY_CLIENT_ID, getString(R.string.oauth2_client_id)
-        );
-        uriBuilder.appendQueryParameter(
-                OAuth2Constants.KEY_SCOPE, getString(R.string.oauth2_scope)
-        );
-        uri = uriBuilder.build();
-        Log_OC.d(TAG, "Starting browser to view " + uri.toString());
-        Intent i = new Intent(Intent.ACTION_VIEW, uri);
-        startActivity(i);
-    }
-
-
-    /**
-     * Starts the Web Single Sign On flow to get access to the root folder
-     * in the server.
-     */
-    private void startSamlBasedFederatedSingleSignOnAuthorization() {
-        /// be gentle with the user
-        mAuthStatusIcon = R.drawable.progress_small;
-        mAuthStatusText = getResources().getString(R.string.auth_connecting_auth_server);
-        showAuthStatus();
-
-        /// Show SAML-based SSO web dialog
-        String targetUrl = mServerInfo.mBaseUrl
-                + AuthenticatorUrlUtils.getWebdavPath(mServerInfo.mVersion, mAuthTokenType, this);
-        SamlWebViewDialog dialog = SamlWebViewDialog.newInstance(targetUrl, targetUrl);
-        dialog.show(getSupportFragmentManager(), SAML_DIALOG_TAG);
-    }
-
-    /**
-     * Callback method invoked when a RemoteOperation executed by this Activity finishes.
-     *
-     * Dispatches the operation flow to the right method.
-     */
-    @Override
-    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
-
-        if (operation instanceof GetServerInfoOperation) {
-            if (operation.hashCode() == mWaitingForOpId) {
-                onGetServerInfoFinish(result);
-            }   // else nothing ; only the last check operation is considered; 
-            // multiple can be started if the user amends a URL quickly
-
-        } else if (operation instanceof OAuth2GetAccessToken) {
-            onGetOAuthAccessTokenFinish(result);
-
-        } else if (operation instanceof GetRemoteUserInfoOperation) {
-            onGetUserNameFinish(result);
-        }
-
-    }
-
-    private void onGetUserNameFinish(RemoteOperationResult result) {
-        mWaitingForOpId = Long.MAX_VALUE;
-        if (result.isSuccess()) {
-            boolean success = false;
-            String username;
-            if (result.getData().get(0) instanceof UserInfo) {
-                username = ((UserInfo) result.getData().get(0)).getDisplayName();
-            } else {
-                username = (String) result.getData().get(0);
-            }
-
-            if (mAction == ACTION_CREATE) {
-                if (!webViewLoginMethod) {
-                    mUsernameInput.setText(username);
-                }
-                success = createAccount(result);
-            } else {
-
-                if (!webViewLoginMethod && !mUsernameInput.getText().toString().trim().equals(username)) {
-                    // fail - not a new account, but an existing one; disallow
-                    result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_THE_SAME);
-                    mAuthToken = "";
-                    updateAuthStatusIconAndText(result);
-                    showAuthStatus();
-                    Log_OC.d(TAG, result.getLogMessage());
-                } else {
-                    try {
-                        updateAccountAuthentication();
-                        success = true;
-
-                    } catch (AccountNotFoundException e) {
-                        Log_OC.e(TAG, "Account " + mAccount + " was removed!", e);
-                        DisplayUtils.showSnackMessage(findViewById(R.id.scroll), R.string.auth_account_does_not_exist);
-                        finish();
-                    }
-                }
-            }
-
-            if (success) {
-                finish();
-            }
-        } else {
-            if (!webViewLoginMethod) {
-                int statusText = result.getCode() == ResultCode.MAINTENANCE_MODE ? R.string.maintenance_mode : R.string.auth_fail_get_user_name;
-                updateStatusIconFailUserName(statusText);
-                showAuthStatus();
-            }
-            Log_OC.e(TAG, "Access to user name failed: " + result.getLogMessage());
-        }
-
-    }
-
-    /**
-     * Processes the result of the server check performed when the user finishes the enter of the
-     * server URL.
-     *
-     * @param result Result of the check.
-     */
-    private void onGetServerInfoFinish(RemoteOperationResult result) {
-        /// update activity state
-        mServerIsChecked = true;
-        mWaitingForOpId = Long.MAX_VALUE;
-
-        // update server status, but don't show it yet
-        if (!webViewLoginMethod) {
-            updateServerStatusIconAndText(result);
-        }
-
-        if (result.isSuccess()) {
-            /// SUCCESS means:
-            //      1. connection succeeded, and we know if it's SSL or not
-            //      2. server is installed
-            //      3. we got the server version
-            //      4. we got the authentication method required by the server 
-            mServerInfo = (GetServerInfoOperation.ServerInfo) (result.getData().get(0));
-
-            // show outdated warning
-            if (getResources().getBoolean(R.bool.show_outdated_server_warning) &&
-                    mServerInfo.mVersion.compareTo(MainApp.OUTDATED_SERVER_VERSION) < 0) {
-                DisplayUtils.showServerOutdatedSnackbar(this);
-            }
-
-            webViewLoginMethod = mServerInfo.mVersion.isWebLoginSupported() && !forceOldLoginMethod;
-
-            if (webViewUser != null && !webViewUser.isEmpty() &&
-                    webViewPassword != null && !webViewPassword.isEmpty()) {
-                checkBasicAuthorization(webViewUser, webViewPassword);
-            } else if (webViewLoginMethod) {
-                // hide old login
-                setOldLoginVisibility(View.GONE);
-
-                setContentView(R.layout.account_setup_webview);
-                mLoginWebView = findViewById(R.id.login_webview);
-                initWebViewLogin(mServerInfo.mBaseUrl);
-            } else {
-                // show old login
-                setOldLoginVisibility(View.VISIBLE);
-            }
-
-            if (!authSupported(mServerInfo.mAuthMethod)) {
-
-                if (!webViewLoginMethod) {
-                    // overrides updateServerStatusIconAndText()
-                    updateServerStatusIconNoRegularAuth();
-                }
-                mServerIsValid = false;
-
-            } else {
-                mServerIsValid = true;
-            }
-
-        } else {
-            mServerIsValid = false;
-        }
-
-        // refresh UI
-        if (!webViewLoginMethod) {
-            showRefreshButton(!mServerIsValid);
-            showServerStatus();
-            mOkButton.setEnabled(mServerIsValid);
-        }
-
-        if (!mServerIsValid) {
-            // hide old login
-            setOldLoginVisibility(View.GONE);
-        }
-
-        /// very special case (TODO: move to a common place for all the remote operations)
-        if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {
-            showUntrustedCertDialog(result);
-        }
-    }
-
-    private void setOldLoginVisibility(int visible) {
-        mOkButton.setVisibility(visible);
-        mUsernameInputLayout.setVisibility(visible);
-        mPasswordInputLayout.setVisibility(visible);
-    }
-
-    private boolean authSupported(AuthenticationMethod authMethod) {
-        return ((basicTokenType.equals(mAuthTokenType) &&
-                AuthenticationMethod.BASIC_HTTP_AUTH.equals(authMethod)) ||
-                (oauthTokenType.equals(mAuthTokenType) &&
-                        AuthenticationMethod.BEARER_TOKEN.equals(authMethod)) ||
-                (samlTokenType.equals(mAuthTokenType) &&
-                        AuthenticationMethod.SAML_WEB_SSO.equals(authMethod))
-        );
-    }
-
-    /**
-     * Chooses the right icon and text to show to the user for the received operation result.
-     *
-     * @param result Result of a remote operation performed in this activity
-     */
-    private void updateServerStatusIconAndText(RemoteOperationResult result) {
-        mServerStatusIcon = R.drawable.ic_alert;    // the most common case in the switch below
-
-        switch (result.getCode()) {
-            case OK_SSL:
-                mServerStatusIcon = R.drawable.ic_lock_white;
-                mServerStatusText = getResources().getString(R.string.auth_secure_connection);
-                break;
-
-            case OK_NO_SSL:
-            case OK:
-                if (mHostUrlInput.getText().toString().trim().toLowerCase(Locale.ROOT).startsWith(HTTP_PROTOCOL)) {
-                    mServerStatusText = getResources().getString(R.string.auth_connection_established);
-                    mServerStatusIcon = R.drawable.ic_ok;
-                } else {
-                    mServerStatusText = getResources().getString(R.string.auth_nossl_plain_ok_title);
-                    mServerStatusIcon = R.drawable.ic_lock_open_white;
-                }
-                break;
-
-            case NO_NETWORK_CONNECTION:
-                mServerStatusIcon = R.drawable.no_network;
-                mServerStatusText = getResources().getString(R.string.auth_no_net_conn_title);
-                break;
-
-            case SSL_RECOVERABLE_PEER_UNVERIFIED:
-                mServerStatusText = getResources().getString(R.string.auth_ssl_unverified_server_title);
-                break;
-            case BAD_OC_VERSION:
-                mServerStatusText = getResources().getString(R.string.auth_bad_oc_version_title);
-                break;
-            case WRONG_CONNECTION:
-                mServerStatusText = getResources().getString(R.string.auth_wrong_connection_title);
-                break;
-            case TIMEOUT:
-                mServerStatusText = getResources().getString(R.string.auth_timeout_title);
-                break;
-            case INCORRECT_ADDRESS:
-                mServerStatusText = getResources().getString(R.string.auth_incorrect_address_title);
-                break;
-            case SSL_ERROR:
-                mServerStatusText = getResources().getString(R.string.auth_ssl_general_error_title);
-                break;
-            case UNAUTHORIZED:
-                mServerStatusText = getResources().getString(R.string.auth_unauthorized);
-                break;
-            case HOST_NOT_AVAILABLE:
-                mServerStatusText = getResources().getString(R.string.auth_unknown_host_title);
-                break;
-            case INSTANCE_NOT_CONFIGURED:
-                mServerStatusText = getResources().getString(R.string.auth_not_configured_title);
-                break;
-            case FILE_NOT_FOUND:
-                mServerStatusText = getResources().getString(R.string.auth_incorrect_path_title);
-                break;
-            case OAUTH2_ERROR:
-                mServerStatusText = getResources().getString(R.string.auth_oauth_error);
-                break;
-            case OAUTH2_ERROR_ACCESS_DENIED:
-                mServerStatusText = getResources().getString(R.string.auth_oauth_error_access_denied);
-                break;
-            case UNHANDLED_HTTP_CODE:
-                mServerStatusText = getResources().getString(R.string.auth_unknown_error_http_title);
-                break;
-            case UNKNOWN_ERROR:
-                if (result.getException() != null &&
-                        !TextUtils.isEmpty(result.getException().getMessage())) {
-                    mServerStatusText = getResources().getString(
-                            R.string.auth_unknown_error_exception_title,
-                            result.getException().getMessage()
-                    );
-                } else {
-                    mServerStatusText = getResources().getString(R.string.auth_unknown_error_title);
-                }
-                break;
-            case OK_REDIRECT_TO_NON_SECURE_CONNECTION:
-                mServerStatusIcon = R.drawable.ic_lock_open_white;
-                mServerStatusText = getResources().getString(R.string.auth_redirect_non_secure_connection_title);
-                break;
-            case MAINTENANCE_MODE:
-                mServerStatusText = getResources().getString(R.string.maintenance_mode);
-                break;
-            case UNTRUSTED_DOMAIN:
-                mServerStatusText = getResources().getString(R.string.untrusted_domain);
-                break;
-            default:
-                mServerStatusText = "";
-                mServerStatusIcon = 0;
-                break;
-        }
-    }
-
-
-    /**
-     * Chooses the right icon and text to show to the user for the received operation result.
-     *
-     * @param result Result of a remote operation performed in this activity
-     */
-    private void updateAuthStatusIconAndText(RemoteOperationResult result) {
-        mAuthStatusIcon = R.drawable.ic_alert;    // the most common case in the switch below
-
-        switch (result.getCode()) {
-            case OK_SSL:
-                mAuthStatusIcon = R.drawable.ic_lock_white;
-                mAuthStatusText = getResources().getString(R.string.auth_secure_connection);
-                break;
-
-            case OK_NO_SSL:
-            case OK:
-                if (mHostUrlInput.getText().toString().trim().toLowerCase(Locale.ROOT).startsWith(HTTP_PROTOCOL)) {
-                    mAuthStatusText = getResources().getString(R.string.auth_connection_established);
-                    mAuthStatusIcon = R.drawable.ic_ok;
-                } else {
-                    mAuthStatusText = getResources().getString(R.string.auth_nossl_plain_ok_title);
-                    mAuthStatusIcon = R.drawable.ic_lock_open_white;
-                }
-                break;
-
-            case NO_NETWORK_CONNECTION:
-                mAuthStatusIcon = R.drawable.no_network;
-                mAuthStatusText = getResources().getString(R.string.auth_no_net_conn_title);
-                break;
-
-            case SSL_RECOVERABLE_PEER_UNVERIFIED:
-                mAuthStatusText = getResources().getString(R.string.auth_ssl_unverified_server_title);
-                break;
-            case TIMEOUT:
-                mAuthStatusText = getResources().getString(R.string.auth_timeout_title);
-                break;
-            case HOST_NOT_AVAILABLE:
-                mAuthStatusText = getResources().getString(R.string.auth_unknown_host_title);
-                break;
-            case UNHANDLED_HTTP_CODE:
-            default:
-                mAuthStatusText = ErrorMessageAdapter.getErrorCauseMessage(result, null, getResources());
-        }
-    }
-
-    private void updateStatusIconFailUserName(int failedStatusText) {
-        mAuthStatusIcon = R.drawable.ic_alert;
-        mAuthStatusText = getResources().getString(failedStatusText);
-    }
-
-    private void updateServerStatusIconNoRegularAuth() {
-        mServerStatusIcon = R.drawable.ic_alert;
-        mServerStatusText = getResources().getString(R.string.auth_can_not_auth_against_server);
-    }
-
-    /**
-     * Processes the result of the request for and access token send
-     * to an OAuth authorization server.
-     *
-     * @param result Result of the operation.
-     */
-    private void onGetOAuthAccessTokenFinish(RemoteOperationResult result) {
-        mWaitingForOpId = Long.MAX_VALUE;
-        dismissDialog(WAIT_DIALOG_TAG);
-
-        if (result.isSuccess()) {
-            /// be gentle with the user
-            IndeterminateProgressDialog dialog =
-                    IndeterminateProgressDialog.newInstance(R.string.auth_trying_to_login, true);
-            dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);
-
-            /// time to test the retrieved access token on the ownCloud server
-            @SuppressWarnings("unchecked")
-            Map<String, String> tokens = (Map<String, String>) (result.getData().get(0));
-            mAuthToken = tokens.get(OAuth2Constants.KEY_ACCESS_TOKEN);
-            Log_OC.d(TAG, "Got ACCESS TOKEN: " + mAuthToken);
-
-            /// validate token accessing to root folder / getting session
-            OwnCloudCredentials credentials = OwnCloudCredentialsFactory.newBearerCredentials(
-                    mAuthToken);
-            accessRootFolder(credentials);
-
-        } else {
-            updateAuthStatusIconAndText(result);
-            showAuthStatus();
-            Log_OC.d(TAG, "Access failed: " + result.getLogMessage());
-        }
-    }
-
-
-    /**
-     * Processes the result of the access check performed to try the user credentials.
-     *
-     * Creates a new account through the AccountManager.
-     *
-     * @param result Result of the operation.
-     */
-    @Override
-    public void onAuthenticatorTaskCallback(RemoteOperationResult result) {
-        mWaitingForOpId = Long.MAX_VALUE;
-        dismissDialog(WAIT_DIALOG_TAG);
-        mAsyncTask = null;
-
-        if (result.isSuccess()) {
-            Log_OC.d(TAG, "Successful access - time to save the account");
-
-            boolean success = false;
-
-            if (mAction == ACTION_CREATE) {
-                success = createAccount(result);
-
-            } else {
-                try {
-                    updateAccountAuthentication();
-                    success = true;
-
-                } catch (AccountNotFoundException e) {
-                    Log_OC.e(TAG, "Account " + mAccount + " was removed!", e);
-                    DisplayUtils.showSnackMessage(findViewById(R.id.scroll), R.string.auth_account_does_not_exist);
-                    finish();
-                }
-            }
-
-            // Reset webView
-            webViewPassword = null;
-            webViewUser = null;
-            forceOldLoginMethod = false;
-            deleteCookies();
-
-            if (success) {
-                finish();
-            } else {
-                // init webView again
-                if (mLoginWebView != null) {
-                    mLoginWebView.setVisibility(View.GONE);
-                }
-                setContentView(R.layout.account_setup);
-
-                initOverallUi();
-
-                CustomEditText serverAddressField = findViewById(R.id.hostUrlInput);
-                serverAddressField.setText(mServerInfo.mBaseUrl);
-
-                findViewById(R.id.oauth_onOff_check).setVisibility(View.GONE);
-                findViewById(R.id.server_status_text).setVisibility(View.GONE);
-                mAuthStatusView = findViewById(R.id.auth_status_text);
-
-                showAuthStatus();
-            }
-
-        } else if (result.isServerFail() || result.isException()) {
-            /// server errors or exceptions in authorization take to requiring a new check of 
-            /// the server
-            mServerIsChecked = true;
-            mServerIsValid = false;
-            mServerInfo = new GetServerInfoOperation.ServerInfo();
-
-            // update status icon and text
-            updateServerStatusIconAndText(result);
-            showServerStatus();
-            mAuthStatusIcon = 0;
-            mAuthStatusText = "";
-            if (!webViewLoginMethod) {
-                showAuthStatus();
-
-                // update input controls state
-                showRefreshButton(true);
-                mOkButton.setEnabled(false);
-            }
-
-            // very special case (TODO: move to a common place for all the remote operations)
-            if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {
-                showUntrustedCertDialog(result);
-            }
-
-        } else {    // authorization fail due to client side - probably wrong credentials
-            if (webViewLoginMethod) {
-                mLoginWebView = findViewById(R.id.login_webview);
-                initWebViewLogin(mServerInfo.mBaseUrl);
-
-                DisplayUtils.showSnackMessage(this, mLoginWebView, R.string.auth_access_failed, result.getLogMessage());
-            } else {
-                updateAuthStatusIconAndText(result);
-                showAuthStatus();
-            }
-            // reset webview
-            webViewPassword = null;
-            webViewUser = null;
-            deleteCookies();
-
-            Log_OC.d(TAG, "Access failed: " + result.getLogMessage());
-        }
-    }
-
-
-    /**
-     * Updates the authentication token.
-     *
-     * Sets the proper response so that the AccountAuthenticator that started this activity
-     * saves a new authorization token for mAccount.
-     *
-     * Kills the session kept by OwnCloudClientManager so that a new one will created with
-     * the new credentials when needed.
-     */
-    private void updateAccountAuthentication() throws AccountNotFoundException {
-        String accountType = MainApp.getAccountType(this);
-
-        Bundle response = new Bundle();
-        response.putString(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);
-        response.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccount.type);
-
-        if (AccountTypeUtils.getAuthTokenTypeAccessToken(accountType).equals(mAuthTokenType)) {
-            response.putString(AccountManager.KEY_AUTHTOKEN, mAuthToken);
-            // the next line is necessary, notifications are calling directly to the 
-            // AuthenticatorActivity to update, without AccountManager intervention
-            mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);
-
-        } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(accountType).equals(mAuthTokenType)) {
-            response.putString(AccountManager.KEY_AUTHTOKEN, mAuthToken);
-            // the next line is necessary; by now, notifications are calling directly to the 
-            // AuthenticatorActivity to update, without AccountManager intervention
-            mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);
-
-        } else {
-            if (!webViewLoginMethod) {
-                response.putString(AccountManager.KEY_AUTHTOKEN, mPasswordInput.getText().toString());
-                mAccountMgr.setPassword(mAccount, mPasswordInput.getText().toString());
-            } else {
-                response.putString(AccountManager.KEY_AUTHTOKEN, webViewPassword);
-                mAccountMgr.setPassword(mAccount, webViewPassword);
-            }
-        }
-
-        // remove managed clients for this account to enforce creation with fresh credentials
-        OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, this);
-        OwnCloudClientManagerFactory.getDefaultSingleton().removeClientFor(ocAccount);
-
-        setAccountAuthenticatorResult(response);
-        final Intent intent = new Intent();
-        intent.putExtras(response);
-        setResult(RESULT_OK, intent);
-
-    }
-
-
-    /**
-     * Creates a new account through the Account Authenticator that started this activity.
-     *
-     * This makes the account permanent.
-     *
-     * TODO Decide how to name the OAuth accounts
-     */
-    @SuppressFBWarnings("DMI")
-    private boolean createAccount(RemoteOperationResult authResult) {
-        String accountType = MainApp.getAccountType(this);
-
-        // create and save new ownCloud account
-        boolean isOAuth = AccountTypeUtils.getAuthTokenTypeAccessToken(accountType).equals(mAuthTokenType);
-        boolean isSaml = AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(accountType).equals(mAuthTokenType);
-
-        String lastPermanentLocation = authResult.getLastPermanentLocation();
-        if (lastPermanentLocation != null) {
-            mServerInfo.mBaseUrl = AuthenticatorUrlUtils.trimWebdavSuffix(lastPermanentLocation);
-        }
-
-        Uri uri = Uri.parse(mServerInfo.mBaseUrl);
-        String username;
-        if (!webViewLoginMethod) {
-            username = mUsernameInput.getText().toString().trim();
-        } else {
-            username = webViewUser;
-        }
-        if (isOAuth) {
-            username = "OAuth_user" + (new java.util.Random(System.currentTimeMillis())).nextLong();
-        }
-
-        String accountName = com.owncloud.android.lib.common.accounts.AccountUtils.buildAccountName(uri, username);
-        Account newAccount = new Account(accountName, accountType);
-        if (AccountUtils.exists(newAccount, getApplicationContext())) {
-            // fail - not a new account, but an existing one; disallow
-            RemoteOperationResult result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_NEW);
-
-            updateAuthStatusIconAndText(result);
-            showAuthStatus();
-
-            Log_OC.d(TAG, result.getLogMessage());
-            return false;
-
-        } else {
-            mAccount = newAccount;
-
-            if (isOAuth || isSaml) {
-                // with external authorizations, the password is never input in the app
-                mAccountMgr.addAccountExplicitly(mAccount, "", null);
-            } else {
-                if (!webViewLoginMethod) {
-                    mAccountMgr.addAccountExplicitly(mAccount, mPasswordInput.getText().toString(), null);
-                } else {
-                    mAccountMgr.addAccountExplicitly(mAccount, webViewPassword, null);
-                }
-            }
-
-            // include account version with the new account
-            mAccountMgr.setUserData(mAccount, Constants.KEY_OC_ACCOUNT_VERSION,
-                    Integer.toString(AccountUtils.ACCOUNT_VERSION));
-
-            /// add the new account as default in preferences, if there is none already
-            Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this);
-            if (defaultAccount == null) {
-                SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
-                editor.putString("select_oc_account", accountName);
-                editor.apply();
-            }
-
-            /// prepare result to return to the Authenticator
-            //  TODO check again what the Authenticator makes with it; probably has the same 
-            //  effect as addAccountExplicitly, but it's not well done
-            final Intent intent = new Intent();
-            intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, accountType);
-            intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);
-            intent.putExtra(AccountManager.KEY_USERDATA, username);
-            if (isOAuth || isSaml) {
-                mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);
-            }
-            /// add user data to the new account; TODO probably can be done in the last parameter 
-            //      addAccountExplicitly, or in KEY_USERDATA
-            mAccountMgr.setUserData(mAccount, Constants.KEY_OC_VERSION, mServerInfo.mVersion.getVersion());
-            mAccountMgr.setUserData(mAccount, Constants.KEY_OC_BASE_URL, mServerInfo.mBaseUrl);
-
-            if (authResult.getData() != null) {
-                try {
-                    UserInfo userInfo = (UserInfo) authResult.getData().get(0);
-                    mAccountMgr.setUserData(mAccount, Constants.KEY_DISPLAY_NAME, userInfo.getDisplayName());
-                    mAccountMgr.setUserData(mAccount, Constants.KEY_USER_ID, userInfo.getId());
-                } catch (ClassCastException c) {
-                    Log_OC.w(TAG, "Couldn't get display name for " + username);
-                }
-            } else {
-                Log_OC.w(TAG, "Couldn't get display name for " + username);
-            }
-
-            if (isSaml) {
-                mAccountMgr.setUserData(mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO, "TRUE");
-            } else if (isOAuth) {
-                mAccountMgr.setUserData(mAccount, Constants.KEY_SUPPORTS_OAUTH2, "TRUE");
-            }
-
-            setAccountAuthenticatorResult(intent.getExtras());
-            setResult(RESULT_OK, intent);
-
-            return true;
-        }
-    }
-
-
-    /**
-     * Starts and activity to open the 'new account' page in the ownCloud web site
-     *
-     * @param view 'Account register' button
-     */
-    public void onRegisterClick(View view) {
-        Intent register = new Intent(
-                Intent.ACTION_VIEW, Uri.parse(getString(R.string.welcome_link_url))
-        );
-        setResult(RESULT_CANCELED);
-        startActivity(register);
-    }
-
-
-    /**
-     * Updates the content and visibility state of the icon and text associated
-     * to the last check on the ownCloud server.
-     */
-    private void showServerStatus() {
-        if (mServerStatusIcon == 0 && "".equals(mServerStatusText)) {
-            mServerStatusView.setVisibility(View.INVISIBLE);
-        } else {
-            mServerStatusView.setText(mServerStatusText);
-            mServerStatusView.setCompoundDrawablesWithIntrinsicBounds(mServerStatusIcon, 0, 0, 0);
-            mServerStatusView.setVisibility(View.VISIBLE);
-        }
-    }
-
-
-    /**
-     * Updates the content and visibility state of the icon and text associated
-     * to the interactions with the OAuth authorization server.
-     */
-    private void showAuthStatus() {
-        if (mAuthStatusIcon == 0 && "".equals(mAuthStatusText)) {
-            mAuthStatusView.setVisibility(View.INVISIBLE);
-        } else {
-            mAuthStatusView.setText(mAuthStatusText);
-            mAuthStatusView.setCompoundDrawablesWithIntrinsicBounds(mAuthStatusIcon, 0, 0, 0);
-            mAuthStatusView.setVisibility(View.VISIBLE);
-        }
-    }
-
-
-    private void showRefreshButton(boolean show) {
-        if (webViewLoginMethod && mRefreshButton != null) {
-            if (show) {
-                mRefreshButton.setVisibility(View.VISIBLE);
-            } else {
-                mRefreshButton.setVisibility(View.GONE);
-            }
-        }
-    }
-
-    /**
-     * Called when the eye icon in the password field is clicked.
-     *
-     * Toggles the visibility of the password in the field.
-     */
-    public void onViewPasswordClick() {
-        int selectionStart = mPasswordInput.getSelectionStart();
-        int selectionEnd = mPasswordInput.getSelectionEnd();
-        if (isPasswordVisible()) {
-            hidePassword();
-        } else {
-            showPassword();
-        }
-        mPasswordInput.setSelection(selectionStart, selectionEnd);
-    }
-
-
-    /**
-     * Called when the checkbox for OAuth authorization is clicked.
-     *
-     * Hides or shows the input fields for user & password.
-     *
-     * @param view 'View password' 'button'
-     */
-    public void onCheckClick(View view) {
-        CheckBox oAuth2Check = (CheckBox) view;
-        if (oAuth2Check.isChecked()) {
-            mAuthTokenType = oauthTokenType;
-        } else {
-            mAuthTokenType = basicTokenType;
-        }
-        updateAuthenticationPreFragmentVisibility();
-    }
-
-
-    /**
-     * Called when the 'action' button in an IME is pressed ('enter' in software keyboard).
-     * 
-     * Used to trigger the authentication check when the user presses 'enter' after writing the
-     * password, or to throw the server test when the only field on screen is the URL input field.
-     */
-    @Override
-    public boolean onEditorAction(TextView inputField, int actionId, KeyEvent event) {
-        if (actionId == EditorInfo.IME_ACTION_DONE && inputField != null &&
-                inputField.equals(mPasswordInput)) {
-            if (mOkButton.isEnabled()) {
-                mOkButton.performClick();
-            }
-
-        } else if (actionId == EditorInfo.IME_ACTION_NEXT && inputField != null &&
-                inputField.equals(mHostUrlInput)) {
-            checkOcServer();
-        }
-        return false;   // always return false to grant that the software keyboard is hidden anyway
-    }
-
-
-    private abstract static class RightDrawableOnTouchListener implements OnTouchListener {
-
-        private int fuzz = 75;
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public boolean onTouch(View view, MotionEvent event) {
-            Drawable rightDrawable = null;
-            if (view instanceof TextView) {
-                Drawable[] drawables = ((TextView) view).getCompoundDrawables();
-                if (drawables.length > 2) {
-                    rightDrawable = drawables[2];
-                }
-            }
-            if (rightDrawable != null) {
-                final int x = (int) event.getX();
-                final int y = (int) event.getY();
-                final Rect bounds = rightDrawable.getBounds();
-                if (x >= (view.getRight() - bounds.width() - fuzz) &&
-                        x <= (view.getRight() - view.getPaddingRight() + fuzz) &&
-                        y >= (view.getPaddingTop() - fuzz) &&
-                        y <= (view.getHeight() - view.getPaddingBottom()) + fuzz) {
-
-                    return onDrawableTouch(event);
-                }
-            }
-            return false;
-        }
-
-        public abstract boolean onDrawableTouch(final MotionEvent event);
-    }
-
-
-    private void getRemoteUserNameOperation(String sessionCookie) {
-
-        Intent getUserNameIntent = new Intent();
-        getUserNameIntent.setAction(OperationsService.ACTION_GET_USER_NAME);
-        getUserNameIntent.putExtra(OperationsService.EXTRA_SERVER_URL, mServerInfo.mBaseUrl);
-        getUserNameIntent.putExtra(OperationsService.EXTRA_COOKIE, sessionCookie);
-
-        if (mOperationsServiceBinder != null) {
-            mWaitingForOpId = mOperationsServiceBinder.queueNewOperation(getUserNameIntent);
-        }
-    }
-
-
-    @Override
-    public void onSsoFinished(String sessionCookie) {
-        if (sessionCookie != null && sessionCookie.length() > 0) {
-            Log_OC.d(TAG, "Successful SSO - time to save the account");
-            mAuthToken = sessionCookie;
-            getRemoteUserNameOperation(sessionCookie);
-            Fragment fd = getSupportFragmentManager().findFragmentByTag(SAML_DIALOG_TAG);
-            if (fd instanceof DialogFragment) {
-                Dialog d = ((DialogFragment) fd).getDialog();
-                if (d != null && d.isShowing()) {
-                    d.dismiss();
-                }
-            }
-
-        } else {
-            // TODO - show fail
-            Log_OC.d(TAG, "SSO failed");
-        }
-
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType(this)).equals(mAuthTokenType) &&
-                mHostUrlInput.hasFocus() && event.getAction() == MotionEvent.ACTION_DOWN) {
-            checkOcServer();
-        }
-        return super.onTouchEvent(event);
-    }
-
-
-    /**
-     * Show untrusted cert dialog
-     */
-    public void showUntrustedCertDialog(X509Certificate x509Certificate, SslError error, SslErrorHandler handler) {
-        // Show a dialog with the certificate info
-        SslUntrustedCertDialog dialog;
-        if (x509Certificate == null) {
-            dialog = SslUntrustedCertDialog.newInstanceForEmptySslError(error, handler);
-        } else {
-            dialog = SslUntrustedCertDialog.newInstanceForFullSslError(x509Certificate, error, handler);
-        }
-        FragmentManager fm = getSupportFragmentManager();
-        FragmentTransaction ft = fm.beginTransaction();
-        ft.addToBackStack(null);
-        dialog.show(ft, UNTRUSTED_CERT_DIALOG_TAG);
-    }
-
-
-    /**
-     * Show untrusted cert dialog
-     */
-    private void showUntrustedCertDialog(RemoteOperationResult result) {
-        // Show a dialog with the certificate info
-        SslUntrustedCertDialog dialog = SslUntrustedCertDialog.
-                newInstanceForFullSslError((CertificateCombinedException) result.getException());
-        FragmentManager fm = getSupportFragmentManager();
-        FragmentTransaction ft = fm.beginTransaction();
-        ft.addToBackStack(null);
-        dialog.show(ft, UNTRUSTED_CERT_DIALOG_TAG);
-
-    }
-
-    /**
-     * Called from SslValidatorDialog when a new server certificate was correctly saved.
-     */
-    public void onSavedCertificate() {
-        Fragment fd = getSupportFragmentManager().findFragmentByTag(SAML_DIALOG_TAG);
-        if (fd == null) {
-            // if SAML dialog is not shown, 
-            // the SslDialog was shown due to an SSL error in the server check
-            checkOcServer();
-        }
-    }
-
-    /**
-     * Called from SslValidatorDialog when a new server certificate could not be saved
-     * when the user requested it.
-     */
-    @Override
-    public void onFailedSavingCertificate() {
-        dismissDialog(SAML_DIALOG_TAG);
-        DisplayUtils.showSnackMessage(this, R.string.ssl_validator_not_saved);
-    }
-
-    @Override
-    public void onCancelCertificate() {
-        dismissDialog(SAML_DIALOG_TAG);
-    }
-
-
-    private void doOnResumeAndBound() {
-        //Log_OC.e(TAG, "registering to listen for operation callbacks" );
-        mOperationsServiceBinder.addOperationListener(AuthenticatorActivity.this, mHandler);
-        if (mWaitingForOpId <= Integer.MAX_VALUE) {
-            mOperationsServiceBinder.dispatchResultIfFinished((int) mWaitingForOpId, this);
-        }
-
-        if (!webViewLoginMethod && mHostUrlInput.getText() != null && mHostUrlInput.getText().length() > 0
-                && !mServerIsChecked) {
-            checkOcServer();
-        }
-    }
-
-
-    private void dismissDialog(String dialogTag) {
-        Fragment frag = getSupportFragmentManager().findFragmentByTag(dialogTag);
-        if (frag instanceof DialogFragment) {
-            DialogFragment dialog = (DialogFragment) frag;
-
-            try {
-                dialog.dismiss();
-            } catch (IllegalStateException e) {
-                Log_OC.e(TAG, e.getMessage());
-                dialog.dismissAllowingStateLoss();
-            }
-        }
-    }
-
-
-    /**
-     * Implements callback methods for service binding.
-     */
-    private class OperationsServiceConnection implements ServiceConnection {
-
-        @Override
-        public void onServiceConnected(ComponentName component, IBinder service) {
-            if (component.equals(
-                    new ComponentName(AuthenticatorActivity.this, OperationsService.class)
-            )) {
-                mOperationsServiceBinder = (OperationsServiceBinder) service;
-
-                doOnResumeAndBound();
-
-            }
-
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName component) {
-            if (component.equals(
-                    new ComponentName(AuthenticatorActivity.this, OperationsService.class)
-            )) {
-                Log_OC.e(TAG, "Operations service crashed");
-                mOperationsServiceBinder = null;
-            }
-        }
-    }
-
-    /**
-     * Create and show dialog for request authentication to the user
-     *
-     * @param webView Web view to embed into the authentication dialog.
-     * @param handler Object responsible for catching and recovering HTTP authentication fails.
-     */
-    public void createAuthenticationDialog(WebView webView, HttpAuthHandler handler) {
-
-        // Show a dialog with the certificate info
-        CredentialsDialogFragment dialog = CredentialsDialogFragment.newInstanceForCredentials(webView, handler);
-        FragmentManager fm = getSupportFragmentManager();
-        FragmentTransaction ft = fm.beginTransaction();
-        ft.addToBackStack(null);
-        dialog.setCancelable(false);
-        dialog.show(ft, CREDENTIALS_DIALOG_TAG);
-
-        if (!mIsFirstAuthAttempt) {
-            DisplayUtils.showSnackMessage(this, R.string.saml_authentication_wrong_pass);
-        } else {
-            mIsFirstAuthAttempt = false;
-        }
-    }
-
-    /**
-     * For retrieving the clicking on authentication cancel button.
-     */
-    public void doNegativeAuthenticationDialogClick() {
-        mIsFirstAuthAttempt = true;
-    }
-}
+/*
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
+ * @author David A. Velasco
+ * @author masensio
+ * @author Mario Danic
+ * Copyright (C) 2012  Bartek Przybylski
+ * Copyright (C) 2015 ownCloud Inc.
+ * Copyright (C) 2017 Mario Danic
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * 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/>.
+ *
+ * All changes by Mario Danic are distributed under the following terms:
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.authentication;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.annotation.SuppressLint;
+import android.app.Dialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.content.pm.ActivityInfo;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.net.http.SslError;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.preference.PreferenceManager;
+import android.support.annotation.Nullable;
+import android.support.design.widget.Snackbar;
+import android.support.design.widget.TextInputLayout;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.util.AndroidRuntimeException;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+import android.view.View.OnTouchListener;
+import android.view.inputmethod.EditorInfo;
+import android.webkit.CookieManager;
+import android.webkit.CookieSyncManager;
+import android.webkit.HttpAuthHandler;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+import com.owncloud.android.MainApp;
+import com.owncloud.android.R;
+import com.owncloud.android.authentication.SsoWebViewClient.SsoWebViewClientListener;
+import com.owncloud.android.lib.common.OwnCloudAccount;
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
+import com.owncloud.android.lib.common.OwnCloudCredentials;
+import com.owncloud.android.lib.common.OwnCloudCredentialsFactory;
+import com.owncloud.android.lib.common.UserInfo;
+import com.owncloud.android.lib.common.accounts.AccountTypeUtils;
+import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
+import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
+import com.owncloud.android.lib.common.network.CertificateCombinedException;
+import com.owncloud.android.lib.common.network.NetworkUtils;
+import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.status.OwnCloudVersion;
+import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation;
+import com.owncloud.android.operations.DetectAuthenticationMethodOperation.AuthenticationMethod;
+import com.owncloud.android.operations.GetServerInfoOperation;
+import com.owncloud.android.operations.OAuth2GetAccessToken;
+import com.owncloud.android.services.OperationsService;
+import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
+import com.owncloud.android.ui.activity.FirstRunActivity;
+import com.owncloud.android.ui.components.CustomEditText;
+import com.owncloud.android.ui.dialog.CredentialsDialogFragment;
+import com.owncloud.android.ui.dialog.IndeterminateProgressDialog;
+import com.owncloud.android.ui.dialog.SamlWebViewDialog;
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener;
+import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.ErrorMessageAdapter;
+
+import java.io.InputStream;
+import java.net.URLDecoder;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * This Activity is used to add an ownCloud account to the App
+ */
+public class AuthenticatorActivity extends AccountAuthenticatorActivity
+        implements OnRemoteOperationListener, OnFocusChangeListener, OnEditorActionListener,
+        SsoWebViewClientListener, OnSslUntrustedCertListener,
+        AuthenticatorAsyncTask.OnAuthenticatorTaskListener {
+
+    private static final String TAG = AuthenticatorActivity.class.getSimpleName();
+
+    public static final String EXTRA_ACTION = "ACTION";
+    public static final String EXTRA_ACCOUNT = "ACCOUNT";
+    public static final String EXTRA_USE_PROVIDER_AS_WEBLOGIN = "USE_PROVIDER_AS_WEBLOGIN";
+
+    private static final String KEY_AUTH_TOKEN_TYPE = "AUTH_TOKEN_TYPE";
+
+    private static final String KEY_HOST_URL_TEXT = "HOST_URL_TEXT";
+    private static final String KEY_OC_VERSION = "OC_VERSION";
+    private static final String KEY_SERVER_VALID = "SERVER_VALID";
+    private static final String KEY_SERVER_CHECKED = "SERVER_CHECKED";
+    private static final String KEY_SERVER_STATUS_TEXT = "SERVER_STATUS_TEXT";
+    private static final String KEY_SERVER_STATUS_ICON = "SERVER_STATUS_ICON";
+    private static final String KEY_IS_SSL_CONN = "IS_SSL_CONN";
+    private static final String KEY_PASSWORD_EXPOSED = "PASSWORD_VISIBLE";
+    private static final String KEY_AUTH_STATUS_TEXT = "AUTH_STATUS_TEXT";
+    private static final String KEY_AUTH_STATUS_ICON = "AUTH_STATUS_ICON";
+    private static final String KEY_SERVER_AUTH_METHOD = "SERVER_AUTH_METHOD";
+    private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";
+    private static final String KEY_AUTH_TOKEN = "AUTH_TOKEN";
+
+    private static final String AUTH_ON = "on";
+    private static final String AUTH_OPTIONAL = "optional";
+
+    public static final byte ACTION_CREATE = 0;
+    public static final byte ACTION_UPDATE_EXPIRED_TOKEN = 2;       // detected by the app
+
+    private static final String UNTRUSTED_CERT_DIALOG_TAG = "UNTRUSTED_CERT_DIALOG";
+    private static final String SAML_DIALOG_TAG = "SAML_DIALOG";
+    private static final String WAIT_DIALOG_TAG = "WAIT_DIALOG";
+    private static final String CREDENTIALS_DIALOG_TAG = "CREDENTIALS_DIALOG";
+    private static final String KEY_AUTH_IS_FIRST_ATTEMPT_TAG = "KEY_AUTH_IS_FIRST_ATTEMPT";
+
+    private static final String KEY_USERNAME = "USERNAME";
+    private static final String KEY_PASSWORD = "PASSWORD";
+    private static final String KEY_ASYNC_TASK_IN_PROGRESS = "AUTH_IN_PROGRESS";
+    private static final String WEB_LOGIN = "/index.php/login/flow";
+    public static final String PROTOCOL_SUFFIX = "://";
+    public static final String LOGIN_URL_DATA_KEY_VALUE_SEPARATOR = ":";
+    public static final String HTTPS_PROTOCOL = "https://";
+    public static final String HTTP_PROTOCOL = "http://";
+
+    public static final String REGULAR_SERVER_INPUT_TYPE = "regular";
+    public static final String SUBDOMAIN_SERVER_INPUT_TYPE = "prefix";
+    public static final String DIRECTORY_SERVER_INPUT_TYPE = "suffix";
+
+    /// parameters from EXTRAs in starter Intent
+    private byte mAction;
+    private Account mAccount;
+    private String mAuthTokenType;
+
+    /// activity-level references / state
+    private final Handler mHandler = new Handler();
+    private ServiceConnection mOperationsServiceConnection = null;
+    private OperationsServiceBinder mOperationsServiceBinder = null;
+    private AccountManager mAccountMgr;
+    private Uri mNewCapturedUriFromOAuth2Redirection;
+
+    /// Server PRE-Fragment elements 
+    private CustomEditText mHostUrlInput;
+    private View mRefreshButton;
+    private TextView mServerStatusView;
+
+    private TextWatcher mHostUrlInputWatcher;
+    private String mServerStatusText = "";
+    private int mServerStatusIcon;
+
+    private boolean mServerIsChecked;
+    private boolean mServerIsValid;
+
+    private GetServerInfoOperation.ServerInfo mServerInfo = new GetServerInfoOperation.ServerInfo();
+
+    /// Authentication PRE-Fragment elements 
+    private CheckBox mOAuth2Check;
+    private TextView mOAuthAuthEndpointText;
+    private TextView mOAuthTokenEndpointText;
+    private EditText mUsernameInput;
+    private EditText mPasswordInput;
+    private View mOkButton;
+    private TextView mAuthStatusView;
+    private ImageButton mTestServerButton;
+
+    private WebView mLoginWebView;
+
+    private String mAuthStatusText = "";
+    private int mAuthStatusIcon;
+
+    private String mAuthToken = "";
+    private AuthenticatorAsyncTask mAsyncTask;
+
+    private boolean mIsFirstAuthAttempt;
+
+    /// Identifier of operation in progress which result shouldn't be lost 
+    private long mWaitingForOpId = Long.MAX_VALUE;
+
+    private String basicTokenType;
+    private String oauthTokenType;
+    private String samlTokenType;
+
+    private boolean webViewLoginMethod;
+    private String webViewUser;
+    private String webViewPassword;
+    private TextInputLayout mUsernameInputLayout;
+    private TextInputLayout mPasswordInputLayout;
+    private boolean forceOldLoginMethod;
+
+    /**
+     * {@inheritDoc}
+     *
+     * IMPORTANT ENTRY POINT 1: activity is shown to the user
+     */
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        //Log_OC.e(TAG,  "onCreate init");
+        super.onCreate(savedInstanceState);
+
+        if (savedInstanceState == null) {
+            FirstRunActivity.runIfNeeded(this);
+        }
+        
+        basicTokenType = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType(this));
+        oauthTokenType = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType(this));
+        samlTokenType = AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType(this));
+
+        // delete cookies for webView
+        deleteCookies();
+
+        // Workaround, for fixing a problem with Android Library Support v7 19
+        //getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+        if (getSupportActionBar() != null) {
+            getSupportActionBar().hide();
+            getSupportActionBar().setDisplayHomeAsUpEnabled(false);
+            getSupportActionBar().setDisplayShowHomeEnabled(false);
+            getSupportActionBar().setDisplayShowTitleEnabled(false);
+        }
+
+        mIsFirstAuthAttempt = true;
+
+        /// init activity state
+        mAccountMgr = AccountManager.get(this);
+        mNewCapturedUriFromOAuth2Redirection = null;
+
+        /// get input values
+        mAction = getIntent().getByteExtra(EXTRA_ACTION, ACTION_CREATE);
+        mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT);
+        if (savedInstanceState == null) {
+            initAuthTokenType();
+        } else {
+            mAuthTokenType = savedInstanceState.getString(KEY_AUTH_TOKEN_TYPE);
+            mWaitingForOpId = savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID);
+            mIsFirstAuthAttempt = savedInstanceState.getBoolean(KEY_AUTH_IS_FIRST_ATTEMPT_TAG);
+        }
+
+        String webloginUrl;
+        boolean showLegacyLogin;
+        if (getIntent().getBooleanExtra(EXTRA_USE_PROVIDER_AS_WEBLOGIN, false)) {
+            webViewLoginMethod = true;
+            webloginUrl = getString(R.string.provider_registration_server);
+            showLegacyLogin = false;
+        } else {
+            webViewLoginMethod = !TextUtils.isEmpty(getResources().getString(R.string.webview_login_url));
+            webloginUrl = null;
+            showLegacyLogin = true;
+        }
+
+        if (webViewLoginMethod) {
+            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+        }
+
+        /// load user interface
+        if (!webViewLoginMethod) {
+            setContentView(R.layout.account_setup);
+
+            /// initialize general UI elements
+            initOverallUi();
+
+            findViewById(R.id.centeredRefreshButton).setOnClickListener(new View.OnClickListener() {
+
+                @Override
+                public void onClick(View v) {
+                    checkOcServer();
+                }
+            });
+
+            findViewById(R.id.embeddedRefreshButton).setOnClickListener(new View.OnClickListener() {
+
+                @Override
+                public void onClick(View v) {
+                    checkOcServer();
+                }
+            });
+
+            /// initialize block to be moved to single Fragment to check server and get info about it
+
+            /// initialize block to be moved to single Fragment to retrieve and validate credentials
+            initAuthorizationPreFragment(savedInstanceState);
+
+        } else {
+            setContentView(R.layout.account_setup_webview);
+            mLoginWebView = findViewById(R.id.login_webview);
+            initWebViewLogin(webloginUrl, showLegacyLogin);
+        }
+
+        initServerPreFragment(savedInstanceState);
+    }
+
+    private void deleteCookies() {
+        try {
+            CookieSyncManager.createInstance(this);
+            CookieManager cookieManager = CookieManager.getInstance();
+
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                cookieManager.removeAllCookies(null);
+            } else {
+                cookieManager.removeAllCookie();
+            }
+        } catch (AndroidRuntimeException e) {
+            Log_OC.e(TAG, e.getMessage());
+        }
+    }
+
+    private static String getWebLoginUserAgent() {
+        return Build.MANUFACTURER.substring(0, 1).toUpperCase(Locale.getDefault()) +
+                Build.MANUFACTURER.substring(1).toLowerCase(Locale.getDefault()) + " " + Build.MODEL;
+    }
+
+    @SuppressLint("SetJavaScriptEnabled")
+    private void initWebViewLogin(String baseURL, boolean showLegacyLogin) {
+        mLoginWebView.setVisibility(View.GONE);
+
+        final ProgressBar progressBar = findViewById(R.id.login_webview_progress_bar);
+
+        mLoginWebView.getSettings().setAllowFileAccess(false);
+        mLoginWebView.getSettings().setJavaScriptEnabled(true);
+        mLoginWebView.getSettings().setDomStorageEnabled(true);
+        mLoginWebView.getSettings().setUserAgentString(getWebLoginUserAgent());
+        mLoginWebView.getSettings().setSaveFormData(false);
+        mLoginWebView.getSettings().setSavePassword(false);
+
+        Map<String, String> headers = new HashMap<>();
+        headers.put(RemoteOperation.OCS_API_HEADER, RemoteOperation.OCS_API_HEADER_VALUE);
+
+        String url;
+        if (baseURL != null && !baseURL.isEmpty()) {
+            url = baseURL;
+        } else {
+            url = getResources().getString(R.string.webview_login_url);
+        }
+
+        mLoginWebView.loadUrl(url, headers);
+
+        setClient(progressBar);
+
+        // show snackbar after 60s to switch back to old login method
+        if (showLegacyLogin) {
+            new Handler().postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    DisplayUtils.createSnackbar(mLoginWebView, R.string.fallback_weblogin_text, Snackbar.LENGTH_INDEFINITE)
+                            .setActionTextColor(getResources().getColor(R.color.primary_dark))
+                            .setAction(R.string.fallback_weblogin_back, new View.OnClickListener() {
+                                @Override
+                                public void onClick(View v) {
+                                    mLoginWebView.setVisibility(View.INVISIBLE);
+                                    webViewLoginMethod = false;
+
+                                    setContentView(R.layout.account_setup);
+
+                                    // initialize general UI elements
+                                    initOverallUi();
+
+                                    mPasswordInputLayout.setVisibility(View.VISIBLE);
+                                    mUsernameInputLayout.setVisibility(View.VISIBLE);
+                                    mUsernameInput.requestFocus();
+                                    mOAuth2Check.setVisibility(View.INVISIBLE);
+                                    mAuthStatusView.setVisibility(View.INVISIBLE);
+                                    mServerStatusView.setVisibility(View.INVISIBLE);
+                                    mTestServerButton.setVisibility(View.INVISIBLE);
+                                    forceOldLoginMethod = true;
+                                    mOkButton.setVisibility(View.VISIBLE);
+
+                                    initServerPreFragment(null);
+
+                                    mHostUrlInput.setText(baseURL);
+
+                                    checkOcServer();
+                                }
+                            }).show();
+                }
+            }, 60 * 1000);
+        }
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (mLoginWebView != null && event.getAction() == KeyEvent.ACTION_DOWN) {
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_BACK:
+                    if (mLoginWebView.canGoBack()) {
+                        mLoginWebView.goBack();
+                    } else {
+                        finish();
+                    }
+                    return true;
+            }
+
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    private void setClient(ProgressBar progressBar) {
+        mLoginWebView.setWebViewClient(new WebViewClient() {
+            @Override
+            public boolean shouldOverrideUrlLoading(WebView view, String url) {
+                if (url.startsWith(getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/")) {
+                    parseAndLoginFromWebView(url);
+                    return true;
+                }
+                return false;
+            }
+
+            @Override
+            public void onPageFinished(WebView view, String url) {
+                super.onPageFinished(view, url);
+
+                progressBar.setVisibility(View.GONE);
+                mLoginWebView.setVisibility(View.VISIBLE);
+            }
+
+            @Override
+            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+                X509Certificate cert = SsoWebViewClient.getX509CertificateFromError(error);
+
+                try {
+                    if (cert != null && NetworkUtils.isCertInKnownServersStore(cert, getApplicationContext())) {
+                        handler.proceed();
+                    } else {
+                        showUntrustedCertDialog(cert, error, handler);
+                    }
+                } catch (Exception e) {
+                    Log_OC.e(TAG, "Cert could not be verified");
+                }
+            }
+
+            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+                progressBar.setVisibility(View.GONE);
+                mLoginWebView.setVisibility(View.VISIBLE);
+
+                InputStream resources = getResources().openRawResource(R.raw.custom_error);
+                String customError = DisplayUtils.getData(resources);
+
+                if (!customError.isEmpty()) {
+                    mLoginWebView.loadData(customError, "text/html; charset=UTF-8", null);
+                }
+            }
+        });
+    }
+
+    private void parseAndLoginFromWebView(String dataString) {
+        String prefix = getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/";
+        LoginUrlInfo loginUrlInfo = parseLoginDataUrl(prefix, dataString);
+
+        if (loginUrlInfo != null) {
+            mServerInfo.mBaseUrl = AuthenticatorUrlUtils.normalizeUrlSuffix(loginUrlInfo.serverAddress);
+            webViewUser = loginUrlInfo.username;
+            webViewPassword = loginUrlInfo.password;
+            checkOcServer();
+        }
+    }
+
+    private void populateLoginFields(String dataString) throws IllegalArgumentException {
+        // check if it is cloud://login/
+        if (dataString.startsWith(getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/")) {
+            String prefix = getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/";
+            LoginUrlInfo loginUrlInfo = parseLoginDataUrl(prefix, dataString);
+
+            if (loginUrlInfo != null) {
+                mHostUrlInput.setText(loginUrlInfo.serverAddress);
+                mUsernameInput.setText(loginUrlInfo.username);
+                mPasswordInput.setText(loginUrlInfo.password);
+
+                if (loginUrlInfo.serverAddress != null && !mServerIsChecked) {
+                    onUrlInputFocusLost();
+                }
+            }
+        }
+    }
+
+    /**
+     * parses a URI string and returns a login data object with the information from the URI string.
+     *
+     * @param prefix     URI beginning, e.g. cloud://login/
+     * @param dataString the complete URI
+     * @return login data
+     * @throws IllegalArgumentException when
+     */
+    public static LoginUrlInfo parseLoginDataUrl(String prefix, String dataString) throws IllegalArgumentException {
+        if (dataString.length() < prefix.length()) {
+            throw new IllegalArgumentException("Invalid login URL detected");
+        }
+        LoginUrlInfo loginUrlInfo = new LoginUrlInfo();
+
+        // format is basically xxx://login/server:xxx&user:xxx&password while all variables are optional
+        String data = dataString.substring(prefix.length());
+
+        // parse data
+        String[] values = data.split("&");
+
+        if (values.length < 1 || values.length > 3) {
+            // error illegal number of URL elements detected
+            throw new IllegalArgumentException("Illegal number of login URL elements detected: " + values.length);
+        }
+
+        for (String value : values) {
+            if (value.startsWith("user" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) {
+                loginUrlInfo.username = URLDecoder.decode(
+                        value.substring(("user" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length()));
+            } else if (value.startsWith("password" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) {
+                loginUrlInfo.password = URLDecoder.decode(
+                        value.substring(("password" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length()));
+            } else if (value.startsWith("server" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) {
+                loginUrlInfo.serverAddress = URLDecoder.decode(
+                        value.substring(("server" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length()));
+            } else {
+                // error illegal URL element detected
+                throw new IllegalArgumentException("Illegal magic login URL element detected: " + value);
+            }
+        }
+
+        return loginUrlInfo;
+    }
+
+    private void initAuthTokenType() {
+        mAuthTokenType = getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);
+        if (mAuthTokenType == null) {
+            if (mAccount != null) {
+                boolean oAuthRequired = mAccountMgr.getUserData(mAccount, Constants.KEY_SUPPORTS_OAUTH2) != null;
+                boolean samlWebSsoRequired = (
+                        mAccountMgr.getUserData
+                                (mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null
+                );
+                mAuthTokenType = chooseAuthTokenType(oAuthRequired, samlWebSsoRequired);
+
+            } else {
+                boolean oAuthSupported = AUTH_ON.equals(getString(R.string.auth_method_oauth2));
+                boolean samlWebSsoSupported = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso));
+                mAuthTokenType = chooseAuthTokenType(oAuthSupported, samlWebSsoSupported);
+            }
+        }
+    }
+
+    private String chooseAuthTokenType(boolean oauth, boolean saml) {
+        if (saml) {
+            return samlTokenType;
+        } else if (oauth) {
+            return oauthTokenType;
+        } else {
+            return basicTokenType;
+        }
+    }
+
+
+    /**
+     * Configures elements in the user interface under direct control of the Activity.
+     */
+    private void initOverallUi() {
+        mHostUrlInput = findViewById(R.id.hostUrlInput);
+        mUsernameInputLayout = findViewById(R.id.input_layout_account_username);
+        mPasswordInputLayout = findViewById(R.id.input_layout_account_password);
+        mPasswordInput = findViewById(R.id.account_password);
+        mUsernameInput = findViewById(R.id.account_username);
+        mAuthStatusView = findViewById(R.id.auth_status_text);
+        mOAuth2Check = findViewById(R.id.oauth_onOff_check);
+        mServerStatusView = findViewById(R.id.server_status_text);
+        mTestServerButton = findViewById(R.id.testServerButton);
+
+        mOkButton = findViewById(R.id.buttonOK);
+        mOkButton.setOnClickListener(v -> onOkClick());
+
+        setupInstructionMessage();
+
+        mTestServerButton.setVisibility(mAction == ACTION_CREATE ? View.VISIBLE : View.GONE);
+    }
+
+
+    private void setupInstructionMessage() {
+        String instructionsMessageText = calculateInstructionMessageText(mAction, mAuthTokenType);
+        TextView instructionsView = findViewById(R.id.instructions_message);
+
+        if (instructionsMessageText != null) {
+            instructionsView.setVisibility(View.VISIBLE);
+            instructionsView.setText(instructionsMessageText);
+        } else {
+            instructionsView.setVisibility(View.GONE);
+        }
+    }
+
+    @Nullable
+    private String calculateInstructionMessageText(byte action, String authTokenType) {
+        if (action == ACTION_UPDATE_EXPIRED_TOKEN) {
+            if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType(this)).equals(authTokenType)) {
+                return getString(R.string.auth_expired_oauth_token_toast);
+
+            } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType(this))
+                    .equals(authTokenType)) {
+                return getString(R.string.auth_expired_saml_sso_token_toast);
+
+            } else {
+                return getString(R.string.auth_expired_basic_auth_toast);
+            }
+        }
+
+        return null;
+    }
+
+    public void onTestServerConnectionClick(View v) {
+        checkOcServer();
+    }
+
+
+    /**
+     * @param savedInstanceState Saved activity state, as in {{@link #onCreate(Bundle)}
+     */
+    private void initServerPreFragment(Bundle savedInstanceState) {
+
+        /// step 1 - load and process relevant inputs (resources, intent, savedInstanceState)
+        boolean isUrlInputAllowed = getResources().getBoolean(R.bool.show_server_url_input);
+        if (savedInstanceState == null) {
+            if (mAccount != null) {
+                mServerInfo.mBaseUrl = mAccountMgr.getUserData(mAccount, Constants.KEY_OC_BASE_URL);
+                // TODO do next in a setter for mBaseUrl
+                mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith(HTTPS_PROTOCOL);
+                mServerInfo.mVersion = AccountUtils.getServerVersion(mAccount);
+            } else {
+                if (!webViewLoginMethod) {
+                    mServerInfo.mBaseUrl = getString(R.string.server_url).trim();
+                } else {
+                    mServerInfo.mBaseUrl = getString(R.string.webview_login_url).trim();
+                }
+                mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith(HTTPS_PROTOCOL);
+            }
+        } else {
+            mServerStatusText = savedInstanceState.getString(KEY_SERVER_STATUS_TEXT);
+            mServerStatusIcon = savedInstanceState.getInt(KEY_SERVER_STATUS_ICON);
+
+            mServerIsValid = savedInstanceState.getBoolean(KEY_SERVER_VALID);
+            mServerIsChecked = savedInstanceState.getBoolean(KEY_SERVER_CHECKED);
+
+            // TODO parcelable
+            mServerInfo.mIsSslConn = savedInstanceState.getBoolean(KEY_IS_SSL_CONN);
+            mServerInfo.mBaseUrl = savedInstanceState.getString(KEY_HOST_URL_TEXT);
+            String ocVersion = savedInstanceState.getString(KEY_OC_VERSION);
+            if (ocVersion != null) {
+                mServerInfo.mVersion = new OwnCloudVersion(ocVersion);
+            }
+            mServerInfo.mAuthMethod = AuthenticationMethod.valueOf(
+                    savedInstanceState.getString(KEY_SERVER_AUTH_METHOD));
+
+        }
+
+        if (!webViewLoginMethod) {
+            /// step 2 - set properties of UI elements (text, visibility, enabled...)
+            mHostUrlInput = findViewById(R.id.hostUrlInput);
+            // Convert IDN to Unicode
+            mHostUrlInput.setText(DisplayUtils.convertIdn(mServerInfo.mBaseUrl, false));
+            if (mAction != ACTION_CREATE) {
+                /// lock things that should not change
+                mHostUrlInput.setEnabled(false);
+                mHostUrlInput.setFocusable(false);
+            }
+            if (isUrlInputAllowed) {
+                mRefreshButton = findViewById(R.id.embeddedRefreshButton);
+            } else {
+                findViewById(R.id.hostUrlFrame).setVisibility(View.GONE);
+                mRefreshButton = findViewById(R.id.centeredRefreshButton);
+            }
+            showRefreshButton(mServerIsChecked && !mServerIsValid &&
+                    mWaitingForOpId > Integer.MAX_VALUE);
+            mServerStatusView = findViewById(R.id.server_status_text);
+            showServerStatus();
+
+            /// step 3 - bind some listeners and options
+            mHostUrlInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+            mHostUrlInput.setOnEditorActionListener(this);
+
+            /// step 4 - create listeners that will be bound at onResume
+            mHostUrlInputWatcher = new TextWatcher() {
+
+                @Override
+                public void afterTextChanged(Editable s) {
+                    if (mOkButton.isEnabled() &&
+                            !mServerInfo.mBaseUrl.equals(
+                                    AuthenticatorUrlUtils.normalizeUrl(s.toString(), mServerInfo.mIsSslConn))) {
+                        mOkButton.setEnabled(false);
+                    }
+                }
+
+                @Override
+                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+                    // not used at the moment
+                }
+
+                @Override
+                public void onTextChanged(CharSequence s, int start, int before, int count) {
+                    if (mAuthStatusIcon != 0) {
+                        Log_OC.d(TAG, "onTextChanged: hiding authentication status");
+                        mAuthStatusIcon = 0;
+                        mAuthStatusText = "";
+                        showAuthStatus();
+                    }
+                }
+            };
+
+
+            // TODO find out if this is really necessary, or if it can done in a different way
+            findViewById(R.id.scroll).setOnTouchListener(new OnTouchListener() {
+                @Override
+                public boolean onTouch(View view, MotionEvent event) {
+                    if (event.getAction() == MotionEvent.ACTION_DOWN &&
+                            AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(
+                                    MainApp.getAccountType(getBaseContext())).equals(mAuthTokenType) &&
+                            mHostUrlInput.hasFocus()) {
+                        checkOcServer();
+                    }
+                    return false;
+                }
+            });
+        }
+    }
+
+
+    /**
+     * @param savedInstanceState Saved activity state, as in {{@link #onCreate(Bundle)}
+     */
+    private void initAuthorizationPreFragment(Bundle savedInstanceState) {
+
+        /// step 0 - get UI elements in layout
+        mOAuth2Check = findViewById(R.id.oauth_onOff_check);
+        mOAuthAuthEndpointText = findViewById(R.id.oAuthEntryPoint_1);
+        mOAuthTokenEndpointText = findViewById(R.id.oAuthEntryPoint_2);
+        mUsernameInput = findViewById(R.id.account_username);
+        mPasswordInput = findViewById(R.id.account_password);
+        mAuthStatusView = findViewById(R.id.auth_status_text);
+
+        /// step 1 - load and process relevant inputs (resources, intent, savedInstanceState)
+        String presetUserName = null;
+        boolean isPasswordExposed = false;
+        if (savedInstanceState == null) {
+            if (mAccount != null) {
+                presetUserName = com.owncloud.android.lib.common.accounts.AccountUtils.getUsernameForAccount(mAccount);
+            }
+        } else {
+            isPasswordExposed = savedInstanceState.getBoolean(KEY_PASSWORD_EXPOSED, false);
+            mAuthStatusText = savedInstanceState.getString(KEY_AUTH_STATUS_TEXT);
+            mAuthStatusIcon = savedInstanceState.getInt(KEY_AUTH_STATUS_ICON);
+            mAuthToken = savedInstanceState.getString(KEY_AUTH_TOKEN);
+        }
+
+        /// step 2 - set properties of UI elements (text, visibility, enabled...)
+        mOAuth2Check.setChecked(
+                AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType(this)).equals(mAuthTokenType));
+        if (presetUserName != null) {
+            mUsernameInput.setText(presetUserName);
+        }
+        if (mAction != ACTION_CREATE) {
+            mUsernameInput.setEnabled(false);
+            mUsernameInput.setFocusable(false);
+        }
+        mPasswordInput.setText(""); // clean password to avoid social hacking
+        if (isPasswordExposed) {
+            showPassword();
+        }
+        updateAuthenticationPreFragmentVisibility();
+        showAuthStatus();
+        mOkButton.setEnabled(mServerIsValid);
+
+
+        /// step 3 - bind listeners
+        // bindings for password input field
+        mPasswordInput.setOnFocusChangeListener(this);
+        mPasswordInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
+        mPasswordInput.setOnEditorActionListener(this);
+        mPasswordInput.setOnTouchListener(new RightDrawableOnTouchListener() {
+            @Override
+            public boolean onDrawableTouch(final MotionEvent event) {
+                if (event.getAction() == MotionEvent.ACTION_UP) {
+                    AuthenticatorActivity.this.onViewPasswordClick();
+                }
+                return true;
+            }
+        });
+
+    }
+
+
+    /**
+     * Changes the visibility of input elements depending on
+     * the current authorization method.
+     */
+    private void updateAuthenticationPreFragmentVisibility() {
+        if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType(this)).equals(mAuthTokenType)) {
+            // SAML-based web Single Sign On
+            mOAuth2Check.setVisibility(View.GONE);
+            mOAuthAuthEndpointText.setVisibility(View.GONE);
+            mOAuthTokenEndpointText.setVisibility(View.GONE);
+            mUsernameInput.setVisibility(View.GONE);
+            mPasswordInput.setVisibility(View.GONE);
+
+        } else {
+            if (mAction == ACTION_CREATE &&
+                    AUTH_OPTIONAL.equals(getString(R.string.auth_method_oauth2))) {
+                mOAuth2Check.setVisibility(View.VISIBLE);
+            } else {
+                mOAuth2Check.setVisibility(View.GONE);
+            }
+
+            if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType(this)).equals(mAuthTokenType)) {
+                // OAuth 2 authorization
+                mOAuthAuthEndpointText.setVisibility(View.VISIBLE);
+                mOAuthTokenEndpointText.setVisibility(View.VISIBLE);
+                mUsernameInput.setVisibility(View.GONE);
+                mPasswordInput.setVisibility(View.GONE);
+
+            } else {
+                // basic HTTP authorization
+                mOAuthAuthEndpointText.setVisibility(View.GONE);
+                mOAuthTokenEndpointText.setVisibility(View.GONE);
+                mUsernameInput.setVisibility(View.VISIBLE);
+                mPasswordInput.setVisibility(View.VISIBLE);
+            }
+        }
+    }
+
+
+    /**
+     * Saves relevant state before {@link #onPause()}
+     *
+     * Do NOT save {@link #mNewCapturedUriFromOAuth2Redirection}; it keeps a temporal flag,
+     * intended to defer the processing of the redirection caught in
+     * {@link #onNewIntent(Intent)} until {@link #onResume()}
+     *
+     * See {@link super#onSaveInstanceState(Bundle)}
+     */
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        //Log_OC.e(TAG, "onSaveInstanceState init" );
+        super.onSaveInstanceState(outState);
+
+        /// global state
+        outState.putString(KEY_AUTH_TOKEN_TYPE, mAuthTokenType);
+        outState.putLong(KEY_WAITING_FOR_OP_ID, mWaitingForOpId);
+
+        if (!webViewLoginMethod) {
+            /// Server PRE-fragment state
+            outState.putString(KEY_SERVER_STATUS_TEXT, mServerStatusText);
+            outState.putInt(KEY_SERVER_STATUS_ICON, mServerStatusIcon);
+            outState.putBoolean(KEY_SERVER_CHECKED, mServerIsChecked);
+            outState.putBoolean(KEY_SERVER_VALID, mServerIsValid);
+
+            /// Authentication PRE-fragment state
+            outState.putBoolean(KEY_PASSWORD_EXPOSED, isPasswordVisible());
+            outState.putInt(KEY_AUTH_STATUS_ICON, mAuthStatusIcon);
+            outState.putString(KEY_AUTH_STATUS_TEXT, mAuthStatusText);
+            outState.putString(KEY_AUTH_TOKEN, mAuthToken);
+        }
+
+        outState.putBoolean(KEY_IS_SSL_CONN, mServerInfo.mIsSslConn);
+        outState.putString(KEY_HOST_URL_TEXT, mServerInfo.mBaseUrl);
+        if (mServerInfo.mVersion != null) {
+            outState.putString(KEY_OC_VERSION, mServerInfo.mVersion.getVersion());
+        }
+        outState.putString(KEY_SERVER_AUTH_METHOD, mServerInfo.mAuthMethod.name());
+
+        /// authentication
+        outState.putBoolean(KEY_AUTH_IS_FIRST_ATTEMPT_TAG, mIsFirstAuthAttempt);
+
+        /// AsyncTask (User and password)
+        if (!webViewLoginMethod) {
+            outState.putString(KEY_USERNAME, mUsernameInput.getText().toString().trim());
+            outState.putString(KEY_PASSWORD, mPasswordInput.getText().toString());
+        }
+
+        if (mAsyncTask != null) {
+            mAsyncTask.cancel(true);
+            outState.putBoolean(KEY_ASYNC_TASK_IN_PROGRESS, true);
+        } else {
+            outState.putBoolean(KEY_ASYNC_TASK_IN_PROGRESS, false);
+        }
+        mAsyncTask = null;
+
+        //Log_OC.e(TAG, "onSaveInstanceState end" );
+    }
+
+    @Override
+    public void onRestoreInstanceState(Bundle savedInstanceState) {
+        super.onRestoreInstanceState(savedInstanceState);
+
+        mServerIsChecked = savedInstanceState.getBoolean(KEY_SERVER_CHECKED, false);
+
+        // AsyncTask
+        boolean inProgress = savedInstanceState.getBoolean(KEY_ASYNC_TASK_IN_PROGRESS);
+        if (inProgress) {
+            String username = savedInstanceState.getString(KEY_USERNAME);
+            String password = savedInstanceState.getString(KEY_PASSWORD);
+
+            OwnCloudCredentials credentials = null;
+            if (basicTokenType.equals(mAuthTokenType)) {
+                credentials = OwnCloudCredentialsFactory.newBasicCredentials(username, password);
+
+            } else if (oauthTokenType.equals(mAuthTokenType)) {
+                credentials = OwnCloudCredentialsFactory.newBearerCredentials(mAuthToken);
+
+            }
+            accessRootFolder(credentials);
+        }
+    }
+
+    /**
+     * The redirection triggered by the OAuth authentication server as response to the
+     * GET AUTHORIZATION request is caught here.
+     *
+     * To make this possible, this activity needs to be qualified with android:launchMode =
+     * "singleTask" in the AndroidManifest.xml file.
+     */
+    @Override
+    protected void onNewIntent(Intent intent) {
+        Log_OC.d(TAG, "onNewIntent()");
+        Uri data = intent.getData();
+        if (data != null && data.toString().startsWith(getString(R.string.oauth2_redirect_uri))) {
+            mNewCapturedUriFromOAuth2Redirection = data;
+        }
+
+        if (intent.getBooleanExtra(EXTRA_USE_PROVIDER_AS_WEBLOGIN, false)) {
+            webViewLoginMethod = true;
+            setContentView(R.layout.account_setup_webview);
+            mLoginWebView = findViewById(R.id.login_webview);
+            initWebViewLogin(getString(R.string.provider_registration_server), false);
+        }
+    }
+
+
+    /**
+     * The redirection triggered by the OAuth authentication server as response to the
+     * GET AUTHORIZATION, and deferred in {@link #onNewIntent(Intent)}, is processed here.
+     */
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        if (!webViewLoginMethod) {
+            // bound here to avoid spurious changes triggered by Android on device rotations
+            mHostUrlInput.setOnFocusChangeListener(this);
+            mHostUrlInput.addTextChangedListener(mHostUrlInputWatcher);
+
+            if (mNewCapturedUriFromOAuth2Redirection != null) {
+                getOAuth2AccessTokenFromCapturedRedirection();
+            }
+
+            String dataString = getIntent().getDataString();
+            if (dataString != null) {
+                try {
+                    populateLoginFields(dataString);
+                } catch (IllegalArgumentException e) {
+                    DisplayUtils.showSnackMessage(findViewById(R.id.scroll), R.string.auth_illegal_login_used);
+                    Log_OC.e(TAG, "Illegal login data URL used, no Login pre-fill!", e);
+                }
+            }
+        }
+
+        // bind to Operations Service
+        mOperationsServiceConnection = new OperationsServiceConnection();
+        if (!bindService(new Intent(this, OperationsService.class),
+                mOperationsServiceConnection,
+                Context.BIND_AUTO_CREATE)) {
+            DisplayUtils.showSnackMessage(findViewById(R.id.scroll), R.string.error_cant_bind_to_operations_service);
+            finish();
+        }
+
+        if (mOperationsServiceBinder != null) {
+            doOnResumeAndBound();
+        }
+    }
+
+
+    @Override
+    protected void onPause() {
+        if (mOperationsServiceBinder != null) {
+            mOperationsServiceBinder.removeOperationListener(this);
+        }
+
+        if (!webViewLoginMethod) {
+            mHostUrlInput.removeTextChangedListener(mHostUrlInputWatcher);
+            mHostUrlInput.setOnFocusChangeListener(null);
+        }
+
+        super.onPause();
+    }
+
+    @Override
+    protected void onDestroy() {
+
+        mHostUrlInputWatcher = null;
+
+        if (mOperationsServiceConnection != null) {
+            unbindService(mOperationsServiceConnection);
+            mOperationsServiceBinder = null;
+        }
+
+        if (webViewLoginMethod) {
+            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
+        }
+
+        super.onDestroy();
+    }
+
+    /**
+     * Parses the redirection with the response to the GET AUTHORIZATION request to the
+     * oAuth server and requests for the access token (GET ACCESS TOKEN)
+     */
+    private void getOAuth2AccessTokenFromCapturedRedirection() {
+        /// Parse data from OAuth redirection
+        String queryParameters = mNewCapturedUriFromOAuth2Redirection.getQuery();
+        mNewCapturedUriFromOAuth2Redirection = null;
+
+        /// Showing the dialog with instructions for the user.
+        IndeterminateProgressDialog dialog =
+                IndeterminateProgressDialog.newInstance(R.string.auth_getting_authorization, true);
+        dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);
+
+        /// GET ACCESS TOKEN to the oAuth server
+        Intent getServerInfoIntent = new Intent();
+        getServerInfoIntent.setAction(OperationsService.ACTION_OAUTH2_GET_ACCESS_TOKEN);
+
+        getServerInfoIntent.putExtra(
+                OperationsService.EXTRA_SERVER_URL,
+                mOAuthTokenEndpointText.getText().toString().trim());
+
+        getServerInfoIntent.putExtra(
+                OperationsService.EXTRA_OAUTH2_QUERY_PARAMETERS,
+                queryParameters);
+
+        if (mOperationsServiceBinder != null) {
+            //Log_OC.e(TAG, "getting access token..." );
+            mWaitingForOpId = mOperationsServiceBinder.queueNewOperation(getServerInfoIntent);
+        }
+    }
+
+
+    /**
+     * Handles the change of focus on the text inputs for the server URL and the password
+     */
+    public void onFocusChange(View view, boolean hasFocus) {
+        if (view.getId() == R.id.hostUrlInput) {
+            if (!hasFocus) {
+                onUrlInputFocusLost();
+            } else {
+                showRefreshButton(false);
+            }
+
+        } else if (view.getId() == R.id.account_password) {
+            onPasswordFocusChanged(hasFocus);
+        }
+    }
+
+
+    /**
+     * Handles changes in focus on the text input for the server URL.
+     *
+     * IMPORTANT ENTRY POINT 2: When (!hasFocus), user wrote the server URL and changed to
+     * other field. The operation to check the existence of the server in the entered URL is
+     * started.
+     *
+     * When hasFocus:    user 'comes back' to write again the server URL.
+     */
+    private void onUrlInputFocusLost() {
+        if (!mServerInfo.mBaseUrl.equals(
+                AuthenticatorUrlUtils.normalizeUrl(mHostUrlInput.getText().toString(), mServerInfo.mIsSslConn))) {
+            // check server again only if the user changed something in the field
+            checkOcServer();
+        } else {
+            mOkButton.setEnabled(mServerIsValid);
+            showRefreshButton(!mServerIsValid);
+        }
+    }
+
+
+    private void checkOcServer() {
+        String uri;
+        if (mHostUrlInput != null && !mHostUrlInput.getText().toString().isEmpty()) {
+            uri = mHostUrlInput.getText().toString().trim();
+            mOkButton.setEnabled(false);
+            showRefreshButton(false);
+        } else {
+            uri = mServerInfo.mBaseUrl;
+        }
+
+        mServerIsValid = false;
+        mServerIsChecked = false;
+        mServerInfo = new GetServerInfoOperation.ServerInfo();
+
+        if (uri.length() != 0) {
+            if (mHostUrlInput != null) {
+                uri = AuthenticatorUrlUtils.stripIndexPhpOrAppsFiles(uri);
+                mHostUrlInput.setText(uri);
+            }
+
+            // Handle internationalized domain names
+            try {
+                uri = DisplayUtils.convertIdn(uri, true);
+            } catch (IllegalArgumentException ex) {
+                // Let Owncloud library check the error of the malformed URI
+                Log_OC.e(TAG, "Error converting internationalized domain name " + uri, ex);
+            }
+
+            if (mHostUrlInput != null) {
+                mServerStatusText = getResources().getString(R.string.auth_testing_connection);
+                mServerStatusIcon = R.drawable.progress_small;
+                showServerStatus();
+            }
+
+            Intent getServerInfoIntent = new Intent();
+            getServerInfoIntent.setAction(OperationsService.ACTION_GET_SERVER_INFO);
+            getServerInfoIntent.putExtra(OperationsService.EXTRA_SERVER_URL,
+                    AuthenticatorUrlUtils.normalizeUrlSuffix(uri));
+
+            if (mOperationsServiceBinder != null) {
+                mWaitingForOpId = mOperationsServiceBinder.queueNewOperation(getServerInfoIntent);
+            } else {
+                Log_OC.e(TAG, "Server check tried with OperationService unbound!");
+            }
+
+        } else {
+            mServerStatusText = "";
+            mServerStatusIcon = 0;
+            if (!webViewLoginMethod) {
+                showServerStatus();
+            }
+        }
+    }
+
+
+    /**
+     * Handles changes in focus on the text input for the password (basic authorization).
+     *
+     * When (hasFocus), the button to toggle password visibility is shown.
+     *
+     * When (!hasFocus), the button is made invisible and the password is hidden.
+     *
+     * @param hasFocus 'True' if focus is received, 'false' if is lost
+     */
+
+    private void onPasswordFocusChanged(boolean hasFocus) {
+        if (hasFocus) {
+            showViewPasswordButton();
+        } else {
+            hidePassword();
+            hidePasswordButton();
+        }
+    }
+
+
+    private void showViewPasswordButton() {
+        int drawable = R.drawable.ic_view;
+        if (isPasswordVisible()) {
+            drawable = R.drawable.ic_hide;
+        }
+        mPasswordInput.setCompoundDrawablesWithIntrinsicBounds(0, 0, drawable, 0);
+    }
+
+    private boolean isPasswordVisible() {
+        return ((mPasswordInput.getInputType() & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) ==
+                InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
+    }
+
+    private void hidePasswordButton() {
+        mPasswordInput.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
+    }
+
+    private void showPassword() {
+        mPasswordInput.setInputType(
+                InputType.TYPE_CLASS_TEXT |
+                        InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD |
+                        InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
+        );
+        showViewPasswordButton();
+    }
+
+    private void hidePassword() {
+        mPasswordInput.setInputType(
+                InputType.TYPE_CLASS_TEXT |
+                        InputType.TYPE_TEXT_VARIATION_PASSWORD |
+                        InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
+        );
+        showViewPasswordButton();
+    }
+
+    /**
+     * Checks the credentials of the user in the root of the ownCloud server
+     * before creating a new local account.
+     *
+     * For basic authorization, a check of existence of the root folder is
+     * performed.
+     *
+     * For OAuth, starts the flow to get an access token; the credentials test
+     * is postponed until it is available.
+     *
+     * IMPORTANT ENTRY POINT 4
+     */
+    public void onOkClick() {
+        // this check should be unnecessary
+        if (mServerInfo.mVersion == null ||
+                !mServerInfo.mVersion.isVersionValid() ||
+                mServerInfo.mBaseUrl == null ||
+                mServerInfo.mBaseUrl.length() == 0) {
+            mServerStatusIcon = R.drawable.ic_alert;
+            mServerStatusText = getResources().getString(R.string.auth_wtf_reenter_URL);
+            showServerStatus();
+            mOkButton.setEnabled(false);
+            return;
+        }
+
+        if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType(this)).equals(mAuthTokenType)) {
+            startOauthorization();
+        } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType(this))
+                .equals(mAuthTokenType)) {
+            startSamlBasedFederatedSingleSignOnAuthorization();
+        } else {
+            checkBasicAuthorization(null, null);
+        }
+    }
+
+
+    /**
+     * Tests the credentials entered by the user performing a check of existence on
+     * the root folder of the ownCloud server.
+     */
+    private void checkBasicAuthorization(@Nullable String webViewUsername, @Nullable String webViewPassword) {
+        /// get basic credentials entered by user
+        String username;
+        String password;
+        if (!webViewLoginMethod) {
+            username = mUsernameInput.getText().toString().trim();
+            password = mPasswordInput.getText().toString();
+        } else {
+            username = webViewUsername;
+            password = webViewPassword;
+        }
+
+        /// be gentle with the user
+        IndeterminateProgressDialog dialog =
+                IndeterminateProgressDialog.newInstance(R.string.auth_trying_to_login, true);
+        dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);
+
+        /// validate credentials accessing the root folder
+        OwnCloudCredentials credentials = OwnCloudCredentialsFactory.newBasicCredentials(username, password);
+        accessRootFolder(credentials);
+    }
+
+    private void accessRootFolder(OwnCloudCredentials credentials) {
+        mAsyncTask = new AuthenticatorAsyncTask(this);
+        Object[] params = {mServerInfo.mBaseUrl, credentials};
+        mAsyncTask.execute(params);
+    }
+
+
+    /**
+     * Starts the OAuth 'grant type' flow to get an access token, with
+     * a GET AUTHORIZATION request to the BUILT-IN authorization server.
+     */
+    private void startOauthorization() {
+        // be gentle with the user
+        mAuthStatusIcon = R.drawable.progress_small;
+        mAuthStatusText = getResources().getString(R.string.oauth_login_connection);
+        showAuthStatus();
+
+        // GET AUTHORIZATION request
+        Uri uri = Uri.parse(mOAuthAuthEndpointText.getText().toString().trim());
+        Uri.Builder uriBuilder = uri.buildUpon();
+        uriBuilder.appendQueryParameter(
+                OAuth2Constants.KEY_RESPONSE_TYPE, getString(R.string.oauth2_response_type)
+        );
+        uriBuilder.appendQueryParameter(
+                OAuth2Constants.KEY_REDIRECT_URI, getString(R.string.oauth2_redirect_uri)
+        );
+        uriBuilder.appendQueryParameter(
+                OAuth2Constants.KEY_CLIENT_ID, getString(R.string.oauth2_client_id)
+        );
+        uriBuilder.appendQueryParameter(
+                OAuth2Constants.KEY_SCOPE, getString(R.string.oauth2_scope)
+        );
+        uri = uriBuilder.build();
+        Log_OC.d(TAG, "Starting browser to view " + uri.toString());
+        Intent i = new Intent(Intent.ACTION_VIEW, uri);
+        startActivity(i);
+    }
+
+
+    /**
+     * Starts the Web Single Sign On flow to get access to the root folder
+     * in the server.
+     */
+    private void startSamlBasedFederatedSingleSignOnAuthorization() {
+        /// be gentle with the user
+        mAuthStatusIcon = R.drawable.progress_small;
+        mAuthStatusText = getResources().getString(R.string.auth_connecting_auth_server);
+        showAuthStatus();
+
+        /// Show SAML-based SSO web dialog
+        String targetUrl = mServerInfo.mBaseUrl
+                + AuthenticatorUrlUtils.getWebdavPath(mServerInfo.mVersion, mAuthTokenType, this);
+        SamlWebViewDialog dialog = SamlWebViewDialog.newInstance(targetUrl, targetUrl);
+        dialog.show(getSupportFragmentManager(), SAML_DIALOG_TAG);
+    }
+
+    /**
+     * Callback method invoked when a RemoteOperation executed by this Activity finishes.
+     *
+     * Dispatches the operation flow to the right method.
+     */
+    @Override
+    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+
+        if (operation instanceof GetServerInfoOperation) {
+            if (operation.hashCode() == mWaitingForOpId) {
+                onGetServerInfoFinish(result);
+            }   // else nothing ; only the last check operation is considered; 
+            // multiple can be started if the user amends a URL quickly
+
+        } else if (operation instanceof OAuth2GetAccessToken) {
+            onGetOAuthAccessTokenFinish(result);
+
+        } else if (operation instanceof GetRemoteUserInfoOperation) {
+            onGetUserNameFinish(result);
+        }
+
+    }
+
+    private void onGetUserNameFinish(RemoteOperationResult result) {
+        mWaitingForOpId = Long.MAX_VALUE;
+        if (result.isSuccess()) {
+            boolean success = false;
+            String username;
+            if (result.getData().get(0) instanceof UserInfo) {
+                username = ((UserInfo) result.getData().get(0)).getDisplayName();
+            } else {
+                username = (String) result.getData().get(0);
+            }
+
+            if (mAction == ACTION_CREATE) {
+                if (!webViewLoginMethod) {
+                    mUsernameInput.setText(username);
+                }
+                success = createAccount(result);
+            } else {
+
+                if (!webViewLoginMethod && !mUsernameInput.getText().toString().trim().equals(username)) {
+                    // fail - not a new account, but an existing one; disallow
+                    result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_THE_SAME);
+                    mAuthToken = "";
+                    updateAuthStatusIconAndText(result);
+                    showAuthStatus();
+                    Log_OC.d(TAG, result.getLogMessage());
+                } else {
+                    try {
+                        updateAccountAuthentication();
+                        success = true;
+
+                    } catch (AccountNotFoundException e) {
+                        Log_OC.e(TAG, "Account " + mAccount + " was removed!", e);
+                        DisplayUtils.showSnackMessage(findViewById(R.id.scroll), R.string.auth_account_does_not_exist);
+                        finish();
+                    }
+                }
+            }
+
+            if (success) {
+                finish();
+            }
+        } else {
+            if (!webViewLoginMethod) {
+                int statusText = result.getCode() == ResultCode.MAINTENANCE_MODE ? R.string.maintenance_mode : R.string.auth_fail_get_user_name;
+                updateStatusIconFailUserName(statusText);
+                showAuthStatus();
+            }
+            Log_OC.e(TAG, "Access to user name failed: " + result.getLogMessage());
+        }
+
+    }
+
+    /**
+     * Processes the result of the server check performed when the user finishes the enter of the
+     * server URL.
+     *
+     * @param result Result of the check.
+     */
+    private void onGetServerInfoFinish(RemoteOperationResult result) {
+        /// update activity state
+        mServerIsChecked = true;
+        mWaitingForOpId = Long.MAX_VALUE;
+
+        // update server status, but don't show it yet
+        if (!webViewLoginMethod) {
+            updateServerStatusIconAndText(result);
+        }
+
+        if (result.isSuccess()) {
+            /// SUCCESS means:
+            //      1. connection succeeded, and we know if it's SSL or not
+            //      2. server is installed
+            //      3. we got the server version
+            //      4. we got the authentication method required by the server 
+            mServerInfo = (GetServerInfoOperation.ServerInfo) (result.getData().get(0));
+
+            // show outdated warning
+            if (getResources().getBoolean(R.bool.show_outdated_server_warning) &&
+                    mServerInfo.mVersion.compareTo(MainApp.OUTDATED_SERVER_VERSION) < 0) {
+                DisplayUtils.showServerOutdatedSnackbar(this);
+            }
+
+            webViewLoginMethod = mServerInfo.mVersion.isWebLoginSupported() && !forceOldLoginMethod;
+
+            if (webViewUser != null && !webViewUser.isEmpty() &&
+                    webViewPassword != null && !webViewPassword.isEmpty()) {
+                checkBasicAuthorization(webViewUser, webViewPassword);
+            } else if (webViewLoginMethod) {
+                // hide old login
+                setOldLoginVisibility(View.GONE);
+
+                setContentView(R.layout.account_setup_webview);
+                mLoginWebView = findViewById(R.id.login_webview);
+                initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, true);
+            } else {
+                // show old login
+                setOldLoginVisibility(View.VISIBLE);
+            }
+
+            if (!authSupported(mServerInfo.mAuthMethod)) {
+
+                if (!webViewLoginMethod) {
+                    // overrides updateServerStatusIconAndText()
+                    updateServerStatusIconNoRegularAuth();
+                }
+                mServerIsValid = false;
+
+            } else {
+                mServerIsValid = true;
+            }
+
+        } else {
+            mServerIsValid = false;
+        }
+
+        // refresh UI
+        if (!webViewLoginMethod) {
+            showRefreshButton(!mServerIsValid);
+            showServerStatus();
+            mOkButton.setEnabled(mServerIsValid);
+        }
+
+        if (!mServerIsValid) {
+            // hide old login
+            setOldLoginVisibility(View.GONE);
+        }
+
+        /// very special case (TODO: move to a common place for all the remote operations)
+        if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {
+            showUntrustedCertDialog(result);
+        }
+    }
+
+    private void setOldLoginVisibility(int visible) {
+        mOkButton.setVisibility(visible);
+        mUsernameInputLayout.setVisibility(visible);
+        mPasswordInputLayout.setVisibility(visible);
+    }
+
+    private boolean authSupported(AuthenticationMethod authMethod) {
+        return ((basicTokenType.equals(mAuthTokenType) &&
+                AuthenticationMethod.BASIC_HTTP_AUTH.equals(authMethod)) ||
+                (oauthTokenType.equals(mAuthTokenType) &&
+                        AuthenticationMethod.BEARER_TOKEN.equals(authMethod)) ||
+                (samlTokenType.equals(mAuthTokenType) &&
+                        AuthenticationMethod.SAML_WEB_SSO.equals(authMethod))
+        );
+    }
+
+    /**
+     * Chooses the right icon and text to show to the user for the received operation result.
+     *
+     * @param result Result of a remote operation performed in this activity
+     */
+    private void updateServerStatusIconAndText(RemoteOperationResult result) {
+        mServerStatusIcon = R.drawable.ic_alert;    // the most common case in the switch below
+
+        switch (result.getCode()) {
+            case OK_SSL:
+                mServerStatusIcon = R.drawable.ic_lock_white;
+                mServerStatusText = getResources().getString(R.string.auth_secure_connection);
+                break;
+
+            case OK_NO_SSL:
+            case OK:
+                if (mHostUrlInput.getText().toString().trim().toLowerCase(Locale.ROOT).startsWith(HTTP_PROTOCOL)) {
+                    mServerStatusText = getResources().getString(R.string.auth_connection_established);
+                    mServerStatusIcon = R.drawable.ic_ok;
+                } else {
+                    mServerStatusText = getResources().getString(R.string.auth_nossl_plain_ok_title);
+                    mServerStatusIcon = R.drawable.ic_lock_open_white;
+                }
+                break;
+
+            case NO_NETWORK_CONNECTION:
+                mServerStatusIcon = R.drawable.no_network;
+                mServerStatusText = getResources().getString(R.string.auth_no_net_conn_title);
+                break;
+
+            case SSL_RECOVERABLE_PEER_UNVERIFIED:
+                mServerStatusText = getResources().getString(R.string.auth_ssl_unverified_server_title);
+                break;
+            case BAD_OC_VERSION:
+                mServerStatusText = getResources().getString(R.string.auth_bad_oc_version_title);
+                break;
+            case WRONG_CONNECTION:
+                mServerStatusText = getResources().getString(R.string.auth_wrong_connection_title);
+                break;
+            case TIMEOUT:
+                mServerStatusText = getResources().getString(R.string.auth_timeout_title);
+                break;
+            case INCORRECT_ADDRESS:
+                mServerStatusText = getResources().getString(R.string.auth_incorrect_address_title);
+                break;
+            case SSL_ERROR:
+                mServerStatusText = getResources().getString(R.string.auth_ssl_general_error_title);
+                break;
+            case UNAUTHORIZED:
+                mServerStatusText = getResources().getString(R.string.auth_unauthorized);
+                break;
+            case HOST_NOT_AVAILABLE:
+                mServerStatusText = getResources().getString(R.string.auth_unknown_host_title);
+                break;
+            case INSTANCE_NOT_CONFIGURED:
+                mServerStatusText = getResources().getString(R.string.auth_not_configured_title);
+                break;
+            case FILE_NOT_FOUND:
+                mServerStatusText = getResources().getString(R.string.auth_incorrect_path_title);
+                break;
+            case OAUTH2_ERROR:
+                mServerStatusText = getResources().getString(R.string.auth_oauth_error);
+                break;
+            case OAUTH2_ERROR_ACCESS_DENIED:
+                mServerStatusText = getResources().getString(R.string.auth_oauth_error_access_denied);
+                break;
+            case UNHANDLED_HTTP_CODE:
+                mServerStatusText = getResources().getString(R.string.auth_unknown_error_http_title);
+                break;
+            case UNKNOWN_ERROR:
+                if (result.getException() != null &&
+                        !TextUtils.isEmpty(result.getException().getMessage())) {
+                    mServerStatusText = getResources().getString(
+                            R.string.auth_unknown_error_exception_title,
+                            result.getException().getMessage()
+                    );
+                } else {
+                    mServerStatusText = getResources().getString(R.string.auth_unknown_error_title);
+                }
+                break;
+            case OK_REDIRECT_TO_NON_SECURE_CONNECTION:
+                mServerStatusIcon = R.drawable.ic_lock_open_white;
+                mServerStatusText = getResources().getString(R.string.auth_redirect_non_secure_connection_title);
+                break;
+            case MAINTENANCE_MODE:
+                mServerStatusText = getResources().getString(R.string.maintenance_mode);
+                break;
+            case UNTRUSTED_DOMAIN:
+                mServerStatusText = getResources().getString(R.string.untrusted_domain);
+                break;
+            default:
+                mServerStatusText = "";
+                mServerStatusIcon = 0;
+                break;
+        }
+    }
+
+
+    /**
+     * Chooses the right icon and text to show to the user for the received operation result.
+     *
+     * @param result Result of a remote operation performed in this activity
+     */
+    private void updateAuthStatusIconAndText(RemoteOperationResult result) {
+        mAuthStatusIcon = R.drawable.ic_alert;    // the most common case in the switch below
+
+        switch (result.getCode()) {
+            case OK_SSL:
+                mAuthStatusIcon = R.drawable.ic_lock_white;
+                mAuthStatusText = getResources().getString(R.string.auth_secure_connection);
+                break;
+
+            case OK_NO_SSL:
+            case OK:
+                if (mHostUrlInput.getText().toString().trim().toLowerCase(Locale.ROOT).startsWith(HTTP_PROTOCOL)) {
+                    mAuthStatusText = getResources().getString(R.string.auth_connection_established);
+                    mAuthStatusIcon = R.drawable.ic_ok;
+                } else {
+                    mAuthStatusText = getResources().getString(R.string.auth_nossl_plain_ok_title);
+                    mAuthStatusIcon = R.drawable.ic_lock_open_white;
+                }
+                break;
+
+            case NO_NETWORK_CONNECTION:
+                mAuthStatusIcon = R.drawable.no_network;
+                mAuthStatusText = getResources().getString(R.string.auth_no_net_conn_title);
+                break;
+
+            case SSL_RECOVERABLE_PEER_UNVERIFIED:
+                mAuthStatusText = getResources().getString(R.string.auth_ssl_unverified_server_title);
+                break;
+            case TIMEOUT:
+                mAuthStatusText = getResources().getString(R.string.auth_timeout_title);
+                break;
+            case HOST_NOT_AVAILABLE:
+                mAuthStatusText = getResources().getString(R.string.auth_unknown_host_title);
+                break;
+            case UNHANDLED_HTTP_CODE:
+            default:
+                mAuthStatusText = ErrorMessageAdapter.getErrorCauseMessage(result, null, getResources());
+        }
+    }
+
+    private void updateStatusIconFailUserName(int failedStatusText) {
+        mAuthStatusIcon = R.drawable.ic_alert;
+        mAuthStatusText = getResources().getString(failedStatusText);
+    }
+
+    private void updateServerStatusIconNoRegularAuth() {
+        mServerStatusIcon = R.drawable.ic_alert;
+        mServerStatusText = getResources().getString(R.string.auth_can_not_auth_against_server);
+    }
+
+    /**
+     * Processes the result of the request for and access token send
+     * to an OAuth authorization server.
+     *
+     * @param result Result of the operation.
+     */
+    private void onGetOAuthAccessTokenFinish(RemoteOperationResult result) {
+        mWaitingForOpId = Long.MAX_VALUE;
+        dismissDialog(WAIT_DIALOG_TAG);
+
+        if (result.isSuccess()) {
+            /// be gentle with the user
+            IndeterminateProgressDialog dialog =
+                    IndeterminateProgressDialog.newInstance(R.string.auth_trying_to_login, true);
+            dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);
+
+            /// time to test the retrieved access token on the ownCloud server
+            @SuppressWarnings("unchecked")
+            Map<String, String> tokens = (Map<String, String>) (result.getData().get(0));
+            mAuthToken = tokens.get(OAuth2Constants.KEY_ACCESS_TOKEN);
+            Log_OC.d(TAG, "Got ACCESS TOKEN: " + mAuthToken);
+
+            /// validate token accessing to root folder / getting session
+            OwnCloudCredentials credentials = OwnCloudCredentialsFactory.newBearerCredentials(
+                    mAuthToken);
+            accessRootFolder(credentials);
+
+        } else {
+            updateAuthStatusIconAndText(result);
+            showAuthStatus();
+            Log_OC.d(TAG, "Access failed: " + result.getLogMessage());
+        }
+    }
+
+
+    /**
+     * Processes the result of the access check performed to try the user credentials.
+     *
+     * Creates a new account through the AccountManager.
+     *
+     * @param result Result of the operation.
+     */
+    @Override
+    public void onAuthenticatorTaskCallback(RemoteOperationResult result) {
+        mWaitingForOpId = Long.MAX_VALUE;
+        dismissDialog(WAIT_DIALOG_TAG);
+        mAsyncTask = null;
+
+        if (result.isSuccess()) {
+            Log_OC.d(TAG, "Successful access - time to save the account");
+
+            boolean success = false;
+
+            if (mAction == ACTION_CREATE) {
+                success = createAccount(result);
+
+            } else {
+                try {
+                    updateAccountAuthentication();
+                    success = true;
+
+                } catch (AccountNotFoundException e) {
+                    Log_OC.e(TAG, "Account " + mAccount + " was removed!", e);
+                    DisplayUtils.showSnackMessage(findViewById(R.id.scroll), R.string.auth_account_does_not_exist);
+                    finish();
+                }
+            }
+
+            // Reset webView
+            webViewPassword = null;
+            webViewUser = null;
+            forceOldLoginMethod = false;
+            deleteCookies();
+
+            if (success) {
+                finish();
+            } else {
+                // init webView again
+                if (mLoginWebView != null) {
+                    mLoginWebView.setVisibility(View.GONE);
+                }
+                setContentView(R.layout.account_setup);
+
+                initOverallUi();
+
+                CustomEditText serverAddressField = findViewById(R.id.hostUrlInput);
+                serverAddressField.setText(mServerInfo.mBaseUrl);
+
+                findViewById(R.id.oauth_onOff_check).setVisibility(View.GONE);
+                findViewById(R.id.server_status_text).setVisibility(View.GONE);
+                mAuthStatusView = findViewById(R.id.auth_status_text);
+
+                showAuthStatus();
+            }
+
+        } else if (result.isServerFail() || result.isException()) {
+            /// server errors or exceptions in authorization take to requiring a new check of 
+            /// the server
+            mServerIsChecked = true;
+            mServerIsValid = false;
+            mServerInfo = new GetServerInfoOperation.ServerInfo();
+
+            // update status icon and text
+            updateServerStatusIconAndText(result);
+            showServerStatus();
+            mAuthStatusIcon = 0;
+            mAuthStatusText = "";
+            if (!webViewLoginMethod) {
+                showAuthStatus();
+
+                // update input controls state
+                showRefreshButton(true);
+                mOkButton.setEnabled(false);
+            }
+
+            // very special case (TODO: move to a common place for all the remote operations)
+            if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {
+                showUntrustedCertDialog(result);
+            }
+
+        } else {    // authorization fail due to client side - probably wrong credentials
+            if (webViewLoginMethod) {
+                mLoginWebView = findViewById(R.id.login_webview);
+                initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, true);
+
+                DisplayUtils.showSnackMessage(this, mLoginWebView, R.string.auth_access_failed, result.getLogMessage());
+            } else {
+                updateAuthStatusIconAndText(result);
+                showAuthStatus();
+            }
+            // reset webview
+            webViewPassword = null;
+            webViewUser = null;
+            deleteCookies();
+
+            Log_OC.d(TAG, "Access failed: " + result.getLogMessage());
+        }
+    }
+
+
+    /**
+     * Updates the authentication token.
+     *
+     * Sets the proper response so that the AccountAuthenticator that started this activity
+     * saves a new authorization token for mAccount.
+     *
+     * Kills the session kept by OwnCloudClientManager so that a new one will created with
+     * the new credentials when needed.
+     */
+    private void updateAccountAuthentication() throws AccountNotFoundException {
+        String accountType = MainApp.getAccountType(this);
+
+        Bundle response = new Bundle();
+        response.putString(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);
+        response.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccount.type);
+
+        if (AccountTypeUtils.getAuthTokenTypeAccessToken(accountType).equals(mAuthTokenType)) {
+            response.putString(AccountManager.KEY_AUTHTOKEN, mAuthToken);
+            // the next line is necessary, notifications are calling directly to the 
+            // AuthenticatorActivity to update, without AccountManager intervention
+            mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);
+
+        } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(accountType).equals(mAuthTokenType)) {
+            response.putString(AccountManager.KEY_AUTHTOKEN, mAuthToken);
+            // the next line is necessary; by now, notifications are calling directly to the 
+            // AuthenticatorActivity to update, without AccountManager intervention
+            mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);
+
+        } else {
+            if (!webViewLoginMethod) {
+                response.putString(AccountManager.KEY_AUTHTOKEN, mPasswordInput.getText().toString());
+                mAccountMgr.setPassword(mAccount, mPasswordInput.getText().toString());
+            } else {
+                response.putString(AccountManager.KEY_AUTHTOKEN, webViewPassword);
+                mAccountMgr.setPassword(mAccount, webViewPassword);
+            }
+        }
+
+        // remove managed clients for this account to enforce creation with fresh credentials
+        OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, this);
+        OwnCloudClientManagerFactory.getDefaultSingleton().removeClientFor(ocAccount);
+
+        setAccountAuthenticatorResult(response);
+        final Intent intent = new Intent();
+        intent.putExtras(response);
+        setResult(RESULT_OK, intent);
+
+    }
+
+
+    /**
+     * Creates a new account through the Account Authenticator that started this activity.
+     *
+     * This makes the account permanent.
+     *
+     * TODO Decide how to name the OAuth accounts
+     */
+    @SuppressFBWarnings("DMI")
+    private boolean createAccount(RemoteOperationResult authResult) {
+        String accountType = MainApp.getAccountType(this);
+
+        // create and save new ownCloud account
+        boolean isOAuth = AccountTypeUtils.getAuthTokenTypeAccessToken(accountType).equals(mAuthTokenType);
+        boolean isSaml = AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(accountType).equals(mAuthTokenType);
+
+        String lastPermanentLocation = authResult.getLastPermanentLocation();
+        if (lastPermanentLocation != null) {
+            mServerInfo.mBaseUrl = AuthenticatorUrlUtils.trimWebdavSuffix(lastPermanentLocation);
+        }
+
+        Uri uri = Uri.parse(mServerInfo.mBaseUrl);
+        String username;
+        if (!webViewLoginMethod) {
+            username = mUsernameInput.getText().toString().trim();
+        } else {
+            username = webViewUser;
+        }
+        if (isOAuth) {
+            username = "OAuth_user" + (new java.util.Random(System.currentTimeMillis())).nextLong();
+        }
+
+        String accountName = com.owncloud.android.lib.common.accounts.AccountUtils.buildAccountName(uri, username);
+        Account newAccount = new Account(accountName, accountType);
+        if (AccountUtils.exists(newAccount, getApplicationContext())) {
+            // fail - not a new account, but an existing one; disallow
+            RemoteOperationResult result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_NEW);
+
+            updateAuthStatusIconAndText(result);
+            showAuthStatus();
+
+            Log_OC.d(TAG, result.getLogMessage());
+            return false;
+
+        } else {
+            mAccount = newAccount;
+
+            if (isOAuth || isSaml) {
+                // with external authorizations, the password is never input in the app
+                mAccountMgr.addAccountExplicitly(mAccount, "", null);
+            } else {
+                if (!webViewLoginMethod) {
+                    mAccountMgr.addAccountExplicitly(mAccount, mPasswordInput.getText().toString(), null);
+                } else {
+                    mAccountMgr.addAccountExplicitly(mAccount, webViewPassword, null);
+                }
+            }
+
+            // include account version with the new account
+            mAccountMgr.setUserData(mAccount, Constants.KEY_OC_ACCOUNT_VERSION,
+                    Integer.toString(AccountUtils.ACCOUNT_VERSION));
+
+            /// add the new account as default in preferences, if there is none already
+            Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this);
+            if (defaultAccount == null) {
+                SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
+                editor.putString("select_oc_account", accountName);
+                editor.apply();
+            }
+
+            /// prepare result to return to the Authenticator
+            //  TODO check again what the Authenticator makes with it; probably has the same 
+            //  effect as addAccountExplicitly, but it's not well done
+            final Intent intent = new Intent();
+            intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, accountType);
+            intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);
+            intent.putExtra(AccountManager.KEY_USERDATA, username);
+            if (isOAuth || isSaml) {
+                mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);
+            }
+            /// add user data to the new account; TODO probably can be done in the last parameter 
+            //      addAccountExplicitly, or in KEY_USERDATA
+            mAccountMgr.setUserData(mAccount, Constants.KEY_OC_VERSION, mServerInfo.mVersion.getVersion());
+            mAccountMgr.setUserData(mAccount, Constants.KEY_OC_BASE_URL, mServerInfo.mBaseUrl);
+
+            if (authResult.getData() != null) {
+                try {
+                    UserInfo userInfo = (UserInfo) authResult.getData().get(0);
+                    mAccountMgr.setUserData(mAccount, Constants.KEY_DISPLAY_NAME, userInfo.getDisplayName());
+                    mAccountMgr.setUserData(mAccount, Constants.KEY_USER_ID, userInfo.getId());
+                } catch (ClassCastException c) {
+                    Log_OC.w(TAG, "Couldn't get display name for " + username);
+                }
+            } else {
+                Log_OC.w(TAG, "Couldn't get display name for " + username);
+            }
+
+            if (isSaml) {
+                mAccountMgr.setUserData(mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO, "TRUE");
+            } else if (isOAuth) {
+                mAccountMgr.setUserData(mAccount, Constants.KEY_SUPPORTS_OAUTH2, "TRUE");
+            }
+
+            setAccountAuthenticatorResult(intent.getExtras());
+            setResult(RESULT_OK, intent);
+
+            return true;
+        }
+    }
+
+    /**
+     * Updates the content and visibility state of the icon and text associated
+     * to the last check on the ownCloud server.
+     */
+    private void showServerStatus() {
+        if (mServerStatusIcon == 0 && "".equals(mServerStatusText)) {
+            mServerStatusView.setVisibility(View.INVISIBLE);
+        } else {
+            mServerStatusView.setText(mServerStatusText);
+            mServerStatusView.setCompoundDrawablesWithIntrinsicBounds(mServerStatusIcon, 0, 0, 0);
+            mServerStatusView.setVisibility(View.VISIBLE);
+        }
+    }
+
+
+    /**
+     * Updates the content and visibility state of the icon and text associated
+     * to the interactions with the OAuth authorization server.
+     */
+    private void showAuthStatus() {
+        if (mAuthStatusIcon == 0 && "".equals(mAuthStatusText)) {
+            mAuthStatusView.setVisibility(View.INVISIBLE);
+        } else {
+            mAuthStatusView.setText(mAuthStatusText);
+            mAuthStatusView.setCompoundDrawablesWithIntrinsicBounds(mAuthStatusIcon, 0, 0, 0);
+            mAuthStatusView.setVisibility(View.VISIBLE);
+        }
+    }
+
+
+    private void showRefreshButton(boolean show) {
+        if (webViewLoginMethod && mRefreshButton != null) {
+            if (show) {
+                mRefreshButton.setVisibility(View.VISIBLE);
+            } else {
+                mRefreshButton.setVisibility(View.GONE);
+            }
+        }
+    }
+
+    /**
+     * Called when the eye icon in the password field is clicked.
+     *
+     * Toggles the visibility of the password in the field.
+     */
+    public void onViewPasswordClick() {
+        int selectionStart = mPasswordInput.getSelectionStart();
+        int selectionEnd = mPasswordInput.getSelectionEnd();
+        if (isPasswordVisible()) {
+            hidePassword();
+        } else {
+            showPassword();
+        }
+        mPasswordInput.setSelection(selectionStart, selectionEnd);
+    }
+
+
+    /**
+     * Called when the checkbox for OAuth authorization is clicked.
+     *
+     * Hides or shows the input fields for user & password.
+     *
+     * @param view 'View password' 'button'
+     */
+    public void onCheckClick(View view) {
+        CheckBox oAuth2Check = (CheckBox) view;
+        if (oAuth2Check.isChecked()) {
+            mAuthTokenType = oauthTokenType;
+        } else {
+            mAuthTokenType = basicTokenType;
+        }
+        updateAuthenticationPreFragmentVisibility();
+    }
+
+
+    /**
+     * Called when the 'action' button in an IME is pressed ('enter' in software keyboard).
+     * 
+     * Used to trigger the authentication check when the user presses 'enter' after writing the
+     * password, or to throw the server test when the only field on screen is the URL input field.
+     */
+    @Override
+    public boolean onEditorAction(TextView inputField, int actionId, KeyEvent event) {
+        if (actionId == EditorInfo.IME_ACTION_DONE && inputField != null &&
+                inputField.equals(mPasswordInput)) {
+            if (mOkButton.isEnabled()) {
+                mOkButton.performClick();
+            }
+
+        } else if ((actionId == EditorInfo.IME_ACTION_NEXT || actionId == EditorInfo.IME_NULL)
+                && inputField != null && inputField.equals(mHostUrlInput)) {
+            checkOcServer();
+        }
+        return false;   // always return false to grant that the software keyboard is hidden anyway
+    }
+
+
+    private abstract static class RightDrawableOnTouchListener implements OnTouchListener {
+
+        private int fuzz = 75;
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean onTouch(View view, MotionEvent event) {
+            Drawable rightDrawable = null;
+            if (view instanceof TextView) {
+                Drawable[] drawables = ((TextView) view).getCompoundDrawables();
+                if (drawables.length > 2) {
+                    rightDrawable = drawables[2];
+                }
+            }
+            if (rightDrawable != null) {
+                final int x = (int) event.getX();
+                final int y = (int) event.getY();
+                final Rect bounds = rightDrawable.getBounds();
+                if (x >= (view.getRight() - bounds.width() - fuzz) &&
+                        x <= (view.getRight() - view.getPaddingRight() + fuzz) &&
+                        y >= (view.getPaddingTop() - fuzz) &&
+                        y <= (view.getHeight() - view.getPaddingBottom()) + fuzz) {
+
+                    return onDrawableTouch(event);
+                }
+            }
+            return false;
+        }
+
+        public abstract boolean onDrawableTouch(final MotionEvent event);
+    }
+
+
+    private void getRemoteUserNameOperation(String sessionCookie) {
+
+        Intent getUserNameIntent = new Intent();
+        getUserNameIntent.setAction(OperationsService.ACTION_GET_USER_NAME);
+        getUserNameIntent.putExtra(OperationsService.EXTRA_SERVER_URL, mServerInfo.mBaseUrl);
+        getUserNameIntent.putExtra(OperationsService.EXTRA_COOKIE, sessionCookie);
+
+        if (mOperationsServiceBinder != null) {
+            mWaitingForOpId = mOperationsServiceBinder.queueNewOperation(getUserNameIntent);
+        }
+    }
+
+
+    @Override
+    public void onSsoFinished(String sessionCookie) {
+        if (sessionCookie != null && sessionCookie.length() > 0) {
+            Log_OC.d(TAG, "Successful SSO - time to save the account");
+            mAuthToken = sessionCookie;
+            getRemoteUserNameOperation(sessionCookie);
+            Fragment fd = getSupportFragmentManager().findFragmentByTag(SAML_DIALOG_TAG);
+            if (fd instanceof DialogFragment) {
+                Dialog d = ((DialogFragment) fd).getDialog();
+                if (d != null && d.isShowing()) {
+                    d.dismiss();
+                }
+            }
+
+        } else {
+            // TODO - show fail
+            Log_OC.d(TAG, "SSO failed");
+        }
+
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType(this)).equals(mAuthTokenType) &&
+                mHostUrlInput.hasFocus() && event.getAction() == MotionEvent.ACTION_DOWN) {
+            checkOcServer();
+        }
+        return super.onTouchEvent(event);
+    }
+
+
+    /**
+     * Show untrusted cert dialog
+     */
+    public void showUntrustedCertDialog(X509Certificate x509Certificate, SslError error, SslErrorHandler handler) {
+        // Show a dialog with the certificate info
+        SslUntrustedCertDialog dialog;
+        if (x509Certificate == null) {
+            dialog = SslUntrustedCertDialog.newInstanceForEmptySslError(error, handler);
+        } else {
+            dialog = SslUntrustedCertDialog.newInstanceForFullSslError(x509Certificate, error, handler);
+        }
+        FragmentManager fm = getSupportFragmentManager();
+        FragmentTransaction ft = fm.beginTransaction();
+        ft.addToBackStack(null);
+        dialog.show(ft, UNTRUSTED_CERT_DIALOG_TAG);
+    }
+
+
+    /**
+     * Show untrusted cert dialog
+     */
+    private void showUntrustedCertDialog(RemoteOperationResult result) {
+        // Show a dialog with the certificate info
+        SslUntrustedCertDialog dialog = SslUntrustedCertDialog.
+                newInstanceForFullSslError((CertificateCombinedException) result.getException());
+        FragmentManager fm = getSupportFragmentManager();
+        FragmentTransaction ft = fm.beginTransaction();
+        ft.addToBackStack(null);
+        dialog.show(ft, UNTRUSTED_CERT_DIALOG_TAG);
+
+    }
+
+    /**
+     * Called from SslValidatorDialog when a new server certificate was correctly saved.
+     */
+    public void onSavedCertificate() {
+        Fragment fd = getSupportFragmentManager().findFragmentByTag(SAML_DIALOG_TAG);
+        if (fd == null) {
+            // if SAML dialog is not shown, 
+            // the SslDialog was shown due to an SSL error in the server check
+            checkOcServer();
+        }
+    }
+
+    /**
+     * Called from SslValidatorDialog when a new server certificate could not be saved
+     * when the user requested it.
+     */
+    @Override
+    public void onFailedSavingCertificate() {
+        dismissDialog(SAML_DIALOG_TAG);
+        DisplayUtils.showSnackMessage(this, R.string.ssl_validator_not_saved);
+    }
+
+    @Override
+    public void onCancelCertificate() {
+        dismissDialog(SAML_DIALOG_TAG);
+    }
+
+
+    private void doOnResumeAndBound() {
+        //Log_OC.e(TAG, "registering to listen for operation callbacks" );
+        mOperationsServiceBinder.addOperationListener(AuthenticatorActivity.this, mHandler);
+        if (mWaitingForOpId <= Integer.MAX_VALUE) {
+            mOperationsServiceBinder.dispatchResultIfFinished((int) mWaitingForOpId, this);
+        }
+
+        if (!webViewLoginMethod && mHostUrlInput.getText() != null && mHostUrlInput.getText().length() > 0
+                && !mServerIsChecked) {
+            checkOcServer();
+        }
+    }
+
+
+    private void dismissDialog(String dialogTag) {
+        Fragment frag = getSupportFragmentManager().findFragmentByTag(dialogTag);
+        if (frag instanceof DialogFragment) {
+            DialogFragment dialog = (DialogFragment) frag;
+
+            try {
+                dialog.dismiss();
+            } catch (IllegalStateException e) {
+                Log_OC.e(TAG, e.getMessage());
+                dialog.dismissAllowingStateLoss();
+            }
+        }
+    }
+
+
+    /**
+     * Implements callback methods for service binding.
+     */
+    private class OperationsServiceConnection implements ServiceConnection {
+
+        @Override
+        public void onServiceConnected(ComponentName component, IBinder service) {
+            if (component.equals(
+                    new ComponentName(AuthenticatorActivity.this, OperationsService.class)
+            )) {
+                mOperationsServiceBinder = (OperationsServiceBinder) service;
+
+                doOnResumeAndBound();
+
+            }
+
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName component) {
+            if (component.equals(
+                    new ComponentName(AuthenticatorActivity.this, OperationsService.class)
+            )) {
+                Log_OC.e(TAG, "Operations service crashed");
+                mOperationsServiceBinder = null;
+            }
+        }
+    }
+
+    /**
+     * Create and show dialog for request authentication to the user
+     *
+     * @param webView Web view to embed into the authentication dialog.
+     * @param handler Object responsible for catching and recovering HTTP authentication fails.
+     */
+    public void createAuthenticationDialog(WebView webView, HttpAuthHandler handler) {
+
+        // Show a dialog with the certificate info
+        CredentialsDialogFragment dialog = CredentialsDialogFragment.newInstanceForCredentials(webView, handler);
+        FragmentManager fm = getSupportFragmentManager();
+        FragmentTransaction ft = fm.beginTransaction();
+        ft.addToBackStack(null);
+        dialog.setCancelable(false);
+        dialog.show(ft, CREDENTIALS_DIALOG_TAG);
+
+        if (!mIsFirstAuthAttempt) {
+            DisplayUtils.showSnackMessage(this, R.string.saml_authentication_wrong_pass);
+        } else {
+            mIsFirstAuthAttempt = false;
+        }
+    }
+
+    /**
+     * For retrieving the clicking on authentication cancel button.
+     */
+    public void doNegativeAuthenticationDialogClick() {
+        mIsFirstAuthAttempt = true;
+    }
+}

+ 115 - 0
src/main/java/com/owncloud/android/features/FeatureItem.java

@@ -0,0 +1,115 @@
+/*
+ *   Nextcloud Android client application
+ *
+ *   @author Bartosz Przybylski
+ *   Copyright (C) 2015 Bartosz Przybylski
+ *   Copyright (C) 2015 ownCloud Inc.
+ *   Copyright (C) 2016 Nextcloud.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ *   License as published by the Free Software Foundation; either
+ *   version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ *   You should have received a copy of the GNU Affero General Public
+ *   License along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.owncloud.android.features;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.owncloud.android.R;
+
+/**
+ * @author Bartosz Przybylski
+ * @author Tobias Kaminsky
+ */
+public class FeatureItem implements Parcelable {
+    private static final int DO_NOT_SHOW = -1;
+    private int image;
+    private int titleText;
+    private int contentText;
+    private boolean contentCentered;
+    private boolean bulletList;
+
+    public FeatureItem(int image, int titleText, int contentText, boolean contentCentered, boolean bulletList) {
+        this.image = image;
+        this.titleText = titleText;
+        this.contentText = contentText;
+        this.contentCentered = contentCentered;
+        this.bulletList = bulletList;
+    }
+
+    public boolean shouldShowImage() {
+        return image != DO_NOT_SHOW;
+    }
+
+    public int getImage() {
+        return image;
+    }
+
+    public boolean shouldShowTitleText() {
+        return titleText != DO_NOT_SHOW && titleText != R.string.empty;
+    }
+
+    public int getTitleText() {
+        return titleText;
+    }
+
+    public boolean shouldShowContentText() {
+        return contentText != DO_NOT_SHOW && contentText != R.string.empty;
+    }
+
+    public int getContentText() {
+        return contentText;
+    }
+
+    public boolean shouldContentCentered() {
+        return contentCentered;
+    }
+
+    public boolean shouldShowBulletPointList() {
+        return bulletList;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(image);
+        dest.writeInt(titleText);
+        dest.writeInt(contentText);
+        dest.writeByte((byte) (contentCentered ? 1 : 0));
+        dest.writeByte((byte) (bulletList ? 1 : 0));
+    }
+
+    private FeatureItem(Parcel p) {
+        image = p.readInt();
+        titleText = p.readInt();
+        contentText = p.readInt();
+        contentCentered = p.readByte() == 1;
+        bulletList = p.readByte() == 1;
+    }
+
+    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+        @Override
+        public Object createFromParcel(Parcel source) {
+            return new FeatureItem(source);
+        }
+
+        @Override
+        public Object[] newArray(int size) {
+            return new FeatureItem[size];
+        }
+    };
+}

+ 0 - 194
src/main/java/com/owncloud/android/features/FeatureList.java

@@ -1,194 +0,0 @@
-/*
- *   Nextcloud Android client application
- *
- *   @author Bartosz Przybylski
- *   Copyright (C) 2015 Bartosz Przybylski
- *   Copyright (C) 2015 ownCloud Inc.
- *   Copyright (C) 2016 Nextcloud.
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- *   License as published by the Free Software Foundation; either
- *   version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- *   You should have received a copy of the GNU Affero General Public
- *   License along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.owncloud.android.features;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.owncloud.android.MainApp;
-import com.owncloud.android.R;
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * @author Bartosz Przybylski
- */
-public class FeatureList {
-    private static final boolean SHOW_ON_FIRST_RUN = true;
-    private static final boolean SHOW_ON_UPGRADE = false;
-
-    private static final int VERSION_1_0_0 = 10000099;
-    private static final int VERSION_3_0_0 = 30000099;
-    private static final int VERSION_3_3_0 = 30030099;
-    private static final int BETA_VERSION_0 = 0;
-
-    static public List<FeatureItem> get(boolean isMultiAccount) {
-        List<FeatureItem> featuresList = new ArrayList<>();
-        // Basic features showed on first install
-        featuresList.add(new FeatureItem(R.drawable.whats_new_files,
-                R.string.welcome_feature_1_title, R.string.welcome_feature_1_text,
-                VERSION_1_0_0, BETA_VERSION_0, SHOW_ON_FIRST_RUN, true, false));
-        if (isMultiAccount) {
-            featuresList.add(new FeatureItem(R.drawable.whats_new_accounts,
-                    R.string.welcome_feature_2_title, R.string.welcome_feature_2_text,
-                    VERSION_1_0_0, BETA_VERSION_0, SHOW_ON_FIRST_RUN, true, false));
-        }
-        featuresList.add(new FeatureItem(R.drawable.whats_new_auto_upload,
-                R.string.welcome_feature_3_title, R.string.welcome_feature_3_text,
-                VERSION_1_0_0, BETA_VERSION_0, SHOW_ON_FIRST_RUN, true, false));
-
-        // 3.0.0
-        featuresList.add(new FeatureItem(R.drawable.whats_new_end_to_end_encryption,
-                R.string.whats_new_end_to_end_encryption_title, R.string.whats_new_end_to_end_encryption_content,
-                VERSION_3_0_0, BETA_VERSION_0, SHOW_ON_UPGRADE, false, false));
-        featuresList.add(new FeatureItem(R.drawable.whats_new_resized_images, R.string.whats_new_resized_images_title,
-                R.string.whats_new_resized_images_content, VERSION_3_0_0, BETA_VERSION_0, SHOW_ON_UPGRADE,
-                false, false));
-        featuresList.add(new FeatureItem(R.drawable.whats_new_ipv6, R.string.whats_new_ipv6_title,
-                R.string.whats_new_ipv6_content, VERSION_3_0_0,
-                BETA_VERSION_0, SHOW_ON_UPGRADE, false, false));
-
-        // 3.3.0
-        featuresList.add(new FeatureItem(R.drawable.whats_new_device_credentials,
-                R.string.whats_new_device_credentials_title, R.string.whats_new_device_credentials_content,
-                VERSION_3_3_0, BETA_VERSION_0, SHOW_ON_UPGRADE, false, false));
-
-        return featuresList;
-    }
-
-    static public FeatureItem[] getFiltered(int lastSeenVersionCode, boolean isFirstRun, boolean isBeta,
-                                            boolean isMultiAccount) {
-        List<FeatureItem> features = new LinkedList<>();
-
-        for (FeatureItem item : get(isMultiAccount)) {
-            final int itemVersionCode = isBeta ? item.getBetaVersionNumber() : item.getVersionCode();
-            if (isFirstRun && item.shouldShowOnFirstRun()) {
-                features.add(item);
-            } else if (!isFirstRun && !item.shouldShowOnFirstRun() &&
-                    MainApp.getVersionCode() >= itemVersionCode &&
-                    lastSeenVersionCode < itemVersionCode) {
-                features.add(item);
-            }
-        }
-        return features.toArray(new FeatureItem[features.size()]);
-    }
-
-    static public class FeatureItem implements Parcelable {
-        public static final int DO_NOT_SHOW = -1;
-        private int image;
-        private int titleText;
-        private int contentText;
-        private int versionCode;
-        private int betaVersion;
-        private boolean showOnInitialRun;
-        private boolean contentCentered;
-        private boolean bulletList;
-
-        public FeatureItem(int image, int titleText, int contentText, int version, int betaVersion) {
-            this(image, titleText, contentText, version, betaVersion, false, true, true);
-        }
-
-        public FeatureItem(int image, int titleText, int contentText, int version, int betaVersion,
-                           boolean showOnInitialRun) {
-            this(image, titleText, contentText, version, betaVersion, showOnInitialRun, true, true);
-        }
-
-        public FeatureItem(int image, int titleText, int contentText, int versionCode, int betaVersion,
-                           boolean showOnInitialRun, boolean contentCentered, boolean bulletList) {
-            this.image = image;
-            this.titleText = titleText;
-            this.contentText = contentText;
-            this.versionCode = versionCode;
-            this.betaVersion = betaVersion;
-            this.showOnInitialRun = showOnInitialRun;
-            this.contentCentered = contentCentered;
-            this.bulletList = bulletList;
-        }
-
-        public boolean shouldShowImage() { return image != DO_NOT_SHOW; }
-        public int getImage() { return image; }
-
-        public boolean shouldShowTitleText() { return titleText != DO_NOT_SHOW; }
-        public int getTitleText() { return titleText; }
-
-        public boolean shouldShowContentText() { return contentText != DO_NOT_SHOW; }
-        public int getContentText() { return contentText; }
-
-        public int getVersionCode() {
-            return versionCode;
-        }
-        public int getBetaVersionNumber() { return betaVersion; }
-        public boolean shouldShowOnFirstRun() { return showOnInitialRun; }
-
-        public boolean shouldContentCentered() {
-            return contentCentered;
-        }
-
-        public boolean shouldShowBulletPointList() {
-            return bulletList;
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(image);
-            dest.writeInt(titleText);
-            dest.writeInt(contentText);
-            dest.writeInt(versionCode);
-            dest.writeInt(betaVersion);
-            dest.writeByte((byte) (showOnInitialRun ? 1 : 0));
-            dest.writeByte((byte) (contentCentered ? 1 : 0));
-            dest.writeByte((byte) (bulletList ? 1 : 0));
-        }
-
-        private FeatureItem(Parcel p) {
-            image = p.readInt();
-            titleText = p.readInt();
-            contentText = p.readInt();
-            versionCode = p.readInt();
-            betaVersion = p.readInt();
-            showOnInitialRun = p.readByte() == 1;
-            contentCentered = p.readByte() == 1;
-            bulletList = p.readByte() == 1;
-        }
-        public static final Parcelable.Creator CREATOR =
-                new Parcelable.Creator() {
-
-                    @Override
-                    public Object createFromParcel(Parcel source) {
-                        return new FeatureItem(source);
-                    }
-
-                    @Override
-                    public Object[] newArray(int size) {
-                        return new FeatureItem[size];
-                    }
-                };
-    }
-}

+ 1 - 1
src/main/java/com/owncloud/android/ui/activity/BaseActivity.java

@@ -105,7 +105,7 @@ public abstract class BaseActivity extends AppCompatActivity {
     /**
      * Tries to swap the current ownCloud {@link Account} for other valid and existing.
      *
-     * If no valid ownCloud {@link Account} exists, the the user is requested
+     * If no valid ownCloud {@link Account} exists, then the user is requested
      * to create a new ownCloud {@link Account}.
      *
      * POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}.

+ 3 - 1
src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java

@@ -446,7 +446,9 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU
                 UserInfoActivity.openAccountRemovalConfirmationDialog(getAccount(), getFragmentManager(), true);
                 break;
             case R.id.drawer_menu_account_add:
-                createAccount(false);
+                Intent firstRunIntent = new Intent(getApplicationContext(), FirstRunActivity.class);
+                firstRunIntent.putExtra(FirstRunActivity.EXTRA_ALLOW_CLOSE, true);
+                startActivity(firstRunIntent);
                 break;
             case R.id.drawer_menu_account_manage:
                 Intent manageAccountsIntent = new Intent(getApplicationContext(), ManageAccountsActivity.class);

+ 228 - 0
src/main/java/com/owncloud/android/ui/activity/FirstRunActivity.java

@@ -0,0 +1,228 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Bartosz Przybylski
+ * Copyright (C) 2015 Bartosz Przybylski
+ * Copyright (C) 2015 ownCloud Inc.
+ * Copyright (C) 2016 Nextcloud.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.owncloud.android.ui.activity;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.v4.view.ViewPager;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.owncloud.android.MainApp;
+import com.owncloud.android.R;
+import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.authentication.AuthenticatorActivity;
+import com.owncloud.android.features.FeatureItem;
+import com.owncloud.android.ui.adapter.FeaturesViewAdapter;
+import com.owncloud.android.ui.whatsnew.ProgressIndicator;
+import com.owncloud.android.utils.DisplayUtils;
+
+/**
+ * Activity displaying general feature after a fresh install.
+ */
+public class FirstRunActivity extends BaseActivity implements ViewPager.OnPageChangeListener {
+
+    public static final String KEY_LAST_SEEN_VERSION_CODE = "lastSeenVersionCode";
+    public static final String EXTRA_ALLOW_CLOSE = "ALLOW_CLOSE";
+    public static final int FIRST_RUN_RESULT_CODE = 199;
+
+    private static final String TAG = FirstRunActivity.class.getSimpleName();
+
+    private ProgressIndicator mProgress;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.first_run_activity);
+
+        boolean isProviderOrOwnInstallationVisible = getResources().getBoolean(R.bool.show_provider_or_own_installation);
+        
+        setSlideshowSize(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
+
+        Button loginButton = findViewById(R.id.login);
+        loginButton.setBackgroundColor(Color.WHITE);
+        loginButton.setTextColor(Color.BLACK);
+
+        loginButton.setOnClickListener(v -> {
+            if (getIntent().getBooleanExtra(EXTRA_ALLOW_CLOSE, false)) {
+                Intent authenticatorActivityIntent = new Intent(this, AuthenticatorActivity.class);
+                authenticatorActivityIntent.putExtra(AuthenticatorActivity.EXTRA_USE_PROVIDER_AS_WEBLOGIN, false);
+                startActivityForResult(authenticatorActivityIntent, FIRST_RUN_RESULT_CODE);
+            } else {
+                finish();
+            }
+        });
+
+        Button providerButton = findViewById(R.id.signup);
+        providerButton.setBackgroundColor(getResources().getColor(R.color.primary_dark));
+        providerButton.setTextColor(getResources().getColor(R.color.login_text_color));
+        providerButton.setVisibility(isProviderOrOwnInstallationVisible ? View.VISIBLE : View.GONE);
+        providerButton.setOnClickListener(v -> {
+            Intent authenticatorActivityIntent = new Intent(this, AuthenticatorActivity.class);
+            authenticatorActivityIntent.putExtra(AuthenticatorActivity.EXTRA_USE_PROVIDER_AS_WEBLOGIN, true);
+
+            if (getIntent().getBooleanExtra(EXTRA_ALLOW_CLOSE, false)) {
+                startActivityForResult(authenticatorActivityIntent, FIRST_RUN_RESULT_CODE);
+            } else {
+                authenticatorActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                startActivity(authenticatorActivityIntent);
+            }
+        });
+
+        TextView hostOwnServerTextView = findViewById(R.id.host_own_server);
+        hostOwnServerTextView.setTextColor(getResources().getColor(R.color.login_text_color));
+        hostOwnServerTextView.setVisibility(isProviderOrOwnInstallationVisible ? View.VISIBLE : View.GONE);
+
+        mProgress = findViewById(R.id.progressIndicator);
+        ViewPager mPager = findViewById(R.id.contentPanel);
+
+        // Sometimes, accounts are not deleted when you uninstall the application so we'll do it now
+        if (isFirstRun(this)) {
+            AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE);
+            if (am != null) {
+                for (Account account : AccountUtils.getAccounts(this)) {
+                    am.removeAccount(account, null, null);
+                }
+            }
+        }
+
+        FeaturesViewAdapter featuresViewAdapter = new FeaturesViewAdapter(getSupportFragmentManager(),
+                getFirstRun());
+        mProgress.setNumberOfSteps(featuresViewAdapter.getCount());
+        mPager.setAdapter(featuresViewAdapter);
+
+        mPager.addOnPageChangeListener(this);
+    }
+
+    private void setSlideshowSize(boolean isLandscape) {
+        boolean isProviderOrOwnInstallationVisible = getResources().getBoolean(R.bool.show_provider_or_own_installation);
+        LinearLayout buttonLayout = findViewById(R.id.buttonLayout);
+        LinearLayout.LayoutParams layoutParams;
+
+        buttonLayout.setOrientation(isLandscape ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL);
+
+        LinearLayout bottomLayout = findViewById(R.id.bottomLayout);
+        if (isProviderOrOwnInstallationVisible) {
+            layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT);
+        } else {
+            layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                    DisplayUtils.convertDpToPixel(isLandscape ? 100f : 150f, this));
+        }
+
+        bottomLayout.setLayoutParams(layoutParams);
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            setSlideshowSize(true);
+        } else {
+            setSlideshowSize(false);
+        }
+    }
+
+    @Override
+    public void onBackPressed() {
+        onFinish();
+
+        if (getIntent().getBooleanExtra(EXTRA_ALLOW_CLOSE, false)) {
+            super.onBackPressed();
+        }
+    }
+
+    private void onFinish() {
+        SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
+        SharedPreferences.Editor editor = pref.edit();
+        editor.putInt(KEY_LAST_SEEN_VERSION_CODE, MainApp.getVersionCode());
+        editor.apply();
+    }
+
+    static private boolean isFirstRun(Context context) {
+        return AccountUtils.getCurrentOwnCloudAccount(context) == null;
+    }
+
+    static public boolean runIfNeeded(Context context) {
+        if (context instanceof FirstRunActivity) {
+            return false;
+        }
+
+        if (isFirstRun(context) && context instanceof AuthenticatorActivity) {
+            context.startActivity(new Intent(context, FirstRunActivity.class));
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+        // unused but to be implemented due to abstract parent
+    }
+
+    @Override
+    public void onPageSelected(int position) {
+        mProgress.animateToStep(position + 1);
+    }
+
+    @Override
+    public void onPageScrollStateChanged(int state) {
+        // unused but to be implemented due to abstract parent
+    }
+
+    public void onHostYourOwnServerClick(View view) {
+        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_server_install))));
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (FIRST_RUN_RESULT_CODE == requestCode && RESULT_OK == resultCode) {
+            setAccount(AccountUtils.getCurrentOwnCloudAccount(this));
+            onAccountSet(false);
+
+            Intent i = new Intent(this, FileDisplayActivity.class);
+            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            startActivity(i);
+        }
+    }
+
+    public static FeatureItem[] getFirstRun() {
+        return new FeatureItem[]{
+                new FeatureItem(R.drawable.logo, R.string.first_run_1_text, R.string.empty, true, false),
+                new FeatureItem(R.drawable.first_run_files, R.string.first_run_2_text, R.string.empty, true, false),
+                new FeatureItem(R.drawable.first_run_groupware, R.string.first_run_3_text, R.string.empty, true, false),
+                new FeatureItem(R.drawable.first_run_talk, R.string.first_run_4_text, R.string.empty, true, false)};
+    }
+}

+ 10 - 3
src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java

@@ -270,6 +270,13 @@ public class ManageAccountsActivity extends FileActivity
     }
 
     @Override
+    public void showFirstRunActivity() {
+        Intent firstRunIntent = new Intent(getApplicationContext(), FirstRunActivity.class);
+        firstRunIntent.putExtra(FirstRunActivity.EXTRA_ALLOW_CLOSE, true);
+        startActivity(firstRunIntent);
+    }
+
+    //    @Override
     public void createAccount() {
         AccountManager am = AccountManager.get(getApplicationContext());
         am.addAccount(MainApp.getAccountType(this),
@@ -286,9 +293,9 @@ public class ManageAccountsActivity extends FileActivity
                                 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
                                 AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), name);
                                 mAccountListAdapter = new AccountListAdapter(
-                                    ManageAccountsActivity.this,
-                                    getAccountListItems(),
-                                    mTintedCheck
+                                        ManageAccountsActivity.this,
+                                        getAccountListItems(),
+                                        mTintedCheck
                                 );
                                 mListView.setAdapter(mAccountListAdapter);
                                 runOnUiThread(new Runnable() {

+ 30 - 232
src/main/java/com/owncloud/android/ui/activity/WhatsNewActivity.java

@@ -22,48 +22,30 @@
 
 package com.owncloud.android.ui.activity;
 
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Build;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentPagerAdapter;
 import android.support.v4.view.ViewPager;
-import android.text.SpannableString;
-import android.text.Spanned;
-import android.text.style.BulletSpan;
-import android.view.Gravity;
-import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
 import android.widget.Button;
 import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
-import com.owncloud.android.authentication.AccountAuthenticatorActivity;
 import com.owncloud.android.authentication.AccountUtils;
-import com.owncloud.android.features.FeatureList;
-import com.owncloud.android.features.FeatureList.FeatureItem;
+import com.owncloud.android.features.FeatureItem;
+import com.owncloud.android.ui.adapter.FeaturesViewAdapter;
+import com.owncloud.android.ui.adapter.FeaturesWebViewAdapter;
 import com.owncloud.android.ui.whatsnew.ProgressIndicator;
 import com.owncloud.android.utils.ThemeUtils;
 
 /**
- * Activity displaying general feature after a fresh install and new features after an update.
+ * Activity displaying new features after an update.
  */
 public class WhatsNewActivity extends FragmentActivity implements ViewPager.OnPageChangeListener {
 
@@ -79,22 +61,12 @@ public class WhatsNewActivity extends FragmentActivity implements ViewPager.OnPa
         super.onCreate(savedInstanceState);
         setContentView(R.layout.whats_new_activity);
 
-        int fontColor = ThemeUtils.fontColor(this);
+        int fontColor = getResources().getColor(R.color.login_text_color);
 
         mProgress = findViewById(R.id.progressIndicator);
         mPager = findViewById(R.id.contentPanel);
-        final boolean isBeta = getResources().getBoolean(R.bool.is_beta);
-        final boolean isMultiAccount = getResources().getBoolean(R.bool.multiaccount_support);
         String[] urls = getResources().getStringArray(R.array.whatsnew_urls);
 
-        // Sometimes, accounts are not deleted when you uninstall the application so we'll do it now
-        if (isFirstRun()) {
-            AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE);
-            for (Account account : AccountUtils.getAccounts(this)) {
-                am.removeAccount(account, null, null);
-            }
-        }
-
         boolean showWebView = urls.length > 0;
 
         if (showWebView) {
@@ -104,29 +76,25 @@ public class WhatsNewActivity extends FragmentActivity implements ViewPager.OnPa
             mPager.setAdapter(featuresWebViewAdapter);
         } else {
             FeaturesViewAdapter featuresViewAdapter = new FeaturesViewAdapter(getSupportFragmentManager(),
-                    FeatureList.getFiltered(getLastSeenVersionCode(), isFirstRun(), isBeta, isMultiAccount));
+                    getWhatsNew(this));
             mProgress.setNumberOfSteps(featuresViewAdapter.getCount());
             mPager.setAdapter(featuresViewAdapter);
         }
 
         mPager.addOnPageChangeListener(this);
 
-
         mForwardFinishButton = findViewById(R.id.forward);
         ThemeUtils.colorImageButton(mForwardFinishButton, fontColor);
-        
-        mForwardFinishButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                if (mProgress.hasNextStep()) {
-                    mPager.setCurrentItem(mPager.getCurrentItem() + 1, true);
-                    mProgress.animateToStep(mPager.getCurrentItem() + 1);
-                } else {
-                    onFinish();
-                    finish();
-                }
-                updateNextButtonIfNeeded();
+
+        mForwardFinishButton.setOnClickListener(view -> {
+            if (mProgress.hasNextStep()) {
+                mPager.setCurrentItem(mPager.getCurrentItem() + 1, true);
+                mProgress.animateToStep(mPager.getCurrentItem() + 1);
+            } else {
+                onFinish();
+                finish();
             }
+            updateNextButtonIfNeeded();
         });
 
         if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
@@ -137,20 +105,15 @@ public class WhatsNewActivity extends FragmentActivity implements ViewPager.OnPa
 
         mSkipButton = findViewById(R.id.skip);
         mSkipButton.setTextColor(fontColor);
-        mSkipButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                onFinish();
-                finish();
-            }
+        mSkipButton.setOnClickListener(view -> {
+            onFinish();
+            finish();
         });
 
         TextView tv = findViewById(R.id.welcomeText);
 
         if (showWebView) {
             tv.setText(R.string.app_name);
-        } else if (isFirstRun()) {
-            tv.setText(R.string.empty);
         } else {
             tv.setText(String.format(getString(R.string.whats_new_title), MainApp.getVersionName()));
         }
@@ -164,7 +127,6 @@ public class WhatsNewActivity extends FragmentActivity implements ViewPager.OnPa
         super.onBackPressed();
     }
 
-
     private void updateNextButtonIfNeeded() {
         if (!mProgress.hasNextStep()) {
             mForwardFinishButton.setImageResource(R.drawable.ic_done_white);
@@ -182,15 +144,6 @@ public class WhatsNewActivity extends FragmentActivity implements ViewPager.OnPa
         editor.apply();
     }
 
-    static public int getLastSeenVersionCode() {
-        SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(MainApp.getAppContext());
-        return pref.getInt(KEY_LAST_SEEN_VERSION_CODE, 0);
-    }
-
-    static private boolean isFirstRun() {
-        return getLastSeenVersionCode() == 0 && AccountUtils.getCurrentOwnCloudAccount(MainApp.getAppContext()) == null;
-    }
-
     static public void runIfNeeded(Context context) {
         if (!context.getResources().getBoolean(R.bool.show_whats_new)) {
             return;
@@ -206,12 +159,7 @@ public class WhatsNewActivity extends FragmentActivity implements ViewPager.OnPa
     }
 
     static private boolean shouldShow(Context context) {
-        final boolean isBeta = context.getResources().getBoolean(R.bool.is_beta);
-        final boolean isMultiAccount = context.getResources().getBoolean(R.bool.multiaccount_support);
-
-        return (isFirstRun() && context instanceof AccountAuthenticatorActivity) || (!(isFirstRun() &&
-                (context instanceof FileDisplayActivity)) && !(context instanceof PassCodeActivity) &&
-                (FeatureList.getFiltered(getLastSeenVersionCode(), isFirstRun(), isBeta, isMultiAccount).length > 0));
+        return !(context instanceof PassCodeActivity) && (getWhatsNew(context).length > 0);
     }
 
     @Override
@@ -230,172 +178,22 @@ public class WhatsNewActivity extends FragmentActivity implements ViewPager.OnPa
         // unused but to be implemented due to abstract parent
     }
 
-    private final class FeaturesWebViewAdapter extends FragmentPagerAdapter {
-        private String[] mWebUrls;
-
-        public FeaturesWebViewAdapter(FragmentManager fm, String[] webUrls) {
-            super(fm);
-            mWebUrls = webUrls;
-        }
-
-        @Override
-        public Fragment getItem(int position) {
-            return FeatureWebFragment.newInstance(mWebUrls[position]);
-        }
-
-        @Override
-        public int getCount() {
-            return mWebUrls.length;
-        }
+    static private boolean isFirstRun(Context context) {
+        return AccountUtils.getCurrentOwnCloudAccount(context) == null;
     }
 
-    public static class FeatureWebFragment extends Fragment {
-        private String mWebUrl;
+    static private FeatureItem[] getWhatsNew(Context context) {
+        int itemVersionCode = 30030000;
 
-        static public FeatureWebFragment newInstance(String webUrl) {
-            FeatureWebFragment f = new FeatureWebFragment();
-            Bundle args = new Bundle();
-            args.putString("url", webUrl);
-            f.setArguments(args);
-            return f;
-        }
+        int lastSeenVersionCode = MainApp.getLastSeenVersionCode(context);
 
-        @Override
-        public void onCreate(@Nullable Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-            mWebUrl = getArguments() != null ? getArguments().getString("url") : null;
-        }
-
-        @SuppressLint("SetJavaScriptEnabled")
-        @Nullable
-        @Override
-        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, 
-                                 @Nullable Bundle savedInstanceState) {
-            View v = inflater.inflate(R.layout.whats_new_webview_element, container, false);
-
-            WebView webView = v.findViewById(R.id.whatsNewWebView);
-            webView.getSettings().setJavaScriptEnabled(true);
-            webView.getSettings().setDomStorageEnabled(true);
-            webView.getSettings().setAllowFileAccess(false);
-            webView.setWebViewClient(new WebViewClient());
-            webView.loadUrl(mWebUrl);
-
-            return v;
-        }
-    }
-
-    private final class FeaturesViewAdapter extends FragmentPagerAdapter {
-
-        private FeatureItem[] mFeatures;
-
-        public FeaturesViewAdapter(FragmentManager fm, FeatureItem[] features) {
-            super(fm);
-            mFeatures = features;
-        }
-
-        @Override
-        public Fragment getItem(int position) {
-            return FeatureFragment.newInstance(mFeatures[position]);
-        }
-
-        @Override
-        public int getCount() {
-            return mFeatures.length;
-        }
-    }
-
-    public static class FeatureFragment extends Fragment {
-        private FeatureItem mItem;
-
-        static public FeatureFragment newInstance(FeatureItem item) {
-            FeatureFragment f = new FeatureFragment();
-            Bundle args = new Bundle();
-            args.putParcelable("feature", item);
-            f.setArguments(args);
-            return f;
-        }
-
-        @Override
-        public void onCreate(@Nullable Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-            mItem = getArguments() != null ? (FeatureItem) getArguments().getParcelable("feature") : null;
-        }
-
-        @Nullable
-        @Override
-        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, 
-                                 @Nullable Bundle savedInstanceState) {
-            View v = inflater.inflate(R.layout.whats_new_element, container, false);
-            int fontColor = ThemeUtils.fontColor(getContext());
-
-            ImageView iv = v.findViewById(R.id.whatsNewImage);
-            if (mItem.shouldShowImage()) {
-                iv.setImageResource(mItem.getImage());
-            }
-
-            TextView titleTextView = v.findViewById(R.id.whatsNewTitle);
-            if (mItem.shouldShowTitleText()) {
-                titleTextView.setText(mItem.getTitleText());
-                titleTextView.setTextColor(fontColor);
-            }
-
-            if (mItem.shouldShowContentText()) {
-                LinearLayout linearLayout = v.findViewById(R.id.whatsNewTextLayout);
-
-
-                if (mItem.shouldShowBulletPointList()) {
-                    String[] texts = getText(mItem.getContentText()).toString().split("\n");
-
-                    for (String text : texts) {
-                        TextView textView = generateTextView(text, getContext(),
-                                mItem.shouldContentCentered(), fontColor, true);
-
-                        linearLayout.addView(textView);
-                    }
-                } else {
-                    TextView textView = generateTextView(getText(mItem.getContentText()).toString(),
-                            getContext(), mItem.shouldContentCentered(), fontColor, false);
-
-                    linearLayout.addView(textView);
-                }
-            }
-
-            return v;
-        }
-    }
-
-    private static TextView generateTextView(String text, Context context,
-                                             boolean shouldContentCentered, int fontColor,
-                                             boolean showBulletPoints) {
-        int standardMargin = context.getResources().getDimensionPixelSize(R.dimen.standard_margin);
-        int doubleMargin = context.getResources()
-                .getDimensionPixelSize(R.dimen.standard_double_margin);
-        int zeroMargin = context.getResources().getDimensionPixelSize(R.dimen.zero);
-
-        TextView textView = new TextView(context);
-        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-        layoutParams.setMargins(doubleMargin, standardMargin, doubleMargin, zeroMargin);
-        textView.setTextAppearance(context, R.style.NextcloudTextAppearanceMedium);
-        textView.setLayoutParams(layoutParams);
-
-        if (showBulletPoints) {
-            BulletSpan bulletSpan = new BulletSpan(standardMargin, fontColor);
-            SpannableString spannableString = new SpannableString(text);
-            spannableString.setSpan(bulletSpan, 0, spannableString.length(),
-                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-            textView.setText(spannableString);
+        if (!isFirstRun(context) && MainApp.getVersionCode() >= itemVersionCode
+                && lastSeenVersionCode < itemVersionCode) {
+            return new FeatureItem[]{(new FeatureItem(R.drawable.whats_new_device_credentials,
+                    R.string.whats_new_device_credentials_title, R.string.whats_new_device_credentials_content,
+                    false, false))};
         } else {
-            textView.setText(text);
+            return new FeatureItem[0];
         }
-        textView.setTextColor(fontColor);
-
-        if (!shouldContentCentered) {
-            textView.setGravity(Gravity.START);
-        } else {
-            textView.setGravity(Gravity.CENTER_HORIZONTAL);
-        }
-
-        return textView;
     }
 }

+ 2 - 2
src/main/java/com/owncloud/android/ui/adapter/AccountListAdapter.java

@@ -127,7 +127,7 @@ public class AccountListAdapter extends ArrayAdapter<AccountListItem> implements
         ((ImageView) actionView.findViewById(R.id.user_icon)).setImageResource(R.drawable.ic_account_plus);
 
         // bind action listener
-        actionView.setOnClickListener(v -> mListener.createAccount());
+        actionView.setOnClickListener(v -> mListener.showFirstRunActivity());
         return actionView;
     }
 
@@ -184,7 +184,7 @@ public class AccountListAdapter extends ArrayAdapter<AccountListItem> implements
      */
     public interface AccountListAdapterListener {
 
-        void createAccount();
+        void showFirstRunActivity();
     }
 
     /**

+ 28 - 0
src/main/java/com/owncloud/android/ui/adapter/FeaturesViewAdapter.java

@@ -0,0 +1,28 @@
+package com.owncloud.android.ui.adapter;
+
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+
+import com.owncloud.android.features.FeatureItem;
+import com.owncloud.android.ui.fragment.FeatureFragment;
+
+public class FeaturesViewAdapter extends FragmentPagerAdapter {
+
+    private FeatureItem[] mFeatures;
+
+    public FeaturesViewAdapter(FragmentManager fm, FeatureItem[] features) {
+        super(fm);
+        mFeatures = features;
+    }
+
+    @Override
+    public Fragment getItem(int position) {
+        return FeatureFragment.newInstance(mFeatures[position]);
+    }
+
+    @Override
+    public int getCount() {
+        return mFeatures.length;
+    }
+}

+ 26 - 0
src/main/java/com/owncloud/android/ui/adapter/FeaturesWebViewAdapter.java

@@ -0,0 +1,26 @@
+package com.owncloud.android.ui.adapter;
+
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+
+import com.owncloud.android.ui.fragment.FeatureWebFragment;
+
+public class FeaturesWebViewAdapter extends FragmentPagerAdapter {
+    private String[] mWebUrls;
+
+    public FeaturesWebViewAdapter(FragmentManager fm, String[] webUrls) {
+        super(fm);
+        mWebUrls = webUrls;
+    }
+
+    @Override
+    public Fragment getItem(int position) {
+        return FeatureWebFragment.newInstance(mWebUrls[position]);
+    }
+
+    @Override
+    public int getCount() {
+        return mWebUrls.length;
+    }
+}

+ 119 - 0
src/main/java/com/owncloud/android/ui/fragment/FeatureFragment.java

@@ -0,0 +1,119 @@
+package com.owncloud.android.ui.fragment;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.style.BulletSpan;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.owncloud.android.R;
+import com.owncloud.android.features.FeatureItem;
+
+
+public class FeatureFragment extends Fragment {
+    private FeatureItem mItem;
+
+    static public FeatureFragment newInstance(FeatureItem item) {
+        FeatureFragment f = new FeatureFragment();
+        Bundle args = new Bundle();
+        args.putParcelable("feature", item);
+        f.setArguments(args);
+        return f;
+    }
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mItem = getArguments() != null ? (FeatureItem) getArguments().getParcelable("feature") : null;
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+                             @Nullable Bundle savedInstanceState) {
+        View v = inflater.inflate(R.layout.whats_new_element, container, false);
+        int fontColor = getResources().getColor(R.color.login_text_color);
+
+        ImageView iv = v.findViewById(R.id.whatsNewImage);
+        if (mItem.shouldShowImage()) {
+            iv.setImageResource(mItem.getImage());
+        }
+
+        TextView titleTextView = v.findViewById(R.id.whatsNewTitle);
+        if (mItem.shouldShowTitleText()) {
+            titleTextView.setText(mItem.getTitleText());
+            titleTextView.setTextColor(fontColor);
+            titleTextView.setVisibility(View.VISIBLE);
+        } else {
+            titleTextView.setVisibility(View.GONE);
+        }
+
+        LinearLayout linearLayout = v.findViewById(R.id.whatsNewTextLayout);
+        if (mItem.shouldShowContentText()) {
+            if (mItem.shouldShowBulletPointList()) {
+                String[] texts = getText(mItem.getContentText()).toString().split("\n");
+
+                for (String text : texts) {
+                    TextView textView = generateTextView(text, getContext(),
+                            mItem.shouldContentCentered(), fontColor, true);
+
+                    linearLayout.addView(textView);
+                }
+            } else {
+                TextView textView = generateTextView(getText(mItem.getContentText()).toString(),
+                        getContext(), mItem.shouldContentCentered(), fontColor, false);
+
+                linearLayout.addView(textView);
+            }
+        } else {
+            linearLayout.setVisibility(View.GONE);
+        }
+
+        return v;
+    }
+
+    private TextView generateTextView(String text, Context context,
+                                      boolean shouldContentCentered, int fontColor,
+                                      boolean showBulletPoints) {
+        int standardMargin = context.getResources().getDimensionPixelSize(R.dimen.standard_margin);
+        int doubleMargin = context.getResources()
+                .getDimensionPixelSize(R.dimen.standard_double_margin);
+        int zeroMargin = context.getResources().getDimensionPixelSize(R.dimen.zero);
+
+        TextView textView = new TextView(context);
+        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+        layoutParams.setMargins(doubleMargin, standardMargin, doubleMargin, zeroMargin);
+        textView.setTextAppearance(context, R.style.NextcloudTextAppearanceMedium);
+        textView.setLayoutParams(layoutParams);
+
+        if (showBulletPoints) {
+            BulletSpan bulletSpan = new BulletSpan(standardMargin, fontColor);
+            SpannableString spannableString = new SpannableString(text);
+            spannableString.setSpan(bulletSpan, 0, spannableString.length(),
+                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+            textView.setText(spannableString);
+        } else {
+            textView.setText(text);
+        }
+        textView.setTextColor(fontColor);
+
+        if (!shouldContentCentered) {
+            textView.setGravity(Gravity.START);
+        } else {
+            textView.setGravity(Gravity.CENTER_HORIZONTAL);
+        }
+
+        return textView;
+    }
+}

+ 49 - 0
src/main/java/com/owncloud/android/ui/fragment/FeatureWebFragment.java

@@ -0,0 +1,49 @@
+package com.owncloud.android.ui.fragment;
+
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import com.owncloud.android.R;
+
+public class FeatureWebFragment extends Fragment {
+    private String mWebUrl;
+
+    static public FeatureWebFragment newInstance(String webUrl) {
+        FeatureWebFragment f = new FeatureWebFragment();
+        Bundle args = new Bundle();
+        args.putString("url", webUrl);
+        f.setArguments(args);
+        return f;
+    }
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mWebUrl = getArguments() != null ? getArguments().getString("url") : null;
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater,
+                             @Nullable ViewGroup container,
+                             @Nullable Bundle savedInstanceState) {
+        View v = inflater.inflate(R.layout.whats_new_webview_element, container, false);
+
+        WebView webView = v.findViewById(R.id.whatsNewWebView);
+        webView.getSettings().setJavaScriptEnabled(true);
+        webView.getSettings().setDomStorageEnabled(true);
+        webView.getSettings().setAllowFileAccess(false);
+        webView.setWebViewClient(new WebViewClient());
+        webView.loadUrl(mWebUrl);
+
+        return v;
+    }
+}

+ 1 - 2
src/main/java/com/owncloud/android/ui/whatsnew/ProgressIndicator.java

@@ -33,7 +33,6 @@ import android.widget.ImageView;
 import android.widget.LinearLayout;
 
 import com.owncloud.android.R;
-import com.owncloud.android.utils.ThemeUtils;
 
 /**
  * Progress indicator visualizing the actual progress with dots.
@@ -65,7 +64,7 @@ public class ProgressIndicator extends FrameLayout {
     }
 
     public void setNumberOfSteps(int steps) {
-        int fontColor = ThemeUtils.fontColor(getContext());
+        int fontColor = getResources().getColor(R.color.login_text_color);
         mNumberOfSteps = steps;
         mDotsContainer.removeAllViews();
         for (int i = 0; i < steps; ++i) {

+ 8 - 0
src/main/java/com/owncloud/android/utils/DisplayUtils.java

@@ -50,6 +50,7 @@ import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.text.style.StyleSpan;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -762,6 +763,13 @@ public class DisplayUtils {
         }
     }
 
+    public static int convertDpToPixel(float dp, Context context) {
+        Resources resources = context.getResources();
+        DisplayMetrics metrics = resources.getDisplayMetrics();
+
+        return (int) (dp * ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT));
+    }
+    
     static public void showServerOutdatedSnackbar(Activity activity) {
         Snackbar.make(activity.findViewById(android.R.id.content),
                 R.string.outdated_server, Snackbar.LENGTH_INDEFINITE)

+ 11 - 0
src/main/res/drawable/first_run_files.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="16dp"
+        android:height="16dp"
+        android:viewportWidth="16"
+        android:viewportHeight="16">
+
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M1.5,2 C1.25,2,1,2.25,1,2.5 L1,13.5 C1,13.76,1.24,14,1.5,14 L14.5,14 C14.76,14,15,13.759,15,13.5 L15,4.5 C15,4.25,14.75,4,14.5,4 L8,4 L6,2 L1.5,2 Z M10.25,5.5 A1.25,1.25,0,0,1,11.5,6.75 A1.25,1.25,0,0,1,10.25,8 A1.25,1.25,0,0,1,9.4492,7.709 L6.998,8.9355 A1.25,1.25,0,0,1,7,9 A1.25,1.25,0,0,1,6.9961,9.0645 L9.4492,10.291 A1.25,1.25,0,0,1,10.25,10 A1.25,1.25,0,0,1,11.5,11.25 A1.25,1.25,0,0,1,10.25,12.5 A1.25,1.25,0,0,1,9,11.25 A1.25,1.25,0,0,1,9.0039,11.186 L6.5508,9.959 A1.25,1.25,0,0,1,5.75,10.25 A1.25,1.25,0,0,1,4.5,9 A1.25,1.25,0,0,1,5.75,7.75 A1.25,1.25,0,0,1,6.5508,8.041 L9.002,6.8145 A1.25,1.25,0,0,1,9,6.75 A1.25,1.25,0,0,1,10.25,5.5 Z"/>
+</vector>

+ 11 - 0
src/main/res/drawable/first_run_groupware.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="16dp"
+        android:height="16dp"
+        android:viewportWidth="16"
+        android:viewportHeight="16">
+
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M9,1 C7.254,1,6,2.43,6,3.8 C6,5.2,6.1,6.2,6.8,7.3 C7.024,7.59,7.285,7.65,7.5,7.9 C7.635,8.4,7.74,8.9,7.6,9.4 C7.164,9.553,6.75,9.732,6.33,9.9 C5.82,9.627,5.23,9.4,4.72,9.2 C4.65,8.92,4.7,8.713,4.77,8.45 C4.89,8.325,5,8.27,5.13,8.15 C5.5,7.7,5.52,6.94,5.52,6.4 C5.52,5.6,4.8,5,4.02,5 C3.15,5,2.52,5.72,2.52,6.4 L2.5,6.4 C2.5,7.1,2.55,7.6,2.9,8.15 C3,8.3,3.142,8.325,3.25,8.45 C3.3174,8.7,3.371,8.95,3.3,9.2 C2.66,9.423,2.056,9.7,1.5,10 C1.08,10.3,1.267,10.182,1,11.15 C0.876,11.65,2.3,11.88,3.32,11.96 C3.27,12.235,3.2,12.6,3,13.3 C2.68,14.55,7.353,15,9,15 C11.43,15,15.313,14.544,14.98,13.3 C14.46,11.36,14.772,11.59,14,11 C12.91,10.346,11.548,9.833,10.4,9.4 C10.25,8.843,10.36,8.43,10.5,7.9 C10.735,7.65,11,7.54,11.22,7.3 C11.91,6.416,12,4.876,12,3.8 C12,2.214,10.57,1,9,1 Z"/>
+</vector>

+ 16 - 0
src/main/res/drawable/first_run_talk.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="16dp"
+        android:height="16dp"
+        android:viewportWidth="16"
+        android:viewportHeight="16">
+
+    <group
+        android:translateX="-15.580506"
+        android:translateY="-164.12649">
+        <path
+            android:fillColor="#ffffff"
+            android:strokeWidth="0.13229023"
+            android:pathData="M 23.579679,165.51155 a 6.6138496,6.6139445 0 0 0 -6.613756,6.61414 6.6138496,6.6139445 0 0 0 6.613756,6.61394 6.6138496,6.6139445 0 0 0 3.430853,-0.96761 c 0.812866,0.32302 2.633614,1.28133 3.066959,0.86739 0.452829,-0.43245 -0.531627,-2.46778 -0.767642,-3.2241 a 6.6138496,6.6139445 0 0 0 0.88351,-3.28968 6.6138496,6.6139445 0 0 0 -6.613662,-6.61385 z m 0.000769,2.51456 a 4.1009972,4.1010914 0 0 1 4.100984,4.10109 4.1009972,4.1010914 0 0 1 -4.100997,4.10081 4.1009972,4.1010914 0 0 1 -4.100997,-4.10081 4.1009972,4.1010914 0 0 1 4.100997,-4.10109 z"/>
+    </group>
+</vector>

+ 0 - 20
src/main/res/layout-land/account_setup.xml

@@ -288,26 +288,6 @@
 			android:text="@string/setup_btn_connect"
 			android:contentDescription="@string/setup_btn_connect"
 			android:visibility="gone"/>
-
-		<LinearLayout
-			android:layout_width="match_parent"
-			android:layout_height="match_parent"
-			android:gravity="center|bottom">
-
-			<Button
-				android:id="@+id/welcome_link"
-				android:layout_width="wrap_content"
-				android:layout_height="wrap_content"
-				android:layout_gravity="center_horizontal"
-				android:background="@android:color/transparent"
-				android:onClick="onRegisterClick"
-				android:paddingTop="@dimen/alternate_half_padding"
-				android:text="@string/auth_register"
-				android:textColor="@color/login_text_hint_color"
-				android:contentDescription="@string/auth_register"/>
-
-		</LinearLayout>
-
 	</LinearLayout>
 		
 </RelativeLayout>

+ 0 - 19
src/main/res/layout/account_setup.xml

@@ -271,25 +271,6 @@
             android:text="@string/setup_btn_connect"
             android:contentDescription="@string/setup_btn_connect"
             android:visibility="gone"/>
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:gravity="center|bottom">
-
-            <Button
-                android:id="@+id/welcome_link"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:background="@android:color/transparent"
-                android:onClick="onRegisterClick"
-                android:paddingBottom="@dimen/alternate_half_padding"
-                android:paddingTop="@dimen/alternate_half_padding"
-                android:text="@string/auth_register"
-                android:textColor="@color/login_text_hint_color"
-                android:contentDescription="@string/auth_register"/>
-            
-        </LinearLayout>
         </LinearLayout>
 
     </LinearLayout>

+ 100 - 0
src/main/res/layout/first_run_activity.xml

@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Nextcloud Android client application
+
+  @author Tobias Kaminsky
+  Copyright (C) 2018 Tobias Kaminsky
+  Copyright (C) 2018 Nextcloud GmbH.
+ 
+  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, see <https://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/standard_margin"
+        android:layout_weight="1"
+        android:orientation="vertical">
+
+        <android.support.v4.view.ViewPager
+            android:id="@+id/contentPanel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"/>
+
+        <com.owncloud.android.ui.whatsnew.ProgressIndicator
+            android:id="@+id/progressIndicator"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/standard_margin">
+
+        </com.owncloud.android.ui.whatsnew.ProgressIndicator>
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/bottomLayout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="15dp"
+        android:layout_marginLeft="15dp"
+        android:layout_marginRight="15dp"
+        android:layout_weight="0"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:id="@+id/buttonLayout"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <Button
+                android:id="@+id/login"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:layout_margin="5dp"
+                android:layout_weight="1"
+                android:maxWidth="500dp"
+                android:minWidth="300dp"
+                android:text="@string/login"/>
+
+            <Button
+                android:id="@+id/signup"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:layout_margin="5dp"
+                android:layout_weight="1"
+                android:maxWidth="500dp"
+                android:minWidth="300dp"
+                android:text="@string/signup_with_provider"/>
+        </LinearLayout>
+
+        <TextView
+            android:id="@+id/host_own_server"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="10dp"
+            android:layout_marginTop="10dp"
+            android:gravity="center_horizontal"
+            android:onClick="onHostYourOwnServerClick"
+            android:text="@string/host_your_own_server"/>
+    </LinearLayout>
+
+</LinearLayout>

+ 4 - 2
src/main/res/layout/whats_new_activity.xml

@@ -47,8 +47,10 @@
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="0dp"
+        android:layout_marginBottom="@dimen/standard_margin"
         android:layout_marginLeft="@dimen/standard_margin"
         android:layout_marginRight="@dimen/standard_margin"
+        android:layout_marginTop="@dimen/standard_double_margin"
         android:layout_weight="8"
         android:orientation="horizontal"
         android:weightSum="3">
@@ -86,8 +88,8 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center"
-                android:src="@drawable/arrow_right"
-                android:contentDescription="@string/forward"/>
+                android:contentDescription="@string/forward"
+                android:src="@drawable/arrow_right"/>
         </LinearLayout>
     </LinearLayout>
 

+ 24 - 24
src/main/res/layout/whats_new_element.xml

@@ -20,48 +20,48 @@
   License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:orientation="vertical"
+              xmlns:app="http://schemas.android.com/apk/res-auto"
               android:layout_width="match_parent"
-              android:layout_height="match_parent"
+              android:layout_height="wrap_content"
+              android:gravity="center"
+              android:orientation="vertical"
               android:weightSum="100">
 
     <ImageView
-        android:layout_width="wrap_content"
-        android:layout_height="0dp"
         android:id="@+id/whatsNewImage"
+        android:layout_width="200dp"
+        android:layout_height="0dp"
         android:layout_gravity="center_horizontal"
         android:layout_marginBottom="@dimen/alternate_margin"
-        android:layout_weight="50"
-        android:src="@drawable/whats_new_files"
-        android:contentDescription="@string/what_s_new_image"/>
+        android:layout_weight="60"
+        android:contentDescription="@string/what_s_new_image"
+        app:srcCompat="@drawable/whats_new_files"/>
 
     <TextView
+        android:id="@+id/whatsNewTitle"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:textAppearance="@style/NextcloudTextAppearanceHeadline"
-        android:textColor="@color/white"
-        android:textStyle="bold"
-        android:text="@string/welcome_feature_1_title"
-        android:id="@+id/whatsNewTitle"
+        android:layout_gravity="center_horizontal|center"
+        android:layout_marginBottom="@dimen/standard_half_margin"
+        android:layout_marginEnd="@dimen/standard_margin"
         android:layout_marginLeft="@dimen/standard_margin"
-        android:layout_marginStart="@dimen/standard_margin"
         android:layout_marginRight="@dimen/standard_margin"
-        android:layout_marginEnd="@dimen/standard_margin"
-        android:layout_marginBottom="@dimen/standard_half_margin"
-        android:layout_gravity="center_horizontal"
-        android:gravity="center"/>
+        android:layout_marginStart="@dimen/standard_margin"
+        android:gravity="center"
+        android:text="@string/welcome_feature_1_title"
+        android:textAppearance="@style/NextcloudTextAppearanceHeadline"
+        android:textColor="@color/white"
+        android:textStyle="bold"/>
 
     <LinearLayout
         android:id="@+id/whatsNewTextLayout"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal"
-        android:gravity="center"
-        android:layout_marginLeft="@dimen/standard_margin"
-        android:layout_marginStart="@dimen/standard_margin"
-        android:layout_marginRight="@dimen/standard_margin"
+        android:layout_gravity="center_horizontal|center"
+        android:layout_margin="@dimen/standard_margin"
         android:layout_marginEnd="@dimen/standard_margin"
-        android:layout_marginBottom="@dimen/standard_half_margin"
+        android:layout_marginStart="@dimen/standard_margin"
+        android:gravity="center"
         android:orientation="vertical">
     </LinearLayout>
 </LinearLayout>

+ 2 - 2
src/main/res/values/setup.xml

@@ -27,8 +27,8 @@
     <!-- Can be regular (full input), prefix (subdomain input) and suffix (directory input) -->
     <!-- Requires server url to be set -->
     <string name="server_input_type">regular</string>
-    <bool name="show_welcome_link">true</bool>
-    <string name="welcome_link_url">"https://nextcloud.com/providers"</string>
+    <bool name="show_provider_or_own_installation">true</bool>
+    <string name="provider_registration_server">https://www.nextcloud.com/register</string>
 
     <!-- Flags to setup the authentication methods available in the app -->
     <string name="auth_method_oauth2">off</string>

+ 7 - 1
src/main/res/values/strings.xml

@@ -797,6 +797,13 @@
     <string name="prefs_e2e_mnemonic">E2E mnemonic</string>
     <string name="prefs_e2e_no_device_credentials">To show mnemonic please enable device credentials.</string>
     <string name="whats_new_device_credentials_title">Use Android\'s device internal protection</string>
+    <string name="login">Log in</string>
+    <string name="signup_with_provider">Sign up with provider</string>
+    <string name="host_your_own_server">Host your own server</string>
+    <string name="first_run_1_text">Keep your data secure and under your control</string>
+    <string name="first_run_2_text">Secure collaboration &amp; file exchange</string>
+    <string name="first_run_3_text">Easy-to-use web mail, calendering &amp; contacts</string>
+    <string name="first_run_4_text">Screensharing, online meetings &amp; web conferences</string>
     <string name="whats_new_device_credentials_content">Use anything like a pattern, password, pin or your fingerprint to keep your data safe.</string>
     <string name="restore_button_description">Restore deleted file</string>
 	<string name="restore">Restore file</string>
@@ -810,7 +817,6 @@
     <string name="new_media_folder_detected">New %1$s media folder detected.</string>
     <string name="new_media_folder_photos">photo</string>
     <string name="new_media_folder_videos">video</string>
-
     <string name="outdated_server">The server has reached end of life, please upgrade!</string>
     <string name="dismiss">Dismiss</string>
     <string name="feedback_no_mail_app">No app available to send mails!</string>