app/build.gradle
@@ -29,8 +29,8 @@ applicationId "com.driver.goposttrip" minSdkVersion 23 targetSdkVersion 36 versionCode 58 versionName "1.7.9" versionCode 59 versionName "1.8.0" multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -177,7 +177,7 @@ implementation 'androidx.activity:activity-ktx:1.8.0' implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs') implementation "com.facebook.soloader:soloader:0.12.1" implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.0" implementation "org.jetbrains.kotlin:kotlin-stdlib:2.2.21" implementation 'com.tencent.mm.opensdk:wechat-sdk-android:6.8.34' implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.core:core-ktx:1.2.0' @@ -272,4 +272,6 @@ // implementation 'com.umeng.umsdk:asms:1.8.7.2' //必选 //微信 // implementation 'com.umeng.umsdk:share-wx:7.3.7' implementation "io.github.petterpx:floatingx-app:3.0.0" // App 级全局浮窗(跟随 Activity) implementation "io.github.petterpx:floatingx-system:3.0.0" // 系统级浮窗(WindowManager + 权限) } app/src/main/AndroidManifest.xml
@@ -42,7 +42,9 @@ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <!-- 用于申请调用A-GPS模块 --> <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> <!-- 用于申请获取蓝牙信息进行室内定位 --> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" tools:ignore="ForegroundServicesPolicy" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> @@ -54,6 +56,15 @@ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <!-- <uses-permission android:name="android.permission.READ_CONTACTS" /> --> <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" /> <!-- 诱导悬浮窗 --> <uses-permission android:name="android.permission.MANAGE_OVERLAY_PERMISSION" /> <!-- Android 10+ 后台定位权限 --> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" tools:ignore="BackgroundLocationPolicy" /> <!-- Android 14+ 定位前台服务专属权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" /> <!-- Android 13+ 通知权限 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <application android:name=".base.MyApplication" @@ -66,6 +77,13 @@ android:theme="@style/AppTheme" android:usesCleartextTraffic="true" tools:replace="android:allowBackup"> <service android:name=".service.LocationForegroundService" android:enabled="true" android:foregroundServiceType="location" android:exported="true" android:permission="android.permission.FOREGROUND_SERVICE" /> <activity android:name=".ui.main.ShowPictureActivity" android:exported="false" /> @@ -113,7 +131,9 @@ android:name=".ui.pub.AreaCodeActivity" android:launchMode="singleTask" /> <activity android:name=".ui.pub.ForgetPwdActivity" /> <activity android:name=".ui.main.MainActivity" /> <activity android:name=".ui.main.MainActivity" android:launchMode="singleTask" /> <activity android:name=".ui.mine.MineActivity" /> <activity android:name=".ui.mine.money_bag.MinePurseActivity" /> <activity android:name=".ui.mine.money_bag.MineAwardActivity" /> app/src/main/java/com/driver/igotrip/base/Const.java
@@ -89,6 +89,7 @@ public static String FIRST_LOGIN = "FIRST_LOGIN"; public static String REFUSE_LOCATION = "REFUSE_LOCATION"; public static String REFUSE_FLOATING_WINDOW = "REFUSE_FLOATING_WINDOW"; } app/src/main/java/com/driver/igotrip/base/MyApplication.kt
@@ -12,6 +12,8 @@ import android.os.* import android.util.Log import android.view.View import android.widget.ImageView import android.widget.TextView import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import cn.sinata.rxnetty.LogHelper.initLogs @@ -24,16 +26,31 @@ import com.driver.igotrip.bean.OrderSimpleData import com.driver.igotrip.bean.websocket.HeartBean import com.driver.igotrip.netUtls.* import com.driver.igotrip.service.LocationForegroundService import com.driver.igotrip.ui.main.MainActivity import com.driver.igotrip.ui.main.small_cargo.SmallCargoActivity import com.driver.igotrip.ui.pub.LoginActivity import com.driver.igotrip.utils.AudioRecoderUtils import com.driver.igotrip.utils.Cache.CacheKey import com.driver.igotrip.utils.Cache.CacheUtil import com.driver.igotrip.utils.LanguageSP import com.driver.igotrip.utils.LanguageSP.LanguageConst import com.driver.igotrip.utils.LogUtils import com.driver.igotrip.utils.crash.CrashHandler import com.driver.igotrip.utils.glide.GlideUtil import com.google.android.gms.maps.model.LatLng import com.google.cloud.texttospeech.v1.* import com.google.gson.Gson import com.petterp.floatingx.app.AppHost import com.petterp.floatingx.core.FloatingX import com.petterp.floatingx.core.FxControl import com.petterp.floatingx.core.FxListener import com.petterp.floatingx.core.layout.FxAdsorb import com.petterp.floatingx.core.layout.FxEdge import com.petterp.floatingx.core.layout.FxGravity import com.petterp.floatingx.core.storage.FxSpStorage import com.petterp.floatingx.system.permission.FxPermissionStrategy import com.petterp.floatingx.system.systemHost import com.xuexiang.xui.XUI import org.greenrobot.eventbus.EventBus import org.jetbrains.anko.startActivity @@ -92,7 +109,7 @@ private val MSG_ORDER_CANCEL = 1002 @SuppressLint("HandlerLeak") private val mHandler: Handler = object : Handler() { private val mHandler: Handler = object : Handler(Looper.getMainLooper()) { override fun handleMessage(msg: Message) { super.handleMessage(msg) when (msg.what) { @@ -158,32 +175,6 @@ } } // private val mAliasCallback = // TagAliasCallback { code, alias, tags -> // val logs: String // when (code) { // 0 -> { // logs = "Set tag and alias success" // Log.i("TAG", logs) // } // // 6002 -> { // logs = "Failed to set alias and tags due to timeout. Try again after 60s." // Log.i("TAG", logs) // // 延迟 60 秒来调用 Handler 设置别名 // var alisa = "DRIVER" + CacheKey.getUserId() // Handler().postDelayed({ // JPushInterface.setAliasAndTags(this, alisa, null, null) // }, 60 * 1000) // } // // else -> { // logs = "Failed with errorCode = $code" // Log.e("TAG", logs) // } // } // } private fun initSocket() { NettyClient.getInstance().init(this, Api.SOCKET_SERVER, Api.SOCKET_PORT, true) NettyClient.getInstance().addOnMessageListener { message: String -> @@ -220,6 +211,8 @@ CacheUtil.get().clear() CacheKey.putKeyStr("isAgreen", "1") NettyClient.getInstance().stopService() couldShowFloatingWindow = false LocationForegroundService.stop() isLogin = false val intent = Intent() intent.setClass(this, LoginActivity::class.java) @@ -391,18 +384,15 @@ logRecord("socket==>订单超时:$jsob") val act = getTopActivity() /** * 司机超时推送 * @param timeOutType 超时类型(1=用户可免费取消提醒,2=预约单接单提醒,3=超时循环提醒) * @param orderId 订单id * @param orderType 订单类型(1=打车,4=包裹) * @param describe 展示内容 * @param audioUrl 语音播报音频地址 */ //超时类型(1=用户可免费取消提醒,2=预约单接单提醒,3=超时循环提醒) val timeOutType = jsob.optString("timeOutType") //订单id val orderId = jsob.optString("orderId") //订单类型(1=打车,4=包裹) val orderType = jsob.optString("orderType") //展示内容 val describe = jsob.optString("describe") //语音播报音频地址 val audioUrl = jsob.optString("audioUrl") if (timeOutType == "1" || timeOutType == "3") { // 仅提示 @@ -528,6 +518,31 @@ var lastPlayTime = 0L //上次提示播放时间 var hasAutoGoTripping = false //true 本次启动已经自动跳转过 var isLogin: Boolean = true //是否在上班 var isWorking = false set(value) { field = value refreshFloatingWindow() } private var aMapLocation: LatLng? = null var currentOrderId: String = "" var currentOrderType: String = "" var orderStatueViews: MutableList<OrderStatueView> = mutableListOf() //悬浮窗tag private const val FLOATING_X_TAG = "GO POST DRIVER" //是否能显示悬浮窗 @JvmStatic var couldShowFloatingWindow = false set(value) { field = value if (!value) { dismissFloatingWindow() } } fun getInstance(): MyApplication? { if (appContext == null) { appContext = MyApplication() @@ -545,11 +560,6 @@ fun getLocation(): LatLng? { return aMapLocation } private var aMapLocation: LatLng? = null var currentOrderId: String = "" var currentOrderType: String = "" var orderStatueViews: MutableList<OrderStatueView> = mutableListOf() //设置定位 fun setLocation(latLng: LatLng) { @@ -570,12 +580,94 @@ fun removeOrderView(view: OrderStatueView?) { orderStatueViews.remove(view) } //显示悬浮窗 fun showFloatingWindow() { (FloatingX.controlOrNull(FLOATING_X_TAG) ?: FloatingX.install(FLOATING_X_TAG) { view { ctx -> View.inflate(ctx, R.layout.fx_card, null).apply { findViewById<TextView>(R.id.tv1).apply { val language = LanguageSP.getLanguage(ctx) text = when (language) { LanguageConst.ZH_CN -> { if (isWorking) "听单中" else "休息中" } LanguageConst.EN_US -> { if (isWorking) "GO" else "On break" } else -> { if (isWorking) "Aller" else "En pause" } } } findViewById<ImageView>(R.id.iv_logo).apply { GlideUtil.loadResource(this, R.mipmap.ic_launcher, true) } } } anchor(FxGravity.CENTER_START) adsorb(FxAdsorb.Edges(setOf(FxEdge.START, FxEdge.END))) persist(FxSpStorage(appContext!!)) enableLog("GO POST floating") systemHost(appContext!!) { theme(R.style.Theme_FloatingX) permission(FxPermissionStrategy.auto()) // this. 消歧:这里的 fallback / keyboard 既是 Builder 方法名也是本函数的参数名 this.fallback(AppHost.builder(appContext!!).theme(R.style.Theme_FloatingX).build()) } }.also { it.addListener(object : FxListener { override fun onClick(control: FxControl, view: View) { dismissFloatingWindow() val activity = appContext?.getTopActivity() if (activity == null) { view.context.startActivity(Intent(view.context, MainActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }) } else { activity.startActivity<MainActivity>() } } override fun onLongClick(control: FxControl, view: View) { } }) }).show() } //隐藏悬浮窗 @JvmStatic fun dismissFloatingWindow() { FloatingX.controlOrNull(FLOATING_X_TAG)?.hide() } //刷新悬浮窗 fun refreshFloatingWindow() { val language = LanguageSP.getLanguage(appContext) FloatingX.controlOrNull(FLOATING_X_TAG)?.contentView?.findViewById<TextView>(R.id.tv1)?.text = when (language) { LanguageConst.ZH_CN -> { if (isWorking) "听单中" else "休息中" } LanguageConst.EN_US -> { if (isWorking) "GO" else "On break" } else -> { if (isWorking) "Aller" else "En pause" } } } } private val activities = ArrayList<Activity?>() //获取顶部activity private fun getTopActivity(): Activity? { fun getTopActivity(): Activity? { return activities.lastOrNull() } @@ -621,6 +713,7 @@ override fun onActivityStarted(activity: Activity) { showNum++ dismissFloatingWindow() } override fun onActivityResumed(activity: Activity) { @@ -643,15 +736,27 @@ } isPlayVoice = true }, 600) if (showNum == 0 && couldShowFloatingWindow) { showFloatingWindow() } } override fun onActivityDestroyed(activity: Activity) { logRecord("onActivityDestroyed: " + activity.javaClass.name) activities.remove(activity) if (activities.isEmpty()) { couldShowFloatingWindow = false dismissFloatingWindow() } } override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { // logRecord("onActivitySaveInstanceState: " + activity.javaClass.name) } override fun onTerminate() { super.onTerminate() couldShowFloatingWindow = false LocationForegroundService.stop() } } app/src/main/java/com/driver/igotrip/netUtls/MyNoMsgObserver.java
@@ -7,6 +7,7 @@ import com.driver.igotrip.base.BaseEvent; import com.driver.igotrip.base.MyApplication; import com.driver.igotrip.service.LocationForegroundService; import com.driver.igotrip.ui.pub.LoginActivity; import com.driver.igotrip.utils.Cache.CacheUtil; import com.driver.igotrip.utils.LogUtils; @@ -88,6 +89,8 @@ success(responseString); } else { if (baseBean.getCode() == 600) { MyApplication.setCouldShowFloatingWindow(false); LocationForegroundService.stop(); CacheUtil.get().clear(); NettyClient.getInstance().stopService(); Intent intent = new Intent(); app/src/main/java/com/driver/igotrip/netUtls/MyObserver.java
@@ -8,6 +8,7 @@ import com.driver.igotrip.base.BaseEvent; import com.driver.igotrip.base.MyApplication; import com.driver.igotrip.service.LocationForegroundService; import com.driver.igotrip.ui.pub.LoginActivity; import com.driver.igotrip.utils.Cache.CacheUtil; import com.driver.igotrip.utils.LogUtils; @@ -89,6 +90,8 @@ success(responseString); } else { if (baseBean.getCode() == 600) { MyApplication.setCouldShowFloatingWindow(false); LocationForegroundService.stop(); CacheUtil.get().clear(); NettyClient.getInstance().stopService(); Intent intent = new Intent(); app/src/main/java/com/driver/igotrip/service/LocationForegroundService.kt
New file @@ -0,0 +1,181 @@ package com.driver.igotrip.service import android.Manifest 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.content.pm.PackageManager import android.os.Build import android.os.IBinder import android.os.Looper import android.util.Log import androidx.core.app.ActivityCompat import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat import cn.sinata.rxnetty.LogHelper import com.driver.igotrip.R import com.driver.igotrip.base.MyApplication import com.driver.igotrip.netUtls.MyNoMsgObserver import com.driver.igotrip.ui.main.MainActivity import com.google.android.gms.location.FusedLocationProviderClient import com.google.android.gms.location.LocationCallback import com.google.android.gms.location.LocationRequest import com.google.android.gms.location.LocationResult import com.google.android.gms.location.LocationServices import com.google.android.gms.location.Priority //前台定位服务 class LocationForegroundService : Service() { private val tag = "LocationService" /** 融合定位客户端,系统级 API,自动融合 GPS/Wi-Fi/基站 */ private lateinit var fusedClient: FusedLocationProviderClient /** 定位请求参数 */ private lateinit var locationRequest: LocationRequest /** 定位回调 */ private lateinit var locationCallback: LocationCallback companion object { private const val NOTIFICATION_ID = 1001 private const val CHANNEL_ID = "background location" private const val ACTION_STOP = "action_stop_location" //是否正在运行 private var isRunning = false //启动 只能应用处于前台才能调用 fun start() { val intent = Intent(MyApplication.appContext!!, LocationForegroundService::class.java) ContextCompat.startForegroundService(MyApplication.appContext!!, intent) isRunning = true } // 停止 @JvmStatic fun stop() { if (!isRunning) { return } val intent = Intent(MyApplication.appContext, LocationForegroundService::class.java).apply { action = ACTION_STOP } MyApplication.appContext!!.startService(intent) } } override fun onCreate() { super.onCreate() // 初始化融合定位客户端 fusedClient = LocationServices.getFusedLocationProviderClient(this) // 高精度 + 5 秒间隔,出行场景标配 locationRequest = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 5_000L).apply { setMinUpdateIntervalMillis(5_000L) // 最快 5 秒一次 setWaitForAccurateLocation(true) // 等待精准定位 }.build() // 定位回调:收到位置后对外分发 locationCallback = object : LocationCallback() { override fun onLocationResult(result: LocationResult) { result.lastLocation?.let { location -> Log.d(tag, "location:${location.latitude} ${location.longitude}") MyApplication.Companion.setLocation(location.latitude, location.longitude) } } } startTracking() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { // 被系统杀死后尝试重启(前提是通知栏仍在) if (intent?.action == ACTION_STOP) { stopTracking() } return START_STICKY } //开始定位 private fun startTracking() { val hadLocationPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED val hadBackgroundLocationPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED if (!hadLocationPermission || !hadBackgroundLocationPermission) { LogHelper.logRecord("had not permission hadLocationPermission:$hadLocationPermission hadBackgroundLocationPermission:$hadBackgroundLocationPermission") return } // 1. 必须先 startForeground,否则服务会被系统立即回收 startForeground(NOTIFICATION_ID, buildNotification()) // 2. 注册定位监听 fusedClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()) } //停止定位 private fun stopTracking() { isRunning = false fusedClient.removeLocationUpdates(locationCallback) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { stopForeground(STOP_FOREGROUND_REMOVE) } stopSelf() } //构建前台服务通知(保活的门面) private fun buildNotification(): Notification { val notificationManager: NotificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel: NotificationChannel = NotificationChannel( CHANNEL_ID, "background location", NotificationManager.IMPORTANCE_HIGH ) channel.description = "background location channel" notificationManager.createNotificationChannel(channel) } // 点击通知回到应用 val contentIntent = PendingIntent.getActivity( this, 0, Intent(this, MainActivity::class.java).apply { flags = if (MyApplication.Companion.appContext!!.getTopActivity() == null) { Intent.FLAG_ACTIVITY_NEW_TASK } else { Intent.FLAG_ACTIVITY_SINGLE_TOP } }, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) return NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle(getString(R.string.定位中)) .setContentText(getString(R.string.正在后台持续获取位置)) .setSmallIcon(R.mipmap.ic_launcher) .setContentIntent(contentIntent) .setOngoing(true) // 常驻通知,不可滑动清除 .setPriority(NotificationCompat.PRIORITY_HIGH) .build() } override fun onDestroy() { isRunning = false // 务必清理,否则会耗电 + 内存泄漏 if (::fusedClient.isInitialized) { fusedClient.removeLocationUpdates(locationCallback) } super.onDestroy() } override fun onBind(intent: Intent): IBinder? { return null } } app/src/main/java/com/driver/igotrip/ui/DialogUtil.kt
@@ -171,7 +171,7 @@ } pop.contentView.find<View>(R.id.tv_ok_server_mode).setOnClickListener { if (adapter.getAllMode().isEmpty()){ ToastUtils.showShortToast(context,"请选择内容") ToastUtils.showShortToast(context,context.getString(R.string.请选择内容)) return@setOnClickListener } pop.dismiss() @@ -192,7 +192,7 @@ } pop.contentView.find<View>(R.id.tv_ok_server_mode).setOnClickListener { if (adapter.selectPosition==-1){ ToastUtils.showShortToast(context,"请选择内容") ToastUtils.showShortToast(context,context.getString(R.string.请选择内容)) return@setOnClickListener } pop.dismiss() @@ -214,7 +214,7 @@ } pop.contentView.find<View>(R.id.tv_ok_server_mode).setOnClickListener { if (adapter.getSelectId().isEmpty()){ ToastUtils.showShortToast(context,"请选择内容") ToastUtils.showShortToast(context,context.getString(R.string.请选择内容)) return@setOnClickListener } pop.dismiss() app/src/main/java/com/driver/igotrip/ui/main/MainActivity.kt
@@ -1,20 +1,23 @@ package com.driver.igotrip.ui.main import android.Manifest import android.annotation.SuppressLint import android.content.ActivityNotFoundException import android.content.Intent import android.content.pm.PackageManager import android.os.Build import android.os.Bundle import android.os.Handler import android.os.Looper import android.os.Message import android.provider.Settings import android.util.Log import android.view.View import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView import android.widget.Toast import androidx.core.app.ActivityCompat import androidx.core.net.toUri import cn.sinata.rxnetty.LogHelper import cn.sinata.rxnetty.NettyClient import cn.sinata.xldutils.utils.SPUtils import cn.sinata.xldutils.utils.clickDelay @@ -41,6 +44,7 @@ import com.driver.igotrip.netUtls.Api import com.driver.igotrip.netUtls.callNet import com.driver.igotrip.netUtls.getMapByAny import com.driver.igotrip.service.LocationForegroundService import com.driver.igotrip.ui.DialogUtil import com.driver.igotrip.ui.DialogUtil.getDelAndSureDialog import com.driver.igotrip.ui.main.event.MineEventActivity @@ -56,7 +60,6 @@ import com.driver.mask_talk.utils.toTimeEnglish import com.driver.mask_talk.utils.toTimeFrench import com.google.android.gms.maps.GoogleMap import com.google.android.gms.maps.SupportMapFragment import com.google.gson.Gson import com.tbruyelle.rxpermissions2.RxPermissions import com.wang.avi.AVLoadingIndicatorView @@ -85,7 +88,6 @@ private val tv_today_time by lazy { find<TextView>(R.id.tv_today_time) } private val tv_week_time by lazy { find<TextView>(R.id.tv_week_time) } private val tv_month_time by lazy { find<TextView>(R.id.tv_month_time) } private val map_view by lazy { supportFragmentManager.findFragmentById(R.id.map_view) } private val avv_anim by lazy { find<AVLoadingIndicatorView>(R.id.avv_anim) } private val tv_up_avv by lazy { find<TextView>(R.id.tv_up_avv) } private val tv_order_num by lazy { find<TextView>(R.id.tv_order_num) } @@ -380,12 +382,10 @@ lateinit var aMap: GoogleMap override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (CacheKey.getKeyStr(Const.REFUSE_LOCATION) .isNotEmpty() && !RxPermissions(this).isGranted( Manifest.permission.ACCESS_FINE_LOCATION ) if (CacheKey.getKeyStr(Const.REFUSE_LOCATION).isNotEmpty() && !RxPermissions(this).isGranted(Manifest.permission.ACCESS_FINE_LOCATION) ) { toast("Without positioning permission, you will not be able to receive new order push notifications") toast(getString(R.string.没有定位权限提示)) } else { if (!RxPermissions(this).isGranted(Manifest.permission.ACCESS_FINE_LOCATION)) { DialogUtil.getDelAndSureDialog( @@ -394,57 +394,72 @@ getString(R.string.拒绝权限), getString(R.string.定位权限说明), { LogHelper.logRecord("用户拒绝定位权限1") }) { val subscribe = RxPermissions(this).request(Manifest.permission.ACCESS_FINE_LOCATION) .subscribe { .subscribe { it -> if (!it) { toast("Without positioning permission, you will not be able to receive new order push notifications") toast(getString(R.string.没有定位权限提示)) CacheKey.putKeyStr(Const.REFUSE_LOCATION, "1") } else initLocation() LogHelper.logRecord("用户拒绝定位权限2") } else { val subscribe = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { RxPermissions(this).request(Manifest.permission.ACCESS_BACKGROUND_LOCATION) .subscribe { if (!it) { toast(getString(R.string.没有定位权限提示)) CacheKey.putKeyStr(Const.REFUSE_LOCATION, "1") LogHelper.logRecord("用户拒绝定位权限3") } else { initLocation() initFloatingWindow() } } } else { initLocation() initFloatingWindow() } } } } } else } else { initLocation() } } @SuppressLint("MissingPermission", "CheckResult") private fun initLocation() { val fragment = map_view as SupportMapFragment AMapKit.initMap(fragment) { it -> // zmc-remark 测试代码 给个初始位置 // MyApplication.aMapLocation = LatLng(30.659221715540937,104.06676612263988) aMap = it aMap.isMyLocationEnabled = true aMap.setOnMyLocationChangeListener { it?.let { Log.e("定位==============》", "${it.latitude},${it.longitude}") MyApplication.setLocation(it.latitude, it.longitude) } initFloatingWindow() } // val fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) // val locationRequest = LocationRequest.create().apply { // interval = 10000 // 10秒间隔 // priority = LocationRequest.PRIORITY_HIGH_ACCURACY // } // // fusedLocationClient.requestLocationUpdates(locationRequest, // object : LocationCallback() { // override fun onLocationResult(it: LocationResult) { // // 处理位置更新 // Log.e("定位 by fusedLocationClient ==============》","${it.lastLocation?.latitude},${it.lastLocation?.longitude}") // } // }, Looper.getMainLooper() // ) } } //初始化定位 private fun initLocation() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return } LocationForegroundService.start() } //初始化悬浮窗 private fun initFloatingWindow() { if (!Settings.canDrawOverlays(this) && CacheKey.getKeyStr(Const.REFUSE_FLOATING_WINDOW) != "1") { DialogUtil.getDelAndSureDialog( this, getString(R.string.确认), getString(R.string.拒绝权限), getString(R.string.悬浮窗说明), { CacheKey.putKeyStr(Const.REFUSE_FLOATING_WINDOW, "1") }) { val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, "package:${packageName}".toUri()).apply { putExtra("package", packageName) } startActivity(intent) } } } override fun onResume() { super.onResume() MyApplication.couldShowFloatingWindow = Settings.canDrawOverlays(this) && CacheKey.getKeyStr(Const.REFUSE_FLOATING_WINDOW) != "1" mainFragment?.refresh() callNet(Api.needToSettle, getMapByAny()) { var bean = gson.fromJson(it, BooleanBean::class.java).data @@ -480,6 +495,7 @@ tv_lien_name.text = data.data.brand.toString() tv_car.text = if (data.data.work == 1) getString(R.string.下班) else getString(R.string.出车) MyApplication.isWorking = data.data.work == 1 if (data.data.work == 1) { /*try { vehicleReporter?.setVehicleState(RidesharingVehicleReporter.VehicleState.ONLINE) @@ -569,6 +585,7 @@ callNet(Api.work, getMapByAny()) { homeDataBean?.data?.work = 2 tv_car.text = getString(R.string.出车) MyApplication.isWorking = false beOnDuty(false) val bean = Gson().fromJson<UpCarInfo>(it, UpCarInfo::class.java) MyApplication.getTTsManager().setVideoText(bean.data?.audioUrl) @@ -765,16 +782,6 @@ mainFragment?.refresh() } BaseEvent.OFF_LINE -> { Thread() { try { /* vehicleReporter?.disableLocationTracking() RidesharingDriverApi.clearInstance()*/ } catch (e: Exception) { } }.start() } BaseEvent.FORCED_OFFLINE -> { initCall() } @@ -800,6 +807,8 @@ */ override fun onDestroy() { MyApplication.couldShowFloatingWindow = false LocationForegroundService.stop() super.onDestroy() MyApplication.removeOrderView(qeeOrderView) } app/src/main/java/com/driver/igotrip/ui/mine/MineActivity.kt
@@ -16,6 +16,7 @@ import cn.sinata.xldutils.utils.clickDelay import cn.sinata.xldutils.utils.getFormatOne import cn.sinata.xldutils.utils.getFormatTwo import com.driver.igotrip.service.LocationForegroundService import com.driver.igotrip.R import com.driver.igotrip.base.BaseEvent import com.driver.igotrip.base.MyApplication @@ -190,10 +191,12 @@ rl_settlement.setOnClickListener { startActivity<OfflinePayActivity>() } // // 退出登录 rl_login_out.setOnClickListener { DialogUtil.getDelAndSureDialog(this, getString(R.string.是否退出登录), {}, { MyApplication.couldShowFloatingWindow = false LocationForegroundService.stop() CacheUtil.get().clear() NettyClient.getInstance().stopService() CacheKey.putKeyStr("isAgreen", "1") app/src/main/java/com/driver/igotrip/ui/mine/setting/LanghActivity.kt
@@ -6,6 +6,7 @@ import cn.sinata.xldutils.utils.setDrawableRight import com.driver.igotrip.R import com.driver.igotrip.base.Const import com.driver.igotrip.base.MyApplication import com.driver.igotrip.base.MyBaseActivity import com.driver.igotrip.netUtls.Api import com.driver.igotrip.netUtls.callNet @@ -44,7 +45,7 @@ changeServerLanguage { LanguageUtil.reApp(this) } MyApplication.refreshFloatingWindow() } } @@ -54,6 +55,7 @@ changeServerLanguage { LanguageUtil.reApp(this) } MyApplication.refreshFloatingWindow() } } @@ -63,6 +65,7 @@ changeServerLanguage { LanguageUtil.reApp(this) } MyApplication.refreshFloatingWindow() } } } app/src/main/java/com/driver/igotrip/ui/mine/setting/SettingActivity.kt
@@ -1,12 +1,16 @@ package com.driver.igotrip.ui.mine.setting import android.content.Intent import android.provider.Settings import android.view.View import android.widget.TextView import androidx.core.net.toUri import cn.sinata.xldutils.utils.clickDelay import cn.sinata.xldutils.utils.getVersionName import com.driver.emanagercar.ui.base.BaseWebActivity import com.driver.igotrip.R import com.driver.igotrip.base.BaseEvent import com.driver.igotrip.base.Const import com.driver.igotrip.base.MyApplication import com.driver.igotrip.base.MyBaseActivity import com.driver.igotrip.bean.AgreeBean @@ -15,7 +19,9 @@ import com.driver.igotrip.netUtls.callNet import com.driver.igotrip.netUtls.getMapByAny import com.driver.igotrip.ui.DialogUtil import com.driver.igotrip.utils.Cache.CacheKey import com.driver.igotrip.utils.glide.GlideCacheUtil import com.google.android.material.switchmaterial.SwitchMaterial import com.tencent.mm.opensdk.modelbase.BaseReq import com.tencent.mm.opensdk.modelbase.BaseResp import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler @@ -41,6 +47,8 @@ private val ll_clear by lazy { find<View>(R.id.ll_clear) } private val ll_version by lazy { find<View>(R.id.ll_version) } private val tv_qa by lazy { find<View>(R.id.tv_qa) } private val ll_floating_window by lazy { find<View>(R.id.ll_floating_window) } private val sm_floating_window by lazy { find<SwitchMaterial>(R.id.sm_floating_window) } override fun initView() { setTitleText(getString(R.string.设置)) @@ -119,6 +127,36 @@ ll_version.setOnClickListener { callVersion() } sm_floating_window.setOnCheckedChangeListener { _, isChecked -> MyApplication.couldShowFloatingWindow = isChecked } ll_floating_window.setOnClickListener { if (!sm_floating_window.isChecked) { if (CacheKey.getKeyStr(Const.REFUSE_FLOATING_WINDOW) != "1") { //用户没有拒绝过,但是没有授予权限 val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, "package:${packageName}".toUri()).apply { putExtra("package", packageName) } startActivity(intent) } else { //用户拒绝过 CacheKey.putKeyStr(Const.REFUSE_FLOATING_WINDOW, "") if (!Settings.canDrawOverlays(this)) { //没有权限 val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, "package:${packageName}".toUri()).apply { putExtra("package", packageName) } startActivity(intent) } else { //有权限 sm_floating_window.isChecked = true } } } else { sm_floating_window.isChecked = false CacheKey.putKeyStr(Const.REFUSE_FLOATING_WINDOW, "1") } } } @@ -163,4 +201,8 @@ } } override fun onResume() { super.onResume() sm_floating_window.isChecked = Settings.canDrawOverlays(this) && CacheKey.getKeyStr(Const.REFUSE_FLOATING_WINDOW) != "1" } } app/src/main/java/com/driver/igotrip/utils/MyUtils.java
@@ -25,6 +25,7 @@ import android.view.inputmethod.InputMethodManager; import com.driver.igotrip.BuildConfig; import com.driver.igotrip.R; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.lljjcoder.style.citylist.Toast.ToastUtils; @@ -318,7 +319,7 @@ */ public void CallPhone(Activity context, String phone) { if (phone == null || phone.trim().isEmpty()) { ToastUtils.showShortToast(context, "手机号为空"); ToastUtils.showShortToast(context, context.getString(R.string.手机号为空)); return; } try { app/src/main/java/com/driver/igotrip/utils/glide/GlideUtil.java
@@ -12,6 +12,7 @@ import androidx.annotation.Nullable; import com.bumptech.glide.Glide; import com.bumptech.glide.RequestBuilder; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.engine.GlideException; @@ -73,13 +74,25 @@ /*** * 加载图片 */ @SuppressLint("CheckResult") public static void loadResource(ImageView imageView, int res, boolean isCircle) { RequestBuilder<Drawable> load = Glide.with(imageView).load(res); if (isCircle) { load.apply(new RequestOptions().circleCrop()); } load.into(imageView); } /*** * 加载图片 * @param context * @param url * @param imageView */ @SuppressLint("CheckResult") public static void load(Context context, String url, ImageView imageView, int num) { if (url == null || url.isEmpty()){ if (url == null || url.isEmpty()) { return; } if (url.endsWith("mp4") || url.endsWith("AVI") || url.endsWith("MP4") || url.endsWith("avi")) { @@ -87,7 +100,7 @@ try { Bitmap myBitmap = Glide.with(context).asBitmap().load(url).submit(100, 100).get(); new Handler(Looper.getMainLooper()).post(() -> { loadBM(context,myBitmap,imageView,num); loadBM(context, myBitmap, imageView, num); }); } catch (ExecutionException e) { e.printStackTrace(); @@ -111,7 +124,7 @@ try { Bitmap myBitmap = Glide.with(context).asBitmap().load(url).submit(100, 100).get(); new Handler(Looper.getMainLooper()).post(() -> { loadBM(context,myBitmap,imageView,num); loadBM(context, myBitmap, imageView, num); }); } catch (ExecutionException e) { e.printStackTrace(); @@ -138,11 +151,11 @@ public static void loadBitMap(Context context, String url, ImageView imageView) { loadBitMap(context, url, imageView, 4,false); loadBitMap(context, url, imageView, 4, false); } public static void loadBitMapFit(Context context, String url, ImageView imageView) { loadBitMap(context, url, imageView, 4,true); loadBitMap(context, url, imageView, 4, true); } @@ -152,9 +165,9 @@ if (url.endsWith("mp4") || url.endsWith("AVI") || url.endsWith("MP4") || url.endsWith("avi")) { new Thread(() -> { try { Bitmap myBitmap = Glide.with(context).asBitmap().load(url).submit(imageView.getWidth()/3, imageView.getHeight()/3).get(); Bitmap myBitmap = Glide.with(context).asBitmap().load(url).submit(imageView.getWidth() / 3, imageView.getHeight() / 3).get(); new Handler(Looper.getMainLooper()).post(() -> { loadBMFit(context,myBitmap,imageView,num); loadBMFit(context, myBitmap, imageView, num); }); } catch (ExecutionException e) { e.printStackTrace(); @@ -172,15 +185,15 @@ } public static void loadFit(Context context, String url, ImageView imageView, int num, int placeHolder,OverImgView view) { public static void loadFit(Context context, String url, ImageView imageView, int num, int placeHolder, OverImgView view) { if (TextUtils.isEmpty(url)) return; if (url.endsWith("mp4") || url.endsWith("AVI") || url.endsWith("MP4") || url.endsWith("avi")) { new Thread(() -> { try { Bitmap myBitmap = Glide.with(context).asBitmap().load(url).submit(imageView.getWidth()/3, imageView.getHeight()/3).get(); Bitmap myBitmap = Glide.with(context).asBitmap().load(url).submit(imageView.getWidth() / 3, imageView.getHeight() / 3).get(); new Handler(Looper.getMainLooper()).post(() -> { loadBMFit(context,myBitmap,imageView,num); loadBMFit(context, myBitmap, imageView, num); }); } catch (ExecutionException e) { e.printStackTrace(); @@ -210,31 +223,31 @@ } public interface OverImgView{ public interface OverImgView { void over(); void fail(); } private static void loadBM(Context context, Bitmap bitmap, ImageView imageView, int num){ private static void loadBM(Context context, Bitmap bitmap, ImageView imageView, int num) { try { Glide.with(context) .load(bitmap) .apply(getRequestOption(num)) .into(imageView); }catch (Exception e){ } catch (Exception e) { } } private static void loadBMFit(Context context, Bitmap bitmap, ImageView imageView, int num){ private static void loadBMFit(Context context, Bitmap bitmap, ImageView imageView, int num) { try { Glide.with(context) .load(bitmap) .apply(getRequestOptionFit(num)) .into(imageView); }catch (Exception e){ } catch (Exception e) { } } @@ -300,29 +313,24 @@ } public static void loadBitMap(Context context, String url, ImageView imageView, Integer i,boolean isfit) { public static void loadBitMap(Context context, String url, ImageView imageView, Integer i, boolean isfit) { new Thread(() -> { try { Bitmap myBitmap = Glide.with(context).asBitmap().load(url).submit(100, 100).get(); new Handler(Looper.getMainLooper()).post(() -> { if (url.endsWith("mp4") || url.endsWith("avi")) { Bitmap map = doBlur(myBitmap, 15, false); if (!isfit){ loadBM(context,map,imageView,i); }else { loadBMFit(context,map,imageView,i); if (!isfit) { loadBM(context, map, imageView, i); } else { loadBMFit(context, map, imageView, i); } } else { Bitmap map = doBlur(myBitmap, 15, false); if (!isfit){ loadBM(context,map,imageView,i); }else { loadBMFit(context,map,imageView,i); if (!isfit) { loadBM(context, map, imageView, i); } else { loadBMFit(context, map, imageView, i); } } }); app/src/main/res/color/selector_switch_thumb_tint.xml
New file @@ -0,0 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_checked="false" android:color="@color/btn_color"/> <item android:state_checked="true" android:color="@color/blue_1"/> </selector> app/src/main/res/color/selector_switch_track_tint.xml
New file @@ -0,0 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_checked="false" android:color="@color/main_gray"/> <item android:state_checked="true" android:color="@color/blue_3"/> </selector> app/src/main/res/layout/activity_main.xml
@@ -373,24 +373,6 @@ <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/map_view" xmlns:map="http://schemas.android.com/apk/res-auto" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="100dp" map:uiZoomControls="false" map:uiRotateGestures="true" map:cameraBearing="112.5" map:cameraTargetLat="-33.796923" map:cameraTargetLng="150.922433" map:cameraTilt="30" map:cameraZoom="13" map:mapType="normal" map:uiCompass="false" map:uiScrollGestures="true" map:uiTiltGestures="true" map:uiZoomGestures="true" android:layout_height="100dp" /> <RelativeLayout android:id="@+id/rl_container" app/src/main/res/layout/activity_setting.xml
@@ -1,227 +1,248 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:orientation="vertical" <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/bg_main" android:layout_height="match_parent"> <TextView android:id="@+id/tv_more_langh" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" android:paddingStart="14dp" android:background="@color/white" android:paddingEnd="14dp" android:drawableEnd="@mipmap/more_black" android:text="@string/多语言" android:textColor="#ff333333" android:textSize="14sp" /> <View android:layout_width="match_parent" android:layout_height="14dp" android:background="#F3F4F5" android:id="@+id/view_line_14" android:alpha="0.3" /> <TextView android:id="@+id/tv_user_to" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" android:paddingStart="14dp" android:background="@color/white" android:paddingEnd="14dp" android:drawableEnd="@mipmap/more_black" android:text="@string/用户指南" android:textColor="#ff333333" android:textSize="14sp" /> <include layout="@layout/include_line_14"/> <TextView android:id="@+id/tv_qa" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" android:paddingStart="14dp" android:background="@color/white" android:paddingEnd="14dp" android:drawableEnd="@mipmap/more_black" android:text="@string/常见问题" android:textColor="#ff333333" android:textSize="14sp" /> <include layout="@layout/include_line_14"/> <TextView android:id="@+id/tv_rule" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" android:paddingStart="14dp" android:background="@color/white" android:paddingEnd="14dp" android:drawableEnd="@mipmap/more_black" android:text="@string/法律条款和平台规则" android:textColor="#ff333333" android:textSize="14sp" /> <include layout="@layout/include_line_14"/> <TextView android:id="@+id/tv_yh" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" android:paddingStart="14dp" android:background="@color/white" android:paddingEnd="14dp" android:drawableEnd="@mipmap/more_black" android:text="@string/用户协议" android:textColor="#ff333333" android:textSize="14sp" /> <include layout="@layout/include_line_14"/> <TextView android:id="@+id/tv_about_ys" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" android:paddingStart="14dp" android:background="@color/white" android:paddingEnd="14dp" android:drawableEnd="@mipmap/more_black" android:text="@string/隐私协议" android:textColor="#ff333333" android:textSize="14sp" /> <include layout="@layout/include_line_14"/> <TextView android:id="@+id/tv_about_me" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" android:paddingStart="14dp" android:background="@color/white" android:paddingEnd="14dp" android:drawableEnd="@mipmap/more_black" android:text="@string/关于我们" android:textColor="#ff333333" android:textSize="14sp" /> <include layout="@layout/include_line_14"/> <LinearLayout android:id="@+id/ll_clear" android:layout_width="match_parent" android:background="@color/white" android:layout_height="50dp" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="50dp" android:gravity="center_vertical" android:paddingStart="14dp" android:background="@color/white" android:paddingEnd="14dp" android:text="@string/清除缓存" android:textColor="#ff333333" android:textSize="14sp" /> <include layout="@layout/include_weight_width"/> <TextView android:id="@+id/tv_cache" android:layout_width="wrap_content" android:layout_height="50dp" android:gravity="center_vertical" android:paddingStart="14dp" android:background="@color/white" android:drawablePadding="@dimen/dp_10" android:paddingEnd="14dp" android:alpha="0.4" android:text="61.7M" android:textColor="#ff333333" android:textSize="14sp" /> </LinearLayout> <include layout="@layout/include_line_14"/> android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:background="@color/white" android:layout_height="50dp" android:orientation="horizontal"> android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:id="@+id/tv_more_langh" android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/white" android:drawableEnd="@mipmap/more_black" android:gravity="center_vertical" android:paddingStart="14dp" android:background="@color/white" android:paddingEnd="14dp" android:text="@string/当前版本" android:text="@string/多语言" android:textColor="#ff333333" android:textSize="14sp" /> android:textSize="14sp" /> <include layout="@layout/include_weight_width"/> <View android:id="@+id/view_line_14" android:layout_width="match_parent" android:layout_height="14dp" android:alpha="0.3" android:background="#F3F4F5" /> <TextView android:id="@+id/tv_version_code" android:layout_width="wrap_content" android:id="@+id/tv_user_to" android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/white" android:drawableEnd="@mipmap/more_black" android:gravity="center_vertical" android:paddingStart="14dp" android:background="@color/white" android:drawablePadding="@dimen/dp_10" android:paddingEnd="14dp" android:alpha="0.4" android:text="V1.0" android:text="@string/用户指南" android:textColor="#ff333333" android:textSize="14sp" /> android:textSize="14sp" /> <include layout="@layout/include_line_14" /> <TextView android:id="@+id/tv_qa" android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/white" android:drawableEnd="@mipmap/more_black" android:gravity="center_vertical" android:paddingStart="14dp" android:paddingEnd="14dp" android:text="@string/常见问题" android:textColor="#ff333333" android:textSize="14sp" /> <include layout="@layout/include_line_14" /> <TextView android:id="@+id/tv_rule" android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/white" android:drawableEnd="@mipmap/more_black" android:gravity="center_vertical" android:paddingStart="14dp" android:paddingEnd="14dp" android:text="@string/法律条款和平台规则" android:textColor="#ff333333" android:textSize="14sp" /> <include layout="@layout/include_line_14" /> <TextView android:id="@+id/tv_yh" android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/white" android:drawableEnd="@mipmap/more_black" android:gravity="center_vertical" android:paddingStart="14dp" android:paddingEnd="14dp" android:text="@string/用户协议" android:textColor="#ff333333" android:textSize="14sp" /> <include layout="@layout/include_line_14" /> <TextView android:id="@+id/tv_about_ys" android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/white" android:drawableEnd="@mipmap/more_black" android:gravity="center_vertical" android:paddingStart="14dp" android:paddingEnd="14dp" android:text="@string/隐私协议" android:textColor="#ff333333" android:textSize="14sp" /> <include layout="@layout/include_line_14" /> <TextView android:id="@+id/tv_about_me" android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/white" android:drawableEnd="@mipmap/more_black" android:gravity="center_vertical" android:paddingStart="14dp" android:paddingEnd="14dp" android:text="@string/关于我们" android:textColor="#ff333333" android:textSize="14sp" /> <include layout="@layout/include_line_14" /> <LinearLayout android:id="@+id/ll_floating_window" android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/white" android:orientation="horizontal" android:paddingHorizontal="14dp"> <TextView android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center_vertical" android:text="@string/开启悬浮窗" android:textColor="#ff333333" android:textSize="14sp" /> <com.google.android.material.switchmaterial.SwitchMaterial android:id="@+id/sm_floating_window" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="false" android:clickable="false" android:enabled="false" android:focusable="false" android:focusableInTouchMode="false" app:thumbTint="@color/selector_switch_thumb_tint" app:trackTint="@color/selector_switch_track_tint" app:useMaterialThemeColors="false" /> </LinearLayout> <include layout="@layout/include_line_14" /> <LinearLayout android:id="@+id/ll_clear" android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/white" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="50dp" android:background="@color/white" android:gravity="center_vertical" android:paddingStart="14dp" android:paddingEnd="14dp" android:text="@string/清除缓存" android:textColor="#ff333333" android:textSize="14sp" /> <include layout="@layout/include_weight_width" /> <TextView android:id="@+id/tv_cache" android:layout_width="wrap_content" android:layout_height="50dp" android:alpha="0.4" android:background="@color/white" android:drawablePadding="@dimen/dp_10" android:gravity="center_vertical" android:paddingStart="14dp" android:paddingEnd="14dp" android:text="61.7M" android:textColor="#ff333333" android:textSize="14sp" /> </LinearLayout> <include layout="@layout/include_line_14" /> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/white" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="50dp" android:background="@color/white" android:gravity="center_vertical" android:paddingStart="14dp" android:paddingEnd="14dp" android:text="@string/当前版本" android:textColor="#ff333333" android:textSize="14sp" /> <include layout="@layout/include_weight_width" /> <TextView android:id="@+id/tv_version_code" android:layout_width="wrap_content" android:layout_height="50dp" android:alpha="0.4" android:background="@color/white" android:drawablePadding="@dimen/dp_10" android:gravity="center_vertical" android:paddingStart="14dp" android:paddingEnd="14dp" android:text="V1.0" android:textColor="#ff333333" android:textSize="14sp" /> </LinearLayout> <include layout="@layout/include_line_14" /> <TextView android:id="@+id/ll_version" android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/white" android:drawableEnd="@mipmap/more_black" android:gravity="center_vertical" android:paddingStart="14dp" android:paddingEnd="14dp" android:text="@string/版本更新" android:textColor="#ff333333" android:textSize="14sp" /> </LinearLayout> <include layout="@layout/include_line_14"/> <TextView android:id="@+id/ll_version" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" android:paddingStart="14dp" android:background="@color/white" android:paddingEnd="14dp" android:drawableEnd="@mipmap/more_black" android:text="@string/版本更新" android:textColor="#ff333333" android:textSize="14sp" /> </LinearLayout> </ScrollView> app/src/main/res/layout/fx_card.xml
New file @@ -0,0 +1,51 @@ <?xml version="1.0" encoding="utf-8"?> <com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/fxCard" android:layout_width="wrap_content" android:layout_height="wrap_content" app:cardCornerRadius="10dp" app:cardElevation="4dp"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="140dp" android:layout_height="74dp" android:background="@drawable/bg_login"> <ImageView android:id="@+id/iv_logo" android:layout_width="56dp" android:layout_height="56dp" android:layout_marginEnd="6dp" android:src="@mipmap/ic_launcher" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/tv1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="12dp" android:layout_marginTop="14dp" android:gravity="center" android:text="@string/listen_order" android:textColor="@color/white" android:textSize="15sp" android:textStyle="bold" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="4dp" android:gravity="center" android:text="@string/IGO打车" android:textColor="@color/white" android:textSize="12sp" app:layout_constraintStart_toStartOf="@id/tv1" app:layout_constraintTop_toBottomOf="@id/tv1" /> </androidx.constraintlayout.widget.ConstraintLayout> </com.google.android.material.card.MaterialCardView> app/src/main/res/values-en/strings.xml
@@ -631,6 +631,7 @@ <string name="立即支付">PAY NOW</string> <string name="交货">Delivery</string> <string name="定位中">Positioning…</string> <string name="正在后台持续获取位置">continuously obtaining location in the background</string> <string name="选择照片">Choose a photo</string> <string name="年">Year</string> <string name="月">Month</string> @@ -672,8 +673,8 @@ <string name="当前可更换车辆">Currently Replaceable Vehicles</string> <string name="等待用户支付差价">Waiting for the user to pay the difference</string> <string name="请输入4位号码">Please enter a 4-digit number</string> <string name="分享错误" >Share error</string> <string name="分享成功" >Share success</string> <string name="分享错误">Share error</string> <string name="分享成功">Share success</string> <string name="朋友圈">Moments</string> <string name="微信">WeChat</string> <string name="机动车行驶证号码">Roadworthiness sticker number</string> @@ -725,7 +726,7 @@ <string name="pay_often">Settlement cycle</string> <string name="请填写居住地址">Please enter your residential address</string> <string name="请选择保险到期日期">Please select an insurance expiration date</string> <string name="too_far" >Far destination</string> <string name="too_far">Far destination</string> <string name="too_busy">Traffic jam</string> <string name="no_rider">Rider did not show up</string> <string name="car_problom">"Vehicle problem "</string> @@ -786,8 +787,8 @@ <string name="争议订单协商价格">( Note: Disputed order, after tripartite negotiation, the final pricing of the platform is FCFA %s )</string> <string name="被冻结">The order has been blocked by GOPOST, and GOPOST customer service will contact you</string> <string name="取消订单费用">Cancellation fee</string> <string name="请求出错" >Request error</string> <string name="定位权限说明" > GOPOST Driver requires location permission to:\n1. Check if service is available in your current district,\n2. Match and push nearby orders to you,\n3. Transmit your real-time location during trips to show passengers your current position.\n\nWe will upload your location data to our backend in real-time, both when the app is in the foreground and during active trips (even if briefly in the background), solely for the above core service purposes.\nIf you deny location authorization, you will not be able to receive orders or provide trip services normally.\nDo you confirm the authorization?</string> <string name="请求出错">Request error</string> <string name="定位权限说明">The GOPOST driver app requires location permission for the following purposes: \nchecking if service is available in your current area, \nmatching and pushing nearby orders to you, \nand transmitting your location in real-time during the trip so that passengers can view your current position. \nWe will upload your location data in real-time to the backend during the application trip (even in the background), solely for the aforementioned core service purposes. \nIf you refuse to authorize, you will not be able to receive orders or provide trip services normally. \nAre you sure you want to authorize?</string> <string name="拒绝权限">Deny</string> <string name="充值">Recharge</string> <string name="余额充值">Balance recharge</string> @@ -831,5 +832,11 @@ <string name="收款金额">Payment Amount</string> <string name="订单收款金额">Order payment amount</string> <string name="已经是最新版">当前已经是最新版本了</string> <string name="悬浮窗说明">The GOPOST driver app requires permission to access the floating window feature, which allows you to quickly return to the app to receive orders or provide ride services</string> <string name="开启悬浮窗">open the floating window</string> <string name="请选择内容">please select content</string> <string name="没有定位权限提示">Without positioning permission, you will not be able to receive new order push notifications</string> <string name="手机号为空">the phone number is empty</string> <string name="休息中">On break</string> </resources> app/src/main/res/values-fr/strings.xml
@@ -637,6 +637,7 @@ <string name="立即支付">Payez maintenant</string> <string name="交货">Livré</string> <string name="定位中">Penentuan posisi…</string> <string name="正在后台持续获取位置">La localisation est en cours de récupération en arrière-plan</string> <string name="选择照片">CHOISISSEZ UNE PHOTO</string> <string name="年">L’an</string> <string name="月">Mois</string> @@ -791,7 +792,7 @@ <string name="被冻结">La commande a été bloquée par GOPOST, et le service client d’GOPOST vous contactera</string> <string name="取消订单费用">Frais d\'annulation</string> <string name="请求出错" >Erreur de demande</string> <string name="定位权限说明" >GOPOST Driver a besoin de l\'autorisation de localisation pour :\n1. Vérifier si le service est disponible dans votre quartier actuel,\n2. Vous correspondre et vous proposer des commandes à proximité,\n3. Transmettre votre position en temps réel pendant les trajets afin que les passagers puissent voir votre emplacement actuel.\n\nNous téléchargerons vos données de localisation sur notre serveur en temps réel, tant lorsque l\'application est en premier plan que pendant les trajets actifs (même brièvement en arrière-plan), uniquement pour les besoins des services de base mentionnés ci-dessus.\nSi vous refusez l\'autorisation de localisation, vous ne pourrez pas recevoir de commandes ni fournir de services de trajet normalement.\nConfirmez-vous l\'autorisation ?</string> <string name="定位权限说明" >L\'application GOPOST pour conducteurs nécessite l\'autorisation d\'accéder à la localisation, à des fins de : \nVérifier si votre zone actuelle est couverte par nos services, \nVous attribuer et envoyer des commandes à proximité, \nTransmettre en temps réel votre position pendant le trajet pour que les passagers puissent voir votre localisation actuelle. \nNous transmettrons vos données de localisation en temps réel au serveur, même en arrière-plan, uniquement pour les services essentiels mentionnés ci-dessus. \nSi vous refusez l\'autorisation, vous ne pourrez pas recevoir normalement les commandes ou fournir les services de trajet. \nConfirmez-vous l\'autorisation ?</string> <string name="拒绝权限" >Refuser</string> <string name="充值">Recharge</string> <string name="余额充值">Recharge du solde</string> @@ -835,5 +836,11 @@ <string name="收款金额">Montant de recette</string> <string name="订单收款金额">Montant perçu de la commande</string> <string name="已经是最新版">Vous utilisez déjà la dernière version.</string> <string name="悬浮窗说明">L\'application conducteur de GOPOST nécessite l\'autorisation de fenêtre flottante pour vous permettre de revenir rapidement à l\'application afin de recevoir des commandes ou de fournir des services de trajet</string> <string name="开启悬浮窗">Activer la fenêtre flottante</string> <string name="请选择内容">Veuillez sélectionner le contenu</string> <string name="没有定位权限提示">Sans autorisation de localisation, vous ne pourrez pas recevoir les notifications push de nouvelles commandes.</string> <string name="手机号为空">Le numéro de téléphone est vide.</string> <string name="休息中">En pause</string> </resources> app/src/main/res/values/colors.xml
@@ -103,6 +103,7 @@ <color name="color_F3F4F5">#99000000</color> <color name="color_f07207">#fff07207</color> <color name="blue_1">#0E7151</color> <color name="blue_3">#800E7151</color> <color name="blue_2">#89BB28</color> <color name="color_EE6307">#F07207</color> <color name="color_5DB03D">#5DB03D</color> app/src/main/res/values/strings.xml
@@ -613,6 +613,7 @@ <string name="立即支付">立即支付</string> <string name="交货">交货</string> <string name="定位中">定位中…</string> <string name="正在后台持续获取位置">正在后台持续获取位置</string> <string name="选择照片">选择照片</string> <string name="年">年</string> <string name="月">月</string> @@ -777,7 +778,7 @@ <string name="被冻结">此订单已被平台冻结,平台客服将会联系您</string> <string name="取消订单费用">取消订单费用</string> <string name="请求出错">请求出错</string> <string name="定位权限说明"> GOPOST 司机端 需要获取位置权限,用于:\n检查你当前区域是否可提供服务,\n为你匹配并推送附近订单,\n在行程中实时传输你的位置,以便乘客查看你的当前位置。\n我们会在应用前台及行程中(即使短暂处于后台)将你的位置数据实时上传至后端,仅用于上述核心服务目的。\n若你拒绝位置授权,将无法正常接收订单或提供行程服务。\n是否确认授权?</string> <string name="定位权限说明">GOPOST 司机端 需要获取位置权限,用于:\n检查你当前区域是否可提供服务,\n为你匹配并推送附近订单,\n在行程中实时传输你的位置,以便乘客查看你的当前位置。\n我们会在应用行程中(即使处于后台)将你的位置数据实时上传至后端,仅用于上述核心服务目的。\n若你拒绝授权,将无法正常接收订单或提供行程服务。\n是否确认授权?</string> <string name="拒绝权限">拒绝</string> @@ -823,5 +824,11 @@ <string name="收款金额">收款金额</string> <string name="订单收款金额">订单收款金额</string> <string name="已经是最新版">当前已经是最新版本了</string> <string name="悬浮窗说明">GOPOST 司机端 需要获取悬浮窗权限,方便您快速回到应用接收订单或提供行程服务</string> <string name="开启悬浮窗">开启悬浮窗</string> <string name="请选择内容">请选择内容</string> <string name="没有定位权限提示">如果没有定位权限,您将无法接收新的订单推送通知</string> <string name="手机号为空">手机号为空</string> <string name="休息中">休息中</string> </resources> app/src/main/res/values/styles.xml
@@ -51,4 +51,5 @@ <item name="android:layout_height">1px</item> <item name="android:layout_width">match_parent</item> </style> <style name="Theme.FloatingX" parent="Theme.Material3.DayNight.NoActionBar" /> </resources> build.gradle
@@ -23,7 +23,7 @@ } dependencies { classpath 'com.android.tools.build:gradle:8.6.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.21" classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files xldUtils/src/main/java/cn/sinata/xldutils/activitys/BaseActivity.java
@@ -194,7 +194,7 @@ */ protected void closeAll() { Intent intent = new Intent(ACTION_CLOSE_ALL); sendBroadcast(intent); LocalBroadcastManager.getInstance(this).sendBroadcast(intent); } /**