import android.text.Editable;\r
import android.text.InputType;\r
import android.text.TextWatcher;\r
+import android.util.Log;\r
import android.view.KeyEvent;\r
import android.view.MotionEvent;\r
import android.view.View;\r
private static final String KEY_AUTH_STATUS_ICON = "AUTH_STATUS_ICON";\r
private static final String KEY_REFRESH_BUTTON_ENABLED = "KEY_REFRESH_BUTTON_ENABLED";\r
//private static final String KEY_IS_SHARED_SUPPORTED = "KEY_IS_SHARE_SUPPORTED";\r
+ private static final String KEY_SERVER_AUTH_METHOD = "KEY_SERVER_AUTH_METHOD";\r
+ private static final String KEY_DETECT_AUTH_OP_ID = "KEY_DETECT_AUTH_OP_ID";\r
+\r
\r
private static final String AUTH_ON = "on";\r
private static final String AUTH_OFF = "off";\r
private String mAuthMessageText;\r
private int mAuthMessageVisibility, mServerStatusText, mServerStatusIcon;\r
private boolean mServerIsChecked, mServerIsValid, mIsSslConn;\r
+ private AuthenticationMethod mServerAuthMethod = AuthenticationMethod.UNKNOWN;\r
+ private int mDetectAuthOpId = -1;\r
+\r
private int mAuthStatusText, mAuthStatusIcon; \r
private TextView mAuthStatusLayout;\r
\r
- private ServiceConnection mOperationsConnection = null;\r
- private OperationsServiceBinder mOperationsBinder = null;\r
- \r
private final Handler mHandler = new Handler();\r
private Thread mOperationThread;\r
private GetRemoteStatusOperation mOcServerChkOperation;\r
\r
private OperationsServiceBinder mOperationsServiceBinder = null;\r
\r
-\r
/**\r
* {@inheritDoc}\r
* \r
getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
\r
// bind to Operations Service\r
- mOperationsConnection = new ServiceConnection() {\r
-\r
- @Override\r
- public void onServiceConnected(ComponentName name, IBinder service) {\r
- Log_OC.d(TAG, "Operations service connected");\r
- mOperationsBinder = (OperationsServiceBinder) service;\r
- }\r
-\r
- @Override\r
- public void onServiceDisconnected(ComponentName name) {\r
- Log_OC.d(TAG, "Operations service crashed");\r
- mOperationsBinder = null;\r
- }\r
- \r
- };\r
+ mOperationsServiceConnection = new OperationsServiceConnection();\r
if (!bindService(new Intent(this, OperationsService.class), \r
- mOperationsConnection, \r
- Context.BIND_AUTO_CREATE)) {\r
+ mOperationsServiceConnection, \r
+ Context.BIND_AUTO_CREATE)) {\r
Toast.makeText(this, \r
R.string.error_cant_bind_to_operations_service, \r
Toast.LENGTH_LONG)\r
.show();\r
finish();\r
}\r
-\r
+ \r
/// set view and get references to view elements\r
setContentView(R.layout.account_setup);\r
mAuthMessage = (TextView) findViewById(R.id.auth_message);\r
refreshButtonEnabled = savedInstanceState.getBoolean(KEY_REFRESH_BUTTON_ENABLED);\r
\r
\r
+ mServerAuthMethod = AuthenticationMethod.valueOf(\r
+ savedInstanceState.getString(KEY_SERVER_AUTH_METHOD));\r
+ mDetectAuthOpId = savedInstanceState.getInt(KEY_DETECT_AUTH_OP_ID);\r
+\r
}\r
\r
if (mAuthMessageVisibility== View.VISIBLE) {\r
}\r
});\r
\r
- mOperationsServiceConnection = new OperationsServiceConnection();\r
- bindService(new Intent(this, OperationsService.class), mOperationsServiceConnection, Context.BIND_AUTO_CREATE);\r
}\r
\r
\r
*/\r
@Override\r
protected void onSaveInstanceState(Bundle outState) {\r
+ //Log.wtf(TAG, "onSaveInstanceState init" );\r
super.onSaveInstanceState(outState);\r
\r
/// connection state and info\r
\r
// refresh button enabled\r
outState.putBoolean(KEY_REFRESH_BUTTON_ENABLED, (mRefreshButton.getVisibility() == View.VISIBLE));\r
-\r
+ \r
+ outState.putString(KEY_SERVER_AUTH_METHOD, mServerAuthMethod.name());\r
+ outState.putInt(KEY_DETECT_AUTH_OP_ID, mDetectAuthOpId);\r
+ //Log.wtf(TAG, "onSaveInstanceState end" );\r
}\r
\r
\r
}\r
\r
\r
- @Override \r
- protected void onStart() {\r
- if (mOperationsServiceBinder != null) {\r
- mOperationsServiceBinder.addOperationListener(AuthenticatorActivity.this, mHandler);\r
- }\r
- \r
- super.onStart();\r
- }\r
- \r
- \r
- @Override \r
- protected void onStop() {\r
- if (mOperationsServiceBinder != null) {\r
- mOperationsServiceBinder.removeOperationListener(this);\r
- }\r
- super.onStop();\r
- }\r
- \r
-\r
-\r
/**\r
* The redirection triggered by the OAuth authentication server as response to the GET AUTHORIZATION, and \r
* deferred in {@link #onNewIntent(Intent)}, is processed here.\r
*/\r
@Override\r
protected void onResume() {\r
+ //Log.wtf(TAG, "onResume init" );\r
super.onResume();\r
+ \r
if (mAction == ACTION_UPDATE_TOKEN && mJustCreated && getIntent().getBooleanExtra(EXTRA_ENFORCED_UPDATE, false)) {\r
if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(mAuthTokenType)) {\r
//Toast.makeText(this, R.string.auth_expired_oauth_token_toast, Toast.LENGTH_LONG).show();\r
if (mNewCapturedUriFromOAuth2Redirection != null) {\r
getOAuth2AccessTokenFromCapturedRedirection(); \r
}\r
-\r
+ \r
mJustCreated = false;\r
\r
+ if (mOperationsServiceBinder != null) {\r
+ doOnResumeAndBound();\r
+ }\r
+ \r
+ //Log.wtf(TAG, "onResume end" );\r
}\r
+\r
\r
+ @Override\r
+ protected void onPause() {\r
+ //Log.wtf(TAG, "onPause init" );\r
+ if (mOperationsServiceBinder != null) {\r
+ //Log.wtf(TAG, "unregistering to listen for operation callbacks" );\r
+ mOperationsServiceBinder.removeOperationListener(this);\r
+ }\r
+ super.onPause();\r
+ //Log.wtf(TAG, "onPause end" );\r
+ }\r
\r
@Override\r
protected void onDestroy() {\r
- if (mOperationsConnection != null) {\r
- unbindService(mOperationsConnection);\r
- mOperationsBinder = null;\r
+ if (mOperationsServiceConnection != null) {\r
+ unbindService(mOperationsServiceConnection);\r
+ mOperationsServiceBinder = null;\r
}\r
super.onDestroy();\r
}\r
onGetUserNameFinish((GetRemoteUserNameOperation) operation, result);\r
\r
} else if (operation instanceof DetectAuthenticationMethodOperation) {\r
- onDetectAutheticationFinish((DetectAuthenticationMethodOperation) operation, result);\r
+ Log.wtf(TAG, "received detection response through callback" );\r
+ onDetectAuthenticationFinish(result);\r
}\r
\r
}\r
\r
- private void onDetectAutheticationFinish(DetectAuthenticationMethodOperation operation, RemoteOperationResult result) {\r
+ private void onDetectAuthenticationFinish(RemoteOperationResult result) {\r
// Read authentication method\r
+ mDetectAuthOpId = -1;\r
if (result.getData().size() > 0) {\r
AuthenticationMethod authMethod = (AuthenticationMethod) result.getData().get(0);\r
String basic = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, mAuthTokenType);\r
\r
/// test credentials \r
- Intent service = new Intent(this, OperationsService.class); \r
- service.setAction(OperationsService.ACTION_DETECT_AUTHENTICATION_METHOD);\r
- service.putExtra(OperationsService.EXTRA_SERVER_URL, mHostBaseUrl);\r
- service.putExtra(OperationsService.EXTRA_WEBDAV_PATH, webdav_path);\r
- startService(service);\r
+ //Intent detectAuthIntent = new Intent(this, OperationsService.class);\r
+ Intent detectAuthIntent = new Intent();\r
+ detectAuthIntent.setAction(OperationsService.ACTION_DETECT_AUTHENTICATION_METHOD);\r
+ detectAuthIntent.putExtra(OperationsService.EXTRA_SERVER_URL, mHostBaseUrl);\r
+ detectAuthIntent.putExtra(OperationsService.EXTRA_WEBDAV_PATH, webdav_path);\r
+ \r
+ //if (mOperationsBinder != null) { // let's let it crash to detect if is really possible\r
+ mServerAuthMethod = AuthenticationMethod.UNKNOWN;\r
+ if (mOperationsServiceBinder != null) {\r
+ //Log.wtf(TAG, "starting detection..." );\r
+ mDetectAuthOpId = mOperationsServiceBinder.newOperation(detectAuthIntent);\r
+ }\r
+ //}\r
}\r
\r
\r
}\r
\r
}\r
-\r
+ \r
+ \r
+ private void doOnResumeAndBound() {\r
+ //Log.wtf(TAG, "registering to listen for operation callbacks" );\r
+ mOperationsServiceBinder.addOperationListener(AuthenticatorActivity.this, mHandler);\r
+ \r
+ if (mDetectAuthOpId != -1) {\r
+ RemoteOperationResult result = \r
+ mOperationsServiceBinder.getOperationResultIfFinished(mDetectAuthOpId);\r
+ if (result != null) {\r
+ //Log.wtf(TAG, "found result of operation finished while rotating");\r
+ onDetectAuthenticationFinish(result);\r
+ }\r
+ }\r
+ }\r
+ \r
/** \r
- * Implements callback methods for service binding. Passed as a parameter to { \r
+ * Implements callback methods for service binding. \r
*/\r
private class OperationsServiceConnection implements ServiceConnection {\r
\r
@Override\r
public void onServiceConnected(ComponentName component, IBinder service) {\r
if (component.equals(new ComponentName(AuthenticatorActivity.this, OperationsService.class))) {\r
- Log_OC.d(TAG, "Operations service connected");\r
+ //Log_OC.wtf(TAG, "Operations service connected");\r
mOperationsServiceBinder = (OperationsServiceBinder) service;\r
- mOperationsServiceBinder.addOperationListener(AuthenticatorActivity.this, mHandler);\r
+ \r
+ doOnResumeAndBound();\r
+ \r
} else {\r
return;\r
}\r
@Override\r
public void onServiceDisconnected(ComponentName component) {\r
if (component.equals(new ComponentName(AuthenticatorActivity.this, OperationsService.class))) {\r
- Log_OC.d(TAG, "Operations service disconnected");\r
+ Log_OC.e(TAG, "Operations service crashed");\r
mOperationsServiceBinder = null;\r
- // TODO whatever could be waiting for the service is unbound\r
}\r
}\r
\r
}\r
+ \r
}\r
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.datamodel.FileDataStorageManager;
import com.owncloud.android.lib.common.OwnCloudClientFactory;
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<Pair<Target, RemoteOperation>> mPendingOperations = new ConcurrentLinkedQueue<Pair<Target, RemoteOperation>>();
+ private ConcurrentLinkedQueue<Pair<Target, RemoteOperation>> mPendingOperations =
+ new ConcurrentLinkedQueue<Pair<Target, RemoteOperation>>();
+
+ private ConcurrentMap<Integer, RemoteOperationResult> mOperationResults =
+ new ConcurrentHashMap<Integer, RemoteOperationResult>();
private static class Target {
public Uri mServerUrl = null;
mBinder = new OperationsServiceBinder();
}
+
/**
* Entry point to add a new operation to the queue of operations.
*
*/
@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 if (action.equals(ACTION_DETECT_AUTHENTICATION_METHOD)) { // Detect Authentication Method
- String webdav_url = serverUrl + intent.getStringExtra(EXTRA_WEBDAV_PATH);
- operation = new DetectAuthenticationMethodOperation(this.getApplicationContext(), webdav_url);
-
- } else {
- // nothing we are going to handle
- return START_NOT_STICKY;
- }
-
- mPendingOperations.add(new Pair<Target , RemoteOperation>(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;
}
*/
@Override
public IBinder onBind(Intent intent) {
+ //Log.wtf(TAG, "onBind" );
return mBinder;
}
*/
@Override
public boolean onUnbind(Intent intent) {
- //((OperationsServiceBinder)mBinder).clearListeners();
+ ((OperationsServiceBinder)mBinder).clearListeners();
return false; // not accepting rebinding (default behaviour)
}
/**
* Map of listeners that will be reported about the end of operations from a {@link OperationsServiceBinder} instance
*/
- private Map<OnRemoteOperationListener, Handler> mBoundListeners = new HashMap<OnRemoteOperationListener, Handler>();
+ private ConcurrentMap<OnRemoteOperationListener, Handler> mBoundListeners =
+ new ConcurrentHashMap<OnRemoteOperationListener, Handler>();
/**
* Cancels an operation
* @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);
+ }
}
* @param listener Object to notify about progress of transfer.
*/
public void removeOperationListener (OnRemoteOperationListener listener) {
- mBoundListeners.remove(listener);
+ synchronized (mBoundListeners) {
+ mBoundListeners.remove(listener);
+ }
}
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);
+ target = new Target(
+ account,
+ (serverUrl == null) ? null : Uri.parse(serverUrl)
+ );
+
+ 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_DETECT_AUTHENTICATION_METHOD)) {
+ // Detect Authentication Method
+ String webdav_url =
+ serverUrl + operationIntent.getStringExtra(EXTRA_WEBDAV_PATH);
+ operation = new DetectAuthenticationMethodOperation(
+ OperationsService.this,
+ webdav_url);
+ }
+ }
+
+ } catch (IllegalArgumentException e) {
+ Log_OC.e(TAG, "Bad information provided in intent: " + e.getMessage());
+ operation = null;
+ }
+
+ if (operation != null) {
+ mPendingOperations.add(new Pair<Target , RemoteOperation>(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);
+ }
+
}
*/
private void nextOperation() {
+ //Log.wtf(TAG, "nextOperation init" );
+
Pair<Target, RemoteOperation> next = null;
synchronized(mPendingOperations) {
next = mPendingOperations.peek();
} finally {
synchronized(mPendingOperations) {
mPendingOperations.poll();
+ mOperationResults.put(mCurrentOperation.hashCode(), result);
}
}
* @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<OnRemoteOperationListener> listeners = mBinder.mBoundListeners.keySet().iterator();
while (listeners.hasNext()) {
final OnRemoteOperationListener listener = listeners.next();
listener.onRemoteOperationFinish(operation, result);
}
});
+ count += 1;
}
}
-
+ Log_OC.d(TAG, "Called " + count + " listeners");
}