diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 00000000..a9823e8e --- /dev/null +++ b/.github/workflows/android.yml @@ -0,0 +1,17 @@ +name: Android CI +# from https://medium.com/@wkrzywiec/github-actions-for-android-first-approach-f616c24aa0f9 + +on: push + +jobs: + test: + name: Test + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@master + - name: set up JDK 1.8 + uses: actions/setup-java@master + with: + java-version: 1.8 + - name: Unit tests + run: bash ./gradlew test --stacktrace diff --git a/TODO.md b/TODO.md index 5b50b05d..b70ec4a8 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,7 @@ # High priority Work items for soon alpha builds +* update play store listing for public beta * run services in sim mode on emulator * show offline nodes as greyed out * show time since last contact on the node info card diff --git a/app/build.gradle b/app/build.gradle index 56012448..1ea64284 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ android { applicationId "com.geeksville.mesh" minSdkVersion 22 // The oldest emulator image I have tried is 22 (though 21 probably works) targetSdkVersion 29 - versionCode 9 - versionName "0.0.9" + versionCode 104 + versionName "0.1.4" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -45,7 +45,7 @@ android { composeOptions { kotlinCompilerVersion "1.3.61-dev-withExperimentalGoogleExtensions-20200129" - kotlinCompilerExtensionVersion "0.1.0-dev05" + kotlinCompilerExtensionVersion "0.1.0-dev06" } } diff --git a/app/src/main/java/com/geeksville/mesh/MainActivity.kt b/app/src/main/java/com/geeksville/mesh/MainActivity.kt index afbe6189..dd816aca 100644 --- a/app/src/main/java/com/geeksville/mesh/MainActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/MainActivity.kt @@ -13,6 +13,7 @@ import android.os.Build import android.os.Bundle import android.view.Menu import android.view.MenuItem +import android.view.MotionEvent import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat @@ -29,6 +30,7 @@ import com.geeksville.mesh.ui.AppStatus import com.geeksville.mesh.ui.MeshApp import com.geeksville.mesh.ui.ScanState import com.geeksville.mesh.ui.Screen +import com.geeksville.util.Exceptions import com.geeksville.util.exceptionReporter import com.google.android.gms.auth.api.signin.GoogleSignIn import com.google.android.gms.auth.api.signin.GoogleSignInAccount @@ -239,6 +241,8 @@ class MainActivity : AppCompatActivity(), Logging, override fun onDestroy() { unregisterMeshReceiver() + UIState.meshService = + null // When our activity goes away make sure we don't keep a ptr around to the service super.onDestroy() } @@ -328,6 +332,18 @@ class MainActivity : AppCompatActivity(), Logging, } } + override fun dispatchTouchEvent(ev: MotionEvent?): Boolean { + return try { + super.dispatchTouchEvent(ev) + } catch (ex: Throwable) { + Exceptions.report( + ex, + "dispatchTouchEvent" + ) // hide this Compose error from the user but report to the mothership + false + } + } + private val meshServiceReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) = exceptionReporter { @@ -395,7 +411,8 @@ class MainActivity : AppCompatActivity(), Logging, private fun bindMeshService() { debug("Binding to mesh service!") // we bind using the well known name, to make sure 3rd party apps could also - logAssert(UIState.meshService == null) + if (UIState.meshService != null) + Exceptions.reportError("meshService was supposed to be null, ignoring (but reporting a bug)") MeshService.startService(this)?.let { intent -> // ALSO bind so we can use the api diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt index 85266139..6284fec5 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -530,6 +530,12 @@ class MeshService : Service(), Logging { else -> TODO() } + + GeeksvilleApplication.analytics.track( + "data_receive", + DataPair("num_bytes", bytes.size), + DataPair("type", data.typValue) + ) } /// Update our DB of users based on someone sending out a User subpacket @@ -686,10 +692,20 @@ class MeshService : Service(), Logging { try { reinitFromRadio() + val radioModel = DataPair("radio_model", myNodeInfo?.model ?: "unknown") GeeksvilleApplication.analytics.track( "mesh_connect", DataPair("num_nodes", numNodes), - DataPair("num_online", numOnlineNodes) + DataPair("num_online", numOnlineNodes), + radioModel + ) + + // Once someone connects to hardware start tracking the approximate number of nodes in their mesh + // this allows us to collect stats on what typical mesh size is and to tell difference between users who just + // downloaded the app, vs has connected it to some hardware. + GeeksvilleApplication.analytics.setUserInfo( + DataPair("num_nodes", numNodes), + radioModel ) } catch (ex: RemoteException) { // It seems that when the ESP32 goes offline it can briefly come back for a 100ms ish which @@ -838,6 +854,12 @@ class MeshService : Service(), Logging { sendToRadio(ToRadio.newBuilder().apply { this.packet = packet }) + + GeeksvilleApplication.analytics.track( + "data_send", + DataPair("num_bytes", payloadIn.size), + DataPair("type", typ) + ) } override fun getRadioConfig(): ByteArray = toRemoteExceptions { diff --git a/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt b/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt index 1281b2d0..6b0e485a 100644 --- a/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt @@ -221,7 +221,7 @@ class RadioInterfaceService : Service(), Logging { // Handle an incoming packet from the radio, broadcasts it as an android intent private fun handleFromRadio(p: ByteArray) { - if(logReceives) { + if (logReceives) { receivedPacketsLog.write(p) receivedPacketsLog.flush() } @@ -279,6 +279,9 @@ class RadioInterfaceService : Service(), Logging { fromNum = service.getCharacteristic(BTM_FROMNUM_CHARACTER) + // We must set this to true before broadcasting connectionChanged + isConnected = true + safe!!.setNotify(fromNum, true) { debug("fromNum changed, so we are reading new messages") doReadFromRadio() @@ -286,7 +289,6 @@ class RadioInterfaceService : Service(), Logging { // Now tell clients they can (finally use the api) broadcastConnectionChanged(true) - isConnected = true // Immediately broadcast any queued packets sitting on the device doReadFromRadio() @@ -349,7 +351,7 @@ class RadioInterfaceService : Service(), Logging { info("Closing radio interface service") if (logSends) sentPacketsLog.close() - if(logReceives) + if (logReceives) receivedPacketsLog.close() safe?.close() safe = null diff --git a/app/src/main/java/com/geeksville/mesh/ui/Analytics.kt b/app/src/main/java/com/geeksville/mesh/ui/Analytics.kt new file mode 100644 index 00000000..57fedcb3 --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/ui/Analytics.kt @@ -0,0 +1,19 @@ +package com.geeksville.mesh.ui + +import androidx.compose.Composable +import androidx.compose.onCommit +import com.geeksville.android.GeeksvilleApplication + +/** + * Track compose screen visibility + */ +@Composable +fun analyticsScreen(name: String) { + onCommit(AppStatus.currentScreen) { + GeeksvilleApplication.analytics.sendScreenView(name) + + onDispose { + GeeksvilleApplication.analytics.endScreenView() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/ui/AppDrawer.kt b/app/src/main/java/com/geeksville/mesh/ui/AppDrawer.kt index 032ada63..ae9f471a 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/AppDrawer.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/AppDrawer.kt @@ -7,7 +7,6 @@ import androidx.ui.core.Text import androidx.ui.foundation.shape.corner.RoundedCornerShape import androidx.ui.graphics.Color import androidx.ui.layout.* -import androidx.ui.material.Button import androidx.ui.material.Divider import androidx.ui.material.MaterialTheme import androidx.ui.material.TextButton @@ -75,9 +74,9 @@ private fun DrawerButton( Surface( modifier = modifier + LayoutPadding( - left = 8.dp, + start = 8.dp, top = 8.dp, - right = 8.dp, + end = 8.dp, bottom = 0.dp ), color = backgroundColor, diff --git a/app/src/main/java/com/geeksville/mesh/ui/BTScanScreen.kt b/app/src/main/java/com/geeksville/mesh/ui/BTScanScreen.kt index 7a024daa..5104f905 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/BTScanScreen.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/BTScanScreen.kt @@ -3,11 +3,13 @@ package com.geeksville.mesh.ui import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothManager import android.bluetooth.le.* +import android.content.Context import android.os.ParcelUuid -import androidx.compose.* +import androidx.compose.Composable +import androidx.compose.Model import androidx.compose.frames.modelMapOf +import androidx.compose.onCommit import androidx.ui.core.ContextAmbient -import androidx.ui.core.LayoutModifier import androidx.ui.core.Text import androidx.ui.layout.Column import androidx.ui.layout.LayoutGravity @@ -45,7 +47,7 @@ object ScanState : Logging { debug("stopping scan") try { scanner!!.stopScan(callback) - } catch(ex: Throwable) { + } catch (ex: Throwable) { warn("Ignoring error stopping scan, probably BT adapter was disabled suddenly: ${ex.message}") } callback = null @@ -67,7 +69,9 @@ fun BTScanScreen() { val bluetoothAdapter = (context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter - onActive { + analyticsScreen(name = "settings") + onCommit(AppStatus.currentScreen) { + ScanState.debug("BTScan component active") ScanUIState.selectedMacAddr = RadioInterfaceService.getBondedDeviceAddress(context) val scanCallback = object : ScanCallback() { @@ -117,10 +121,10 @@ fun BTScanScreen() { /// The following call might return null if the user doesn't have bluetooth access permissions val s: BluetoothLeScanner? = bluetoothAdapter.bluetoothLeScanner - if(s == null) { - ScanUIState.errorText = "This application requires bluetooth access. Please grant access in android settings." - } - else { + if (s == null) { + ScanUIState.errorText = + "This application requires bluetooth access. Please grant access in android settings." + } else { ScanState.debug("starting scan") // filter and only accept devices that have a sw update service @@ -138,6 +142,7 @@ fun BTScanScreen() { } onDispose { + ScanState.debug("BTScan component deactivated") ScanState.stopScan() } } @@ -147,7 +152,10 @@ fun BTScanScreen() { Text("An unexpected error was encountered. Please file a bug on our github: ${ScanUIState.errorText}") } else { if (ScanUIState.devices.isEmpty()) { - Text(text = "Looking for Meshtastic devices... (zero found)", modifier = LayoutGravity.Center) + Text( + text = "Looking for Meshtastic devices... (zero found)", + modifier = LayoutGravity.Center + ) CircularProgressIndicator() // Show that we are searching still } else { diff --git a/app/src/main/java/com/geeksville/mesh/ui/Channel.kt b/app/src/main/java/com/geeksville/mesh/ui/Channel.kt index 81eac742..3f289c7a 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/Channel.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/Channel.kt @@ -3,20 +3,22 @@ package com.geeksville.mesh.ui import android.content.Intent import android.graphics.Bitmap import androidx.compose.Composable -import androidx.ui.core.ContextAmbient -import androidx.ui.core.Text -import androidx.ui.foundation.DrawImage -import androidx.ui.graphics.Image -import androidx.ui.graphics.ImageConfig -import androidx.ui.graphics.NativeImage +import androidx.ui.core.* +import androidx.ui.foundation.Box +import androidx.ui.graphics.* import androidx.ui.graphics.colorspace.ColorSpace import androidx.ui.graphics.colorspace.ColorSpaces +import androidx.ui.graphics.painter.ImagePainter import androidx.ui.layout.* import androidx.ui.material.MaterialTheme import androidx.ui.material.OutlinedButton import androidx.ui.material.ripple.Ripple import androidx.ui.tooling.preview.Preview +import androidx.ui.unit.Density +import androidx.ui.unit.PxSize import androidx.ui.unit.dp +import androidx.ui.unit.toRect +import com.geeksville.analytics.DataPair import com.geeksville.android.GeeksvilleApplication import com.geeksville.android.Logging import com.geeksville.mesh.R @@ -70,8 +72,39 @@ class AndroidImage(val bitmap: Bitmap) : Image { } } + +/// Stolen from the Compose SimpleImage, replace with their real Image component someday +// TODO(mount, malkov) : remove when RepaintBoundary is a modifier: b/149982905 +// This is class and not val because if b/149985596 +private object ClipModifier : DrawModifier { + override fun draw(density: Density, drawContent: () -> Unit, canvas: Canvas, size: PxSize) { + canvas.save() + canvas.clipRect(size.toRect()) + drawContent() + canvas.restore() + } +} + +/// Stolen from the Compose SimpleImage, replace with their real Image component someday +@Composable +fun ScaledImage( + image: Image, + modifier: Modifier = Modifier.None, + tint: Color? = null +) { + with(DensityAmbient.current) { + val imageModifier = ImagePainter(image).toModifier( + scaleFit = ScaleFit.FillMaxDimension, + colorFilter = tint?.let { ColorFilter(it, BlendMode.srcIn) } + ) + Box(modifier + ClipModifier + imageModifier) + } +} + @Composable fun ChannelContent(channel: Channel = Channel("Default", 7)) { + analyticsScreen(name = "channel") + val typography = MaterialTheme.typography() val context = ContextAmbient.current @@ -87,14 +120,18 @@ fun ChannelContent(channel: Channel = Channel("Default", 7)) { // val image = imageResource(id = R.drawable.qrcode) val image = AndroidImage(UIState.getChannelQR(context)) - Container(modifier = LayoutGravity.Center + LayoutSize.Min(200.dp, 200.dp)) { - DrawImage(image = image) - } + ScaledImage( + image = image, + modifier = LayoutGravity.Center + LayoutSize.Min(200.dp, 200.dp) + ) Ripple(bounded = false) { - OutlinedButton(modifier = LayoutGravity.Center + LayoutPadding(left = 24.dp), + OutlinedButton(modifier = LayoutGravity.Center + LayoutPadding(start = 24.dp), onClick = { - GeeksvilleApplication.analytics.track("channel_share") // track how many times users share channels + GeeksvilleApplication.analytics.track( + "share", + DataPair("content_type", "channel") + ) // track how many times users share channels val sendIntent: Intent = Intent().apply { action = Intent.ACTION_SEND diff --git a/app/src/main/java/com/geeksville/mesh/ui/MeshApp.kt b/app/src/main/java/com/geeksville/mesh/ui/MeshApp.kt index 1d033f00..a9c2e2ba 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/MeshApp.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/MeshApp.kt @@ -2,7 +2,6 @@ package com.geeksville.mesh.ui import androidx.compose.Composable import androidx.compose.state -import androidx.ui.animation.Crossfade import androidx.ui.core.ContextAmbient import androidx.ui.core.Text import androidx.ui.layout.Column @@ -34,6 +33,8 @@ fun getInitials(name: String): String { @Composable fun HomeContent() { + analyticsScreen(name = "users") + Column { Row { VectorImage( @@ -124,35 +125,30 @@ fun previewView() { @Composable private fun AppContent(openDrawer: () -> Unit) { - Crossfade(AppStatus.currentScreen) { screen -> - Surface(color = (MaterialTheme.colors()).background) { + // crossfade breaks onCommit behavior because it keeps old views around + //Crossfade(AppStatus.currentScreen) { screen -> + Surface(color = (MaterialTheme.colors()).background) { - Column { - TopAppBar( - title = { Text(text = "Meshtastic") }, - navigationIcon = { - Container(LayoutSize(40.dp, 40.dp)) { - VectorImageButton(R.drawable.ic_launcher_new_foreground) { - openDrawer() - } + Column { + TopAppBar( + title = { Text(text = "Meshtastic") }, + navigationIcon = { + Container(LayoutSize(40.dp, 40.dp)) { + VectorImageButton(R.drawable.ic_launcher_new_foreground) { + openDrawer() } } - ) - - // VerticalScroller breaks flexible layouts - because verticalscrollers have 'infinite' height - // VerticalScroller(modifier = LayoutFlexible(1f)) { - //if (screen != Screen.settings) - // ScanState.stopScan() // Nasty hack to teardown the bt scanner - - when (screen) { - Screen.messages -> MessagesContent() - Screen.settings -> SettingsContent() - Screen.users -> HomeContent() - Screen.channel -> ChannelContent() - else -> TODO() } - //} + ) + + when (AppStatus.currentScreen) { + Screen.messages -> MessagesContent() + Screen.settings -> SettingsContent() + Screen.users -> HomeContent() + Screen.channel -> ChannelContent() + else -> TODO() } } } + //} } diff --git a/app/src/main/java/com/geeksville/mesh/ui/Messages.kt b/app/src/main/java/com/geeksville/mesh/ui/Messages.kt index 37504595..1e4b5685 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/Messages.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/Messages.kt @@ -39,7 +39,7 @@ fun MessageCard(msg: TextMessage, modifier: Modifier = Modifier.None) { Row(modifier = modifier) { UserIcon(NodeDB.nodes[msg.from]) - Column(modifier = LayoutPadding(left = 12.dp)) { + Column(modifier = LayoutPadding(start = 12.dp)) { Row { val nodes = NodeDB.nodes @@ -51,7 +51,7 @@ fun MessageCard(msg: TextMessage, modifier: Modifier = Modifier.None) { ProvideEmphasis(emphasis = TimestampEmphasis) { Text( text = dateFormat.format(msg.date), - modifier = LayoutPadding(left = 8.dp), + modifier = LayoutPadding(start = 8.dp), style = MaterialTheme.typography().caption ) } @@ -67,6 +67,8 @@ fun MessageCard(msg: TextMessage, modifier: Modifier = Modifier.None) { @Composable fun MessagesContent() { + analyticsScreen(name = "messages") + Column(modifier = LayoutSize.Fill) { val sidePad = 8.dp @@ -79,8 +81,8 @@ fun MessagesContent() { messages.forEach { msg -> MessageCard( msg, modifier = LayoutPadding( - left = sidePad, - right = sidePad, + start = sidePad, + end = sidePad, top = topPad, bottom = topPad ) diff --git a/app/src/main/java/com/geeksville/mesh/ui/NodeInfoCard.kt b/app/src/main/java/com/geeksville/mesh/ui/NodeInfoCard.kt index 6edba21d..cc17f427 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/NodeInfoCard.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/NodeInfoCard.kt @@ -69,7 +69,7 @@ fun NodeInfoCard(node: NodeInfo) { // Text("Node: ${it.user?.longName}") Row(modifier = LayoutPadding(16.dp)) { UserIcon( - modifier = LayoutPadding(left = 0.dp, top = 0.dp, right = 0.dp, bottom = 0.dp), + modifier = LayoutPadding(start = 0.dp, top = 0.dp, end = 0.dp, bottom = 0.dp), user = node ) diff --git a/app/src/main/java/com/geeksville/mesh/ui/Settings.kt b/app/src/main/java/com/geeksville/mesh/ui/Settings.kt index 2e065951..dbdb88de 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/Settings.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/Settings.kt @@ -1,7 +1,6 @@ package com.geeksville.mesh.ui import androidx.compose.Composable -import androidx.compose.ambient import androidx.compose.state import androidx.ui.core.ContextAmbient import androidx.ui.core.Text diff --git a/app/src/main/java/com/geeksville/mesh/ui/Vectors.kt b/app/src/main/java/com/geeksville/mesh/ui/Vectors.kt index 0ad6c10c..22fb0f5d 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/Vectors.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/Vectors.kt @@ -2,25 +2,23 @@ package com.geeksville.mesh.ui import androidx.annotation.DrawableRes import androidx.compose.Composable -import androidx.ui.core.DensityAmbient import androidx.ui.core.Modifier -import androidx.ui.foundation.Clickable +import androidx.ui.foundation.Icon import androidx.ui.graphics.Color import androidx.ui.graphics.vector.DrawVector import androidx.ui.layout.Container import androidx.ui.layout.LayoutSize -import androidx.ui.material.ripple.Ripple +import androidx.ui.material.IconButton import androidx.ui.res.vectorResource -import androidx.ui.unit.dp @Composable fun VectorImageButton(@DrawableRes id: Int, onClick: () -> Unit) { - Ripple(bounded = false) { - Clickable(onClick = onClick) { - VectorImage(id = id /* , modifier = LayoutSize(40.dp, 40.dp) */) - } + //Ripple(bounded = false) { + IconButton(onClick = onClick) { + Icon(vectorResource(id) /* , modifier = LayoutSize(40.dp, 40.dp) */) } + //} } /* fun AppBarIcon(icon: Image, onClick: () -> Unit) { @@ -40,13 +38,13 @@ fun VectorImage( ) { val vector = vectorResource(id) // WithDensity { - Container( - modifier = modifier + LayoutSize( - vector.defaultWidth, - vector.defaultHeight - ) - ) { - DrawVector(vector, tint) - } + Container( + modifier = modifier + LayoutSize( + vector.defaultWidth, + vector.defaultHeight + ) + ) { + DrawVector(vector, tint) + } // } } diff --git a/app/src/main/proto b/app/src/main/proto index e1a48b6e..f309ee8f 160000 --- a/app/src/main/proto +++ b/app/src/main/proto @@ -1 +1 @@ -Subproject commit e1a48b6e75c2ec3ad3995165a7b4fb64ce597e02 +Subproject commit f309ee8f9e9db37daabd7c76da683e052ef62f7a diff --git a/build.gradle b/build.gradle index 13557f96..c4072156 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { ext.kotlin_version = '1.3.61' - ext.compose_version = '0.1.0-dev05' + ext.compose_version = '0.1.0-dev06' repositories { google() jcenter() @@ -18,7 +18,7 @@ buildscript { // Check that you have the Google Services Gradle plugin v4.3.2 or later // (if not, add it). classpath 'com.google.gms:google-services:4.3.3' - classpath 'com.google.firebase:firebase-crashlytics-gradle:2.0.0-beta01' + classpath 'com.google.firebase:firebase-crashlytics-gradle:2.0.0-beta02' // protobuf plugin - docs here https://github.com/google/protobuf-gradle-plugin classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.11' diff --git a/debugging-android.md b/debugging-android.md new file mode 100644 index 00000000..bcb789b6 --- /dev/null +++ b/debugging-android.md @@ -0,0 +1,61 @@ +# Found a problem with our android app? + +Oops sorry about that ;-). Android sends us automated crash reports for some types of failures but not all failures. + +It would be super useful if you could help us by capturing a "logcat" file of the app while it was doing the bad thing and you attach that file to a github [issue](https://github.com/meshtastic/Meshtastic-Android/issues). + +Here's how to do that... + +Setup your phone & PC to allow debugging: + +* Install "adb" (android debug bridge). [Here's](https://lifehacker.com/the-easiest-way-to-install-androids-adb-and-fastboot-to-1586992378) +a tutorial I found on the web. Please let me know if it works for you. +* [Enable](https://www.howtogeek.com/129728/how-to-access-the-developer-options-menu-and-enable-usb-debugging-on-android-4.2/) +developer mode on your phone. The procedure might be slightly different for some phones, if necessary google for "enable developer mode YOURPHONENAME" +* Connect your phone to your PC USB port. A dialog on the phone will say "do you want to allow this PC to access debug mode on your phone?" +Say yes and also click the checkbox to always allow your PC access. +* type "adb devices" at your computer shell prompt, you should see your phone listed. If you see that ADB is working fine. + +* Long press on the meshtastic app and choose "force stop", to ensure that we are starting from scratch for this log (it will make it easier to understand it) +* If you have a Mac or Linux type: +``` +adb shell 'logcat --pid=$(pidof -s com.geeksville.mesh)' | tee newlogfile.txt +``` + +* If you have a PC type: +``` +adb shell "logcat --pid=$(pidof -s com.geeksville.mesh)" >newlogfile.txt (I don't know the equivalent of TEE for windows?) +``` + +This will capture a bunch of logging information as you use the app. Please go through the app to the part that was giving you troubles (No device listed on the settings screen etc). And then press +ctrl-c in the adb window to stop logging. Please open a github [issue](https://github.com/meshtastic/Meshtastic-Android/issues) describing the problem and attach the log file. We'll get back to you with what we find (possibly with some extra questions). + +``` +kevinh@kevin-server:~/development$ adb shell 'logcat --pid=$(pidof -s com.geeksville.mesh)' | +--------- beginning of main +03-07 17:10:05.669 13452 13452 W ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@fbf5fa0 +03-07 17:10:05.927 13452 13452 D com.geeksville.mesh.MainActivity: Checking permissions +03-07 17:10:06.033 13452 13452 W geeksville.mes: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (greylist, reflection, allowed) +03-07 17:10:06.034 13452 13452 W geeksville.mes: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (greylist, reflection, allowed) +03-07 17:10:06.179 13452 13452 D com.geeksville.mesh.MainActivity: Binding to mesh service! +03-07 17:10:06.267 13452 13484 I geeksville.mes: Background concurrent copying GC freed 18374(1149KB) AllocSpace objects, 5(164KB) LOS objects, 49% free, 2384KB/4769KB, paused 329us total 124.902ms +03-07 17:10:06.267 13452 13484 W geeksville.mes: Reducing the number of considered missed Gc histogram windows from 1692 to 100 +03-07 17:10:06.288 13452 24599 I FA : Tag Manager is not found and thus will not be used +03-07 17:10:06.500 13452 24593 I Adreno : QUALCOMM build : 4a00b69, I4e7e888065 +03-07 17:10:06.500 13452 24593 I Adreno : Build Date : 04/09/19 +03-07 17:10:06.500 13452 24593 I Adreno : OpenGL ES Shader Compiler Version: EV031.26.06.00 +03-07 17:10:06.500 13452 24593 I Adreno : Local Branch : mybranche95a5ea3-cf05-f19a-a0e7-5cb90179c3d8 +03-07 17:10:06.500 13452 24593 I Adreno : Remote Branch : quic/gfx-adreno.lnx.1.0 +03-07 17:10:06.500 13452 24593 I Adreno : Remote Branch : NONE +03-07 17:10:06.500 13452 24593 I Adreno : Reconstruct Branch : NOTHING +03-07 17:10:06.500 13452 24593 I Adreno : Build Config : S P 8.0.6 AArch64 +03-07 17:10:06.508 13452 24593 I Adreno : PFP: 0x016ee183, ME: 0x00000000 +03-07 17:10:06.546 13452 24593 W Gralloc3: mapper 3.x is not supported +03-07 17:10:06.548 13452 24593 E libc : Access denied finding property "vendor.gralloc.disable_ahardware_buffer" +03-07 17:10:06.544 13452 13452 W RenderThread: type=1400 audit(0.0:7134): avc: denied { read } for name="u:object_r:vendor_default_prop:s0" dev="tmpfs" ino=24620 scontext=u:r:untrusted_app:s0:c157,c257,c512,c768 tcontext=u:object_r:vendor_default_prop:s0 tclass=file permissive=0 +03-07 17:10:06.607 13452 13452 I com.geeksville.mesh.service.MeshService: in isConnected=false +03-07 17:10:06.608 13452 13452 D com.geeksville.mesh.MainActivity: connchange false +03-07 17:10:06.608 13452 13452 D com.geeksville.mesh.MainActivity$mesh$1: connected to mesh service, isConnected=false +03-07 17:10:06.609 13452 13452 D com.geeksville.mesh.ui.AnalyticsLog: logging screen view messages + +``` \ No newline at end of file diff --git a/geeksville-androidlib b/geeksville-androidlib index b9616763..188cf4fb 160000 --- a/geeksville-androidlib +++ b/geeksville-androidlib @@ -1 +1 @@ -Subproject commit b9616763f34cf5c09d8e0abe49fb79a5844ce27c +Subproject commit 188cf4fbb503ac0384f1fce4d3d3f0c2c9f07c02