diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 00000000..5f704c43 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 5806fb33..0dd4b354 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,7 +1,6 @@ - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 1dbd94dd..5000f8bd 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,18 +2,18 @@ - - - - - - - - - - + + + + + + + + + + - + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 37207a69..a6474934 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,8 @@ android { minSdkVersion 21 targetSdkVersion 28 // scheme for these version numbers: EPOCH MAJOR MINOR PATCH BUILD - versionCode 1_03_00_02_00 - versionName "3.0.2" + versionCode 1_03_01_00_03 + versionName "3.1.0" vectorDrawables.useSupportLibrary = false // no need for this since we're min SDK=21 @@ -65,6 +65,11 @@ android { androidExtensions { experimental = true } + + kotlinOptions { + jvmTarget = "1.8" + } + } diff --git a/app/src/main/java/io/particle/android/sdk/ui/FlashAppHelper.kt b/app/src/main/java/io/particle/android/sdk/ui/FlashAppHelper.kt index 02c299ef..bc3d2f5e 100644 --- a/app/src/main/java/io/particle/android/sdk/ui/FlashAppHelper.kt +++ b/app/src/main/java/io/particle/android/sdk/ui/FlashAppHelper.kt @@ -8,6 +8,7 @@ import androidx.fragment.app.FragmentActivity import io.particle.android.sdk.cloud.ParticleDevice import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.ARGON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.A_SOM +import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B5_SOM import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.BLUZ import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.BORON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B_SOM @@ -44,6 +45,7 @@ fun flashTinkerWithDialog( ARGON -> R.raw.tinker_firmware_080_rc27_argon BORON -> R.raw.tinker_firmware_080_rc27_boron XENON -> R.raw.tinker_firmware_080_rc27_xenon + B5_SOM -> R.raw.b5som_tinker_1_4_5_b5som_2 CORE -> { flashKnownAppWithDialog(activity, device, ParticleDevice.KnownApp.TINKER) diff --git a/app/src/main/java/io/particle/android/sdk/ui/devicelist/DeviceListTransformer.kt b/app/src/main/java/io/particle/android/sdk/ui/devicelist/DeviceListTransformer.kt index d63c204d..77d3888b 100644 --- a/app/src/main/java/io/particle/android/sdk/ui/devicelist/DeviceListTransformer.kt +++ b/app/src/main/java/io/particle/android/sdk/ui/devicelist/DeviceListTransformer.kt @@ -4,6 +4,7 @@ import io.particle.android.sdk.cloud.ParticleDevice import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.ARGON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.A_SOM +import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B5_SOM import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.BORON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B_SOM import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.ELECTRON @@ -37,7 +38,7 @@ enum class OnlineStatusFilter { } enum class DeviceTypeFilter { - BORON, // also B SoM + BORON, // also B SoM/B5 SoM ELECTRON, // also E SoM ARGON, // also A SoM PHOTON, // also P1 @@ -102,6 +103,7 @@ private fun ParticleDeviceType?.toDeviceTypeFilter(): DeviceTypeFilter { ARGON -> DeviceTypeFilter.ARGON B_SOM, + B5_SOM, BORON -> DeviceTypeFilter.BORON PHOTON, diff --git a/app/src/main/res/raw/b5som_tinker_1_4_5_b5som_2.bin b/app/src/main/res/raw/b5som_tinker_1_4_5_b5som_2.bin new file mode 100644 index 00000000..8def437e Binary files /dev/null and b/app/src/main/res/raw/b5som_tinker_1_4_5_b5som_2.bin differ diff --git a/app/src/main/res/values/tinker_strings.xml b/app/src/main/res/values/tinker_strings.xml new file mode 100644 index 00000000..9125b534 --- /dev/null +++ b/app/src/main/res/values/tinker_strings.xml @@ -0,0 +1,204 @@ + + + + <no name> + Cancel + Use + Flash + Copy to clipboard + Copy data to clipboard + Copy event to clipboard + Close + Yes + No + OK + Save + Clear All + Log out + Log in + Publish event + Share application logs + Argon / Boron / Xenon + Photon + Electron / SIM + v{version}b{build} + Skipping authentication will run Particle app in limited functionality mode - you would only be able to setup Wi-Fi credentials to Photon based devices but not claim them to your account nor use Tinker or device inspector. Are you sure you want to continue? + Get Started + API Base URL + Please enter Particle API Base URL + + Your Devices + Search devices… + Unknown + No devices + No devices found matching \'{searchTerm}\' + No devices found matching the current filter + photon_wifi.mp4 + SETUP button + Error + Error loading devices, please check your internet connection. + Warning + Device setup did not complete. + Error + Error while unclaiming device: {error} + Error + Error getting information from Particle Cloud + Authentication + You must be logged to your Particle account in to setup an Argon / Boron / Xenon + Authentication + You must be logged to your Particle account in to setup an Electron + Error + There was an error exporting application logs. + Success + Nice, you\'ve successfully set up your first Particle! You\'ll be receiving a welcome email with helpful tips and links to resources. Start developing by going to https://build.particle.io/ on your computer, or stay here and enjoy the magic of Tinker. + Success + Nice, you\'ve successfully set up your first Particle! You\'ll be receiving a welcome email with helpful tips and links to resources. Start developing by going to https://build.particle.io/ on your computer, or stay here and enjoy the magic of Tinker. + Success + You successfully setup the device Wi-Fi credentials. Verify its LED is breathing cyan. + Setup up a new device + Log out + Are you sure you want to log out? + Your devices + See and manage your devices.\n\nOnline devices have their indicator \'breathing\' cyan, offline ones are gray.\n\nTap a device to enter Device Inspector mode, device must run Tinker firmware to enter Tinker mode.\n\nSwipe left to remove a device from your account.\n\nPull down to refresh your list. + Setup a new device + Tap the plus button to set up a new Photon or Electron device you wish to add to your account + Unclaim + + Filters + Show {count} device + Show {count} devices + Online Status + Online + Offline + Sort By + Online Status + Device Type + Name + Last Heard + Device Type + Boron / B SoM + Electron / E SoM + Argon + Photon + Xenon + Other + + Whoops! + Looks like you are scanning the wrong sticker. Please scan the ICCID barcode that came with your SIM card. + + Events + Functions + Variables + Tinker + Flashing error + Error flashing device + Welcome to Device Inspector + See advanced information on your device. + Modes + Device inspector has 4 views:\n\nEvents - view a real-time searchable list of published events.\n\nFunctions - interact with your device\'s functions.\n\nVariables - interact with your device\'s variables.\n\nTinker - control pin behavior for your device + Additional actions + Tap the Control Panel button to access advanced actions. + + Online + Offline + Flashing + Signal Device + Notes + Name + Use this space to keep notes on this device. Add or edit them. + Ping + Pinging device + The Particle Cloud has sent a ping to this device. It will wait up to 15 seconds to hear back. + Success + This device is online and connected! + Copied + {label} value was copied to the clipboard + Error + This device was unreachable by the Particle cloud within 15 seconds. The device may be powered off, or may be having trouble connecting to the Particle Cloud. + Error + Error renaming device: {error} + Error + Error editing notes device: {error} + Type + ID + Serial + Last ICCID + IMEI + Last Heard + Last IP Address + Device OS + Unknown + Never + + Search events… + No events + Clear all events + All events data will be deleted. Are you sure? + Copied + Event data was copied to the clipboard + Copied + Event payload was copied to the clipboard + Device Events + This is a searchable log of the events your device published to the cloud. Tap the blue clipboard button to copy event payload to your clipboard. + Search events + Tap filter text field and type text to filter the events list and show only events containing the search text. Filtering is performed on event name and data. + Play and pause + Tap play/pause button to pause the events stream momentarily. Events published while stream is paused will not be added to the list. + Event + Data + Time + + Publish an event + Name + Value + Event visibility: + Private + Public + Failed to publish event \'{name}\' + + No exposed functions + Device is offline + (Arguments) + Error + + Sending argument failed. + + Device Functions + Tap the function cell to access the arguments box. Type in function arguments (comma separated if more than one) and tap send or the function name to call it. + Device offline + Device is offline. To execute functions device must be online. + No exposed variables + Device is offline + Error + + Device Variables + Simply tap a variable name to read its current value. Tap any long variable value to show a popup with the full string value in case it has been truncated. + Device offline + Device is offline. To update variable values device must be online. + Copy to clipboard + Copied + Variable value was copied to the clipboard + Device is offline + To enable Tinker, you need to flash the Tinker firmware to this device. + FLASH TINKER + analogRead + analogWrite + digitalRead + digitalWrite + HIGH + LOW + Flash Tinker? + Flashing will overwrite the application firmware on your Particle device with the Tinker app. + Welcome to Tinker! + Tinker is the fastest and easiest way to prototype and play with your Particle device. Access the basic input/output functions of the device pins without writing a line of code. + Blink the onboard LED + Tap any pin to get started. Start with pin D7 - select \'digitalWrite\' and tap the pin, see what happens on your device. You\'ve just flashed an LED over the internet! Reset any pin function by long-pressing it. + Flashing error + Error flashing device: {error} + Reflash Tinker + App does not support flashing tinker to this device. + Error + There was an error while reading value of {pin} pin. + Error + There was an error while updating value of {pin} pin. + diff --git a/build.gradle b/build.gradle index ec7ef8c5..8c909dcf 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { - ext.kotlin_version = '1.3.61' + ext.kotlin_version = '1.3.72' repositories { google() @@ -10,13 +10,13 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.5.3' + classpath 'com.android.tools.build:gradle:4.0.0-rc01' classpath 'com.google.gms:google-services:4.3.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.1.0" classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' - classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.0' + classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.1' } } diff --git a/cloudsdk/build.gradle b/cloudsdk/build.gradle index 08aff37d..fe3e7c58 100644 --- a/cloudsdk/build.gradle +++ b/cloudsdk/build.gradle @@ -75,6 +75,9 @@ android { experimental = true } + kotlinOptions { + jvmTarget = "1.8" + } } dependencies { @@ -123,7 +126,6 @@ jacoco { coveralls { jacocoReportPath 'build/reports/jacocoTestReport/jacocoTestReport.xml' } - task jacocoTestReport(type: JacocoReport, dependsOn: "testDebugUnitTest") { group = "Reporting" description = "Generate Jacoco code coverage reports for debug builds" @@ -155,7 +157,11 @@ task jacocoTestReport(type: JacocoReport, dependsOn: "testDebugUnitTest") { excludes: excludes) def mainSrc = "${project.projectDir}/src/main/java" - classDirectories = files([debugTree], [kotlinDebugTree]) - executionData = files("$buildDir/jacoco/testDebugUnitTest.exec") - sourceDirectories = files([mainSrc]) +// classDirectories = files([debugTree], [kotlinDebugTree]) + getClassDirectories().setFrom(files([debugTree], [kotlinDebugTree])) +// executionData = files("$buildDir/jacoco/testDebugUnitTest.exec") + getExecutionData().setFrom(files("$buildDir/jacoco/testDebugUnitTest.exec")) +// sourceDirectories = files([mainSrc]) + getSourceDirectories().setFrom(files([mainSrc])) } + diff --git a/cloudsdk/src/main/java/io/particle/android/sdk/cloud/ApiFactory.java b/cloudsdk/src/main/java/io/particle/android/sdk/cloud/ApiFactory.java index dcfec1c1..7d050255 100644 --- a/cloudsdk/src/main/java/io/particle/android/sdk/cloud/ApiFactory.java +++ b/cloudsdk/src/main/java/io/particle/android/sdk/cloud/ApiFactory.java @@ -14,6 +14,7 @@ import javax.annotation.ParametersAreNonnullByDefault; import okio.ByteString; +import retrofit.RequestInterceptor.RequestFacade; import retrofit.RestAdapter; import retrofit.RestAdapter.Log; import retrofit.RestAdapter.LogLevel; @@ -78,8 +79,10 @@ private static OkHttpClient buildClientWithTimeout(int timeoutInSeconds) { ApiDefs.CloudApi buildNewCloudApi() { RestAdapter restAdapter = buildCommonRestAdapterBuilder(gson, normalTimeoutClient) - .setRequestInterceptor(request -> request.addHeader("Authorization", "Bearer " + - tokenDelegate.getTokenValue())) + .setRequestInterceptor(request -> { + request.addHeader("Authorization", "Bearer " + tokenDelegate.getTokenValue()); + addParticleToolsHeader(request); + }) .build(); return restAdapter.create(ApiDefs.CloudApi.class); } @@ -88,7 +91,10 @@ ApiDefs.IdentityApi buildNewIdentityApi() { final String basicAuthValue = getBasicAuthValue(); RestAdapter restAdapter = buildCommonRestAdapterBuilder(gson, normalTimeoutClient) - .setRequestInterceptor(request -> request.addHeader("Authorization", basicAuthValue)) + .setRequestInterceptor(request -> { + request.addHeader("Authorization", basicAuthValue); + addParticleToolsHeader(request); + }) .build(); return restAdapter.create(ApiDefs.IdentityApi.class); } @@ -109,6 +115,10 @@ private String getBasicAuthValue() { return "Basic " + authBytes.base64(); } + private void addParticleToolsHeader(RequestFacade request) { + request.addHeader("X-Particle-Tool", "android-cloud-sdk"); + } + private RestAdapter.Builder buildCommonRestAdapterBuilder(Gson gson, OkHttpClient client) { return new RestAdapter.Builder() .setClient(new OkClient(client)) diff --git a/cloudsdk/src/main/java/io/particle/android/sdk/cloud/ParticleDevice.kt b/cloudsdk/src/main/java/io/particle/android/sdk/cloud/ParticleDevice.kt index c6ab9007..6a654c21 100644 --- a/cloudsdk/src/main/java/io/particle/android/sdk/cloud/ParticleDevice.kt +++ b/cloudsdk/src/main/java/io/particle/android/sdk/cloud/ParticleDevice.kt @@ -187,7 +187,8 @@ class ParticleDevice internal constructor( XENON(14), A_SOM(22), B_SOM(23), - X_SOM(24); + X_SOM(24), + B5_SOM(25); companion object { diff --git a/commonui/build.gradle b/commonui/build.gradle index 845865a8..b2d2fe2e 100644 --- a/commonui/build.gradle +++ b/commonui/build.gradle @@ -33,6 +33,10 @@ android { exclude 'META-INF/main.kotlin_module' } + kotlinOptions { + jvmTarget = "1.8" + } + } dependencies { diff --git a/commonui/src/main/java/io/particle/commonui/DeviceDecorations.kt b/commonui/src/main/java/io/particle/commonui/DeviceDecorations.kt index 06395bc6..4b148dbc 100644 --- a/commonui/src/main/java/io/particle/commonui/DeviceDecorations.kt +++ b/commonui/src/main/java/io/particle/commonui/DeviceDecorations.kt @@ -8,6 +8,7 @@ import androidx.core.graphics.drawable.DrawableCompat import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.ARGON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.A_SOM +import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B5_SOM import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.BLUZ import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.BORON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B_SOM @@ -48,7 +49,7 @@ fun ParticleDeviceType.toDecorationColor(): Int { ARGON, A_SOM -> R.color.spark_blue - BORON, B_SOM -> R.color.device_color_boron + BORON, B_SOM, B5_SOM -> R.color.device_color_boron XENON, X_SOM -> R.color.device_color_xenon @@ -76,7 +77,8 @@ fun ParticleDeviceType.toDecorationLetter(): String { ARGON, A_SOM -> "A" BORON, - B_SOM -> "B" + B_SOM, + B5_SOM -> "B" XENON, X_SOM -> "X" DIGISTUMP_OAK, diff --git a/commonui/src/main/java/io/particle/commonui/Devices.kt b/commonui/src/main/java/io/particle/commonui/Devices.kt index c21e86bd..4e2d8ef7 100644 --- a/commonui/src/main/java/io/particle/commonui/Devices.kt +++ b/commonui/src/main/java/io/particle/commonui/Devices.kt @@ -5,6 +5,7 @@ import androidx.annotation.StringRes import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.ARGON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.A_SOM +import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B5_SOM import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.BLUZ import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.BORON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B_SOM @@ -52,7 +53,8 @@ private val ParticleDeviceType.productImageAndName: ProductImageAndName BORON -> pian(R.string.product_name_boron, R.drawable.product_image_boron) - B_SOM -> pian(R.string.product_name_b_series, R.drawable.product_image_boron) + B_SOM, + B5_SOM -> pian(R.string.product_name_b_series, R.drawable.product_image_boron) XENON -> pian(R.string.product_name_xenon, R.drawable.product_image_xenon) diff --git a/devicesetup/build.gradle b/devicesetup/build.gradle index 6ba3a17a..876146e3 100644 --- a/devicesetup/build.gradle +++ b/devicesetup/build.gradle @@ -73,11 +73,11 @@ dependencies { api 'com.segment.analytics.android:analytics:4.3.1' api 'com.madgag.spongycastle:core:1.58.0.0' - api 'com.google.dagger:dagger:2.24' - annotationProcessor 'com.google.dagger:dagger-compiler:2.24' + api 'com.google.dagger:dagger:2.27' + annotationProcessor 'com.google.dagger:dagger-compiler:2.27' - api 'com.jakewharton:butterknife:10.2.0' - annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.0' + api 'com.jakewharton:butterknife:10.2.1' + annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1' api 'androidx.appcompat:appcompat:1.1.0' api 'androidx.recyclerview:recyclerview:1.0.0' diff --git a/devicesetup/src/main/res/values/particle_setup_strings.xml b/devicesetup/src/main/res/values/particle_setup_strings.xml new file mode 100644 index 00000000..68d45e1f --- /dev/null +++ b/devicesetup/src/main/res/values/particle_setup_strings.xml @@ -0,0 +1,200 @@ + + + + Cancel + Log out + Open + Yes + No + Ok + Understood + Exit setup + Could not retrieve public key from device + Could not store public key in device keychain + Skipping authentication will allow you to configure Wi-Fi credentials to your device but it will not be claimed to your account. Are you sure you want to skip authentication? + Particle device + Setup button + blue + https://www.particle.io/legal/privacy + https://www.particle.io/legal/terms-of-service + https://login.particle.io/forgot + https://community.spark.io/t/spark-core-troubleshooting-guide-spark-team/696 + Create account + email + password + verify password + first name + last name + company name + This is a business account + This is a personal account + By clicking \"SIGN UP\" you are indicating that you have read and agreed to the + Terms of Service + and + Privacy Policy + SIGN UP + Skip authentication + I already have a {brand} account + Error + Password must be at least 8 characters long + Error + Passwords do not match + Could not signup + Make sure your user email does not already exist and that you have entered the activation code correctly and that it was not already used. + Error + Invalid email address + Error + {error} + Skip Authentication + Your account + email + password + LOG IN + I forgot my password + I don\'t have a {brand} account + Skip authentication + Cannot Sign In + Invalid email address + Cannot Sign In + {error} + Cannot Sign In + Password cannot be blank + Skip Authentication + + Request password reset + An email will be sent to you with a link to a webpage where you can create a new password. + email + I remember my password + RESET PASSWORD + Reset password + Instructions on how to reset your password will be sent to the provided email address. Please check your email and continue according to the instructions. + Reset password + Invalid email address + Reset password + Could not find a user with supplied email address, please check the address supplied or create a new user via the signup screen + + Enter a login code + Open your authenticator app on your mobile device and enter the 6-digit login code + login code + VERIFY + Lost access to your phone? Recover your account. + Error + Please enter the code. + Two-step Authentication Error + {error} + Time to set up your {device}! + Plug in your {device} to power it on + The on-board LED should be blinking blue. If not, hold the {mode_button} for 3 seconds + Make sure your {os_name} device is connected to the Internet + Scroll down for more instructions:\n{instructions} + READY + Log in + Error + {error} + Access denied + Sorry, you must be logged in as a {brand} customer. + Error + Could not communicate with Particle cloud. Make sure your {os_name} device is connected to the internet and retry.\n\n{error} + Error + Could not communicate with Particle cloud. Are you sure your organization and product slugs are setup correctly?\n\n{error} + Log out + Are you sure you want to log out? + + Permission to read WIFI SSID + Photon setup reads current Wi-Fi SSID to determine when your phone connects to a device.\n\nStarting iOS 13, for apps to have access to Wi-Fi SSID information, user must grant location services permission.\n\nParticle app will only use this permission to read Wi-Fi SSID and not to track your location. + + Location services required + Location services are required to pair your Android device with your Photon to complete the setup process. Particle will not use your location data for any other purposes. + Enable Location + + Wi-Fi required + Wi-Fi is required to pair your Android device with your Photon to complete the setup process. + Enable Wi-Fi + + (No {device} devices found) + Connecting to {device} + + The Location permission has been disabled for this app. Please change this in Permissions for this app under Settings → Apps. The Particle app will only use this permission to read Wi-Fi SSID and not to track your location. + Photon setup reads current Wi-Fi SSID to determine when your phone connects to a device.\n\nStarting iOS 13, for apps to have access to Wi-Fi SSID information, user must grant location services permission.\n\nYou have previously denied Particle application permission to access location services. Please grant the permission in Settings app.\n\nParticle app will only use this permission to read Wi-Fi SSID and not to track your location. + GRANT PERMISSION + OPEN SETTINGS + + Choose your {device} + {device} not listed here? Hold the {mode_button} for three seconds to put it in setup mode; the indicator light should turn blue + You are logged in as: {username} + + Error connecting + Please try running setup again after resetting your {device} and putting it back in blinking blue listen mode if needed. + + + + Tap Home > Settings > Wi-Fi + Make sure Wi-Fi is turned on, and choose the network below: + Once connected, return to this app + {network prefix}-XXXX + XXXX will be a unique 4-digit code + SHOW ME HOW + Connected + Your phone has connected to {deviceName}. Tap to continue Setup. + Product ownership + Do you want to claim ownership of this {deviceName} to {userName} + Change owner + + Select your Wi-Fi network + My network is not listed + REFRESH + + Enterprise Wi-Fi networks not supported for mobile setup. + (No Wi-Fi networks found) + + Manual network name + Network requires password + Network name + CONNECT + Secured network password + Password + Hide password + CONNECT + + Secured with WEP + Secured with WPA + Secured with WPA2 + + + Invalid password + Password must be {length} characters or longer + + Connecting + + Your {device} is connecting to: + This can take about a minute. + Configure Wi-Fi credentials + Connect to Wi-Fi network + Wait for device cloud connection + Check for internet connectivity + Verify device ownership + Setup completed successfully + Congrats! You\'ve successfully set up your {device}. + Setup completed + Your device has been successfully claimed to your account, however it is offline. If the device was already claimed before this setup, then the Wi-Fi connection may have failed, and you should try setup again. + Setup completed + Setup was successful, but since you do not own this device we cannot know if the {device} has connected to the Internet. If you see the LED breathing cyan this means it worked! If not, please restart the setup process. + Setup failed + Setup process failed at claiming your {device}, if your {device} LED is blinking in blue or green this means that you provided wrong Wi-Fi credentials, please try setup process again. + Oops! + Setup process couldn\'t disconnect from the {device} Wi-fi network. This is an internal problem with the device, so please try running setup again after resetting your {device} and putting it back in listen mode (blinking blue LED) if needed. + Error! + Setup process couldn\'t configure the Wi-Fi credentials for your {device}, please try running setup again after resetting your {device} and putting it back in blinking blue listen mode if needed. + Uh oh! + Setup lost connection to the device before finalizing configuration process, please try running setup again after putting {device} back in blinking blue listen mode. + Firmware update + If this is the first time you are setting up this device it might blink its LED in magenta color for a while, this means the device is currently updating its firmware from the cloud to the latest version. Please be patient and do not press the reset button. Device LED will breathe cyan once update has completed and it has come online. + Name your new device: + DeviceNamePlaceholder + + This field is required + Failed to change device name + + DONE + Troubleshooting + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c12d914b..594c724d 100755 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip diff --git a/mesh/src/main/java/io/particle/mesh/setup/BarcodeData.kt b/mesh/src/main/java/io/particle/mesh/setup/BarcodeData.kt index a4464dd6..ee669ff5 100644 --- a/mesh/src/main/java/io/particle/mesh/setup/BarcodeData.kt +++ b/mesh/src/main/java/io/particle/mesh/setup/BarcodeData.kt @@ -5,6 +5,7 @@ import io.particle.android.sdk.cloud.ParticleCloud import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.ARGON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.A_SOM +import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B5_SOM import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.BLUZ import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.BORON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B_SOM @@ -48,7 +49,8 @@ fun ParticleDeviceType.toConnectivityType(): Gen3ConnectivityType { ELECTRON, BORON, - B_SOM -> CELLULAR + B_SOM, + B5_SOM -> CELLULAR XENON, X_SOM -> MESH_ONLY diff --git a/mesh/src/main/java/io/particle/mesh/setup/Constants.kt b/mesh/src/main/java/io/particle/mesh/setup/Constants.kt deleted file mode 100644 index f8160353..00000000 --- a/mesh/src/main/java/io/particle/mesh/setup/Constants.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.particle.mesh.setup - - -val ARGON_SERIAL_PREFIXES = listOf("ARGH", "ARNH", "ARNK") -val XENON_SERIAL_PREFIXES = listOf("XENH", "XENK") -val BORON_SERIAL_PREFIXES = listOf("B40H", "B40K", "B31H", "B31K") -val B_SERIES_SERIAL_PREFIXES = listOf("P001", "P002") -val A_SERIES_SERIAL_PREFIXES = listOf("P003") -val X_SERIES_SERIAL_PREFIXES = listOf("P004") diff --git a/mesh/src/main/java/io/particle/mesh/setup/SerialNumbers.kt b/mesh/src/main/java/io/particle/mesh/setup/SerialNumbers.kt index 0f832ca3..6d66ff7a 100644 --- a/mesh/src/main/java/io/particle/mesh/setup/SerialNumbers.kt +++ b/mesh/src/main/java/io/particle/mesh/setup/SerialNumbers.kt @@ -4,7 +4,6 @@ import androidx.annotation.WorkerThread import io.particle.android.sdk.cloud.ParticleCloud import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType import mu.KotlinLogging -import java.util.* private val log = KotlinLogging.logger {} @@ -16,29 +15,5 @@ inline class SerialNumber(val value: String) @WorkerThread fun SerialNumber.toDeviceType(cloud: ParticleCloud): ParticleDeviceType { - - fun SerialNumber.toDeviceType(): ParticleDeviceType { - return when (this.value.take(4)) { - in ARGON_SERIAL_PREFIXES -> ParticleDeviceType.ARGON - in BORON_SERIAL_PREFIXES -> ParticleDeviceType.BORON - in XENON_SERIAL_PREFIXES -> ParticleDeviceType.XENON - in A_SERIES_SERIAL_PREFIXES -> ParticleDeviceType.A_SOM - in B_SERIES_SERIAL_PREFIXES -> ParticleDeviceType.B_SOM - in X_SERIES_SERIAL_PREFIXES -> ParticleDeviceType.X_SOM - else -> throw IllegalArgumentException("Invalid serial number from barcode: $this") - } - } - - var gotTypeFromCloud = false - val dt = try { - this.toDeviceType() - } catch (badArg: IllegalArgumentException) { - gotTypeFromCloud = true - cloud.getPlatformId(this.value) - } - - val source = if (gotTypeFromCloud) "cloud" else "local serial number lookup" - log.info { "Retrieved device type $dt from $source" } - - return dt + return cloud.getPlatformId(this.value) } diff --git a/mesh/src/main/java/io/particle/mesh/setup/connection/ProtocolTransceiver.kt b/mesh/src/main/java/io/particle/mesh/setup/connection/ProtocolTransceiver.kt index a5694b27..09cb5f62 100644 --- a/mesh/src/main/java/io/particle/mesh/setup/connection/ProtocolTransceiver.kt +++ b/mesh/src/main/java/io/particle/mesh/setup/connection/ProtocolTransceiver.kt @@ -248,11 +248,6 @@ class ProtocolTransceiver internal constructor( return buildResult(response) { r -> GetInterfaceReply.parseFrom(r.payloadData) } } - suspend fun sendGetInterfaceList(): Result { - val response = sendRequest(GetInterfaceListRequest.newBuilder().build()) - return buildResult(response) { r -> GetInterfaceListReply.parseFrom(r.payloadData) } - } - suspend fun sendStartListeningMode(): Result { val response = sendRequest(StartListeningModeRequest.newBuilder().build()) return buildResult(response) { r -> StartListeningModeReply.parseFrom(r.payloadData) } @@ -458,6 +453,11 @@ class ProtocolTransceiver internal constructor( return buildResult(response) { r -> StopNyanSignalReply.parseFrom(r.payloadData) } } + suspend fun sendGetInterfaceList(): Result { + val response = sendRequest(GetInterfaceListRequest.newBuilder().build()) + return buildResult(response) { r -> GetInterfaceListReply.parseFrom(r.payloadData) } + } + internal fun receiveResponse(responseFrame: DeviceResponse) { val callback = requestCallbacks[responseFrame.requestId.toInt()] if (callback != null) { diff --git a/mesh/src/main/java/io/particle/mesh/setup/flow/DeviceConnector.kt b/mesh/src/main/java/io/particle/mesh/setup/flow/DeviceConnector.kt index e2852e85..f07b9add 100644 --- a/mesh/src/main/java/io/particle/mesh/setup/flow/DeviceConnector.kt +++ b/mesh/src/main/java/io/particle/mesh/setup/flow/DeviceConnector.kt @@ -6,6 +6,7 @@ import io.particle.android.sdk.cloud.ParticleCloud import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.ARGON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.A_SOM +import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B5_SOM import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.BORON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B_SOM import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.XENON @@ -128,7 +129,8 @@ class DeviceConnector( ARGON, A_SOM -> "Argon" BORON, - B_SOM -> "Boron" + B_SOM, + B5_SOM -> "Boron" XENON, X_SOM -> "Xenon" else -> throw IllegalArgumentException("Not a mesh device: $deviceType") diff --git a/mesh/src/main/java/io/particle/mesh/setup/flow/FlowUtils.kt b/mesh/src/main/java/io/particle/mesh/setup/flow/FlowUtils.kt index 90c49751..bf5c93fa 100644 --- a/mesh/src/main/java/io/particle/mesh/setup/flow/FlowUtils.kt +++ b/mesh/src/main/java/io/particle/mesh/setup/flow/FlowUtils.kt @@ -4,6 +4,7 @@ import androidx.annotation.StringRes import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.ARGON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.A_SOM +import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B5_SOM import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.BORON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B_SOM import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.XENON @@ -25,6 +26,7 @@ fun ParticleDeviceType.toUserFacingName(): Int { XENON -> R.string.product_name_xenon A_SOM -> R.string.product_name_a_series B_SOM -> R.string.product_name_b_series + B5_SOM -> R.string.product_name_b5_som X_SOM -> R.string.product_name_x_series else -> throw IllegalArgumentException("Not a mesh device: $this") } diff --git a/mesh/src/main/java/io/particle/mesh/setup/flow/MeshFlowExecutor.kt b/mesh/src/main/java/io/particle/mesh/setup/flow/MeshFlowExecutor.kt index 07df00ec..d8637787 100644 --- a/mesh/src/main/java/io/particle/mesh/setup/flow/MeshFlowExecutor.kt +++ b/mesh/src/main/java/io/particle/mesh/setup/flow/MeshFlowExecutor.kt @@ -186,6 +186,7 @@ class MeshFlowExecutor( StepEnsureLatestFirmware(deps.flowUi, deps.firmwareUpdateManager), StepStopSignal(), StepFetchDeviceId(), + StepCheckTargetDeviceHasThreadInterface(), StepGetAPINetworks(deps.cloud), StepCheckIfTargetDeviceShouldBeClaimed(deps.cloud, deps.flowUi), StepEnsureTargetDeviceIsNotOnMeshNetwork(deps.cloud, deps.dialogTool), @@ -201,6 +202,7 @@ class MeshFlowExecutor( StepEnsureLatestFirmware(deps.flowUi, deps.firmwareUpdateManager), StepStopSignal(), StepFetchDeviceId(), + StepCheckTargetDeviceHasThreadInterface(), StepGetAPINetworks(deps.cloud), StepShowTargetPairingSuccessful(deps.flowUi), StepDetermineFlowAfterPreflow(deps.flowUi) @@ -277,7 +279,7 @@ class MeshFlowExecutor( CELLULAR_FLOW -> listOf( StepEnsureCardOnFile(deps.flowUi, deps.cloud), - StepFetchIccid(), + StepFetchIccid(deps.flowUi), StepEnsureSimActivationStatusUpdated(deps.cloud), StepShowPricingImpact(deps.flowUi, deps.cloud), StepShowShouldConnectToDeviceCloudConfirmation(deps.flowUi), diff --git a/mesh/src/main/java/io/particle/mesh/setup/flow/MeshFlowRunner.kt b/mesh/src/main/java/io/particle/mesh/setup/flow/MeshFlowRunner.kt index c44d368d..b0bc3dcd 100644 --- a/mesh/src/main/java/io/particle/mesh/setup/flow/MeshFlowRunner.kt +++ b/mesh/src/main/java/io/particle/mesh/setup/flow/MeshFlowRunner.kt @@ -450,7 +450,7 @@ class MeshFlowRunner( log.info { "endCurrentFlow()" } deps.flowUi.showGlobalProgressSpinner(false) flowExecutor.contexts?.let { - log.info { "Clearing state and cancelling scopes..." } + log.info { "Clearing state & cancelling scopes..." } it.clearState() } } diff --git a/mesh/src/main/java/io/particle/mesh/setup/flow/context/MeshContext.kt b/mesh/src/main/java/io/particle/mesh/setup/flow/context/MeshContext.kt index 0cee60c2..c2393d00 100644 --- a/mesh/src/main/java/io/particle/mesh/setup/flow/context/MeshContext.kt +++ b/mesh/src/main/java/io/particle/mesh/setup/flow/context/MeshContext.kt @@ -32,6 +32,7 @@ class MeshContext : Clearable { var newNetworkCreatedSuccessfully by log.logged(false) var checkedForExistingNetwork by log.logged(false) var currentlyJoinedNetwork: Mesh.NetworkInfo? by log.logged() + var hasThreadInterface: Boolean? by log.logged() override fun clearState() { log.info { "clearState()" } @@ -56,6 +57,7 @@ class MeshContext : Clearable { showNewNetworkOptionInScanner = false shownNetworkPasswordUi = false currentlyJoinedNetwork = null + hasThreadInterface = null } fun updateSelectedMeshNetworkToJoin(meshNetworkToJoin: Mesh.NetworkInfo) { diff --git a/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepCheckTargetDeviceHasNetworkInterfaces.kt b/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepCheckTargetDeviceHasNetworkInterfaces.kt deleted file mode 100644 index f321fd74..00000000 --- a/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepCheckTargetDeviceHasNetworkInterfaces.kt +++ /dev/null @@ -1,27 +0,0 @@ -package io.particle.mesh.setup.flow.setupsteps - -import io.particle.mesh.setup.flow.MeshSetupStep -import io.particle.mesh.setup.flow.Scopes -import io.particle.mesh.setup.flow.context.SetupContexts - - -class StepCheckTargetDeviceHasNetworkInterfaces : MeshSetupStep() { - - override suspend fun doRunStep(ctxs: SetupContexts, scopes: Scopes) { - - TODO() - -// if (context.targetDevice.activeInternetInterface == nil) { -// getActiveInternetInterface() -// } else if (context.targetDevice.activeInternetInterface! == .ppp && context.targetDevice.externalSim == nil) { -// getTargetDeviceActiveSim() -// } else if (context.targetDevice.activeInternetInterface! == .ppp && context.targetDevice.deviceICCID == nil) { -// getTargetDeviceICCID() -// } else if (context.targetDevice.activeInternetInterface! == .ppp && context.targetDevice.simActive == nil) { -// getSimInfo() -// } else { -// stepCompleted() -// } - } - -} \ No newline at end of file diff --git a/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepCheckTargetDeviceHasThreadInterface.kt b/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepCheckTargetDeviceHasThreadInterface.kt new file mode 100644 index 00000000..1e732f7c --- /dev/null +++ b/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepCheckTargetDeviceHasThreadInterface.kt @@ -0,0 +1,31 @@ +package io.particle.mesh.setup.flow.setupsteps + +import io.particle.firmwareprotos.ctrl.Network.InterfaceType +import io.particle.mesh.common.Result.Absent +import io.particle.mesh.common.Result.Error +import io.particle.mesh.common.Result.Present +import io.particle.mesh.setup.flow.MeshSetupStep +import io.particle.mesh.setup.flow.Scopes +import io.particle.mesh.setup.flow.context.SetupContexts +import io.particle.mesh.setup.flow.throwOnErrorOrAbsent +import mu.KotlinLogging + + +class StepCheckTargetDeviceHasThreadInterface : MeshSetupStep() { + + private val log = KotlinLogging.logger {} + + override suspend fun doRunStep(ctxs: SetupContexts, scopes: Scopes) { + if (ctxs.mesh.hasThreadInterface != null) { + return + } + + val response = ctxs.requireTargetXceiver().sendGetInterfaceList().throwOnErrorOrAbsent() + val hasThreadInterface = null != response.interfacesList.firstOrNull { + it.type == InterfaceType.THREAD + } + + ctxs.mesh.hasThreadInterface = hasThreadInterface + } + +} \ No newline at end of file diff --git a/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepDetermineFlowAfterPreflow.kt b/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepDetermineFlowAfterPreflow.kt index 604703de..9d6e48a4 100644 --- a/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepDetermineFlowAfterPreflow.kt +++ b/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepDetermineFlowAfterPreflow.kt @@ -3,6 +3,7 @@ package io.particle.mesh.setup.flow.setupsteps import androidx.annotation.WorkerThread import io.particle.firmwareprotos.ctrl.Network.InterfaceEntry import io.particle.firmwareprotos.ctrl.Network.InterfaceType +import io.particle.mesh.common.android.livedata.awaitUpdate import io.particle.mesh.common.android.livedata.nonNull import io.particle.mesh.common.android.livedata.runBlockOnUiThreadAndAwaitUpdate import io.particle.mesh.setup.flow.* @@ -67,6 +68,15 @@ class StepDetermineFlowAfterPreflow(private val flowUi: FlowUiDelegate) : MeshSe ctxs: SetupContexts, scopes: Scopes ): List { + if (ctxs.mesh.hasThreadInterface != true) { + ctxs.device.networkSetupTypeLD.nonNull(scopes).runBlockOnUiThreadAndAwaitUpdate { + log.info { + "No Thread interface on target device; forcing network setup type to STANDALONE" + } + ctxs.device.updateNetworkSetupType(STANDALONE) + } + } + determineNetworkSetupType(ctxs, scopes) if (ctxs.device.networkSetupTypeLD.value!! == NetworkSetupType.NODE_JOINER) { diff --git a/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepEnsureTargetDeviceIsNotOnMeshNetwork.kt b/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepEnsureTargetDeviceIsNotOnMeshNetwork.kt index a31e3c20..5319586e 100644 --- a/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepEnsureTargetDeviceIsNotOnMeshNetwork.kt +++ b/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepEnsureTargetDeviceIsNotOnMeshNetwork.kt @@ -22,7 +22,10 @@ class StepEnsureTargetDeviceIsNotOnMeshNetwork( private val log = KotlinLogging.logger {} override suspend fun doRunStep(ctxs: SetupContexts, scopes: Scopes) { - if (ctxs.mesh.checkedForExistingNetwork || ctxs.flowIntent != FlowIntent.FIRST_TIME_SETUP) { + if (ctxs.mesh.checkedForExistingNetwork + || ctxs.flowIntent != FlowIntent.FIRST_TIME_SETUP + || ctxs.mesh.hasThreadInterface == false + ) { return } diff --git a/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepFetchIccid.kt b/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepFetchIccid.kt index 8912aa6f..898b4645 100644 --- a/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepFetchIccid.kt +++ b/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepFetchIccid.kt @@ -3,6 +3,7 @@ package io.particle.mesh.setup.flow.setupsteps import io.particle.mesh.common.Result import io.particle.mesh.common.truthy import io.particle.mesh.setup.connection.ResultCode +import io.particle.mesh.setup.flow.FlowUiDelegate import io.particle.mesh.setup.flow.MeshSetupFlowException import io.particle.mesh.setup.flow.MeshSetupStep import io.particle.mesh.setup.flow.Scopes @@ -10,15 +11,18 @@ import io.particle.mesh.setup.flow.context.SetupContexts import kotlinx.coroutines.delay -class StepFetchIccid : MeshSetupStep() { +class StepFetchIccid(private val flowUi: FlowUiDelegate) : MeshSetupStep() { override suspend fun doRunStep(ctxs: SetupContexts, scopes: Scopes) { if (ctxs.targetDevice.iccid.truthy()) { return } + + val targetXceiver = ctxs.requireTargetXceiver() + flowUi.showGlobalProgressSpinner(true) val iccidReply = targetXceiver.sendGetIccId() when (iccidReply) { is Result.Present -> { diff --git a/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepGetAPINetworks.kt b/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepGetAPINetworks.kt index a960cb71..087d751d 100644 --- a/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepGetAPINetworks.kt +++ b/mesh/src/main/java/io/particle/mesh/setup/flow/setupsteps/StepGetAPINetworks.kt @@ -12,6 +12,11 @@ class StepGetAPINetworks(private val cloud: ParticleCloud) : MeshSetupStep() { @WorkerThread override suspend fun doRunStep(ctxs: SetupContexts, scopes: Scopes) { + // don't bother with this for non-mesh devices + if (ctxs.mesh.hasThreadInterface == false) { + return + } + val networks = cloud.getNetworks() ctxs.cloud.apiNetworks = networks } diff --git a/mesh/src/main/res/values/mesh_strings.xml b/mesh/src/main/res/values/mesh_strings.xml new file mode 100644 index 00000000..e1559f2d --- /dev/null +++ b/mesh/src/main/res/values/mesh_strings.xml @@ -0,0 +1,392 @@ + + + Press and hold the MODE button for 3 seconds + Assisting device blinking blue + Find a device that is already on the {network} mesh network + + Add {device} to {network} mesh network + Confirm the device is blinking blue and your phone remains physically close to that device + Scan the sticker + Make sure the sticker is steady and well-lit + To connect, your {device} will use an Ethernet connection + Next + Standalone devices require a connection to the Device Cloud to securely talk to the Internet + OK—Let’s get this device connected to the Device Cloud + Device OS has been successfully updated. + Please keep your phone awake with this app open during this Device OS update. + Sending part {partIdx} to device — {progress}% done + Installing part {partIdx} on device + Congrats! + Updating Device OS + IMPORTANT! + To connect, you will send the {device} mesh network credentials + Next + Mesh nodes require a connection to the Device Cloud via a local mesh network to securely talk to the Internet + OK—Let’s get this mesh node connected to the Device Cloud + Once connected, this device can communicate with the Device Cloud via a mesh gateway, and locally with other devices in the mesh network + Pair {device} with your phone + Scan data matrix + Find the data matrix sticker on the front of your device. Use your phone camera to scan the code. + ${price} + First {freeDeviceCount} devices FREE + DEVICE CLOUD + Cellular device + {dataAllowance}MB of cellular data/mo.\naddnl. MBs start at ${pricePerMB} + Next + To create a new mesh network, please enroll in a Device Cloud subscription + Standard support + MICRO NETWORK + To activate this device, please enroll in a Device Cloud subscription + MESH NETWORK INCLUDES + Wi-Fi/Ethernet device + Wi-Fi/Ethernet Gateway + Woo-hoo! Enjoy this new mesh network on us + Device Cloud Features + + Cellular Gateway + First {freeNetworksCount} networks FREE + Woo-hoo! Enjoy Device Cloud access for this device on us + Enroll in subscription + per mo. + {maxDevices} total devices + up to {maxGateways} gateway + FREE for {freeMonths} months + DEVICE CLOUD INCLUDES + Congrats! + You’ve successfully paired {deviceName} + Pairing with your {device} + Error + This device was already set up and belongs to your account. Would you like to switch to Control Panel or continue this guided setup? + Leave current network? + Switch to Control Panel + The device you are trying to set up is already part of a mesh network. Would you like to have the device leave its current mesh network to continue setup? + Your device does not support scanning data matrices. Please use a device with a camera. + Are you sure you want to stop setting up your device? + It seems that you declined camera access for Particle app. Please grant camera access permissions in Settings app to continue. + End setup + We have detected that you are using external SIM card. Cellular settings are only available for devices with active internal SIM card. + Error + Error + Documentation + Unclaim Device + Ethernet + Mesh + Cellular + Device Name + Control Panel + Notes + Wi-Fi + Success + SIM data limit was changed + Success + Wi-Fi credentials were successfully added to {deviceName} + Success + Ethernet pins activated + Ethernet pins deactivated + Success + SIM activated + SIM deactivated + Success + {deviceName} was removed from mesh network + Role + Network Info + Leave network + Add to network + PanID + Device Count + Gateway + Name + Channel + Device Info + ExtPanID + Node + Demote from gateway + ID + Mesh + Promote to gateway + No network + Active + This Particle SIM card is paused. The device using this SIM cannot connect to the Internet via cellular until it is unpaused. + Unpause SIM Card + Unpausing may take up to a few minutes. Please be patient. + Unpause SIM + SIM Status + Unpausing your SIM with ICCID ending in …{iccid} will immediately resume cellular data transfer. You do have the option of waiting until the start of your next billing period when Particle will automatically unpause your SIM.\r\n\r\nPlease adjust your data limit below. Note that the new data limit will carry over to future billing periods. + Reactivate SIM Card + Reactivation may take up to a few minutes. Please be patient. + Reactivate SIM + SIM Status + We’re so glad you’d like to reactivate your Particle SIM with an ICCID ending in ...{iccid}. This will resume cellular data transfer and immediately allow devices using this SIM to connect to the Internet.\r\n\r\nReactivation of the SIM also resumes monthly Device Cloud subscription. + This Particle SIM has not been activated yet. To connect this device to the Internet via cellular, please run standard setup (via the \"+\" button on the device list screen), which will activate the SIM card. + Inactive + This Particle SIM card is active. The device using this SIM should be able to connect to the Internet via cellular. + Cellular Data + {dataLimit}MB + Cellular data usage can take up to 24 hours to be reported. Overage costs in that timeframe may apply. + Set Data Limit + Monthly Data Limit + Service will be paused once your SIM has reached the data limit below: + None + Deactivated + Cellular + This Particle SIM card is deactivated. The device using this SIM cannot connect to the Internet via cellular until it is reactivated. + Paused + SIM Status + Deactivate SIM Card + Deactivation may take up to a few minutes. Please be patient. + Deactivate SIM + SIM Status + Are you sure that you want to deactivate data service of the SIM with an ICCID ending in ...{iccid}?\r\n\r\nThis will immediately stop {device} using this SIM from sending or receiving data via a cellular network, and will disrupt expected device behavior until an active SIM is used. + Monthly Data Limit + Cancel + Cancel + Leave Network + Remove + Cancel + Signal + Singal only works for devices breathing cyan + Prepare For Pairing + To proceed app needs to pair to your device. Please put {deviceName} into listening mode. + Unclaim Device + Yes, Unclaim Device + Unclaim Device + Are you sure you would like to unclaim the device {deviceName}?\r\n\r\nThe current owner will lose the ability to view or interact with the device via the Particle Cloud. The device will be returned to an unclaimed State. + Manage Wi-Fi + Select stored WiFi credentials you want to remove + To enable Ethernet connectivity using the Particle Ethernet Featherwing, the SPI interface (SCK, MOSI, MISO) is used. Activating the Ethernet interface uses pins D3, D4, and D5 for control signals, and you will not be able to use those pins in your project. + Ethernet Pins + Ethernet + Inactive + Active + Documentation + RSSI + Connect to new Wi-Fi + Network Info + BSSID + No network + SSID + Channel + Manage Wi-Fi + Wi-Fi + Remove WiFi credentials? + Leave current network? + Are you sure you want to remove this device from current mesh network? + Are you sure you want to remove WiFi credentials for \'{wifiSSID}\' + Congrats! + You’ve successfully paired {deviceName} + Pairing with your {device} + Starting a secure session with the Particle Device Cloud + Your {device} has successfully connected to the Particle Device Cloud + Connecting to the internet via Ethernet + Congrats! + Your {device} is connecting to the Particle Device Cloud + Adding {device} to the mesh network + Your {device} has been successfully added to {network} mesh network + Requesting permission from assisting device to add {device} + Congrats! + Your {device} is joining the {network} mesh network + Starting a secure session with the Particle Device Cloud via gateway + This device will act as the assisting device to allow your {device} to join the {network} mesh network + Scan assisting device + Pair assisting device with your phone + HELPFUL TIP! + Find the data matrix sticker on the front of the assisting device. Use your phone camera to scan the code. + Your device may receive multiple files as part of this Device OS update. It will reboot in-between each file it receives from Device Cloud. + Begin update + Let’s get your device updated + HELPFUL TIP! + Update your device to the latest-and-greatest version of Device OS to continue setup + Create new network or select mesh network to join + Create new network + Your network has been created with {deviceName} acting as a gateway + Congrats! + Itching to get started? + I’m done + Adding more devices to your network? + Set up next device + Connecting to the internet via cellular + Your {device} has successfully connected to the Particle Device Cloud + Activating Particle SIM + Congrats! + Your {device} is connecting to the Particle Device Cloud + Starting a secure session with the Particle Device Cloud + Name your network something you will remember to help you easily identify it later. + Next + Give your network a name + Network name + HELPFUL TIP! + USE IN MESH NETWORK + Do you want to use this {device} in a mesh network? + This {device} can act as a gateway to the Internet and create a local wireless mesh network that other devices can join + DON\'T USE IN MESH NETWORK + {deviceName} creating the mesh network locally + Your network has been created! + Registering the mesh network with the Particle Device Cloud + Congrats! + Creating network + To connect the device will use the Particle SIM inside your {device} which has already been activated + Connect to Device Cloud + Standalone devices require a connection to the Device Cloud to securely talk to the Internet + To connect we’ll activate the Particle SIM inside your {device} + OK—Let’s get this device connected to the Device Cloud + Activate SIM & Connect + Select mesh network to join + {count} devices on network + 1 device on network + Connect to Device Cloud + Gateways require a connection to the Device Cloud to allow communication between the local mesh network and the Internet + Once connected you can create or join a mesh network using this {device} + To connect we’ll activate the Particle SIM inside your {device} + OK—Let’s get this mesh gateway connected to the Device Cloud + Activate SIM & Connect + To connect the device will use the Particle SIM inside your {device} which has already been activated + Toggle ethernet setup + Get your {device} ready for setup + Next + I have attached the Wi-Fi and bluetooth antennas and see that the device is blinking blue + I have attached the cellular and bluetooth antennas and see that the device is blinking blue + I have attached the cellular antenna and see that the device is blinking blue + Toggle ethernet featherwing setup + Attach your Ethernet Featherwing + I have attached the bluetooth antenna and see that the device is blinking blue + Get your {device} ready for setup + USE WITH ETHERNET? + I have attached the Wi-Fi antenna and see that the device is blinking blue + Get your {device} ready for setup + USE WITH ETHERNET? + There is a problem with the sticker on your device. Please contact support for a solution. + Failed to download the firmware update. Please try again later. + This device is on a different mesh network than the one you are trying to join. Please find the device that belongs to selected mesh network and try again. + Your device was unable to join the network (TIMEOUT). Please press try again. + SIM activation is taking longer than expected. Please retry your SIM activation. If you have retried multiple times, please contact support. + Sending Bluetooth messages failed. Please try again. + This is not valid device sticker. Please scan 3rd generation device sticker. + There was an error attempting to claim this device to your account. + Device is in invalid state, please reset the device and start again. + There was a network error communicating to Particle Device Cloud. + There was an error while adding your device to mesh network on Particle Device Cloud. + There was an error while performing a Device OS update. + Bluetooth appears to be disabled on your phone. Please enable Bluetooth and try again. + Unable to find your mesh device. Make sure the mesh device\'s LED is blinking blue and that it\'s not connected to any other devices. + Your device failed to obtain an IP address. Please make sure your device has internet access. + This is the device that is being setup. Please scan the sticker of device that is on the mesh network you are trying to join. + SIM deactivation is taking longer than expected. Please retry your SIM deactivation. If you have retried multiple times, please contact support. + There was a problem with the setup. Please contact support with the latest device log to help us fix it as soon as possible. + The SIM you are trying to interact with is owned by a different user account. + Support for adding multiple gateways to a single network is coming soon. Argons, Borons, and Xenons with Ethernet FeatherWings, must be set up as a standalone device or as the first gateway in a new mesh network. + Your device name cannot be empty. + You phone failed to connect to your mesh device. Please try again. + This device now acts as commissioner. Please restart the setup if you want to set it up again. + There was an error while registering your new network with Particle Device Cloud. + There was an error in accessing the modem on the device. The modem is now being rebooted in an attempt to recover. Wait a few seconds and then try again. If the error persists, try resetting the device manually by tapping the RESET button, and restart the setup process. + It seems that your device has exited listening mode. Please put your device in listening mode (blinking blue) and retry. + Your device was unable to join the network (NOT_ALLOWED). Please press try again. + Your mesh device is too far away from your phone. Please hold your phone closer and try again. + Unable to get information about the device from Device Cloud. + Unable to establish a secure connection with your device. Usually, this happens because the Bluetooth modem on your mobile phone has become unresponsive. Please restart the Bluetooth radio in settings, or restart your phone to try again. If this problem persists once you’ve done so, please contact support. + Something went wrong with Bluetooth. Please restart the set up process and try again. + The Bluetooth connection was dropped unexpectedly. Please restart the set up and try again. + The password you entered is too short. + This is not valid device sticker. Please scan 3rd generation device sticker. + Your device could not connect to Device Cloud. Please try again. + Your device failed to be claimed. Please try again. + There was an error while notifying the Particle Device Cloud about successful device setup. Please try again. + The password you entered is incorrect. + Unable to rename your device at this time. Please try again later. + There was an error while retrieving pricing information. Please try again. + There was an error while reading internal SIM card status. Please try again. + We have detected that you are using external SIM card. Use the internal SIM to complete setup. You may use an external SIM after setup is complete. + Your network password must be between 6 and 16 characters. + The network you are trying to join was created locally with test version of the app. Please create new network. + There was an error while accessing your mesh network information on Particle Device Cloud. + Your device is taking longer than expected to connect to the Internet. If you are setting up a Boron 2/3G, it may take up to 5 minutes to establish a connection with the cellular tower in your area. + Bluetooth appears to be disabled on your phone. Please enable Bluetooth and try again. + There was an error while removing your device from the mesh network on Particle Device Cloud. + You already own a network with this name. Please use different name. + You need to add a credit card to your account to continue. Please visit https://console.particle.io/billing/edit-card to add a card and return here when you\'re done. + Illegal operation. + There was an error changing data limit for SIM card. If you have retried multiple times, please contact support. + Your device was unable to join the network (NOT_FOUND). Please press try again. + device + Pair assisting device with your phone + Point the camera at the data matrix on the device. + Retry + Leave Network + Contact Support + Yes + Switch to Control Panel + Continue + Continue Setup + Open Settings + Cancel Setup + No + Ok + Cancel + To connect you will send the {device} Wi-Fi network credentials + Next + Standalone devices require a connection to the Device Cloud to securely talk to the Internet + OK—Let’s get this device connected to the Device Cloud + Adding more devices to this network? + {deviceName} is all set up! + Congrats! + Itching to get started? + Done + Set up another device + Name your device something you will remember to help you easily identify it later. + Next + Give your {device} a name + Device name + HELPFUL TIP! + Enter password for {network} + Password + Connect to Device Cloud + To connect, your {device} will use an Ethernet connection + Next + Gateways require a connection to the Device Cloud to allow communication between the local mesh network and the Internet + OK—Let’s get this mesh gateway connected to the Device Cloud + Once connected you can create or join a mesh network using this {device} + To connect you will send the {device} Wi-Fi network credentials + Next + Gateways require a connection to the Device Cloud to allow communication between the local mesh network and the Internet + OK—Let’s get this mesh gateway connected to the Device Cloud + Once connected you can create or join a mesh network using this {device} + This is the password that was set when the mesh network was first created. This password is required to authenticate new devices added to this network. + Join Network + Enter network password for {network} + Network password + HELPFUL TIP! + Mesh + Cellular + Mesh only + Choose the device you’re setting up + Mesh + Wi-Fi + Your Argon is scanning for Wi-Fi networks to join + Create network + Password and repeated password do not match. + Confirm network password + You’ll need this password each time you want to add a new device to this mesh network. + Set network admin password + Network password + KEEP THIS PASSWORD SAFE! + Starting a secure session with the Particle Device Cloud + Your {device} has successfully connected to the Particle Device Cloud + Connecting to the internet via Wi-Fi + Congrats! + Your {device} is connecting to the Particle Device Cloud + + Mesh network names must be fewer than 16 characters, and can only contain letters, numbers, and underscores. + Exit Setup + + Let\'s get building! + HELPFUL TIP! + Did you already close your web browser? You can always head straight to: + setup.particle.io?start-building + To start building with your device, look back at your web browser where you got started with setup. + + Permission needed + Control Panel uses Bluetooth scanning to find your devices.\n\nBecause it could potentially reveal your location, Bluetooth scanning requires the Location permission.\n\nControl Panel features will be available after you tap ALLOW on the next screen. + Got it + + OK + Location permission required + The Location permission has been disabled for this app. Please change this in Permissions for this app, under Settings → Apps. + + diff --git a/mesh/src/main/res/values/strings_mesh.xml b/mesh/src/main/res/values/strings_mesh.xml index 3f936352..d8641dd4 100644 --- a/mesh/src/main/res/values/strings_mesh.xml +++ b/mesh/src/main/res/values/strings_mesh.xml @@ -7,6 +7,7 @@ X SoM A SoM B SoM + B5 SoM Get your {product_type} ready for setup My device is blinking blue diff --git a/meshui/build.gradle b/meshui/build.gradle index 7ef811d8..c56f7740 100644 --- a/meshui/build.gradle +++ b/meshui/build.gradle @@ -69,9 +69,9 @@ dependencies { // for barcode scanning in Mesh setup implementation 'com.google.firebase:firebase-core:17.2.0' - implementation 'com.google.firebase:firebase-ml-vision:23.0.0' - implementation 'com.google.firebase:firebase-ml-vision-image-label-model:18.0.0' - implementation 'com.google.firebase:firebase-ml-model-interpreter:21.0.0' + implementation 'com.google.firebase:firebase-ml-vision:24.0.2' + implementation 'com.google.firebase:firebase-ml-vision-image-label-model:20.0.0' + implementation 'com.google.firebase:firebase-ml-model-interpreter:22.0.2' implementation 'com.afollestad.material-dialogs:core:0.9.6.0' implementation 'com.snakydesign.livedataextensions:lives:1.3.0' diff --git a/meshui/src/main/java/io/particle/mesh/ui/controlpanel/ControlPanelLandingFragment.kt b/meshui/src/main/java/io/particle/mesh/ui/controlpanel/ControlPanelLandingFragment.kt index dd01eaa1..121d35dc 100644 --- a/meshui/src/main/java/io/particle/mesh/ui/controlpanel/ControlPanelLandingFragment.kt +++ b/meshui/src/main/java/io/particle/mesh/ui/controlpanel/ControlPanelLandingFragment.kt @@ -18,6 +18,7 @@ import io.particle.android.sdk.cloud.ParticleCloudSDK import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.ARGON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.A_SOM +import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B5_SOM import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.BLUZ import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.BORON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B_SOM @@ -101,7 +102,7 @@ class ControlPanelLandingFragment : BaseControlPanelFragment() { } } - p_controlpanel_landing_cellular_item_frame.isVisible = deviceType in listOf(BORON, B_SOM) + p_controlpanel_landing_cellular_item_frame.isVisible = deviceType in listOf(BORON, B_SOM, B5_SOM) p_controlpanel_landing_cellular_item.setOnClickListener { flowRunner.startShowControlPanelCellularOptionsFlow(device) } @@ -115,8 +116,12 @@ class ControlPanelLandingFragment : BaseControlPanelFragment() { p_controlpanel_landing_mesh_item.isVisible = deviceType in gen3Devices p_controlpanel_landing_mesh_item.setOnClickListener { - flowScopes.onMain { - startFlowWithBarcode(flowRunner::startControlPanelMeshInspectCurrentNetworkFlow) + val uri: Uri = Uri.parse( + "https://docs.particle.io/reference/developer-tools/cli/#particle-mesh" + ) + val intent = Intent(Intent.ACTION_VIEW, uri) + if (intent.resolveActivity(requireContext().packageManager) != null) { + startActivity(intent) } } @@ -156,7 +161,7 @@ class ControlPanelLandingFragment : BaseControlPanelFragment() { private fun editNotes() { val editLD = MutableLiveData() DeviceNotesDelegate.editDeviceNotes( - activity!!, + requireActivity(), device, flowManagementScope, editLD @@ -172,6 +177,7 @@ private val gen3Devices = setOf( ParticleDeviceType.A_SOM, ParticleDeviceType.BORON, ParticleDeviceType.B_SOM, + ParticleDeviceType.B5_SOM, ParticleDeviceType.XENON, ParticleDeviceType.X_SOM ) @@ -184,7 +190,7 @@ private fun showDocumentation(context: Context, deviceType: ParticleDeviceType) P1 -> "datasheets/wi-fi/p1-datasheet" ELECTRON -> "electron" ARGON, A_SOM -> "argon" - BORON, B_SOM -> "boron" + BORON, B_SOM, B5_SOM -> "boron" XENON, X_SOM -> "xenon" RASPBERRY_PI, RED_BEAR_DUO, diff --git a/meshui/src/main/java/io/particle/mesh/ui/setup/SelectDeviceFragment.kt b/meshui/src/main/java/io/particle/mesh/ui/setup/SelectDeviceFragment.kt index 556652d9..1f99fd59 100644 --- a/meshui/src/main/java/io/particle/mesh/ui/setup/SelectDeviceFragment.kt +++ b/meshui/src/main/java/io/particle/mesh/ui/setup/SelectDeviceFragment.kt @@ -14,6 +14,7 @@ import io.particle.android.common.easyDiffUtilCallback import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.ARGON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.A_SOM +import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B5_SOM import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.BORON import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.B_SOM import io.particle.android.sdk.cloud.ParticleDevice.ParticleDeviceType.XENON @@ -154,6 +155,7 @@ private fun ParticleDeviceType.toDisplayName(): Int { A_SOM -> R.string.product_name_a_series B_SOM -> R.string.product_name_b_series X_SOM -> R.string.product_name_x_series + B5_SOM -> R.string.product_name_b5_som else -> throw IllegalArgumentException("Not a mesh device: $this") } } diff --git a/setup_testapp/build.gradle b/setup_testapp/build.gradle index e06069e2..2ead7931 100644 --- a/setup_testapp/build.gradle +++ b/setup_testapp/build.gradle @@ -34,7 +34,7 @@ dependencies { testImplementation "junit:junit:4.12" testImplementation 'com.github.fabioCollini:DaggerMock:0.7.0' testImplementation "org.mockito:mockito-core:2.16.0" - testImplementation 'com.google.dagger:dagger-compiler:2.24' + testImplementation 'com.google.dagger:dagger-compiler:2.27' androidTestImplementation 'com.android.support:support-annotations:28.0.0' androidTestImplementation "org.mockito:mockito-core:2.16.0"