Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7cbdf7f
migrate brapi token management to accountmanager
trife Feb 16, 2026
1941776
minor refactoring
chaneylc Mar 4, 2026
7cf4916
migrate brapi to card-based layout with multiple servers
trife Mar 7, 2026
746a035
layout improvements
trife Mar 7, 2026
bbecf93
collapsible server cards
trife Mar 7, 2026
a62dc7f
removed unused icons and layouts
trife Mar 8, 2026
76dc2ff
server card update
trife Mar 8, 2026
f54715c
bug fixes
trife Mar 8, 2026
10c9c7c
Merge branch 'main' into accountmanager
trife Mar 8, 2026
7166dfe
restore ic_launcher_round
trife Mar 8, 2026
cffab71
remove community servers, mlkit pref, add brapi drawables
trife Mar 8, 2026
bd3d044
Merge branch 'main' into accountmanager
trife Mar 10, 2026
f205cb1
Merge branch 'main' into accountmanager
trife Mar 17, 2026
9e33d98
compose and other improvements
trife Apr 7, 2026
9790460
fix permissions issues
trife Apr 16, 2026
1403277
fix settings flash and account visibility
trife Apr 16, 2026
103c686
fix blank white screen when adding account from settings
trife Apr 16, 2026
5c4d71e
fully compose add account dialog
trife Apr 16, 2026
1500fa4
transition to brapiaccountviewmodel
trife Apr 16, 2026
6636bce
add dialog when auth fails
trife Apr 17, 2026
375af41
address handling of extras/prefs
trife Apr 27, 2026
e5f1e3f
fix issues with account edits and duplications
trife Apr 27, 2026
d770f43
brapi server compatibility fixes
trife Apr 27, 2026
014c2c7
bug fixes
trife Apr 27, 2026
c9cca54
Swapped getTokenBlocking() for peekToken().
trife May 3, 2026
3ab262b
better handle auth response contract
trife May 3, 2026
c517ec5
migrate to shared auth model
trife May 5, 2026
6d44ce2
additional code into brapi-provider module
trife May 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'androidx.navigation.safeargs'
Expand Down Expand Up @@ -138,6 +137,8 @@ tasks.withType(KotlinCompile).configureEach {

dependencies {

implementation project(':brapi-provider')

//seven segment display compose ui
implementation 'com.github.rabross:SegmentedDisplay:0.4.0'

Expand Down
Binary file removed app/src/debug/res/mipmap-hdpi/ic_launcher_round.webp
Binary file not shown.
Binary file removed app/src/debug/res/mipmap-mdpi/ic_launcher_round.webp
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
36 changes: 33 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.fieldbook.tracker">

<!-- Custom permission allowing other PhenoApps to request BrAPI tokens via AccountManager.
Normal protection: any app that declares uses-permission is granted it without a user
prompt. Account visibility is controlled per-package in BrapiAuthenticator. -->
<permission
android:name="org.phenoapps.brapi.READ_TOKEN"
android:protectionLevel="normal" />

<uses-permission android:name="org.phenoapps.brapi.READ_TOKEN" />

<application
android:name=".application.FieldBook"
android:hardwareAccelerated="true"
Expand Down Expand Up @@ -168,6 +177,12 @@
android:configChanges="orientation|keyboardHidden|screenSize|locale"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name=".activities.brapi.BrapiAddAccountActivity"
android:configChanges="orientation|keyboardHidden|screenSize|locale"
android:exported="false"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name=".activities.brapi.BrapiAuthActivity"
android:configChanges="orientation|keyboardHidden|screenSize|locale"
Expand All @@ -183,7 +198,7 @@

<data
android:host=""
android:scheme="fieldbook"
android:scheme="${appAuthRedirectScheme}"
tools:ignore="AppLinkUrlError" /> <!-- https://stackoverflow.com/questions/48093833/deeplink-empty-path-error-androidpath-cannot-be-empty -->
</intent-filter>
<intent-filter>
Expand Down Expand Up @@ -214,7 +229,7 @@
<data
android:host="app"
android:path="/auth"
android:scheme="fieldbook" />
android:scheme="${appAuthRedirectScheme}" />
</intent-filter>
</activity>
<activity android:name=".activities.CropImageActivity"
Expand Down Expand Up @@ -267,6 +282,19 @@

<!--TODO: Temporarily opt out of forced layout changes in sdk 36. Needs to be addressed before updating to sdk 37 -->
<property android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY" android:value="true" />

<!-- BrAPI AccountManager authenticator service -->
<service
android:name=".brapi.BrapiAuthenticatorService"
android:exported="true"
android:permission="android.permission.AUTHENTICATE_ACCOUNTS">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/brapi_authenticator" />
</service>
</application>

<queries>
Expand Down Expand Up @@ -326,7 +354,9 @@
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />

<uses-sdk tools:overrideLibrary="com.google.zxing.client.android,com.binayshaw7777.kotstep" />

</manifest>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import com.fieldbook.tracker.objects.FieldFileObject
import com.fieldbook.tracker.objects.FieldObject
import com.fieldbook.tracker.preferences.GeneralKeys
import com.fieldbook.tracker.preferences.PreferenceKeys
import com.fieldbook.tracker.utilities.BrapiAccountHelper
import com.fieldbook.tracker.utilities.SnackbarUtils
import com.fieldbook.tracker.utilities.TapTargetUtil
import com.fieldbook.tracker.utilities.Utils
Expand All @@ -56,6 +57,7 @@ import java.util.LinkedHashMap
import java.util.NoSuchElementException
import java.util.StringJoiner
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import java.util.Locale
import androidx.core.content.edit
import androidx.core.net.toUri
Expand All @@ -69,6 +71,9 @@ class FieldEditorActivity : BaseFieldActivity(), FieldSortController {
private const val PERMISSIONS_REQUEST_STORAGE = 998
}

@Inject
lateinit var brapiAccountHelper: BrapiAccountHelper

private lateinit var fieldFile: FieldFileObject.FieldFileBase
private lateinit var unique: Spinner
private lateinit var mGpsTracker: GPSTracker
Expand Down Expand Up @@ -461,22 +466,18 @@ class FieldEditorActivity : BaseFieldActivity(), FieldSortController {
}

private fun showFileDialog() {
val importArray = arrayOfNulls<String>(
if (mPrefs.getBoolean(
PreferenceKeys.BRAPI_ENABLED,
false
)
) 4 else 3
)
val hasBrapi = brapiAccountHelper.hasActiveServer()
val importArray = arrayOfNulls<String>(if (hasBrapi) 4 else 3)
importArray[0] = getString(R.string.import_source_local)
importArray[1] = getString(R.string.import_source_cloud)
importArray[2] = getString(R.string.fields_new_create_field)

if (mPrefs.getBoolean(PreferenceKeys.BRAPI_ENABLED, false)) {
val displayName = mPrefs.getString(
PreferenceKeys.BRAPI_DISPLAY_NAME,
getString(R.string.brapi_edit_display_name_default)
)
if (hasBrapi) {
val activeAccount = brapiAccountHelper.findAccount()
val displayName = activeAccount?.let {
brapiAccountHelper.getUserData(it, com.fieldbook.tracker.brapi.BrapiAuthenticator.KEY_DISPLAY_NAME)
?.takeIf { name -> name.isNotEmpty() }
} ?: getString(R.string.brapi_edit_display_name_default)
importArray[3] = displayName
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.fieldbook.tracker.activities.brapi

import android.accounts.AccountAuthenticatorResponse
import android.accounts.AccountManager
import android.os.Bundle
import android.widget.Toast
import androidx.activity.compose.setContent
import com.fieldbook.tracker.activities.ThemedActivity
import com.fieldbook.tracker.brapi.dialogs.BrapiStepperAccountDialogFragment
import com.fieldbook.tracker.ui.theme.AppTheme
import dagger.hilt.android.AndroidEntryPoint
import org.phenoapps.brapi.BrapiAccountConstants

/**
* Thin activity that hosts the BrAPI add-account dialog.
* Launched by the system AccountManager (via BrapiAuthenticator.addAccount),
* or by the BrAPI preferences screen when the user taps "Add Account".
*/
@AndroidEntryPoint
class BrapiAddAccountActivity : ThemedActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

if (intent.getBooleanExtra(BrapiAccountConstants.EXTRA_SHOW_IN_APP_ADDER_TOAST, false)) {
val message = getString(org.phenoapps.brapi.R.string.pheno_brapi_add_account_in_app_only)
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
intent.getParcelableExtra<AccountAuthenticatorResponse>(
AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
)?.onError(AccountManager.ERROR_CODE_CANCELED, message)
finish()
return
}

setContent { AppTheme { } }

if (savedInstanceState == null) {
val fragment = BrapiStepperAccountDialogFragment.newInstance(
authResponse = intent.getParcelableExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE)
)
fragment.show(supportFragmentManager, BrapiStepperAccountDialogFragment.TAG)
}
}
}
Loading