1 /* ownCloud Android client application 
   2  *   Copyright (C) 2012  Bartek Przybylski 
   3  *   Copyright (C) 2012-2013 ownCloud Inc. 
   5  *   This program is free software: you can redistribute it and/or modify 
   6  *   it under the terms of the GNU General Public License version 2, 
   7  *   as published by the Free Software Foundation. 
   9  *   This program is distributed in the hope that it will be useful, 
  10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of 
  11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  12  *   GNU General Public License for more details. 
  14  *   You should have received a copy of the GNU General Public License 
  15  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  19 package com
.owncloud
.android
.authentication
; 
  21 import java
.security
.cert
.X509Certificate
; 
  23 import android
.accounts
.Account
; 
  24 import android
.accounts
.AccountManager
; 
  25 import android
.app
.AlertDialog
; 
  26 import android
.app
.Dialog
; 
  27 import android
.app
.ProgressDialog
; 
  28 import android
.content
.DialogInterface
; 
  29 import android
.content
.Intent
; 
  30 import android
.content
.SharedPreferences
; 
  31 import android
.graphics
.Rect
; 
  32 import android
.graphics
.drawable
.Drawable
; 
  33 import android
.net
.Uri
; 
  34 import android
.net
.http
.SslError
; 
  35 import android
.os
.Bundle
; 
  36 import android
.os
.Handler
; 
  37 import android
.preference
.PreferenceManager
; 
  38 import android
.support
.v4
.app
.Fragment
; 
  39 import android
.support
.v4
.app
.FragmentManager
; 
  40 import android
.support
.v4
.app
.FragmentTransaction
; 
  41 import android
.text
.Editable
; 
  42 import android
.text
.InputType
; 
  43 import android
.text
.TextWatcher
; 
  44 import android
.view
.KeyEvent
; 
  45 import android
.view
.MotionEvent
; 
  46 import android
.view
.View
; 
  47 import android
.view
.View
.OnFocusChangeListener
; 
  48 import android
.view
.View
.OnTouchListener
; 
  49 import android
.view
.Window
; 
  50 import android
.view
.inputmethod
.EditorInfo
; 
  51 import android
.webkit
.SslErrorHandler
; 
  52 import android
.widget
.Button
; 
  53 import android
.widget
.CheckBox
; 
  54 import android
.widget
.EditText
; 
  55 import android
.widget
.TextView
; 
  56 import android
.widget
.TextView
.OnEditorActionListener
; 
  58 import com
.actionbarsherlock
.app
.SherlockDialogFragment
; 
  59 import com
.owncloud
.android
.MainApp
; 
  60 import com
.owncloud
.android
.R
; 
  61 import com
.owncloud
.android
.authentication
.SsoWebViewClient
.SsoWebViewClientListener
; 
  62 import com
.owncloud
.android
.lib
.common
.accounts
.AccountTypeUtils
; 
  63 import com
.owncloud
.android
.lib
.common
.accounts
.AccountUtils
.Constants
; 
  64 import com
.owncloud
.android
.lib
.common
.OwnCloudClientFactory
; 
  65 import com
.owncloud
.android
.lib
.common
.OwnCloudClient
; 
  66 import com
.owncloud
.android
.operations
.DetectAuthenticationMethodOperation
; 
  67 import com
.owncloud
.android
.operations
.DetectAuthenticationMethodOperation
.AuthenticationMethod
; 
  68 import com
.owncloud
.android
.operations
.OAuth2GetAccessToken
; 
  70 import com
.owncloud
.android
.lib
.common
.network
.CertificateCombinedException
; 
  71 import com
.owncloud
.android
.lib
.common
.operations
.OnRemoteOperationListener
; 
  72 import com
.owncloud
.android
.lib
.resources
.status
.GetRemoteStatusOperation
; 
  73 import com
.owncloud
.android
.lib
.common
.operations
.RemoteOperation
; 
  74 import com
.owncloud
.android
.lib
.common
.operations
.RemoteOperationResult
; 
  75 import com
.owncloud
.android
.lib
.common
.operations
.RemoteOperationResult
.ResultCode
; 
  76 import com
.owncloud
.android
.lib
.resources
.files
.ExistenceCheckRemoteOperation
; 
  77 import com
.owncloud
.android
.lib
.resources
.users
.GetRemoteUserNameOperation
; 
  79 import com
.owncloud
.android
.ui
.dialog
.SamlWebViewDialog
; 
  80 import com
.owncloud
.android
.ui
.dialog
.SslUntrustedCertDialog
; 
  81 import com
.owncloud
.android
.ui
.dialog
.SslUntrustedCertDialog
.OnSslUntrustedCertListener
; 
  82 import com
.owncloud
.android
.utils
.Log_OC
; 
  83 import com
.owncloud
.android
.lib
.resources
.status
.OwnCloudVersion
; 
  86  * This Activity is used to add an ownCloud account to the App 
  88  * @author Bartek Przybylski 
  89  * @author David A. Velasco 
  91 public class AuthenticatorActivity 
extends AccountAuthenticatorActivity
 
  92 implements  OnRemoteOperationListener
, OnFocusChangeListener
, OnEditorActionListener
,  
  93 SsoWebViewClientListener
, OnSslUntrustedCertListener 
{ 
  95     private static final String TAG 
= AuthenticatorActivity
.class.getSimpleName(); 
  97     public static final String EXTRA_ACCOUNT 
= "ACCOUNT"; 
  98     public static final String EXTRA_USER_NAME 
= "USER_NAME"; 
  99     public static final String EXTRA_HOST_NAME 
= "HOST_NAME"; 
 100     public static final String EXTRA_ACTION 
= "ACTION"; 
 101     public static final String EXTRA_ENFORCED_UPDATE 
= "ENFORCE_UPDATE"; 
 103     private static final String KEY_AUTH_MESSAGE_VISIBILITY 
= "AUTH_MESSAGE_VISIBILITY"; 
 104     private static final String KEY_AUTH_MESSAGE_TEXT 
= "AUTH_MESSAGE_TEXT"; 
 105     private static final String KEY_HOST_URL_TEXT 
= "HOST_URL_TEXT"; 
 106     private static final String KEY_OC_VERSION 
= "OC_VERSION"; 
 107     private static final String KEY_ACCOUNT 
= "ACCOUNT"; 
 108     private static final String KEY_SERVER_VALID 
= "SERVER_VALID"; 
 109     private static final String KEY_SERVER_CHECKED 
= "SERVER_CHECKED"; 
 110     private static final String KEY_SERVER_CHECK_IN_PROGRESS 
= "SERVER_CHECK_IN_PROGRESS";  
 111     private static final String KEY_SERVER_STATUS_TEXT 
= "SERVER_STATUS_TEXT"; 
 112     private static final String KEY_SERVER_STATUS_ICON 
= "SERVER_STATUS_ICON"; 
 113     private static final String KEY_IS_SSL_CONN 
= "IS_SSL_CONN"; 
 114     private static final String KEY_PASSWORD_VISIBLE 
= "PASSWORD_VISIBLE"; 
 115     private static final String KEY_AUTH_STATUS_TEXT 
= "AUTH_STATUS_TEXT"; 
 116     private static final String KEY_AUTH_STATUS_ICON 
= "AUTH_STATUS_ICON"; 
 117     private static final String KEY_REFRESH_BUTTON_ENABLED 
= "KEY_REFRESH_BUTTON_ENABLED"; 
 118     //private static final String KEY_IS_SHARED_SUPPORTED = "KEY_IS_SHARE_SUPPORTED"; 
 120     private static final String AUTH_ON 
= "on"; 
 121     private static final String AUTH_OFF 
= "off"; 
 122     private static final String AUTH_OPTIONAL 
= "optional"; 
 124     private static final int DIALOG_LOGIN_PROGRESS 
= 0; 
 125     private static final int DIALOG_CERT_NOT_SAVED 
= 1; 
 126     private static final int DIALOG_OAUTH2_LOGIN_PROGRESS 
= 2; 
 128     public static final byte ACTION_CREATE 
= 0; 
 129     public static final byte ACTION_UPDATE_TOKEN 
= 1; 
 131     private static final String TAG_SAML_DIALOG 
= "samlWebViewDialog"; 
 133     private String mHostBaseUrl
; 
 134     private OwnCloudVersion mDiscoveredVersion
; 
 136     private String mAuthMessageText
; 
 137     private int mAuthMessageVisibility
, mServerStatusText
, mServerStatusIcon
; 
 138     private boolean mServerIsChecked
, mServerIsValid
, mIsSslConn
; 
 139     private int mAuthStatusText
, mAuthStatusIcon
;     
 140     private TextView mAuthStatusLayout
; 
 142     private final Handler mHandler 
= new Handler(); 
 143     private Thread mOperationThread
; 
 144     private GetRemoteStatusOperation mOcServerChkOperation
; 
 145     private ExistenceCheckRemoteOperation mAuthCheckOperation
; 
 147     private Uri mNewCapturedUriFromOAuth2Redirection
; 
 149     private AccountManager mAccountMgr
; 
 150     private boolean mJustCreated
; 
 151     private byte mAction
; 
 152     private Account mAccount
; 
 154     private TextView mAuthMessage
; 
 156     private EditText mHostUrlInput
; 
 157     private boolean mHostUrlInputEnabled
; 
 158     private View mRefreshButton
; 
 160     private String mAuthTokenType
; 
 162     private EditText mUsernameInput
; 
 163     private EditText mPasswordInput
; 
 165     private CheckBox mOAuth2Check
; 
 167     private TextView mOAuthAuthEndpointText
; 
 168     private TextView mOAuthTokenEndpointText
; 
 170     private SamlWebViewDialog mSamlDialog
; 
 172     private View mOkButton
; 
 174     private String mAuthToken
; 
 176     private boolean mResumed
; // Control if activity is resumed 
 178     public static String DIALOG_UNTRUSTED_CERT 
= "DIALOG_UNTRUSTED_CERT"; 
 180     private DetectAuthenticationMethodOperation mDetectAuthenticationOperation
; 
 186      * IMPORTANT ENTRY POINT 1: activity is shown to the user 
 189     protected void onCreate(Bundle savedInstanceState
) { 
 190         super.onCreate(savedInstanceState
); 
 191         getWindow().requestFeature(Window
.FEATURE_NO_TITLE
); 
 193         /// set view and get references to view elements 
 194         setContentView(R
.layout
.account_setup
); 
 195         mAuthMessage 
= (TextView
) findViewById(R
.id
.auth_message
); 
 196         mHostUrlInput 
= (EditText
) findViewById(R
.id
.hostUrlInput
); 
 197         mHostUrlInput
.setText(getString(R
.string
.server_url
));  // valid although R.string.server_url is an empty string 
 198         mUsernameInput 
= (EditText
) findViewById(R
.id
.account_username
); 
 199         mPasswordInput 
= (EditText
) findViewById(R
.id
.account_password
); 
 200         mOAuthAuthEndpointText 
= (TextView
)findViewById(R
.id
.oAuthEntryPoint_1
); 
 201         mOAuthTokenEndpointText 
= (TextView
)findViewById(R
.id
.oAuthEntryPoint_2
); 
 202         mOAuth2Check 
= (CheckBox
) findViewById(R
.id
.oauth_onOff_check
); 
 203         mOkButton 
= findViewById(R
.id
.buttonOK
); 
 204         mAuthStatusLayout 
= (TextView
) findViewById(R
.id
.auth_status_text
);  
 206         /// set Host Url Input Enabled 
 207         mHostUrlInputEnabled 
= getResources().getBoolean(R
.bool
.show_server_url_input
); 
 209         /// set visibility of link for new users 
 210         boolean accountRegisterVisibility 
= getResources().getBoolean(R
.bool
.show_welcome_link
); 
 211         Button welcomeLink 
= (Button
) findViewById(R
.id
.welcome_link
); 
 212         if (welcomeLink 
!= null
) { 
 213             if (accountRegisterVisibility
) { 
 214                 welcomeLink
.setVisibility(View
.VISIBLE
); 
 215                 welcomeLink
.setText(String
.format(getString(R
.string
.auth_register
), getString(R
.string
.app_name
)));             
 217                 findViewById(R
.id
.welcome_link
).setVisibility(View
.GONE
); 
 222         mAccountMgr 
= AccountManager
.get(this); 
 223         mNewCapturedUriFromOAuth2Redirection 
= null
; 
 224         mAction 
= getIntent().getByteExtra(EXTRA_ACTION
, ACTION_CREATE
);  
 227         boolean refreshButtonEnabled 
= false
; 
 229         // URL input configuration applied 
 230         if (!mHostUrlInputEnabled
) 
 232             findViewById(R
.id
.hostUrlFrame
).setVisibility(View
.GONE
); 
 233             mRefreshButton 
= findViewById(R
.id
.centeredRefreshButton
); 
 236             mRefreshButton 
= findViewById(R
.id
.embeddedRefreshButton
); 
 239         if (savedInstanceState 
== null
) { 
 241             /// connection state and info 
 242             mAuthMessageVisibility 
= View
.GONE
; 
 243             mServerStatusText 
= mServerStatusIcon 
= 0; 
 244             mServerIsValid 
= false
; 
 245             mServerIsChecked 
= false
; 
 247             mAuthStatusText 
= mAuthStatusIcon 
= 0; 
 249             /// retrieve extras from intent 
 250             mAccount 
= getIntent().getExtras().getParcelable(EXTRA_ACCOUNT
); 
 251             if (mAccount 
!= null
) { 
 252                 String ocVersion 
= mAccountMgr
.getUserData(mAccount
, Constants
.KEY_OC_VERSION
); 
 253                 if (ocVersion 
!= null
) { 
 254                     mDiscoveredVersion 
= new OwnCloudVersion(ocVersion
); 
 256                 mHostBaseUrl 
= normalizeUrl(mAccountMgr
.getUserData(mAccount
, Constants
.KEY_OC_BASE_URL
)); 
 257                 mHostUrlInput
.setText(mHostBaseUrl
); 
 258                 String userName 
= mAccount
.name
.substring(0, mAccount
.name
.lastIndexOf('@')); 
 259                 mUsernameInput
.setText(userName
); 
 262             initAuthorizationMethod();  // checks intent and setup.xml to determine mCurrentAuthorizationMethod 
 265             if (mAction 
== ACTION_UPDATE_TOKEN 
|| !mHostUrlInputEnabled
) { 
 271             /// connection state and info 
 272             mAuthMessageVisibility 
= savedInstanceState
.getInt(KEY_AUTH_MESSAGE_VISIBILITY
); 
 273             mAuthMessageText 
= savedInstanceState
.getString(KEY_AUTH_MESSAGE_TEXT
); 
 274             mServerIsValid 
= savedInstanceState
.getBoolean(KEY_SERVER_VALID
); 
 275             mServerIsChecked 
= savedInstanceState
.getBoolean(KEY_SERVER_CHECKED
); 
 276             mServerStatusText 
= savedInstanceState
.getInt(KEY_SERVER_STATUS_TEXT
); 
 277             mServerStatusIcon 
= savedInstanceState
.getInt(KEY_SERVER_STATUS_ICON
); 
 278             mIsSslConn 
= savedInstanceState
.getBoolean(KEY_IS_SSL_CONN
); 
 279             mAuthStatusText 
= savedInstanceState
.getInt(KEY_AUTH_STATUS_TEXT
); 
 280             mAuthStatusIcon 
= savedInstanceState
.getInt(KEY_AUTH_STATUS_ICON
); 
 281             if (savedInstanceState
.getBoolean(KEY_PASSWORD_VISIBLE
, false
)) { 
 286             String ocVersion 
= savedInstanceState
.getString(KEY_OC_VERSION
); 
 287             if (ocVersion 
!= null
) { 
 288                 mDiscoveredVersion 
= new OwnCloudVersion(ocVersion
); 
 290             mHostBaseUrl 
= savedInstanceState
.getString(KEY_HOST_URL_TEXT
); 
 292             // account data, if updating 
 293             mAccount 
= savedInstanceState
.getParcelable(KEY_ACCOUNT
); 
 294             mAuthTokenType 
= savedInstanceState
.getString(AccountAuthenticator
.KEY_AUTH_TOKEN_TYPE
); 
 295             if (mAuthTokenType 
== null
) { 
 296                 mAuthTokenType 
=  AccountTypeUtils
.getAuthTokenTypePass(MainApp
.getAccountType()); 
 300             // check if server check was interrupted by a configuration change 
 301             if (savedInstanceState
.getBoolean(KEY_SERVER_CHECK_IN_PROGRESS
, false
)) { 
 305             // refresh button enabled 
 306             refreshButtonEnabled 
= savedInstanceState
.getBoolean(KEY_REFRESH_BUTTON_ENABLED
); 
 311         if (mAuthMessageVisibility
== View
.VISIBLE
) { 
 312             showAuthMessage(mAuthMessageText
); 
 317         adaptViewAccordingToAuthenticationMethod(); 
 321         if (mAction 
== ACTION_UPDATE_TOKEN
) { 
 322             /// lock things that should not change 
 323             mHostUrlInput
.setEnabled(false
); 
 324             mHostUrlInput
.setFocusable(false
); 
 325             mUsernameInput
.setEnabled(false
); 
 326             mUsernameInput
.setFocusable(false
); 
 327             mOAuth2Check
.setVisibility(View
.GONE
); 
 330         //if (mServerIsChecked && !mServerIsValid && mRefreshButtonEnabled) showRefreshButton(); 
 331         if (mServerIsChecked 
&& !mServerIsValid 
&& refreshButtonEnabled
) showRefreshButton(); 
 332         mOkButton
.setEnabled(mServerIsValid
); // state not automatically recovered in configuration changes 
 334         if (AccountTypeUtils
.getAuthTokenTypeSamlSessionCookie(MainApp
.getAccountType()).equals(mAuthTokenType
) ||  
 335                 !AUTH_OPTIONAL
.equals(getString(R
.string
.auth_method_oauth2
))) { 
 336             mOAuth2Check
.setVisibility(View
.GONE
); 
 339         mPasswordInput
.setText("");     // clean password to avoid social hacking (disadvantage: password in removed if the device is turned aside) 
 341         /// bind view elements to listeners and other friends 
 342         mHostUrlInput
.setOnFocusChangeListener(this); 
 343         mHostUrlInput
.setImeOptions(EditorInfo
.IME_ACTION_NEXT
); 
 344         mHostUrlInput
.setOnEditorActionListener(this); 
 345         mHostUrlInput
.addTextChangedListener(new TextWatcher() { 
 348             public void afterTextChanged(Editable s
) { 
 349                 if (!mHostBaseUrl
.equals(normalizeUrl(mHostUrlInput
.getText().toString()))) { 
 350                     mOkButton
.setEnabled(false
); 
 355             public void beforeTextChanged(CharSequence s
, int start
, int count
, int after
) { 
 359             public void onTextChanged(CharSequence s
, int start
, int before
, int count
) { 
 369         mPasswordInput
.setOnFocusChangeListener(this); 
 370         mPasswordInput
.setImeOptions(EditorInfo
.IME_ACTION_DONE
); 
 371         mPasswordInput
.setOnEditorActionListener(this); 
 372         mPasswordInput
.setOnTouchListener(new RightDrawableOnTouchListener() { 
 374             public boolean onDrawableTouch(final MotionEvent event
) { 
 375                 if (event
.getAction() == MotionEvent
.ACTION_UP
) { 
 376                     AuthenticatorActivity
.this.onViewPasswordClick(); 
 382         findViewById(R
.id
.scroll
).setOnTouchListener(new OnTouchListener() { 
 384             public boolean onTouch(View view
, MotionEvent event
) { 
 385                 if (event
.getAction() == MotionEvent
.ACTION_DOWN
) { 
 386                     if (AccountTypeUtils
.getAuthTokenTypeSamlSessionCookie(MainApp
.getAccountType()).equals(mAuthTokenType
) && 
 387                             mHostUrlInput
.hasFocus()) { 
 398     private void initAuthorizationMethod() { 
 399         boolean oAuthRequired 
= false
; 
 400         boolean samlWebSsoRequired 
= false
; 
 402         mAuthTokenType 
= getIntent().getExtras().getString(AccountAuthenticator
.KEY_AUTH_TOKEN_TYPE
); 
 403         mAccount 
= getIntent().getExtras().getParcelable(EXTRA_ACCOUNT
); 
 405         // TODO could be a good moment to validate the received token type, if not null 
 407         if (mAuthTokenType 
== null
) {     
 408             if (mAccount 
!= null
) { 
 409                 /// same authentication method than the one used to create the account to update 
 410                 oAuthRequired 
= (mAccountMgr
.getUserData(mAccount
, Constants
.KEY_SUPPORTS_OAUTH2
) != null
); 
 411                 samlWebSsoRequired 
= (mAccountMgr
.getUserData(mAccount
, Constants
.KEY_SUPPORTS_SAML_WEB_SSO
) != null
); 
 414                 /// use the one set in setup.xml 
 415                 oAuthRequired 
= AUTH_ON
.equals(getString(R
.string
.auth_method_oauth2
)); 
 416                 samlWebSsoRequired 
= AUTH_ON
.equals(getString(R
.string
.auth_method_saml_web_sso
));             
 419                 mAuthTokenType 
= AccountTypeUtils
.getAuthTokenTypeAccessToken(MainApp
.getAccountType()); 
 420             } else if (samlWebSsoRequired
) { 
 421                 mAuthTokenType 
= AccountTypeUtils
.getAuthTokenTypeSamlSessionCookie(MainApp
.getAccountType()); 
 423                 mAuthTokenType 
= AccountTypeUtils
.getAuthTokenTypePass(MainApp
.getAccountType()); 
 427         if (mAccount 
!= null
) { 
 428             String userName 
= mAccount
.name
.substring(0, mAccount
.name
.lastIndexOf('@')); 
 429             mUsernameInput
.setText(userName
); 
 432         mOAuth2Check
.setChecked(AccountTypeUtils
.getAuthTokenTypeAccessToken(MainApp
.getAccountType()).equals(mAuthTokenType
)); 
 437      * Saves relevant state before {@link #onPause()} 
 439      * Do NOT save {@link #mNewCapturedUriFromOAuth2Redirection}; it keeps a temporal flag, intended to defer the  
 440      * processing of the redirection caught in {@link #onNewIntent(Intent)} until {@link #onResume()}  
 442      * See {@link #loadSavedInstanceState(Bundle)} 
 445     protected void onSaveInstanceState(Bundle outState
) { 
 446         super.onSaveInstanceState(outState
); 
 448         /// connection state and info 
 449         outState
.putInt(KEY_AUTH_MESSAGE_VISIBILITY
, mAuthMessage
.getVisibility()); 
 450         outState
.putString(KEY_AUTH_MESSAGE_TEXT
, mAuthMessage
.getText().toString()); 
 451         outState
.putInt(KEY_SERVER_STATUS_TEXT
, mServerStatusText
); 
 452         outState
.putInt(KEY_SERVER_STATUS_ICON
, mServerStatusIcon
); 
 453         outState
.putBoolean(KEY_SERVER_VALID
, mServerIsValid
); 
 454         outState
.putBoolean(KEY_SERVER_CHECKED
, mServerIsChecked
); 
 455         outState
.putBoolean(KEY_SERVER_CHECK_IN_PROGRESS
, (!mServerIsValid 
&& mOcServerChkOperation 
!= null
)); 
 456         outState
.putBoolean(KEY_IS_SSL_CONN
, mIsSslConn
); 
 457         outState
.putBoolean(KEY_PASSWORD_VISIBLE
, isPasswordVisible()); 
 458         outState
.putInt(KEY_AUTH_STATUS_ICON
, mAuthStatusIcon
); 
 459         outState
.putInt(KEY_AUTH_STATUS_TEXT
, mAuthStatusText
); 
 462         if (mDiscoveredVersion 
!= null
) { 
 463             outState
.putString(KEY_OC_VERSION
, mDiscoveredVersion
.getVersion()); 
 465         outState
.putString(KEY_HOST_URL_TEXT
, mHostBaseUrl
); 
 467         /// account data, if updating 
 468         if (mAccount 
!= null
) { 
 469             outState
.putParcelable(KEY_ACCOUNT
, mAccount
); 
 471         outState
.putString(AccountAuthenticator
.KEY_AUTH_TOKEN_TYPE
, mAuthTokenType
); 
 473         // refresh button enabled 
 474         outState
.putBoolean(KEY_REFRESH_BUTTON_ENABLED
, (mRefreshButton
.getVisibility() == View
.VISIBLE
)); 
 481      * The redirection triggered by the OAuth authentication server as response to the GET AUTHORIZATION request 
 484      * To make this possible, this activity needs to be qualified with android:launchMode = "singleTask" in the 
 485      * AndroidManifest.xml file. 
 488     protected void onNewIntent (Intent intent
) { 
 489         Log_OC
.d(TAG
, "onNewIntent()"); 
 490         Uri data 
= intent
.getData(); 
 491         if (data 
!= null 
&& data
.toString().startsWith(getString(R
.string
.oauth2_redirect_uri
))) { 
 492             mNewCapturedUriFromOAuth2Redirection 
= data
; 
 498      * The redirection triggered by the OAuth authentication server as response to the GET AUTHORIZATION, and  
 499      * deferred in {@link #onNewIntent(Intent)}, is processed here. 
 502     protected void onResume() { 
 504         if (mAction 
== ACTION_UPDATE_TOKEN 
&& mJustCreated 
&& getIntent().getBooleanExtra(EXTRA_ENFORCED_UPDATE
, false
)) { 
 505             if (AccountTypeUtils
.getAuthTokenTypeAccessToken(MainApp
.getAccountType()).equals(mAuthTokenType
)) { 
 506                 //Toast.makeText(this, R.string.auth_expired_oauth_token_toast, Toast.LENGTH_LONG).show(); 
 507                 showAuthMessage(getString(R
.string
.auth_expired_oauth_token_toast
)); 
 508             } else if (AccountTypeUtils
.getAuthTokenTypeSamlSessionCookie(MainApp
.getAccountType()).equals(mAuthTokenType
)) { 
 509                 //Toast.makeText(this, R.string.auth_expired_saml_sso_token_toast, Toast.LENGTH_LONG).show(); 
 510                 showAuthMessage(getString(R
.string
.auth_expired_saml_sso_token_toast
)); 
 512                 //Toast.makeText(this, R.string.auth_expired_basic_auth_toast, Toast.LENGTH_LONG).show(); 
 513                 showAuthMessage(getString(R
.string
.auth_expired_basic_auth_toast
)); 
 517         if (mNewCapturedUriFromOAuth2Redirection 
!= null
) { 
 518             getOAuth2AccessTokenFromCapturedRedirection();             
 521         mJustCreated 
= false
; 
 527      * Parses the redirection with the response to the GET AUTHORIZATION request to the  
 528      * oAuth server and requests for the access token (GET ACCESS TOKEN) 
 530     private void getOAuth2AccessTokenFromCapturedRedirection() { 
 531         /// Parse data from OAuth redirection 
 532         String queryParameters 
= mNewCapturedUriFromOAuth2Redirection
.getQuery(); 
 533         mNewCapturedUriFromOAuth2Redirection 
= null
; 
 535         /// Showing the dialog with instructions for the user. 
 536         showDialog(DIALOG_OAUTH2_LOGIN_PROGRESS
); 
 538         /// GET ACCESS TOKEN to the oAuth server  
 539         RemoteOperation operation 
= new OAuth2GetAccessToken(   getString(R
.string
.oauth2_client_id
),  
 540                 getString(R
.string
.oauth2_redirect_uri
),        
 541                 getString(R
.string
.oauth2_grant_type
), 
 543         //OwnCloudClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(getString(R.string.oauth2_url_endpoint_access)), getApplicationContext()); 
 544         OwnCloudClient client 
= OwnCloudClientFactory
.createOwnCloudClient(Uri
.parse(mOAuthTokenEndpointText
.getText().toString().trim()), getApplicationContext(), true
); 
 545         operation
.execute(client
, this, mHandler
); 
 551      * Handles the change of focus on the text inputs for the server URL and the password 
 553     public void onFocusChange(View view
, boolean hasFocus
) { 
 554         if (view
.getId() == R
.id
.hostUrlInput
) {    
 556                 onUrlInputFocusLost((TextView
) view
); 
 562         } else if (view
.getId() == R
.id
.account_password
) { 
 563             onPasswordFocusChanged((TextView
) view
, hasFocus
); 
 569      * Handles changes in focus on the text input for the server URL. 
 571      * IMPORTANT ENTRY POINT 2: When (!hasFocus), user wrote the server URL and changed to  
 572      * other field. The operation to check the existence of the server in the entered URL is 
 575      * When hasFocus:    user 'comes back' to write again the server URL. 
 577      * @param hostInput     TextView with the URL input field receiving the change of focus. 
 579     private void onUrlInputFocusLost(TextView hostInput
) { 
 580         if (!mHostBaseUrl
.equals(normalizeUrl(mHostUrlInput
.getText().toString()))) { 
 583             mOkButton
.setEnabled(mServerIsValid
); 
 584             if (!mServerIsValid
) { 
 591     private void checkOcServer() { 
 592         String uri 
= trimUrlWebdav(mHostUrlInput
.getText().toString().trim()); 
 594         if (!mHostUrlInputEnabled
){ 
 595             uri 
= getString(R
.string
.server_url
); 
 598         mServerIsValid 
= false
; 
 599         mServerIsChecked 
= false
; 
 600         mOkButton
.setEnabled(false
); 
 601         mDiscoveredVersion 
= null
; 
 603         if (uri
.length() != 0) { 
 604             mServerStatusText 
= R
.string
.auth_testing_connection
; 
 605             mServerStatusIcon 
= R
.drawable
.progress_small
; 
 607             mOcServerChkOperation 
= new  GetRemoteStatusOperation(uri
, this); 
 608             OwnCloudClient client 
= OwnCloudClientFactory
.createOwnCloudClient(Uri
.parse(uri
), this, true
); 
 609             mOperationThread 
= mOcServerChkOperation
.execute(client
, this, mHandler
); 
 611             mServerStatusText 
= 0; 
 612             mServerStatusIcon 
= 0; 
 619      * Handles changes in focus on the text input for the password (basic authorization). 
 621      * When (hasFocus), the button to toggle password visibility is shown. 
 623      * When (!hasFocus), the button is made invisible and the password is hidden. 
 625      * @param passwordInput    TextView with the password input field receiving the change of focus. 
 626      * @param hasFocus          'True' if focus is received, 'false' if is lost 
 628     private void onPasswordFocusChanged(TextView passwordInput
, boolean hasFocus
) { 
 630             showViewPasswordButton(); 
 633             hidePasswordButton(); 
 638     private void showViewPasswordButton() { 
 639         //int drawable = android.R.drawable.ic_menu_view; 
 640         int drawable 
= R
.drawable
.ic_view
; 
 641         if (isPasswordVisible()) { 
 642             //drawable = android.R.drawable.ic_secure; 
 643             drawable 
= R
.drawable
.ic_hide
; 
 645         mPasswordInput
.setCompoundDrawablesWithIntrinsicBounds(0, 0, drawable
, 0); 
 648     private boolean isPasswordVisible() { 
 649         return ((mPasswordInput
.getInputType() & InputType
.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
) == InputType
.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
); 
 652     private void hidePasswordButton() { 
 653         mPasswordInput
.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); 
 656     private void showPassword() { 
 657         mPasswordInput
.setInputType(InputType
.TYPE_CLASS_TEXT 
| InputType
.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
); 
 658         showViewPasswordButton(); 
 661     private void hidePassword() { 
 662         mPasswordInput
.setInputType(InputType
.TYPE_CLASS_TEXT 
| InputType
.TYPE_TEXT_VARIATION_PASSWORD
); 
 663         showViewPasswordButton(); 
 668      * Cancels the authenticator activity 
 670      * IMPORTANT ENTRY POINT 3: Never underestimate the importance of cancellation 
 672      * This method is bound in the layout/acceoun_setup.xml resource file. 
 674      * @param view      Cancel button 
 676     public void onCancelClick(View view
) { 
 677         setResult(RESULT_CANCELED
);     // TODO review how is this related to AccountAuthenticator (debugging) 
 684      * Checks the credentials of the user in the root of the ownCloud server 
 685      * before creating a new local account. 
 687      * For basic authorization, a check of existence of the root folder is 
 690      * For OAuth, starts the flow to get an access token; the credentials test  
 691      * is postponed until it is available. 
 693      * IMPORTANT ENTRY POINT 4 
 695      * @param view      OK button 
 697     public void onOkClick(View view
) { 
 698         // this check should be unnecessary 
 699         if (mDiscoveredVersion 
== null 
|| !mDiscoveredVersion
.isVersionValid()  || mHostBaseUrl 
== null 
|| mHostBaseUrl
.length() == 0) { 
 700             mServerStatusIcon 
= R
.drawable
.common_error
; 
 701             mServerStatusText 
= R
.string
.auth_wtf_reenter_URL
; 
 703             mOkButton
.setEnabled(false
); 
 704             Log_OC
.wtf(TAG
,  "The user was allowed to click 'connect' to an unchecked server!!"); 
 708         if (AccountTypeUtils
.getAuthTokenTypeAccessToken(MainApp
.getAccountType()).equals(mAuthTokenType
)) { 
 709             startOauthorization(); 
 710         } else if (AccountTypeUtils
.getAuthTokenTypeSamlSessionCookie(MainApp
.getAccountType()).equals(mAuthTokenType
)) {  
 711             startSamlBasedFederatedSingleSignOnAuthorization(); 
 713             checkBasicAuthorization(); 
 719      * Tests the credentials entered by the user performing a check of existence on  
 720      * the root folder of the ownCloud server. 
 722     private void checkBasicAuthorization() { 
 723         /// get the path to the root folder through WebDAV from the version server 
 724         String webdav_path 
= AccountUtils
.getWebdavPath(mDiscoveredVersion
, mAuthTokenType
); 
 726         /// get basic credentials entered by user 
 727         String username 
= mUsernameInput
.getText().toString(); 
 728         String password 
= mPasswordInput
.getText().toString(); 
 730         /// be gentle with the user 
 731         showDialog(DIALOG_LOGIN_PROGRESS
); 
 733         /// test credentials accessing the root folder 
 734         mAuthCheckOperation 
= new  ExistenceCheckRemoteOperation("", this, false
); 
 735         OwnCloudClient client 
= OwnCloudClientFactory
.createOwnCloudClient(Uri
.parse(mHostBaseUrl 
+ webdav_path
), this, true
); 
 736         client
.setBasicCredentials(username
, password
); 
 737         mOperationThread 
= mAuthCheckOperation
.execute(client
, this, mHandler
); 
 742      * Starts the OAuth 'grant type' flow to get an access token, with  
 743      * a GET AUTHORIZATION request to the BUILT-IN authorization server.  
 745     private void startOauthorization() { 
 746         // be gentle with the user 
 747         mAuthStatusIcon 
= R
.drawable
.progress_small
; 
 748         mAuthStatusText 
= R
.string
.oauth_login_connection
; 
 752         // GET AUTHORIZATION request 
 753         //Uri uri = Uri.parse(getString(R.string.oauth2_url_endpoint_auth)); 
 754         Uri uri 
= Uri
.parse(mOAuthAuthEndpointText
.getText().toString().trim()); 
 755         Uri
.Builder uriBuilder 
= uri
.buildUpon(); 
 756         uriBuilder
.appendQueryParameter(OAuth2Constants
.KEY_RESPONSE_TYPE
, getString(R
.string
.oauth2_response_type
)); 
 757         uriBuilder
.appendQueryParameter(OAuth2Constants
.KEY_REDIRECT_URI
, getString(R
.string
.oauth2_redirect_uri
));    
 758         uriBuilder
.appendQueryParameter(OAuth2Constants
.KEY_CLIENT_ID
, getString(R
.string
.oauth2_client_id
)); 
 759         uriBuilder
.appendQueryParameter(OAuth2Constants
.KEY_SCOPE
, getString(R
.string
.oauth2_scope
)); 
 760         //uriBuilder.appendQueryParameter(OAuth2Constants.KEY_STATE, whateverwewant); 
 761         uri 
= uriBuilder
.build(); 
 762         Log_OC
.d(TAG
, "Starting browser to view " + uri
.toString()); 
 763         Intent i 
= new Intent(Intent
.ACTION_VIEW
, uri
); 
 769      * Starts the Web Single Sign On flow to get access to the root folder 
 772     private void startSamlBasedFederatedSingleSignOnAuthorization() { 
 773         // be gentle with the user 
 774         mAuthStatusIcon 
= R
.drawable
.progress_small
; 
 775         mAuthStatusText 
= R
.string
.auth_connecting_auth_server
; 
 777         showDialog(DIALOG_LOGIN_PROGRESS
); 
 779         /// get the path to the root folder through WebDAV from the version server 
 780         String webdav_path 
= AccountUtils
.getWebdavPath(mDiscoveredVersion
, mAuthTokenType
); 
 782         /// test credentials accessing the root folder 
 783         mAuthCheckOperation 
= new  ExistenceCheckRemoteOperation("", this, false
); 
 784         OwnCloudClient client 
= OwnCloudClientFactory
.createOwnCloudClient(Uri
.parse(mHostBaseUrl 
+ webdav_path
), this, false
); 
 785         mOperationThread 
= mAuthCheckOperation
.execute(client
, this, mHandler
); 
 790      * Callback method invoked when a RemoteOperation executed by this Activity finishes. 
 792      * Dispatches the operation flow to the right method. 
 795     public void onRemoteOperationFinish(RemoteOperation operation
, RemoteOperationResult result
) { 
 797         if (operation 
instanceof GetRemoteStatusOperation
) { 
 798             onOcServerCheckFinish((GetRemoteStatusOperation
) operation
, result
); 
 800         } else if (operation 
instanceof OAuth2GetAccessToken
) { 
 801             onGetOAuthAccessTokenFinish((OAuth2GetAccessToken
)operation
, result
); 
 803         } else if (operation 
instanceof ExistenceCheckRemoteOperation
)  { 
 804             if (AccountTypeUtils
.getAuthTokenTypeSamlSessionCookie(MainApp
.getAccountType()).equals(mAuthTokenType
)) { 
 805                 onSamlBasedFederatedSingleSignOnAuthorizationStart(operation
, result
); 
 808                 onAuthorizationCheckFinish((ExistenceCheckRemoteOperation
)operation
, result
); 
 810         } else if (operation 
instanceof GetRemoteUserNameOperation
) { 
 811             onGetUserNameFinish((GetRemoteUserNameOperation
) operation
, result
); 
 813         } else if (operation 
instanceof DetectAuthenticationMethodOperation
) { 
 814             onDetectAutheticationFinish((DetectAuthenticationMethodOperation
) operation
, result
); 
 819     private void onDetectAutheticationFinish(DetectAuthenticationMethodOperation operation
, RemoteOperationResult result
) { 
 820         // Read authentication method 
 821         if (result
.getData().size() > 0) { 
 822             AuthenticationMethod authMethod 
= (AuthenticationMethod
) result
.getData().get(0); 
 823             String basic 
= AccountTypeUtils
.getAuthTokenTypePass(MainApp
.getAccountType()); 
 824             String oAuth 
= AccountTypeUtils
.getAuthTokenTypeAccessToken(MainApp
.getAccountType()); 
 825             String saml 
=  AccountTypeUtils
.getAuthTokenTypeSamlSessionCookie(MainApp
.getAccountType()); 
 827             if ( ( mAuthTokenType
.equals(basic
) && !authMethod
.equals(AuthenticationMethod
.BASIC_HTTP_AUTH
) ) || 
 828                     ( mAuthTokenType
.equals(oAuth
) && !authMethod
.equals(AuthenticationMethod
.BEARER_TOKEN
) ) ||  
 829                     ( mAuthTokenType
.equals(saml
)  && !authMethod
.equals(AuthenticationMethod
.SAML_WEB_SSO
) ) ) { 
 831                 mOkButton
.setEnabled(false
); 
 832                 mServerIsValid 
= false
; 
 833                 //show an alert message ( Server Status ) 
 834                 updateServerStatusIconNoRegularAuth(); 
 838                 mOkButton
.setEnabled(true
); 
 840                 // Show server status 
 849     private void onGetUserNameFinish(GetRemoteUserNameOperation operation
, RemoteOperationResult result
) { 
 851         if (result
.isSuccess()) { 
 852             boolean success 
= false
; 
 853             String username 
= operation
.getUserName(); 
 855             if ( mAction 
== ACTION_CREATE
) { 
 856                 mUsernameInput
.setText(username
); 
 857                 success 
= createAccount(); 
 860                 if (!mUsernameInput
.getText().toString().equals(username
)) { 
 861                     // fail - not a new account, but an existing one; disallow 
 862                     result 
= new RemoteOperationResult(ResultCode
.ACCOUNT_NOT_THE_SAME
);  
 863                     updateAuthStatusIconAndText(result
); 
 865                     Log_OC
.d(TAG
, result
.getLogMessage()); 
 875             updateStatusIconFailUserName(); 
 877             Log_OC
.e(TAG
, "Access to user name failed: " + result
.getLogMessage()); 
 882     private void onSamlBasedFederatedSingleSignOnAuthorizationStart(RemoteOperation operation
, RemoteOperationResult result
) { 
 884             dismissDialog(DIALOG_LOGIN_PROGRESS
); 
 885         } catch (IllegalArgumentException e
) { 
 886             // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens 
 889         //if (result.isTemporalRedirection() && result.isIdPRedirection()) { 
 890         if (result
.isIdPRedirection()) { 
 891             String url 
= result
.getRedirectedLocation(); 
 892             String targetUrl 
= mHostBaseUrl 
+ AccountUtils
.getWebdavPath(mDiscoveredVersion
, mAuthTokenType
); 
 895             mSamlDialog 
= SamlWebViewDialog
.newInstance(url
, targetUrl
);             
 896             mSamlDialog
.show(getSupportFragmentManager(), TAG_SAML_DIALOG
); 
 902             mAuthStatusIcon 
= R
.drawable
.common_error
; 
 903             mAuthStatusText 
= R
.string
.auth_unsupported_auth_method
; 
 911      * Processes the result of the server check performed when the user finishes the enter of the 
 914      * @param operation     Server check performed. 
 915      * @param result        Result of the check. 
 917     private void onOcServerCheckFinish(GetRemoteStatusOperation operation
, RemoteOperationResult result
) { 
 918         if (operation
.equals(mOcServerChkOperation
)) { 
 919             /// save result state 
 920             mServerIsChecked 
= true
; 
 921             mServerIsValid 
= result
.isSuccess(); 
 922             mIsSslConn 
= (result
.getCode() == ResultCode
.OK_SSL
); 
 923             mOcServerChkOperation 
= null
; 
 926             /// retrieve discovered version and normalize server URL 
 927             mDiscoveredVersion 
= operation
.getDiscoveredVersion(); 
 928             mHostBaseUrl 
= normalizeUrl(mHostUrlInput
.getText().toString()); 
 930             // Refresh server status, but don't show it 
 931             updateServerStatusIconAndText(result
); 
 933             /// update status icon and text 
 934             if (mServerIsValid
) { 
 936                 // Try to create an account with user and pass "", to know if it is a regular server 
 937                 // Update connect button in the answer of this method 
 938                 detectAuthorizationMethod(); 
 941                 // Show server status 
 945             /// very special case (TODO: move to a common place for all the remote operations) 
 946             if (result
.getCode() == ResultCode
.SSL_RECOVERABLE_PEER_UNVERIFIED
) { 
 947                 showUntrustedCertDialog(result
); 
 951         }   // else nothing ; only the last check operation is considered;  
 952         // multiple can be triggered if the user amends a URL before a previous check can be triggered 
 957      *  Try to access with  user/pass ""/"", to know if it is a regular server 
 959     private void detectAuthorizationMethod() { 
 961         Log_OC
.d(TAG
, "Trying empty authorization to detect authentication method"); 
 963         /// get the path to the root folder through WebDAV from the version server 
 964         String webdav_path 
= AccountUtils
.getWebdavPath(mDiscoveredVersion
, mAuthTokenType
); 
 967         mDetectAuthenticationOperation 
= new DetectAuthenticationMethodOperation(this); 
 968         OwnCloudClient client 
= OwnCloudClientFactory
.createOwnCloudClient(Uri
.parse(mHostBaseUrl 
+ webdav_path
), this, true
); 
 969         mOperationThread 
= mDetectAuthenticationOperation
.execute(client
, this, mHandler
); 
 973     private String 
normalizeUrl(String url
) { 
 974         if (url 
!= null 
&& url
.length() > 0) { 
 976             if (!url
.toLowerCase().startsWith("http://") && 
 977                     !url
.toLowerCase().startsWith("https://")) { 
 979                     url 
= "https://" + url
; 
 981                     url 
= "http://" + url
; 
 985             // OC-208: Add suffix remote.php/webdav to normalize (OC-34)             
 986             url 
= trimUrlWebdav(url
); 
 988             if (url
.endsWith("/")) { 
 989                 url 
= url
.substring(0, url
.length() - 1); 
 993         return (url 
!= null ? url 
: ""); 
 997     private String 
trimUrlWebdav(String url
){        
 998         if(url
.toLowerCase().endsWith(AccountUtils
.WEBDAV_PATH_4_0
)){ 
 999             url 
= url
.substring(0, url
.length() - AccountUtils
.WEBDAV_PATH_4_0
.length());              
1000         } else if(url
.toLowerCase().endsWith(AccountUtils
.WEBDAV_PATH_2_0
)){ 
1001             url 
= url
.substring(0, url
.length() - AccountUtils
.WEBDAV_PATH_2_0
.length());              
1002         } else if (url
.toLowerCase().endsWith(AccountUtils
.WEBDAV_PATH_1_2
)){ 
1003             url 
= url
.substring(0, url
.length() - AccountUtils
.WEBDAV_PATH_1_2
.length());              
1005         return (url 
!= null ? url 
: ""); 
1010      * Chooses the right icon and text to show to the user for the received operation result. 
1012      * @param result    Result of a remote operation performed in this activity 
1014     private void updateServerStatusIconAndText(RemoteOperationResult result
) { 
1015         mServerStatusIcon 
= R
.drawable
.common_error
;    // the most common case in the switch below 
1017         switch (result
.getCode()) { 
1019             mServerStatusIcon 
= android
.R
.drawable
.ic_secure
; 
1020             mServerStatusText 
= R
.string
.auth_secure_connection
; 
1025             if (mHostUrlInput
.getText().toString().trim().toLowerCase().startsWith("http://") ) { 
1026                 mServerStatusText 
= R
.string
.auth_connection_established
; 
1027                 mServerStatusIcon 
= R
.drawable
.ic_ok
; 
1029                 mServerStatusText 
= R
.string
.auth_nossl_plain_ok_title
; 
1030                 mServerStatusIcon 
= android
.R
.drawable
.ic_partial_secure
; 
1034         case NO_NETWORK_CONNECTION
: 
1035             mServerStatusIcon 
= R
.drawable
.no_network
; 
1036             mServerStatusText 
= R
.string
.auth_no_net_conn_title
; 
1039         case SSL_RECOVERABLE_PEER_UNVERIFIED
: 
1040             mServerStatusText 
= R
.string
.auth_ssl_unverified_server_title
; 
1042         case BAD_OC_VERSION
: 
1043             mServerStatusText 
= R
.string
.auth_bad_oc_version_title
; 
1045         case WRONG_CONNECTION
: 
1046             mServerStatusText 
= R
.string
.auth_wrong_connection_title
; 
1049             mServerStatusText 
= R
.string
.auth_timeout_title
; 
1051         case INCORRECT_ADDRESS
: 
1052             mServerStatusText 
= R
.string
.auth_incorrect_address_title
; 
1055             mServerStatusText 
= R
.string
.auth_ssl_general_error_title
; 
1058             mServerStatusText 
= R
.string
.auth_unauthorized
; 
1060         case HOST_NOT_AVAILABLE
: 
1061             mServerStatusText 
= R
.string
.auth_unknown_host_title
; 
1063         case INSTANCE_NOT_CONFIGURED
: 
1064             mServerStatusText 
= R
.string
.auth_not_configured_title
; 
1066         case FILE_NOT_FOUND
: 
1067             mServerStatusText 
= R
.string
.auth_incorrect_path_title
; 
1070             mServerStatusText 
= R
.string
.auth_oauth_error
; 
1072         case OAUTH2_ERROR_ACCESS_DENIED
: 
1073             mServerStatusText 
= R
.string
.auth_oauth_error_access_denied
; 
1075         case UNHANDLED_HTTP_CODE
: 
1077             mServerStatusText 
= R
.string
.auth_unknown_error_title
; 
1080             mServerStatusText 
= 0; 
1081             mServerStatusIcon 
= 0; 
1087      * Chooses the right icon and text to show to the user for the received operation result. 
1089      * @param result    Result of a remote operation performed in this activity 
1091     private void updateAuthStatusIconAndText(RemoteOperationResult result
) { 
1092         mAuthStatusIcon 
= R
.drawable
.common_error
;    // the most common case in the switch below 
1094         switch (result
.getCode()) { 
1096             mAuthStatusIcon 
= android
.R
.drawable
.ic_secure
; 
1097             mAuthStatusText 
= R
.string
.auth_secure_connection
; 
1102             if (mHostUrlInput
.getText().toString().trim().toLowerCase().startsWith("http://") ) { 
1103                 mAuthStatusText 
= R
.string
.auth_connection_established
; 
1104                 mAuthStatusIcon 
= R
.drawable
.ic_ok
; 
1106                 mAuthStatusText 
= R
.string
.auth_nossl_plain_ok_title
; 
1107                 mAuthStatusIcon 
= android
.R
.drawable
.ic_partial_secure
; 
1111         case NO_NETWORK_CONNECTION
: 
1112             mAuthStatusIcon 
= R
.drawable
.no_network
; 
1113             mAuthStatusText 
= R
.string
.auth_no_net_conn_title
; 
1116         case SSL_RECOVERABLE_PEER_UNVERIFIED
: 
1117             mAuthStatusText 
= R
.string
.auth_ssl_unverified_server_title
; 
1119         case BAD_OC_VERSION
: 
1120             mAuthStatusText 
= R
.string
.auth_bad_oc_version_title
; 
1122         case WRONG_CONNECTION
: 
1123             mAuthStatusText 
= R
.string
.auth_wrong_connection_title
; 
1126             mAuthStatusText 
= R
.string
.auth_timeout_title
; 
1128         case INCORRECT_ADDRESS
: 
1129             mAuthStatusText 
= R
.string
.auth_incorrect_address_title
; 
1132             mAuthStatusText 
= R
.string
.auth_ssl_general_error_title
; 
1135             mAuthStatusText 
= R
.string
.auth_unauthorized
; 
1137         case HOST_NOT_AVAILABLE
: 
1138             mAuthStatusText 
= R
.string
.auth_unknown_host_title
; 
1140         case INSTANCE_NOT_CONFIGURED
: 
1141             mAuthStatusText 
= R
.string
.auth_not_configured_title
; 
1143         case FILE_NOT_FOUND
: 
1144             mAuthStatusText 
= R
.string
.auth_incorrect_path_title
; 
1147             mAuthStatusText 
= R
.string
.auth_oauth_error
; 
1149         case OAUTH2_ERROR_ACCESS_DENIED
: 
1150             mAuthStatusText 
= R
.string
.auth_oauth_error_access_denied
; 
1152         case ACCOUNT_NOT_NEW
: 
1153             mAuthStatusText 
= R
.string
.auth_account_not_new
; 
1155         case ACCOUNT_NOT_THE_SAME
: 
1156             mAuthStatusText 
= R
.string
.auth_account_not_the_same
; 
1158         case UNHANDLED_HTTP_CODE
: 
1160             mAuthStatusText 
= R
.string
.auth_unknown_error_title
; 
1163             mAuthStatusText 
= 0; 
1164             mAuthStatusIcon 
= 0; 
1169     private void updateStatusIconFailUserName(){ 
1170         mAuthStatusIcon 
= R
.drawable
.common_error
; 
1171         mAuthStatusText 
= R
.string
.auth_fail_get_user_name
; 
1174     private void updateServerStatusIconNoRegularAuth(){ 
1175         mServerStatusIcon 
= R
.drawable
.common_error
; 
1176         mServerStatusText 
= R
.string
.auth_can_not_auth_against_server
; 
1180      * Processes the result of the request for and access token send  
1181      * to an OAuth authorization server. 
1183      * @param operation     Operation performed requesting the access token. 
1184      * @param result        Result of the operation. 
1186     private void onGetOAuthAccessTokenFinish(OAuth2GetAccessToken operation
, RemoteOperationResult result
) { 
1188             dismissDialog(DIALOG_OAUTH2_LOGIN_PROGRESS
); 
1189         } catch (IllegalArgumentException e
) { 
1190             // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens 
1193         String webdav_path 
= AccountUtils
.getWebdavPath(mDiscoveredVersion
, mAuthTokenType
); 
1194         if (result
.isSuccess() && webdav_path 
!= null
) { 
1195             /// be gentle with the user 
1196             showDialog(DIALOG_LOGIN_PROGRESS
); 
1198             /// time to test the retrieved access token on the ownCloud server 
1199             mAuthToken 
= ((OAuth2GetAccessToken
)operation
).getResultTokenMap().get(OAuth2Constants
.KEY_ACCESS_TOKEN
); 
1200             Log_OC
.d(TAG
, "Got ACCESS TOKEN: " + mAuthToken
); 
1201             mAuthCheckOperation 
= new ExistenceCheckRemoteOperation("", this, false
); 
1202             OwnCloudClient client 
= OwnCloudClientFactory
.createOwnCloudClient(Uri
.parse(mHostBaseUrl 
+ webdav_path
), this, true
); 
1203             client
.setBearerCredentials(mAuthToken
); 
1204             mAuthCheckOperation
.execute(client
, this, mHandler
); 
1207             updateAuthStatusIconAndText(result
); 
1209             Log_OC
.d(TAG
, "Access failed: " + result
.getLogMessage()); 
1215      * Processes the result of the access check performed to try the user credentials. 
1217      * Creates a new account through the AccountManager. 
1219      * @param operation     Access check performed. 
1220      * @param result        Result of the operation. 
1222     private void onAuthorizationCheckFinish(ExistenceCheckRemoteOperation operation
, RemoteOperationResult result
) { 
1224             dismissDialog(DIALOG_LOGIN_PROGRESS
); 
1225         } catch (IllegalArgumentException e
) { 
1226             // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens 
1229         if (result
.isSuccess()) { 
1230             Log_OC
.d(TAG
, "Successful access - time to save the account"); 
1232             boolean success 
= false
; 
1233             if (mAction 
== ACTION_CREATE
) { 
1234                 success 
= createAccount(); 
1245         } else if (result
.isServerFail() || result
.isException()) { 
1246             /// if server fail or exception in authorization, the UI is updated as when a server check failed 
1247             mServerIsChecked 
= true
; 
1248             mServerIsValid 
= false
; 
1250             mOcServerChkOperation 
= null
; 
1251             mDiscoveredVersion 
= null
; 
1252             mHostBaseUrl 
= normalizeUrl(mHostUrlInput
.getText().toString()); 
1254             // update status icon and text 
1255             updateServerStatusIconAndText(result
); 
1257             mAuthStatusIcon 
= 0; 
1258             mAuthStatusText 
= 0; 
1261             // update input controls state 
1262             showRefreshButton(); 
1263             mOkButton
.setEnabled(false
); 
1265             // very special case (TODO: move to a common place for all the remote operations) (dangerous here?) 
1266             if (result
.getCode() == ResultCode
.SSL_RECOVERABLE_PEER_UNVERIFIED
) { 
1267                 showUntrustedCertDialog(result
); 
1270         } else {    // authorization fail due to client side - probably wrong credentials 
1271             updateAuthStatusIconAndText(result
); 
1273             Log_OC
.d(TAG
, "Access failed: " + result
.getLogMessage()); 
1281      * Sets the proper response to get that the Account Authenticator that started this activity saves  
1282      * a new authorization token for mAccount. 
1284     private void updateToken() { 
1285         Bundle response 
= new Bundle(); 
1286         response
.putString(AccountManager
.KEY_ACCOUNT_NAME
, mAccount
.name
); 
1287         response
.putString(AccountManager
.KEY_ACCOUNT_TYPE
, mAccount
.type
); 
1289         if (AccountTypeUtils
.getAuthTokenTypeAccessToken(MainApp
.getAccountType()).equals(mAuthTokenType
)) {  
1290             response
.putString(AccountManager
.KEY_AUTHTOKEN
, mAuthToken
); 
1291             // the next line is necessary; by now, notifications are calling directly to the AuthenticatorActivity to update, without AccountManager intervention 
1292             mAccountMgr
.setAuthToken(mAccount
, mAuthTokenType
, mAuthToken
); 
1294         } else if (AccountTypeUtils
.getAuthTokenTypeSamlSessionCookie(MainApp
.getAccountType()).equals(mAuthTokenType
)) { 
1296             response
.putString(AccountManager
.KEY_AUTHTOKEN
, mAuthToken
); 
1297             // the next line is necessary; by now, notifications are calling directly to the AuthenticatorActivity to update, without AccountManager intervention 
1298             mAccountMgr
.setAuthToken(mAccount
, mAuthTokenType
, mAuthToken
); 
1301             response
.putString(AccountManager
.KEY_AUTHTOKEN
, mPasswordInput
.getText().toString()); 
1302             mAccountMgr
.setPassword(mAccount
, mPasswordInput
.getText().toString()); 
1304         setAccountAuthenticatorResult(response
); 
1310      * Creates a new account through the Account Authenticator that started this activity.  
1312      * This makes the account permanent. 
1314      * TODO Decide how to name the OAuth accounts 
1316     private boolean createAccount() { 
1317         /// create and save new ownCloud account 
1318         boolean isOAuth 
= AccountTypeUtils
.getAuthTokenTypeAccessToken(MainApp
.getAccountType()).equals(mAuthTokenType
); 
1319         boolean isSaml 
=  AccountTypeUtils
.getAuthTokenTypeSamlSessionCookie(MainApp
.getAccountType()).equals(mAuthTokenType
); 
1321         Uri uri 
= Uri
.parse(mHostBaseUrl
); 
1322         String username 
= mUsernameInput
.getText().toString().trim(); 
1324             username 
= "OAuth_user" + (new java
.util
.Random(System
.currentTimeMillis())).nextLong(); 
1326         String accountName 
= username 
+ "@" + uri
.getHost(); 
1327         if (uri
.getPort() >= 0) { 
1328             accountName 
+= ":" + uri
.getPort(); 
1330         mAccount 
= new Account(accountName
, MainApp
.getAccountType()); 
1331         if (AccountUtils
.exists(mAccount
, getApplicationContext())) { 
1332             // fail - not a new account, but an existing one; disallow 
1333             RemoteOperationResult result 
= new RemoteOperationResult(ResultCode
.ACCOUNT_NOT_NEW
);  
1334             updateAuthStatusIconAndText(result
); 
1336             Log_OC
.d(TAG
, result
.getLogMessage()); 
1341             if (isOAuth 
|| isSaml
) { 
1342                 mAccountMgr
.addAccountExplicitly(mAccount
, "", null
);  // with external authorizations, the password is never input in the app 
1344                 mAccountMgr
.addAccountExplicitly(mAccount
, mPasswordInput
.getText().toString(), null
); 
1347             /// add the new account as default in preferences, if there is none already 
1348             Account defaultAccount 
= AccountUtils
.getCurrentOwnCloudAccount(this); 
1349             if (defaultAccount 
== null
) { 
1350                 SharedPreferences
.Editor editor 
= PreferenceManager
 
1351                         .getDefaultSharedPreferences(this).edit(); 
1352                 editor
.putString("select_oc_account", accountName
); 
1356             /// prepare result to return to the Authenticator 
1357             //  TODO check again what the Authenticator makes with it; probably has the same effect as addAccountExplicitly, but it's not well done 
1358             final Intent intent 
= new Intent();        
1359             intent
.putExtra(AccountManager
.KEY_ACCOUNT_TYPE
,    MainApp
.getAccountType()); 
1360             intent
.putExtra(AccountManager
.KEY_ACCOUNT_NAME
,    mAccount
.name
); 
1362                 intent.putExtra(AccountManager.KEY_AUTHTOKEN,   MainApp.getAccountType()); */ 
1363             intent
.putExtra(AccountManager
.KEY_USERDATA
,        username
); 
1364             if (isOAuth 
|| isSaml
) { 
1365                 mAccountMgr
.setAuthToken(mAccount
, mAuthTokenType
, mAuthToken
); 
1367             /// add user data to the new account; TODO probably can be done in the last parameter addAccountExplicitly, or in KEY_USERDATA 
1368             mAccountMgr
.setUserData(mAccount
, Constants
.KEY_OC_VERSION
,         mDiscoveredVersion
.getVersion()); 
1369             mAccountMgr
.setUserData(mAccount
, Constants
.KEY_OC_BASE_URL
,   mHostBaseUrl
); 
1372                 mAccountMgr
.setUserData(mAccount
, Constants
.KEY_SUPPORTS_SAML_WEB_SSO
, "TRUE");  
1373             } else if (isOAuth
) { 
1374                 mAccountMgr
.setUserData(mAccount
, Constants
.KEY_SUPPORTS_OAUTH2
, "TRUE");   
1377             setAccountAuthenticatorResult(intent
.getExtras()); 
1378             setResult(RESULT_OK
, intent
); 
1388      * Necessary to update the contents of the SSL Dialog 
1390      * TODO move to some common place for all possible untrusted SSL failures 
1393     protected void onPrepareDialog(int id
, Dialog dialog
, Bundle args
) { 
1395         case DIALOG_LOGIN_PROGRESS
: 
1396         case DIALOG_CERT_NOT_SAVED
: 
1397         case DIALOG_OAUTH2_LOGIN_PROGRESS
: 
1400             Log_OC
.e(TAG
, "Incorrect dialog called with id = " + id
); 
1409     protected Dialog 
onCreateDialog(int id
) { 
1410         Dialog dialog 
= null
; 
1412         case DIALOG_LOGIN_PROGRESS
: { 
1413             /// simple progress dialog 
1414             ProgressDialog working_dialog 
= new ProgressDialog(this); 
1415             working_dialog
.setMessage(getResources().getString(R
.string
.auth_trying_to_login
)); 
1416             working_dialog
.setIndeterminate(true
); 
1417             working_dialog
.setCancelable(true
); 
1419             .setOnCancelListener(new DialogInterface
.OnCancelListener() { 
1421                 public void onCancel(DialogInterface dialog
) { 
1422                     /// TODO study if this is enough 
1423                     Log_OC
.i(TAG
, "Login canceled"); 
1424                     if (mOperationThread 
!= null
) { 
1425                         mOperationThread
.interrupt(); 
1430             dialog 
= working_dialog
; 
1433         case DIALOG_OAUTH2_LOGIN_PROGRESS
: { 
1434             ProgressDialog working_dialog 
= new ProgressDialog(this); 
1435             working_dialog
.setMessage(String
.format("Getting authorization"));  
1436             working_dialog
.setIndeterminate(true
); 
1437             working_dialog
.setCancelable(true
); 
1439             .setOnCancelListener(new DialogInterface
.OnCancelListener() { 
1441                 public void onCancel(DialogInterface dialog
) { 
1442                     Log_OC
.i(TAG
, "Login canceled"); 
1446             dialog 
= working_dialog
; 
1449         case DIALOG_CERT_NOT_SAVED
: { 
1450             AlertDialog
.Builder builder 
= new AlertDialog
.Builder(this); 
1451             builder
.setMessage(getResources().getString(R
.string
.ssl_validator_not_saved
)); 
1452             builder
.setCancelable(false
); 
1453             builder
.setPositiveButton(R
.string
.common_ok
, new DialogInterface
.OnClickListener() { 
1455                 public void onClick(DialogInterface dialog
, int which
) { 
1459             dialog 
= builder
.create(); 
1463             Log_OC
.e(TAG
, "Incorrect dialog called with id = " + id
); 
1470      * Starts and activity to open the 'new account' page in the ownCloud web site 
1472      * @param view      'Account register' button 
1474     public void onRegisterClick(View view
) { 
1475         Intent register 
= new Intent(Intent
.ACTION_VIEW
, Uri
.parse(getString(R
.string
.welcome_link_url
))); 
1476         setResult(RESULT_CANCELED
); 
1477         startActivity(register
); 
1482      * Updates the content and visibility state of the icon and text associated 
1483      * to the last check on the ownCloud server. 
1485     private void showServerStatus() { 
1486         TextView tv 
= (TextView
) findViewById(R
.id
.server_status_text
); 
1488         if (mServerStatusIcon 
== 0 && mServerStatusText 
== 0) { 
1489             tv
.setVisibility(View
.INVISIBLE
); 
1492             tv
.setText(mServerStatusText
); 
1493             tv
.setCompoundDrawablesWithIntrinsicBounds(mServerStatusIcon
, 0, 0, 0); 
1494             tv
.setVisibility(View
.VISIBLE
); 
1501      * Updates the content and visibility state of the icon and text associated 
1502      * to the interactions with the OAuth authorization server. 
1504     private void showAuthStatus() { 
1505         if (mAuthStatusIcon 
== 0 && mAuthStatusText 
== 0) { 
1506             mAuthStatusLayout
.setVisibility(View
.INVISIBLE
); 
1509             mAuthStatusLayout
.setText(mAuthStatusText
); 
1510             mAuthStatusLayout
.setCompoundDrawablesWithIntrinsicBounds(mAuthStatusIcon
, 0, 0, 0); 
1511             mAuthStatusLayout
.setVisibility(View
.VISIBLE
); 
1516     private void showRefreshButton() { 
1517         mRefreshButton
.setVisibility(View
.VISIBLE
); 
1520     private void hideRefreshButton() { 
1521         mRefreshButton
.setVisibility(View
.GONE
); 
1525      * Called when the refresh button in the input field for ownCloud host is clicked. 
1527      * Performs a new check on the URL in the input field. 
1529      * @param view      Refresh 'button' 
1531     public void onRefreshClick(View view
) { 
1537      * Called when the eye icon in the password field is clicked. 
1539      * Toggles the visibility of the password in the field.  
1541     public void onViewPasswordClick() { 
1542         int selectionStart 
= mPasswordInput
.getSelectionStart(); 
1543         int selectionEnd 
= mPasswordInput
.getSelectionEnd(); 
1544         if (isPasswordVisible()) { 
1549         mPasswordInput
.setSelection(selectionStart
, selectionEnd
); 
1554      * Called when the checkbox for OAuth authorization is clicked. 
1556      * Hides or shows the input fields for user & password.  
1558      * @param view      'View password' 'button' 
1560     public void onCheckClick(View view
) { 
1561         CheckBox oAuth2Check 
= (CheckBox
)view
; 
1562         if (oAuth2Check
.isChecked()) { 
1563             mAuthTokenType 
= AccountTypeUtils
.getAuthTokenTypeAccessToken(MainApp
.getAccountType()); 
1565             mAuthTokenType 
= AccountTypeUtils
.getAuthTokenTypePass(MainApp
.getAccountType()); 
1567         adaptViewAccordingToAuthenticationMethod(); 
1572      * Changes the visibility of input elements depending on 
1573      * the current authorization method. 
1575     private void adaptViewAccordingToAuthenticationMethod () { 
1576         if (AccountTypeUtils
.getAuthTokenTypeAccessToken(MainApp
.getAccountType()).equals(mAuthTokenType
)) { 
1577             // OAuth 2 authorization 
1578             mOAuthAuthEndpointText
.setVisibility(View
.VISIBLE
); 
1579             mOAuthTokenEndpointText
.setVisibility(View
.VISIBLE
); 
1580             mUsernameInput
.setVisibility(View
.GONE
); 
1581             mPasswordInput
.setVisibility(View
.GONE
); 
1583         } else if (AccountTypeUtils
.getAuthTokenTypeSamlSessionCookie(MainApp
.getAccountType()).equals(mAuthTokenType
)) { 
1584             // SAML-based web Single Sign On 
1585             mOAuthAuthEndpointText
.setVisibility(View
.GONE
); 
1586             mOAuthTokenEndpointText
.setVisibility(View
.GONE
); 
1587             mUsernameInput
.setVisibility(View
.GONE
); 
1588             mPasswordInput
.setVisibility(View
.GONE
); 
1590             // basic HTTP authorization 
1591             mOAuthAuthEndpointText
.setVisibility(View
.GONE
); 
1592             mOAuthTokenEndpointText
.setVisibility(View
.GONE
); 
1593             mUsernameInput
.setVisibility(View
.VISIBLE
); 
1594             mPasswordInput
.setVisibility(View
.VISIBLE
); 
1599      *  Called when the 'action' button in an IME is pressed ('enter' in software keyboard). 
1601      *  Used to trigger the authentication check when the user presses 'enter' after writing the password,  
1602      *  or to throw the server test when the only field on screen is the URL input field. 
1605     public boolean onEditorAction(TextView inputField
, int actionId
, KeyEvent event
) { 
1606         if (actionId 
== EditorInfo
.IME_ACTION_DONE 
&& inputField 
!= null 
&& inputField
.equals(mPasswordInput
)) { 
1607             if (mOkButton
.isEnabled()) { 
1608                 mOkButton
.performClick(); 
1611         } else if (actionId 
== EditorInfo
.IME_ACTION_NEXT 
&& inputField 
!= null 
&& inputField
.equals(mHostUrlInput
)) { 
1612             if (AccountTypeUtils
.getAuthTokenTypeSamlSessionCookie(MainApp
.getAccountType()).equals(mAuthTokenType
)) { 
1616         return false
;   // always return false to grant that the software keyboard is hidden anyway 
1620     private abstract static class RightDrawableOnTouchListener 
implements OnTouchListener  
{ 
1622         private int fuzz 
= 75; 
1628         public boolean onTouch(View view
, MotionEvent event
) { 
1629             Drawable rightDrawable 
= null
; 
1630             if (view 
instanceof TextView
) { 
1631                 Drawable
[] drawables 
= ((TextView
)view
).getCompoundDrawables(); 
1632                 if (drawables
.length 
> 2) { 
1633                     rightDrawable 
= drawables
[2]; 
1636             if (rightDrawable 
!= null
) { 
1637                 final int x 
= (int) event
.getX(); 
1638                 final int y 
= (int) event
.getY(); 
1639                 final Rect bounds 
= rightDrawable
.getBounds(); 
1640                 if (x 
>= (view
.getRight() - bounds
.width() - fuzz
) && x 
<= (view
.getRight() - view
.getPaddingRight() + fuzz
) 
1641                         && y 
>= (view
.getPaddingTop() - fuzz
) && y 
<= (view
.getHeight() - view
.getPaddingBottom()) + fuzz
) { 
1643                     return onDrawableTouch(event
); 
1649         public abstract boolean onDrawableTouch(final MotionEvent event
); 
1653     public void onSamlDialogSuccess(String sessionCookie
) { 
1654         mAuthToken 
= sessionCookie
; 
1656         if (sessionCookie 
!= null 
&& sessionCookie
.length() > 0) { 
1657             mAuthToken 
= sessionCookie
; 
1659             GetRemoteUserNameOperation getUserOperation 
= new GetRemoteUserNameOperation();             
1660             OwnCloudClient client 
= OwnCloudClientFactory
.createOwnCloudClient(Uri
.parse(mHostBaseUrl
), getApplicationContext(), true
); 
1661             client
.setSsoSessionCookie(mAuthToken
); 
1662             getUserOperation
.execute(client
, this, mHandler
); 
1670     public void onSsoFinished(String sessionCookies
) { 
1671         //Toast.makeText(this, "got cookies: " + sessionCookie, Toast.LENGTH_LONG).show(); 
1673         if (sessionCookies 
!= null 
&& sessionCookies
.length() > 0) { 
1674             Log_OC
.d(TAG
, "Successful SSO - time to save the account"); 
1675             onSamlDialogSuccess(sessionCookies
); 
1676             Fragment fd 
= getSupportFragmentManager().findFragmentByTag(TAG_SAML_DIALOG
); 
1677             if (fd 
!= null 
&& fd 
instanceof SherlockDialogFragment
) { 
1678                 Dialog d 
= ((SherlockDialogFragment
)fd
).getDialog(); 
1679                 if (d 
!= null 
&& d
.isShowing()) { 
1686             Log_OC
.d(TAG
, "SSO failed"); 
1691     /** Show auth_message  
1695     private void showAuthMessage(String message
) { 
1696         mAuthMessage
.setVisibility(View
.VISIBLE
); 
1697         mAuthMessage
.setText(message
); 
1700     private void hideAuthMessage() { 
1701         mAuthMessage
.setVisibility(View
.GONE
); 
1705     public boolean onTouchEvent(MotionEvent event
) { 
1706         if (AccountTypeUtils
.getAuthTokenTypeSamlSessionCookie(MainApp
.getAccountType()).equals(mAuthTokenType
) && 
1707                 mHostUrlInput
.hasFocus() && event
.getAction() == MotionEvent
.ACTION_DOWN
) { 
1710         return super.onTouchEvent(event
); 
1715      * Show untrusted cert dialog  
1717     public void showUntrustedCertDialog(X509Certificate x509Certificate
, SslError error
, SslErrorHandler handler
) { 
1718         // Show a dialog with the certificate info 
1719         SslUntrustedCertDialog dialog 
= null
; 
1720         if (x509Certificate 
== null
) { 
1721             dialog 
= SslUntrustedCertDialog
.newInstanceForEmptySslError(error
, handler
); 
1723             dialog 
= SslUntrustedCertDialog
.newInstanceForFullSslError(x509Certificate
, error
, handler
); 
1725         FragmentManager fm 
= getSupportFragmentManager(); 
1726         FragmentTransaction ft 
= fm
.beginTransaction(); 
1727         ft
.addToBackStack(null
); 
1728         dialog
.show(ft
, DIALOG_UNTRUSTED_CERT
); 
1732      * Show untrusted cert dialog  
1734     public void showUntrustedCertDialog(RemoteOperationResult result
) { 
1735         // Show a dialog with the certificate info 
1736         SslUntrustedCertDialog dialog 
= SslUntrustedCertDialog
.newInstanceForFullSslError((CertificateCombinedException
)result
.getException()); 
1737         FragmentManager fm 
= getSupportFragmentManager(); 
1738         FragmentTransaction ft 
= fm
.beginTransaction(); 
1739         ft
.addToBackStack(null
); 
1740         dialog
.show(ft
, DIALOG_UNTRUSTED_CERT
); 
1745      * Dismiss untrusted cert dialog 
1747     public void dismissUntrustedCertDialog(){ 
1748         /*Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_UNTRUSTED_CERT); 
1750             SslErrorViewAdapter dialog = (SslErrorViewAdapter) frag; 
1757      * Called from SslValidatorDialog when a new server certificate was correctly saved. 
1759     public void onSavedCertificate() { 
1760         Fragment fd 
= getSupportFragmentManager().findFragmentByTag(TAG_SAML_DIALOG
); 
1762             // if SAML dialog is not shown, the SslDialog was shown due to an SSL error in the server check 
1768      * Called from SslValidatorDialog when a new server certificate could not be saved  
1769      * when the user requested it. 
1772     public void onFailedSavingCertificate() { 
1773         showDialog(DIALOG_CERT_NOT_SAVED
); 
1778     public void onCancelCertificate() { 
1783     public void cancelWebView() { 
1784         Fragment fd 
= getSupportFragmentManager().findFragmentByTag(TAG_SAML_DIALOG
); 
1785         if (fd 
!= null 
&& fd 
instanceof SherlockDialogFragment
) { 
1786             Dialog d 
= ((SherlockDialogFragment
)fd
).getDialog(); 
1787             if (d 
!= null 
&& d
.isShowing()) {