chore: add build artifacts, map assets, and routing data
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
@@ -0,0 +1,89 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- Permissions for High-Precision Navigation and Background Audio -->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
|
||||
<application
|
||||
android:label="خرائط سيرو"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:taskAffinity=""
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
|
||||
<!-- Custom URI Scheme: siromaps:// -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="siromaps" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- Standard Geo Scheme: geo:lat,lng -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="geo" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
|
||||
<!-- Android Auto Navigation Service -->
|
||||
<service
|
||||
android:name=".car.SiroCarAppService"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="androidx.car.app.CarAppService" />
|
||||
<category android:name="androidx.car.app.category.NAVIGATION"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<meta-data
|
||||
android:name="androidx.car.app.minCarApiLevel"
|
||||
android:value="1" />
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.car.application"
|
||||
android:resource="@xml/automotive_app_desc" />
|
||||
</application>
|
||||
<!-- Required to query activities that can process text, see:
|
||||
https://developer.android.com/training/package-visibility and
|
||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||
|
||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||
<data android:mimeType="text/plain"/>
|
||||
</intent>
|
||||
</queries>
|
||||
</manifest>
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.siro_map.siro_maps
|
||||
|
||||
import com.siro_map.siro_maps.car.CarNavigationState
|
||||
import com.siro_map.siro_maps.car.SiroCarAppService
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
|
||||
class MainActivity : FlutterActivity() {
|
||||
private val CHANNEL = "com.siro.siro_maps/car_navigation"
|
||||
|
||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||
super.configureFlutterEngine(flutterEngine)
|
||||
|
||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
|
||||
when (call.method) {
|
||||
"isCarAppConnected" -> {
|
||||
result.success(SiroCarAppService.isConnected)
|
||||
}
|
||||
"updateNavState" -> {
|
||||
try {
|
||||
val lat = call.argument<Double>("lat") ?: 0.0
|
||||
val lng = call.argument<Double>("lng") ?: 0.0
|
||||
val bearing = call.argument<Double>("bearing") ?: 0.0
|
||||
val speed = call.argument<Double>("speed") ?: 0.0
|
||||
val instruction = call.argument<String>("instruction") ?: ""
|
||||
val distanceToStep = call.argument<Double>("distanceToStep") ?: 0.0
|
||||
val totalDistance = call.argument<Double>("totalDistance") ?: 0.0
|
||||
val eta = call.argument<Double>("eta") ?: 0.0
|
||||
val maneuver = call.argument<Int>("maneuver") ?: 0
|
||||
val isNavigating = call.argument<Boolean>("isNavigating") ?: false
|
||||
val isMapDarkMode = call.argument<Boolean>("isMapDarkMode") ?: false
|
||||
|
||||
val newState = CarNavigationState(
|
||||
lat = lat,
|
||||
lng = lng,
|
||||
bearing = bearing,
|
||||
speed = speed,
|
||||
instruction = instruction,
|
||||
distanceToStep = distanceToStep,
|
||||
totalDistance = totalDistance,
|
||||
eta = eta,
|
||||
maneuver = maneuver,
|
||||
isNavigating = isNavigating,
|
||||
isMapDarkMode = isMapDarkMode
|
||||
)
|
||||
SiroCarAppService.updateNavState(newState)
|
||||
result.success(true)
|
||||
} catch (e: Exception) {
|
||||
result.error("UPDATE_FAILED", e.localizedMessage, null)
|
||||
}
|
||||
}
|
||||
"stopNavigation" -> {
|
||||
SiroCarAppService.stopNavigation()
|
||||
result.success(true)
|
||||
}
|
||||
else -> {
|
||||
result.notImplemented()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.siro_map.siro_maps.car
|
||||
|
||||
data class CarNavigationState(
|
||||
val lat: Double = 0.0,
|
||||
val lng: Double = 0.0,
|
||||
val bearing: Double = 0.0,
|
||||
val speed: Double = 0.0,
|
||||
val instruction: String = "",
|
||||
val distanceToStep: Double = 0.0,
|
||||
val totalDistance: Double = 0.0,
|
||||
val eta: Double = 0.0,
|
||||
val maneuver: Int = 0,
|
||||
val isNavigating: Boolean = false,
|
||||
val isMapDarkMode: Boolean = false
|
||||
) {
|
||||
val formattedSpeed: String
|
||||
get() = "${speed.toInt()} كم/س"
|
||||
|
||||
val formattedRemainingDistance: String
|
||||
get() = if (totalDistance >= 1000) {
|
||||
String.format("%.1f كم", totalDistance / 1000.0)
|
||||
} else {
|
||||
"${totalDistance.toInt()} م"
|
||||
}
|
||||
|
||||
val formattedDistanceToStep: String
|
||||
get() = if (distanceToStep >= 1000) {
|
||||
String.format("بعد %.1f كم", distanceToStep / 1000.0)
|
||||
} else {
|
||||
"بعد ${distanceToStep.toInt()} م"
|
||||
}
|
||||
|
||||
val formattedRemainingDuration: String
|
||||
get() {
|
||||
val minutes = (eta / 60.0).toInt()
|
||||
return if (minutes >= 60) {
|
||||
val hours = minutes / 60
|
||||
val remMin = minutes % 60
|
||||
"$hours س $remMin د"
|
||||
} else {
|
||||
"$minutes دقيقة"
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package com.siro_map.siro_maps.car
|
||||
|
||||
import androidx.car.app.CarAppService
|
||||
import androidx.car.app.Session
|
||||
import androidx.car.app.validation.HostValidator
|
||||
|
||||
class SiroCarAppService : CarAppService() {
|
||||
|
||||
companion object {
|
||||
var currentNavState: CarNavigationState = CarNavigationState()
|
||||
var activeSession: SiroCarSession? = null
|
||||
|
||||
fun updateNavState(state: CarNavigationState) {
|
||||
currentNavState = state
|
||||
activeSession?.requestScreenUpdate()
|
||||
}
|
||||
|
||||
fun stopNavigation() {
|
||||
currentNavState = currentNavState.copy(isNavigating = false)
|
||||
activeSession?.requestScreenUpdate()
|
||||
}
|
||||
|
||||
val isConnected: Boolean
|
||||
get() = activeSession != null
|
||||
}
|
||||
|
||||
override fun createHostValidator(): HostValidator {
|
||||
return HostValidator.ALLOW_ALL_HOSTS_VALIDATOR
|
||||
}
|
||||
|
||||
override fun onCreateSession(): Session {
|
||||
val session = SiroCarSession()
|
||||
activeSession = session
|
||||
return session
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
activeSession = null
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.siro_map.siro_maps.car
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.car.app.Screen
|
||||
import androidx.car.app.Session
|
||||
|
||||
class SiroCarSession : Session() {
|
||||
private var activeScreen: SiroNavScreen? = null
|
||||
|
||||
init {
|
||||
SiroCarAppService.activeSession = this
|
||||
}
|
||||
|
||||
override fun onCreateScreen(intent: Intent): Screen {
|
||||
val screen = SiroNavScreen(carContext)
|
||||
activeScreen = screen
|
||||
return screen
|
||||
}
|
||||
|
||||
fun requestScreenUpdate() {
|
||||
activeScreen?.invalidate()
|
||||
}
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package com.siro_map.siro_maps.car
|
||||
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.Screen
|
||||
import androidx.car.app.model.*
|
||||
|
||||
class SiroNavScreen(carContext: CarContext) : Screen(carContext) {
|
||||
|
||||
override fun onGetTemplate(): Template {
|
||||
val state = SiroCarAppService.currentNavState
|
||||
|
||||
return if (state.isNavigating) {
|
||||
buildActiveNavTemplate(state)
|
||||
} else {
|
||||
buildIdleTemplate(state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildActiveNavTemplate(state: CarNavigationState): Template {
|
||||
val paneBuilder = Pane.Builder()
|
||||
|
||||
// 1. Current instruction & distance
|
||||
paneBuilder.addRow(
|
||||
Row.Builder()
|
||||
.setTitle(state.instruction.ifEmpty { "تابع السير نحو الوجهة" })
|
||||
.addText(state.formattedDistanceToStep)
|
||||
.build()
|
||||
)
|
||||
|
||||
// 2. Trip summary (Distance and Duration)
|
||||
paneBuilder.addRow(
|
||||
Row.Builder()
|
||||
.setTitle("المسار المتبقي")
|
||||
.addText("${state.formattedRemainingDistance} • الوصول خلال ${state.formattedRemainingDuration}")
|
||||
.build()
|
||||
)
|
||||
|
||||
// 3. Live Speed
|
||||
paneBuilder.addRow(
|
||||
Row.Builder()
|
||||
.setTitle("السرعة الحالية")
|
||||
.addText(state.formattedSpeed)
|
||||
.build()
|
||||
)
|
||||
|
||||
// Stop navigation action button
|
||||
paneBuilder.addAction(
|
||||
Action.Builder()
|
||||
.setTitle("إنهاء الملاحة")
|
||||
.setOnClickListener {
|
||||
SiroCarAppService.stopNavigation()
|
||||
invalidate()
|
||||
}
|
||||
.build()
|
||||
)
|
||||
|
||||
return PaneTemplate.Builder(paneBuilder.build())
|
||||
.setTitle("ملاحة سيرو • جارية الآن")
|
||||
.setHeaderAction(Action.APP_ICON)
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun buildIdleTemplate(state: CarNavigationState): Template {
|
||||
val paneBuilder = Pane.Builder()
|
||||
|
||||
paneBuilder.addRow(
|
||||
Row.Builder()
|
||||
.setTitle("خرائط سيرو السيادية (Siro Maps)")
|
||||
.addText("التطبيق متصل بنجاح بشاشة السيارة")
|
||||
.build()
|
||||
)
|
||||
|
||||
paneBuilder.addRow(
|
||||
Row.Builder()
|
||||
.setTitle("وضع القيادة الحر")
|
||||
.addText("السرعة: ${state.formattedSpeed}")
|
||||
.build()
|
||||
)
|
||||
|
||||
paneBuilder.addRow(
|
||||
Row.Builder()
|
||||
.setTitle("بدء الملاحة")
|
||||
.addText("حدد وجهتك من شاشة الهاتف للانتقال الفوري إلى وضع الملاحة ثلاثية الأبعاد")
|
||||
.build()
|
||||
)
|
||||
|
||||
return PaneTemplate.Builder(paneBuilder.build())
|
||||
.setTitle("خرائط سيرو")
|
||||
.setHeaderAction(Action.APP_ICON)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="?android:colorBackground" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<automotiveApp>
|
||||
<uses name="navigation" />
|
||||
</automotiveApp>
|
||||
@@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
Reference in New Issue
Block a user