GithubHelp home page GithubHelp logo

relaycorp / awala-ping-android Goto Github PK

View Code? Open in Web Editor NEW
0.0 2.0 0.0 1.11 MB

Android app for the Awala Ping Service

License: GNU General Public License v3.0

Kotlin 100.00%
android awala awala-service-ping

awala-ping-android's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar filmaluco avatar gnarea avatar lilianafaustinodev avatar sdsantos avatar

Watchers

 avatar  avatar

awala-ping-android's Issues

Set up development environment

  • Configure Gradle (the latest stable version).
  • Configure linter.
  • Configure build automation / Maven.
  • Configure test runner.
  • Set up continuous integration
  • Etc.

Set up AWS Device Farm

  • Configure with Terraform.
  • Test Android versions 4.4 (KitKat) to v9. Versions 4 and 5 are to be confirmed.

This issue doesn't include writing tests (see #6).

App fails to bind to gateway on Android 11

... So you get the screen saying that the gateway isn't installed.

I'm 60% confident I tried an early version of the Ping app on Android 11 and it worked, so if I'm not making that up, then we must've changed something that dropped Android 11 support.

I've already uninstalled and reinstalled both apps but the issue persists.

Ping screen: Status is missing right after sending ping

I think it'd be good to show something when the ping was sent but the pong hasn't been received yet -- Especially when the user is using the app for the first time and the pong takes a while to arrive. And we should also make it more obvious when the pong authorisation timed out.

I think there are a couple of ways to solve this, sorted by preference:

  1. By moving creation time to a separate row and placing the ping status icon in its place. This would also address an issue I raised on Figma the other day: A long public address combined with the full date format will break the UI.
  2. By creating a new row for the status (pong pending, pong received, timed out).
  3. By setting the Pong received at field to something like Pending/Timed out.

App crashes if it fails to bind to gateway

For example, if the gateway isn't installed.

2021-04-06 09:52:08.511 23186-23209/tech.relaycorp.ping E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
    Process: tech.relaycorp.ping, PID: 23186
    tech.relaycorp.awaladroid.GatewayBindingException: Failed binding to Awala Gateway for registration
        at tech.relaycorp.awaladroid.GatewayClientImpl$bind$2.invokeSuspend(GatewayClientImpl.kt:65)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
     Caused by: tech.relaycorp.awaladroid.background.ServiceInteractor$BindFailedException: Binding failed
        at tech.relaycorp.awaladroid.background.ServiceInteractor.bind(ServiceInteractor.kt:71)
        at tech.relaycorp.awaladroid.GatewayClientImpl$bind$2.invokeSuspend(GatewayClientImpl.kt:60)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) 
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106) 
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571) 
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750) 
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678) 
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665) 

App crashes on Android 5

Here's what I get when I try to install it on a Nexus 4:

    --------- beginning of crash
E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-3
    Process: tech.relaycorp.ping, PID: 4527
    android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
        at android.app.ContextImpl.startActivity(ContextImpl.java:1238)
        at android.app.ContextImpl.startActivity(ContextImpl.java:1225)
        at android.content.ContextWrapper.startActivity(ContextWrapper.java:323)
        at tech.relaycorp.ping.App.openNoGateway(App.kt:59)
        at tech.relaycorp.ping.App.setupAwala$suspendImpl(App.kt:54)
        at tech.relaycorp.ping.App$setupAwala$1.invokeSuspend(App.kt)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)

App fails to start if installed from a signed APK/AAB

The app works absolutely fine if I install it from an unsigned APK via Android Studio. However, if installed from a signed AAB/APK (as would be the case if downloaded from the Google Play Store), it'd crash as soon as it starts.

I've already tried a brand new keyring, and cleared the cache and build folders.

The issue appears to be related to the desugaring functionality in the Android Gradle plugin. I suspect Android Studio isn't executing the appropriate tasks when generating signed APKs/AABs (most likely due to a configuration issue). Here's the traceback:

2021-04-09 17:01:06.141 10359-10374/? E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
    Process: tech.relaycorp.ping, PID: 10359
    java.lang.NoClassDefFoundError: Failed resolution of: Lj$/$r8$retargetLibraryMember$virtualDispatch$Date$toInstant$dispatchHolder;
        at tech.relaycorp.relaynet.wrappers.x509.Certificate.dateToZonedDateTime(Certificate.kt:321)
        at tech.relaycorp.relaynet.wrappers.x509.Certificate.getStartDate(Certificate.kt:170)
        at tech.relaycorp.relaynet.wrappers.x509.Certificate.validateValidityPeriod(Certificate.kt:224)
        at tech.relaycorp.relaynet.wrappers.x509.Certificate.validate(Certificate.kt:218)
        at tech.relaycorp.awaladroid.endpoint.PublicThirdPartyEndpoint$Companion.import(ThirdPartyEndpoint.kt:179)
        at tech.relaycorp.ping.domain.AddPublicPeer.add(AddPublicPeer.kt:17)
        at tech.relaycorp.ping.domain.BootstrapData.importDefaultPublicPeer(BootstrapData.kt:27)
        at tech.relaycorp.ping.domain.BootstrapData.bootstrapIfNeeded(BootstrapData.kt:21)
        at tech.relaycorp.ping.domain.BootstrapData$bootstrapIfNeeded$1.invokeSuspend(Unknown Source:11)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "j$.$r8$retargetLibraryMember$virtualDispatch$Date$toInstant$dispatchHolder" on path: DexPathList[[zip file "/data/app/tech.relaycorp.ping-Qv974gcM15UExBdf4eRz9g==/base.apk", zip file "/data/app/tech.relaycorp.ping-Qv974gcM15UExBdf4eRz9g==/split_config.en.apk", zip file "/data/app/tech.relaycorp.ping-Qv974gcM15UExBdf4eRz9g==/split_config.xxhdpi.apk"],nativeLibraryDirectories=[/data/app/tech.relaycorp.ping-Qv974gcM15UExBdf4eRz9g==/lib/arm64, /system/lib64, /vendor/lib64]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:125)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
        at tech.relaycorp.relaynet.wrappers.x509.Certificate.dateToZonedDateTime(Certificate.kt:321) 
        at tech.relaycorp.relaynet.wrappers.x509.Certificate.getStartDate(Certificate.kt:170) 
        at tech.relaycorp.relaynet.wrappers.x509.Certificate.validateValidityPeriod(Certificate.kt:224) 
        at tech.relaycorp.relaynet.wrappers.x509.Certificate.validate(Certificate.kt:218) 
        at tech.relaycorp.awaladroid.endpoint.PublicThirdPartyEndpoint$Companion.import(ThirdPartyEndpoint.kt:179) 
        at tech.relaycorp.ping.domain.AddPublicPeer.add(AddPublicPeer.kt:17) 
        at tech.relaycorp.ping.domain.BootstrapData.importDefaultPublicPeer(BootstrapData.kt:27) 
        at tech.relaycorp.ping.domain.BootstrapData.bootstrapIfNeeded(BootstrapData.kt:21) 
        at tech.relaycorp.ping.domain.BootstrapData$bootstrapIfNeeded$1.invokeSuspend(Unknown Source:11) 
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) 
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104) 
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571) 
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750) 
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678) 
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665) 
    	Suppressed: java.io.IOException: No original dex files found for dex location /data/app/tech.relaycorp.ping-Qv974gcM15UExBdf4eRz9g==/split_config.en.apk
        at dalvik.system.DexFile.openDexFileNative(Native Method)
        at dalvik.system.DexFile.openDexFile(DexFile.java:353)
        at dalvik.system.DexFile.<init>(DexFile.java:100)
        at dalvik.system.DexFile.<init>(DexFile.java:74)
        at dalvik.system.DexPathList.loadDexFile(DexPathList.java:374)
        at dalvik.system.DexPathList.makeDexElements(DexPathList.java:337)
        at dalvik.system.DexPathList.<init>(DexPathList.java:157)
        at dalvik.system.BaseDexClassLoader.<init>(BaseDexClassLoader.java:65)
        at dalvik.system.PathClassLoader.<init>(PathClassLoader.java:64)
        at com.android.internal.os.ClassLoaderFactory.createClassLoader(ClassLoaderFactory.java:73)
        at com.android.internal.os.ClassLoaderFactory.createClassLoader(ClassLoaderFactory.java:88)
        at android.app.ApplicationLoaders.getClassLoader(ApplicationLoaders.java:69)
        at android.app.ApplicationLoaders.getClassLoader(ApplicationLoaders.java:35)
        at android.app.LoadedApk.createOrUpdateClassLoaderLocked(LoadedApk.java:693)
        at android.app.LoadedApk.getClassLoader(LoadedApk.java:727)
        at android.app.LoadedApk.getResources(LoadedApk.java:954)
        at android.app.ContextImpl.createAppContext(ContextImpl.java:2270)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5639)
        at android.app.ActivityThread.-wrap1(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1656)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
2021-04-09 17:01:06.142 10359-10374/? E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
    	Suppressed: java.io.IOException: No original dex files found for dex location /data/app/tech.relaycorp.ping-Qv974gcM15UExBdf4eRz9g==/split_config.xxhdpi.apk
        at dalvik.system.DexFile.openDexFileNative(Native Method)
        at dalvik.system.DexFile.openDexFile(DexFile.java:353)
        at dalvik.system.DexFile.<init>(DexFile.java:100)
        at dalvik.system.DexFile.<init>(DexFile.java:74)
        at dalvik.system.DexPathList.loadDexFile(DexPathList.java:374)
        at dalvik.system.DexPathList.makeDexElements(DexPathList.java:337)
        at dalvik.system.DexPathList.<init>(DexPathList.java:157)
        at dalvik.system.BaseDexClassLoader.<init>(BaseDexClassLoader.java:65)
        at dalvik.system.PathClassLoader.<init>(PathClassLoader.java:64)
        at com.android.internal.os.ClassLoaderFactory.createClassLoader(ClassLoaderFactory.java:73)
        at com.android.internal.os.ClassLoaderFactory.createClassLoader(ClassLoaderFactory.java:88)
        at android.app.ApplicationLoaders.getClassLoader(ApplicationLoaders.java:69)
        at android.app.ApplicationLoaders.getClassLoader(ApplicationLoaders.java:35)
        at android.app.LoadedApk.createOrUpdateClassLoaderLocked(LoadedApk.java:693)
        at android.app.LoadedApk.getClassLoader(LoadedApk.java:727)
        at android.app.LoadedApk.getResources(LoadedApk.java:954)
        at android.app.ContextImpl.createAppContext(ContextImpl.java:2270)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5639)
        at android.app.ActivityThread.-wrap1(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1656)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

@sdsantos, can you please try reproducing this? There's no need to upload anything to the Google Play Store: Just generate a local key and generate a signed APK: https://developer.android.com/studio/publish/app-signing#sign-apk

Flaky instrumentation tests break CI on Android 11

I've found 3 tests that often break:

Test 1: tech.relaycorp.ping.ui.ping.SendPingActivityTest:picksDefaultPeer

See: #165 (comment)

Test 2: tech.relaycorp.ping.ui.ping.PingActivityTest:displaysPingWithPong

com.adevinta.android.barista.internal.failurehandler.BaristaException: No view matching ((an instance of android.widget.TextView and view.getText() with or without transformation to match: is "example.org" or (view.getParent() is assignable from class <class com.google.android.material.textfield.TextInputLayout> and (view is an instance of android.view.ViewGroup and has descendant matching an instance of android.widget.TextView and view.getText() with or without transformation to match: is "example.org")))) was found
	at com.adevinta.android.barista.internal.failurehandler.SpyFailureHandler.resendFirstError(SpyFailureHandler.kt:25)
	at com.adevinta.android.barista.internal.AssertAnyKt.assertAnyView(AssertAny.kt:40)
	at com.adevinta.android.barista.internal.AssertAnyKt.assertAny(AssertAny.kt:18)
	at com.adevinta.android.barista.assertion.BaristaVisibilityAssertions.assertDisplayed(BaristaVisibilityAssertions.kt:38)
	at tech.relaycorp.ping.ui.ping.PingActivityTest.displaysPingWithPong(PingActivityTest.kt:79)
	... 34 trimmed
Caused by: androidx.test.espresso.NoMatchingViewException: No views in hierarchy found matching: (an instance of android.widget.TextView and view.getText() with or without transformation to match: is "example.org" or (view.getParent() is assignable from class <class com.google.android.material.textfield.TextInputLayout> and (view is an instance of android.view.ViewGroup and has descendant matching an instance of android.widget.TextView and view.getText() with or without transformation to match: is "example.org")))

View Hierarchy:
+>DecorView{id=-1, visibility=VISIBLE, width=1080, height=1920, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params={(0,0)(fillxfill) ty=BASE_APPLICATION wanim=0x10302fe
  fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
  pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND FIT_INSETS_CONTROLLED
  fitSides=}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2} 
|
+->LinearLayout{id=-1, visibility=VISIBLE, width=1080, height=1920, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@4747566, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2} 
|
+-->ViewStub{id=16908719, res-name=action_mode_bar_stub, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=true, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@43f40a7, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0} 
|
+-->FrameLayout{id=-1, visibility=VISIBLE, width=1080, height=1920, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@66010fd, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1} 
|
+--->FitWindowsLinearLayout{id=2131296319, res-name=action_bar_root, visibility=VISIBLE, width=1080, height=1920, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@f2f6c0, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2} 
|
+---->ViewStubCompat{id=2131296331, res-name=action_mode_bar_stub, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=true, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@721bff9, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0} 
|
+---->ContentFrameLayout{id=16908290, res-name=content, visibility=VISIBLE, width=1080, height=1920, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@bc19d9f, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1} 
|
+----->CoordinatorLayout{id=-1, visibility=VISIBLE, width=1080, height=1920, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@770beec, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2} 
|
+------>AppBarLayout{id=2131296346, res-name=appBar, visibility=VISIBLE, width=1080, height=220, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.coordinatorlayout.widget.CoordinatorLayout$LayoutParams@d4c5d4a, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1} 
|
+------->Toolbar{id=2131296734, res-name=toolbar, visibility=VISIBLE, width=1080, height=154, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=com.google.android.material.appbar.AppBarLayout$LayoutParams@fa67531, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=66.0, child-count=2} 
|
+-------->MaterialTextView{id=2131296735, res-name=toolbarTitle, visibility=VISIBLE, width=108, height=69, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.appcompat.widget.Toolbar$LayoutParams@67b0416, tag=null, root-is-layout-requested=false, has-input-connection=false, x=486.0, y=42.0, text=Ping, input-type=0, ime-target=false, has-links=false} 
|
+-------->AppCompatImageButton{id=-1, visibility=VISIBLE, width=154, height=154, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=androidx.appcompat.widget.Toolbar$LayoutParams@ca3a197, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0} 
|
+------>NestedScrollView{id=2131296511, res-name=list, visibility=VISIBLE, width=1080, height=1700, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=androidx.coordinatorlayout.widget.CoordinatorLayout$LayoutParams@1bc336d, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=220.0, child-count=1} 
|
+------->LinearLayout{id=-1, visibility=VISIBLE, width=1080, height=1076, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@97bb1c, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=6} 
|
+-------->LinearLayout{id=-1, visibility=VISIBLE, width=1080, height=198, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@f36d08, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=3} 
|
+--------->AppCompatImageView{id=2131296477, res-name=icon, desc=Public Endpoint, visibility=VISIBLE, width=66, height=66, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@f0e0ca1, tag=null, root-is-layout-requested=false, has-input-connection=false, x=44.0, y=66.0} 
|
+--------->MaterialTextView{id=2131296612, res-name=recipient, visibility=VISIBLE, width=838, height=55, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@65a9ec6, tag=null, root-is-layout-requested=false, has-input-connection=false, x=154.0, y=71.0, text=, input-type=0, ime-target=false, has-links=false} 
|
+--------->AppCompatImageView{id=2131296685, res-name=state, desc=Pong pending, visibility=VISIBLE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@41a1e87, tag=null, root-is-layout-requested=false, has-input-connection=false, x=1036.0, y=99.0} 
|
+-------->View{id=-1, visibility=VISIBLE, width=1080, height=1, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@7d651b4, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=198.0} 
|
+-------->FieldView{id=2131296602, res-name=pingIdField, visibility=VISIBLE, width=1080, height=209, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@3d1e152, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=199.0, child-count=1} 
|
+--------->ConstraintLayout{id=-1, visibility=VISIBLE, width=1080, height=209, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@89e577f, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=4} 
|
+---------->MaterialTextView{id=2131296492, res-name=labelText, visibility=VISIBLE, width=309, height=203, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@54e234c, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, text=ID, input-type=0, ime-target=false, has-links=false} 
|
+---------->MaterialTextView{id=2131296752, res-name=valueText, visibility=VISIBLE, width=617, height=209, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@9ce5f95, tag=null, root-is-layout-requested=false, has-input-connection=false, x=309.0, y=0.0, text=, input-type=0, ime-target=false, has-links=false} 
|
+---------->MaterialButton{id=2131296393, res-name=copy, desc=Copy, visibility=VISIBLE, width=110, height=120, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@3c48aa, tag=null, root-is-layout-requested=false, has-input-connection=false, x=948.0, y=44.0, text=, input-type=0, ime-target=false, has-links=false, is-checked=false} 
|
+---------->View{id=-1, visibility=VISIBLE, width=1080, height=1, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@54aec9b, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=208.0} 
|
+-------->FieldView{id=2131296657, res-name=sentAtField, visibility=VISIBLE, width=1080, height=209, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@2026011, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=408.0, child-count=1} 
|
+--------->ConstraintLayout{id=-1, visibility=VISIBLE, width=1080, height=209, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@8f14302, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=4} 
|
+---------->MaterialTextView{id=2131296492, res-name=labelText, visibility=VISIBLE, width=309, height=203, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@6b05413, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, text=Sent at, input-type=0, ime-target=false, has-links=false} 
|
+---------->MaterialTextView{id=2131296752, res-name=valueText, visibility=VISIBLE, width=771, height=209, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@c63c650, tag=null, root-is-layout-requested=false, has-input-connection=false, x=309.0, y=0.0, text=, input-type=0, ime-target=false, has-links=false} 
|
+---------->MaterialButton{id=2131296393, res-name=copy, desc=Copy, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=true, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@ec80049, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, text=, input-type=0, ime-target=false, has-links=false, is-checked=false} 
|
+---------->View{id=-1, visibility=VISIBLE, width=1080, height=1, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@cb48d4e, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=208.0} 
|
+-------->FieldView{id=2131296445, res-name=expiresAtField, visibility=VISIBLE, width=1080, height=209, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@e46f77c, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=617.0, child-count=1} 
|
+--------->ConstraintLayout{id=-1, visibility=VISIBLE, width=1080, height=209, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@32a6f81, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=4} 
|
+---------->MaterialTextView{id=2131296492, res-name=labelText, visibility=VISIBLE, width=309, height=203, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@5d0f826, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, text=Time out, input-type=0, ime-target=false, has-links=false} 
|
+---------->MaterialTextView{id=2131296752, res-name=valueText, visibility=VISIBLE, width=771, height=209, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@8f96c67, tag=null, root-is-layout-requested=false, has-input-connection=false, x=309.0, y=0.0, text=, input-type=0, ime-target=false, has-links=false} 
|
+---------->MaterialButton{id=2131296393, res-name=copy, desc=Copy, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=true, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@fe4ba14, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, text=, input-type=0, ime-target=false, has-links=false, is-checked=false} 
|
+---------->View{id=-1, visibility=VISIBLE, width=1080, height=1, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@48d82bd, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=208.0} 
|
+-------->FieldView{id=2131296603, res-name=pongReceivedField, visibility=VISIBLE, width=1080, height=250, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@8266803, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=826.0, child-count=1} 
|
+--------->ConstraintLayout{id=-1, visibility=VISIBLE, width=1080, height=250, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@6f537ac, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=4} 
|
+---------->MaterialTextView{id=2131296492, res-name=labelText, visibility=VISIBLE, width=309, height=250, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@8674c75, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, text=Pong received at, input-type=0, ime-target=false, has-links=false} 
|
+---------->MaterialTextView{id=2131296752, res-name=valueText, visibility=VISIBLE, width=771, height=209, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@4c5640a, tag=null, root-is-layout-requested=false, has-input-connection=false, x=309.0, y=0.0, text=, input-type=0, ime-target=false, has-links=false} 
|
+---------->MaterialButton{id=2131296393, res-name=copy, desc=Copy, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=true, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@642d47b, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, text=, input-type=0, ime-target=false, has-links=false, is-checked=false} 
|
+---------->View{id=-1, visibility=VISIBLE, width=1080, height=1, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@9542298, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=249.0} 
|
+->View{id=16908336, res-name=navigationBarBackground, visibility=VISIBLE, width=1080, height=132, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@4ed3af1, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=1788.0} 
	at androidx.test.espresso.NoMatchingViewException$Builder.build(NoMatchingViewException.java:5)
	at androidx.test.espresso.base.ViewFinderImpl.getView(ViewFinderImpl.java:26)
	at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:5)
	at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:1)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at android.os.Handler.handleCallback(Handler.java:938)
	at android.os.Handler.dispatchMessage(Handler.java:99)
	at android.os.Looper.loop(Looper.java:223)
	at android.app.ActivityThread.main(ActivityThread.java:7656)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

https://console.firebase.google.com/u/0/project/awala-ping-android/testlab/histories/bh.6e5c9f23e2ef2570/matrices/5338090043455903581/executions/bs.8fe1913caddc3279/testcases/9/logs

Test 3: tech.relaycorp.ping.ui.peers.AddPublicPeerActivityTest:addPublicPeerSuccessfully

java.lang.AssertionError: Timeout waiting
	at tech.relaycorp.ping.test.WaitAssertions.waitFor(WaitAssertions.kt:19)
	at tech.relaycorp.ping.test.ActivityAssertions.waitForCurrentActivityToBe(ActivityAssertions.kt:32)
	at tech.relaycorp.ping.ui.peers.AddPublicPeerActivityTest.addPublicPeerSuccessfully(AddPublicPeerActivityTest.kt:65)
	... 39 trimmed
Caused by: org.junit.ComparisonFailure: expected:<...ycorp.ping.ui.peers.[Peers]Activity> but was:<...ycorp.ping.ui.peers.[AddPublicPeer]Activity>
	at org.junit.Assert.assertEquals(Assert.java:115)
	at org.junit.Assert.assertEquals(Assert.java:144)
	at tech.relaycorp.ping.test.ActivityAssertions.assertCurrentActivity(ActivityAssertions.kt:28)
	at tech.relaycorp.ping.test.ActivityAssertions$waitForCurrentActivityToBe$1.invoke(ActivityAssertions.kt:32)
	at tech.relaycorp.ping.test.ActivityAssertions$waitForCurrentActivityToBe$1.invoke(ActivityAssertions.kt:32)
	at tech.relaycorp.ping.test.WaitAssertions.waitFor(WaitAssertions.kt:12)
	... 42 more

https://console.firebase.google.com/u/0/project/awala-ping-android/testlab/histories/bh.6e5c9f23e2ef2570/matrices/5338090043455903581/executions/bs.8fe1913caddc3279/testcases/2/test-cases

Home screen: Ping timeouts take too long to be reflected

It takes too long for the status to be reflected on the home screen.

Here's an example of a ping that timed out after 1 minute:

Screenshot_20210403-105607

And this is what it looks like on the home screen after 10 minutes:

Screenshot_20210403-110405

Ideally, these things would be updated in real-time, but I suspect that'd make the implementation too complicated for such an infrequent use case. So as a compromise I'd suggest to re-query the DB when the user goes back to the home screen, for example, after being on the ping screen.

Implement sending of ping messages

If recipient is a private endpoint (e.g., another Android phone), this should use the Parcel Delivery Authorization generated by the recipient in #1.

Flaky tests break CI intermittently

tech.relaycorp.ping.ui.peers.AddPublicPeerActivityTest.addPublicPeerMissingCertificate is the culprit: https://console.firebase.google.com/u/0/project/awala-ping-android/testlab/histories/bh.6e5c9f23e2ef2570/matrices/5757771105566649704/executions/bs.2400bf6e6bbc3d1/testcases/3/test-cases

com.schibsted.spain.barista.internal.failurehandler.BaristaException: No view matching (with string from resource id: <2131887517>[peer_add_missing_certificate] value: Missing Identity Certificate) was found
at com.schibsted.spain.barista.internal.failurehandler.SpyFailureHandler.resendFirstError(SpyFailureHandler.kt:25)
at com.schibsted.spain.barista.internal.AssertAnyKt.assertAnyView(AssertAny.kt:40)
at com.schibsted.spain.barista.internal.AssertAnyKt.assertAny(AssertAny.kt:18)
at com.schibsted.spain.barista.assertion.BaristaVisibilityAssertions.assertDisplayed(BaristaVisibilityAssertions.kt:33)
at tech.relaycorp.ping.ui.peers.AddPublicPeerActivityTest.addPublicPeerMissingCertificate(AddPublicPeerActivityTest.kt:71)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at androidx.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:80)
at tech.relaycorp.ping.test.IntentsRule$apply$1.evaluate(IntentsRule.kt:18)
at com.schibsted.spain.barista.rule.cleardata.ClearFilesRule$apply$1.evaluate(ClearFilesRule.kt:25)
at tech.relaycorp.ping.test.ClearTestDatabaseRule$apply$1.evaluate(ClearTestDatabaseRule.kt:20)
at com.schibsted.spain.barista.rule.cleardata.ClearPreferencesRule$1.evaluate(ClearPreferencesRule.java:26)
at androidx.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:549)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:154)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:395)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2189)
Caused by: androidx.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with string from resource id: <2131887517>[peer_add_missing_certificate] value: Missing Identity Certificate

View Hierarchy:
+>DecorView{id=-1, visibility=VISIBLE, width=1080, height=1920, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params={(0,0)(fillxfill) sim={adjust=resize} ty=BASE_APPLICATION wanim=0x10302fe
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}
|
+->LinearLayout{id=-1, visibility=VISIBLE, width=1080, height=1920, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@f702737, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}
|
+-->ViewStub{id=16908692, res-name=action_mode_bar_stub, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=true, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@a3da4a4, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0}
|
+-->FrameLayout{id=-1, visibility=VISIBLE, width=1080, height=1920, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@3f745c2, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}
|
+--->FitWindowsLinearLayout{id=2131296319, res-name=action_bar_root, visibility=VISIBLE, width=1080, height=1920, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@bccf209, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}
|
+---->ViewStubCompat{id=2131296330, res-name=action_mode_bar_stub, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=true, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@3f7fc0e, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0}
|
+---->ContentFrameLayout{id=16908290, res-name=content, visibility=VISIBLE, width=1080, height=1920, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@f0ee43c, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}
|
+----->CoordinatorLayout{id=-1, visibility=VISIBLE, width=1080, height=1920, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@549a5c5, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}
|
+------>AppBarLayout{id=2131296345, res-name=appBar, visibility=VISIBLE, width=1080, height=220, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.coordinatorlayout.widget.CoordinatorLayout$LayoutParams@d73964b, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}
|
+------->Toolbar{id=2131296729, res-name=toolbar, visibility=VISIBLE, width=1080, height=154, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=com.google.android.material.appbar.AppBarLayout$LayoutParams@2634c27, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=66.0, child-count=3}
|
+-------->MaterialTextView{id=2131296730, res-name=toolbarTitle, visibility=VISIBLE, width=390, height=69, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.appcompat.widget.Toolbar$LayoutParams@2a57ed4, tag=null, root-is-layout-requested=false, has-input-connection=false, x=345.0, y=42.0, text=Public Endpoint, input-type=0, ime-target=false, has-links=false}
|
+-------->AppCompatImageButton{id=-1, visibility=VISIBLE, width=154, height=154, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=androidx.appcompat.widget.Toolbar$LayoutParams@913c87d, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0}
|
+-------->ActionMenuView{id=-1, visibility=VISIBLE, width=150, height=154, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.appcompat.widget.Toolbar$LayoutParams@cae83c3, tag=null, root-is-layout-requested=false, has-input-connection=false, x=930.0, y=0.0, child-count=1}
|
+--------->ActionMenuItemView{id=2131296620, res-name=save, visibility=VISIBLE, width=150, height=132, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=androidx.appcompat.widget.ActionMenuView$LayoutParams@e45b440, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=11.0, text=Save, input-type=0, ime-target=false, has-links=false}
|
+------>LinearLayout{id=-1, visibility=VISIBLE, width=1080, height=455, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.coordinatorlayout.widget.CoordinatorLayout$LayoutParams@b388a35, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=220.0, child-count=4}
|
+------->LinearLayout{id=-1, visibility=VISIBLE, width=1080, height=203, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@75dcb58, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}
|
+-------->MaterialTextView{id=2, visibility=VISIBLE, width=309, height=203, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@4f494b1, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, text=Address *, input-type=0, ime-target=false, has-links=false}
|
+-------->TextInputEditText{id=2131296337, res-name=addressEdit, visibility=VISIBLE, width=727, height=120, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@a8ccaed, tag=null, root-is-layout-requested=false, has-input-connection=true, editor-info=[inputType=0x11 imeOptions=0x6 privateImeOptions=null actionLabel=null actionId=0 initialSelStart=0 initialSelEnd=0 initialCapsMode=0x0 hintText=Type an address label=null packageName=null fieldId=0 fieldName=null extras=null hintLocales=null contentMimeTypes=null ], x=309.0, y=41.0, text=ping.awala.services, hint=Type an address, input-type=17, ime-target=false, has-links=false}
|
+------->View{id=-1, visibility=VISIBLE, width=1080, height=1, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@414cd22, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=203.0}
|
+------->LinearLayout{id=-1, visibility=VISIBLE, width=1080, height=250, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@9f828e9, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=204.0, child-count=4}
|
+-------->MaterialTextView{id=-1, visibility=VISIBLE, width=309, height=250, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@856996e, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, text=Identity Certificate *, input-type=0, ime-target=false, has-links=false}
|
+-------->MaterialButton{id=2131296367, res-name=certificateButton, visibility=VISIBLE, width=727, height=132, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@8b3080f, tag=null, root-is-layout-requested=false, has-input-connection=false, x=309.0, y=59.0, text=Upload certificate, input-type=0, ime-target=false, has-links=false, is-checked=false}
|
+-------->MaterialTextView{id=2131296369, res-name=certificateName, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=true, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@b49309c, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, text=, input-type=0, ime-target=false, has-links=false}
|
+-------->MaterialButton{id=2131296368, res-name=certificateClear, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=true, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@fa16aa5, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, text=, input-type=0, ime-target=false, has-links=false, is-checked=false}
|
+------->View{id=-1, visibility=VISIBLE, width=1080, height=1, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@6d6de7a, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=454.0}
|
+->View{id=16908336, res-name=navigationBarBackground, visibility=VISIBLE, width=1080, height=132, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@da2162b, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=1788.0}
|
at androidx.test.espresso.NoMatchingViewException$Builder.build(NoMatchingViewException.java:15)
at androidx.test.espresso.base.ViewFinderImpl.getView(ViewFinderImpl.java:33)
at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:4)
at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:2)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

Determine how to handle the case when the gateway is upgraded whilst we're using it

Because right now it's crashing due to relaycorp/awala-endpoint-android#75.

One way to handle it is by catching the appropriate exception in the statement below, and re-doing the binding to the gateway.

GatewayClient.receiveMessages().collect(receivePong::receive)

Alternatively, we could do something in awaladroid that won't require changes to this app. But is there anything reliable that we can do?

Pre-registration failed, received wrong reply

Describe the bug

If I attempt to use ping before establishing a connection with the awala gateway the ping app crashes.
This is because we don't handle "GATEWAY_NOT_REGISTERED"

How to reproduce

Steps to reproduce the behavior:
(must be done with a clean install on both, and no Internet access)

  1. Go to Awala (Gateway) complete the onboarding (make sure it says you are disconnected)
  2. Go to Ping
  3. See Ping Crash

Expected behavior

The Ping App should not crash, it should only display an info saying it failed to connect to a gateway or something similar

Additional context

To replicate make a clean install on both apps, and have no Internet access so the gateway can not establish a connection.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.