Skip to content

Commit 6c01c6b

Browse files
committed
Initial Commit.
0 parents  commit 6c01c6b

39 files changed

+871
-0
lines changed

.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

app/build.gradle

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
apply plugin: 'com.android.application'
2+
apply plugin: 'kotlin-android'
3+
apply plugin: 'kotlin-android-extensions'
4+
5+
android {
6+
compileSdkVersion 27
7+
defaultConfig {
8+
applicationId "com.spartons.driverapp"
9+
minSdkVersion 20
10+
targetSdkVersion 27
11+
versionCode 1
12+
versionName "1.0"
13+
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14+
}
15+
buildTypes {
16+
release {
17+
minifyEnabled false
18+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19+
}
20+
}
21+
}
22+
23+
dependencies {
24+
implementation fileTree(dir: 'libs', include: ['*.jar'])
25+
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
26+
implementation 'com.android.support:appcompat-v7:27.1.1'
27+
implementation 'com.android.support:support-v4:27.1.1'
28+
implementation 'com.android.support:animated-vector-drawable:27.1.1'
29+
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
30+
implementation 'com.google.android.gms:play-services-maps:15.0.1'
31+
implementation 'com.google.firebase:firebase-database:16.0.1'
32+
implementation 'com.google.android.gms:play-services-location:15.0.1'
33+
implementation 'com.afollestad.material-dialogs:core:0.9.6.0'
34+
testImplementation 'junit:junit:4.12'
35+
androidTestImplementation 'com.android.support.test:runner:1.0.2'
36+
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
37+
}
38+
apply plugin: 'com.google.gms.google-services'

app/proguard-rules.pro

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.spartons.driverapp
2+
3+
import android.support.test.InstrumentationRegistry
4+
import android.support.test.runner.AndroidJUnit4
5+
6+
import org.junit.Test
7+
import org.junit.runner.RunWith
8+
9+
import org.junit.Assert.*
10+
11+
/**
12+
* Instrumented test, which will execute on an Android device.
13+
*
14+
* See [testing documentation](http://d.android.com/tools/testing).
15+
*/
16+
@RunWith(AndroidJUnit4::class)
17+
class ExampleInstrumentedTest {
18+
@Test
19+
fun useAppContext() {
20+
// Context of the app under test.
21+
val appContext = InstrumentationRegistry.getTargetContext()
22+
assertEquals("com.spartons.driverapp", appContext.packageName)
23+
}
24+
}

app/src/main/AndroidManifest.xml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
package="com.spartons.driverapp">
4+
5+
<uses-feature
6+
android:glEsVersion="0x00020000"
7+
android:required="true" />
8+
9+
<permission
10+
android:name="com.spartons.driverapp.permission.MAPS_RECEIVE"
11+
android:protectionLevel="signature" />
12+
13+
<uses-permission android:name="android.permission.INTERNET" />
14+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
15+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
16+
17+
<application
18+
android:allowBackup="true"
19+
android:icon="@mipmap/ic_launcher"
20+
android:label="@string/app_name"
21+
android:roundIcon="@mipmap/ic_launcher_round"
22+
android:supportsRtl="true"
23+
android:theme="@style/AppTheme">
24+
<activity android:name=".MainActivity">
25+
<intent-filter>
26+
<action android:name="android.intent.action.MAIN" />
27+
28+
<category android:name="android.intent.category.LAUNCHER" />
29+
</intent-filter>
30+
</activity>
31+
32+
<meta-data
33+
android:name="com.google.android.gms.version"
34+
android:value="@integer/google_play_services_version" />
35+
36+
<meta-data
37+
android:name="com.google.android.geo.API_KEY"
38+
android:value="@string/map_api_key" />
39+
40+
41+
</application>
42+
43+
</manifest>
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package com.spartons.driverapp
2+
3+
import android.Manifest
4+
import android.annotation.SuppressLint
5+
import android.content.Intent
6+
import android.content.pm.PackageManager.PERMISSION_DENIED
7+
import android.content.pm.PackageManager.PERMISSION_GRANTED
8+
import android.os.Bundle
9+
import android.os.Looper
10+
import android.provider.Settings
11+
import android.support.v4.app.ActivityCompat
12+
import android.support.v7.app.AppCompatActivity
13+
import android.support.v7.widget.SwitchCompat
14+
import android.util.Log
15+
import android.widget.TextView
16+
import android.widget.Toast
17+
import com.google.android.gms.location.*
18+
import com.google.android.gms.maps.GoogleMap
19+
import com.google.android.gms.maps.OnMapReadyCallback
20+
import com.google.android.gms.maps.SupportMapFragment
21+
import com.google.android.gms.maps.model.LatLng
22+
import com.google.android.gms.maps.model.Marker
23+
import com.spartons.driverapp.helper.*
24+
import com.spartons.driverapp.interfaces.IPositiveNegativeListener
25+
import com.spartons.driverapp.interfaces.LatLngInterpolator
26+
import com.spartons.driverapp.model.Driver
27+
28+
class MainActivity : AppCompatActivity() {
29+
30+
companion object {
31+
private const val MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 2200
32+
}
33+
34+
private lateinit var googleMap: GoogleMap
35+
private lateinit var locationProviderClient: FusedLocationProviderClient
36+
private lateinit var locationRequest: LocationRequest
37+
private lateinit var locationCallback: LocationCallback
38+
private var locationFlag = true
39+
private var driverOnlineFlag = false
40+
private var currentPositionMarker: Marker? = null
41+
private val googleMapHelper = GoogleMapHelper()
42+
private val firebaseHelper = FirebaseHelper("0000")
43+
private val markerAnimationHelper = MarkerAnimationHelper()
44+
private val uiHelper = UiHelper()
45+
46+
override fun onCreate(savedInstanceState: Bundle?) {
47+
super.onCreate(savedInstanceState)
48+
setContentView(R.layout.activity_main)
49+
val mapFragment: SupportMapFragment = supportFragmentManager.findFragmentById(R.id.supportMap) as SupportMapFragment
50+
mapFragment.getMapAsync(object : OnMapReadyCallback {
51+
override fun onMapReady(p0: GoogleMap?) {
52+
googleMap = p0!!
53+
}
54+
})
55+
createLocationCallback()
56+
locationProviderClient = LocationServices.getFusedLocationProviderClient(this)
57+
locationRequest = uiHelper.getLocationRequest()
58+
if (!uiHelper.isPlayServicesAvailable(this)) {
59+
Toast.makeText(this, "Play Services did not installed!", Toast.LENGTH_SHORT).show()
60+
finish()
61+
} else requestLocationUpdate()
62+
val driverStatusTextView = findViewById<TextView>(R.id.driverStatusTextView)
63+
findViewById<SwitchCompat>(R.id.driverStatusSwitch).setOnCheckedChangeListener { _, b ->
64+
driverOnlineFlag = b
65+
if (driverOnlineFlag) driverStatusTextView.text = resources.getString(R.string.online_driver)
66+
else {
67+
driverStatusTextView.text = resources.getString(R.string.offline)
68+
firebaseHelper.deleteDriver()
69+
}
70+
}
71+
}
72+
73+
@SuppressLint("MissingPermission")
74+
private fun requestLocationUpdate() {
75+
if (!uiHelper.isHaveLocationPermission(this)) {
76+
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION)
77+
return
78+
}
79+
if (uiHelper.isLocationProviderEnabled(this))
80+
uiHelper.showPositiveDialogWithListener(this, resources.getString(R.string.need_location), resources.getString(R.string.location_content), object : IPositiveNegativeListener {
81+
override fun onPositive() {
82+
startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
83+
}
84+
}, "Turn On", false)
85+
locationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper())
86+
}
87+
88+
private fun createLocationCallback() {
89+
locationCallback = object : LocationCallback() {
90+
override fun onLocationResult(locationResult: LocationResult?) {
91+
super.onLocationResult(locationResult)
92+
if (locationResult!!.lastLocation == null) return
93+
val latLng = LatLng(locationResult.lastLocation.latitude, locationResult.lastLocation.longitude)
94+
Log.e("Location", latLng.latitude.toString() + " , " + latLng.longitude)
95+
if (locationFlag) {
96+
locationFlag = false
97+
animateCamera(latLng)
98+
}
99+
if (driverOnlineFlag) firebaseHelper.updateDriver(Driver(lat = latLng.latitude, lng = latLng.longitude))
100+
showOrAnimateMarker(latLng)
101+
}
102+
}
103+
}
104+
105+
private fun showOrAnimateMarker(latLng: LatLng) {
106+
if (currentPositionMarker == null)
107+
currentPositionMarker = googleMap.addMarker(googleMapHelper.getDriverMarkerOptions(latLng))
108+
else markerAnimationHelper.animateMarkerToGB(currentPositionMarker!!, latLng, LatLngInterpolator.Spherical())
109+
}
110+
111+
private fun animateCamera(latLng: LatLng) {
112+
val cameraUpdate = googleMapHelper.buildCameraUpdate(latLng)
113+
googleMap.animateCamera(cameraUpdate, 10, null)
114+
}
115+
116+
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
117+
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
118+
if (requestCode == MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION) {
119+
val value = grantResults[0]
120+
if (value == PERMISSION_DENIED) {
121+
Toast.makeText(this, "Location Permission denied", Toast.LENGTH_SHORT).show()
122+
finish()
123+
} else if (value == PERMISSION_GRANTED) requestLocationUpdate()
124+
}
125+
}
126+
}
127+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.spartons.driverapp.helper
2+
3+
import android.util.Log
4+
import com.google.firebase.database.DatabaseReference
5+
import com.google.firebase.database.FirebaseDatabase
6+
import com.spartons.driverapp.model.Driver
7+
8+
class FirebaseHelper constructor(driverId: String) {
9+
10+
companion object {
11+
private const val ONLINE_DRIVERS = "online_drivers"
12+
}
13+
14+
private val onlineDriverDatabaseReference: DatabaseReference = FirebaseDatabase
15+
.getInstance()
16+
.reference
17+
.child(ONLINE_DRIVERS)
18+
.child(driverId)
19+
20+
init {
21+
onlineDriverDatabaseReference
22+
.onDisconnect()
23+
.removeValue()
24+
}
25+
26+
fun updateDriver(driver: Driver) {
27+
onlineDriverDatabaseReference
28+
.setValue(driver)
29+
Log.e("Driver Info", " Updated")
30+
}
31+
32+
fun deleteDriver() {
33+
onlineDriverDatabaseReference
34+
.removeValue()
35+
}
36+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.spartons.driverapp.helper
2+
3+
import com.google.android.gms.maps.CameraUpdate
4+
import com.google.android.gms.maps.CameraUpdateFactory
5+
import com.google.android.gms.maps.model.BitmapDescriptorFactory
6+
import com.google.android.gms.maps.model.CameraPosition
7+
import com.google.android.gms.maps.model.LatLng
8+
import com.google.android.gms.maps.model.MarkerOptions
9+
import com.spartons.driverapp.R
10+
11+
class GoogleMapHelper {
12+
13+
companion object {
14+
private const val ZOOM_LEVEL = 18
15+
private const val TILT_LEVEL = 25
16+
}
17+
18+
/**
19+
* @param latLng in which position to Zoom the camera.
20+
* @return the [CameraUpdate] with Zoom and Tilt level added with the given position.
21+
*/
22+
23+
fun buildCameraUpdate(latLng: LatLng): CameraUpdate {
24+
val cameraPosition = CameraPosition.Builder()
25+
.target(latLng)
26+
.tilt(TILT_LEVEL.toFloat())
27+
.zoom(ZOOM_LEVEL.toFloat())
28+
.build()
29+
return CameraUpdateFactory.newCameraPosition(cameraPosition)
30+
}
31+
32+
/**
33+
* @param position where to draw the [com.google.android.gms.maps.model.Marker]
34+
* @return the [MarkerOptions] with given properties added to it.
35+
*/
36+
37+
fun getDriverMarkerOptions(position: LatLng): MarkerOptions {
38+
val options = getMarkerOptions(R.drawable.car_icon, position)
39+
options.flat(true)
40+
return options
41+
}
42+
43+
private fun getMarkerOptions(resource: Int, position: LatLng): MarkerOptions {
44+
return MarkerOptions()
45+
.icon(BitmapDescriptorFactory.fromResource(resource))
46+
.position(position)
47+
}
48+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.spartons.driverapp.helper
2+
3+
import android.os.Handler
4+
import android.os.SystemClock
5+
import android.view.animation.AccelerateDecelerateInterpolator
6+
import com.google.android.gms.maps.model.LatLng
7+
import com.google.android.gms.maps.model.Marker
8+
import com.spartons.driverapp.interfaces.LatLngInterpolator
9+
10+
class MarkerAnimationHelper {
11+
12+
fun animateMarkerToGB(marker: Marker, finalPosition: LatLng, latLngInterpolator: LatLngInterpolator) {
13+
val startPosition = marker.position
14+
val handler = Handler()
15+
val start = SystemClock.uptimeMillis()
16+
val interpolator = AccelerateDecelerateInterpolator()
17+
val durationInMs = 2000f
18+
handler.post(object : Runnable {
19+
var elapsed: Long = 0
20+
var t: Float = 0.toFloat()
21+
var v: Float = 0.toFloat()
22+
override fun run() {
23+
// Calculate progress using interpolator
24+
elapsed = SystemClock.uptimeMillis() - start
25+
t = elapsed / durationInMs
26+
v = interpolator.getInterpolation(t)
27+
marker.position = latLngInterpolator.interpolate(v, startPosition, finalPosition)
28+
// Repeat till progress is complete.
29+
if (t < 1) {
30+
// Post again 16ms later.
31+
handler.postDelayed(this, 16)
32+
}
33+
}
34+
})
35+
}
36+
}

0 commit comments

Comments
 (0)