diff --git a/sharing/android/README.md b/sharing/android/README.md
new file mode 100644
index 00000000..a9e26abb
--- /dev/null
+++ b/sharing/android/README.md
@@ -0,0 +1,59 @@
+# Nearby Sharing Android API
+
+## The slice API
+The nearby module in GMSCore provides a third-party accessible slice to bind to, to provide live data on nearby targets using Nearby Share. Clicking on any of these targets will take you to the main Nearby Share screen, where the transfer will begin and continually update the progress.
+
+The slice URI is `content://com.google.android.gms.nearby.sharing/scan`. Upon first launch after install, you will be prompted to grant permission to the client application. After that, the slice will be kept up to date with the latest targets nearby.
+
+## How to use the API ##
+In Kotlin:
+```kotlin
+// Derive the Slice URI.
+val sliceUri = Uri.parse("content://com.google.android.gms.nearby.sharing/scan")
+// Get the SliceViewManager
+val sliceManager = SliceViewManager.getInstance(context)
+// Pin the slice and register your callback.
+sliceManager.registerSliceCallback(sliceUri, { slice: Slice? ->
+ if (slice == null) {
+ return
+ }
+ for (targetItem in slice.items.reversed()) {
+ // Each row containing a target has the hints LIST_ITEM and ACTIVITY.
+ if (!(targetItem.format == SLICE && targetItem.hints.containsAll(listOf(LIST_ITEM, ACTIVITY)))) {
+ continue
+ }
+ val targetSlice = targetItem.slice
+ var deviceName: String? = null
+ var action: PendingIntent? = null
+ var profileIcon: IconCompat? = null
+
+ for (item in targetSlice.items) {
+ // The slice item of the target's device name contains the TITLE hint.
+ if (item.format == TEXT && item.hints.contains(TITLE)) {
+ deviceName = item.text.toString()
+ }
+ // The slice item of the target action contains the SHORTCUT and TITLE hints.
+ if (item.format == ACTION && item.hints.containsAll(listOf(SHORTCUT, TITLE))) {
+ action = item.action
+
+ val iconSlice: Slice? = item.slice
+ if (iconSlice != null) {
+ for (iconitem in iconSlice.items) {
+ // The target's icon is indicated by the IMAGE slice item format and the NO_TINT hint.
+ if (iconitem.format == IMAGE && iconitem.hints.contains(NO_TINT)) {
+ profileIcon = iconitem.icon
+ }
+ }
+ }
+ }
+ }
+ // Returns null if the data parsed from the slice is incomplete.
+ if (deviceName == null || action == null || profileIcon == null) {
+ continue
+ }
+ }
+})
+// Remember to bind the slice after you pin it to avoid race conditions!
+val slice = sliceManager.bindSlice(sliceUri)
+```
+Refer to the [SliceViewManager#registerSliceCallback() documentation](https://developer.android.com/reference/androidx/slice/SliceViewManager#registerSliceCallback(android.net.Uri,androidx.slice.SliceViewManager.SliceCallback)) for more information about the race condition described above.
diff --git a/sharing/android/example/.gitignore b/sharing/android/example/.gitignore
new file mode 100644
index 00000000..565a5412
--- /dev/null
+++ b/sharing/android/example/.gitignore
@@ -0,0 +1,16 @@
+*.iml
+.gradle
+.idea
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/sharing/android/example/README.md b/sharing/android/example/README.md
new file mode 100644
index 00000000..24f43575
--- /dev/null
+++ b/sharing/android/example/README.md
@@ -0,0 +1,25 @@
+# Nearby Share sample app
+
+This app is a demonstration of how to bind to and use the Nearby Share slice.
+
+## Build instructions
+From the root of the repository:
+```
+// Run this before importing into Android Studio!
+$ cd sharing/android/example
+$ gradle wrapper
+$ ./gradlew build
+```
+For the gradle wrapper, we recommend Gradle 8.0+.
+
+## Key callouts
+MainViewModel - contains the business logic for processing and binding to the slice, as well as the lifecycle of the slice.
+
+MainActivity - hosts the `MainView` composable and provides the intent to fill in the slice's PendingIntent action with, providing the data to send via Nearby Share.
+
+## Screenshots
+
+
+
+
+
diff --git a/sharing/android/example/app/.gitignore b/sharing/android/example/app/.gitignore
new file mode 100644
index 00000000..796b96d1
--- /dev/null
+++ b/sharing/android/example/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/sharing/android/example/app/build.gradle.kts b/sharing/android/example/app/build.gradle.kts
new file mode 100644
index 00000000..acbe5cc2
--- /dev/null
+++ b/sharing/android/example/app/build.gradle.kts
@@ -0,0 +1,62 @@
+plugins {
+ id("com.android.application")
+ id("org.jetbrains.kotlin.android")
+}
+
+android {
+ namespace = "com.google.nearby.sharedemo"
+ compileSdk = 33
+
+ defaultConfig {
+ applicationId = "com.google.nearby.sharedemo"
+ minSdk = 30
+ targetSdk = 33
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ vectorDrawables {
+ useSupportLibrary = true
+ }
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+ buildFeatures {
+ compose = true
+ }
+ composeOptions {
+ kotlinCompilerExtensionVersion = "1.4.3"
+ }
+ packaging {
+ resources {
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
+ }
+ }
+}
+
+dependencies {
+ implementation("androidx.core:core-ktx:1.9.0")
+ implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
+ implementation("androidx.activity:activity-compose:1.7.2")
+ implementation(platform("androidx.compose:compose-bom:2023.03.00"))
+ implementation("androidx.compose.ui:ui")
+ implementation("androidx.compose.ui:ui-graphics")
+ implementation("androidx.compose.ui:ui-tooling-preview")
+ implementation("androidx.compose.material3:material3")
+ implementation("androidx.slice:slice-core:1.1.0-alpha02")
+ implementation("androidx.slice:slice-view:1.1.0-alpha02")
+ debugImplementation("androidx.compose.ui:ui-tooling")
+ debugImplementation("androidx.compose.ui:ui-test-manifest")
+}
diff --git a/sharing/android/example/app/proguard-rules.pro b/sharing/android/example/app/proguard-rules.pro
new file mode 100644
index 00000000..f1b42451
--- /dev/null
+++ b/sharing/android/example/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/sharing/android/example/app/src/main/AndroidManifest.xml b/sharing/android/example/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..096bbb17
--- /dev/null
+++ b/sharing/android/example/app/src/main/AndroidManifest.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sharing/android/example/app/src/main/java/com/google/nearby/sharedemo/MainActivity.kt b/sharing/android/example/app/src/main/java/com/google/nearby/sharedemo/MainActivity.kt
new file mode 100644
index 00000000..f4b7672e
--- /dev/null
+++ b/sharing/android/example/app/src/main/java/com/google/nearby/sharedemo/MainActivity.kt
@@ -0,0 +1,165 @@
+package com.google.nearby.sharedemo
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.provider.OpenableColumns
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.rememberLauncherForActivityResult
+import androidx.activity.compose.setContent
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.activity.viewModels
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
+import androidx.compose.foundation.lazy.grid.items
+import androidx.compose.material3.Button
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.slice.Slice
+import androidx.slice.widget.SliceView
+import com.google.nearby.sharedemo.ui.theme.NearbyShareDemoTheme
+
+class MainActivity : ComponentActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val viewModel: MainViewModel by viewModels(factoryProducer = { MainViewModel.Factory })
+ setContent {
+ NearbyShareDemoTheme {
+ // A surface container using the 'background' color from the theme
+ val state by viewModel.targetsFlow.collectAsState()
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(MaterialTheme.colorScheme.background)
+ ) {
+ MainView(
+ state,
+ onShareTargetClicked = { data, intent ->
+ viewModel.onShareTargetClicked(data, this@MainActivity, intent)
+ })
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun MainView(
+ state: SliceState,
+ onShareTargetClicked: (ShareTargetData, Intent) -> Unit,
+) {
+ when (state) {
+ is SliceState.PermissionNeeded -> {
+ AndroidView(factory = {
+ val view = SliceView(it)
+ view.slice = state.slice
+ return@AndroidView view
+ })
+ }
+
+ is SliceState.Active -> {
+ var uris by rememberSaveable { mutableStateOf(listOf()) }
+ val launcher =
+ rememberLauncherForActivityResult(contract = ActivityResultContracts.GetMultipleContents()) {
+ uris = it
+ }
+ Column {
+ Button(onClick = { launcher.launch("*/*") }) { Text("Select files") }
+ if (uris.isNotEmpty()) {
+ for (uri in uris) {
+ Text(
+ uri.toString(),
+ style = MaterialTheme.typography.bodySmall
+ )
+ }
+ val sendIntent =
+ Intent("com.google.android.gms.SHARE_NEARBY").apply {
+ if (uris.size == 1) {
+ putExtra(Intent.EXTRA_STREAM, uris[0])
+ } else {
+ putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris.toArrayList())
+ }
+ type = "*/*"
+ flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+ }
+ val context = LocalContext.current
+ // We need to call sendIntent.migrateExtraStreamToClipData() to show the preview images on
+ // Android Q and above but the method is hidden. Hence we call PendingIntent.getActivity as
+ // a proxy/wrapper which calls the above method. This method can throw exception if files
+ // are too large.
+ // We need to call sendIntent.migrateExtraStreamToClipData() to show the preview images on
+ // Android Q and above but the method is hidden. Hence we call PendingIntent.getActivity as
+ // a proxy/wrapper which calls the above method. This method can throw exception if files
+ // are too large.
+ val pendingIntentFlags = PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
+
+ PendingIntent.getActivity(context.applicationContext, 0, sendIntent, pendingIntentFlags)
+ ShareDestinations(sendIntent, state.targets, onShareTargetClicked = { data, intent ->
+ for (uri in uris) {
+ context.grantUriPermission(
+ "com.google.android.gms",
+ uri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ )
+ }
+ onShareTargetClicked(data, intent)
+ })
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun ShareDestinations(
+ sendIntent: Intent,
+ targets: Set,
+ onShareTargetClicked: (ShareTargetData, Intent) -> Unit,
+) {
+ Card(
+ modifier = Modifier.padding(16.dp),
+ colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant)
+ ) {
+ if (targets.isEmpty()) {
+ Text("No devices nearby!")
+ return@Card
+ }
+ LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 72.dp)) {
+ items(targets.toList()) {
+ ShareTarget(data = it, onShareTargetClicked = { data ->
+ onShareTargetClicked(data, sendIntent)
+ })
+ }
+ }
+ }
+}
+
+private fun List.toArrayList(): java.util.ArrayList {
+ val list = java.util.ArrayList()
+ list.addAll(this)
+ return list
+}
+
+sealed class SliceState {
+ data class PermissionNeeded(val slice: Slice) : SliceState()
+ data class Active(val targets: Set) : SliceState()
+}
diff --git a/sharing/android/example/app/src/main/java/com/google/nearby/sharedemo/MainViewModel.kt b/sharing/android/example/app/src/main/java/com/google/nearby/sharedemo/MainViewModel.kt
new file mode 100644
index 00000000..0cd48102
--- /dev/null
+++ b/sharing/android/example/app/src/main/java/com/google/nearby/sharedemo/MainViewModel.kt
@@ -0,0 +1,123 @@
+package com.google.nearby.sharedemo
+
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import androidx.core.graphics.drawable.IconCompat
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.viewmodel.initializer
+import androidx.lifecycle.viewmodel.viewModelFactory
+import androidx.slice.Slice
+import androidx.slice.SliceViewManager
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class MainViewModel(context: Context) : ViewModel() {
+ private val _targetsFlow: MutableStateFlow = MutableStateFlow(SliceState.Active(setOf()))
+ val targetsFlow: StateFlow = _targetsFlow.asStateFlow()
+
+ private var targetMapping = mapOf()
+
+ private val sliceManager = SliceViewManager.getInstance(context)
+ private val sliceCallback: (Slice?) -> Unit = {
+ targetMapping = parseSlice(it)
+ if (targetMapping.isEmpty() && it != null) {
+ _targetsFlow.value = SliceState.PermissionNeeded(it)
+ } else {
+ _targetsFlow.value = SliceState.Active(targetMapping.keys)
+ }
+ }
+
+ init {
+ sliceManager.registerSliceCallback(SCAN_SLICE_URI, sliceCallback)
+ val slice = sliceManager.bindSlice(SCAN_SLICE_URI)
+ targetMapping = parseSlice(slice)
+ if (targetMapping.isEmpty() && slice != null) {
+ _targetsFlow.value = SliceState.PermissionNeeded(slice)
+ } else {
+ _targetsFlow.value = SliceState.Active(targetMapping.keys)
+ }
+ }
+
+ /**
+ * This function is run just before the ViewModel is closed, allowing us to unpin the sharing
+ * slice.
+ */
+ override fun onCleared() {
+ super.onCleared()
+ sliceManager.unregisterSliceCallback(SCAN_SLICE_URI, sliceCallback)
+ }
+
+ /**
+ * Called when a slice's share target is tapped, as represented by [ShareTarget].
+ */
+ fun onShareTargetClicked(data: ShareTargetData, context: Context, sendIntent: Intent) {
+ targetMapping[data]!!.send(context, 0, sendIntent)
+ }
+
+ private fun parseSlice(slice: Slice?): Map {
+ android.util.Log.d("NSDemo", "slice: $slice")
+ if (slice == null) {
+ return mapOf()
+ }
+ val ret = mutableMapOf()
+ for (targetItem in slice.items.reversed()) {
+ if (!(targetItem.format == SLICE && targetItem.hints.containsAll(listOf(LIST_ITEM, ACTIVITY)))) {
+ continue
+ }
+ val targetSlice = targetItem.slice
+ var deviceName: String? = null
+ var action: PendingIntent? = null
+ var profileIcon: IconCompat? = null
+
+ for (item in targetSlice.items) {
+ if (item.format == TEXT && item.hints.contains(TITLE)) {
+ deviceName = item.text.toString()
+ }
+ if (item.format == ACTION && item.hints.containsAll(listOf(SHORTCUT, TITLE))) {
+ action = item.action
+
+ val iconSlice: Slice? = item.slice
+ if (iconSlice != null) {
+ for (iconitem in iconSlice.items) {
+ if (iconitem.format == IMAGE && iconitem.hints.contains(NO_TINT)) {
+ profileIcon = iconitem.icon
+ }
+ }
+ }
+ }
+ }
+ // Returns null if the data parsed from the slice is incomplete.
+ if (deviceName == null || action == null || profileIcon == null) {
+ continue
+ }
+ ret[ShareTargetData(profileIcon, deviceName)] = action
+ }
+ return ret
+ }
+
+ companion object {
+ private val SCAN_SLICE_URI: Uri =
+ Uri.parse("content://com.google.android.gms.nearby.sharing/scan")
+
+ // Slice parsing.
+ private const val SLICE = "slice"
+ private const val LIST_ITEM = "list_item"
+ private const val ACTIVITY = "activity"
+ private const val TEXT = "text"
+ private const val TITLE = "title"
+ private const val ACTION = "action"
+ private const val SHORTCUT = "shortcut"
+ private const val IMAGE = "image"
+ private const val NO_TINT = "no_tint"
+
+ val Factory: ViewModelProvider.Factory = viewModelFactory {
+ initializer {
+ MainViewModel(this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY]!!)
+ }
+ }
+ }
+}
diff --git a/sharing/android/example/app/src/main/java/com/google/nearby/sharedemo/ShareTarget.kt b/sharing/android/example/app/src/main/java/com/google/nearby/sharedemo/ShareTarget.kt
new file mode 100644
index 00000000..2b3c843f
--- /dev/null
+++ b/sharing/android/example/app/src/main/java/com/google/nearby/sharedemo/ShareTarget.kt
@@ -0,0 +1,43 @@
+package com.google.nearby.sharedemo
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.core.graphics.drawable.IconCompat
+import androidx.core.graphics.drawable.toBitmap
+
+@Composable
+fun ShareTarget(data: ShareTargetData, onShareTargetClicked: (ShareTargetData) -> Unit) {
+ val context = LocalContext.current
+ Column(
+ modifier = Modifier
+ .padding(8.dp)
+ .clickable { onShareTargetClicked(data) },
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Icon(
+ data.profileIcon.loadDrawable(context)!!.toBitmap().asImageBitmap(),
+ contentDescription = null,
+ tint = Color.Unspecified,
+ )
+ Text(
+ data.deviceName,
+ style = MaterialTheme.typography.bodySmall,
+ )
+ }
+}
+
+data class ShareTargetData(
+ val profileIcon: IconCompat,
+ val deviceName: String,
+)
diff --git a/sharing/android/example/app/src/main/java/com/google/nearby/sharedemo/ui/theme/Theme.kt b/sharing/android/example/app/src/main/java/com/google/nearby/sharedemo/ui/theme/Theme.kt
new file mode 100644
index 00000000..ced49795
--- /dev/null
+++ b/sharing/android/example/app/src/main/java/com/google/nearby/sharedemo/ui/theme/Theme.kt
@@ -0,0 +1,51 @@
+package com.google.nearby.sharedemo.ui.theme
+
+import android.app.Activity
+import android.os.Build
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Typography
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.dynamicDarkColorScheme
+import androidx.compose.material3.dynamicLightColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.SideEffect
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalView
+import androidx.core.view.WindowCompat
+
+private val DarkColorScheme = darkColorScheme()
+
+private val LightColorScheme = lightColorScheme()
+
+@Composable
+fun NearbyShareDemoTheme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ // Dynamic color is available on Android 12+
+ dynamicColor: Boolean = true,
+ content: @Composable () -> Unit
+) {
+ val colorScheme = when {
+ dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
+ val context = LocalContext.current
+ dynamicLightColorScheme(context)
+ }
+ else -> LightColorScheme
+ }
+ val view = LocalView.current
+ if (!view.isInEditMode) {
+ SideEffect {
+ val window = (view.context as Activity).window
+ window.statusBarColor = colorScheme.primary.toArgb()
+ WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
+ }
+ }
+
+ MaterialTheme(
+ colorScheme = colorScheme,
+ typography = Typography(),
+ content = content
+ )
+}
diff --git a/sharing/android/example/app/src/main/res/drawable/ic_launcher_background.xml b/sharing/android/example/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 00000000..61bb79ed
--- /dev/null
+++ b/sharing/android/example/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sharing/android/example/app/src/main/res/drawable/ic_launcher_foreground.xml b/sharing/android/example/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 00000000..04d1a347
--- /dev/null
+++ b/sharing/android/example/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sharing/android/example/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/sharing/android/example/app/src/main/res/mipmap-anydpi/ic_launcher.xml
new file mode 100644
index 00000000..3fe24419
--- /dev/null
+++ b/sharing/android/example/app/src/main/res/mipmap-anydpi/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/sharing/android/example/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/sharing/android/example/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
new file mode 100644
index 00000000..3fe24419
--- /dev/null
+++ b/sharing/android/example/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/sharing/android/example/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/sharing/android/example/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 00000000..c209e78e
Binary files /dev/null and b/sharing/android/example/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/sharing/android/example/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/sharing/android/example/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..b2dfe3d1
Binary files /dev/null and b/sharing/android/example/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/sharing/android/example/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/sharing/android/example/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 00000000..4f0f1d64
Binary files /dev/null and b/sharing/android/example/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/sharing/android/example/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/sharing/android/example/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..62b611da
Binary files /dev/null and b/sharing/android/example/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/sharing/android/example/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/sharing/android/example/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 00000000..948a3070
Binary files /dev/null and b/sharing/android/example/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/sharing/android/example/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/sharing/android/example/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..1b9a6956
Binary files /dev/null and b/sharing/android/example/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/sharing/android/example/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/sharing/android/example/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 00000000..28d4b77f
Binary files /dev/null and b/sharing/android/example/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/sharing/android/example/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/sharing/android/example/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..9287f508
Binary files /dev/null and b/sharing/android/example/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/sharing/android/example/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/sharing/android/example/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 00000000..aa7d6427
Binary files /dev/null and b/sharing/android/example/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/sharing/android/example/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/sharing/android/example/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..9126ae37
Binary files /dev/null and b/sharing/android/example/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/sharing/android/example/app/src/main/res/values/colors.xml b/sharing/android/example/app/src/main/res/values/colors.xml
new file mode 100644
index 00000000..758655a2
--- /dev/null
+++ b/sharing/android/example/app/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
diff --git a/sharing/android/example/app/src/main/res/values/strings.xml b/sharing/android/example/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..d31406f5
--- /dev/null
+++ b/sharing/android/example/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Nearby Share Demo
+
diff --git a/sharing/android/example/app/src/main/res/values/themes.xml b/sharing/android/example/app/src/main/res/values/themes.xml
new file mode 100644
index 00000000..3632dee2
--- /dev/null
+++ b/sharing/android/example/app/src/main/res/values/themes.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/sharing/android/example/app/src/main/res/xml/backup_rules.xml b/sharing/android/example/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 00000000..d0ef1359
--- /dev/null
+++ b/sharing/android/example/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/sharing/android/example/app/src/main/res/xml/data_extraction_rules.xml b/sharing/android/example/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 00000000..d868289e
--- /dev/null
+++ b/sharing/android/example/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
diff --git a/sharing/android/example/build.gradle.kts b/sharing/android/example/build.gradle.kts
new file mode 100644
index 00000000..92ffad26
--- /dev/null
+++ b/sharing/android/example/build.gradle.kts
@@ -0,0 +1,5 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ id("com.android.application") version "8.1.1" apply false
+ id("org.jetbrains.kotlin.android") version "1.8.10" apply false
+}
diff --git a/sharing/android/example/gradle.properties b/sharing/android/example/gradle.properties
new file mode 100644
index 00000000..2cbd6d19
--- /dev/null
+++ b/sharing/android/example/gradle.properties
@@ -0,0 +1,23 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
diff --git a/sharing/android/example/screenshots/consent.png b/sharing/android/example/screenshots/consent.png
new file mode 100644
index 00000000..37ea82fb
Binary files /dev/null and b/sharing/android/example/screenshots/consent.png differ
diff --git a/sharing/android/example/screenshots/devices.png b/sharing/android/example/screenshots/devices.png
new file mode 100644
index 00000000..2f9b3c73
Binary files /dev/null and b/sharing/android/example/screenshots/devices.png differ
diff --git a/sharing/android/example/screenshots/no_devices.png b/sharing/android/example/screenshots/no_devices.png
new file mode 100644
index 00000000..254217b2
Binary files /dev/null and b/sharing/android/example/screenshots/no_devices.png differ
diff --git a/sharing/android/example/settings.gradle.kts b/sharing/android/example/settings.gradle.kts
new file mode 100644
index 00000000..cf3e20db
--- /dev/null
+++ b/sharing/android/example/settings.gradle.kts
@@ -0,0 +1,17 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "Nearby Share Demo"
+include(":app")