diff --git a/app/build.gradle b/app/build.gradle index 0455fef..668a913 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -140,6 +140,7 @@ dependencies { implementation 'me.zhanghai.android.materialratingbar:library:1.4.0' implementation project(path: ':mylibrary') + implementation project(path: ':keeplibrary') //高德地图 // implementation 'com.amap.api:3dmap:9.8.3' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6e674f1..8d8629e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,7 +46,7 @@ - + @@ -94,7 +94,13 @@ + + + + +// // 定义前台服务的通知点击事件 +//// ActivityUtils.startActivity(applicationContext,HomeActivity::class.java) +// } +//// 启动保活服务 +// KeepLive.startWork(this, +// KeepLive.RunMode.ENERGY, +// foregroundNotification, //你需要保活的服务,如socket连接、定时任务等,建议不用匿名内部类的方式在这里写 +// object : UpLocationService23() { +// /** +// * 运行中 +// * 由于服务可能会多次自动启动,该方法可能重复调用 +// */ +// override fun onWorking() { +// // do something +// } +// +// /** +// * 服务终止 +// * 由于服务可能会被多次终止,该方法可能重复调用,需同onWorking配套使用,如注册和注销broadcast +// */ +// override fun onStop() { +// // do something +// } +// } +// ) } override fun attachBaseContext(base: Context) { diff --git a/app/src/main/java/com/dahe/gldriver/service/MyNotification.kt b/app/src/main/java/com/dahe/gldriver/service/MyNotification.kt new file mode 100644 index 0000000..b953c15 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/service/MyNotification.kt @@ -0,0 +1,137 @@ +package com.dahe.gldriver.service + +import android.annotation.SuppressLint +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.app.Service +import android.content.Context +import android.content.Context.NOTIFICATION_SERVICE +import android.content.Intent +import android.graphics.Color +import android.os.Build +import androidx.core.app.NotificationCompat +import com.dahe.gldriver.R +import com.dahe.gldriver.ui.HomeActivity +import com.dahe.gldriver.utils.OcrUtils +import com.dahe.mylibrary.base.SingletonNoPHolder + +/** + * @ClassName MyNotification + * @Author john + * @Date 2024/4/1 08:37 + * @Description TODO + */ +class MyNotification private constructor() { + + companion object : SingletonNoPHolder(::MyNotification) + + fun getNotification(context: Context): Notification { +// return buildNotification(context) + return sendNotify(context) + } + + + /** + * 实现包装方法(参数按自己需求来) + * @param title 标题 + * @param content 内容 + * @param priorityType 通知级别:0为重要通知(有提示音),非0为普通通知(无提示音) + */ + + +} + +private var notificationManager: NotificationManager? = null +var isCreateChannel = false +fun buildNotification(ctx: Context): Notification { + var builder: Notification.Builder? = null + var notification: Notification? = null + if (Build.VERSION.SDK_INT >= 26) { + //Android O上对Notification进行了修改,如果设置的targetSDKVersion>=26建议使用此种方式创建通知栏 + if (null == notificationManager) { + notificationManager = + ctx.getSystemService(Service.NOTIFICATION_SERVICE) as NotificationManager + } + val channelId = ctx.packageName + if (!isCreateChannel) { + val notificationChannel = NotificationChannel( + channelId, + "BackgroundLocation", NotificationManager.IMPORTANCE_DEFAULT + ) + notificationChannel.enableLights(true) //是否在桌面icon右上角展示小圆点 + notificationChannel.lightColor = Color.BLUE //小圆点颜色 + notificationChannel.setShowBadge(true) //是否在久按桌面图标时显示此渠道的通知 + notificationManager?.createNotificationChannel(notificationChannel) + isCreateChannel = true + } + builder = Notification.Builder(ctx, channelId) + } else { + builder = Notification.Builder(ctx) + } + builder.setSmallIcon(R.mipmap.app_icon) + .setContentTitle("大河好运司机端") + .setContentText("大河好运司机端为您提供服务") + .setWhen(System.currentTimeMillis()) + notification = if (Build.VERSION.SDK_INT >= 16) { + builder.build() + } else { + return builder.notification + } + return notification +} + + + + +fun sendNotify( context: Context) : Notification{ + + var manager = context.getSystemService (NOTIFICATION_SERVICE) as NotificationManager + + var wsschannel:NotificationChannel;// channel(安卓8.0及以上才用到) + var channel_id = "my_notification_important"; // channelId用于绑定builder配置 + var priority = NotificationCompat.PRIORITY_LOW; // 通知级别 + + // 判断是否8.0及以上版本,并选择发送消息的级别 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { +// if (priorityType == 0) { + wsschannel = + NotificationChannel ("my_notification_important", "重要通知", NotificationManager.IMPORTANCE_HIGH); + channel_id = "my_notification_important"; +// } else { +// wsschannel = +// NotificationChannel (NORMAL_CHANNEL_ID, "一般通知", NotificationManager.IMPORTANCE_LOW); +// channel_id = NORMAL_CHANNEL_ID; +// } + manager.createNotificationChannel(wsschannel); + } + + // 通知级别 +// if (priorityType == 0) { +// priority = NotificationCompat.PRIORITY_HIGH; +// } else { +// priority = NotificationCompat.PRIORITY_LOW; +// } + + // 点击意图 + var intent = Intent(context, HomeActivity::class.java); + var pendingIntent = PendingIntent.getActivity (context, 0, intent, PendingIntent.FLAG_IMMUTABLE); + + // 通知配置 + var notification = NotificationCompat.Builder (context, channel_id) + .setContentTitle("大河好运司机端") // 标题 + .setContentText("大河好运司机端为您提供服务") // 内容 + .setSmallIcon(R.mipmap.app_icon) // 小图标 + .setPriority(NotificationCompat.PRIORITY_HIGH) // 7.0 设置优先级 + .setContentIntent(pendingIntent) // 跳转意图 +// .setAutoCancel(true) // 点击后自动销毁 + .build(); + + // 给每个通知随机id +// int id =(int)((Math.random() * 9 + 1) * (6)); + + // 生成通知 + manager.notify(1, notification); + return notification +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/service/UpLocationService2.kt b/app/src/main/java/com/dahe/gldriver/service/UpLocationService2.kt new file mode 100644 index 0000000..7cdd9db --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/service/UpLocationService2.kt @@ -0,0 +1,185 @@ +package com.dahe.gldriver.service + +import android.annotation.SuppressLint +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.app.Service +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.os.Build +import android.os.Environment +import android.os.Handler +import android.os.IBinder +import android.os.Message +import android.util.Log +import com.amap.api.location.AMapLocation +import com.dahe.gldriver.R +import com.dahe.gldriver.base.AppConfig +import com.dahe.gldriver.bean.OrderDetailBean +import com.dahe.gldriver.bean.UpLocation +import com.dahe.gldriver.net.BaseObserver +import com.dahe.gldriver.net.DataManager +import com.dahe.gldriver.net.RxHttpCallBack +import com.dahe.gldriver.ui.HomeActivity +import com.dahe.gldriver.utils.GDLocationUtils +import com.dahe.mylibrary.net.CommonResponseBean +import com.dahe.mylibrary.utils.BaseSPUtils +import com.dahe.mylibrary.utils.FileIOUtils +import com.google.gson.Gson +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.schedulers.Schedulers +import java.text.DateFormat +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Timer +import java.util.TimerTask + + +/** + * @ClassName UpLocationService + * @Author john + * @Date 2024/3/28 09:08 + * @Description TODO + */ +class UpLocationService2 : Service() { + + private val hd = Handler { msg: Message -> + when (msg.what) { + 123 -> { + var orderString = + BaseSPUtils.get(application, AppConfig.NEED_UP_ORDER, "") as String + if (!orderString.isNullOrEmpty()) { + var order = Gson().fromJson(orderString, OrderDetailBean::class.java) + GDLocationUtils.instance.getLocation2(application) { + if (it.errorCode == 0 && it.latitude != 0.0) { + loadLocation(it, order) + } + } + } else { + GDLocationUtils.instance.stopLocation() + } + + //获取文件输出路径 +// val path = Environment.getExternalStorageDirectory() +// .toString() + "/crashinfo/" +// val time: String = formatter.format(Date()) +// val time2: String = formatter2.format(Date()) +// val fileName = "crash-$time.txt" +// +// GDLocationUtils.instance.getLocation2(application) { +// if (it.errorCode == 0 && it.latitude != 0.0) { +// FileIOUtils.writeFileFromString( +// path + fileName, +// """当前时间:${time2},经纬度:${it.latitude}:${it.longitude}""", +// true +// ) +// +// } else { +// FileIOUtils.writeFileFromString( +// path + fileName, +// """当前时间:${time2},经纬度:${it.latitude}${it.errorInfo}""", +// true +// ) +// } +// } + + } + } + false + } + + private val formatter: DateFormat = SimpleDateFormat("yyyy-MM-dd") + private val formatter2: DateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss") + + override fun onBind(intent: Intent?): IBinder? { + return null + } + + override fun onRebind(intent: Intent?) { + super.onRebind(intent) + } + + private val timeSum = 1000 * 60 * 3 + + // private val timeSum = 3000 + private var timer: Timer? = null + override fun onCreate() { + super.onCreate() + + Log.e("开始循环上传,等待100ms", "-----") + timer = Timer() + timer?.schedule(object : TimerTask() { + override fun run() { + val msg = Message.obtain() + msg.what = 123 + hd.sendMessage(msg) + } + }, 1000, timeSum.toLong()) + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + +// Log.d(TAG, "onStartCommand flags:$flags, startId:$startId [$this] ${Thread.currentThread()}") + + val pendingIntent: PendingIntent = + Intent(this, HomeActivity::class.java).let { notificationIntent -> + PendingIntent.getActivity(this, 0, notificationIntent, 0) + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val chanId = "f-channel" + val chan = NotificationChannel( + chanId, "前台服务channel", + NotificationManager.IMPORTANCE_NONE + ) + chan.lightColor = Color.BLUE + chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE + val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + service.createNotificationChannel(chan) +// Log.d(TAG, "服务调用startForeground") + + val notification: Notification = + Notification.Builder(applicationContext, chanId) + .setContentTitle("大河好运司机端") + .setContentText("大河好运司机端为您提供服务") + .setSmallIcon(R.mipmap.app_icon) + .setContentIntent(pendingIntent) + .build() + startForeground(1, notification) + } else { +// Log.d(TAG, "${Build.VERSION.SDK_INT} < O(API 26) ") + } + return START_STICKY + } + + private fun loadLocation(loc: AMapLocation, order: OrderDetailBean) { + DataManager.getInstance().driverUploadLocus( + UpLocation( + loc.latitude, + loc.longitude, + order.orderId, + order.waybillId + ) + ) + .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) + .subscribe(BaseObserver(application, object : RxHttpCallBack() { + override fun onSuccess(t: CommonResponseBean) { + super.onSuccess(t) + } + })) + } + + override fun onDestroy() { + super.onDestroy() + if (timer != null) { + timer?.cancel() + timer = null + } + GDLocationUtils.instance.stopLocation() + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/waybill/activity/WaybillUpPicActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/waybill/activity/WaybillUpPicActivity.kt index 1eaa7e8..3f88487 100644 --- a/app/src/main/java/com/dahe/gldriver/ui/waybill/activity/WaybillUpPicActivity.kt +++ b/app/src/main/java/com/dahe/gldriver/ui/waybill/activity/WaybillUpPicActivity.kt @@ -14,6 +14,7 @@ import com.dahe.gldriver.net.DataManager import com.dahe.gldriver.net.RxHttpCallBack import com.dahe.gldriver.oss.OssServiceUtil import com.dahe.gldriver.utils.GDLocationUtils +import com.dahe.gldriver.utils.OrderUtils import com.dahe.mylibrary.adapter.GridImageAdapter import com.dahe.mylibrary.adapter.GridImageAdapter.OnItemClickListener import com.dahe.mylibrary.base.BaseActivity @@ -256,7 +257,10 @@ class WaybillUpPicActivity : BaseActivity() { mContext, WaybillSuccActivity::class.java, intent.extras) + //装货成功-开启轨迹上传 + OrderUtils.getInstance().upLocation(mContext) } else { + OrderUtils.getInstance().stopUpLocation(mContext) ActivityUtils.startActivity( mContext, WaybillSuccActivity::class.java, diff --git a/app/src/main/java/com/dahe/gldriver/utils/GDLocationUtils.kt b/app/src/main/java/com/dahe/gldriver/utils/GDLocationUtils.kt index e645923..9bbf063 100644 --- a/app/src/main/java/com/dahe/gldriver/utils/GDLocationUtils.kt +++ b/app/src/main/java/com/dahe/gldriver/utils/GDLocationUtils.kt @@ -1,10 +1,18 @@ package com.dahe.gldriver.utils +import android.annotation.SuppressLint +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service import android.content.Context +import android.graphics.Color +import android.os.Build import com.amap.api.location.AMapLocationClient import com.amap.api.location.AMapLocationClientOption import com.amap.api.location.AMapLocationListener - +import com.dahe.gldriver.R +import com.dahe.gldriver.service.MyNotification class GDLocationUtils private constructor(){ @@ -52,7 +60,8 @@ class GDLocationUtils private constructor(){ //设置是否允许模拟位置,默认为true,允许模拟位置 mLocationOption?.setMockEnable(true) - + //启动后台定位,第一个参数为通知栏ID,建议整个APP使用一个 +// mLocationClient?.enableBackgroundLocation(1,buildNotification(ctx)) //给定位客户端对象设置定位参数 mLocationClient?.setLocationOption(mLocationOption); if(null != mLocationClient){ @@ -62,8 +71,57 @@ class GDLocationUtils private constructor(){ mLocationClient?.startLocation() } } + + + /** + * 上传轨迹专用 + * @param ctx Context + * @param mLocationListener AMapLocationListener + */ + fun getLocation2(ctx : Context,mLocationListener : AMapLocationListener){ + //初始化定位 + mLocationClient = AMapLocationClient(ctx) + //设置定位回调监听 + mLocationClient?.setLocationListener(mLocationListener) + //初始化AMapLocationClientOption对象 + mLocationOption = AMapLocationClientOption() + + /** + * 设置定位场景,目前支持三种场景(签到、出行、运动,默认无场景) + */ + mLocationOption?.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.SignIn) + + + //设置定位模式为AMapLocationMode.Hight_Accuracy,高精度模式。 + mLocationOption?.setLocationMode(AMapLocationClientOption.AMapLocationMode.Battery_Saving) +// mLocationOption?.setLocationMode(AMapLocationClientOption.AMapLocationMode.Battery_Saving) + + //获取一次定位结果: + //该方法默认为false。 + mLocationOption?.setOnceLocation(true) + + //获取最近3s内精度最高的一次定位结果: +//设置setOnceLocationLatest(boolean b)接口为true,启动定位时SDK会返回最近3s内精度最高的一次定位结果。如果设置其为true,setOnceLocation(boolean b)接口也会被设置为true,反之不会,默认为false。 + mLocationOption?.setOnceLocationLatest(true) + + //设置是否允许模拟位置,默认为true,允许模拟位置 + mLocationOption?.setMockEnable(true) + //启动后台定位,第一个参数为通知栏ID,建议整个APP使用一个 + mLocationClient?.enableBackgroundLocation(1,MyNotification.getInstance().getNotification(ctx)) + //给定位客户端对象设置定位参数 + mLocationClient?.setLocationOption(mLocationOption); + if(null != mLocationClient){ + mLocationClient?.setLocationOption(mLocationOption); + //设置场景模式后最好调用一次stop,再调用start以保证场景模式生效 + mLocationClient?.stopLocation() + mLocationClient?.startLocation() + } + } + + fun stopLocation(){ if(null != mLocationClient){ + mLocationClient?.disableBackgroundLocation(true) mLocationClient?.stopLocation() } } diff --git a/app/src/main/java/com/dahe/gldriver/utils/OrderUtils.kt b/app/src/main/java/com/dahe/gldriver/utils/OrderUtils.kt index 59328e9..58b1027 100644 --- a/app/src/main/java/com/dahe/gldriver/utils/OrderUtils.kt +++ b/app/src/main/java/com/dahe/gldriver/utils/OrderUtils.kt @@ -2,6 +2,7 @@ package com.dahe.gldriver.utils import android.content.Context import android.content.Intent +import android.os.Build import android.os.Bundle import com.dahe.gldriver.base.App import com.dahe.gldriver.base.AppConfig @@ -14,6 +15,7 @@ import com.dahe.gldriver.net.BaseObserver import com.dahe.gldriver.net.DataManager import com.dahe.gldriver.net.RxHttpCallBack import com.dahe.gldriver.service.UpLocationService +import com.dahe.gldriver.service.UpLocationService2 import com.dahe.gldriver.ui.waybill.activity.WaybillLoadActivity import com.dahe.mylibrary.base.SingletonNoPHolder import com.dahe.mylibrary.net.CommonResponseBean @@ -164,23 +166,25 @@ class OrderUtils private constructor() { super.onSuccess(t) if (t.data != null) { BaseSPUtils.put(context, NEED_UP_ORDER, Gson().toJson(t.data)) - context.startService(Intent(context, UpLocationService::class.java)) -// if (!Cactus.instance.isRunning(context)) { -// Cactus.instance.addCallback { -// context.startService(Intent(context, UpLocationService::class.java)) -// }.restart(context) -// }else{ -// Cactus.instance.addCallback { -// context.startService(Intent(context, UpLocationService::class.java)) -// }.restart(context) -// } -// OrderUtils.getInstance().upLocation("","",t.data.orderId,t.data.waybillId) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.startForegroundService(Intent(context, UpLocationService2::class.java)) + }else{ + context.startService(Intent(context, UpLocationService2::class.java)) + } } else { - context.stopService(Intent(context, UpLocationService::class.java)) + context.stopService(Intent(context, UpLocationService2::class.java)) BaseSPUtils.remove(context, NEED_UP_ORDER) } } })) } + + /** + * 关闭上传运行中运单轨迹 + * @param context Context + */ + fun stopUpLocation(context: Context){ + context.stopService(Intent(context, UpLocationService2::class.java)) + } } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 649748d..e04e5d9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -22,3 +22,4 @@ dependencyResolutionManagement { rootProject.name = "GLDriver" include ':app' include ':mylibrary' +include ':keeplibrary'