Commit a2d9f548 authored by wanglei's avatar wanglei

...

parent 2080767f
......@@ -114,4 +114,8 @@ dependencies {
//facebook
implementation("com.facebook.android:facebook-android-sdk:[8,9)")
//work
implementation("androidx.work:work-runtime-ktx:2.7.1") // 请使用最新版本
}
\ No newline at end of file
import android.content.Context
import android.util.Log
import com.base.locationsharewhite.helper.EventUtils
import com.base.locationsharewhite.helper.EventUtils.event
import com.base.locationsharewhite.utils.AppPreferences
import com.base.locationsharewhite.utils.LogEx
import com.google.android.gms.tasks.OnCompleteListener
import com.google.android.gms.tasks.Task
import com.google.firebase.FirebaseApp
import com.google.firebase.messaging.FirebaseMessaging
import org.json.JSONObject
object FCMManager {
fun initFirebase(context: Context?) {
FirebaseApp.initializeApp(context!!)
LogEx.logDebug("initFirebase", "initFirebase")
getToken()
}
fun subscribeToTopic(topic: String) {
Log.e("FCMUtil", "subscribeToTopic")
FirebaseMessaging.getInstance().subscribeToTopic(topic)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
getToken()
Log.e("FCMUtil", "isSuccessful")
event("FCM_Topic_$topic", null, null, false)
} else {
event("FCM_Error", "subscribeToTopic task.isSuccessful=${task.isSuccessful} ", null, false)
}
}
}
fun unsubscribeFromTopic(topic: String?) {
FirebaseMessaging.getInstance().unsubscribeFromTopic(topic!!)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
} else {
}
}
}
private fun getToken() {
FirebaseMessaging.getInstance().token
.addOnCompleteListener(object : OnCompleteListener<String> {
override fun onComplete(task: Task<String>) {
LogEx.logDebug("FCM", "onComplete ${task.isSuccessful}")
if (!task.isSuccessful) {
Log.e("FCM", "Fetching FCM registration token failed", task.exception)
return
}
// Get new FCM registration token
val token: String = task.result
LogEx.logDebug("FCM", "token=$token")
val json = JSONObject()
json.put("token", token)
EventUtils.event("fcm_message_received", ext = json)
AppPreferences.getInstance().put("token", token)
// Handle new token
Log.d("FCM", "FCM Registration Token: $token")
}
})
}
}
package com.base.locationsharewhite.fcm;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.base.locationsharewhite.helper.EventUtils;
import com.base.locationsharewhite.utils.LogEx;
import com.base.pdfreaderallpdfreader.fcm.PopupConstObject;
public class FcmReceiver extends BroadcastReceiver {
private String TAG = "FcmReceiver";
@Override
public void onReceive(Context context, Intent intent) {
LogEx.INSTANCE.logDebug(TAG, "onReceive", false);
EventUtils.INSTANCE.event("FCM_Received", null, null, false);
NotificationUiUtil.INSTANCE.sendNotificationIfCan(context, PopupConstObject.POPUP_WHERE_FCM, null);
}
}
package com.base.locationsharewhite.fcm;
import android.annotation.SuppressLint;
import androidx.annotation.NonNull;
import com.base.locationsharewhite.helper.EventUtils;
import com.base.locationsharewhite.utils.LogEx;
import com.base.pdfreaderallpdfreader.fcm.PopupConstObject;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
@SuppressLint("MissingFirebaseInstanceTokenRefresh")
public class MessagingService extends FirebaseMessagingService {
private static final String TAG = "MessagingService";
@Override
public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
LogEx.INSTANCE.logDebug(TAG, "onMessageReceived", false);
EventUtils.INSTANCE.event("FCM_Received", null, null, false);
NotificationUiUtil.INSTANCE.sendNotificationIfCan(this, PopupConstObject.POPUP_WHERE_FCM, null);
}
}
\ No newline at end of file
package com.base.locationsharewhite.notification
package com.base.locationsharewhite.fcm
import android.content.Context
import android.os.Handler
import android.os.HandlerThread
import com.base.locationsharewhite.fcm.MsgMgr
import com.base.locationsharewhite.helper.MyApplication
import com.base.locationsharewhite.utils.AppPreferences
import com.base.locationsharewhite.utils.LogEx
import com.base.pdfreaderallpdfreader.fcm.PopupConstObject.popup_hover_count
import com.base.pdfreaderallpdfreader.fcm.PopupConstObject.popup_hover_delay
import com.base.pdfreaderallpdfreader.fcm.PopupConstObject.popup_hover_status
object NotificationHoverUtils {
......@@ -15,7 +19,13 @@ object NotificationHoverUtils {
/**
* 发送悬停通知
*/
fun sendHoverNotification(context: Context, hoverCount: Int, hoverDelay: Int) {
fun sendHoverNotification(context: Context) {
val hoverCount = AppPreferences.getInstance().getString(popup_hover_count, "0").toInt()
val hoverDelay = AppPreferences.getInstance().getString(popup_hover_delay, "0").toLong()
val hoverStatus = AppPreferences.getInstance().getString(popup_hover_status, "0").toInt()
if (hoverStatus == 0) return
if (handlerThread == null) {
handlerThread = HandlerThread("NotificationHandlerThread")
handlerThread?.start()
......@@ -29,10 +39,17 @@ object NotificationHoverUtils {
}
for (i in 1..hoverCount) {
val time = (i * hoverDelay * 1000 + 300).toLong()
val time = i * hoverDelay
handler?.postDelayed(Runnable {
//发送普通通知,不需要在悬停,这里就关闭了悬停
MsgMgr.sendNotification(context, MsgMgr.hoverActionId, 0)
LogEx.logDebug(TAG, "handler ${MyApplication.PAUSED_VALUE}")
if (MyApplication.PAUSED_VALUE == 1) {
handler?.removeCallbacksAndMessages(null)
return@Runnable
}
if (MyApplication.PAUSED_VALUE != 1) {
LogEx.logDebug(TAG, "handler send notification")
NotificationUiUtil.setActionNotification(context, NotificationUiUtil.hoverActionId)
}
}, time)
}
}
......
package com.base.locationsharewhite.fcm
import android.annotation.SuppressLint
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.drawable.Icon
import android.os.Build
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import androidx.core.graphics.drawable.IconCompat
import com.base.locationsharewhite.BuildConfig
import com.base.locationsharewhite.R
import com.base.locationsharewhite.fcm.PopupConstObject.POPUP_WHERE_FCM
import com.base.locationsharewhite.fcm.PopupConstObject.POPUP_WHERE_LOCK
import com.base.locationsharewhite.fcm.PopupConstObject.POPUP_WHERE_TIMBER
import com.base.locationsharewhite.fcm.PopupConstObject.popup_count
import com.base.locationsharewhite.fcm.PopupConstObject.popup_end
import com.base.locationsharewhite.fcm.PopupConstObject.popup_fcm_interval
import com.base.locationsharewhite.fcm.PopupConstObject.popup_interval
import com.base.locationsharewhite.fcm.PopupConstObject.popup_lock_interval
import com.base.locationsharewhite.fcm.PopupConstObject.popup_start
import com.base.locationsharewhite.fcm.PopupConstObject.popup_status
import com.base.locationsharewhite.fcm.PopupConstObject.popup_timer_interval
import com.base.locationsharewhite.helper.EventUtils
import com.base.locationsharewhite.helper.MyApplication
import com.base.locationsharewhite.helper.config.ConstConfig.ACTION_APP_PROCESS
import com.base.locationsharewhite.utils.AppPreferences
import com.base.locationsharewhite.utils.LogEx
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import kotlin.random.Random
/**
* 构建发送通知 UI
* 用的actionId代替notificationId使用
*/
object NotificationUiUtil {
private val TAG = "NotificationUiUtil"
const val CHANNEL_ID = "browser_notification_id" // 通知渠道ID
const val CHANNEL_NAME = "browser_fcm_channel" // 通知渠道名称
var NOTIFICATION_ID = 8999
private fun currentDate(): String {
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
val currentDate = Calendar.getInstance().time
return dateFormat.format(currentDate)
}
//当天推送次数
var dayPopupCount = 0
get() {
return AppPreferences.getInstance().getInt("dayPopupCount_${currentDate()}", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("dayPopupCount_${currentDate()}", value, true)
}
var lastPopupTime = 0L
get() {
return AppPreferences.getInstance().getLong("lastPopupTime", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("lastPopupTime", value, true)
}
fun canSendNotification(where: String, actionId: String): Boolean {
//是否开启推送
val status = AppPreferences.getInstance().getString(popup_status, "1").toInt()
if (status == 0) {
EventUtils.event("Notification_Error", "status=$status")
LogEx.logDebug("canSendNotification", "status")
return false
}
//当天推送次数
val count = AppPreferences.getInstance().getString(popup_count, "20").toInt()
if (dayPopupCount > count) {
LogEx.logDebug("canSendNotification", "count")
EventUtils.event("Notification_Error", "dayPopupCount=$dayPopupCount count=$count where=$where actionId=$actionId")
return false
}
//判断是否在时间区域
val start = AppPreferences.getInstance().getString(popup_start, "0").toInt()
val end = AppPreferences.getInstance().getString(popup_end, "24").toInt()
val calendar = Calendar.getInstance()
val currentHour = calendar.get(Calendar.HOUR_OF_DAY)
if (currentHour !in start until end) {
LogEx.logDebug("canSendNotification", "start-end currentHour=$currentHour start=$start end=$end")
EventUtils.event("Notification_Error", "start=$start end=$end currentHour=$currentHour where=$where actionId=$actionId")
return false
}
//单位分钟
var interval = AppPreferences.getInstance().getString(popup_interval, "1").toInt()
if (where == POPUP_WHERE_TIMBER) {
interval = AppPreferences.getInstance().getString(popup_timer_interval, "7").toInt()
}
if (where == POPUP_WHERE_LOCK) {
interval = AppPreferences.getInstance().getString(popup_lock_interval, "1").toInt()
}
if (where == POPUP_WHERE_FCM) {
interval = AppPreferences.getInstance().getString(popup_fcm_interval, "1").toInt()
}
val passedTime = System.currentTimeMillis() - lastPopupTime
if (passedTime < interval * 60 * 1000L) {
EventUtils.event("Notification_Error", "where=$where actionId=$actionId interval=$interval passedTime=$passedTime")
LogEx.logDebug("canSendNotification", "interval where=$where passedTime=$passedTime interval=$interval")
return false
}
return true
}
var hoverActionId = ""
@SuppressLint("RemoteViewLayout")
fun sendNotificationIfCan(context: Context, where: String = "", id: String? = null) {
val actionId = id ?: getNextActionId()
if (!canSendNotification(where, actionId)) return
if (MyApplication.PAUSED_VALUE == 1) {
LogEx.logDebug(TAG, "APP Resumed")
return
}
//发送通知
setActionNotification(context, actionId)
//上报通知
EventUtils.event("Notification_Popup", "where=$where actionId=$actionId")
//当天次数加一
dayPopupCount += 1
//推送时间
lastPopupTime = System.currentTimeMillis()
//悬停通知
hoverActionId = actionId
NotificationHoverUtils.sendHoverNotification(context)
}
fun setActionNotification(context: Context, actionId: String) {
// val bigRemoteViews = RemoteViews(MyApplication.appContext.packageName, R.layout.notification_message)
// val smallRemoteViews = RemoteViews(MyApplication.appContext.packageName, R.layout.notification_message)
// val intent = Intent(context, MyStartActivity::class.java)
// intent.putExtra("actionId", actionId)
//
when (actionId) {
else -> {
EventUtils.event("Notification_Error", "unKnow actionId actionId=$actionId")
}
}
}
private fun sendCustomNotification(
context: Context,
intent: Intent,
bigRemoteViews: RemoteViews,
smallRemoteViews: RemoteViews,
) {
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//创建channel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH
)
channel.lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
notificationManager.createNotificationChannel(channel)
}
// Create the notification
val builder: NotificationCompat.Builder = NotificationCompat.Builder(context, CHANNEL_ID)
//设置状态栏内的小图标
val smallIcon = IconCompat.createFromIcon(
context, Icon.createWithResource(
context, R.mipmap.logo
)
)
smallIcon?.let {
builder.setSmallIcon(smallIcon)
}
builder.setContentTitle(context.resources.getString(R.string.app_name))
.setContentText("notification")
val requestCode = Random.nextInt(1000)
val pendingIntent = PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_IMMUTABLE)
builder.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setAutoCancel(true)
var small: RemoteViews? = bigRemoteViews
//Android 12以下需要适配小RemoteViews
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
small = smallRemoteViews
}
// 设置小视图
builder.setCustomContentView(smallRemoteViews)
// 设置悬浮通知视图(Android 12 及以上)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
builder.setCustomHeadsUpContentView(bigRemoteViews)
}
// 设置大视图
builder.setCustomBigContentView(bigRemoteViews)
notificationManager.notify(NOTIFICATION_ID, builder.build())
}
val looper_actionId = listOf(
ACTION_APP_PROCESS,
)
var actionIdList = arrayListOf<String>()
fun getNextActionId(): String {
if (actionIdList.isEmpty()) {
actionIdList.addAll(looper_actionId)
}
val next = actionIdList[0]
actionIdList.removeAt(0)
if (BuildConfig.DEBUG) {
// return NOTIFICATION_ACTION_WEATHER
}
return next
}
}
\ No newline at end of file
package com.base.locationsharewhite.fcm
import com.base.locationsharewhite.utils.AppPreferences
object PopupConstObject {
const val POPUP_WHERE_TIMBER = "Timer"
const val POPUP_WHERE_LOCK = "Lock"
const val POPUP_WHERE_FCM = "fcm"
const val POPUP_WHERE_ALARM = "Alarm"
const val POPUP_WHERE_WORK_MANAGER = "workmanager"
const val POPUP_WHERE_MEDIA_CHANGE = "media_change"
const val POPUP_WHERE_HOVER_HANDLE = "hover_handle"//悬停调用
//推送总开关 0 关 1开
val popup_status = "popup_status"
//推送总数量现在
const val popup_count = "popup_count"//所有常规推送的当日推送次数限制,0 为不限制
const val popup_start = "popup_start"
const val popup_end = "popup_end"
const val popup_interval = "popup_interval"
const val popup_timer_interval = "popup_timber_interval"
const val popup_lock_interval = "popup_lock_interval"
const val popup_fcm_interval = "popup_fcm_interval"
const val popup_hover_status = "popup_hover_status"
const val popup_hover_count = "popup_hover_count"
const val popup_hover_delay = "popup_hover_delay"
const val lockS = "lockS"
const val timerS = "timerS"
const val timerDelay = "timerDelay"
const val timerInterval = "timerInterval"
var topic_number = ""
get() {
return AppPreferences.getInstance().getString("topic_number", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("topic_number", value, true)
}
}
\ No newline at end of file
package com.base.locationsharewhite.fcm;
import static com.base.locationsharewhite.fcm.PopupConstObject.lockS;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import com.base.locationsharewhite.utils.AppPreferences;
import com.base.locationsharewhite.utils.LogEx;
import java.util.Objects;
public class ScreenStatusReceiver extends BroadcastReceiver {
private static boolean isDeviceInteractive = true;
private static boolean isSecureLockActive = false;
public static void setupScreenStatusListener(Context context) {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
intentFilter.addAction(Intent.ACTION_USER_PRESENT);
final Context applicationContext = context.getApplicationContext();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
applicationContext.registerReceiver(new ScreenStatusReceiver(), intentFilter, Context.RECEIVER_EXPORTED);
} else {
applicationContext.registerReceiver(new ScreenStatusReceiver(), intentFilter);
}
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (Objects.requireNonNull(action)) {
case Intent.ACTION_SCREEN_ON:
setDeviceInteractive(true);
break;
case Intent.ACTION_SCREEN_OFF:
setDeviceInteractive(false);
setSecureLockActive(true);
break;
case Intent.ACTION_USER_PRESENT:
LogEx.INSTANCE.logDebug("ScreenStatusReceiver", "ACTION_USER_PRESENT", false);
setSecureLockActive(false);
if (isDeviceInteractive() && !isSecureLockActive()) {
int secureSetting = Integer.parseInt(AppPreferences.getInstance().getString(lockS, "1"));
if (secureSetting == 1) {
NotificationUiUtil.INSTANCE.sendNotificationIfCan(context, PopupConstObject.POPUP_WHERE_LOCK, null);
}
}
break;
}
}
private void setDeviceInteractive(boolean interactive) {
isDeviceInteractive = interactive;
}
public static boolean isDeviceInteractive() {
return isDeviceInteractive;
}
private void setSecureLockActive(boolean active) {
isSecureLockActive = active;
}
public static boolean isSecureLockActive() {
return isSecureLockActive;
}
}
\ No newline at end of file
package com.base.locationsharewhite.fcm;
import android.util.Log;
import com.base.locationsharewhite.helper.MyApplication;
import com.base.locationsharewhite.utils.LogEx;
import java.util.Timer;
import java.util.TimerTask;
public class TimerManager {
private static TimerManager instance;
private Timer taskTimer;
private boolean isTimerActive;
private TimerManager() {
// 私有构造方法
}
public static synchronized TimerManager getInstance() {
if (instance == null) {
instance = new TimerManager();
}
return instance;
}
public void scheduleTask(long delay, long period) {
LogEx.INSTANCE.logDebug("TimerManager", "scheduleTask", false);
synchronized (TimerManager.class) {
ensureTimerIsStopped(); // 确保定时器未运行
taskTimer = new Timer(); // 创建新的 Timer 实例
TimerTask task = new TimerTask() {
@Override
public void run() {
Log.d("glc", "Scheduled task is running");
// 确保设备处于交互状态,未锁定,且应用未暂停
if (ScreenStatusReceiver.isDeviceInteractive() &&
!ScreenStatusReceiver.isSecureLockActive() &&
MyApplication.PAUSED_VALUE != 1) {
Log.d("glc", "Scheduled task conditions are met");
NotificationUiUtil.INSTANCE.sendNotificationIfCan(MyApplication.appContext,
PopupConstObject.POPUP_WHERE_TIMBER, null);
}
}
};
taskTimer.schedule(task, delay, period); // 调度任务
isTimerActive = true; // 设置定时器状态为活跃
}
}
private void ensureTimerIsStopped() {
if (isTimerActive) {
if (taskTimer != null) {
taskTimer.cancel();
taskTimer.purge(); // 清除所有取消的任务
}
isTimerActive = false; // 重置定时器状态
}
}
public void stopTaskTimer() {
synchronized (TimerManager.class) {
ensureTimerIsStopped(); // 停止定时器
}
}
public boolean isTaskTimerActive() {
return isTimerActive;
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.fcm.alarm
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.base.locationsharewhite.fcm.PopupConstObject
import com.base.pdfreaderallpdfreader.BuildConfig
import com.base.pdfreaderallpdfreader.fcm.NotificationUiUtil.sendNotificationIfCan
import com.base.pdfreaderallpdfreader.helper.EventUtils
import com.base.pdfreaderallpdfreader.utils.AppPreferences
import com.base.pdfreaderallpdfreader.utils.LogEx
class AlarmJobReceiver : BroadcastReceiver() {
private val TAG = "AlarmJobReceiver"
@SuppressLint("UnsafeProtectedBroadcastReceiver")
override fun onReceive(context: Context, intent: Intent?) {
LogEx.logDebug(TAG, "AlarmJobReceiver onReceive")
EventUtils.event("alarm_push")
var firstAlemtime = AppPreferences.getInstance().getLong("firstAlemtime", 0L)
if (BuildConfig.DEBUG) {
firstAlemtime = 1
}
if (firstAlemtime > 0) {
val leatTime = System.currentTimeMillis()
if (leatTime - firstAlemtime >= 1000 * 30 * 60) {
sendNotificationIfCan(context, PopupConstObject.POPUP_WHERE_ALARM)
}
}
AppPreferences.getInstance().put("firstAlemtime", System.currentTimeMillis())
return
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.fcm.alarm
import android.app.AlarmManager
import android.app.PendingIntent
import android.app.job.JobService
import android.content.Context
import android.content.Intent
import com.base.pdfreaderallpdfreader.BuildConfig
import com.base.pdfreaderallpdfreader.fcm.work.RepeatingWorker.Companion.schedulePeriodicWork
import com.base.pdfreaderallpdfreader.service.StayJobService.Companion.startJob
import java.util.Calendar
object AlarmUtils {
fun startAlarm(context: Context) {
context.startJob()
//闹钟定时任务
val alarmManager = context.getSystemService(JobService.ALARM_SERVICE) as AlarmManager
val pendingIntent = PendingIntent.getBroadcast(
context, 1, Intent(context, AlarmJobReceiver::class.java),
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val calendar = Calendar.getInstance()
calendar.set(Calendar.HOUR_OF_DAY, 6)
calendar.set(Calendar.MINUTE, 0)
calendar.set(Calendar.SECOND, 0)
var delay = 1800000L
if (BuildConfig.DEBUG) {
delay = 1 * 60 * 1000L
}
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP, calendar.timeInMillis, delay, pendingIntent
)
schedulePeriodicWork(context)
}
}
\ No newline at end of file
package com.base.locationsharewhite.fcm.work
import android.content.Context
import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.NetworkType
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.base.locationsharewhite.fcm.NotificationUiUtil.sendNotificationIfCan
import com.base.locationsharewhite.fcm.PopupConstObject
import com.base.locationsharewhite.helper.EventUtils
import java.util.concurrent.TimeUnit
class RepeatingWorker(val appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) {
override fun doWork(): Result {
// 这里执行你的任务
// 例如,更新UI,发送网络请求等
EventUtils.event("workmanager_live")
try {
sendNotificationIfCan(appContext, PopupConstObject.POPUP_WHERE_WORK_MANAGER);
} catch (e: Exception) {
EventUtils.event("WorkManager Error")
}
return Result.success()
}
companion object {
const val TAG = "uniqueWorkName"
fun schedulePeriodicWork(context: Context) {
WorkManager.getInstance(context).cancelAllWorkByTag(TAG)
val request = PeriodicWorkRequestBuilder<RepeatingWorker>(15, TimeUnit.MINUTES)
.setConstraints(
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
)
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
TAG, ExistingPeriodicWorkPolicy.KEEP, request
)
}
}
}
\ No newline at end of file
......@@ -14,10 +14,6 @@ object ConstConfig {
inline val insertAdId get() = if (BuildConfig.DEBUG) interAdmobIdTest else interAdmobId
inline val nativeAdId get() = if (BuildConfig.DEBUG) nativeAdmobIdTest else nativeAdmobId
//云控remoteConfig对应的key
const val REMOTE_MSG = "MsgConfig"//云控消息配置对应的key
const val REMOTE_AD = "AdmobConfig"//云控广告配置对应的key
//admob test id
const val openAdmobIdTest = "ca-app-pub-3940256099942544/9257395921"
......@@ -31,20 +27,5 @@ object ConstConfig {
const val openAdmobId = "/6499/example/app-open"
const val bannerAdmobId = "ca-app-pub-3940256099942544/9214581111"
//通知相关配置
const val CHANNEL_ID = "msg_notification_id" // 通知渠道ID
const val CHANNEL_NAME = "msg_fcm_channel" // 通知渠道名称
const val NOTIFICATION_ID = 8889//普通通知id
const val NOTIFICATION_PERMANENT_ID = 10001//常驻通知id
val NOTIFICATION_LOGO = R.mipmap.logo
//通知栏的一些应用事件,自己定咯,不同事件和不同的自定义通知栏视图
const val ACTION_STAY_HOME = 0
const val ACTION_STAY_MY_CODE = 1
const val ACTION_STAY_SHARE = 2
const val ACTION_STAY_SETTING = 3
const val ACTION_SHARE_LOCATION = 4
const val ACTION_ENABLE_LOCATION = 5
const val ACTION_COPY_CODE = 6
const val ACTION_APP_PROCESS = ""
}
\ No newline at end of file
package com.base.locationsharewhite.notification
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.base.locationsharewhite.fcm.MsgMgr
/**
*通知刪除监听
*/
class DeleteNotificationReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
MsgMgr.stopHoverNotification()
}
}
\ No newline at end of file
package com.base.locationsharewhite.notification
import android.content.Intent
import android.widget.RemoteViews
/**
* 自定义通知栏的配置
* @property intent 自定义通知栏传入的跳转或者传参之类
* @property bigRemoteViews
* @property smallRemoteViews
*/
class NotificationBean(
val intent: Intent, val bigRemoteViews: RemoteViews,
val smallRemoteViews: RemoteViews
)
\ No newline at end of file
package com.base.locationsharewhite.notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.drawable.Icon
import android.os.Build
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import androidx.core.graphics.drawable.IconCompat
import com.base.locationsharewhite.R
import com.base.locationsharewhite.helper.config.ConstConfig
import kotlin.random.Random
/**
*通知管理类
*/
object NotificationMgr {
fun init(context: Context) {
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//创建channel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
ConstConfig.CHANNEL_ID,
ConstConfig.CHANNEL_NAME,
NotificationManager.IMPORTANCE_HIGH
)
channel.lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
channel.enableLights(false)
channel.enableVibration(false)
channel.vibrationPattern = longArrayOf(0)
channel.setSound(null, null)
notificationManager.createNotificationChannel(channel)
}
}
fun sendNotification(
context: Context, intent: Intent,
bigRemoteViews: RemoteViews,
smallRemoteViews: RemoteViews
) {
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Create the notification
val builder: NotificationCompat.Builder =
NotificationCompat.Builder(context, ConstConfig.CHANNEL_ID)
//设置状态栏内的小图标
val smallIcon = IconCompat.createFromIcon(
context, Icon.createWithResource(
context, ConstConfig.NOTIFICATION_LOGO
)
)
smallIcon?.let {
builder.setSmallIcon(smallIcon)
}
builder.setContentTitle(context.resources.getString(R.string.app_name))
.setContentText("notification")
val requestCode = Random.nextInt(1000)
val pendingIntent =
PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_IMMUTABLE)
val deleteIntent =
PendingIntent.getBroadcast(
context,
requestCode,
Intent(context, DeleteNotificationReceiver::class.java),
PendingIntent.FLAG_IMMUTABLE
)
builder.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setAutoCancel(true)
.setVibrate(longArrayOf(0))
.setSound(null)
.setDeleteIntent(deleteIntent)
// 设置小视图
builder.setCustomContentView(smallRemoteViews)
// 设置悬浮通知视图(Android 12 及以上)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
builder.setCustomHeadsUpContentView(bigRemoteViews)
}
// 设置大视图
builder.setCustomBigContentView(bigRemoteViews)
notificationManager.notify(ConstConfig.NOTIFICATION_ID, builder.build())
}
}
\ No newline at end of file
package com.base.locationsharewhite.service
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.ServiceInfo
import android.graphics.BitmapFactory
import android.graphics.drawable.Icon
import android.os.Build
import android.os.IBinder
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import androidx.core.graphics.drawable.IconCompat
import com.base.locationsharewhite.R
import com.base.locationsharewhite.bean.ConstObject
import com.base.locationsharewhite.helper.config.ConstConfig
import com.base.locationsharewhite.ui.main.MainActivity
import com.base.locationsharewhite.ui.splash.SplashActivity
import kotlin.random.Random
/**
* 常驻通知栏
*/
class StayNotificationService : Service() {
private val TAG = "StayNotificationService"
companion object {
var isRunning = false
fun Context.startStayNotification() {
if (isRunning) return
val intent = Intent(this, StayNotificationService::class.java)
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU) {
return
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
}
fun Context.restartStartStayNotification() {
val intent = Intent(this, StayNotificationService::class.java)
stopService(intent)
startStayNotification()
}
fun createPermanentNotification(context: Context): Notification {
val channelName = "Permanent Foreground Service Channel"
val channelId = "permanent_channel"
val contentView = RemoteViews(context.packageName, R.layout.stay_notification_big)
val expendView = RemoteViews(context.packageName, R.layout.stay_notification_big)
val requestCode1 = Random.nextInt(1800)
val intent1 = Intent(context, SplashActivity::class.java).apply {
putExtra("actionId", ConstConfig.ACTION_STAY_HOME)
}
val pendingIntent1 =
PendingIntent.getActivity(
context,
requestCode1,
intent1,
PendingIntent.FLAG_IMMUTABLE
)
contentView.setOnClickPendingIntent(R.id.ll_1, pendingIntent1)
expendView.setOnClickPendingIntent(R.id.ll_1, pendingIntent1)
val requestCode2 = Random.nextInt(1800)
val intent2 = Intent(context, SplashActivity::class.java).apply {
putExtra("actionId", ConstConfig.ACTION_STAY_MY_CODE)
}
val pendingIntent2 =
PendingIntent.getActivity(
context,
requestCode2,
intent2,
PendingIntent.FLAG_IMMUTABLE
)
contentView.setOnClickPendingIntent(R.id.ll_2, pendingIntent2)
expendView.setOnClickPendingIntent(R.id.ll_2, pendingIntent2)
val requestCode3 = Random.nextInt(1800)
val intent3 = Intent(context, SplashActivity::class.java).apply {
putExtra("actionId", ConstConfig.ACTION_STAY_SHARE)
}
val pendingIntent3 =
PendingIntent.getActivity(
context,
requestCode3,
intent3,
PendingIntent.FLAG_IMMUTABLE
)
contentView.setOnClickPendingIntent(R.id.ll_3, pendingIntent3)
expendView.setOnClickPendingIntent(R.id.ll_3, pendingIntent3)
val requestCode4 = Random.nextInt(1800)
val intent4 = Intent(context, SplashActivity::class.java).apply {
putExtra("actionId", ConstConfig.ACTION_STAY_SETTING)
}
val pendingIntent4 =
PendingIntent.getActivity(
context,
requestCode4,
intent4,
PendingIntent.FLAG_IMMUTABLE
)
contentView.setOnClickPendingIntent(R.id.ll_4, pendingIntent4)
expendView.setOnClickPendingIntent(R.id.ll_4, pendingIntent4)
val builder = NotificationCompat.Builder(context, channelId)
val smallIcon = IconCompat.createFromIcon(
context, Icon.createWithResource(
context, ConstConfig.NOTIFICATION_LOGO
)
)
smallIcon?.let {
builder.setSmallIcon(smallIcon) //设置状态栏内的小图标
}
val nfIntent = Intent(context, MainActivity::class.java)
val pendingIntent =
PendingIntent.getActivity(context, 0, nfIntent, PendingIntent.FLAG_IMMUTABLE)
builder.setLargeIcon(
BitmapFactory.decodeResource(
context.resources,
ConstConfig.NOTIFICATION_LOGO
)
)
builder.setContentTitle(context.resources.getString(R.string.app_name))
builder.setContentIntent(pendingIntent) //设置PendingIntent
builder.setVisibility(NotificationCompat.VISIBILITY_PRIVATE) //设置通知公开可见
builder.setAutoCancel(false)
builder.setOngoing(true)
builder.setPriority(NotificationCompat.PRIORITY_MAX) //优先级为:重要通知
builder.setWhen(System.currentTimeMillis())
builder.setCustomContentView(contentView)
builder.setCustomBigContentView(expendView)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel =
NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW)
channel.lockscreenVisibility = 1
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
builder.setChannelId(channelId)
}
return builder.build()
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
//LogEx.logDebug(TAG, "onStartCommand intent=$intent")
if (intent == null) {
// EventUtils.event("onStartCommand", "Foreground System auto launch intent=null isRunning=$isRunning")
return START_NOT_STICKY
}
if (!isRunning) {
// LogEx.logDebug(TAG, "onStartCommand startForeground")
startForeground()
isRunning = true
}
return START_STICKY
}
private fun startForeground() {
val notification = createPermanentNotification(GoogleSdkMgr.context)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(
ConstConfig.NOTIFICATION_PERMANENT_ID,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
)
} else {
startForeground(ConstConfig.NOTIFICATION_PERMANENT_ID, notification)
}
isRunning = true
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onDestroy() {
isRunning = false
super.onDestroy()
}
}
\ No newline at end of file
......@@ -10,9 +10,9 @@ import com.base.locationsharewhite.ads.AdsShowCallBack
import com.base.locationsharewhite.bean.ConstObject.ifAgreePrivacy
import com.base.locationsharewhite.bean.ConstObject.isFirstLauncher
import com.base.locationsharewhite.databinding.ActivitySplashBinding
import com.base.locationsharewhite.fcm.NotificationHoverUtils
import com.base.locationsharewhite.helper.BaseActivity
import com.base.locationsharewhite.helper.config.ConstConfig
import com.base.locationsharewhite.notification.NotificationHoverUtils
import com.base.locationsharewhite.service.StayNotificationService.Companion.startStayNotification
import com.base.locationsharewhite.ui.howuse.HowUseActivity
import com.base.locationsharewhite.ui.main.LocationCodeActivity
......
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