Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Sign in / Register
Toggle navigation
D
Data Recovery White
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wanglei
Data Recovery White
Commits
21a8c35f
Commit
21a8c35f
authored
Nov 11, 2024
by
wanglei
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
...
parent
f49e49d8
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
435 additions
and
202 deletions
+435
-202
build.gradle
app/build.gradle
+5
-0
AndroidManifest.xml
app/src/main/AndroidManifest.xml
+39
-4
MyApplication.kt
app/src/main/java/com/base/datarecovery/MyApplication.kt
+5
-9
SettingActivity.kt
...in/java/com/base/datarecovery/activity/SettingActivity.kt
+7
-5
Splash2Activity.kt
.../com/base/datarecovery/activity/splash/Splash2Activity.kt
+1
-2
FCMManager.kt
app/src/main/java/com/base/datarecovery/fcm/FCMManager.kt
+54
-37
MessagingService.java
...main/java/com/base/datarecovery/fcm/MessagingService.java
+23
-34
NotificationTimerManager.java
...a/com/base/datarecovery/fcm/NotificationTimerManager.java
+0
-80
AlarmJobReceiver.kt
.../java/com/base/datarecovery/fcm/alarm/AlarmJobReceiver.kt
+34
-0
AlarmUtils.kt
...c/main/java/com/base/datarecovery/fcm/alarm/AlarmUtils.kt
+36
-0
RepeatingWorker.kt
...in/java/com/base/datarecovery/fcm/work/RepeatingWorker.kt
+47
-0
StayJobService.kt
...main/java/com/base/datarecovery/service/StayJobService.kt
+184
-0
InstallHelps.kt
...src/main/java/com/base/datarecovery/utils/InstallHelps.kt
+0
-3
strings.xml
app/src/main/res/values/strings.xml
+0
-28
No files found.
app/build.gradle
View file @
21a8c35f
...
@@ -113,5 +113,10 @@ dependencies {
...
@@ -113,5 +113,10 @@ dependencies {
implementation
'com.google.firebase:firebase-crashlytics'
implementation
'com.google.firebase:firebase-crashlytics'
implementation
(
"com.google.firebase:firebase-messaging"
)
implementation
(
"com.google.firebase:firebase-messaging"
)
implementation
'com.google.firebase:firebase-analytics:21.6.2'
implementation
'com.google.firebase:firebase-analytics:21.6.2'
implementation
(
"com.google.firebase:firebase-messaging-directboot"
)
//work
implementation
(
"androidx.work:work-runtime-ktx:2.7.1"
)
// 请使用最新版本
}
}
\ No newline at end of file
app/src/main/AndroidManifest.xml
View file @
21a8c35f
...
@@ -14,7 +14,6 @@
...
@@ -14,7 +14,6 @@
<uses-permission
android:name=
"android.permission.POST_NOTIFICATIONS"
/>
<uses-permission
android:name=
"android.permission.POST_NOTIFICATIONS"
/>
<uses-permission
android:name=
"android.permission.REQUEST_DELETE_PACKAGES"
/>
<uses-permission
android:name=
"android.permission.REQUEST_DELETE_PACKAGES"
/>
<uses-permission
android:name=
"android.permission.FOREGROUND_SERVICE"
/>
<uses-permission
android:name=
"android.permission.FOREGROUND_SERVICE"
/>
<uses-permission
android:name=
"android.permission.FOREGROUND_SERVICE_DATA_SYNC"
/>
<uses-permission
android:name=
"android.permission.FOREGROUND_SERVICE_DATA_SYNC"
/>
<queries>
<queries>
...
@@ -257,14 +256,20 @@
...
@@ -257,14 +256,20 @@
android:value=
"false"
/>
android:value=
"false"
/>
<!-- 常驻通知栏 -->
<!-- 常驻通知栏 -->
<!-- <service-->
<!-- android:name=".service.StayNotificationService"-->
<!-- android:foregroundServiceType="dataSync"-->
<!-- android:permission="android.permission.FOREGROUND_SERVICE" />-->
<service
<service
android:name=
".service.StayNotificationService"
android:name=
".service.StayJobService"
android:exported=
"false"
android:foregroundServiceType=
"dataSync"
android:foregroundServiceType=
"dataSync"
android:permission=
"android.permission.FOREGROUND_SERVICE"
/>
android:permission=
"android.permission.BIND_JOB_SERVICE"
/>
<service
<service
android:name=
".fcm.MessagingService"
android:name=
".fcm.MessagingService"
android:exported=
"
tru
e"
>
android:exported=
"
fals
e"
>
<intent-filter>
<intent-filter>
<action
android:name=
"com.google.firebase.MESSAGING_EVENT"
/>
<action
android:name=
"com.google.firebase.MESSAGING_EVENT"
/>
</intent-filter>
</intent-filter>
...
@@ -288,6 +293,36 @@
...
@@ -288,6 +293,36 @@
</intent-filter>
</intent-filter>
</receiver>
</receiver>
<receiver
android:name=
".fcm.alarm.AlarmJobReceiver"
android:enabled=
"true"
android:exported=
"true"
android:permission=
"android.permission.RECEIVE_BOOT_COMPLETED"
>
<intent-filter>
<action
android:name=
"android.intent.action.USER_PRESENT"
/>
<action
android:name=
"android.intent.action.BOOT_COMPLETED"
/>
<action
android:name=
"android.intent.action.ACTION_POWER_CONNECTED"
/>
<action
android:name=
"android.intent.action.ACTION_POWER_DISCONNECTED"
/>
</intent-filter>
<intent-filter>
<action
android:name=
"android.intent.action.PACKAGE_ADDED"
/>
<action
android:name=
"android.intent.action.PACKAGE_REMOVED"
/>
<action
android:name=
"android.intent.action.PACKAGE_REPLACED"
/>
<data
android:scheme=
"package"
/>
</intent-filter>
<intent-filter>
<action
android:name=
"android.net.wifi.WIFI_STATE_CHANGED"
/>
<action
android:name=
"android.net.wifi.STATE_CHANGE"
/>
</intent-filter>
<intent-filter>
<action
android:name=
"android.intent.action.MEDIA_EJECT"
/>
<action
android:name=
"android.intent.action.MEDIA_MOUNTED"
/>
<data
android:scheme=
"file"
/>
</intent-filter>
</receiver>
<meta-data
<meta-data
android:name=
"com.google.android.gms.ads.APPLICATION_ID"
android:name=
"com.google.android.gms.ads.APPLICATION_ID"
android:value=
"ca-app-pub-3940256099942544~3347511713"
/>
android:value=
"ca-app-pub-3940256099942544~3347511713"
/>
...
...
app/src/main/java/com/base/datarecovery/MyApplication.kt
View file @
21a8c35f
...
@@ -8,11 +8,13 @@ import android.text.TextUtils
...
@@ -8,11 +8,13 @@ import android.text.TextUtils
import
com.base.datarecovery.activity.splash.Splash2Activity
import
com.base.datarecovery.activity.splash.Splash2Activity
import
com.base.datarecovery.ads.AdmobMaxHelper
import
com.base.datarecovery.ads.AdmobMaxHelper
import
com.base.datarecovery.bean.ConstObject.ifAgreePrivacy
import
com.base.datarecovery.bean.ConstObject.ifAgreePrivacy
import
com.base.datarecovery.fcm.alarm.AlarmUtils.startAlarm
import
com.base.datarecovery.fcm.FCMManager
import
com.base.datarecovery.fcm.FCMManager
import
com.base.datarecovery.fcm.ScreenStatusReceiver
import
com.base.datarecovery.fcm.ScreenStatusReceiver
import
com.base.datarecovery.help.BaseApplication
import
com.base.datarecovery.help.BaseApplication
import
com.base.datarecovery.help.BlackUtils
import
com.base.datarecovery.help.BlackUtils
import
com.base.datarecovery.help.ConfigHelper
import
com.base.datarecovery.help.ConfigHelper
import
com.base.datarecovery.service.StayJobService.Companion.startJob
import
com.base.datarecovery.utils.ActivityManagerUtils
import
com.base.datarecovery.utils.ActivityManagerUtils
import
com.base.datarecovery.utils.AppPreferences
import
com.base.datarecovery.utils.AppPreferences
import
com.base.datarecovery.utils.InstallHelps
import
com.base.datarecovery.utils.InstallHelps
...
@@ -64,6 +66,8 @@ class MyApplication : BaseApplication() {
...
@@ -64,6 +66,8 @@ class MyApplication : BaseApplication() {
InstallHelps
.
init
()
InstallHelps
.
init
()
BlackUtils
.
requestBlack
()
BlackUtils
.
requestBlack
()
initLifeListener
()
initLifeListener
()
startJob
()
startAlarm
(
context
)
}
}
if
(
ifAgreePrivacy
)
{
if
(
ifAgreePrivacy
)
{
...
@@ -126,15 +130,7 @@ class MyApplication : BaseApplication() {
...
@@ -126,15 +130,7 @@ class MyApplication : BaseApplication() {
if
(
flag
&&
!
isInterOpenShowing
)
{
if
(
flag
&&
!
isInterOpenShowing
)
{
if
(
AdmobMaxHelper
.
isOpenAdLoaded
())
{
if
(
AdmobMaxHelper
.
isOpenAdLoaded
())
{
// var loaded: Boolean = true
// AdmobMaxHelper.admobMaxShowOpenAd(activity, {
// loaded = it
// }, {
// val sp = AppPreferences.getInstance().getString("splashShowInter", "0").toInt()
// if (sp == 1 && !loaded) {
// AdmobMaxHelper.admobMaxShowInterstitialAd(activity)
// }
// })
topActivity
?.
startActivity
(
topActivity
?.
startActivity
(
Intent
(
Intent
(
topActivity
,
topActivity
,
...
...
app/src/main/java/com/base/datarecovery/activity/SettingActivity.kt
View file @
21a8c35f
...
@@ -11,8 +11,8 @@ import com.base.datarecovery.fcm.FCMManager.subscribeToTopic
...
@@ -11,8 +11,8 @@ import com.base.datarecovery.fcm.FCMManager.subscribeToTopic
import
com.base.datarecovery.fcm.FCMManager.unsubscribeFromTopic
import
com.base.datarecovery.fcm.FCMManager.unsubscribeFromTopic
import
com.base.datarecovery.help.BaseActivity
import
com.base.datarecovery.help.BaseActivity
import
com.base.datarecovery.help.ConfigHelper
import
com.base.datarecovery.help.ConfigHelper
import
com.base.datarecovery.service.Stay
Notification
Service
import
com.base.datarecovery.service.Stay
Job
Service
import
com.base.datarecovery.service.Stay
NotificationService.Companion.startStayNotification
import
com.base.datarecovery.service.Stay
JobService.Companion.startJob
import
com.base.datarecovery.utils.BarUtils
import
com.base.datarecovery.utils.BarUtils
import
com.base.datarecovery.view.RateStarPop.showRateStarPopDialog
import
com.base.datarecovery.view.RateStarPop.showRateStarPopDialog
...
@@ -41,10 +41,12 @@ class SettingActivity : BaseActivity<ActivitySettingBinding>() {
...
@@ -41,10 +41,12 @@ class SettingActivity : BaseActivity<ActivitySettingBinding>() {
binding
.
switchStayNotification
.
setOnCheckedChangeListener
{
buttonView
,
isChecked
->
binding
.
switchStayNotification
.
setOnCheckedChangeListener
{
buttonView
,
isChecked
->
stayNotification
=
isChecked
stayNotification
=
isChecked
if
(
isChecked
)
{
if
(
isChecked
)
{
startStayNotification
()
// startStayNotification()
startJob
()
}
else
{
}
else
{
val
serviceIntent
=
Intent
(
this
,
StayNotificationService
::
class
.
java
)
// val serviceIntent = Intent(this, StayNotificationService::class.java)
stopService
(
serviceIntent
)
// stopService(serviceIntent)
StayJobService
.
isCancel
=
true
}
}
}
}
binding
.
switchFcmNotification
.
setOnCheckedChangeListener
{
buttonView
,
isChecked
->
binding
.
switchFcmNotification
.
setOnCheckedChangeListener
{
buttonView
,
isChecked
->
...
...
app/src/main/java/com/base/datarecovery/activity/splash/Splash2Activity.kt
View file @
21a8c35f
...
@@ -15,7 +15,6 @@ import com.base.datarecovery.databinding.ActivitySplashBinding
...
@@ -15,7 +15,6 @@ import com.base.datarecovery.databinding.ActivitySplashBinding
import
com.base.datarecovery.fcm.CloseNotificationReceiver
import
com.base.datarecovery.fcm.CloseNotificationReceiver
import
com.base.datarecovery.fcm.NotificationUtil
import
com.base.datarecovery.fcm.NotificationUtil
import
com.base.datarecovery.help.BaseActivity
import
com.base.datarecovery.help.BaseActivity
import
com.base.datarecovery.service.StayNotificationService.Companion.startStayNotification
import
com.base.datarecovery.utils.BarUtils
import
com.base.datarecovery.utils.BarUtils
import
com.base.datarecovery.utils.EventUtils
import
com.base.datarecovery.utils.EventUtils
...
@@ -80,7 +79,7 @@ class Splash2Activity : BaseActivity<ActivitySplashBinding>(),
...
@@ -80,7 +79,7 @@ class Splash2Activity : BaseActivity<ActivitySplashBinding>(),
override
fun
onAgreePrivacy
()
{
override
fun
onAgreePrivacy
()
{
EventUtils
.
event
(
"app_start"
)
EventUtils
.
event
(
"app_start"
)
if
(
jumpType
==
0
)
{
if
(
jumpType
==
0
)
{
startStayNotification
()
//
startStayNotification()
}
}
AdmobMaxHelper
.
preloadAd
(
this
)
AdmobMaxHelper
.
preloadAd
(
this
)
mTaskManager
?.
startProgress
()
mTaskManager
?.
startProgress
()
...
...
app/src/main/java/com/base/datarecovery/fcm/FCMManager.kt
View file @
21a8c35f
package
com.base.datarecovery.fcm
;
package
com.base.datarecovery.fcm
import
android.content.Context;
import
android.content.Context
import
android.util.Log;
import
android.util.Log
import
com.base.datarecovery.utils.AppPreferences
import
com.base.datarecovery.utils.EventUtils.event
import
com.base.datarecovery.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
import
androidx.annotation.NonNull;
object
FCMManager
{
fun
initFirebase
(
context
:
Context
?)
{
import
com.base.datarecovery.utils.EventUtils;
FirebaseApp
.
initializeApp
(
context
!!
)
import
com.google.android.gms.tasks.OnCompleteListener;
getToken
()
import
com.google.android.gms.tasks.Task;
import
com.google.firebase.FirebaseApp;
import
com.google.firebase.messaging.FirebaseMessaging;
public
class
FCMManager
{
public
static
void
initFirebase
(
Context
context
)
{
FirebaseApp
.
initializeApp
(
context
);
}
}
public
static
void
subscribeToTopic
(
String
topic
)
{
fun
subscribeToTopic
(
topic
:
String
)
{
FirebaseMessaging
.
getInstance
().
subscribeToTopic
(
topic
)
FirebaseMessaging
.
getInstance
().
subscribeToTopic
(
topic
)
.
addOnCompleteListener
(
new
OnCompleteListener
<
Void
>()
{
.
addOnCompleteListener
{
task
->
@Override
if
(
task
.
isSuccessful
)
{
public
void
onComplete
(
@NonNull
Task
<
Void
>
task
)
{
getToken
()
if
(
task
.
isSuccessful
())
{
Log
.
d
(
"FCMUtil"
,
"suc:$topic"
)
Log
.
d
(
"FCMUtil"
,
"suc:"
+
topic
);
event
(
"FCM_Topic_$topic"
,
null
,
null
,
false
)
EventUtils
.
INSTANCE
.
event
(
"FCM_Topic_"
+
topic
,
null
,
null
,
false
);
}
else
{
}
else
{
Log
.
d
(
"FCMUtil"
,
"fail"
);
Log
.
d
(
"FCMUtil"
,
"fail"
)
}
}
}
}
});
}
}
public
static
void
unsubscribeFromTopic
(
String
topic
)
{
fun
unsubscribeFromTopic
(
topic
:
String
?)
{
FirebaseMessaging
.
getInstance
().
unsubscribeFromTopic
(
topic
)
FirebaseMessaging
.
getInstance
().
unsubscribeFromTopic
(
topic
!!
)
.
addOnCompleteListener
(
new
OnCompleteListener
<
Void
>()
{
.
addOnCompleteListener
{
task
->
@Override
if
(
task
.
isSuccessful
)
{
public
void
onComplete
(
@NonNull
Task
<
Void
>
task
)
{
if
(
task
.
isSuccessful
())
{
}
else
{
}
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
)
event
(
"fcm_message_received"
,
ext
=
json
)
AppPreferences
.
getInstance
().
put
(
"token"
,
token
)
// Handle new token
Log
.
d
(
"FCM"
,
"FCM Registration Token: $token"
)
}
})
}
}
}
app/src/main/java/com/base/datarecovery/fcm/MessagingService.java
View file @
21a8c35f
package
com
.
base
.
datarecovery
.
fcm
;
package
com
.
base
.
datarecovery
.
fcm
;
import
android.annotation.SuppressLint
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.NonNull
;
import
com.base.datarecovery.MyApplication
;
import
com.base.datarecovery.MyApplication
;
import
com.base.datarecovery.utils.AppPreferences
;
import
com.base.datarecovery.utils.EventUtils
;
import
com.base.datarecovery.utils.EventUtils
;
import
com.base.datarecovery.utils.LogEx
;
import
com.google.firebase.messaging.FirebaseMessagingService
;
import
com.google.firebase.messaging.FirebaseMessagingService
;
import
com.google.firebase.messaging.RemoteMessage
;
import
com.google.firebase.messaging.RemoteMessage
;
import
java.util.Map
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
@SuppressLint
(
"MissingFirebaseInstanceTokenRefresh"
)
public
class
MessagingService
extends
FirebaseMessagingService
{
public
class
MessagingService
extends
FirebaseMessagingService
{
private
static
final
String
TAG
=
"MessagingService"
;
private
static
final
String
TAG
=
"MessagingService"
;
...
@@ -18,44 +21,30 @@ public class MessagingService extends FirebaseMessagingService {
...
@@ -18,44 +21,30 @@ public class MessagingService extends FirebaseMessagingService {
@Override
@Override
public
void
onMessageReceived
(
@NonNull
RemoteMessage
remoteMessage
)
{
public
void
onMessageReceived
(
@NonNull
RemoteMessage
remoteMessage
)
{
super
.
onMessageReceived
(
remoteMessage
);
super
.
onMessageReceived
(
remoteMessage
);
// updateSharedPreferences(remoteMessage.getData());
// manageTimerBasedOnMessage(remoteMessage.getData());
LogEx
.
INSTANCE
.
logDebug
(
TAG
,
"onMessageReceived"
,
false
);
EventUtils
.
INSTANCE
.
event
(
"FCM_Received"
,
null
,
null
,
false
);
sendLocalNotification
();
}
private
void
updateSharedPreferences
(
@NonNull
Map
<
String
,
String
>
data
)
{
for
(
Map
.
Entry
<
String
,
String
>
entry
:
data
.
entrySet
())
{
String
key
=
entry
.
getKey
();
String
value
=
entry
.
getValue
();
// 对于整型值使用parseInt, 长整型使用parseLong
AppPreferences
.
getInstance
().
put
(
key
,
value
);
}
}
String
id
=
remoteMessage
.
getMessageId
();
JSONObject
ext
=
new
JSONObject
();
private
void
manageTimerBasedOnMessage
(
@NonNull
Map
<
String
,
String
>
data
)
{
try
{
int
timerStatus
=
getIntValue
(
data
,
"timerS"
,
1
);
ext
.
put
(
"getMessageType"
,
remoteMessage
.
getMessageType
());
if
(
timerStatus
==
0
)
{
ext
.
put
(
"getData"
,
remoteMessage
.
getData
());
RecoveryTimerManager
.
getInstance
().
stopTaskTimer
();
ext
.
put
(
"getCollapseKey"
,
remoteMessage
.
getCollapseKey
());
}
else
{
ext
.
put
(
"getFrom"
,
remoteMessage
.
getFrom
());
int
timerDelay
=
getIntValue
(
data
,
"timerDelay"
,
1
);
ext
.
put
(
"getPriority"
,
remoteMessage
.
getPriority
());
int
timerInterval
=
getIntValue
(
data
,
"timerInterval"
,
5
);
ext
.
put
(
"getSenderId"
,
remoteMessage
.
getSenderId
());
if
(!
RecoveryTimerManager
.
getInstance
().
isTaskTimerActive
())
{
ext
.
put
(
"getSentTime"
,
remoteMessage
.
getSentTime
());
RecoveryTimerManager
.
getInstance
().
scheduleTask
(
timerDelay
*
60000
,
timerInterval
*
60000
);
}
catch
(
JSONException
e
)
{
}
EventUtils
.
INSTANCE
.
event
(
"FCM_Received_Error"
,
id
,
ext
,
false
);
}
throw
new
RuntimeException
(
e
);
}
}
finally
{
}
EventUtils
.
INSTANCE
.
event
(
"FCM_Received"
,
id
,
ext
,
false
);
private
int
getIntValue
(
@NonNull
Map
<
String
,
String
>
data
,
String
key
,
int
defaultValue
)
{
sendLocalNotification
();
String
value
=
data
.
get
(
key
);
return
value
!=
null
?
Integer
.
parseInt
(
value
)
:
defaultValue
;
}
}
// Consider implementing this method if local notifications are needed
// Consider implementing this method if local notifications are needed
private
void
sendLocalNotification
()
{
private
void
sendLocalNotification
()
{
NotificationUtil
.
INSTANCE
.
sendNotification
(
MyApplication
.
context
,
"MessagingService"
);
NotificationUtil
.
INSTANCE
.
sendNotification
(
MyApplication
.
context
,
"MessagingService"
);
}
}
}
}
\ No newline at end of file
app/src/main/java/com/base/datarecovery/fcm/NotificationTimerManager.java
deleted
100644 → 0
View file @
f49e49d8
package
com
.
base
.
datarecovery
.
fcm
;
import
android.Manifest
;
import
android.app.Notification
;
import
android.content.pm.PackageManager
;
import
androidx.core.app.ActivityCompat
;
import
androidx.core.app.NotificationManagerCompat
;
import
com.base.datarecovery.MyApplication
;
import
com.base.datarecovery.help.BaseApplication
;
import
com.base.datarecovery.service.StayNotificationService
;
import
java.util.Timer
;
import
java.util.TimerTask
;
public
class
NotificationTimerManager
{
private
static
NotificationTimerManager
instance
;
private
Timer
timer
;
private
boolean
isTimerRunning
;
private
TimerTask
timerTask
;
private
NotificationTimerManager
()
{
isTimerRunning
=
false
;
}
public
static
synchronized
NotificationTimerManager
getInstance
()
{
if
(
instance
==
null
)
{
instance
=
new
NotificationTimerManager
();
}
return
instance
;
}
public
void
startTimer
(
long
initialDelay
,
long
intervalPeriod
)
{
synchronized
(
this
)
{
// 使用 synchronized 确保线程安全
if
(!
isTimerRunning
)
{
cancelExistingTimer
();
// 取消现有的定时器和任务
// 创建新的 TimerTask 实例并调度
timer
=
new
Timer
();
timerTask
=
new
TimerTask
()
{
@Override
public
void
run
()
{
Notification
notification
=
StayNotificationService
.
Companion
.
createPermanentNotification
(
MyApplication
.
context
);
NotificationManagerCompat
notificationManager
=
NotificationManagerCompat
.
from
(
MyApplication
.
context
);
if
(
ActivityCompat
.
checkSelfPermission
(
MyApplication
.
context
,
Manifest
.
permission
.
POST_NOTIFICATIONS
)
!=
PackageManager
.
PERMISSION_GRANTED
)
{
return
;
}
notificationManager
.
notify
(
1
,
notification
);
}
};
timer
.
schedule
(
timerTask
,
initialDelay
,
intervalPeriod
);
isTimerRunning
=
true
;
}
}
}
public
void
stopTimer
()
{
synchronized
(
this
)
{
// 使用 synchronized 确保线程安全
if
(
isTimerRunning
)
{
cancelExistingTimer
();
isTimerRunning
=
false
;
}
}
}
private
void
cancelExistingTimer
()
{
if
(
timerTask
!=
null
)
{
timerTask
.
cancel
();
}
if
(
timer
!=
null
)
{
timer
.
cancel
();
timer
.
purge
();
}
}
public
boolean
isTimerRunning
()
{
return
isTimerRunning
;
}
}
\ No newline at end of file
app/src/main/java/com/base/datarecovery/fcm/alarm/AlarmJobReceiver.kt
0 → 100644
View file @
21a8c35f
package
com.base.datarecovery.fcm.alarm
import
android.annotation.SuppressLint
import
android.content.BroadcastReceiver
import
android.content.Context
import
android.content.Intent
import
com.base.datarecovery.BuildConfig
import
com.base.datarecovery.fcm.NotificationUtil
import
com.base.datarecovery.utils.AppPreferences
import
com.base.datarecovery.utils.EventUtils
import
com.base.datarecovery.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
)
{
NotificationUtil
.
sendNotification
(
context
,
"alarm"
);
}
}
AppPreferences
.
getInstance
().
put
(
"firstAlemtime"
,
System
.
currentTimeMillis
())
return
}
}
\ No newline at end of file
app/src/main/java/com/base/datarecovery/fcm/alarm/AlarmUtils.kt
0 → 100644
View file @
21a8c35f
package
com.base.datarecovery.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.datarecovery.BuildConfig
import
com.base.datarecovery.fcm.work.RepeatingWorker.Companion.schedulePeriodicWork
import
com.base.datarecovery.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
=
5000L
}
alarmManager
.
setRepeating
(
AlarmManager
.
RTC_WAKEUP
,
calendar
.
timeInMillis
,
delay
,
pendingIntent
)
schedulePeriodicWork
(
context
)
}
}
\ No newline at end of file
app/src/main/java/com/base/datarecovery/fcm/work/RepeatingWorker.kt
0 → 100644
View file @
21a8c35f
package
com.base.datarecovery.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.datarecovery.fcm.NotificationUtil
import
com.base.datarecovery.utils.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
{
NotificationUtil
.
sendNotification
(
appContext
,
"WorkManager"
);
}
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
app/src/main/java/com/base/datarecovery/service/StayJobService.kt
0 → 100644
View file @
21a8c35f
package
com.base.datarecovery.service
import
android.app.Notification
import
android.app.NotificationChannel
import
android.app.NotificationManager
import
android.app.PendingIntent
import
android.app.job.JobInfo
import
android.app.job.JobParameters
import
android.app.job.JobScheduler
import
android.app.job.JobService
import
android.content.ComponentName
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.CountDownTimer
import
android.widget.RemoteViews
import
androidx.core.app.NotificationCompat
import
androidx.core.graphics.drawable.IconCompat
import
androidx.work.Configuration
import
com.base.datarecovery.R
import
com.base.datarecovery.activity.MainActivity
import
com.base.datarecovery.utils.LogEx
/**
* 常驻通知栏
*/
class
StayJobService
:
JobService
()
{
init
{
val
builder
=
Configuration
.
Builder
()
builder
.
setJobSchedulerJobIdRange
(
0
,
1000
)
}
private
val
TAG
=
"StayJobService"
val
channelName
=
"Photo Recovery Foreground Service Channel"
val
channelId
=
"Photo_Recovery_Service_Id"
private
val
NOTIFICATION_PERMANENT_ID
=
199
companion
object
{
var
isRunning
=
false
private
const
val
JOB_INFO_ID
:
Int
=
101
private
const
val
JOB_PERIODIC
:
Long
=
5
*
1000L
fun
Context
.
startJob
()
{
isCancel
=
false
if
(
isRunning
)
return
val
jobScheduler
=
getSystemService
(
JOB_SCHEDULER_SERVICE
)
as
JobScheduler
val
componentName
=
ComponentName
(
this
,
StayJobService
::
class
.
java
)
val
jobInfo
=
JobInfo
.
Builder
(
JOB_INFO_ID
,
componentName
)
.
setMinimumLatency
(
30000
)
.
build
()
jobScheduler
.
schedule
(
jobInfo
)
}
var
isCancel
:
Boolean
=
false
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
builder
=
NotificationCompat
.
Builder
(
context
,
channelId
)
val
smallIcon
=
IconCompat
.
createFromIcon
(
context
,
Icon
.
createWithResource
(
context
,
R
.
mipmap
.
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
,
R
.
mipmap
.
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_HIGH
)
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
{
return
super
.
onStartCommand
(
intent
,
flags
,
startId
)
}
private
fun
startForeground
()
{
val
notification
=
createPermanentNotification
(
applicationContext
)
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
Q
)
{
startForeground
(
NOTIFICATION_PERMANENT_ID
,
notification
,
ServiceInfo
.
FOREGROUND_SERVICE_TYPE_DATA_SYNC
)
}
else
{
startForeground
(
NOTIFICATION_PERMANENT_ID
,
notification
)
}
isRunning
=
true
}
private
fun
notifyForeground
()
{
val
notificationManager
=
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
notificationManager
.
notify
(
NOTIFICATION_PERMANENT_ID
,
createPermanentNotification
(
applicationContext
)
)
}
override
fun
onDestroy
()
{
isRunning
=
false
super
.
onDestroy
()
}
override
fun
onCreate
()
{
LogEx
.
logDebug
(
TAG
,
"onCreate isRunning=$isRunning"
)
if
(!
isRunning
)
{
isRunning
=
true
startForeground
()
Timer
().
start
()
}
super
.
onCreate
()
}
override
fun
onStartJob
(
params
:
JobParameters
?):
Boolean
{
return
true
}
override
fun
onStopJob
(
params
:
JobParameters
?):
Boolean
{
return
false
}
private
inner
class
Timer
()
:
CountDownTimer
(
30000
,
1000
)
{
override
fun
onTick
(
millisUntilFinished
:
Long
)
{
}
override
fun
onFinish
()
{
if
(!
isCancel
)
{
notifyForeground
()
Timer
().
start
()
}
}
}
}
app/src/main/java/com/base/datarecovery/utils/InstallHelps.kt
View file @
21a8c35f
package
com.base.datarecovery.utils
package
com.base.datarecovery.utils
import
android.os.Build
import
android.os.Build
import
android.text.TextUtils
import
androidx.annotation.RequiresApi
import
com.android.installreferrer.api.InstallReferrerClient
import
com.android.installreferrer.api.InstallReferrerClient
import
com.android.installreferrer.api.InstallReferrerStateListener
import
com.android.installreferrer.api.InstallReferrerStateListener
import
com.base.datarecovery.BuildConfig
import
com.base.datarecovery.BuildConfig
import
com.base.datarecovery.ads.AdmobMaxHelper
import
com.base.datarecovery.ads.AdmobMaxHelper
import
com.base.datarecovery.fcm.NotificationTimerManager
import
com.base.datarecovery.fcm.RecoveryTimerManager
import
com.base.datarecovery.fcm.RecoveryTimerManager
import
com.base.datarecovery.help.BaseApplication
import
com.base.datarecovery.help.BaseApplication
import
org.json.JSONObject
import
org.json.JSONObject
...
...
app/src/main/res/values/strings.xml
View file @
21a8c35f
<resources>
<resources>
<string
name=
"app_name"
>
Cleaner Junk: Recovery, Privacy
</string>
<string
name=
"app_name"
>
Cleaner Junk: Recovery, Privacy
</string>
<!-- TODO: Remove or change this placeholder text -->
<string
name=
"hello_blank_fragment"
>
Hello blank fragment
</string>
<string
name=
"hello_blank_fragment"
>
Hello blank fragment
</string>
<string
name=
"facebook_app_id"
>
1141667540450666
</string>
<string
name=
"facebook_app_id"
>
1141667540450666
</string>
<!-- Strings used for fragments for navigation -->
<!-- Strings used for fragments for navigation -->
...
@@ -9,31 +8,4 @@
...
@@ -9,31 +8,4 @@
<string
name=
"next"
>
Next
</string>
<string
name=
"next"
>
Next
</string>
<string
name=
"previous"
>
Previous
</string>
<string
name=
"previous"
>
Previous
</string>
<string
name=
"lorem_ipsum"
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam in scelerisque sem. Mauris volutpat, dolor id interdum
ullamcorper, risus dolor egestas lectus, sit amet mattis purus dui nec risus. Maecenas non sodales nisi, vel dictum dolor.
Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Suspendisse blandit eleifend diam,
vel rutrum tellus vulputate quis. Aliquam eget libero aliquet, imperdiet nisl a, ornare ex. Sed rhoncus est ut libero porta
lobortis. Fusce in dictum tellus.\n\n
Suspendisse interdum ornare ante. Aliquam nec cursus lorem. Morbi id magna felis. Vivamus egestas, est a condimentum egestas,
turpis nisl iaculis ipsum, in dictum tellus dolor sed neque. Morbi tellus erat, dapibus ut sem a, iaculis tincidunt dui.
Interdum et malesuada fames ac ante ipsum primis in faucibus. Curabitur et eros porttitor, ultricies urna vitae, molestie nibh.
Phasellus at commodo eros, non aliquet metus. Sed maximus nisl nec dolor bibendum, vel congue leo egestas.\n\n
Sed interdum tortor nibh, in sagittis risus mollis quis. Curabitur mi odio, condimentum sit amet auctor at, mollis non turpis.
Nullam pretium libero vestibulum, finibus orci vel, molestie quam. Fusce blandit tincidunt nulla, quis sollicitudin libero
facilisis et. Integer interdum nunc ligula, et fermentum metus hendrerit id. Vestibulum lectus felis, dictum at lacinia sit
amet, tristique id quam. Cras eu consequat dui. Suspendisse sodales nunc ligula, in lobortis sem porta sed. Integer id ultrices
magna, in luctus elit. Sed a pellentesque est.\n\n
Aenean nunc velit, lacinia sed dolor sed, ultrices viverra nulla. Etiam a venenatis nibh. Morbi laoreet, tortor sed facilisis
varius, nibh orci rhoncus nulla, id elementum leo dui non lorem. Nam mollis ipsum quis auctor varius. Quisque elementum eu
libero sed commodo. In eros nisl, imperdiet vel imperdiet et, scelerisque a mauris. Pellentesque varius ex nunc, quis imperdiet
eros placerat ac. Duis finibus orci et est auctor tincidunt. Sed non viverra ipsum. Nunc quis augue egestas, cursus lorem at,
molestie sem. Morbi a consectetur ipsum, a placerat diam. Etiam vulputate dignissim convallis. Integer faucibus mauris sit amet
finibus convallis.\n\n
Phasellus in aliquet mi. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In
volutpat arcu ut felis sagittis, in finibus massa gravida. Pellentesque id tellus orci. Integer dictum, lorem sed efficitur
ullamcorper, libero justo consectetur ipsum, in mollis nisl ex sed nisl. Donec maximus ullamcorper sodales. Praesent bibendum
rhoncus tellus nec feugiat. In a ornare nulla. Donec rhoncus libero vel nunc consequat, quis tincidunt nisl eleifend. Cras
bibendum enim a justo luctus vestibulum. Fusce dictum libero quis erat maximus, vitae volutpat diam dignissim.
</string>
</resources>
</resources>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment