X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/63106c92382d2c6e4ef374df6afaf76bbac76c96..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 6500ce5e..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; @@ -61,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; @@ -83,6 +82,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity 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"; @@ -97,7 +97,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity public static final byte ACTION_CREATE = 0; public static final byte ACTION_UPDATE_TOKEN = 1; - + private String mHostBaseUrl; private OwnCloudVersion mDiscoveredVersion; @@ -119,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; @@ -171,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 @@ -181,26 +186,28 @@ 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 (getIntent().getByteExtra(EXTRA_ACTION, ACTION_CREATE) == ACTION_UPDATE_TOKEN) { + if (mAction == ACTION_UPDATE_TOKEN) { /// lock things that should not change mHostUrlInput.setEnabled(false); mUsernameInput.setEnabled(false); @@ -209,6 +216,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity } mPasswordInput.setText(""); // clean password to avoid social hacking (disadvantage: password in removed if the device is turned aside) + mJustCreated = true; } @@ -235,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); @@ -275,6 +287,9 @@ 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); @@ -318,8 +333,15 @@ 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()); - // the state of mOAuth2Check is automatically recovered between configuration changes, but not before onCreate() finishes + 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. @@ -332,6 +354,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity if (mNewCapturedUriFromOAuth2Redirection != null) { getOAuth2AccessTokenFromCapturedRedirection(); } + + mJustCreated = false; } @@ -358,46 +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. -- TODO REMOVE, UNNECESSARY - /* - mStatusIcon = R.drawable.ic_ok; - mStatusText = R.string.auth_connection_established; - updateAuthStatus(); - */ /// 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); } @@ -737,7 +729,11 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity break; case OAUTH2_ERROR: mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_bad_oauth_token; + 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: @@ -779,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()); } } @@ -803,79 +797,19 @@ 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); - } - - /// 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(); + updateToken(); } - - - /// 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()); @@ -883,7 +817,93 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity } + /** + * 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} *