From: David A. Velasco Date: Thu, 3 Apr 2014 09:27:44 +0000 (+0200) Subject: Merge branch 'develop' into operations_service X-Git-Tag: oc-android-1.7.0_signed~345^2~8^2~2 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/5611205f1d5bc06bc89a73ac27f70098a09bd9ae?hp=901b6ac61e4a84d281e86b4989aa099801b28de7 Merge branch 'develop' into operations_service --- diff --git a/owncloud-android-library b/owncloud-android-library index cecda333..d066e9da 160000 --- a/owncloud-android-library +++ b/owncloud-android-library @@ -1 +1 @@ -Subproject commit cecda3333ac511267d6a70c61b1475211484ec84 +Subproject commit d066e9da51a04837504f9be3e266bdc82caabc64 diff --git a/res/values/strings.xml b/res/values/strings.xml index 0f71d6e3..8d243fce 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -31,7 +31,8 @@ Imprint "Try %1$s on your smartphone!" - "I want to invite you to use %1$s on your smartphone!\nDownload here: %2$s" + "I want to invite you to use %1$s on your smartphone!\nDownload here: %2$s" + Check Server Server address https://… @@ -109,6 +110,7 @@ "Remote: %1$s" There is not space enough to copy the selected files into the %1$s folder. Would like to move them into instead? Please, insert your App PIN + Enter your App PIN The PIN will be requested every time the app is started Please, reenter your App PIN @@ -124,49 +126,51 @@ "%1$s playback finished" No media file found No account provided - File not in a valid account - Unsupported media codec - Media file could not be read - Media file not correctly encoded - Timed out while trying to play - Media file cannot be streamed - Media file cannot be played with the stock media player - Security error trying to play %1$s + File not in a valid account + Unsupported media codec + Media file could not be read + Media file not correctly encoded + Timed out while trying to play + Media file cannot be streamed + Media file cannot be played with the stock media player + Security error trying to play %1$s Input error trying to play %1$s Unexpected error trying to play %1$s Rewind button Play or pause button Fast forward button - Trying to login… - No network connection - Secure connection unavailable. - Connection established - Testing connection… - Malformed server configuration - An account for the same user and server already exists in the device - The entered user does not match the user of this account - Unknown error occurred! - Couldn\'t find host - Server instance not found - The server took too long to respond - Malformed URL - SSL initialization failed - Couldn\'t verify SSL server\'s identity - Unrecognized server version - Couldn\'t establish connection - Secure connection established - Wrong username or password + Getting authorization… + Trying to login… + No network connection + Secure connection unavailable. + Connection established + Testing connection… + Malformed server configuration + An account for the same user and server already exists in the device + The entered user does not match the user of this account + Unknown error occurred! + Couldn\'t find host + Server instance not found + The server took too long to respond + Malformed URL + SSL initialization failed + Couldn\'t verify SSL server\'s identity + Unrecognized server version + Couldn\'t establish connection + Secure connection established + Wrong username or password Unsuccessful authorization Access denied by authorization server - Unexpected state; please, enter the server URL again - Your authorization expired. Please, authorize again - Please, enter the current password - Your session expired. Please connect again + Unexpected state; please, enter the server URL again + Your authorization expired. Please, authorize again + Please, enter the current password + Your session expired. Please connect again Connecting to authentication server… - The server does not support this authentication method + The server does not support this authentication method %1$s does not support multiple accounts - Your server is not returning a correct user id, please contact an administrator + Your server is not returning a correct user id, please contact an administrator + Can not authenticate against this server Keep file up to date @@ -250,8 +254,9 @@ do nothing you are not online for instant upload Failure Message: Please check your server configuration,maybe your quota is exceeded. - - Sorry, sharing is not enabled on your server. Please contact your administrator. + + Sorry, sharing is not enabled on your server. Please contact your + administrator. Unable to share this file or folder. Please, make sure it exists An error occurred while trying to share this file or folder Unable to unshare this file or folder. It does not exist. @@ -259,7 +264,8 @@ Send - Copy link + Copy link Copied to clipboard - + + Critical error: can not perform operations diff --git a/src/com/owncloud/android/authentication/AuthenticatorActivity.java b/src/com/owncloud/android/authentication/AuthenticatorActivity.java index 8cbe7ad8..ac71a59a 100644 --- a/src/com/owncloud/android/authentication/AuthenticatorActivity.java +++ b/src/com/owncloud/android/authentication/AuthenticatorActivity.java @@ -19,14 +19,15 @@ package com.owncloud.android.authentication; import java.security.cert.X509Certificate; +import java.util.Map; import android.accounts.Account; import android.accounts.AccountManager; -import android.app.AlertDialog; import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.DialogInterface; +import android.content.ComponentName; +import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; import android.content.SharedPreferences; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -34,6 +35,7 @@ import android.net.Uri; import android.net.http.SslError; import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; @@ -54,6 +56,7 @@ import android.widget.CheckBox; import android.widget.EditText; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; +import android.widget.Toast; import com.actionbarsherlock.app.SherlockDialogFragment; import com.owncloud.android.MainApp; @@ -61,21 +64,21 @@ import com.owncloud.android.R; import com.owncloud.android.authentication.SsoWebViewClient.SsoWebViewClientListener; import com.owncloud.android.lib.common.accounts.AccountTypeUtils; import com.owncloud.android.lib.common.accounts.AccountUtils.Constants; -import com.owncloud.android.lib.common.OwnCloudClientFactory; -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.operations.DetectAuthenticationMethodOperation; import com.owncloud.android.operations.DetectAuthenticationMethodOperation.AuthenticationMethod; +import com.owncloud.android.operations.GetServerInfoOperation; import com.owncloud.android.operations.OAuth2GetAccessToken; import com.owncloud.android.lib.common.network.CertificateCombinedException; import com.owncloud.android.lib.common.operations.OnRemoteOperationListener; -import com.owncloud.android.lib.resources.status.GetRemoteStatusOperation; 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.resources.files.ExistenceCheckRemoteOperation; import com.owncloud.android.lib.resources.users.GetRemoteUserNameOperation; +import com.owncloud.android.services.OperationsService; +import com.owncloud.android.services.OperationsService.OperationsServiceBinder; +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; @@ -87,6 +90,7 @@ import com.owncloud.android.lib.resources.status.OwnCloudVersion; * * @author Bartek Przybylski * @author David A. Velasco + * @author masensio */ public class AuthenticatorActivity extends AccountAuthenticatorActivity implements OnRemoteOperationListener, OnFocusChangeListener, OnEditorActionListener, @@ -115,35 +119,39 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { 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_REFRESH_BUTTON_ENABLED = "KEY_REFRESH_BUTTON_ENABLED"; - //private static final String KEY_IS_SHARED_SUPPORTED = "KEY_IS_SHARE_SUPPORTED"; + private static final String KEY_SERVER_AUTH_METHOD = "KEY_SERVER_AUTH_METHOD"; + private static final String KEY_DETECT_AUTH_OP_ID = "KEY_DETECT_AUTH_OP_ID"; private static final String AUTH_ON = "on"; - private static final String AUTH_OFF = "off"; + //private static final String AUTH_OFF = "off"; private static final String AUTH_OPTIONAL = "optional"; - private static final int DIALOG_LOGIN_PROGRESS = 0; - private static final int DIALOG_CERT_NOT_SAVED = 1; - private static final int DIALOG_OAUTH2_LOGIN_PROGRESS = 2; - public static final byte ACTION_CREATE = 0; public static final byte ACTION_UPDATE_TOKEN = 1; - private static final String TAG_SAML_DIALOG = "samlWebViewDialog"; + private static final String SAML_DIALOG_TAG = "SAML_DIALOG"; + private static final String WAIT_DIALOG_TAG = "WAIT_DIALOG"; - private String mHostBaseUrl; - private OwnCloudVersion mDiscoveredVersion; + private String mHostBaseUrl; // TODO remove + private OwnCloudVersion mDiscoveredVersion; // TODO remove private String mAuthMessageText; private int mAuthMessageVisibility, mServerStatusText, mServerStatusIcon; private boolean mServerIsChecked, mServerIsValid, mIsSslConn; + private AuthenticationMethod mServerAuthMethod = AuthenticationMethod.UNKNOWN; + + private int mGetServerInfoOpId = -1; + private int mOauth2GetAccessTokenOpId = -1; + private int mAuthStatusText, mAuthStatusIcon; private TextView mAuthStatusLayout; private final Handler mHandler = new Handler(); - private Thread mOperationThread; - private GetRemoteStatusOperation mOcServerChkOperation; - private ExistenceCheckRemoteOperation mAuthCheckOperation; + private GetServerInfoOperation mServerInfoOperation; + private int mExistenceCheckOpId = -1; + private int mGetUserNameOpId = -1; + private Uri mNewCapturedUriFromOAuth2Redirection; private AccountManager mAccountMgr; @@ -176,9 +184,12 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { private boolean mResumed; // Control if activity is resumed public static String DIALOG_UNTRUSTED_CERT = "DIALOG_UNTRUSTED_CERT"; + + private ServiceConnection mOperationsServiceConnection = null; + + private OperationsServiceBinder mOperationsServiceBinder = null; - private DetectAuthenticationMethodOperation mDetectAuthenticationOperation; - + private GetServerInfoOperation.ServerInfo mServerInfo; /** * {@inheritDoc} @@ -190,6 +201,18 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { super.onCreate(savedInstanceState); getWindow().requestFeature(Window.FEATURE_NO_TITLE); + // bind to Operations Service + mOperationsServiceConnection = new OperationsServiceConnection(); + if (!bindService(new Intent(this, OperationsService.class), + mOperationsServiceConnection, + Context.BIND_AUTO_CREATE)) { + Toast.makeText(this, + R.string.error_cant_bind_to_operations_service, + Toast.LENGTH_LONG) + .show(); + finish(); + } + /// set view and get references to view elements setContentView(R.layout.account_setup); mAuthMessage = (TextView) findViewById(R.id.auth_message); @@ -306,6 +329,10 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { refreshButtonEnabled = savedInstanceState.getBoolean(KEY_REFRESH_BUTTON_ENABLED); + mServerAuthMethod = AuthenticationMethod.valueOf( + savedInstanceState.getString(KEY_SERVER_AUTH_METHOD)); + mGetServerInfoOpId = savedInstanceState.getInt(KEY_DETECT_AUTH_OP_ID); + } if (mAuthMessageVisibility== View.VISIBLE) { @@ -327,8 +354,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { mOAuth2Check.setVisibility(View.GONE); } - //if (mServerIsChecked && !mServerIsValid && mRefreshButtonEnabled) showRefreshButton(); - if (mServerIsChecked && !mServerIsValid && refreshButtonEnabled) showRefreshButton(); + showRefreshButton(mServerIsChecked && !mServerIsValid && refreshButtonEnabled); mOkButton.setEnabled(mServerIsValid); // state not automatically recovered in configuration changes if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType) || @@ -391,6 +417,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { return false; } }); + } @@ -443,6 +470,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { */ @Override protected void onSaveInstanceState(Bundle outState) { + //Log.wtf(TAG, "onSaveInstanceState init" ); super.onSaveInstanceState(outState); /// connection state and info @@ -452,7 +480,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { outState.putInt(KEY_SERVER_STATUS_ICON, mServerStatusIcon); outState.putBoolean(KEY_SERVER_VALID, mServerIsValid); outState.putBoolean(KEY_SERVER_CHECKED, mServerIsChecked); - outState.putBoolean(KEY_SERVER_CHECK_IN_PROGRESS, (!mServerIsValid && mOcServerChkOperation != null)); + outState.putBoolean(KEY_SERVER_CHECK_IN_PROGRESS, (!mServerIsValid && mServerInfoOperation != null)); outState.putBoolean(KEY_IS_SSL_CONN, mIsSslConn); outState.putBoolean(KEY_PASSWORD_VISIBLE, isPasswordVisible()); outState.putInt(KEY_AUTH_STATUS_ICON, mAuthStatusIcon); @@ -472,8 +500,10 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { // refresh button enabled outState.putBoolean(KEY_REFRESH_BUTTON_ENABLED, (mRefreshButton.getVisibility() == View.VISIBLE)); - - + + outState.putString(KEY_SERVER_AUTH_METHOD, mServerAuthMethod.name()); + outState.putInt(KEY_DETECT_AUTH_OP_ID, mGetServerInfoOpId); + //Log.wtf(TAG, "onSaveInstanceState end" ); } @@ -500,7 +530,9 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { */ @Override protected void onResume() { + //Log.wtf(TAG, "onResume init" ); super.onResume(); + if (mAction == ACTION_UPDATE_TOKEN && mJustCreated && getIntent().getBooleanExtra(EXTRA_ENFORCED_UPDATE, false)) { if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(mAuthTokenType)) { //Toast.makeText(this, R.string.auth_expired_oauth_token_toast, Toast.LENGTH_LONG).show(); @@ -517,9 +549,35 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { if (mNewCapturedUriFromOAuth2Redirection != null) { getOAuth2AccessTokenFromCapturedRedirection(); } - + mJustCreated = false; + if (mOperationsServiceBinder != null) { + doOnResumeAndBound(); + } + + //Log.wtf(TAG, "onResume end" ); + } + + + @Override + protected void onPause() { + //Log.wtf(TAG, "onPause init" ); + if (mOperationsServiceBinder != null) { + //Log.wtf(TAG, "unregistering to listen for operation callbacks" ); + mOperationsServiceBinder.removeOperationListener(this); + } + super.onPause(); + //Log.wtf(TAG, "onPause end" ); + } + + @Override + protected void onDestroy() { + if (mOperationsServiceConnection != null) { + unbindService(mOperationsServiceConnection); + mOperationsServiceBinder = null; + } + super.onDestroy(); } @@ -533,16 +591,26 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { mNewCapturedUriFromOAuth2Redirection = null; /// Showing the dialog with instructions for the user. - showDialog(DIALOG_OAUTH2_LOGIN_PROGRESS); - - /// GET ACCESS TOKEN to the oAuth server - RemoteOperation operation = new OAuth2GetAccessToken( getString(R.string.oauth2_client_id), - getString(R.string.oauth2_redirect_uri), - getString(R.string.oauth2_grant_type), + 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); - //OwnCloudClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(getString(R.string.oauth2_url_endpoint_access)), getApplicationContext()); - OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(mOAuthTokenEndpointText.getText().toString().trim()), getApplicationContext(), true); - operation.execute(client, this, mHandler); + + if (mOperationsServiceBinder != null) { + //Log.wtf(TAG, "getting access token..." ); + mOauth2GetAccessTokenOpId = mOperationsServiceBinder.newOperation(getServerInfoIntent); + } } @@ -556,7 +624,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { onUrlInputFocusLost((TextView) view); } else { - hideRefreshButton(); + showRefreshButton(false); } } else if (view.getId() == R.id.account_password) { @@ -581,32 +649,39 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { checkOcServer(); } else { mOkButton.setEnabled(mServerIsValid); - if (!mServerIsValid) { - showRefreshButton(); - } + showRefreshButton(!mServerIsValid); } } private void checkOcServer() { - String uri = trimUrlWebdav(mHostUrlInput.getText().toString().trim()); + String uri = mHostUrlInput.getText().toString().trim(); if (!mHostUrlInputEnabled){ - uri = getString(R.string.server_url); + uri = getString(R.string.server_url).trim(); } mServerIsValid = false; mServerIsChecked = false; mOkButton.setEnabled(false); mDiscoveredVersion = null; - hideRefreshButton(); + mServerAuthMethod = AuthenticationMethod.UNKNOWN; + showRefreshButton(false); + if (uri.length() != 0) { mServerStatusText = R.string.auth_testing_connection; mServerStatusIcon = R.drawable.progress_small; showServerStatus(); - mOcServerChkOperation = new GetRemoteStatusOperation(uri, this); - OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(uri), this, true); - mOperationThread = mOcServerChkOperation.execute(client, this, mHandler); + + Intent getServerInfoIntent = new Intent(); + getServerInfoIntent.setAction(OperationsService.ACTION_GET_SERVER_INFO); + getServerInfoIntent.putExtra(OperationsService.EXTRA_SERVER_URL, uri); + getServerInfoIntent.putExtra(OperationsService.EXTRA_AUTH_TOKEN_TYPE, mAuthTokenType); + if (mOperationsServiceBinder != null) { + //Log.wtf(TAG, "checking server..." ); + mGetServerInfoOpId = mOperationsServiceBinder.newOperation(getServerInfoIntent); + } + } else { mServerStatusText = 0; mServerStatusIcon = 0; @@ -663,23 +738,6 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { showViewPasswordButton(); } - - /** - * Cancels the authenticator activity - * - * IMPORTANT ENTRY POINT 3: Never underestimate the importance of cancellation - * - * This method is bound in the layout/acceoun_setup.xml resource file. - * - * @param view Cancel button - */ - public void onCancelClick(View view) { - setResult(RESULT_CANCELED); // TODO review how is this related to AccountAuthenticator (debugging) - finish(); - } - - - /** * Checks the credentials of the user in the root of the ownCloud server * before creating a new local account. @@ -728,15 +786,37 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { String password = mPasswordInput.getText().toString(); /// be gentle with the user - showDialog(DIALOG_LOGIN_PROGRESS); + IndeterminateProgressDialog dialog = + IndeterminateProgressDialog.newInstance(R.string.auth_trying_to_login, true); + dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG); /// test credentials accessing the root folder - mAuthCheckOperation = new ExistenceCheckRemoteOperation("", this, false); - OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this, true); - client.setBasicCredentials(username, password); - mOperationThread = mAuthCheckOperation.execute(client, this, mHandler); + String remotePath =""; + boolean successIfAbsent = false; + boolean followRedirects = true; + startExistenceCheckRemoteOperation(remotePath, this, successIfAbsent, webdav_path, username, password, followRedirects); + } + private void startExistenceCheckRemoteOperation(String remotePath, Context context, boolean successIfAbsent, String webdav_path, + String username, String password, boolean followRedirects) { + + Intent existenceCheckIntent = new Intent(); + existenceCheckIntent.setAction(OperationsService.ACTION_EXISTENCE_CHECK); + existenceCheckIntent.putExtra(OperationsService.EXTRA_SERVER_URL, mHostBaseUrl); + existenceCheckIntent.putExtra(OperationsService.EXTRA_REMOTE_PATH, remotePath); + existenceCheckIntent.putExtra(OperationsService.EXTRA_SUCCESS_IF_ABSENT, successIfAbsent); + existenceCheckIntent.putExtra(OperationsService.EXTRA_WEBDAV_PATH, webdav_path); + existenceCheckIntent.putExtra(OperationsService.EXTRA_USERNAME, username); + existenceCheckIntent.putExtra(OperationsService.EXTRA_PASSWORD, password); + existenceCheckIntent.putExtra(OperationsService.EXTRA_AUTH_TOKEN, mAuthToken); + existenceCheckIntent.putExtra(OperationsService.EXTRA_FOLLOW_REDIRECTS, followRedirects); + + if (mOperationsServiceBinder != null) { + Log_OC.wtf(TAG, "starting existenceCheckRemoteOperation..." ); + mExistenceCheckOpId = mOperationsServiceBinder.newOperation(existenceCheckIntent); + } + } /** * Starts the OAuth 'grant type' flow to get an access token, with @@ -748,7 +828,6 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { mAuthStatusText = R.string.oauth_login_connection; showAuthStatus(); - // GET AUTHORIZATION request //Uri uri = Uri.parse(getString(R.string.oauth2_url_endpoint_auth)); Uri uri = Uri.parse(mOAuthAuthEndpointText.getText().toString().trim()); @@ -774,15 +853,18 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { mAuthStatusIcon = R.drawable.progress_small; mAuthStatusText = R.string.auth_connecting_auth_server; showAuthStatus(); - showDialog(DIALOG_LOGIN_PROGRESS); + IndeterminateProgressDialog dialog = + IndeterminateProgressDialog.newInstance(R.string.auth_trying_to_login, true); + dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG); /// get the path to the root folder through WebDAV from the version server String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, mAuthTokenType); /// test credentials accessing the root folder - mAuthCheckOperation = new ExistenceCheckRemoteOperation("", this, false); - OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this, false); - mOperationThread = mAuthCheckOperation.execute(client, this, mHandler); + String remotePath =""; + boolean successIfAbsent = false; + boolean followRedirections = false; + startExistenceCheckRemoteOperation(remotePath, this, successIfAbsent, webdav_path, "", "", followRedirections); } @@ -794,63 +876,34 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { @Override public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) { - if (operation instanceof GetRemoteStatusOperation) { - onOcServerCheckFinish((GetRemoteStatusOperation) operation, result); + if (operation instanceof GetServerInfoOperation) { + if (operation.hashCode() == mGetServerInfoOpId) { + 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((OAuth2GetAccessToken)operation, result); + onGetOAuthAccessTokenFinish(result); } else if (operation instanceof ExistenceCheckRemoteOperation) { + Log_OC.wtf(TAG, "received detection response through callback" ); if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType)) { - onSamlBasedFederatedSingleSignOnAuthorizationStart(operation, result); + onSamlBasedFederatedSingleSignOnAuthorizationStart(result); } else { - onAuthorizationCheckFinish((ExistenceCheckRemoteOperation)operation, result); + onAuthorizationCheckFinish(result); } } else if (operation instanceof GetRemoteUserNameOperation) { - onGetUserNameFinish((GetRemoteUserNameOperation) operation, result); - - } else if (operation instanceof DetectAuthenticationMethodOperation) { - onDetectAutheticationFinish((DetectAuthenticationMethodOperation) operation, result); + onGetUserNameFinish(result); } } - private void onDetectAutheticationFinish(DetectAuthenticationMethodOperation operation, RemoteOperationResult result) { - // Read authentication method - if (result.getData().size() > 0) { - AuthenticationMethod authMethod = (AuthenticationMethod) result.getData().get(0); - String basic = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType()); - String oAuth = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()); - String saml = AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()); - - if ( ( mAuthTokenType.equals(basic) && !authMethod.equals(AuthenticationMethod.BASIC_HTTP_AUTH) ) || - ( mAuthTokenType.equals(oAuth) && !authMethod.equals(AuthenticationMethod.BEARER_TOKEN) ) || - ( mAuthTokenType.equals(saml) && !authMethod.equals(AuthenticationMethod.SAML_WEB_SSO) ) ) { - - mOkButton.setEnabled(false); - mServerIsValid = false; - //show an alert message ( Server Status ) - updateServerStatusIconNoRegularAuth(); - showServerStatus(); - - } else { - mOkButton.setEnabled(true); - - // Show server status - showServerStatus(); - } - - } - } - - - - private void onGetUserNameFinish(GetRemoteUserNameOperation operation, RemoteOperationResult result) { - + private void onGetUserNameFinish(RemoteOperationResult result) { + mGetUserNameOpId = -1; if (result.isSuccess()) { boolean success = false; - String username = operation.getUserName(); + String username = (String) result.getData().get(0); if ( mAction == ACTION_CREATE) { mUsernameInput.setText(username); @@ -879,12 +932,9 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { } - private void onSamlBasedFederatedSingleSignOnAuthorizationStart(RemoteOperation operation, RemoteOperationResult result) { - try { - dismissDialog(DIALOG_LOGIN_PROGRESS); - } catch (IllegalArgumentException e) { - // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens - } + private void onSamlBasedFederatedSingleSignOnAuthorizationStart(RemoteOperationResult result) { + mExistenceCheckOpId = -1; + dismissDialog(WAIT_DIALOG_TAG); //if (result.isTemporalRedirection() && result.isIdPRedirection()) { if (result.isIdPRedirection()) { @@ -893,7 +943,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { // Show dialog mSamlDialog = SamlWebViewDialog.newInstance(url, targetUrl); - mSamlDialog.show(getSupportFragmentManager(), TAG_SAML_DIALOG); + mSamlDialog.show(getSupportFragmentManager(), SAML_DIALOG_TAG); mAuthStatusIcon = 0; mAuthStatusText = 0; @@ -914,62 +964,68 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { * @param operation Server check performed. * @param result Result of the check. */ - private void onOcServerCheckFinish(GetRemoteStatusOperation operation, RemoteOperationResult result) { - if (operation.equals(mOcServerChkOperation)) { - /// save result state - mServerIsChecked = true; - mServerIsValid = result.isSuccess(); - mIsSslConn = (result.getCode() == ResultCode.OK_SSL); - mOcServerChkOperation = null; - + private void onGetServerInfoFinish(RemoteOperationResult result) { + /// update activity state + mServerIsChecked = true; + mIsSslConn = (result.getCode() == ResultCode.OK_SSL); + mServerInfoOperation = null; + mGetServerInfoOpId = -1; + + // update server status, but don't show it yet + updateServerStatusIconAndText(result); - /// retrieve discovered version and normalize server URL - mDiscoveredVersion = operation.getDiscoveredVersion(); - mHostBaseUrl = normalizeUrl(mHostUrlInput.getText().toString()); - - // Refresh server status, but don't show it - 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)); + mDiscoveredVersion = mServerInfo.mVersion; + mHostBaseUrl = mServerInfo.mBaseUrl; + mServerAuthMethod = mServerInfo.mAuthMethod; + + if (!authSupported(mServerAuthMethod)) { + + updateServerStatusIconNoRegularAuth(); // overrides updateServerStatusIconAndText() + mServerIsValid = false; - /// update status icon and text - if (mServerIsValid) { - hideRefreshButton(); - // Try to create an account with user and pass "", to know if it is a regular server - // Update connect button in the answer of this method - detectAuthorizationMethod(); } else { - showRefreshButton(); - // Show server status - showServerStatus(); - } - - /// very special case (TODO: move to a common place for all the remote operations) - if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) { - showUntrustedCertDialog(result); + mServerIsValid = true; } + + } else { + mServerIsValid = false; + } - - } // else nothing ; only the last check operation is considered; - // multiple can be triggered if the user amends a URL before a previous check can be triggered + // refresh UI + showRefreshButton(!mServerIsValid); + showServerStatus(); + mOkButton.setEnabled(mServerIsValid); + + /// very special case (TODO: move to a common place for all the remote operations) + if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) { + showUntrustedCertDialog(result); + } } - /** - * Try to access with user/pass ""/"", to know if it is a regular server - */ - private void detectAuthorizationMethod() { - - Log_OC.d(TAG, "Trying empty authorization to detect authentication method"); - - /// get the path to the root folder through WebDAV from the version server - String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, mAuthTokenType); - - /// test credentials - mDetectAuthenticationOperation = new DetectAuthenticationMethodOperation(this); - OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this, true); - mOperationThread = mDetectAuthenticationOperation.execute(client, this, mHandler); + private boolean authSupported(AuthenticationMethod authMethod) { + String basic = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType()); + String oAuth = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()); + String saml = AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()); + + return (( mAuthTokenType.equals(basic) && + authMethod.equals(AuthenticationMethod.BASIC_HTTP_AUTH) ) || + ( mAuthTokenType.equals(oAuth) && + authMethod.equals(AuthenticationMethod.BEARER_TOKEN)) || + ( mAuthTokenType.equals(saml) && + authMethod.equals(AuthenticationMethod.SAML_WEB_SSO)) + ); } + // TODO remove, if possible private String normalizeUrl(String url) { if (url != null && url.length() > 0) { url = url.trim(); @@ -981,8 +1037,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { url = "http://" + url; } } - - // OC-208: Add suffix remote.php/webdav to normalize (OC-34) + url = trimUrlWebdav(url); if (url.endsWith("/")) { @@ -994,6 +1049,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { } + // TODO remove, if possible private String trimUrlWebdav(String url){ if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_4_0)){ url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_4_0.length()); @@ -1180,28 +1236,30 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { * Processes the result of the request for and access token send * to an OAuth authorization server. * - * @param operation Operation performed requesting the access token. * @param result Result of the operation. */ - private void onGetOAuthAccessTokenFinish(OAuth2GetAccessToken operation, RemoteOperationResult result) { - try { - dismissDialog(DIALOG_OAUTH2_LOGIN_PROGRESS); - } catch (IllegalArgumentException e) { - // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens - } + private void onGetOAuthAccessTokenFinish(RemoteOperationResult result) { + mOauth2GetAccessTokenOpId = -1; + dismissDialog(WAIT_DIALOG_TAG); String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, mAuthTokenType); if (result.isSuccess() && webdav_path != null) { /// be gentle with the user - showDialog(DIALOG_LOGIN_PROGRESS); + 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 - mAuthToken = ((OAuth2GetAccessToken)operation).getResultTokenMap().get(OAuth2Constants.KEY_ACCESS_TOKEN); + @SuppressWarnings("unchecked") + Map tokens = (Map)(result.getData().get(0)); + mAuthToken = tokens.get(OAuth2Constants.KEY_ACCESS_TOKEN); + //mAuthToken = ((OAuth2GetAccessToken)operation).getResultTokenMap().get(OAuth2Constants.KEY_ACCESS_TOKEN); Log_OC.d(TAG, "Got ACCESS TOKEN: " + mAuthToken); - mAuthCheckOperation = new ExistenceCheckRemoteOperation("", this, false); - OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this, true); - client.setBearerCredentials(mAuthToken); - mAuthCheckOperation.execute(client, this, mHandler); + + String remotePath =""; + boolean successIfAbsent = false; + boolean followRedirects = true; + startExistenceCheckRemoteOperation(remotePath, this, successIfAbsent, webdav_path, "", "", followRedirects); } else { updateAuthStatusIconAndText(result); @@ -1219,12 +1277,9 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { * @param operation Access check performed. * @param result Result of the operation. */ - private void onAuthorizationCheckFinish(ExistenceCheckRemoteOperation operation, RemoteOperationResult result) { - try { - dismissDialog(DIALOG_LOGIN_PROGRESS); - } catch (IllegalArgumentException e) { - // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens - } + private void onAuthorizationCheckFinish(RemoteOperationResult result) { + mExistenceCheckOpId = -1; + dismissDialog(WAIT_DIALOG_TAG); if (result.isSuccess()) { Log_OC.d(TAG, "Successful access - time to save the account"); @@ -1247,7 +1302,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { mServerIsChecked = true; mServerIsValid = false; mIsSslConn = false; - mOcServerChkOperation = null; + mServerInfoOperation = null; mDiscoveredVersion = null; mHostBaseUrl = normalizeUrl(mHostUrlInput.getText().toString()); @@ -1259,7 +1314,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { showAuthStatus(); // update input controls state - showRefreshButton(); + showRefreshButton(true); mOkButton.setEnabled(false); // very special case (TODO: move to a common place for all the remote operations) (dangerous here?) @@ -1383,90 +1438,6 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { /** - * {@inheritDoc} - * - * Necessary to update the contents of the SSL Dialog - * - * TODO move to some common place for all possible untrusted SSL failures - */ - @Override - protected void onPrepareDialog(int id, Dialog dialog, Bundle args) { - switch (id) { - case DIALOG_LOGIN_PROGRESS: - case DIALOG_CERT_NOT_SAVED: - case DIALOG_OAUTH2_LOGIN_PROGRESS: - break; - default: - Log_OC.e(TAG, "Incorrect dialog called with id = " + id); - } - } - - - /** - * {@inheritDoc} - */ - @Override - protected Dialog onCreateDialog(int id) { - Dialog dialog = null; - switch (id) { - case DIALOG_LOGIN_PROGRESS: { - /// simple progress dialog - ProgressDialog working_dialog = new ProgressDialog(this); - working_dialog.setMessage(getResources().getString(R.string.auth_trying_to_login)); - working_dialog.setIndeterminate(true); - working_dialog.setCancelable(true); - working_dialog - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - /// TODO study if this is enough - Log_OC.i(TAG, "Login canceled"); - if (mOperationThread != null) { - mOperationThread.interrupt(); - finish(); - } - } - }); - dialog = working_dialog; - break; - } - case DIALOG_OAUTH2_LOGIN_PROGRESS: { - ProgressDialog working_dialog = new ProgressDialog(this); - working_dialog.setMessage(String.format("Getting authorization")); - working_dialog.setIndeterminate(true); - working_dialog.setCancelable(true); - working_dialog - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - Log_OC.i(TAG, "Login canceled"); - finish(); - } - }); - dialog = working_dialog; - break; - } - case DIALOG_CERT_NOT_SAVED: { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved)); - builder.setCancelable(false); - builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - }; - }); - dialog = builder.create(); - break; - } - default: - Log_OC.e(TAG, "Incorrect dialog called with id = " + id); - } - return dialog; - } - - - /** * Starts and activity to open the 'new account' page in the ownCloud web site * * @param view 'Account register' button @@ -1513,12 +1484,12 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { } - private void showRefreshButton() { - mRefreshButton.setVisibility(View.VISIBLE); - } - - private void hideRefreshButton() { - mRefreshButton.setVisibility(View.GONE); + private void showRefreshButton (boolean show) { + if (show) { + mRefreshButton.setVisibility(View.VISIBLE); + } else { + mRefreshButton.setVisibility(View.GONE); + } } /** @@ -1655,25 +1626,32 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { if (sessionCookie != null && sessionCookie.length() > 0) { mAuthToken = sessionCookie; - - GetRemoteUserNameOperation getUserOperation = new GetRemoteUserNameOperation(); - OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(mHostBaseUrl), getApplicationContext(), true); - client.setSsoSessionCookie(mAuthToken); - getUserOperation.execute(client, this, mHandler); + boolean followRedirects = true; + getRemoteUserNameOperation(sessionCookie, followRedirects); + } + } + + private void getRemoteUserNameOperation(String sessionCookie, boolean followRedirects) { + + Intent getUserNameIntent = new Intent(); + getUserNameIntent.setAction(OperationsService.ACTION_GET_USER_NAME); + getUserNameIntent.putExtra(OperationsService.EXTRA_SERVER_URL, mHostBaseUrl); + getUserNameIntent.putExtra(OperationsService.EXTRA_COOKIE, sessionCookie); + getUserNameIntent.putExtra(OperationsService.EXTRA_FOLLOW_REDIRECTS, followRedirects); + + if (mOperationsServiceBinder != null) { + //Log_OC.wtf(TAG, "starting getRemoteUserNameOperation..." ); + mGetUserNameOpId = mOperationsServiceBinder.newOperation(getUserNameIntent); } - - } @Override public void onSsoFinished(String sessionCookies) { - //Toast.makeText(this, "got cookies: " + sessionCookie, Toast.LENGTH_LONG).show(); - if (sessionCookies != null && sessionCookies.length() > 0) { Log_OC.d(TAG, "Successful SSO - time to save the account"); onSamlDialogSuccess(sessionCookies); - Fragment fd = getSupportFragmentManager().findFragmentByTag(TAG_SAML_DIALOG); + Fragment fd = getSupportFragmentManager().findFragmentByTag(SAML_DIALOG_TAG); if (fd != null && fd instanceof SherlockDialogFragment) { Dialog d = ((SherlockDialogFragment)fd).getDialog(); if (d != null && d.isShowing()) { @@ -1742,22 +1720,10 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { } /** - * Dismiss untrusted cert dialog - */ - public void dismissUntrustedCertDialog(){ - /*Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_UNTRUSTED_CERT); - if (frag != null) { - SslErrorViewAdapter dialog = (SslErrorViewAdapter) frag; - dialog.dismiss(); - } - */ - } - - /** * Called from SslValidatorDialog when a new server certificate was correctly saved. */ public void onSavedCertificate() { - Fragment fd = getSupportFragmentManager().findFragmentByTag(TAG_SAML_DIALOG); + 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(); @@ -1770,25 +1736,99 @@ SsoWebViewClientListener, OnSslUntrustedCertListener { */ @Override public void onFailedSavingCertificate() { - showDialog(DIALOG_CERT_NOT_SAVED); - cancelWebView(); + dismissDialog(SAML_DIALOG_TAG); + Toast.makeText(this, R.string.ssl_validator_not_saved, Toast.LENGTH_LONG).show(); } @Override public void onCancelCertificate() { - cancelWebView(); + dismissDialog(SAML_DIALOG_TAG); } - public void cancelWebView() { - Fragment fd = getSupportFragmentManager().findFragmentByTag(TAG_SAML_DIALOG); - if (fd != null && fd instanceof SherlockDialogFragment) { - Dialog d = ((SherlockDialogFragment)fd).getDialog(); - if (d != null && d.isShowing()) { - d.dismiss(); + private void doOnResumeAndBound() { + //Log.wtf(TAG, "registering to listen for operation callbacks" ); + mOperationsServiceBinder.addOperationListener(AuthenticatorActivity.this, mHandler); + + if (mGetServerInfoOpId != -1) { + RemoteOperationResult result = + mOperationsServiceBinder.getOperationResultIfFinished(mGetServerInfoOpId); + if (result != null) { + //Log_OC.wtf(TAG, "found result of operation finished while rotating"); + onGetServerInfoFinish(result); } - } + + } else if (mOauth2GetAccessTokenOpId != -1) { + RemoteOperationResult result = + mOperationsServiceBinder.getOperationResultIfFinished( + mOauth2GetAccessTokenOpId); + if (result != null) { + //Log_OC.wtf(TAG, "found result of operation finished while rotating"); + onGetOAuthAccessTokenFinish(result); + } + + } else if (mExistenceCheckOpId != -1) { + RemoteOperationResult result = + mOperationsServiceBinder.getOperationResultIfFinished(mExistenceCheckOpId); + if (result != null) { + //Log_OC.wtf(TAG, "found result of operation finished while rotating"); + if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie( + MainApp.getAccountType()).equals(mAuthTokenType)) { + onSamlBasedFederatedSingleSignOnAuthorizationStart(result); + + } else { + onAuthorizationCheckFinish(result); + } + } + }if (mGetUserNameOpId != -1) { + RemoteOperationResult result = + mOperationsServiceBinder.getOperationResultIfFinished(mGetUserNameOpId); + if (result != null) { + //Log_OC.wtf(TAG, "found result of operation finished while rotating"); + onGetUserNameFinish(result); + } + + } + + } + + private void dismissDialog(String dialogTag){ + Fragment frag = getSupportFragmentManager().findFragmentByTag(dialogTag); + if (frag != null && frag instanceof SherlockDialogFragment) { + SherlockDialogFragment dialog = (SherlockDialogFragment) frag; + dialog.dismiss(); + } } + + + /** + * 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))) { + //Log_OC.wtf(TAG, "Operations service connected"); + mOperationsServiceBinder = (OperationsServiceBinder) service; + + doOnResumeAndBound(); + + } else { + return; + } + + } + + @Override + public void onServiceDisconnected(ComponentName component) { + if (component.equals(new ComponentName(AuthenticatorActivity.this, OperationsService.class))) { + Log_OC.e(TAG, "Operations service crashed"); + mOperationsServiceBinder = null; + } + } + + } + } diff --git a/src/com/owncloud/android/operations/DetectAuthenticationMethodOperation.java b/src/com/owncloud/android/operations/DetectAuthenticationMethodOperation.java index c6703161..b817e724 100644 --- a/src/com/owncloud/android/operations/DetectAuthenticationMethodOperation.java +++ b/src/com/owncloud/android/operations/DetectAuthenticationMethodOperation.java @@ -64,14 +64,17 @@ public class DetectAuthenticationMethodOperation extends RemoteOperation { } private Context mContext; + private String mWebDavUrl; /** * Constructor * * @param context Android context of the caller. + * @param webdavUrl */ - public DetectAuthenticationMethodOperation(Context context) { + public DetectAuthenticationMethodOperation(Context context, String webdavUrl) { mContext = context; + mWebDavUrl = webdavUrl; } @@ -90,6 +93,7 @@ public class DetectAuthenticationMethodOperation extends RemoteOperation { AuthenticationMethod authMethod = AuthenticationMethod.UNKNOWN; RemoteOperation operation = new ExistenceCheckRemoteOperation("", mContext, false); + client.setWebdavUri(Uri.parse(mWebDavUrl)); client.setBasicCredentials("", ""); client.setFollowRedirects(false); @@ -122,6 +126,9 @@ public class DetectAuthenticationMethodOperation extends RemoteOperation { // else - fall back to UNKNOWN Log.d(TAG, "Authentication method found: " + authenticationMethodToString(authMethod)); + if (!authMethod.equals(AuthenticationMethod.UNKNOWN)) { + result = new RemoteOperationResult(true, result.getHttpCode(), null); + } ArrayList data = new ArrayList(); data.add(authMethod); result.setData(data); diff --git a/src/com/owncloud/android/operations/GetServerInfoOperation.java b/src/com/owncloud/android/operations/GetServerInfoOperation.java new file mode 100644 index 00000000..c210153e --- /dev/null +++ b/src/com/owncloud/android/operations/GetServerInfoOperation.java @@ -0,0 +1,163 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2014 ownCloud Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.operations; + +import java.util.ArrayList; + +import com.owncloud.android.authentication.AccountUtils; +import com.owncloud.android.lib.common.OwnCloudClient; +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.resources.status.GetRemoteStatusOperation; +import com.owncloud.android.lib.resources.status.OwnCloudVersion; +import com.owncloud.android.operations.DetectAuthenticationMethodOperation.AuthenticationMethod; +import com.owncloud.android.utils.Log_OC; + +import android.content.Context; + +/** + * Get basic information from an ownCloud server given its URL. + * + * Checks the existence of a configured ownCloud server in the URL, gets its version + * and finds out what authentication method is needed to access files in it. + * + * @author David A. Velasco + * @author masensio + */ + +public class GetServerInfoOperation extends RemoteOperation { + + private static final String TAG = GetServerInfoOperation.class.getSimpleName(); + + private String mUrl; + private String mAuthTokenType; + private Context mContext; + + private ServerInfo mResultData; + + /** + * Constructor. + * + * @param url URL to an ownCloud server. + * @param authTokenType Identifies the authorization token supported by the caller; + * TODO ugly dependency, get rid of it. + * @param context Android context; needed to check network state + * TODO ugly dependency, get rid of it. + */ + public GetServerInfoOperation(String url, String authTokenType, Context context) { + mUrl = trimWebdavSuffix(url); + mAuthTokenType = authTokenType; + mContext = context; + + mResultData = new ServerInfo(); + } + + + /** + * Performs the operation + * + * @return Result of the operation. If successful, includes an instance of + * {@link ServerInfo} with the information retrieved from the server. + * Call {@link RemoteOperationResult#getData()}.get(0) to get it. + */ + @Override + protected RemoteOperationResult run(OwnCloudClient client) { + + // first: check the status of the server (including its version) + GetRemoteStatusOperation getStatus = new GetRemoteStatusOperation(mUrl, mContext); + RemoteOperationResult result = getStatus.execute(client); + + if (result.isSuccess()) { + // second: get authentication method required by the server + mResultData.mVersion = (OwnCloudVersion)(result.getData().get(0)); + boolean isSslConn = (result.getCode() == ResultCode.OK_SSL); + mResultData.mBaseUrl = normalizeProtocolPrefix(mUrl, isSslConn); + RemoteOperationResult detectAuthResult = detectAuthorizationMethod(client); + + // third: merge results + if (detectAuthResult.isSuccess()) { + mResultData.mAuthMethod = + (AuthenticationMethod)detectAuthResult.getData().get(0); + ArrayList data = new ArrayList(); + data.add(mResultData); + result.setData(data); + } else { + result = detectAuthResult; + } + } + return result; + } + + + private RemoteOperationResult detectAuthorizationMethod(OwnCloudClient client) { + Log_OC.d(TAG, "Trying empty authorization to detect authentication method"); + String webdav_path = AccountUtils.getWebdavPath(mResultData.mVersion, mAuthTokenType); + String webdav_url = mResultData.mBaseUrl + webdav_path; + DetectAuthenticationMethodOperation operation = + new DetectAuthenticationMethodOperation(mContext, webdav_url); + return operation.execute(client); + } + + + private String trimWebdavSuffix(String url) { + if (url == null) { + url = ""; + } else { + if (url.endsWith("/")) { + url = url.substring(0, url.length() - 1); + } + if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_4_0)){ + url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_4_0.length()); + } else if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_2_0)){ + url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_2_0.length()); + } else if (url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_1_2)){ + url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_1_2.length()); + } + } + return url; + } + + + private String normalizeProtocolPrefix(String url, boolean isSslConn) { + if (!url.toLowerCase().startsWith("http://") && + !url.toLowerCase().startsWith("https://")) { + if (isSslConn) { + return "https://" + url; + } else { + return "http://" + url; + } + } + return url; + } + + + public static class ServerInfo { + public OwnCloudVersion mVersion; + public String mBaseUrl; + public AuthenticationMethod mAuthMethod; + } + +} diff --git a/src/com/owncloud/android/operations/OAuth2GetAccessToken.java b/src/com/owncloud/android/operations/OAuth2GetAccessToken.java index e2d72c5c..5f6a085b 100644 --- a/src/com/owncloud/android/operations/OAuth2GetAccessToken.java +++ b/src/com/owncloud/android/operations/OAuth2GetAccessToken.java @@ -1,5 +1,6 @@ package com.owncloud.android.operations; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -37,15 +38,12 @@ public class OAuth2GetAccessToken extends RemoteOperation { mOAuth2ParsedAuthorizationResponse = new HashMap(); mResultTokenMap = null; } - - - public Map getOauth2AutorizationResponse() { - return mOAuth2ParsedAuthorizationResponse; - } + /* public Map getResultTokenMap() { return mResultTokenMap; } + */ @Override protected RemoteOperationResult run(OwnCloudClient client) { @@ -83,6 +81,9 @@ public class OAuth2GetAccessToken extends RemoteOperation { } else { result = new RemoteOperationResult(true, status, postMethod.getResponseHeaders()); + ArrayList data = new ArrayList(); + data.add(mResultTokenMap); + result.setData(data); } } else { diff --git a/src/com/owncloud/android/services/OperationsService.java b/src/com/owncloud/android/services/OperationsService.java index 80caea71..81a4adee 100644 --- a/src/com/owncloud/android/services/OperationsService.java +++ b/src/com/owncloud/android/services/OperationsService.java @@ -1,5 +1,5 @@ /* ownCloud Android client application - * Copyright (C) 2012-2013 ownCloud Inc. + * Copyright (C) 2012-2014 ownCloud Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -18,20 +18,25 @@ package com.owncloud.android.services; import java.io.IOException; -import java.util.HashMap; import java.util.Iterator; -import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ConcurrentMap; +import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.OwnCloudClient; 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.resources.files.ExistenceCheckRemoteOperation; import com.owncloud.android.lib.resources.shares.ShareType; +import com.owncloud.android.lib.resources.users.GetRemoteUserNameOperation; import com.owncloud.android.operations.common.SyncOperation; import com.owncloud.android.operations.CreateShareOperation; +import com.owncloud.android.operations.GetServerInfoOperation; +import com.owncloud.android.operations.OAuth2GetAccessToken; import com.owncloud.android.operations.UnshareLinkOperation; import com.owncloud.android.utils.Log_OC; @@ -47,7 +52,6 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.Process; -//import android.support.v4.content.LocalBroadcastManager; import android.util.Pair; public class OperationsService extends Service { @@ -56,24 +60,57 @@ public class OperationsService extends Service { public static final String EXTRA_ACCOUNT = "ACCOUNT"; public static final String EXTRA_SERVER_URL = "SERVER_URL"; + public static final String EXTRA_AUTH_TOKEN_TYPE = "AUTH_TOKEN_TYPE"; + public static final String EXTRA_OAUTH2_QUERY_PARAMETERS = "OAUTH2_QUERY_PARAMETERS"; public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; public static final String EXTRA_SEND_INTENT = "SEND_INTENT"; public static final String EXTRA_RESULT = "RESULT"; + // TODO review if ALL OF THEM are necessary + public static final String EXTRA_WEBDAV_PATH = "WEBDAV_PATH"; + public static final String EXTRA_SUCCESS_IF_ABSENT = "SUCCESS_IF_ABSENT"; + public static final String EXTRA_USERNAME = "USERNAME"; + public static final String EXTRA_PASSWORD = "PASSWORD"; + public static final String EXTRA_AUTH_TOKEN = "AUTH_TOKEN"; + public static final String EXTRA_FOLLOW_REDIRECTS = "FOLLOW_REDIRECTS"; + public static final String EXTRA_COOKIE = "COOKIE"; + public static final String ACTION_CREATE_SHARE = "CREATE_SHARE"; public static final String ACTION_UNSHARE = "UNSHARE"; + public static final String ACTION_GET_SERVER_INFO = "GET_SERVER_INFO"; + public static final String ACTION_OAUTH2_GET_ACCESS_TOKEN = "OAUTH2_GET_ACCESS_TOKEN"; + public static final String ACTION_EXISTENCE_CHECK = "EXISTENCE_CHECK"; + public static final String ACTION_GET_USER_NAME = "GET_USER_NAME"; public static final String ACTION_OPERATION_ADDED = OperationsService.class.getName() + ".OPERATION_ADDED"; public static final String ACTION_OPERATION_FINISHED = OperationsService.class.getName() + ".OPERATION_FINISHED"; - private ConcurrentLinkedQueue> mPendingOperations = new ConcurrentLinkedQueue>(); + private ConcurrentLinkedQueue> mPendingOperations = + new ConcurrentLinkedQueue>(); + + private ConcurrentMap mOperationResults = + new ConcurrentHashMap(); private static class Target { public Uri mServerUrl = null; public Account mAccount = null; - public Target(Account account, Uri serverUrl) { + public String mWebDavUrl = ""; + public String mUsername = ""; + public String mPassword = ""; + public String mAuthToken = ""; + public boolean mFollowRedirects = true; + public String mCookie = ""; + + public Target(Account account, Uri serverUrl, String webdavUrl, String username, String password, String authToken, + boolean followRedirects, String cookie) { mAccount = account; mServerUrl = serverUrl; + mWebDavUrl = webdavUrl; + mUsername = username; + mPassword = password; + mAuthToken = authToken; + mFollowRedirects = followRedirects; + mCookie = cookie; } } @@ -99,6 +136,7 @@ public class OperationsService extends Service { mBinder = new OperationsServiceBinder(); } + /** * Entry point to add a new operation to the queue of operations. * @@ -110,47 +148,11 @@ public class OperationsService extends Service { */ @Override public int onStartCommand(Intent intent, int flags, int startId) { - if (!intent.hasExtra(EXTRA_ACCOUNT) && !intent.hasExtra(EXTRA_SERVER_URL)) { - Log_OC.e(TAG, "Not enough information provided in intent"); - return START_NOT_STICKY; - } - try { - Account account = intent.getParcelableExtra(EXTRA_ACCOUNT); - String serverUrl = intent.getStringExtra(EXTRA_SERVER_URL); - - Target target = new Target(account, (serverUrl == null) ? null : Uri.parse(serverUrl)); - RemoteOperation operation = null; - - String action = intent.getAction(); - if (action.equals(ACTION_CREATE_SHARE)) { // Create Share - String remotePath = intent.getStringExtra(EXTRA_REMOTE_PATH); - Intent sendIntent = intent.getParcelableExtra(EXTRA_SEND_INTENT); - if (remotePath.length() > 0) { - operation = new CreateShareOperation(remotePath, ShareType.PUBLIC_LINK, - "", false, "", 1, sendIntent); - } - } else if (action.equals(ACTION_UNSHARE)) { // Unshare file - String remotePath = intent.getStringExtra(EXTRA_REMOTE_PATH); - if (remotePath.length() > 0) { - operation = new UnshareLinkOperation(remotePath, this.getApplicationContext()); - } - } else { - // nothing we are going to handle - return START_NOT_STICKY; - } - - mPendingOperations.add(new Pair(target, operation)); - //sendBroadcastNewOperation(target, operation); - - Message msg = mServiceHandler.obtainMessage(); - msg.arg1 = startId; - mServiceHandler.sendMessage(msg); - - } catch (IllegalArgumentException e) { - Log_OC.e(TAG, "Bad information provided in intent: " + e.getMessage()); - return START_NOT_STICKY; - } - + //Log.wtf(TAG, "onStartCommand init" ); + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + mServiceHandler.sendMessage(msg); + //Log.wtf(TAG, "onStartCommand end" ); return START_NOT_STICKY; } @@ -161,6 +163,7 @@ public class OperationsService extends Service { */ @Override public IBinder onBind(Intent intent) { + //Log.wtf(TAG, "onBind" ); return mBinder; } @@ -170,7 +173,7 @@ public class OperationsService extends Service { */ @Override public boolean onUnbind(Intent intent) { - //((OperationsServiceBinder)mBinder).clearListeners(); + ((OperationsServiceBinder)mBinder).clearListeners(); return false; // not accepting rebinding (default behaviour) } @@ -185,7 +188,8 @@ public class OperationsService extends Service { /** * Map of listeners that will be reported about the end of operations from a {@link OperationsServiceBinder} instance */ - private Map mBoundListeners = new HashMap(); + private ConcurrentMap mBoundListeners = + new ConcurrentHashMap(); /** * Cancels an operation @@ -210,7 +214,9 @@ public class OperationsService extends Service { * @param callbackHandler {@link Handler} to access the listener without breaking Android threading protection. */ public void addOperationListener (OnRemoteOperationListener listener, Handler callbackHandler) { - mBoundListeners.put(listener, callbackHandler); + synchronized (mBoundListeners) { + mBoundListeners.put(listener, callbackHandler); + } } @@ -220,7 +226,9 @@ public class OperationsService extends Service { * @param listener Object to notify about progress of transfer. */ public void removeOperationListener (OnRemoteOperationListener listener) { - mBoundListeners.remove(listener); + synchronized (mBoundListeners) { + mBoundListeners.remove(listener); + } } @@ -233,6 +241,108 @@ public class OperationsService extends Service { return (!mPendingOperations.isEmpty()); } + + /** + * Creates and adds to the queue a new operation, as described by operationIntent + * + * @param operationIntent Intent describing a new operation to queue and execute. + * @return Identifier of the operation created, or -1 if failed. + */ + public int newOperation(Intent operationIntent) { + RemoteOperation operation = null; + Target target = null; + try { + if (!operationIntent.hasExtra(EXTRA_ACCOUNT) && + !operationIntent.hasExtra(EXTRA_SERVER_URL)) { + Log_OC.e(TAG, "Not enough information provided in intent"); + + } else { + Account account = operationIntent.getParcelableExtra(EXTRA_ACCOUNT); + String serverUrl = operationIntent.getStringExtra(EXTRA_SERVER_URL); + String webDavPath = operationIntent.getStringExtra(EXTRA_WEBDAV_PATH); + String webDavUrl = serverUrl + webDavPath; + String username = operationIntent.getStringExtra(EXTRA_USERNAME); + String password = operationIntent.getStringExtra(EXTRA_PASSWORD); + String authToken = operationIntent.getStringExtra(EXTRA_AUTH_TOKEN); + boolean followRedirects = operationIntent.getBooleanExtra(EXTRA_FOLLOW_REDIRECTS, true); + String cookie = operationIntent.getStringExtra(EXTRA_COOKIE); + target = new Target( + account, + (serverUrl == null) ? null : Uri.parse(serverUrl), + ((webDavPath == null) || (serverUrl == null)) ? "" : webDavUrl, + (username == null) ? "" : username, + (password == null) ? "" : password, + (authToken == null) ? "" : authToken, + followRedirects, + (cookie == null) ? "" : cookie + ); + + String action = operationIntent.getAction(); + if (action.equals(ACTION_CREATE_SHARE)) { // Create Share + String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); + Intent sendIntent = operationIntent.getParcelableExtra(EXTRA_SEND_INTENT); + if (remotePath.length() > 0) { + operation = new CreateShareOperation(remotePath, ShareType.PUBLIC_LINK, + "", false, "", 1, sendIntent); + } + + } else if (action.equals(ACTION_UNSHARE)) { // Unshare file + String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); + if (remotePath.length() > 0) { + operation = new UnshareLinkOperation( + remotePath, + OperationsService.this); + } + + } else if (action.equals(ACTION_GET_SERVER_INFO)) { + // check OC server and get basic information from it + String authTokenType = + operationIntent.getStringExtra(EXTRA_AUTH_TOKEN_TYPE); + operation = new GetServerInfoOperation( + serverUrl, authTokenType, OperationsService.this); + + } else if (action.equals(ACTION_OAUTH2_GET_ACCESS_TOKEN)) { + /// GET ACCESS TOKEN to the OAuth server + String oauth2QueryParameters = + operationIntent.getStringExtra(EXTRA_OAUTH2_QUERY_PARAMETERS); + operation = new OAuth2GetAccessToken( + getString(R.string.oauth2_client_id), + getString(R.string.oauth2_redirect_uri), + getString(R.string.oauth2_grant_type), + oauth2QueryParameters); + + } else if (action.equals(ACTION_EXISTENCE_CHECK)) { + // Existence Check + String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); + boolean successIfAbsent = operationIntent.getBooleanExtra(EXTRA_SUCCESS_IF_ABSENT, true); + operation = new ExistenceCheckRemoteOperation(remotePath, OperationsService.this, successIfAbsent); + + } else if (action.equals(ACTION_GET_USER_NAME)) { + // Get User Name + operation = new GetRemoteUserNameOperation(); + } + } + + } catch (IllegalArgumentException e) { + Log_OC.e(TAG, "Bad information provided in intent: " + e.getMessage()); + operation = null; + } + + if (operation != null) { + mPendingOperations.add(new Pair(target, operation)); + startService(new Intent(OperationsService.this, OperationsService.class)); + return operation.hashCode(); + + } else { + return -1; + } + } + + public RemoteOperationResult getOperationResultIfFinished(int mDetectAuthOpId) { + //Log_OC.wtf(TAG, "Searching result for operation with id " + mDetectAuthOpId); + return mOperationResults.remove(mDetectAuthOpId); + } + } @@ -265,11 +375,13 @@ public class OperationsService extends Service { */ private void nextOperation() { + //Log.wtf(TAG, "nextOperation init" ); + Pair next = null; synchronized(mPendingOperations) { next = mPendingOperations.peek(); } - + if (next != null) { mCurrentOperation = next.second; @@ -282,7 +394,18 @@ public class OperationsService extends Service { mOwnCloudClient = OwnCloudClientFactory.createOwnCloudClient(mLastTarget.mAccount, getApplicationContext()); mStorageManager = new FileDataStorageManager(mLastTarget.mAccount, getContentResolver()); } else { - mOwnCloudClient = OwnCloudClientFactory.createOwnCloudClient(mLastTarget.mServerUrl, getApplicationContext(), true); // this is not good enough + mOwnCloudClient = OwnCloudClientFactory.createOwnCloudClient(mLastTarget.mServerUrl, getApplicationContext(), + mLastTarget.mFollowRedirects); // this is not good enough + if (mLastTarget.mWebDavUrl != "") { + mOwnCloudClient.setWebdavUri(Uri.parse(mLastTarget.mWebDavUrl)); + } + if (mLastTarget.mUsername != "" && mLastTarget.mPassword != "") { + mOwnCloudClient.setBasicCredentials(mLastTarget.mUsername, mLastTarget.mPassword); + } else if (mLastTarget.mAuthToken != "") { + mOwnCloudClient.setBearerCredentials(mLastTarget.mAuthToken); + } else if (mLastTarget.mCookie != "") { + mOwnCloudClient.setSsoSessionCookie(mLastTarget.mCookie); + } mStorageManager = null; } } @@ -320,6 +443,7 @@ public class OperationsService extends Service { } finally { synchronized(mPendingOperations) { mPendingOperations.poll(); + mOperationResults.put(mCurrentOperation.hashCode(), result); } } @@ -382,7 +506,9 @@ public class OperationsService extends Service { * @param operation Finished operation. * @param result Result of the operation. */ - private void callbackOperationListeners(Target target, final RemoteOperation operation, final RemoteOperationResult result) { + private void callbackOperationListeners( + Target target, final RemoteOperation operation, final RemoteOperationResult result) { + int count = 0; Iterator listeners = mBinder.mBoundListeners.keySet().iterator(); while (listeners.hasNext()) { final OnRemoteOperationListener listener = listeners.next(); @@ -394,9 +520,10 @@ public class OperationsService extends Service { listener.onRemoteOperationFinish(operation, result); } }); + count += 1; } } - + Log_OC.d(TAG, "Called " + count + " listeners"); } diff --git a/src/com/owncloud/android/ui/activity/FileActivity.java b/src/com/owncloud/android/ui/activity/FileActivity.java index 42b90aec..c4dd28a2 100644 --- a/src/com/owncloud/android/ui/activity/FileActivity.java +++ b/src/com/owncloud/android/ui/activity/FileActivity.java @@ -150,22 +150,26 @@ public class FileActivity extends SherlockFragmentActivity implements OnRemoteOp @Override protected void onStart() { - super.onStart(); + if (mAccountWasSet) { onAccountSet(mAccountWasRestored); } if (mOperationsServiceBinder != null) { mOperationsServiceBinder.addOperationListener(FileActivity.this, mHandler); } + + super.onStart(); } @Override protected void onStop() { - super.onStop(); + if (mOperationsServiceBinder != null) { mOperationsServiceBinder.removeOperationListener(this); } + + super.onStop(); } diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index 867e4cfe..f6136ed3 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -19,6 +19,7 @@ package com.owncloud.android.ui.activity; import java.io.File; + import android.accounts.Account; import android.app.AlertDialog; import android.app.Dialog; diff --git a/src/com/owncloud/android/ui/dialog/SamlWebViewDialog.java b/src/com/owncloud/android/ui/dialog/SamlWebViewDialog.java index cbf1acb0..0c17a6f2 100644 --- a/src/com/owncloud/android/ui/dialog/SamlWebViewDialog.java +++ b/src/com/owncloud/android/ui/dialog/SamlWebViewDialog.java @@ -72,7 +72,7 @@ public class SamlWebViewDialog extends SherlockDialogFragment { * * @param handler * @param Url Url to open at WebView - * @param targetURL mHostBaseUrl + AccountUtils.getWebdavPath(mDiscoveredVersion, mCurrentAuthTokenType) + * @param targetURL mBaseUrl + AccountUtils.getWebdavPath(mDiscoveredVersion, mCurrentAuthTokenType) * @return New dialog instance, ready to show. */ public static SamlWebViewDialog newInstance(String url, String targetUrl) {