Skip to content

Commit

Permalink
[RFR-772] Ignore sync errors while in background (#288)
Browse files Browse the repository at this point in the history
* [RFR-772] Ignore sync errors while in background

* Fix UI test
  • Loading branch information
hb0 authored Sep 25, 2023
1 parent b37afa7 commit 5889c41
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ import java.net.URL
*
* @author Klemens Muthmann
* @author Armin Schnabel
* @version 1.0.0
* @version 1.0.1
* @since 7.7.0
*/
@RunWith(AndroidJUnit4::class)
Expand All @@ -92,7 +92,7 @@ class SyncPerformerTest {
persistence = DefaultPersistenceLayer(context, DefaultPersistenceBehaviour())
SharedTestUtils.clearPersistenceLayer(context, persistence)

oocut = SyncPerformer(context)
oocut = SyncPerformer(context, true)
}

@After
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import kotlinx.coroutines.runBlocking
*
* @author Klemens Muthmann
* @author Armin Schnabel
* @version 5.1.0
* @version 5.1.1
* @since 2.0.0
*/
class CyfaceAuthenticator(private val context: Context) :
Expand Down Expand Up @@ -112,7 +112,8 @@ class CyfaceAuthenticator(private val context: Context) :
ErrorHandler.sendErrorIntent(
context,
ErrorHandler.ErrorCode.UNKNOWN.code,
e.message
e.message,
false // login currently only happens while the user is active
)
throw NetworkErrorException(e)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2022 Cyface GmbH
* Copyright 2018-2023 Cyface GmbH
*
* This file is part of the Cyface SDK for Android.
*
Expand Down Expand Up @@ -41,13 +41,14 @@
* support time for all involved.
*
* @author Armin Schnabel
* @version 2.1.0
* @version 2.2.0
* @since 2.2.0
*/
public class ErrorHandler extends BroadcastReceiver {

public final static String ERROR_INTENT = "de.cyface.error";
public final static String ERROR_CODE_EXTRA = "de.cyface.error.error_code";
public final static String ERROR_BACKGROUND_EXTRA = "de.cyface.error.from_background";
public final static String HTTP_CODE_EXTRA = "de.cyface.error.http_code";
private final Collection<ErrorListener> errorListeners;

Expand Down Expand Up @@ -95,11 +96,15 @@ public static void sendErrorIntent(final Context context, final int errorCode, f
*
* @param context the {@link Context}
* @param errorCode the Cyface error code
* @param message A message which can be shown to the user, e.g. as toast.
* @param fromBackground `true` if the error was caused without user interaction, e.g. to avoid
* disturbing the user while he is not using the app.
*/
public static void sendErrorIntent(final Context context, final int errorCode, @Nullable final String message) {
public static void sendErrorIntent(final Context context, final int errorCode, @Nullable final String message, final boolean fromBackground) {

final Intent intent = new Intent(ERROR_INTENT);
intent.putExtra(ERROR_CODE_EXTRA, errorCode);
intent.putExtra(ERROR_BACKGROUND_EXTRA, fromBackground);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
if (message != null) {
Log.d(TAG, message);
Expand All @@ -111,6 +116,7 @@ public void onReceive(final Context context, final Intent intent) {

Validate.notNull(intent.getExtras());
final int errorCodeInt = intent.getExtras().getInt(ERROR_CODE_EXTRA);
final var fromBackground = intent.getExtras().getBoolean(ERROR_BACKGROUND_EXTRA);
final ErrorCode errorCode = ErrorCode.getValueForCode(errorCodeInt);
Validate.notNull(errorCode);
String errorMessage;
Expand Down Expand Up @@ -220,7 +226,7 @@ public void onReceive(final Context context, final Intent intent) {
}

for (final ErrorListener errorListener : errorListeners) {
errorListener.onErrorReceive(errorCode, errorMessage);
errorListener.onErrorReceive(errorCode, errorMessage, fromBackground);
}
}

Expand Down Expand Up @@ -274,10 +280,15 @@ public static ErrorCode getValueForCode(final int code) {
* @since 1.0.0
*/
public interface ErrorListener {
// These enhanced error details will be (re)implemented with #CY-3709
// @ param causeId Optional id of the cause object for the error, e.g. measurementId
// @ param causeExtra Optional, additional information such as the date of a broken measurement
void onErrorReceive(final ErrorCode errorCode, final String errorMessage);
/**
* Handler called upon new errors.
*
* @param errorCode the Cyface error code
* @param errorMessage A message which can be shown to the user, e.g. as toast.
* @param fromBackground `true` if the error was caused without user interaction, e.g. to avoid
* disturbing the user while he is not using the app.
*/
void onErrorReceive(final ErrorCode errorCode, final String errorMessage, final boolean fromBackground);
}

// The following error handling will be (re)implemented with #CY-3709
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import android.accounts.NetworkErrorException
import android.content.AbstractThreadedSyncAdapter
import android.content.ContentProviderClient
import android.content.ContentResolver
import android.content.ContentResolver.SYNC_EXTRAS_MANUAL
import android.content.Context
import android.content.SyncResult
import android.content.pm.PackageManager
Expand Down Expand Up @@ -56,7 +57,7 @@ import java.io.File
*
* @author Armin Schnabel
* @author Klemens Muthmann
* @version 4.1.0
* @version 4.1.1
* @since 2.0.0
* @property authenticator The authenticator to use for synchronization.
* @property uploader The uploader to use for synchronization.
Expand Down Expand Up @@ -122,7 +123,10 @@ class SyncAdapter private constructor(
context,
DefaultPersistenceBehaviour()
)
val syncPerformer = SyncPerformer(context)
// Ensure sync errors are shown to the user when triggering sync manually
val fromBackground = !extras.getBoolean(SYNC_EXTRAS_MANUAL)
val syncPerformer = SyncPerformer(context, fromBackground)


// Ensure user is authorized before starting synchronization
authenticator.performActionWithFreshTokens { _, _, ex ->
Expand All @@ -132,7 +136,8 @@ class SyncAdapter private constructor(
ErrorHandler.sendErrorIntent(
context,
ErrorCode.AUTHENTICATION_ERROR.code,
ex.message
ex.message,
fromBackground
)
} else {
try {
Expand Down Expand Up @@ -211,7 +216,8 @@ class SyncAdapter private constructor(
ErrorHandler.sendErrorIntent(
context,
ErrorCode.AUTHENTICATION_ERROR.code,
e.message
e.message,
fromBackground
)
} else {
val result = syncPerformer.sendData(
Expand Down Expand Up @@ -272,22 +278,29 @@ class SyncAdapter private constructor(
} catch (e: CursorIsNullException) {
Log.w(TAG, e.javaClass.simpleName + ": " + e.message)
syncResult.databaseError = true
ErrorHandler.sendErrorIntent(context, ErrorCode.DATABASE_ERROR.code, e.message)
ErrorHandler.sendErrorIntent(
context,
ErrorCode.DATABASE_ERROR.code,
e.message,
fromBackground
)
} catch (e: AuthenticatorException) {
Log.w(TAG, e.javaClass.simpleName + ": " + e.message)
syncResult.stats.numAuthExceptions++
ErrorHandler.sendErrorIntent(
context,
ErrorCode.AUTHENTICATION_ERROR.code,
e.message
e.message,
fromBackground
)
} catch (e: SynchronizationInterruptedException) {
Log.w(TAG, e.javaClass.simpleName + ": " + e.message)
syncResult.stats.numIoExceptions++
ErrorHandler.sendErrorIntent(
context,
ErrorCode.SYNCHRONIZATION_INTERRUPTED.code,
e.message
e.message,
fromBackground
)
} catch (e: NetworkErrorException) {
Log.w(TAG, e.javaClass.simpleName + ": " + e.message)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,13 @@ import java.net.MalformedURLException
*
* @author Klemens Muthmann
* @author Armin Schnabel
* @version 7.0.0
* @version 8.0.0
* @since 2.0.0
* @property context The Android `Context` to use for setting the correct server certification information.
* @property fromBackground `true` if the error was caused without user interaction, e.g. to avoid
* disturbing the user while he is not using the app.
*/
internal class SyncPerformer(private val context: Context) {
internal class SyncPerformer(private val context: Context, private val fromBackground: Boolean) {
/**
* Triggers the data transmission to a Cyface server API. The `measurementIdentifier` and
* `deviceIdentifier` need to be globally unique. If they are not the server will probably reject the
Expand Down Expand Up @@ -135,7 +137,8 @@ internal class SyncPerformer(private val context: Context) {
ErrorHandler.sendErrorIntent(
context,
ErrorCode.SERVER_UNAVAILABLE.code,
e.message
e.message,
fromBackground
)
Result.UPLOAD_FAILED
}
Expand All @@ -145,7 +148,8 @@ internal class SyncPerformer(private val context: Context) {
ErrorHandler.sendErrorIntent(
context,
ErrorCode.FORBIDDEN.code,
e.message
e.message,
fromBackground
)
Result.UPLOAD_FAILED
}
Expand All @@ -155,7 +159,8 @@ internal class SyncPerformer(private val context: Context) {
ErrorHandler.sendErrorIntent(
context,
ErrorCode.MALFORMED_URL.code,
e.message
e.message,
fromBackground
)
Result.UPLOAD_FAILED
}
Expand All @@ -165,7 +170,8 @@ internal class SyncPerformer(private val context: Context) {
ErrorHandler.sendErrorIntent(
context,
ErrorCode.SYNCHRONIZATION_ERROR.code,
e.message
e.message,
fromBackground
)
Result.UPLOAD_FAILED
}
Expand All @@ -175,7 +181,8 @@ internal class SyncPerformer(private val context: Context) {
ErrorHandler.sendErrorIntent(
context,
ErrorCode.UNAUTHORIZED.code,
e.message
e.message,
fromBackground
)
Result.UPLOAD_FAILED
}
Expand All @@ -185,7 +192,8 @@ internal class SyncPerformer(private val context: Context) {
ErrorHandler.sendErrorIntent(
context,
ErrorCode.INTERNAL_SERVER_ERROR.code,
e.message
e.message,
fromBackground
)
Result.UPLOAD_FAILED
}
Expand All @@ -195,7 +203,8 @@ internal class SyncPerformer(private val context: Context) {
ErrorHandler.sendErrorIntent(
context,
ErrorCode.ENTITY_NOT_PARSABLE.code,
e.message
e.message,
fromBackground
)
Result.UPLOAD_FAILED
}
Expand All @@ -205,7 +214,8 @@ internal class SyncPerformer(private val context: Context) {
ErrorHandler.sendErrorIntent(
context,
ErrorCode.BAD_REQUEST.code,
e.message
e.message,
fromBackground
)
Result.UPLOAD_FAILED
}
Expand All @@ -215,7 +225,8 @@ internal class SyncPerformer(private val context: Context) {
ErrorHandler.sendErrorIntent(
context,
ErrorCode.NETWORK_UNAVAILABLE.code,
e.message
e.message,
fromBackground
)
Result.UPLOAD_FAILED
}
Expand All @@ -225,7 +236,8 @@ internal class SyncPerformer(private val context: Context) {
ErrorHandler.sendErrorIntent(
context,
ErrorCode.SYNCHRONIZATION_INTERRUPTED.code,
e.message
e.message,
fromBackground
)
e.printStackTrace()
Result.UPLOAD_FAILED
Expand All @@ -236,7 +248,8 @@ internal class SyncPerformer(private val context: Context) {
ErrorHandler.sendErrorIntent(
context,
ErrorCode.TOO_MANY_REQUESTS.code,
e.message
e.message,
fromBackground
)
Result.UPLOAD_FAILED
}
Expand All @@ -246,7 +259,8 @@ internal class SyncPerformer(private val context: Context) {
ErrorHandler.sendErrorIntent(
context,
ErrorCode.UPLOAD_SESSION_EXPIRED.code,
e.message
e.message,
fromBackground
)
Result.UPLOAD_FAILED
}
Expand All @@ -256,7 +270,8 @@ internal class SyncPerformer(private val context: Context) {
ErrorHandler.sendErrorIntent(
context,
ErrorCode.UNEXPECTED_RESPONSE_CODE.code,
e.message
e.message,
fromBackground
)
Result.UPLOAD_FAILED
}
Expand All @@ -266,7 +281,8 @@ internal class SyncPerformer(private val context: Context) {
ErrorHandler.sendErrorIntent(
context,
ErrorCode.ACCOUNT_NOT_ACTIVATED.code,
e.message
e.message,
fromBackground
)
Result.UPLOAD_FAILED
}
Expand Down

0 comments on commit 5889c41

Please sign in to comment.