Skip to content

hud10837/add-privacy-info #795

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 67 commits into from
Apr 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
01ce496
200.6.0 Release - merge v.next into main (#680)
puneet-pdx Nov 25, 2024
321206a
Merge branch 'v.next' of https://github.com/Esri/arcgis-maps-sdk-kotl…
hud10837 Jan 3, 2025
7a6bfa9
Hud10837/init worldscale feature branch (#697)
hud10837 Jan 14, 2025
12570c0
update worldscale public api file (#703)
hud10837 Jan 14, 2025
fc0b680
Add Joyslider Composable + tests (#707)
01smito01 Jan 21, 2025
f68c25f
Pull vnext into WorldScaleSceneView feature branch (#712)
hud10837 Jan 22, 2025
0f6aa1d
WorldScaleSceneView: Handle permissions and implement world tracking …
hud10837 Jan 27, 2025
ab30b22
Hud10837/refactor location tracker (#726)
hud10837 Feb 3, 2025
b3c0ee6
Calibration view (#739)
01smito01 Feb 12, 2025
4d294f0
WorldScaleSceneView: Update Microapp (#749)
hud10837 Feb 20, 2025
573713d
Fix init of elevation/heading offsets in CalibrationView (#765)
01smito01 Feb 28, 2025
8ebcf38
WorldScaleSceneView: Establish good first location without location u…
hud10837 Feb 28, 2025
07ff68c
Hud10837/reset ar session (#770)
hud10837 Mar 6, 2025
cf8afe7
Add clipping distance and fix NaN elevation crash (#775)
hud10837 Mar 12, 2025
3835fdd
prototype geospatial api
hud10837 Mar 13, 2025
8edd134
add tracking mode
hud10837 Mar 13, 2025
1899a8f
Heading Provider (#777)
01smito01 Mar 13, 2025
93172f5
apply elevation offset, format code
gunt0001 Mar 13, 2025
d17c9ac
Merge branch 'hud10837/prototype-geospatial' of https://github.com/Es…
hud10837 Mar 14, 2025
8865230
prototype landscape mode
hud10837 Mar 17, 2025
e48dde3
dynamically apply rotation adjustment based on screen oreintation
hud10837 Mar 18, 2025
4d13940
add camera controller doc
hud10837 Mar 18, 2025
2ccf599
doc
hud10837 Mar 18, 2025
e6e7ae7
add option to microapp to change mode
hud10837 Mar 19, 2025
5bb013a
Merge branch 'feature-branches/world-scale-scene-view' of https://git…
hud10837 Mar 19, 2025
d11173a
working swapping proto
hud10837 Mar 20, 2025
0e7f6d8
cleanup changes for geospatial
hud10837 Mar 21, 2025
6eae182
Deploy PE data from assets (#781)
gunt0001 Mar 21, 2025
da578d2
Merge branch 'feature-branches/world-scale-scene-view' into hud10837/…
gunt0001 Mar 21, 2025
9171345
renames and refactor of constants
gunt0001 Mar 21, 2025
1b26bd4
fix logic to calculate display oriented pose in Geospatial mode
gunt0001 Mar 21, 2025
f249fc2
simplify logic to update scene camera in Geospatial mode
gunt0001 Mar 22, 2025
a4b5dcb
revert "simplify logic to update scene camera in Geospatial mode"
gunt0001 Mar 23, 2025
9602104
Fix geospatial mode crash and not displaying
hud10837 Mar 24, 2025
381afcc
throw error if geospatial not supported
hud10837 Mar 24, 2025
7fc5af6
clean up on session resume
hud10837 Mar 24, 2025
d13de11
fix try/catch
hud10837 Mar 24, 2025
2a2c320
fix initialization status
hud10837 Mar 24, 2025
cd54589
reformat
hud10837 Mar 24, 2025
c60c099
rm api key
hud10837 Mar 24, 2025
5209571
newlines
hud10837 Mar 24, 2025
3197083
rm phantom nmea location provider
hud10837 Mar 24, 2025
01452cf
rm unused constants
hud10837 Mar 24, 2025
1f3f01e
rm unused cc factory funs
hud10837 Mar 24, 2025
6cb29f9
comment out meta data tag in microapp manifest
hud10837 Mar 24, 2025
d98b8ed
apiDump
hud10837 Mar 24, 2025
eb8644f
Add privacy info alert dialogs to WorldScale app and TableTop app
hud10837 Mar 25, 2025
a4d5097
add notes to readme
hud10837 Mar 26, 2025
6ea34a5
update readme
hud10837 Mar 26, 2025
54e0a73
WorldScaleSceneView: add geospatial api (#778)
hud10837 Mar 27, 2025
e6f6db4
Merge branch 'feature-branches/world-scale-scene-view' of https://git…
hud10837 Mar 27, 2025
8f9692a
add dropdownmenu item for showing privacy info and use shared prefs t…
hud10837 Mar 28, 2025
8a426ad
Merge branch 'v.next' of https://github.com/Esri/arcgis-maps-sdk-kotl…
hud10837 Mar 31, 2025
4f83dad
update sdkVersionNumber
hud10837 Mar 31, 2025
9b29b20
formatting
hud10837 Mar 31, 2025
24f8a94
revert sdk build num
hud10837 Apr 1, 2025
0c7249f
rename key
hud10837 Apr 1, 2025
504f3ce
revert change to SceneView.kt
hud10837 Apr 1, 2025
93f956f
add doc to privacy info funs
hud10837 Apr 1, 2025
809565b
refactor PrivacyInfoDialog to accept one lambda
hud10837 Apr 1, 2025
974db03
use string resources
hud10837 Apr 2, 2025
0096a43
extract string resources tabletop
hud10837 Apr 2, 2025
150837b
update top bar title to string resource
hud10837 Apr 2, 2025
807bf62
make funs private
hud10837 Apr 2, 2025
823fbdc
use Dialog over BasicAlertDialog
hud10837 Apr 2, 2025
e2906c7
revert line changes
hud10837 Apr 2, 2025
6cd8956
revert line changes
hud10837 Apr 2, 2025
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
2 changes: 1 addition & 1 deletion microapps/ArTabletopApp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ This micro-app demonstrates the use of the `TableTopSceneView` toolkit component

Launch the app and follow on-screen instructions to point the camera towards a surface while moving the device slightly. When a surface is detected it will appear as a grid of white lines in the camera feed. Tap on the grid to choose an anchor location to place the 3D buildings. Shortly after tapping on the screen, the buildings will appear as shown in the screenshot above.

For more information on the `TableTopSceneView` component and how it works, see its [Readme](../../toolkit/ar/README.md).
For more information on the `TableTopSceneView` component and how it works, see the AR package [Readme](../../toolkit/ar/README.md).
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
Expand Down Expand Up @@ -94,7 +93,7 @@ class MainActivity : ComponentActivity() {
@Composable
fun ArTabletopApp() {
Scaffold(
topBar = { TopAppBar(title = { Text("ArTabletopApp") }) }
topBar = { TopAppBar(title = { Text(stringResource(R.string.top_bar_title)) }) }
) {
Box(Modifier.padding(it)) {
MainScreen()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,41 @@

package com.arcgismaps.toolkit.artabletopapp.screens

import android.content.Context
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextLinkStyles
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withLink
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.arcgismaps.LoadStatus
import com.arcgismaps.data.ArcGISFeature
Expand All @@ -52,6 +69,8 @@ import com.arcgismaps.toolkit.ar.rememberTableTopSceneViewStatus
import com.arcgismaps.toolkit.artabletopapp.R
import kotlinx.coroutines.launch

private const val KEY_PREF_ACCEPTED_PRIVACY_INFO = "ACCEPTED_PRIVACY_INFO"

@Composable
fun MainScreen() {
val arcGISSceneLayer = remember {
Expand Down Expand Up @@ -80,81 +99,110 @@ fun MainScreen() {
val coroutineScope = rememberCoroutineScope()

Box(modifier = Modifier.fillMaxSize()) {
TableTopSceneView(
arcGISScene = arcGISScene,
arcGISSceneAnchor = arcGISSceneAnchor,
translationFactor = 400.0,
modifier = Modifier.fillMaxSize(),
clippingDistance = 400.0,
tableTopSceneViewProxy = tableTopSceneViewProxy,
onInitializationStatusChanged = {
initializationStatus = it
},
onSingleTapConfirmed = { tap ->
arcGISSceneLayer.clearSelection()
coroutineScope.launch {
identifiedBuilding = arcGISSceneLayer.identifyBuilding(
tap.screenCoordinate,
tableTopSceneViewProxy
)
identifiedBuilding?.let { identifiedBuilding ->
arcGISSceneLayer.selectFeature(identifiedBuilding.feature)
}
val sharedPreferences = LocalContext.current.getSharedPreferences("", Context.MODE_PRIVATE)
var acceptedPrivacyInfo by rememberSaveable { mutableStateOf(sharedPreferences.getBoolean(
KEY_PREF_ACCEPTED_PRIVACY_INFO, false)) }
var showPrivacyInfo by rememberSaveable { mutableStateOf(!acceptedPrivacyInfo) }
if (showPrivacyInfo) {
PrivacyInfoDialog(
acceptedPrivacyInfo,
onUserResponse = { accepted ->
acceptedPrivacyInfo = accepted
sharedPreferences.edit().putBoolean(KEY_PREF_ACCEPTED_PRIVACY_INFO, accepted).apply()
showPrivacyInfo = false
}
)
}
if (!acceptedPrivacyInfo) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(stringResource(R.string.privacy_info_not_accepted))
Button(
onClick = { showPrivacyInfo = true }
) {
Text(stringResource(R.string.show_privacy_info))
}
}
) {
identifiedBuilding?.let {
Callout(it.location) {
Text("Building ID: ${it.feature.attributes["OBJECTID"]}")
} else {
TableTopSceneView(
arcGISScene = arcGISScene,
arcGISSceneAnchor = arcGISSceneAnchor,
translationFactor = 400.0,
modifier = Modifier.fillMaxSize(),
clippingDistance = 400.0,
tableTopSceneViewProxy = tableTopSceneViewProxy,
onInitializationStatusChanged = {
initializationStatus = it
},
onSingleTapConfirmed = { tap ->
arcGISSceneLayer.clearSelection()
coroutineScope.launch {
identifiedBuilding = arcGISSceneLayer.identifyBuilding(
tap.screenCoordinate,
tableTopSceneViewProxy
)
identifiedBuilding?.let { identifiedBuilding ->
arcGISSceneLayer.selectFeature(identifiedBuilding.feature)
}
}
}
) {
identifiedBuilding?.let {
Callout(it.location) {
Text("Building ID: ${it.feature.attributes["OBJECTID"]}")
}
}
}
}
}

// Show an overlay with instructions or progress indicator based on the initialization status
when (val status = initializationStatus) {
is TableTopSceneViewStatus.Initializing -> TextWithScrim(text = stringResource(R.string.initializing_overlay))
is TableTopSceneViewStatus.DetectingPlanes -> TextWithScrim(text = stringResource(R.string.detect_planes_overlay))
is TableTopSceneViewStatus.Initialized -> {
val sceneLoadStatus = arcGISScene.loadStatus.collectAsStateWithLifecycle().value
when (sceneLoadStatus) {
is LoadStatus.NotLoaded -> {
// Tell the user to tap the screen if the scene has not started loading
TextWithScrim(text = stringResource(R.string.tap_scene_overlay))
}
// Show an overlay with instructions or progress indicator based on the initialization status
when (val status = initializationStatus) {
is TableTopSceneViewStatus.Initializing -> TextWithScrim(text = stringResource(R.string.initializing_overlay))
is TableTopSceneViewStatus.DetectingPlanes -> TextWithScrim(text = stringResource(R.string.detect_planes_overlay))
is TableTopSceneViewStatus.Initialized -> {
val sceneLoadStatus = arcGISScene.loadStatus.collectAsStateWithLifecycle().value
when (sceneLoadStatus) {
is LoadStatus.NotLoaded -> {
// Tell the user to tap the screen if the scene has not started loading
TextWithScrim(text = stringResource(R.string.tap_scene_overlay))
}

is LoadStatus.Loading -> {
// The scene may take a while to load, so show a progress indicator
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
is LoadStatus.Loading -> {
// The scene may take a while to load, so show a progress indicator
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
}
}

is LoadStatus.FailedToLoad -> {
TextWithScrim(
text = stringResource(
R.string.failed_to_load_scene,
sceneLoadStatus.error
)
)
}

LoadStatus.Loaded -> {} // Do nothing
}
}

is LoadStatus.FailedToLoad -> {
is TableTopSceneViewStatus.FailedToInitialize -> {
TextWithScrim(
text = stringResource(
R.string.failed_to_load_scene,
sceneLoadStatus.error
R.string.failed_to_initialize_overlay,
status.error.message ?: status.error
)
)
}

LoadStatus.Loaded -> {} // Do nothing
}
}

is TableTopSceneViewStatus.FailedToInitialize -> {
TextWithScrim(
text = stringResource(
R.string.failed_to_initialize_overlay,
status.error.message ?: status.error
)
)
}
}
}

Expand Down Expand Up @@ -202,3 +250,81 @@ private suspend fun ArcGISSceneLayer.identifyBuilding(
* @since 200.6.0
*/
private data class IdentifiedBuilding(val feature: ArcGISFeature, val location: Point)

/**
* An alert dialog that asks the user to accept or deny [ARCore's privacy requirements](https://developers.google.com/ar/develop/privacy-requirements).
*
* @since 200.7.0
*/
@Composable
private fun PrivacyInfoDialog(
hasCurrentlyAccepted: Boolean,
onUserResponse: (accepted: Boolean) -> Unit
) {
Dialog(
onDismissRequest = {
onUserResponse(hasCurrentlyAccepted)
}
) {
Card {
Column(
modifier = Modifier.padding(16.dp)
) {
LegalTextArCore()
Spacer(Modifier.height(16.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
TextButton(
onClick = {
onUserResponse(false)
}) {
Text(stringResource(R.string.decline))
}

TextButton(
onClick = {
onUserResponse(true)
}
) {
Text(stringResource(R.string.accept))
}
}
}
}
}
}

/**
* Displays the required privacy information for use of ARCore
*
* @since 200.7.0
*/
@Composable
private fun LegalTextArCore() {
val textLinkStyle =
TextLinkStyles(style = SpanStyle(color = Color.Blue))
Text(
text = buildAnnotatedString {
append("This application runs on ")
withLink(
LinkAnnotation.Url(
"https://play.google.com/store/apps/details?id=com.google.ar.core",
textLinkStyle
)
) {
append("Google Play Services for AR")
}
append(" (ARCore), which is provided by Google and governed by the ")
withLink(
LinkAnnotation.Url(
"https://policies.google.com/privacy",
textLinkStyle
)
) {
append("Google Privacy Policy.")
}
}
)
}
5 changes: 5 additions & 0 deletions microapps/ArTabletopApp/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,9 @@
<string name="initializing_overlay">Setting up AR...</string>
<string name="failed_to_initialize_overlay">Failed to initialize: %1$s</string>
<string name="failed_to_load_scene">Failed to load scene: %1$s</string>
<string name="decline">Decline</string>
<string name="accept">Accept</string>
<string name="privacy_info_not_accepted">Privacy Info not accepted</string>
<string name="show_privacy_info">Show Privacy Info</string>
<string name="top_bar_title">AR Table Top</string>
</resources>
Loading