X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/ac07e35d8ab68bf94d5cd8b45680ea69247fcc9f..7d84fd0c9f15227bc65a2ae00a74e1cfd8f8d33b:/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java diff --git a/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java b/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java index 4d17a831..8dce3bc2 100644 --- a/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java +++ b/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java @@ -19,9 +19,6 @@ package com.owncloud.android.ui.activity; -import java.util.HashMap; -import java.util.Map; - import com.owncloud.android.AccountUtils; import com.owncloud.android.authenticator.AccountAuthenticator; import com.owncloud.android.authenticator.oauth2.OAuth2Context; @@ -35,6 +32,7 @@ import com.owncloud.android.operations.OAuth2GetAccessToken; import com.owncloud.android.operations.OnRemoteOperationListener; import com.owncloud.android.operations.RemoteOperation; import com.owncloud.android.operations.RemoteOperationResult; +import com.owncloud.android.operations.RemoteOperationResult.ResultCode; import android.accounts.Account; import android.accounts.AccountAuthenticatorActivity; @@ -60,6 +58,8 @@ import android.widget.EditText; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; +import android.widget.Toast; + import com.owncloud.android.R; import eu.alefzero.webdav.WebdavClient; @@ -78,9 +78,11 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity public static final String EXTRA_ACCOUNT = "ACCOUNT"; public static final String EXTRA_USER_NAME = "USER_NAME"; public static final String EXTRA_HOST_NAME = "HOST_NAME"; - + public static final String EXTRA_ACTION = "ACTION"; + private static final String KEY_HOST_URL_TEXT = "HOST_URL_TEXT"; private static final String KEY_OC_VERSION = "OC_VERSION"; + private static final String KEY_ACCOUNT = "ACCOUNT"; private static final String KEY_STATUS_TEXT = "STATUS_TEXT"; private static final String KEY_STATUS_ICON = "STATUS_ICON"; private static final String KEY_STATUS_CORRECT = "STATUS_CORRECT"; @@ -93,6 +95,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity private static final int DIALOG_CERT_NOT_SAVED = 2; private static final int DIALOG_OAUTH2_LOGIN_PROGRESS = 3; + public static final byte ACTION_CREATE = 0; + public static final byte ACTION_UPDATE_TOKEN = 1; + private String mHostBaseUrl; private OwnCloudVersion mDiscoveredVersion; @@ -114,6 +119,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity private Uri mNewCapturedUriFromOAuth2Redirection; private AccountManager mAccountMgr; + private boolean mJustCreated; + private byte mAction; + private Account mAccount; private ImageView mRefreshButton; private ImageView mViewPasswordButton; @@ -123,11 +131,10 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity private CheckBox mOAuth2Check; private String mOAuthAccessToken; private View mOkButton; + private TextView mAuthStatusLayout; private TextView mOAuthAuthEndpointText; private TextView mOAuthTokenEndpointText; - - /** @@ -151,6 +158,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity mOAuthTokenEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_2); mOAuth2Check = (CheckBox) findViewById(R.id.oauth_onOff_check); mOkButton = findViewById(R.id.buttonOK); + mAuthStatusLayout = (TextView) findViewById(R.id.auth_status_text); + /// complete label for 'register account' button Button b = (Button) findViewById(R.id.account_register); @@ -165,6 +174,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity /// initialization mAccountMgr = AccountManager.get(this); mNewCapturedUriFromOAuth2Redirection = null; // TODO save? + mAction = getIntent().getByteExtra(EXTRA_ACTION, ACTION_CREATE); + mAccount = null; if (savedInstanceState == null) { /// connection state and info @@ -175,26 +186,37 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity /// retrieve extras from intent String tokenType = getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE); boolean oAuthRequired = AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN.equals(tokenType); - mOAuth2Check.setChecked(oAuthRequired); - changeViewByOAuth2Check(oAuthRequired); - Account account = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT); - if (account != null) { - String ocVersion = mAccountMgr.getUserData(account, AccountAuthenticator.KEY_OC_VERSION); + mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT); + if (mAccount != null) { + String ocVersion = mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION); if (ocVersion != null) { mDiscoveredVersion = new OwnCloudVersion(ocVersion); } - mHostBaseUrl = mAccountMgr.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL); + mHostBaseUrl = mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL); mHostUrlInput.setText(mHostBaseUrl); - String userName = account.name.substring(0, account.name.lastIndexOf('@')); + String userName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@')); mUsernameInput.setText(userName); + oAuthRequired = (mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null); } + mOAuth2Check.setChecked(oAuthRequired); + changeViewByOAuth2Check(oAuthRequired); + } else { loadSavedInstanceState(savedInstanceState); } + if (mAction == ACTION_UPDATE_TOKEN) { + /// lock things that should not change + mHostUrlInput.setEnabled(false); + mUsernameInput.setEnabled(false); + mOAuth2Check.setVisibility(View.GONE); + checkOcServer(); + } + mPasswordInput.setText(""); // clean password to avoid social hacking (disadvantage: password in removed if the device is turned aside) + mJustCreated = true; } @@ -221,6 +243,10 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity outState.putString(KEY_OC_VERSION, mDiscoveredVersion.toString()); outState.putString(KEY_HOST_URL_TEXT, mHostBaseUrl); + /// account data, if updating + if (mAccount != null) + outState.putParcelable(KEY_ACCOUNT, mAccount); + // Saving the state of oAuth2 components. outState.putInt(KEY_OAUTH2_STATUS_ICON, mOAuth2StatusIcon); outState.putInt(KEY_OAUTH2_STATUS_TEXT, mOAuth2StatusText); @@ -246,7 +272,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity mIsSslConn = savedInstanceState.getBoolean(KEY_IS_SSL_CONN); mStatusText = savedInstanceState.getInt(KEY_STATUS_TEXT); mStatusIcon = savedInstanceState.getInt(KEY_STATUS_ICON); - updateOcServerCheckIconAndText(); + updateConnStatus(); /// UI settings depending upon connection mOkButton.setEnabled(mStatusCorrect); // TODO really necessary? @@ -261,10 +287,12 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity mDiscoveredVersion = new OwnCloudVersion(ocVersion); mHostBaseUrl = savedInstanceState.getString(KEY_HOST_URL_TEXT); + // account data, if updating + mAccount = savedInstanceState.getParcelable(KEY_ACCOUNT); + // state of oAuth2 components mOAuth2StatusIcon = savedInstanceState.getInt(KEY_OAUTH2_STATUS_ICON); mOAuth2StatusText = savedInstanceState.getInt(KEY_OAUTH2_STATUS_TEXT); - changeViewByOAuth2Check(mOAuth2Check.isChecked()); /* Leave old OAuth flow // We store a JSon object with all the data returned from oAuth2 server when we get user_code. @@ -305,6 +333,16 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity @Override protected void onResume() { super.onResume(); + // the state of mOAuth2Check is automatically recovered between configuration changes, but not before onCreate() finishes; so keep the next lines here + changeViewByOAuth2Check(mOAuth2Check.isChecked()); + if (mAction == ACTION_UPDATE_TOKEN && mJustCreated) { + if (mOAuth2Check.isChecked()) + Toast.makeText(this, R.string.auth_expired_oauth_token_toast, Toast.LENGTH_LONG).show(); + else + Toast.makeText(this, R.string.auth_expired_basic_auth_toast, Toast.LENGTH_LONG).show(); + } + + /* LEAVE OLD OAUTH FLOW ; // (old oauth code) Registering token receiver. We must listening to the service that is pooling to the oAuth server for a token. if (tokenReceiver == null) { @@ -316,6 +354,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity if (mNewCapturedUriFromOAuth2Redirection != null) { getOAuth2AccessTokenFromCapturedRedirection(); } + + mJustCreated = false; } @@ -342,42 +382,14 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity */ private void getOAuth2AccessTokenFromCapturedRedirection() { /// Parse data from OAuth redirection - Map responseValues = new HashMap(); String queryParameters = mNewCapturedUriFromOAuth2Redirection.getQuery(); mNewCapturedUriFromOAuth2Redirection = null; - String[] pairs = queryParameters.split("&"); - int i = 0; - String key = ""; - String value = ""; - StringBuilder sb = new StringBuilder(); - while (pairs.length > i) { - int j = 0; - String[] part = pairs[i].split("="); - while (part.length > j) { - String p = part[j]; - if (j == 0) { - key = p; - sb.append(key + " = "); - } else if (j == 1) { - value = p; - responseValues.put(key, value); - sb.append(value + "\n"); - } - - Log.v(TAG, "[" + i + "," + j + "] = " + p); - j++; - } - i++; - } - - /// Updating status widget to OK. - updateOAuth2IconAndText(R.drawable.ic_ok, R.string.auth_connection_established); /// Showing the dialog with instructions for the user. showDialog(DIALOG_OAUTH2_LOGIN_PROGRESS); /// GET ACCESS TOKEN to the oAuth server - RemoteOperation operation = new OAuth2GetAccessToken(responseValues); + RemoteOperation operation = new OAuth2GetAccessToken(queryParameters); WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(getString(R.string.oauth_url_endpoint_access)), getApplicationContext()); operation.execute(client, this, mHandler); } @@ -411,26 +423,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity */ private void onUrlInputFocusChanged(TextView hostInput, boolean hasFocus) { if (!hasFocus) { - String uri = hostInput.getText().toString().trim(); - if (uri.length() != 0) { - mStatusText = R.string.auth_testing_connection; - mStatusIcon = R.drawable.progress_small; - updateOcServerCheckIconAndText(); - /** TODO cancel previous connection check if the user tries to ammend a wrong URL - if(mConnChkOperation != null) { - mConnChkOperation.cancel(); - } */ - mOcServerChkOperation = new OwnCloudServerCheckOperation(uri, this); - WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this); - mHostBaseUrl = ""; - mDiscoveredVersion = null; - mOperationThread = mOcServerChkOperation.execute(client, this, mHandler); - } else { - mRefreshButton.setVisibility(View.INVISIBLE); - mStatusText = 0; - mStatusIcon = 0; - updateOcServerCheckIconAndText(); - } + checkOcServer(); + } else { // avoids that the 'connect' button can be clicked if the test was previously passed mOkButton.setEnabled(false); @@ -438,6 +432,30 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity } + private void checkOcServer() { + String uri = mHostUrlInput.getText().toString().trim(); + if (uri.length() != 0) { + mStatusText = R.string.auth_testing_connection; + mStatusIcon = R.drawable.progress_small; + updateConnStatus(); + /** TODO cancel previous connection check if the user tries to ammend a wrong URL + if(mConnChkOperation != null) { + mConnChkOperation.cancel(); + } */ + mOcServerChkOperation = new OwnCloudServerCheckOperation(uri, this); + WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this); + mHostBaseUrl = ""; + mDiscoveredVersion = null; + mOperationThread = mOcServerChkOperation.execute(client, this, mHandler); + } else { + mRefreshButton.setVisibility(View.INVISIBLE); + mStatusText = 0; + mStatusIcon = 0; + updateConnStatus(); + } + } + + /** * Handles changes in focus on the text input for the password (basic authorization). * @@ -495,7 +513,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity if (mDiscoveredVersion == null || !mDiscoveredVersion.isVersionValid() || mHostBaseUrl == null || mHostBaseUrl.length() == 0) { mStatusIcon = R.drawable.common_error; mStatusText = R.string.auth_wtf_reenter_URL; - updateOcServerCheckIconAndText(); + updateConnStatus(); mOkButton.setEnabled(false); Log.wtf(TAG, "The user was allowed to click 'connect' to an unchecked server!!"); return; @@ -539,7 +557,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity */ private void startOauthorization() { // be gentle with the user - updateOAuth2IconAndText(R.drawable.progress_small, R.string.oauth_login_connection); + mStatusIcon = R.drawable.progress_small; + mStatusText = R.string.oauth_login_connection; + updateAuthStatus(); // GET AUTHORIZATION request /* @@ -594,86 +614,19 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity * @param result Result of the check. */ private void onOcServerCheckFinish(OwnCloudServerCheckOperation operation, RemoteOperationResult result) { - /// update status connection icon and text - mStatusText = mStatusIcon = 0; - mStatusCorrect = false; + /// update status icon and text + updateStatusIconAndText(result); + updateConnStatus(); + + /// save result state + mStatusCorrect = result.isSuccess(); + mIsSslConn = (result.getCode() == ResultCode.OK_SSL); - switch (result.getCode()) { - case OK_SSL: - mIsSslConn = true; - mStatusIcon = android.R.drawable.ic_secure; - mStatusText = R.string.auth_secure_connection; - mStatusCorrect = true; - break; - - case OK_NO_SSL: - case OK: - mIsSslConn = false; - mStatusCorrect = true; - if (mHostUrlInput.getText().toString().trim().toLowerCase().startsWith("http://") ) { - mStatusText = R.string.auth_connection_established; - mStatusIcon = R.drawable.ic_ok; - } else { - mStatusText = R.string.auth_nossl_plain_ok_title; - mStatusIcon = android.R.drawable.ic_partial_secure; - } - break; - - /// very special case (TODO: move to a common place for all the remote operations) - case SSL_RECOVERABLE_PEER_UNVERIFIED: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_ssl_unverified_server_title; - mLastSslUntrustedServerResult = result; - showDialog(DIALOG_SSL_VALIDATOR); - break; - - case BAD_OC_VERSION: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_bad_oc_version_title; - break; - case WRONG_CONNECTION: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_wrong_connection_title; - break; - case TIMEOUT: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_timeout_title; - break; - case INCORRECT_ADDRESS: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_incorrect_address_title; - break; - - case SSL_ERROR: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_ssl_general_error_title; - break; - - case HOST_NOT_AVAILABLE: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_unknown_host_title; - break; - case NO_NETWORK_CONNECTION: - mStatusIcon = R.drawable.no_network; - mStatusText = R.string.auth_no_net_conn_title; - break; - case INSTANCE_NOT_CONFIGURED: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_not_configured_title; - break; - case FILE_NOT_FOUND: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_incorrect_path_title; - break; - case UNHANDLED_HTTP_CODE: - case UNKNOWN_ERROR: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_unknown_error_title; - break; - default: - Log.e(TAG, "Incorrect connection checker result type: " + result.getHttpCode()); + /// very special case (TODO: move to a common place for all the remote operations) + if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) { + mLastSslUntrustedServerResult = result; + showDialog(DIALOG_SSL_VALIDATOR); } - updateOcServerCheckIconAndText(); /// update the visibility of the 'retry connection' button if (!mStatusCorrect) @@ -703,6 +656,98 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity /** + * Chooses the right icon and text to show to the user for the received operation result. + * + * @param result Result of a remote operation performed in this activity + */ + private void updateStatusIconAndText(RemoteOperationResult result) { + mStatusText = mStatusIcon = 0; + + switch (result.getCode()) { + case OK_SSL: + mStatusIcon = android.R.drawable.ic_secure; + mStatusText = R.string.auth_secure_connection; + break; + + case OK_NO_SSL: + case OK: + if (mHostUrlInput.getText().toString().trim().toLowerCase().startsWith("http://") ) { + mStatusText = R.string.auth_connection_established; + mStatusIcon = R.drawable.ic_ok; + } else { + mStatusText = R.string.auth_nossl_plain_ok_title; + mStatusIcon = android.R.drawable.ic_partial_secure; + } + break; + + case SSL_RECOVERABLE_PEER_UNVERIFIED: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_ssl_unverified_server_title; + break; + + case BAD_OC_VERSION: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_bad_oc_version_title; + break; + case WRONG_CONNECTION: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_wrong_connection_title; + break; + case TIMEOUT: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_timeout_title; + break; + case INCORRECT_ADDRESS: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_incorrect_address_title; + break; + + case SSL_ERROR: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_ssl_general_error_title; + break; + + case UNAUTHORIZED: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_unauthorized; + break; + case HOST_NOT_AVAILABLE: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_unknown_host_title; + break; + case NO_NETWORK_CONNECTION: + mStatusIcon = R.drawable.no_network; + mStatusText = R.string.auth_no_net_conn_title; + break; + case INSTANCE_NOT_CONFIGURED: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_not_configured_title; + break; + case FILE_NOT_FOUND: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_incorrect_path_title; + break; + case OAUTH2_ERROR: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_oauth_error; + break; + case OAUTH2_ERROR_ACCESS_DENIED: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_oauth_error_access_denied; + break; + case UNHANDLED_HTTP_CODE: + case UNKNOWN_ERROR: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_unknown_error_title; + break; + + default: + break; + } + } + + + /** * Processes the result of the request for and access token send * to an OAuth authorization server. * @@ -716,7 +761,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens } - String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, false); + String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, true); if (result.isSuccess() && webdav_path != null) { /// be gentle with the user showDialog(DIALOG_LOGIN_PROGRESS); @@ -730,11 +775,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity mAuthCheckOperation.execute(client, this, mHandler); } else { - if (webdav_path != null) { - mOAuthAuthEndpointText.setError("A valid authorization could not be obtained"); - } else { - mOAuthAuthEndpointText.setError(getString(R.string.auth_bad_oc_version_title)); // should never happen - } + updateStatusIconAndText(result); + updateAuthStatus(); + Log.d(TAG, "Access failed: " + result.getLogMessage()); } } @@ -754,84 +797,113 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens } - boolean isOAuth = mOAuth2Check.isChecked(); - if (result.isSuccess()) { Log.d(TAG, "Successful access - time to save the account"); - /// create and save new ownCloud account - Uri uri = Uri.parse(mHostBaseUrl); - String username = isOAuth ? - "OAuth_user" + (new java.util.Random(System.currentTimeMillis())).nextLong() : - mUsernameInput.getText().toString().trim(); - // TODO a better way to set an account name - String accountName = username + "@" + uri.getHost(); - if (uri.getPort() >= 0) { - accountName += ":" + uri.getPort(); - } - Account account = new Account(accountName, AccountAuthenticator.ACCOUNT_TYPE); - AccountManager accManager = AccountManager.get(this); - if (isOAuth) { - accManager.addAccountExplicitly(account, "", null); // with our implementation, the password is never input in the app + if (mAction == ACTION_CREATE) { + createAccount(); + } else { - accManager.addAccountExplicitly(account, mPasswordInput.getText().toString(), null); + updateToken(); } - - /// add the new account as default in preferences, if there is none already - Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this); - if (defaultAccount == null) { - SharedPreferences.Editor editor = PreferenceManager - .getDefaultSharedPreferences(this).edit(); - editor.putString("select_oc_account", accountName); - editor.commit(); - } - - - /// prepare result to return to the Authenticator - // TODO check again what the Authenticator makes with it; probably has the same effect as addAccountExplicitly, but it's not well done - final Intent intent = new Intent(); // TODO check if the intent can be retrieved from getIntent(), passed from AccountAuthenticator - intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, AccountAuthenticator.ACCOUNT_TYPE); - intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name); - if (!isOAuth) - intent.putExtra(AccountManager.KEY_AUTHTOKEN, AccountAuthenticator.ACCOUNT_TYPE); // TODO check this; not sure it's right; maybe - intent.putExtra(AccountManager.KEY_USERDATA, username); - if (isOAuth) { - accManager.setAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, mOAuthAccessToken); - } - /// add user data to the new account; TODO probably can be done in the last parameter addAccountExplicitly, or in KEY_USERDATA - accManager.setUserData(account, AccountAuthenticator.KEY_OC_VERSION, mDiscoveredVersion.toString()); - accManager.setUserData(account, AccountAuthenticator.KEY_OC_BASE_URL, mHostBaseUrl); - if (isOAuth) - accManager.setUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2, "TRUE"); // TODO this flag should be unnecessary - - setAccountAuthenticatorResult(intent.getExtras()); - setResult(RESULT_OK, intent); - /// immediately request for the synchronization of the new account - Bundle bundle = new Bundle(); - bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); - ContentResolver.requestSync(account, AccountAuthenticator.AUTHORITY, bundle); - finish(); - - } else { - if (!isOAuth) { - mUsernameInput.setError(result.getLogMessage() + " "); - // the extra spaces are a workaround for an ugly bug: - // 1. insert wrong credentials and connect - // 2. put the focus on the user name field with using hardware controls (don't touch the screen); the error is shown UNDER the field - // 3. touch the user name field; the software keyboard appears; the error popup is moved OVER the field and SHRINKED in width, losing the last word - // Seen, at least, in Android 2.x devices - } else { - mOAuthAuthEndpointText.setError(result.getLogMessage() + " "); - } + } else { + updateStatusIconAndText(result); + updateAuthStatus(); Log.d(TAG, "Access failed: " + result.getLogMessage()); } } + /** + * Sets the proper response to get that the Account Authenticator that started this activity saves + * a new authorization token for mAccount. + */ + private void updateToken() { + Bundle response = new Bundle(); + response.putString(AccountManager.KEY_ACCOUNT_NAME, mAccount.name); + response.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccount.type); + boolean isOAuth = mOAuth2Check.isChecked(); + if (isOAuth) { + response.putString(AccountManager.KEY_AUTHTOKEN, mOAuthAccessToken); + // the next line is necessary; by now, notifications are calling directly to the AuthenticatorActivity to update, without AccountManager intervention + mAccountMgr.setAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, mOAuthAccessToken); + } else { + response.putString(AccountManager.KEY_AUTHTOKEN, mPasswordInput.getText().toString()); + mAccountMgr.setPassword(mAccount, mPasswordInput.getText().toString()); + } + setAccountAuthenticatorResult(response); + } + + + /** + * Creates a new account through the Account Authenticator that started this activity. + * + * This makes the account permanent. + * + * TODO Decide how to name the OAuth accounts + * TODO Minimize the direct interactions with the account manager; seems that not all the operations + * in the current code are really necessary, provided that right extras are returned to the Account + * Authenticator through setAccountAuthenticatorResult + */ + private void createAccount() { + /// create and save new ownCloud account + boolean isOAuth = mOAuth2Check.isChecked(); + + Uri uri = Uri.parse(mHostBaseUrl); + String username = mUsernameInput.getText().toString().trim(); + if (isOAuth) { + username = "OAuth_user" + (new java.util.Random(System.currentTimeMillis())).nextLong(); // TODO change this to something readable + } + String accountName = username + "@" + uri.getHost(); + if (uri.getPort() >= 0) { + accountName += ":" + uri.getPort(); + } + mAccount = new Account(accountName, AccountAuthenticator.ACCOUNT_TYPE); + if (isOAuth) { + mAccountMgr.addAccountExplicitly(mAccount, "", null); // with our implementation, the password is never input in the app + } else { + mAccountMgr.addAccountExplicitly(mAccount, mPasswordInput.getText().toString(), null); + } + + /// add the new account as default in preferences, if there is none already + Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this); + if (defaultAccount == null) { + SharedPreferences.Editor editor = PreferenceManager + .getDefaultSharedPreferences(this).edit(); + editor.putString("select_oc_account", accountName); + editor.commit(); + } + + /// prepare result to return to the Authenticator + // TODO check again what the Authenticator makes with it; probably has the same effect as addAccountExplicitly, but it's not well done + final Intent intent = new Intent(); + intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, AccountAuthenticator.ACCOUNT_TYPE); + intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, mAccount.name); + if (!isOAuth) + intent.putExtra(AccountManager.KEY_AUTHTOKEN, AccountAuthenticator.ACCOUNT_TYPE); // TODO check this; not sure it's right; maybe + intent.putExtra(AccountManager.KEY_USERDATA, username); + if (isOAuth) { + mAccountMgr.setAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, mOAuthAccessToken); + } + /// add user data to the new account; TODO probably can be done in the last parameter addAccountExplicitly, or in KEY_USERDATA + mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION, mDiscoveredVersion.toString()); + mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL, mHostBaseUrl); + if (isOAuth) + mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_OAUTH2, "TRUE"); // TODO this flag should be unnecessary + setAccountAuthenticatorResult(intent.getExtras()); + setResult(RESULT_OK, intent); + + /// immediately request for the synchronization of the new account + Bundle bundle = new Bundle(); + bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); + ContentResolver.requestSync(mAccount, AccountAuthenticator.AUTHORITY, bundle); + } + + /** * {@inheritDoc} * @@ -963,7 +1035,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity * Updates the content and visibility state of the icon and text associated * to the last check on the ownCloud server. */ - private void updateOcServerCheckIconAndText() { + private void updateConnStatus() { ImageView iv = (ImageView) findViewById(R.id.action_indicator); TextView tv = (TextView) findViewById(R.id.status_text); @@ -977,6 +1049,30 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity tv.setVisibility(View.VISIBLE); } } + + + /** + * Updates the content and visibility state of the icon and text associated + * to the interactions with the OAuth authorization server. + */ + private void updateAuthStatus() { + /*ImageView iv = (ImageView) findViewById(R.id.auth_status_icon); + TextView tv = (TextView) findViewById(R.id.auth_status_text);*/ + + if (mStatusIcon == 0 && mStatusText == 0) { + mAuthStatusLayout.setVisibility(View.INVISIBLE); + /*iv.setVisibility(View.INVISIBLE); + tv.setVisibility(View.INVISIBLE);*/ + } else { + mAuthStatusLayout.setText(mStatusText); + mAuthStatusLayout.setCompoundDrawablesWithIntrinsicBounds(mStatusIcon, 0, 0, 0); + /*iv.setImageResource(mStatusIcon); + tv.setText(mStatusText); + /*iv.setVisibility(View.VISIBLE); + tv.setVisibility(View.VISIBLE);^*/ + mAuthStatusLayout.setVisibility(View.VISIBLE); + } + } /** @@ -1035,51 +1131,22 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity */ public void changeViewByOAuth2Check(Boolean checked) { - ImageView auth2ActionIndicator = (ImageView) findViewById(R.id.auth2_action_indicator); - TextView oauth2StatusText = (TextView) findViewById(R.id.oauth2_status_text); - if (checked) { mOAuthAuthEndpointText.setVisibility(View.VISIBLE); mOAuthTokenEndpointText.setVisibility(View.VISIBLE); mUsernameInput.setVisibility(View.GONE); mPasswordInput.setVisibility(View.GONE); mViewPasswordButton.setVisibility(View.GONE); - auth2ActionIndicator.setVisibility(View.INVISIBLE); - oauth2StatusText.setVisibility(View.INVISIBLE); } else { mOAuthAuthEndpointText.setVisibility(View.GONE); mOAuthTokenEndpointText.setVisibility(View.GONE); mUsernameInput.setVisibility(View.VISIBLE); mPasswordInput.setVisibility(View.VISIBLE); mViewPasswordButton.setVisibility(View.INVISIBLE); - auth2ActionIndicator.setVisibility(View.GONE); - oauth2StatusText.setVisibility(View.GONE); } } - /** - * Updates the content and visibility state of the icon and text associated - * to the interactions with the OAuth authorization server. - * - * @param drawable_id Resource id for the icon. - * @param text_id Resource id for the text. - */ - private void updateOAuth2IconAndText(int drawable_id, int text_id) { - ImageView iv = (ImageView) findViewById(R.id.auth2_action_indicator); - TextView tv = (TextView) findViewById(R.id.oauth2_status_text); - - if (drawable_id == 0 && text_id == 0) { - iv.setVisibility(View.INVISIBLE); - tv.setVisibility(View.INVISIBLE); - } else { - iv.setImageResource(drawable_id); - tv.setText(text_id); - iv.setVisibility(View.VISIBLE); - tv.setVisibility(View.VISIBLE); - } - } - /* Leave the old OAuth flow // Results from the first call to oAuth2 server : getting the user_code and verification_url. @Override