diff --git a/src/main/java/com/nextcloud/android/sso/api/NextcloudAPI.java b/src/main/java/com/nextcloud/android/sso/api/NextcloudAPI.java index 03d63c16..bd93d194 100644 --- a/src/main/java/com/nextcloud/android/sso/api/NextcloudAPI.java +++ b/src/main/java/com/nextcloud/android/sso/api/NextcloudAPI.java @@ -25,6 +25,7 @@ import android.content.ServiceConnection; import android.os.IBinder; import android.os.Looper; +import android.os.NetworkOnMainThreadException; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Log; @@ -34,6 +35,7 @@ import com.nextcloud.android.sso.aidl.IThreadListener; import com.nextcloud.android.sso.aidl.NextcloudRequest; import com.nextcloud.android.sso.aidl.ParcelFileDescriptorUtil; +import com.nextcloud.android.sso.exceptions.NextcloudApiNotRespondingException; import com.nextcloud.android.sso.helper.ExponentialBackoff; import com.nextcloud.android.sso.model.SingleSignOnAccount; @@ -49,6 +51,7 @@ import java.io.ObjectOutputStream; import java.io.Reader; import java.lang.reflect.Type; +import java.util.concurrent.atomic.AtomicBoolean; import io.reactivex.Observable; import io.reactivex.annotations.NonNull; @@ -57,9 +60,20 @@ public class NextcloudAPI { + private static final String TAG = NextcloudAPI.class.getCanonicalName(); + + private Gson gson; + private IInputStreamService mService = null; + private final AtomicBoolean mBound = new AtomicBoolean(false); // Flag indicating whether we have called bind on the service + private boolean mDestroyed = false; // Flag indicating if API is destroyed + private SingleSignOnAccount mAccount; + private ApiConnectedListener mCallback; + private Context mContext; + + + public interface ApiConnectedListener { void onConnected(); - void onError(Exception ex); } @@ -72,17 +86,6 @@ public NextcloudAPI(Context context, SingleSignOnAccount account, Gson gson, Api connectApiWithBackoff(); } - private static final String TAG = NextcloudAPI.class.getCanonicalName(); - - private Gson gson; - private IInputStreamService mService = null; - private boolean mBound = false; // Flag indicating whether we have called bind on the service - private boolean mDestroyed = false; // Flag indicating if API is destroyed - private SingleSignOnAccount mAccount; - private ApiConnectedListener mCallback; - private Context mContext; - - private String getAccountName() { return mAccount.name; } @@ -106,7 +109,7 @@ private void connect() { } // Disconnect if connected - if (mBound) { + if (mBound.get()) { stop(); } @@ -132,13 +135,13 @@ public void stop() { mCallback = null; // Unbind from the service - if (mBound) { + if (mBound.get()) { if (mContext != null) { mContext.unbindService(mConnection); } else { Log.e(TAG, "Context was null, cannot unbind nextcloud single sign-on service connection!"); } - mBound = false; + mBound.set(false); mContext = null; } } @@ -152,7 +155,10 @@ public void onServiceConnected(ComponentName className, IBinder service) { Log.i(TAG, "Nextcloud Single sign-on: onServiceConnected"); mService = IInputStreamService.Stub.asInterface(service); - mBound = true; + mBound.set(true); + synchronized (mBound) { + mBound.notifyAll(); + } mCallback.onConnected(); } @@ -161,7 +167,7 @@ public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. mService = null; - mBound = false; + mBound.set(false); if (!mDestroyed) { connectApiWithBackoff(); @@ -169,6 +175,24 @@ public void onServiceDisconnected(ComponentName className) { } }; + private void waitForApi() throws NextcloudApiNotRespondingException { + synchronized (mBound) { + // If service is not bound yet.. wait + if(!mBound.get()) { + Log.v(TAG, "[waitForApi] - api not ready yet.. waiting [" + Thread.currentThread().getName() + "]"); + try { + mBound.wait(10000); // wait up to 10 seconds + + // If api is still not bound after 10 seconds.. throw an exception + if(!mBound.get()) { + throw new NextcloudApiNotRespondingException(); + } + } catch (InterruptedException ex) { + Log.e(TAG, "WaitForAPI failed", ex); + } + } + } + } public Observable performRequestObservable(final Type type, final NextcloudRequest request) { return Observable.fromPublisher(new Publisher() { @@ -249,7 +273,16 @@ public InputStream performNetworkRequest(NextcloudRequest request) throws Except * @throws IOException */ private ParcelFileDescriptor performAidlNetworkRequest(NextcloudRequest request) - throws IOException, RemoteException { + throws IOException, RemoteException, NextcloudApiNotRespondingException { + + // Check if we are on the main thread + if(Looper.myLooper() == Looper.getMainLooper()) { + throw new NetworkOnMainThreadException(); + } + + // Wait for api to be initialized + waitForApi(); + // Log.d(TAG, request.url); request.setAccountName(getAccountName()); request.setToken(getAccountToken()); diff --git a/src/main/java/com/nextcloud/android/sso/exceptions/NextcloudApiNotRespondingException.java b/src/main/java/com/nextcloud/android/sso/exceptions/NextcloudApiNotRespondingException.java new file mode 100644 index 00000000..067def1b --- /dev/null +++ b/src/main/java/com/nextcloud/android/sso/exceptions/NextcloudApiNotRespondingException.java @@ -0,0 +1,18 @@ +package com.nextcloud.android.sso.exceptions; + +import android.content.Context; + +import com.nextcloud.android.sso.R; +import com.nextcloud.android.sso.model.ExceptionMessage; + +public class NextcloudApiNotRespondingException extends SSOException { + + @Override + public void loadExceptionMessage(Context context) { + this.em = new ExceptionMessage( + context.getString(R.string.nextcloud_files_api_not_responsing_title), + context.getString(R.string.nextcloud_files_api_not_responsing_message) + ); + } + +} diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index e75f6b4a..561df5cd 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -30,6 +30,10 @@ Error Your nextcloud files app currently does not support the single sign on feature. Please update it: %1$s + + Error + Nextcloud files app api is not responding. Please report this issue. + Something went wrong.. please try again