Commit fd946558 authored by varun.m's avatar varun.m
Browse files

update password and AppDelegate, Podfile,

and info.plist and App Icons by Srinivas
13-05-2025
parent 2d144052
package `in`.webgrid.generp
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.PluginRegistry
class BackgroundLocationPlugin : FlutterPlugin, ActivityAware {
companion object {
/**
Legacy for v1 embedding
*/
@SuppressWarnings("deprecation")
fun registerWith(registrar: PluginRegistry.Registrar) {
val service = BackgroundLocationService.getInstance()
service.onAttachedToEngine(registrar.context(), registrar.messenger())
registrar.addRequestPermissionsResultListener(service)
}
const val TAG = "com.almoullim.Log.Tag"
const val PLUGIN_ID = "com.almoullim.background_location"
}
override fun onAttachedToEngine(binding: FlutterPluginBinding) {
BackgroundLocationService.getInstance().onAttachedToEngine(binding.applicationContext, binding.binaryMessenger)
}
override fun onDetachedFromEngine(binding: FlutterPluginBinding) {
BackgroundLocationService.getInstance().onDetachedFromEngine()
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
val service = BackgroundLocationService.getInstance()
service.setActivity(binding)
binding.addRequestPermissionsResultListener(service)
}
override fun onDetachedFromActivityForConfigChanges() {
this.onDetachedFromActivity()
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
this.onAttachedToActivity(binding)
}
override fun onDetachedFromActivity() {
BackgroundLocationService.getInstance().setActivity(null)
}
}
\ No newline at end of file
package `in`.webgrid.generp
import android.Manifest
import android.annotation.SuppressLint
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.BinaryMessenger
import android.app.Activity
import android.app.ActivityManager
import android.content.*
import android.content.pm.PackageManager
import android.location.Location
import android.os.IBinder
import android.util.Log
import android.widget.Toast
import androidx.annotation.NonNull
import androidx.core.app.ActivityCompat
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.PluginRegistry
class BackgroundLocationService: MethodChannel.MethodCallHandler, PluginRegistry.RequestPermissionsResultListener {
companion object {
const val METHOD_CHANNEL_NAME = "${BackgroundLocationPlugin.PLUGIN_ID}/methods"
private const val REQUEST_PERMISSIONS_REQUEST_CODE = 34
@SuppressLint("StaticFieldLeak")
private var instance: BackgroundLocationService? = null
/**
* Requests the singleton instance of [BackgroundLocationService] or creates it,
* if it does not yet exist.
*/
fun getInstance(): BackgroundLocationService {
if (instance == null) {
instance = BackgroundLocationService()
}
return instance!!
}
}
/**
* Context that is set once attached to a FlutterEngine.
* Context should no longer be referenced when detached.
*/
private var context: Context? = null
private lateinit var channel: MethodChannel
private var activity: Activity? = null
private var isAttached = false
private var receiver: MyReceiver? = null
private var service: LocationUpdatesService? = null
/**
* Signals whether the LocationUpdatesService is bound
*/
private var bound: Boolean = false
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
bound = true
val binder = service as LocationUpdatesService.LocalBinder
this@BackgroundLocationService.service = binder.service
requestLocation()
}
override fun onServiceDisconnected(name: ComponentName) {
service = null
}
}
fun onAttachedToEngine(@NonNull context: Context, @NonNull messenger: BinaryMessenger) {
this.context = context
isAttached = true
channel = MethodChannel(messenger, METHOD_CHANNEL_NAME)
channel.setMethodCallHandler(this)
receiver = MyReceiver()
LocalBroadcastManager.getInstance(context).registerReceiver(receiver!!,
IntentFilter(LocationUpdatesService.ACTION_BROADCAST))
}
fun onDetachedFromEngine() {
channel.setMethodCallHandler(null)
context = null
isAttached = false
}
fun setActivity(binding: ActivityPluginBinding?) {
this.activity = binding?.activity
if(this.activity != null){
if (Utils.requestingLocationUpdates(context!!)) {
if (!checkPermissions()) {
requestPermissions()
}
}
} else {
stopLocationService()
}
}
private fun startLocationService(distanceFilter: Double?, forceLocationManager : Boolean?): Int{
LocalBroadcastManager.getInstance(context!!).registerReceiver(receiver!!,
IntentFilter(LocationUpdatesService.ACTION_BROADCAST))
if (!bound) {
val intent = Intent(context, LocationUpdatesService::class.java)
intent.putExtra("distance_filter", distanceFilter)
intent.putExtra("force_location_manager", forceLocationManager)
context!!.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
}
return 0
}
private fun isLocationServiceRunning(): Boolean {
val manager: ActivityManager = context!!.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
if (LocationUpdatesService::class.java.getName() == service.service.getClassName()) {
if (service.foreground)
return true
else
return false
}
}
return false
}
private fun stopLocationService(): Int {
service?.removeLocationUpdates()
LocalBroadcastManager.getInstance(context!!).unregisterReceiver(receiver!!)
if (bound) {
context!!.unbindService(serviceConnection)
bound = false
}
return 0
}
private fun setAndroidNotification(title: String?, message: String?, icon: String?):Int{
if (title != null) LocationUpdatesService.NOTIFICATION_TITLE = title
if (message != null) LocationUpdatesService.NOTIFICATION_MESSAGE = message
if (icon != null) LocationUpdatesService.NOTIFICATION_ICON = icon
if (service != null) {
service?.updateNotification()
}
return 0
}
private fun setConfiguration(timeInterval: Long?):Int {
if (timeInterval != null) {
LocationUpdatesService.UPDATE_INTERVAL_IN_MILLISECONDS = timeInterval
LocationUpdatesService.FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = timeInterval/2
}
return 0
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: MethodChannel.Result) {
when (call.method) {
"stop_location_service" -> result.success(stopLocationService())
"start_location_service" -> result.success(startLocationService(call.argument("distance_filter"), call.argument("force_location_manager")))
"is_service_running" -> result.success(isLocationServiceRunning())
"set_android_notification" -> result.success(setAndroidNotification(call.argument("title"),call.argument("message"),call.argument("icon")))
"set_configuration" -> result.success(setConfiguration(call.argument<String>("interval")?.toLongOrNull()))
else -> result.notImplemented()
}
}
/**
* Requests a location updated.
* If permission is denied, it requests the needed permission
*/
private fun requestLocation() {
if (!checkPermissions()) {
requestPermissions()
} else {
service?.requestLocationUpdates()
}
}
/**
* Checks the current permission for `ACCESS_FINE_LOCATION`
*/
private fun checkPermissions(): Boolean {
return PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(context!!, Manifest.permission.ACCESS_FINE_LOCATION)
}
/**
* Requests permission for location.
* Depending on the current activity, displays a rationale for the request.
*/
private fun requestPermissions() {
if(activity == null) {
return
}
val shouldProvideRationale = ActivityCompat.shouldShowRequestPermissionRationale(activity!!, Manifest.permission.ACCESS_FINE_LOCATION)
if (shouldProvideRationale) {
Log.i(BackgroundLocationPlugin.TAG, "Displaying permission rationale to provide additional context.")
Toast.makeText(context, R.string.permission_rationale, Toast.LENGTH_LONG).show()
} else {
Log.i(BackgroundLocationPlugin.TAG, "Requesting permission")
ActivityCompat.requestPermissions(activity!!,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_PERMISSIONS_REQUEST_CODE)
}
}
private inner class MyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val location = intent.getParcelableExtra<Location>(LocationUpdatesService.EXTRA_LOCATION)
if (location != null) {
val locationMap = HashMap<String, Any>()
locationMap["latitude"] = location.latitude
locationMap["longitude"] = location.longitude
locationMap["altitude"] = location.altitude
locationMap["accuracy"] = location.accuracy.toDouble()
locationMap["bearing"] = location.bearing.toDouble()
locationMap["speed"] = location.speed.toDouble()
locationMap["time"] = location.time.toDouble()
locationMap["is_mock"] = location.isFromMockProvider
channel.invokeMethod("location", locationMap, null)
}
}
}
/**
* Handle the response from a permission request
* @return true if the result has been handled.
*/
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray): Boolean{
Log.i(BackgroundLocationPlugin.TAG, "onRequestPermissionResult")
if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
when {
grantResults!!.isEmpty() -> Log.i(BackgroundLocationPlugin.TAG, "User interaction was cancelled.")
grantResults[0] == PackageManager.PERMISSION_GRANTED -> service?.requestLocationUpdates()
else -> Toast.makeText(context, R.string.permission_denied_explanation, Toast.LENGTH_LONG).show()
}
}
return true
}
}
\ No newline at end of file
package `in`.webgrid.generp
import android.annotation.SuppressLint
import android.app.*
import android.location.*
import android.location.LocationListener
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.*
import androidx.core.app.NotificationCompat
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.google.android.gms.location.*
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.common.*
@SuppressLint("Registered")
class LocationUpdatesService : Service() {
private var forceLocationManager: Boolean = false
override fun onBind(intent: Intent?): IBinder {
val distanceFilter = intent?.getDoubleExtra("distance_filter", 0.0)
if (intent != null) {
forceLocationManager = intent.getBooleanExtra("force_location_manager", false)
}
if (distanceFilter != null) {
createLocationRequest(distanceFilter)
} else {
createLocationRequest(0.0)
}
return mBinder
}
private val mBinder = LocalBinder()
private var mNotificationManager: NotificationManager? = null
private var mLocationRequest: LocationRequest? = null
private var mFusedLocationClient: FusedLocationProviderClient? = null
private var mLocationManager: LocationManager? = null
private var mFusedLocationCallback: LocationCallback? = null
private var mLocationManagerCallback: LocationListener? = null
private var mLocation: Location? = null
private var isGoogleApiAvailable: Boolean = false
private var isStarted: Boolean = false
companion object {
var NOTIFICATION_TITLE = "Background service is running"
var NOTIFICATION_MESSAGE = "Background service is running"
var NOTIFICATION_ICON = "@mipmap/ic_launcher"
private const val PACKAGE_NAME = "com.google.android.gms.location.sample.locationupdatesforegroundservice"
private val TAG = LocationUpdatesService::class.java.simpleName
private const val CHANNEL_ID = "channel_01"
internal const val ACTION_BROADCAST = "$PACKAGE_NAME.broadcast"
internal const val EXTRA_LOCATION = "$PACKAGE_NAME.location"
private const val EXTRA_STARTED_FROM_NOTIFICATION = "$PACKAGE_NAME.started_from_notification"
var UPDATE_INTERVAL_IN_MILLISECONDS: Long = 1000
var FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 2
private const val NOTIFICATION_ID = 12345678
private lateinit var broadcastReceiver: BroadcastReceiver
private const val STOP_SERVICE = "stop_service"
}
private val notification: NotificationCompat.Builder
@SuppressLint("UnspecifiedImmutableFlag", "DiscouragedApi")
get() {
val intent = Intent(this, getMainActivityClass(this))
intent.putExtra(EXTRA_STARTED_FROM_NOTIFICATION, true)
intent.action = "Localisation"
//intent.setClass(this, getMainActivityClass(this))
val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
} else {
PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
val builder = NotificationCompat.Builder(this, "BackgroundLocation")
.setContentTitle(NOTIFICATION_TITLE)
.setOngoing(true)
.setSound(null)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setSmallIcon(resources.getIdentifier(NOTIFICATION_ICON, "mipmap", packageName))
.setWhen(System.currentTimeMillis())
.setStyle(NotificationCompat.BigTextStyle().bigText(NOTIFICATION_MESSAGE))
.setContentIntent(pendingIntent)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(CHANNEL_ID)
}
return builder
}
private var mServiceHandler: Handler? = null
override fun onCreate() {
val googleAPIAvailability = GoogleApiAvailability.getInstance()
.isGooglePlayServicesAvailable(applicationContext)
isGoogleApiAvailable = googleAPIAvailability == ConnectionResult.SUCCESS
if (isGoogleApiAvailable && !this.forceLocationManager) {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
mFusedLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
// Smart cast to 'Location' is impossible, because 'locationResult.lastLocation'
// is a property that has open or custom getter
val newLastLocation = locationResult.lastLocation
if (newLastLocation is Location) {
super.onLocationResult(locationResult)
onNewLocation(newLastLocation)
}
}
}
} else {
mLocationManager = getSystemService(LOCATION_SERVICE) as LocationManager?
mLocationManagerCallback = LocationListener { location ->
println(location.toString())
onNewLocation(location)
}
}
getLastLocation()
val handlerThread = HandlerThread(TAG)
handlerThread.start()
mServiceHandler = Handler(handlerThread.looper)
mNotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = "Application Name"
val mChannel = NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_DEFAULT)
mChannel.setSound(null, null)
mNotificationManager!!.createNotificationChannel(mChannel)
}
broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == "stop_service") {
removeLocationUpdates()
}
}
}
val filter = IntentFilter()
filter.addAction(STOP_SERVICE)
registerReceiver(broadcastReceiver, filter)
updateNotification() // to start the foreground service
}
fun requestLocationUpdates() {
Utils.setRequestingLocationUpdates(this, true)
try {
if (isGoogleApiAvailable && !this.forceLocationManager) {
mFusedLocationClient!!.requestLocationUpdates(mLocationRequest!!,
mFusedLocationCallback!!, Looper.myLooper())
} else {
mLocationManager?.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0L, 0f, mLocationManagerCallback!!)
}
} catch (unlikely: SecurityException) {
Utils.setRequestingLocationUpdates(this, false)
}
}
fun updateNotification() {
if (!isStarted) {
isStarted = true
startForeground(NOTIFICATION_ID, notification.build())
} else {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(NOTIFICATION_ID, notification.build())
}
}
fun removeLocationUpdates() {
stopForeground(true)
stopSelf()
}
private fun getLastLocation() {
try {
if(isGoogleApiAvailable && !this.forceLocationManager) {
mFusedLocationClient!!.lastLocation
.addOnCompleteListener { task ->
if (task.isSuccessful && task.result != null) {
mLocation = task.result
}
}
} else {
mLocation = mLocationManager!!.getLastKnownLocation(LocationManager.GPS_PROVIDER)
}
} catch (unlikely: SecurityException) {
}
}
internal fun onNewLocation(location: Location) {
mLocation = location
val intent = Intent(ACTION_BROADCAST)
intent.putExtra(EXTRA_LOCATION, location)
LocalBroadcastManager.getInstance(applicationContext).sendBroadcast(intent)
}
private fun createLocationRequest(distanceFilter: Double) {
mLocationRequest = LocationRequest()
mLocationRequest!!.interval = UPDATE_INTERVAL_IN_MILLISECONDS
mLocationRequest!!.fastestInterval = FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS
mLocationRequest!!.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
mLocationRequest!!.smallestDisplacement = distanceFilter.toFloat()
}
inner class LocalBinder : Binder() {
internal val service: LocationUpdatesService
get() = this@LocationUpdatesService
}
override fun onDestroy() {
super.onDestroy()
isStarted = false
unregisterReceiver(broadcastReceiver)
try {
if (isGoogleApiAvailable && !this.forceLocationManager) {
mFusedLocationClient!!.removeLocationUpdates(mFusedLocationCallback!!)
} else {
mLocationManager!!.removeUpdates(mLocationManagerCallback!!)
}
Utils.setRequestingLocationUpdates(this, false)
mNotificationManager!!.cancel(NOTIFICATION_ID)
} catch (unlikely: SecurityException) {
Utils.setRequestingLocationUpdates(this, true)
}
}
private fun getMainActivityClass(context: Context): Class<*>? {
val packageName = context.packageName
val launchIntent = context.packageManager.getLaunchIntentForPackage(packageName)
val className = launchIntent?.component?.className ?: return null
return try {
Class.forName(className)
} catch (e: ClassNotFoundException) {
e.printStackTrace()
null
}
}
}
\ No newline at end of file
package `in`.webgrid.generp
import `in`.webgrid.generp.BackgroundLocationPlugin
/**
* Copyright 2017 Google Inc. All Rights Reserved.
*
* 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.
*/
import android.content.Context
internal object Utils {
private const val KEY_REQUESTING_LOCATION_UPDATES = "requesting_location_updates"
private const val SHARED_PREFERENCES_FILE = "${BackgroundLocationPlugin.PLUGIN_ID}_preferences"
fun requestingLocationUpdates(context: Context): Boolean {
return context.getSharedPreferences(SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE).getBoolean(KEY_REQUESTING_LOCATION_UPDATES, false)
}
fun setRequestingLocationUpdates(context: Context, requestingLocationUpdates: Boolean) {
context.getSharedPreferences(SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE)
.edit()
.putBoolean(KEY_REQUESTING_LOCATION_UPDATES, requestingLocationUpdates)
.apply()
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment