diff --git a/samples/create-and-edit-geometries/README.md b/samples/create-and-edit-geometries/README.md
new file mode 100644
index 000000000..e9937546c
--- /dev/null
+++ b/samples/create-and-edit-geometries/README.md
@@ -0,0 +1 @@
+# Create and edit geometries
diff --git a/samples/create-and-edit-geometries/README.metadata.json b/samples/create-and-edit-geometries/README.metadata.json
new file mode 100644
index 000000000..4bcd74115
--- /dev/null
+++ b/samples/create-and-edit-geometries/README.metadata.json
@@ -0,0 +1,19 @@
+{
+ "category": "Edit and Manage Data",
+ "description": "TODO",
+ "formal_name": "CreateAndEditGeometries",
+ "ignore": false,
+ "images": [
+ "create-and-edit-geometries.png"
+ ],
+ "keywords": [ ],
+ "language": "kotlin",
+ "redirect_from": "",
+ "relevant_apis": [ ],
+ "snippets": [
+ "src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/CreateAndEditGeometriesViewModel.kt",
+ "src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/CreateAndEditGeometriesScreen.kt",
+ "src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/MainActivity.kt"
+ ],
+ "title": "Create and edit geometries"
+}
diff --git a/samples/create-and-edit-geometries/build.gradle.kts b/samples/create-and-edit-geometries/build.gradle.kts
new file mode 100644
index 000000000..18dc9f4c1
--- /dev/null
+++ b/samples/create-and-edit-geometries/build.gradle.kts
@@ -0,0 +1,22 @@
+plugins {
+ alias(libs.plugins.arcgismaps.android.library)
+ alias(libs.plugins.arcgismaps.android.library.compose)
+ alias(libs.plugins.arcgismaps.kotlin.sample)
+ alias(libs.plugins.gradle.secrets)
+}
+
+secrets {
+ // this file doesn't contain secrets, it just provides defaults which can be committed into git.
+ defaultPropertiesFileName = "secrets.defaults.properties"
+}
+
+android {
+ namespace = "com.esri.arcgismaps.sample.createandeditgeometries"
+ buildFeatures {
+ buildConfig = true
+ }
+}
+
+dependencies {
+ // Only module specific dependencies needed here
+}
diff --git a/samples/create-and-edit-geometries/create-and-edit-geometries.png b/samples/create-and-edit-geometries/create-and-edit-geometries.png
new file mode 100644
index 000000000..84b726c2e
Binary files /dev/null and b/samples/create-and-edit-geometries/create-and-edit-geometries.png differ
diff --git a/samples/create-and-edit-geometries/src/main/AndroidManifest.xml b/samples/create-and-edit-geometries/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..7f287fc31
--- /dev/null
+++ b/samples/create-and-edit-geometries/src/main/AndroidManifest.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/create-and-edit-geometries/src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/MainActivity.kt b/samples/create-and-edit-geometries/src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/MainActivity.kt
new file mode 100644
index 000000000..2c61db02f
--- /dev/null
+++ b/samples/create-and-edit-geometries/src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/MainActivity.kt
@@ -0,0 +1,53 @@
+/* Copyright 2025 Esri
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.esri.arcgismaps.sample.createandeditgeometries
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.Composable
+import com.arcgismaps.ApiKey
+import com.arcgismaps.ArcGISEnvironment
+import com.esri.arcgismaps.sample.sampleslib.theme.SampleAppTheme
+import com.esri.arcgismaps.sample.createandeditgeometries.screens.CreateAndEditGeometriesScreen
+
+class MainActivity : ComponentActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ // authentication with an API key or named user is
+ // required to access basemaps and other location services
+ ArcGISEnvironment.apiKey = ApiKey.create(BuildConfig.ACCESS_TOKEN)
+
+ setContent {
+ SampleAppTheme {
+ CreateAndEditGeometriesApp()
+ }
+ }
+ }
+
+ @Composable
+ private fun CreateAndEditGeometriesApp() {
+ Surface(color = MaterialTheme.colorScheme.background) {
+ CreateAndEditGeometriesScreen(
+ sampleName = getString(R.string.create_and_edit_geometries_app_name)
+ )
+ }
+ }
+}
diff --git a/samples/create-and-edit-geometries/src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/components/CreateAndEditGeometriesViewModel.kt b/samples/create-and-edit-geometries/src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/components/CreateAndEditGeometriesViewModel.kt
new file mode 100644
index 000000000..9fdcd1626
--- /dev/null
+++ b/samples/create-and-edit-geometries/src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/components/CreateAndEditGeometriesViewModel.kt
@@ -0,0 +1,167 @@
+/* Copyright 2025 Esri
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.esri.arcgismaps.sample.createandeditgeometries.components
+
+import android.app.Application
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.viewModelScope
+import com.arcgismaps.geometry.GeometryType
+import com.arcgismaps.geometry.Multipoint
+import com.arcgismaps.geometry.Point
+import com.arcgismaps.geometry.Polygon
+import com.arcgismaps.geometry.Polyline
+import com.arcgismaps.mapping.ArcGISMap
+import com.arcgismaps.mapping.BasemapStyle
+import com.arcgismaps.mapping.Viewpoint
+import com.arcgismaps.mapping.view.Graphic
+import com.arcgismaps.mapping.view.GraphicsOverlay
+import com.arcgismaps.mapping.view.SingleTapConfirmedEvent
+import com.arcgismaps.mapping.view.geometryeditor.GeometryEditor
+import com.arcgismaps.mapping.view.geometryeditor.GeometryEditorStyle
+import com.arcgismaps.toolkit.geoviewcompose.MapViewProxy
+import com.esri.arcgismaps.sample.sampleslib.components.MessageDialogViewModel
+import kotlinx.coroutines.launch
+
+class CreateAndEditGeometriesViewModel(application: Application) : AndroidViewModel(application) {
+ // create a map with the imagery basemap style
+ val arcGISMap by mutableStateOf(
+ ArcGISMap(BasemapStyle.ArcGISImagery).apply {
+ // a viewpoint centered at the island of Inis MeƔin (Aran Islands) in Ireland
+ initialViewpoint = Viewpoint(
+ latitude = 53.08230,
+ longitude = -9.5920,
+ scale = 5000.0
+ )
+ }
+ )
+
+ // create a message dialog view model for handling error messages
+ val messageDialogVM = MessageDialogViewModel()
+
+ // create a MapViewProxy that will be used to identify features in the MapView and set the viewpoint
+ val mapViewProxy = MapViewProxy()
+
+ // create a geometryEditorStyle
+ private val geometryEditorStyle = GeometryEditorStyle()
+ // create a graphic to hold graphics identified on tap
+ private var identifiedGraphic = Graphic()
+ // create a graphics overlay
+ val graphicsOverlay = GraphicsOverlay()
+ // create a geometry editor
+ val geometryEditor = GeometryEditor()
+
+ init {
+ viewModelScope.launch {
+ // load the map
+ arcGISMap.load().onFailure { error ->
+ messageDialogVM.showMessageDialog(
+ title = "Failed to load map",
+ description = error.message.toString()
+ )
+ }
+ }
+ }
+
+ /**
+ * Starts the GeometryEditor using the selected [GeometryType].
+ */
+ fun startEditor(selectedGeometry: GeometryType) {
+ if (!geometryEditor.isStarted.value) {
+ geometryEditor.start(selectedGeometry)
+ }
+ }
+
+ /**
+ * Stops the GeometryEditor and updates the identified graphic or calls [createGraphic].
+ */
+ fun stopEditor() {
+ // check if there was a previously identified graphic
+ if (identifiedGraphic.geometry != null) {
+ // update the identified graphic
+ identifiedGraphic.geometry = geometryEditor.stop()
+ // deselect the identified graphic
+ identifiedGraphic.isSelected = false
+ } else if (geometryEditor.isStarted.value) {
+ // create a graphic from the geometry that was being edited
+ createGraphic()
+ }
+ }
+
+ /**
+ * Creates a graphic from the geometry and adds it to the GraphicsOverlay.
+ */
+ private fun createGraphic() {
+ // stop the geometry editor and get its final geometry state
+ val geometry = geometryEditor.stop()
+ ?: return messageDialogVM.showMessageDialog(
+ title = "Error!",
+ description = "Error stopping editing session"
+ )
+
+ // create a graphic to represent the new geometry
+ val graphic = Graphic(geometry)
+
+ // give the graphic an appropriate fill based on the geometry type
+ when (geometry) {
+ is Point, is Multipoint -> graphic.symbol = geometryEditorStyle.vertexSymbol
+ is Polyline -> graphic.symbol = geometryEditorStyle.lineSymbol
+ is Polygon -> graphic.symbol = geometryEditorStyle.fillSymbol
+ else -> {}
+ }
+ // add the graphic to the graphics overlay
+ graphicsOverlay.graphics.add(graphic)
+ // deselect the graphic
+ graphic.isSelected = false
+ }
+
+ /**
+ * Identifies the graphic at the tapped screen coordinate in the provided [singleTapConfirmedEvent]
+ * and starts the GeometryEditor using the identified graphic's geometry. Hide the BottomSheet on
+ * [singleTapConfirmedEvent].
+ */
+ fun identify(singleTapConfirmedEvent: SingleTapConfirmedEvent) {
+ viewModelScope.launch {
+ // attempt to identify a graphic at the location the user tapped
+ val graphicsResult = mapViewProxy.identifyGraphicsOverlays(
+ screenCoordinate = singleTapConfirmedEvent.screenCoordinate,
+ tolerance = 10.0.dp,
+ returnPopupsOnly = false
+ ).getOrNull()
+
+ if (!geometryEditor.isStarted.value) {
+ if (graphicsResult != null) {
+ if (graphicsResult.isNotEmpty()) {
+ // get the tapped graphic
+ identifiedGraphic = graphicsResult.first().graphics.first()
+ // select the graphic
+ identifiedGraphic.isSelected = true
+ // start the geometry editor with the identified graphic
+ identifiedGraphic.geometry?.let {
+ geometryEditor.start(it)
+ }
+ }
+ }
+ // reset the identified graphic back to null
+ identifiedGraphic.geometry = null
+ }
+ }
+ }
+
+}
diff --git a/samples/create-and-edit-geometries/src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/screens/ButtonMenu.kt b/samples/create-and-edit-geometries/src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/screens/ButtonMenu.kt
new file mode 100644
index 000000000..e005e2ed0
--- /dev/null
+++ b/samples/create-and-edit-geometries/src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/screens/ButtonMenu.kt
@@ -0,0 +1,107 @@
+/* Copyright 2025 Esri
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.esri.arcgismaps.sample.createandeditgeometries.screens
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.Create
+import androidx.compose.material3.DropdownMenu
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.arcgismaps.geometry.GeometryType
+
+/**
+ * Composable component to display the menu buttons.
+ */
+@Composable
+fun ButtonMenu(
+ isGeometryEditorStarted: Boolean,
+ onStartEditingButtonClick: (GeometryType) -> Unit,
+ onStopEditingButtonClick: () -> Unit
+) {
+ val rowModifier = Modifier
+ .padding(12.dp)
+ .fillMaxWidth()
+
+ Row(
+ modifier = rowModifier
+ ) {
+ var expanded by remember { mutableStateOf(false) }
+ Box(
+ modifier = Modifier
+ ) {
+ IconButton(
+ enabled = !isGeometryEditorStarted,
+ onClick = { expanded = !expanded }
+ ) {
+ Icon(imageVector = Icons.Default.Create, contentDescription = "Start")
+ }
+ DropdownMenu(
+ expanded = expanded,
+ onDismissRequest = { expanded = false }
+ ) {
+ DropdownMenuItem(
+ text = { Text("Point") },
+ onClick = {
+ onStartEditingButtonClick(GeometryType.Point)
+ expanded = false
+ }
+ )
+ DropdownMenuItem(
+ text = { Text("Multipoint") },
+ onClick = {
+ onStartEditingButtonClick(GeometryType.Multipoint)
+ expanded = false
+ }
+ )
+ DropdownMenuItem(
+ text = { Text("Polyline") },
+ onClick = {
+ onStartEditingButtonClick(GeometryType.Polyline)
+ expanded = false
+ }
+ )
+ DropdownMenuItem(
+ text = { Text("Polygon") },
+ onClick = {
+ onStartEditingButtonClick(GeometryType.Polygon)
+ expanded = false
+ }
+ )
+ }
+ }
+ IconButton(
+ enabled = isGeometryEditorStarted,
+ onClick = { onStopEditingButtonClick() }
+ ) {
+ Icon(imageVector = Icons.Default.Check, contentDescription = "Save Edits")
+ }
+ }
+}
diff --git a/samples/create-and-edit-geometries/src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/screens/CreateAndEditGeometriesScreen.kt b/samples/create-and-edit-geometries/src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/screens/CreateAndEditGeometriesScreen.kt
new file mode 100644
index 000000000..e80aa770c
--- /dev/null
+++ b/samples/create-and-edit-geometries/src/main/java/com/esri/arcgismaps/sample/createandeditgeometries/screens/CreateAndEditGeometriesScreen.kt
@@ -0,0 +1,75 @@
+/* Copyright 2025 Esri
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.esri.arcgismaps.sample.createandeditgeometries.screens
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Scaffold
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.lifecycle.viewmodel.compose.viewModel
+import com.arcgismaps.toolkit.geoviewcompose.MapView
+import com.esri.arcgismaps.sample.createandeditgeometries.components.CreateAndEditGeometriesViewModel
+import com.esri.arcgismaps.sample.sampleslib.components.MessageDialog
+import com.esri.arcgismaps.sample.sampleslib.components.SampleTopAppBar
+
+/**
+ * Main screen layout for the sample app
+ */
+@Composable
+fun CreateAndEditGeometriesScreen(sampleName: String) {
+ // create a ViewModel to handle MapView interactions
+ val mapViewModel: CreateAndEditGeometriesViewModel = viewModel()
+
+ Scaffold(
+ topBar = { SampleTopAppBar(title = sampleName) },
+ content = {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(it),
+ ) {
+ MapView(
+ modifier = Modifier
+ .fillMaxSize()
+ .weight(1f),
+ arcGISMap = mapViewModel.arcGISMap,
+ mapViewProxy = mapViewModel.mapViewProxy,
+ geometryEditor = mapViewModel.geometryEditor,
+ graphicsOverlays = listOf(mapViewModel.graphicsOverlay),
+ onSingleTapConfirmed = mapViewModel::identify,
+ )
+ ButtonMenu(
+ mapViewModel.geometryEditor.isStarted.collectAsStateWithLifecycle().value,
+ mapViewModel::startEditor,
+ mapViewModel::stopEditor
+ )
+ mapViewModel.messageDialogVM.apply {
+ if (dialogStatus) {
+ MessageDialog(
+ title = messageTitle,
+ description = messageDescription,
+ onDismissRequest = ::dismissDialog
+ )
+ }
+ }
+ }
+ }
+ )
+}
diff --git a/samples/create-and-edit-geometries/src/main/res/values/strings.xml b/samples/create-and-edit-geometries/src/main/res/values/strings.xml
new file mode 100644
index 000000000..af1a89fa8
--- /dev/null
+++ b/samples/create-and-edit-geometries/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Create and edit geometries
+