Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Sign in / Register
Toggle navigation
F
File Recovery RecycleBin
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
File Recovery RecycleBin
Commits
83fae7df
Commit
83fae7df
authored
Jul 26, 2024
by
wanglei
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
....
parent
2beef962
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
685 additions
and
619 deletions
+685
-619
build.gradle
app/build.gradle
+2
-1
AndroidManifest.xml
app/src/main/AndroidManifest.xml
+0
-3
MyApplication.kt
...ain/java/com/base/filerecoveryrecyclebin/MyApplication.kt
+0
-3
RepeatActivity.kt
.../filerecoveryrecyclebin/activity/repeat/RepeatActivity.kt
+0
-3
AdDisplayUtils.java
...a/com/base/filerecoveryrecyclebin/ads/AdDisplayUtils.java
+158
-91
AdmobMaxHelper.kt
...ava/com/base/filerecoveryrecyclebin/ads/AdmobMaxHelper.kt
+3
-1
AdMaxInterstitialUtils.kt
.../filerecoveryrecyclebin/ads/max/AdMaxInterstitialUtils.kt
+1
-0
AdMaxOpenUtils.kt
...com/base/filerecoveryrecyclebin/ads/max/AdMaxOpenUtils.kt
+1
-0
BillingActivity.kt
...om/base/filerecoveryrecyclebin/billing/BillingActivity.kt
+17
-17
BillingClientLifecycle.kt
.../filerecoveryrecyclebin/billing/BillingClientLifecycle.kt
+269
-269
BillingUtilities.kt
...m/base/filerecoveryrecyclebin/billing/BillingUtilities.kt
+170
-170
BillingViewModel.kt
...m/base/filerecoveryrecyclebin/billing/BillingViewModel.kt
+49
-49
MessagingService.java
...com/base/filerecoveryrecyclebin/fcm/MessagingService.java
+2
-3
NewComUtils.kt
...java/com/base/filerecoveryrecyclebin/utils/NewComUtils.kt
+9
-5
build.gradle
build.gradle
+2
-2
libs.versions.toml
gradle/libs.versions.toml
+1
-1
gradle-wrapper.properties
gradle/wrapper/gradle-wrapper.properties
+1
-1
No files found.
app/build.gradle
View file @
83fae7df
...
...
@@ -107,8 +107,9 @@ dependencies {
//firebase
implementation
platform
(
'com.google.firebase:firebase-bom:32.3.1'
)
implementation
'com.google.firebase:firebase-analytics:21.6.2'
implementation
(
"com.google.firebase:firebase-messaging"
)
implementation
'com.google.firebase:firebase-crashlytics'
implementation
'com.google.firebase:firebase-analytics:21.6.2'
//google 内购订阅
...
...
app/src/main/AndroidManifest.xml
View file @
83fae7df
...
...
@@ -25,9 +25,6 @@
android:supportsRtl=
"true"
android:theme=
"@style/Theme.DataRecovery"
tools:targetApi=
"34"
>
<activity
android:name=
".billing.BillingActivity"
android:exported=
"false"
/>
<activity
android:name=
".activity.SplashActivity"
android:exported=
"true"
...
...
app/src/main/java/com/base/filerecoveryrecyclebin/MyApplication.kt
View file @
83fae7df
...
...
@@ -9,7 +9,6 @@ import com.base.filerecoveryrecyclebin.activity.SplashActivity
import
com.base.filerecoveryrecyclebin.ads.AdmobMaxHelper
import
com.base.filerecoveryrecyclebin.ads.admob.AdmobOpenUtils
import
com.base.filerecoveryrecyclebin.bean.ConstObject.ifAgreePrivacy
import
com.base.filerecoveryrecyclebin.billing.BillingClientLifecycle
import
com.base.filerecoveryrecyclebin.fcm.FCMManager
import
com.base.filerecoveryrecyclebin.fcm.RecoveryTimerManager
import
com.base.filerecoveryrecyclebin.fcm.ScreenStatusReceiver
...
...
@@ -32,8 +31,6 @@ class MyApplication : BaseApplication() {
private
val
TAG
=
"MyApplication"
var
uuid
=
""
val
billingClientLifecycle
:
BillingClientLifecycle
get
()
=
BillingClientLifecycle
.
getInstance
(
this
)
companion
object
{
@JvmField
...
...
app/src/main/java/com/base/filerecoveryrecyclebin/activity/repeat/RepeatActivity.kt
View file @
83fae7df
...
...
@@ -7,10 +7,7 @@ import androidx.core.view.updatePadding
import
androidx.lifecycle.lifecycleScope
import
com.base.filerecoveryrecyclebin.adapter.MediaAdapter
import
com.base.filerecoveryrecyclebin.ads.AdmobMaxHelper
import
com.base.filerecoveryrecyclebin.ads.admob.AdmobInterstitialUtils
import
com.base.filerecoveryrecyclebin.ads.admob.AdmobInterstitialUtils.showInterAdSp
import
com.base.filerecoveryrecyclebin.ads.admob.AdmobNativeUtils
import
com.base.filerecoveryrecyclebin.ads.max.AdMaxInterstitialUtils
import
com.base.filerecoveryrecyclebin.bean.MediaBean
import
com.base.filerecoveryrecyclebin.bean.MediaTimeBean
import
com.base.filerecoveryrecyclebin.databinding.ActivityRepeatBinding
...
...
app/src/main/java/com/base/filerecoveryrecyclebin/ads/AdDisplayUtils.java
View file @
83fae7df
...
...
@@ -6,6 +6,7 @@ import android.util.Log;
import
com.base.filerecoveryrecyclebin.BuildConfig
;
import
com.base.filerecoveryrecyclebin.help.BaseApplication
;
import
com.base.filerecoveryrecyclebin.utils.AppPreferences
;
import
com.base.filerecoveryrecyclebin.utils.EventUtils
;
import
com.base.filerecoveryrecyclebin.utils.LogEx
;
...
...
@@ -18,37 +19,47 @@ import java.util.Date;
import
java.util.Locale
;
public
class
AdDisplayUtils
{
private
static
final
int
DEFAULT_MAX_AD_DISPLAY_COUNT
=
45
;
// 总广告展示次数限制默认值
private
static
final
int
DEFAULT_MAX_AD_CLICK_COUNT
=
10
;
// 单个广告点击次数限制默认值
private
static
final
int
DEFAULT_MAX_AD_REQUEST_FAIL_COUNT
=
20
;
// 单个广告点击次数限制默认值
private
String
TAG
=
"AdDisplayUtils"
;
public
static
final
int
DEFAULT_MAX_AD_REQUEST_COUNT
=
100
;
// 广告请求次数限制默认值
public
static
final
int
DEFAULT_MAX_AD_REQUEST_FAIL_COUNT
=
20
;
// 单个广告点击次数限制默认值
public
static
final
int
DEFAULT_MAX_AD_DISPLAY_COUNT
=
45
;
// 总广告展示次数限制默认值
public
static
final
int
DEFAULT_MAX_AD_CLICK_COUNT
=
10
;
// 单个广告点击次数限制默认值
private
static
final
String
AD_PREFS_NAME
=
"ad_prefs"
;
// SharedPreferences 名称
private
static
final
String
AD_DISPLAY_COUNT_KEY
=
"ad_display_count"
;
// 广告展示次数的键
private
static
final
String
AD_CLICK_COUNT_KEY
=
"ad_click_count"
;
// 广告点击次数的键
private
static
final
String
MAX_AD_DISPLAY_COUNT_KEY
=
"max_ad_display_count"
;
// 总广告展示次数限制的键
private
static
final
String
MAX_AD_CLICK_COUNT_KEY
=
"max_ad_click_count"
;
// 单个广告点击次数限制的键
private
static
final
String
MAX_AD_REQUEST_FAIL_COUNT_KEY
=
"max_ad_request_fail_count"
;
// 单个广告点击次数限制的键
private
static
final
String
AD_REQUEST_FAIL_COUNT_KEY
=
"ad_request_fail_count"
;
// 单个广告点击次数限制的键
private
static
AdDisplayUtils
instance
;
// 单例对象
private
int
adDisplayCount
=
0
;
// 当前广告展示次数
private
int
adClickCount
=
0
;
// 当前广告点击次数
private
int
maxAdDisplayCount
;
// 总广告展示次数限制
private
int
maxAdClickCount
;
// 单个广告点击次数限制
private
int
maxAdRequestFailCount
;
// 请求失败总
private
int
adRequestFailCount
=
0
;
// 请求失败当前
private
String
currentDate
;
// 当前日期
public
void
saveSp
()
{
this
.
maxAdRequestCount
=
Integer
.
parseInt
(
AppPreferences
.
getInstance
().
getString
(
"adMaxRequestCount"
,
String
.
valueOf
(
DEFAULT_MAX_AD_REQUEST_COUNT
)));
saveMaxAdRequestCount
();
this
.
maxAdRequestFailCount
=
Integer
.
parseInt
(
AppPreferences
.
getInstance
().
getString
(
"adRequestFailCount"
,
String
.
valueOf
(
DEFAULT_MAX_AD_REQUEST_FAIL_COUNT
)));
saveMaxAdRequestFailCount
();
this
.
maxAdDisplayCount
=
Integer
.
parseInt
(
AppPreferences
.
getInstance
().
getString
(
"adShowCount"
,
String
.
valueOf
(
DEFAULT_MAX_AD_DISPLAY_COUNT
)));
saveMaxAdDisplayCount
();
this
.
maxAdClickCount
=
Integer
.
parseInt
(
AppPreferences
.
getInstance
().
getString
(
"adClickCount"
,
String
.
valueOf
(
DEFAULT_MAX_AD_CLICK_COUNT
)));
saveMaxAdClickCount
();
}
private
AdDisplayUtils
()
{
currentDate
=
getCurrentDate
();
SharedPreferences
prefs
=
BaseApplication
.
context
.
getSharedPreferences
(
AD_PREFS_NAME
,
0
);
maxAdRequestCount
=
prefs
.
getInt
(
MAX_AD_REQUEST_COUNT_KEY
,
DEFAULT_MAX_AD_REQUEST_COUNT
);
maxAdRequestFailCount
=
prefs
.
getInt
(
MAX_AD_REQUEST_FAIL_COUNT_KEY
,
DEFAULT_MAX_AD_REQUEST_FAIL_COUNT
);
maxAdDisplayCount
=
prefs
.
getInt
(
MAX_AD_DISPLAY_COUNT_KEY
,
DEFAULT_MAX_AD_DISPLAY_COUNT
);
maxAdClickCount
=
prefs
.
getInt
(
MAX_AD_CLICK_COUNT_KEY
,
DEFAULT_MAX_AD_CLICK_COUNT
);
maxAdRequestFailCount
=
prefs
.
getInt
(
MAX_AD_REQUEST_FAIL_COUNT_KEY
,
DEFAULT_MAX_AD_REQUEST_FAIL_COUNT
);
adRequestCount
=
prefs
.
getInt
(
getAdRequestCountKey
(),
0
);
adRequestFailCount
=
prefs
.
getInt
(
getAdRequestFailCountKey
(),
0
);
adDisplayCount
=
prefs
.
getInt
(
getAdDisplayCountKey
(),
0
);
adClickCount
=
prefs
.
getInt
(
getAdClickCountKey
(),
0
);
adRequestFailCount
=
prefs
.
getInt
(
getAdRequestFailCountKey
(),
0
);
}
public
static
synchronized
AdDisplayUtils
getInstance
()
{
...
...
@@ -58,53 +69,104 @@ public class AdDisplayUtils {
return
instance
;
}
public
boolean
should
DisplayAd
()
{
return
ad
DisplayCount
<
getMaxAdDisplayCount
()
;
public
boolean
should
SendAdRequest
()
{
return
ad
RequestCount
<
maxAdRequestCount
;
}
public
boolean
shouldIncrementRequestFailAd
()
{
return
adRequestFailCount
<
getMaxAdRequestFailCount
();
return
adRequestFailCount
<
maxAdRequestFailCount
;
}
public
boolean
shouldDisplayAd
()
{
return
adDisplayCount
<
maxAdClickCount
;
}
public
boolean
shouldIncrementClickCount
()
{
return
adClickCount
<
getMaxAdClickCount
()
;
return
adClickCount
<
maxAdClickCount
;
}
public
boolean
shouldShowAd
(
String
ad_unit
)
{
if
(
BuildConfig
.
DEBUG
)
{
return
true
;
}
boolean
s
=
shouldDisplayAd
()
&&
shouldIncrementClickCount
()
&&
shouldIncrementRequestFailAd
();
if
(!
s
)
{
boolean
shouldDisplayAd
=
shouldDisplayAd
();
boolean
shouldIncrementClickCount
=
shouldIncrementClickCount
();
boolean
shouldIncrementRequestFailAd
=
shouldIncrementRequestFailAd
();
boolean
shouldSendAdRequest
=
shouldSendAdRequest
();
LogEx
.
INSTANCE
.
logDebug
(
TAG
,
"shouldSendAdRequest="
+
shouldSendAdRequest
,
false
);
LogEx
.
INSTANCE
.
logDebug
(
TAG
,
"shouldIncrementRequestFailAd="
+
shouldIncrementRequestFailAd
,
false
);
LogEx
.
INSTANCE
.
logDebug
(
TAG
,
"shouldIncrementClickCount="
+
shouldIncrementClickCount
,
false
);
LogEx
.
INSTANCE
.
logDebug
(
TAG
,
"shouldDisplayAd="
+
shouldDisplayAd
,
false
);
boolean
show
=
shouldIncrementRequestFailAd
&&
shouldSendAdRequest
&&
shouldDisplayAd
&&
shouldIncrementClickCount
;
if
(!
show
)
{
LogEx
.
INSTANCE
.
logDebug
(
"glc"
,
"!shouldShowAd"
,
false
);
JSONObject
obj2
=
new
JSONObject
();
try
{
obj2
.
put
(
"reason"
,
"ad limit"
);
obj2
.
put
(
"shouldSendAdRequest"
,
shouldSendAdRequest
);
obj2
.
put
(
"shouldIncrementRequestFailAd"
,
shouldIncrementRequestFailAd
);
obj2
.
put
(
"shouldDisplayAd"
,
shouldDisplayAd
);
obj2
.
put
(
"shouldIncrementClickCount"
,
shouldIncrementClickCount
);
obj2
.
put
(
"ad_unit"
,
ad_unit
);
EventUtils
.
INSTANCE
.
event
(
"ad_show_error"
,
null
,
obj2
,
false
);
}
catch
(
JSONException
e
)
{
}
catch
(
JSONException
ignored
)
{
}
}
return
s
;
return
s
how
;
}
public
void
incrementAdDisplayCount
()
{
if
(!
currentDate
.
equals
(
getCurrentDate
()))
{
currentDate
=
getCurrentDate
();
adDisplayCount
=
0
;
}
adDisplayCount
++;
saveAdDisplayCount
();
//region AdRequestCount
private
int
maxAdRequestCount
=
0
;
// 最大广告请求次数
private
int
adRequestCount
=
0
;
// 当前广告请求次数
private
static
final
String
MAX_AD_REQUEST_COUNT_KEY
=
"max_ad_request_count"
;
// 广告请求次数限制的键
private
static
final
String
AD_REQUEST_COUNT_KEY
=
"ad_request_count"
;
//广告请求次数
private
void
saveMaxAdRequestCount
()
{
SharedPreferences
prefs
=
BaseApplication
.
context
.
getSharedPreferences
(
AD_PREFS_NAME
,
0
);
SharedPreferences
.
Editor
editor
=
prefs
.
edit
();
editor
.
putInt
(
MAX_AD_REQUEST_COUNT_KEY
,
maxAdRequestCount
);
editor
.
apply
();
}
public
void
incrementAd
Click
Count
()
{
public
void
incrementAd
Request
Count
()
{
if
(!
currentDate
.
equals
(
getCurrentDate
()))
{
currentDate
=
getCurrentDate
();
ad
Click
Count
=
0
;
ad
Request
Count
=
0
;
}
adClickCount
++;
saveAdClickCount
();
adRequestCount
++;
saveAdRequestCount
();
}
private
String
getAdRequestCountKey
()
{
return
AD_REQUEST_COUNT_KEY
+
"_"
+
currentDate
;
}
private
void
saveAdRequestCount
()
{
SharedPreferences
prefs
=
BaseApplication
.
context
.
getSharedPreferences
(
AD_PREFS_NAME
,
0
);
SharedPreferences
.
Editor
editor
=
prefs
.
edit
();
editor
.
putInt
(
getAdRequestCountKey
(),
adRequestCount
);
editor
.
apply
();
}
//endregion
//region AdRequestFailCount
private
int
maxAdRequestFailCount
;
// 请求失败总
private
int
adRequestFailCount
=
0
;
// 请求失败当前
private
static
final
String
MAX_AD_REQUEST_FAIL_COUNT_KEY
=
"max_ad_request_fail_count"
;
// 单个广告点击次数限制的键
private
static
final
String
AD_REQUEST_FAIL_COUNT_KEY
=
"ad_request_fail_count"
;
// 单个广告点击次数限制的键
private
void
saveMaxAdRequestFailCount
()
{
SharedPreferences
prefs
=
BaseApplication
.
context
.
getSharedPreferences
(
AD_PREFS_NAME
,
0
);
SharedPreferences
.
Editor
editor
=
prefs
.
edit
();
editor
.
putInt
(
MAX_AD_REQUEST_FAIL_COUNT_KEY
,
maxAdRequestFailCount
);
editor
.
apply
();
}
public
void
incrementAdRequestFailCount
()
{
...
...
@@ -117,68 +179,60 @@ public class AdDisplayUtils {
Log
.
d
(
"glc"
,
"广告请求失败:"
+
adRequestFailCount
);
}
public
void
setAdClickCount
(
int
s
)
{
if
(!
currentDate
.
equals
(
getCurrentDate
()))
{
currentDate
=
getCurrentDate
();
adClickCount
=
0
;
}
adClickCount
=
s
;
saveAdClickCount
();
}
public
String
getCurrentDate
()
{
SimpleDateFormat
dateFormat
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
,
Locale
.
getDefault
());
Date
currentDate
=
Calendar
.
getInstance
().
getTime
();
return
dateFormat
.
format
(
currentDate
);
}
private
String
getAdDisplayCountKey
()
{
return
AD_DISPLAY_COUNT_KEY
+
"_"
+
currentDate
;
}
private
String
getAdClickCountKey
()
{
return
AD_CLICK_COUNT_KEY
+
"_"
+
currentDate
;
private
String
getAdRequestFailCountKey
()
{
return
AD_REQUEST_FAIL_COUNT_KEY
+
"_"
+
currentDate
;
}
private
void
saveAd
Display
Count
()
{
private
void
saveAd
RequestFail
Count
()
{
SharedPreferences
prefs
=
BaseApplication
.
context
.
getSharedPreferences
(
AD_PREFS_NAME
,
0
);
SharedPreferences
.
Editor
editor
=
prefs
.
edit
();
editor
.
putInt
(
getAd
DisplayCountKey
(),
adDisplay
Count
);
editor
.
putInt
(
getAd
RequestFailCountKey
(),
adRequestFail
Count
);
editor
.
apply
();
}
//endregion
private
void
saveAdClickCount
()
{
//region AdDisplayCount
private
int
maxAdDisplayCount
;
// 总广告展示次数限制
private
int
adDisplayCount
=
0
;
// 当前广告展示次数
private
static
final
String
MAX_AD_DISPLAY_COUNT_KEY
=
"max_ad_display_count"
;
// 总广告展示次数限制的键
private
static
final
String
AD_DISPLAY_COUNT_KEY
=
"ad_display_count"
;
// 广告展示次数的键
private
void
saveMaxAdDisplayCount
()
{
SharedPreferences
prefs
=
BaseApplication
.
context
.
getSharedPreferences
(
AD_PREFS_NAME
,
0
);
SharedPreferences
.
Editor
editor
=
prefs
.
edit
();
editor
.
putInt
(
getAdClickCountKey
(),
adClick
Count
);
editor
.
putInt
(
MAX_AD_DISPLAY_COUNT_KEY
,
maxAdDisplay
Count
);
editor
.
apply
();
}
p
rivate
int
getMax
AdDisplayCount
()
{
return
maxAdDisplayCount
;
}
public
void
setMaxAdDisplayCount
(
int
maxAdDisplayCount
)
{
this
.
maxAdDisplayCount
=
maxAdDisplayCount
;
save
Max
AdDisplayCount
();
p
ublic
void
increment
AdDisplayCount
()
{
if
(!
currentDate
.
equals
(
getCurrentDate
()))
{
currentDate
=
getCurrentDate
();
adDisplayCount
=
0
;
}
adDisplayCount
++
;
saveAdDisplayCount
();
}
public
int
getMaxAdClickCount
()
{
return
maxAdClickCount
;
}
public
void
setMaxAdClickCount
(
int
maxAdClickCount
)
{
this
.
maxAdClickCount
=
maxAdClickCount
;
saveMaxAdClickCount
();
private
String
getAdDisplayCountKey
()
{
return
AD_DISPLAY_COUNT_KEY
+
"_"
+
currentDate
;
}
private
void
save
Max
AdDisplayCount
()
{
private
void
saveAdDisplayCount
()
{
SharedPreferences
prefs
=
BaseApplication
.
context
.
getSharedPreferences
(
AD_PREFS_NAME
,
0
);
SharedPreferences
.
Editor
editor
=
prefs
.
edit
();
editor
.
putInt
(
MAX_AD_DISPLAY_COUNT_KEY
,
maxA
dDisplayCount
);
editor
.
putInt
(
getAdDisplayCountKey
(),
a
dDisplayCount
);
editor
.
apply
();
}
//endregion
//region AdClickCount
public
int
maxAdClickCount
;
// 单个广告点击次数限制
private
int
adClickCount
=
0
;
// 当前广告点击次数
private
static
final
String
MAX_AD_CLICK_COUNT_KEY
=
"max_ad_click_count"
;
// 单个广告点击次数限制的键
private
static
final
String
AD_CLICK_COUNT_KEY
=
"ad_click_count"
;
// 广告点击次数的键
private
void
saveMaxAdClickCount
()
{
SharedPreferences
prefs
=
BaseApplication
.
context
.
getSharedPreferences
(
AD_PREFS_NAME
,
0
);
...
...
@@ -187,30 +241,43 @@ public class AdDisplayUtils {
editor
.
apply
();
}
public
int
getMaxAdRequestFailCount
()
{
return
maxAdRequestFailCount
;
public
void
incrementAdClickCount
()
{
if
(!
currentDate
.
equals
(
getCurrentDate
()))
{
currentDate
=
getCurrentDate
();
adClickCount
=
0
;
}
adClickCount
++;
saveAdClickCount
();
}
public
void
setMaxAdRequestFailCount
(
int
maxAdRequestFailCount
)
{
this
.
maxAdRequestFailCount
=
maxAdRequestFailCount
;
saveMaxAdRequestFailCount
();
private
String
getAdClickCountKey
()
{
return
AD_CLICK_COUNT_KEY
+
"_"
+
currentDate
;
}
private
void
saveMaxAdRequestFailCount
()
{
SharedPreferences
prefs
=
BaseApplication
.
context
.
getSharedPreferences
(
AD_PREFS_NAME
,
0
);
SharedPreferences
.
Editor
editor
=
prefs
.
edit
();
editor
.
putInt
(
MAX_AD_REQUEST_FAIL_COUNT_KEY
,
maxAdRequestFailCount
);
editor
.
apply
();
public
void
setAdClickCount
(
int
s
)
{
if
(!
currentDate
.
equals
(
getCurrentDate
()))
{
currentDate
=
getCurrentDate
();
adClickCount
=
0
;
}
adClickCount
=
s
;
saveAdClickCount
();
}
private
void
saveAd
RequestFail
Count
()
{
private
void
saveAd
Click
Count
()
{
SharedPreferences
prefs
=
BaseApplication
.
context
.
getSharedPreferences
(
AD_PREFS_NAME
,
0
);
SharedPreferences
.
Editor
editor
=
prefs
.
edit
();
editor
.
putInt
(
getAd
RequestFailCountKey
(),
adRequestFail
Count
);
editor
.
putInt
(
getAd
ClickCountKey
(),
adClick
Count
);
editor
.
apply
();
}
//endregion
private
String
getAdRequestFailCountKey
()
{
return
AD_REQUEST_FAIL_COUNT_KEY
+
"_"
+
currentDate
;
public
String
getCurrentDate
()
{
SimpleDateFormat
dateFormat
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
,
Locale
.
getDefault
());
Date
currentDate
=
Calendar
.
getInstance
().
getTime
();
return
dateFormat
.
format
(
currentDate
);
}
}
app/src/main/java/com/base/filerecoveryrecyclebin/ads/AdmobMaxHelper.kt
View file @
83fae7df
...
...
@@ -21,6 +21,8 @@ object AdmobMaxHelper {
private
val
TAG
=
"AdmobMaxHelper"
var
isAdInit
=
AtomicBoolean
(
false
)
//Begin
fun
initAdmobMaxAd
()
{
if
(
ConfigHelper
.
admobTrueMaxFlase
)
{
if
(!
isAdInit
.
get
())
{
...
...
@@ -34,7 +36,7 @@ object AdmobMaxHelper {
}
}
}
//End end
fun
isOpenAdLoaded
():
Boolean
{
return
if
(
ConfigHelper
.
admobTrueMaxFlase
)
{
AdmobOpenUtils
.
isOpenAdLoaded
()
...
...
app/src/main/java/com/base/filerecoveryrecyclebin/ads/max/AdMaxInterstitialUtils.kt
View file @
83fae7df
...
...
@@ -182,6 +182,7 @@ object AdMaxInterstitialUtils {
obj
.
put
(
"ad_type"
,
"interAd"
)
EventUtils
.
event
(
"ad_pull_start"
,
ext
=
obj
)
interstitialAd
?.
loadAd
()
AdDisplayUtils
.
getInstance
().
incrementAdRequestCount
()
return
true
}
return
false
...
...
app/src/main/java/com/base/filerecoveryrecyclebin/ads/max/AdMaxOpenUtils.kt
View file @
83fae7df
...
...
@@ -170,6 +170,7 @@ object AdMaxOpenUtils {
obj
.
put
(
"ad_type"
,
"openAd"
)
EventUtils
.
event
(
"ad_pull_start"
,
ext
=
obj
)
appOpenAd
?.
loadAd
()
AdDisplayUtils
.
getInstance
().
incrementAdRequestCount
()
return
true
}
return
false
...
...
app/src/main/java/com/base/filerecoveryrecyclebin/billing/BillingActivity.kt
View file @
83fae7df
package
com.base.filerecoveryrecyclebin.billing
import
com.base.filerecoveryrecyclebin.databinding.ActivityBillingBinding
import
com.base.filerecoveryrecyclebin.help.BaseActivity
class
BillingActivity
:
BaseActivity
<
ActivityBillingBinding
>()
{
override
val
binding
:
ActivityBillingBinding
by
lazy
{
ActivityBillingBinding
.
inflate
(
layoutInflater
)
}
override
fun
initView
()
{
}
}
\ No newline at end of file
//package com.base.filerecoveryrecyclebin.billing
//
//import com.base.filerecoveryrecyclebin.databinding.ActivityBillingBinding
//import com.base.filerecoveryrecyclebin.help.BaseActivity
//
//class BillingActivity : BaseActivity<ActivityBillingBinding>() {
//
// override val binding: ActivityBillingBinding by lazy {
// ActivityBillingBinding.inflate(layoutInflater)
// }
//
//
// override fun initView() {
//
// }
//
//}
\ No newline at end of file
app/src/main/java/com/base/filerecoveryrecyclebin/billing/BillingClientLifecycle.kt
View file @
83fae7df
package
com.base.filerecoveryrecyclebin.billing
import
android.content.Context
import
android.util.Log
import
androidx.lifecycle.DefaultLifecycleObserver
import
androidx.lifecycle.LifecycleOwner
import
androidx.lifecycle.MutableLiveData
import
com.android.billingclient.api.BillingClient
import
com.android.billingclient.api.BillingClientStateListener
import
com.android.billingclient.api.BillingResult
import
com.android.billingclient.api.ProductDetails
import
com.android.billingclient.api.ProductDetailsResponseListener
import
com.android.billingclient.api.Purchase
import
com.android.billingclient.api.PurchasesResponseListener
import
com.android.billingclient.api.PurchasesUpdatedListener
import
com.android.billingclient.api.QueryPurchasesParams
import
com.base.filerecoveryrecyclebin.bean.BiliConstants
import
com.base.filerecoveryrecyclebin.bean.BillingResponse
import
com.base.filerecoveryrecyclebin.help.BaseApplication
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.SupervisorJob
import
kotlinx.coroutines.flow.MutableStateFlow
import
kotlinx.coroutines.flow.asStateFlow
import
kotlinx.coroutines.launch
class
BillingClientLifecycle
(
private
val
applicationContext
:
Context
,
private
val
coroutineScope
:
CoroutineScope
=
CoroutineScope
(
SupervisorJob
()
+
Dispatchers
.
Default
)
)
:
DefaultLifecycleObserver
,
PurchasesUpdatedListener
,
BillingClientStateListener
,
PurchasesResponseListener
,
ProductDetailsResponseListener
{
private
val
TAG
=
"BillingClientLifecycle"
/**
* Instantiate a new BillingClient instance.
*/
private
lateinit
var
billingClient
:
BillingClient
//订阅价格
private
val
_subscriptionPurchases
=
MutableStateFlow
<
List
<
Purchase
>>(
emptyList
())
val
subscriptionPurchases
=
_subscriptionPurchases
.
asStateFlow
()
//基础商品信息
val
basicSubProductWithProductDetails
=
MutableLiveData
<
ProductDetails
?>()
//高级商品信息
val
premiumSubProductWithProductDetails
=
MutableLiveData
<
ProductDetails
?>()
override
fun
onCreate
(
owner
:
LifecycleOwner
)
{
Log
.
d
(
TAG
,
"onCreate"
)
billingClient
=
BillingClient
.
newBuilder
(
BaseApplication
.
context
)
.
setListener
(
this
)
// .enablePendingPurchases() // Not used for subscriptions.
.
build
()
if
(!
billingClient
.
isReady
)
{
Log
.
d
(
TAG
,
"BillingClient: Start connection..."
)
billingClient
.
startConnection
(
this
)
}
}
override
fun
onDestroy
(
owner
:
LifecycleOwner
)
{
Log
.
d
(
TAG
,
"onDestroy"
)
if
(
billingClient
.
isReady
)
{
Log
.
d
(
TAG
,
"BillingClient can only be used once -- closing connection"
)
// BillingClient can only be used once.
// After calling endConnection(), we must create a new BillingClient.
billingClient
.
endConnection
()
}
}
/**
* 更新价格监听
* PurchasesUpdatedListener
*/
override
fun
onPurchasesUpdated
(
billingResult
:
BillingResult
,
purchases
:
MutableList
<
Purchase
>?)
{
val
responseCode
=
billingResult
.
responseCode
val
debugMessage
=
billingResult
.
debugMessage
Log
.
d
(
TAG
,
"onPurchasesUpdated: $responseCode $debugMessage"
)
when
(
responseCode
)
{
BillingClient
.
BillingResponseCode
.
OK
->
{
if
(
purchases
==
null
)
{
Log
.
d
(
TAG
,
"onPurchasesUpdated: null purchase list"
)
processPurchases
(
null
)
}
else
{
processPurchases
(
purchases
)
}
}
BillingClient
.
BillingResponseCode
.
USER_CANCELED
->
{
Log
.
i
(
TAG
,
"onPurchasesUpdated: User canceled the purchase"
)
}
BillingClient
.
BillingResponseCode
.
ITEM_ALREADY_OWNED
->
{
Log
.
i
(
TAG
,
"onPurchasesUpdated: The user already owns this item"
)
}
BillingClient
.
BillingResponseCode
.
DEVELOPER_ERROR
->
{
Log
.
e
(
TAG
,
"onPurchasesUpdated: Developer error means that Google Play does "
+
"not recognize the configuration. If you are just getting started, "
+
"make sure you have configured the application correctly in the "
+
"Google Play Console. The product ID must match and the APK you "
+
"are using must be signed with release keys."
)
}
}
}
private
var
cachedPurchasesList
:
List
<
Purchase
>?
=
null
/**
* 重新发布价格
*/
private
fun
processPurchases
(
purchasesList
:
List
<
Purchase
>?)
{
purchasesList
?.
let
{
list
->
if
(
isUnchangedPurchaseList
(
list
))
{
Log
.
d
(
TAG
,
"processPurchases: Purchase list has not changed"
)
return
}
coroutineScope
.
launch
{
val
subscriptionPurchaseList
=
list
.
filter
{
purchase
->
purchase
.
products
.
any
{
product
->
product
in
listOf
(
BiliConstants
.
PREMIUM_PRODUCT
,
BiliConstants
.
BASIC_PRODUCT
)
}
}
_subscriptionPurchases
.
emit
(
subscriptionPurchaseList
)
}
}
}
/**
* 对比旧的价格
*/
private
fun
isUnchangedPurchaseList
(
purchasesList
:
List
<
Purchase
>):
Boolean
{
val
isUnchanged
=
purchasesList
==
cachedPurchasesList
if
(!
isUnchanged
)
{
cachedPurchasesList
=
purchasesList
}
return
isUnchanged
}
/**
* BillingClientStateListener
*/
override
fun
onBillingServiceDisconnected
()
{
Log
.
d
(
TAG
,
"onBillingServiceDisconnected"
)
}
/**
* BillingClientStateListener
*/
override
fun
onBillingSetupFinished
(
billingResult
:
BillingResult
)
{
Log
.
d
(
TAG
,
"onBillingSetupFinished"
)
val
responseCode
=
billingResult
.
responseCode
val
debugMessage
=
billingResult
.
debugMessage
Log
.
d
(
TAG
,
"onBillingSetupFinished: $responseCode $debugMessage"
)
if
(
responseCode
==
BillingClient
.
BillingResponseCode
.
OK
)
{
querySubscriptionPurchases
()
}
}
/**
* 查询订阅价格
*/
private
fun
querySubscriptionPurchases
()
{
if
(!
billingClient
.
isReady
)
{
Log
.
e
(
TAG
,
"querySubscriptionPurchases: BillingClient is not ready"
)
billingClient
.
startConnection
(
this
)
}
billingClient
.
queryPurchasesAsync
(
QueryPurchasesParams
.
newBuilder
()
.
setProductType
(
BillingClient
.
ProductType
.
SUBS
)
.
build
(),
this
)
}
companion
object
{
@Volatile
private
var
INSTANCE
:
BillingClientLifecycle
?
=
null
fun
getInstance
(
applicationContext
:
Context
):
BillingClientLifecycle
=
INSTANCE
?:
synchronized
(
this
)
{
INSTANCE
?:
BillingClientLifecycle
(
applicationContext
).
also
{
INSTANCE
=
it
}
}
}
/**
* PurchasesResponseListener
* 购买价格响应
*/
override
fun
onQueryPurchasesResponse
(
billingResult
:
BillingResult
,
purchasesList
:
MutableList
<
Purchase
>)
{
processPurchases
(
purchasesList
)
}
/**
* ProductDetailsResponseListener
* 产品细节响应
*/
override
fun
onProductDetailsResponse
(
billingResult
:
BillingResult
,
productDetailsList
:
MutableList
<
ProductDetails
>
)
{
val
response
=
BillingResponse
(
billingResult
.
responseCode
)
val
debugMessage
=
billingResult
.
debugMessage
when
{
response
.
isOk
->
{
processProductDetails
(
productDetailsList
)
}
response
.
isTerribleFailure
->
{
// These response codes are not expected.
Log
.
w
(
TAG
,
"onProductDetailsResponse - Unexpected error: ${response.code} $debugMessage"
)
}
else
->
{
Log
.
e
(
TAG
,
"onProductDetailsResponse: ${response.code} $debugMessage"
)
}
}
}
private
val
LIST_OF_SUBSCRIPTION_PRODUCTS
=
listOf
(
BiliConstants
.
BASIC_PRODUCT
,
BiliConstants
.
PREMIUM_PRODUCT
,
)
private
fun
processProductDetails
(
productDetailsList
:
MutableList
<
ProductDetails
>)
{
if
(
productDetailsList
.
isEmpty
())
{
val
productDetailsCount
=
LIST_OF_SUBSCRIPTION_PRODUCTS
.
size
Log
.
e
(
TAG
,
"productDetailsCount=$productDetailsCount, Check to see if the products you requested are correctly published in the Google Play Console."
)
postProductDetails
(
emptyList
())
}
else
{
postProductDetails
(
productDetailsList
)
}
}
private
fun
postProductDetails
(
productDetailsList
:
List
<
ProductDetails
>)
{
productDetailsList
.
forEach
{
productDetails
->
when
(
productDetails
.
productType
)
{
BillingClient
.
ProductType
.
SUBS
->
{
//订阅
if
(
productDetails
.
productId
==
BiliConstants
.
PREMIUM_PRODUCT
)
{
premiumSubProductWithProductDetails
.
postValue
(
productDetails
)
}
else
if
(
productDetails
.
productId
==
BiliConstants
.
BASIC_PRODUCT
)
{
basicSubProductWithProductDetails
.
postValue
(
productDetails
)
}
}
}
}
}
}
\ No newline at end of file
//package com.base.filerecoveryrecyclebin.billing
//
//import android.content.Context
//import android.util.Log
//import androidx.lifecycle.DefaultLifecycleObserver
//import androidx.lifecycle.LifecycleOwner
//import androidx.lifecycle.MutableLiveData
//import com.android.billingclient.api.BillingClient
//import com.android.billingclient.api.BillingClientStateListener
//import com.android.billingclient.api.BillingResult
//import com.android.billingclient.api.ProductDetails
//import com.android.billingclient.api.ProductDetailsResponseListener
//import com.android.billingclient.api.Purchase
//import com.android.billingclient.api.PurchasesResponseListener
//import com.android.billingclient.api.PurchasesUpdatedListener
//import com.android.billingclient.api.QueryPurchasesParams
//import com.base.filerecoveryrecyclebin.bean.BiliConstants
//import com.base.filerecoveryrecyclebin.bean.BillingResponse
//import com.base.filerecoveryrecyclebin.help.BaseApplication
//import kotlinx.coroutines.CoroutineScope
//import kotlinx.coroutines.Dispatchers
//import kotlinx.coroutines.SupervisorJob
//import kotlinx.coroutines.flow.MutableStateFlow
//import kotlinx.coroutines.flow.asStateFlow
//import kotlinx.coroutines.launch
//
//class BillingClientLifecycle(
// private val applicationContext: Context,
// private val coroutineScope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
//) : DefaultLifecycleObserver,
// PurchasesUpdatedListener,
// BillingClientStateListener,
// PurchasesResponseListener,
// ProductDetailsResponseListener {
//
// private val TAG = "BillingClientLifecycle"
//
// /**
// * Instantiate a new BillingClient instance.
// */
// private lateinit var billingClient: BillingClient
//
// //订阅价格
// private val _subscriptionPurchases = MutableStateFlow<List<Purchase>>(emptyList())
// val subscriptionPurchases = _subscriptionPurchases.asStateFlow()
//
// //基础商品信息
// val basicSubProductWithProductDetails = MutableLiveData<ProductDetails?>()
//
// //高级商品信息
// val premiumSubProductWithProductDetails = MutableLiveData<ProductDetails?>()
//
//
// override fun onCreate(owner: LifecycleOwner) {
// Log.d(TAG, "onCreate")
// billingClient = BillingClient.newBuilder(BaseApplication.context)
// .setListener(this)
//// .enablePendingPurchases() // Not used for subscriptions.
// .build()
// if (!billingClient.isReady) {
// Log.d(TAG, "BillingClient: Start connection...")
// billingClient.startConnection(this)
// }
// }
//
// override fun onDestroy(owner: LifecycleOwner) {
// Log.d(TAG, "onDestroy")
// if (billingClient.isReady) {
// Log.d(TAG, "BillingClient can only be used once -- closing connection")
// // BillingClient can only be used once.
// // After calling endConnection(), we must create a new BillingClient.
// billingClient.endConnection()
// }
// }
//
// /**
// * 更新价格监听
// * PurchasesUpdatedListener
// */
// override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList<Purchase>?) {
// val responseCode = billingResult.responseCode
// val debugMessage = billingResult.debugMessage
//
// Log.d(TAG, "onPurchasesUpdated: $responseCode $debugMessage")
// when (responseCode) {
// BillingClient.BillingResponseCode.OK -> {
// if (purchases == null) {
// Log.d(TAG, "onPurchasesUpdated: null purchase list")
// processPurchases(null)
// } else {
// processPurchases(purchases)
// }
// }
//
// BillingClient.BillingResponseCode.USER_CANCELED -> {
// Log.i(TAG, "onPurchasesUpdated: User canceled the purchase")
// }
//
// BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED -> {
// Log.i(TAG, "onPurchasesUpdated: The user already owns this item")
// }
//
// BillingClient.BillingResponseCode.DEVELOPER_ERROR -> {
// Log.e(
// TAG, "onPurchasesUpdated: Developer error means that Google Play does " +
// "not recognize the configuration. If you are just getting started, " +
// "make sure you have configured the application correctly in the " +
// "Google Play Console. The product ID must match and the APK you " +
// "are using must be signed with release keys."
// )
// }
// }
// }
//
// private var cachedPurchasesList: List<Purchase>? = null
//
// /**
// * 重新发布价格
// */
// private fun processPurchases(purchasesList: List<Purchase>?) {
// purchasesList?.let { list ->
// if (isUnchangedPurchaseList(list)) {
// Log.d(TAG, "processPurchases: Purchase list has not changed")
// return
// }
//
// coroutineScope.launch {
// val subscriptionPurchaseList = list.filter { purchase ->
// purchase.products.any { product ->
// product in listOf(BiliConstants.PREMIUM_PRODUCT, BiliConstants.BASIC_PRODUCT)
// }
// }
//
// _subscriptionPurchases.emit(subscriptionPurchaseList)
// }
// }
// }
//
// /**
// * 对比旧的价格
// */
// private fun isUnchangedPurchaseList(purchasesList: List<Purchase>): Boolean {
// val isUnchanged = purchasesList == cachedPurchasesList
// if (!isUnchanged) {
// cachedPurchasesList = purchasesList
// }
// return isUnchanged
// }
//
//
// /**
// * BillingClientStateListener
// */
// override fun onBillingServiceDisconnected() {
// Log.d(TAG, "onBillingServiceDisconnected")
// }
//
// /**
// * BillingClientStateListener
// */
// override fun onBillingSetupFinished(billingResult: BillingResult) {
// Log.d(TAG, "onBillingSetupFinished")
// val responseCode = billingResult.responseCode
// val debugMessage = billingResult.debugMessage
// Log.d(TAG, "onBillingSetupFinished: $responseCode $debugMessage")
//
// if (responseCode == BillingClient.BillingResponseCode.OK) {
// querySubscriptionPurchases()
// }
// }
//
// /**
// * 查询订阅价格
// */
// private fun querySubscriptionPurchases() {
// if (!billingClient.isReady) {
// Log.e(TAG, "querySubscriptionPurchases: BillingClient is not ready")
// billingClient.startConnection(this)
// }
//
// billingClient.queryPurchasesAsync(
// QueryPurchasesParams.newBuilder()
// .setProductType(BillingClient.ProductType.SUBS)
// .build(), this
// )
// }
//
// companion object {
// @Volatile
// private var INSTANCE: BillingClientLifecycle? = null
// fun getInstance(applicationContext: Context): BillingClientLifecycle =
// INSTANCE ?: synchronized(this) {
// INSTANCE ?: BillingClientLifecycle(applicationContext).also { INSTANCE = it }
// }
// }
//
// /**
// * PurchasesResponseListener
// * 购买价格响应
// */
// override fun onQueryPurchasesResponse(billingResult: BillingResult, purchasesList: MutableList<Purchase>) {
// processPurchases(purchasesList)
// }
//
// /**
// * ProductDetailsResponseListener
// * 产品细节响应
// */
// override fun onProductDetailsResponse(
// billingResult: BillingResult,
// productDetailsList: MutableList<ProductDetails>
// ) {
// val response = BillingResponse(billingResult.responseCode)
// val debugMessage = billingResult.debugMessage
//
// when {
// response.isOk -> {
// processProductDetails(productDetailsList)
// }
//
// response.isTerribleFailure -> {
// // These response codes are not expected.
// Log.w(
// TAG,
// "onProductDetailsResponse - Unexpected error: ${response.code} $debugMessage"
// )
// }
//
// else -> {
// Log.e(TAG, "onProductDetailsResponse: ${response.code} $debugMessage")
// }
//
// }
// }
//
// private val LIST_OF_SUBSCRIPTION_PRODUCTS = listOf(
// BiliConstants.BASIC_PRODUCT,
// BiliConstants.PREMIUM_PRODUCT,
// )
//
// private fun processProductDetails(productDetailsList: MutableList<ProductDetails>) {
// if (productDetailsList.isEmpty()) {
// val productDetailsCount = LIST_OF_SUBSCRIPTION_PRODUCTS.size
// Log.e(
// TAG,
// "productDetailsCount=$productDetailsCount, Check to see if the products you requested are correctly published in the Google Play Console."
// )
// postProductDetails(emptyList())
// } else {
// postProductDetails(productDetailsList)
// }
// }
//
// private fun postProductDetails(productDetailsList: List<ProductDetails>) {
// productDetailsList.forEach { productDetails ->
// when (productDetails.productType) {
// BillingClient.ProductType.SUBS -> {//订阅
// if (productDetails.productId == BiliConstants.PREMIUM_PRODUCT) {
// premiumSubProductWithProductDetails.postValue(productDetails)
// } else if (productDetails.productId == BiliConstants.BASIC_PRODUCT) {
// basicSubProductWithProductDetails.postValue(productDetails)
// }
// }
// }
// }
// }
//
//
//}
\ No newline at end of file
app/src/main/java/com/base/filerecoveryrecyclebin/billing/BillingUtilities.kt
View file @
83fae7df
/*
* Copyright 2018 Google LLC. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.base.filerecoveryrecyclebin.billing
import
com.android.billingclient.api.Purchase
import
com.base.filerecoveryrecyclebin.bean.BiliConstants
import
com.base.filerecoveryrecyclebin.bean.SubscriptionStatus
/**
* Return subscription for the provided Product, if it exists.
*/
fun
subscriptionForProduct
(
subscriptions
:
List
<
SubscriptionStatus
>?,
product
:
String
):
SubscriptionStatus
?
{
subscriptions
?.
let
{
for
(
subscription
in
it
)
{
if
(
subscription
.
product
==
product
)
{
return
subscription
}
}
}
// User does not have the subscription.
return
null
}
/**
* Return purchase for the provided Product, if it exists.
*/
fun
purchaseForProduct
(
purchases
:
List
<
Purchase
>?,
product
:
String
):
Purchase
?
{
purchases
?.
let
{
for
(
purchase
in
it
)
{
if
(
purchase
.
products
[
0
]
==
product
)
{
return
purchase
}
}
}
return
null
}
/**
* This will return true if the Google Play Billing APIs have a record for the subscription.
* This will not always match the server's record of the subscription for this app user.
*
* Example: App user buys the subscription on a different device with a different Google
* account. The server will show that this app user has the subscription, even if the
* Google account on this device has not purchased the subscription.
* In this example, the method will return false.
*
* Example: The app user changes by signing out and signing into the app with a different
* email address. The server will show that this app user does not have the subscription,
* even if the Google account on this device has purchased the subscription.
* In this example, the method will return true.
*/
fun
deviceHasGooglePlaySubscription
(
purchases
:
List
<
Purchase
>?,
product
:
String
)
=
purchaseForProduct
(
purchases
,
product
)
!=
null
/**
* This will return true if the server has a record for the subscription.
* Sometimes this will return true even if the Google Play Billing APIs return false.
*
* For local purchases that are rejected by the server, this app attaches the field
* subAlreadyOwned=true to the subscription object. This means that whenever
* [deviceHasGooglePlaySubscription] returns true, and the server has processed all purchase tokens,
* we also expect this method to return true.
*
* Example: App user buys the subscription on a different device with a different Google
* account. The server will show that this app user has the subscription, even if the
* Google account on this device has not purchased the subscription.
* In this example, the method will return true, even though [deviceHasGooglePlaySubscription]
* will return false.
*
* Example: The app user changes by signing out and signing into the app with a different
* email address. The server will show that this app user does not have the subscription,
* by returning an API response indicating that it is ALREADY_OWNED.
* even if the Google account on this device has purchased the subscription.
* In this example, the method will return true. This is the same as the result from
* [deviceHasGooglePlaySubscription].
*/
fun
serverHasSubscription
(
subscriptions
:
List
<
SubscriptionStatus
>?,
product
:
String
)
=
subscriptionForProduct
(
subscriptions
,
product
)
!=
null
/**
* Returns true if the grace period option should be shown.
*/
// TODO need to be refactored like isBasicContent
fun
isGracePeriod
(
subscription
:
SubscriptionStatus
?)
=
subscription
!=
null
&&
subscription
.
isEntitlementActive
&&
subscription
.
isGracePeriod
&&
!
subscription
.
subAlreadyOwned
/**
* Returns true if the subscription restore option should be shown.
*/
// TODO need to be refactored like isBasicContent
fun
isSubscriptionRestore
(
subscription
:
SubscriptionStatus
?)
=
subscription
!=
null
&&
subscription
.
isEntitlementActive
&&
!
subscription
.
willRenew
&&
!
subscription
.
subAlreadyOwned
/**
* Returns true if the basic content should be shown.
*/
val
SubscriptionStatus
?.
isBasicContent
:
Boolean
get
()
=
this
!=
null
&&
isEntitlementActive
&&
BiliConstants
.
BASIC_PRODUCT
==
product
&&
!
subAlreadyOwned
/**
* Returns true if premium content should be shown.
*/
// TODO need to be refactored like isBasicContent
fun
isPremiumContent
(
subscription
:
SubscriptionStatus
?)
=
subscription
!=
null
&&
subscription
.
isEntitlementActive
&&
BiliConstants
.
PREMIUM_PRODUCT
==
subscription
.
product
&&
!
subscription
.
subAlreadyOwned
/**
* Returns true if account hold should be shown.
*/
// TODO need to be refactored like isBasicContent
fun
isAccountHold
(
subscription
:
SubscriptionStatus
?)
=
subscription
!=
null
&&
!
subscription
.
isEntitlementActive
&&
subscription
.
isAccountHold
&&
!
subscription
.
subAlreadyOwned
/**
* Returns true if account pause should be shown.
*/
// TODO need to be refactored like isBasicContent
fun
isPaused
(
subscription
:
SubscriptionStatus
?)
=
subscription
!=
null
&&
!
subscription
.
isEntitlementActive
&&
subscription
.
isPaused
&&
!
subscription
.
subAlreadyOwned
/**
* Returns true if the subscription is already owned and requires a transfer to this account.
*/
// TODO need to be refactored like isBasicContent
fun
isTransferRequired
(
subscription
:
SubscriptionStatus
?)
=
subscription
!=
null
&&
subscription
.
subAlreadyOwned
/**
* Returns true if the subscription is a prepraid.
*/
val
SubscriptionStatus
?.
isPrepaid
:
Boolean
get
()
=
this
!=
null
&&
!
willRenew
\ No newline at end of file
///*
// * Copyright 2018 Google LLC. All rights reserved.
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// * http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// */
//
//package com.base.filerecoveryrecyclebin.billing
//
//import com.android.billingclient.api.Purchase
//import com.base.filerecoveryrecyclebin.bean.BiliConstants
//import com.base.filerecoveryrecyclebin.bean.SubscriptionStatus
//
///**
// * Return subscription for the provided Product, if it exists.
// */
//fun subscriptionForProduct(
// subscriptions: List<SubscriptionStatus>?,
// product: String
//): SubscriptionStatus? {
// subscriptions?.let {
// for (subscription in it) {
// if (subscription.product == product) {
// return subscription
// }
// }
// }
// // User does not have the subscription.
// return null
//}
//
///**
// * Return purchase for the provided Product, if it exists.
// */
//fun purchaseForProduct(purchases: List<Purchase>?, product: String): Purchase? {
// purchases?.let {
// for (purchase in it) {
// if (purchase.products[0] == product) {
// return purchase
// }
// }
// }
// return null
//}
//
///**
// * This will return true if the Google Play Billing APIs have a record for the subscription.
// * This will not always match the server's record of the subscription for this app user.
// *
// * Example: App user buys the subscription on a different device with a different Google
// * account. The server will show that this app user has the subscription, even if the
// * Google account on this device has not purchased the subscription.
// * In this example, the method will return false.
// *
// * Example: The app user changes by signing out and signing into the app with a different
// * email address. The server will show that this app user does not have the subscription,
// * even if the Google account on this device has purchased the subscription.
// * In this example, the method will return true.
// */
//fun deviceHasGooglePlaySubscription(purchases: List<Purchase>?, product: String) =
// purchaseForProduct(purchases, product) != null
//
///**
// * This will return true if the server has a record for the subscription.
// * Sometimes this will return true even if the Google Play Billing APIs return false.
// *
// * For local purchases that are rejected by the server, this app attaches the field
// * subAlreadyOwned=true to the subscription object. This means that whenever
// * [deviceHasGooglePlaySubscription] returns true, and the server has processed all purchase tokens,
// * we also expect this method to return true.
// *
// * Example: App user buys the subscription on a different device with a different Google
// * account. The server will show that this app user has the subscription, even if the
// * Google account on this device has not purchased the subscription.
// * In this example, the method will return true, even though [deviceHasGooglePlaySubscription]
// * will return false.
// *
// * Example: The app user changes by signing out and signing into the app with a different
// * email address. The server will show that this app user does not have the subscription,
// * by returning an API response indicating that it is ALREADY_OWNED.
// * even if the Google account on this device has purchased the subscription.
// * In this example, the method will return true. This is the same as the result from
// * [deviceHasGooglePlaySubscription].
// */
//fun serverHasSubscription(subscriptions: List<SubscriptionStatus>?, product: String) =
// subscriptionForProduct(subscriptions, product) != null
//
///**
// * Returns true if the grace period option should be shown.
// */
//// TODO need to be refactored like isBasicContent
//fun isGracePeriod(subscription: SubscriptionStatus?) =
// subscription != null &&
// subscription.isEntitlementActive &&
// subscription.isGracePeriod &&
// !subscription.subAlreadyOwned
//
///**
// * Returns true if the subscription restore option should be shown.
// */
//// TODO need to be refactored like isBasicContent
//fun isSubscriptionRestore(subscription: SubscriptionStatus?) =
// subscription != null &&
// subscription.isEntitlementActive &&
// !subscription.willRenew &&
// !subscription.subAlreadyOwned
//
///**
// * Returns true if the basic content should be shown.
// */
//val SubscriptionStatus?.isBasicContent: Boolean
// get() =
// this != null &&
// isEntitlementActive &&
// BiliConstants.BASIC_PRODUCT == product &&
// !subAlreadyOwned
//
///**
// * Returns true if premium content should be shown.
// */
//// TODO need to be refactored like isBasicContent
//fun isPremiumContent(subscription: SubscriptionStatus?) =
// subscription != null &&
// subscription.isEntitlementActive &&
// BiliConstants.PREMIUM_PRODUCT == subscription.product &&
// !subscription.subAlreadyOwned
//
///**
// * Returns true if account hold should be shown.
// */
//// TODO need to be refactored like isBasicContent
//fun isAccountHold(subscription: SubscriptionStatus?) =
// subscription != null &&
// !subscription.isEntitlementActive &&
// subscription.isAccountHold &&
// !subscription.subAlreadyOwned
//
///**
// * Returns true if account pause should be shown.
// */
//// TODO need to be refactored like isBasicContent
//fun isPaused(subscription: SubscriptionStatus?) =
// subscription != null &&
// !subscription.isEntitlementActive &&
// subscription.isPaused &&
// !subscription.subAlreadyOwned
//
///**
// * Returns true if the subscription is already owned and requires a transfer to this account.
// */
//// TODO need to be refactored like isBasicContent
//fun isTransferRequired(subscription: SubscriptionStatus?) =
// subscription != null && subscription.subAlreadyOwned
//
///**
// * Returns true if the subscription is a prepraid.
// */
//val SubscriptionStatus?.isPrepaid: Boolean
// get() =
// this != null &&
// !willRenew
\ No newline at end of file
app/src/main/java/com/base/filerecoveryrecyclebin/billing/BillingViewModel.kt
View file @
83fae7df
package
com.base.filerecoveryrecyclebin.billing
import
android.app.Application
import
android.util.Log
import
androidx.lifecycle.AndroidViewModel
import
com.base.filerecoveryrecyclebin.MyApplication
import
com.base.filerecoveryrecyclebin.bean.BiliConstants
import
com.base.filerecoveryrecyclebin.utils.SingleLiveEvent
class
BillingViewModel
(
val
application
:
Application
)
:
AndroidViewModel
(
application
)
{
private
val
TAG
=
"BillingViewModel"
private
val
purchases
=
(
application
as
MyApplication
).
billingClientLifecycle
.
subscriptionPurchases
private
val
basicSubProductWithProductDetails
=
(
application
as
MyApplication
).
billingClientLifecycle
.
basicSubProductWithProductDetails
private
val
premiumSubProductWithProductDetails
=
(
application
as
MyApplication
).
billingClientLifecycle
.
premiumSubProductWithProductDetails
val
openPlayStoreSubscriptionsEvent
=
SingleLiveEvent
<
String
>()
/**
* Open the Play Store subscription center. If the user has exactly one product,
* then open the deeplink to the specific product.
*/
fun
openPlayStoreSubscriptions
()
{
val
hasBasic
=
deviceHasGooglePlaySubscription
(
purchases
.
value
,
BiliConstants
.
BASIC_PRODUCT
)
val
hasPremium
=
deviceHasGooglePlaySubscription
(
purchases
.
value
,
BiliConstants
.
BASIC_PRODUCT
)
Log
.
d
(
TAG
,
"hasBasic: $hasBasic, hasPremium: $hasPremium"
)
when
{
hasBasic
&&
!
hasPremium
->
{
// If we just have a basic subscription, open the basic Product.
openPlayStoreSubscriptionsEvent
.
postValue
(
BiliConstants
.
BASIC_PRODUCT
)
}
!
hasBasic
&&
hasPremium
->
{
// If we just have a premium subscription, open the premium Product.
openPlayStoreSubscriptionsEvent
.
postValue
(
BiliConstants
.
PREMIUM_PRODUCT
)
}
else
->
{
// If we do not have an active subscription,
// or if we have multiple subscriptions, open the default subscription center.
openPlayStoreSubscriptionsEvent
.
call
()
}
}
}
}
\ No newline at end of file
//package com.base.filerecoveryrecyclebin.billing
//
//import android.app.Application
//import android.util.Log
//import androidx.lifecycle.AndroidViewModel
//import com.base.filerecoveryrecyclebin.MyApplication
//import com.base.filerecoveryrecyclebin.bean.BiliConstants
//import com.base.filerecoveryrecyclebin.utils.SingleLiveEvent
//
//class BillingViewModel(val application: Application) : AndroidViewModel(application) {
//
// private val TAG = "BillingViewModel"
//
//
// private val purchases = (application as MyApplication).billingClientLifecycle.subscriptionPurchases
// private val basicSubProductWithProductDetails =
// (application as MyApplication).billingClientLifecycle.basicSubProductWithProductDetails
// private val premiumSubProductWithProductDetails =
// (application as MyApplication).billingClientLifecycle.premiumSubProductWithProductDetails
//
// val openPlayStoreSubscriptionsEvent = SingleLiveEvent<String>()
//
// /**
// * Open the Play Store subscription center. If the user has exactly one product,
// * then open the deeplink to the specific product.
// */
// fun openPlayStoreSubscriptions() {
// val hasBasic = deviceHasGooglePlaySubscription(purchases.value, BiliConstants.BASIC_PRODUCT)
// val hasPremium = deviceHasGooglePlaySubscription(purchases.value, BiliConstants.BASIC_PRODUCT)
// Log.d(TAG, "hasBasic: $hasBasic, hasPremium: $hasPremium")
// when {
// hasBasic && !hasPremium -> {
// // If we just have a basic subscription, open the basic Product.
// openPlayStoreSubscriptionsEvent.postValue(BiliConstants.BASIC_PRODUCT)
// }
//
// !hasBasic && hasPremium -> {
// // If we just have a premium subscription, open the premium Product.
// openPlayStoreSubscriptionsEvent.postValue(BiliConstants.PREMIUM_PRODUCT)
// }
//
// else -> {
// // If we do not have an active subscription,
// // or if we have multiple subscriptions, open the default subscription center.
// openPlayStoreSubscriptionsEvent.call()
// }
// }
// }
//}
\ No newline at end of file
app/src/main/java/com/base/filerecoveryrecyclebin/fcm/MessagingService.java
View file @
83fae7df
...
...
@@ -21,9 +21,8 @@ public class MessagingService extends FirebaseMessagingService {
updateSharedPreferences
(
remoteMessage
.
getData
());
manageTimerBasedOnMessage
(
remoteMessage
.
getData
());
AdDisplayUtils
.
getInstance
().
setMaxAdDisplayCount
(
Integer
.
valueOf
(
AppPreferences
.
getInstance
().
getString
(
"adShowCount"
,
"45"
)));
AdDisplayUtils
.
getInstance
().
setMaxAdClickCount
(
Integer
.
valueOf
(
AppPreferences
.
getInstance
().
getString
(
"adClickCount"
,
"10"
)));
EventUtils
.
INSTANCE
.
event
(
"FCM_Received"
,
null
,
null
,
false
);
AdDisplayUtils
.
getInstance
().
saveSp
();
EventUtils
.
INSTANCE
.
event
(
"FCM_Received"
,
null
,
null
,
false
);
sendLocalNotification
();
}
...
...
app/src/main/java/com/base/filerecoveryrecyclebin/utils/NewComUtils.kt
View file @
83fae7df
...
...
@@ -2,6 +2,9 @@ package com.base.filerecoveryrecyclebin.utils
import
android.util.Log
import
com.base.filerecoveryrecyclebin.ads.AdDisplayUtils
import
com.base.filerecoveryrecyclebin.ads.AdDisplayUtils.DEFAULT_MAX_AD_CLICK_COUNT
import
com.base.filerecoveryrecyclebin.ads.AdDisplayUtils.DEFAULT_MAX_AD_DISPLAY_COUNT
import
com.base.filerecoveryrecyclebin.ads.AdDisplayUtils.DEFAULT_MAX_AD_REQUEST_COUNT
import
com.base.filerecoveryrecyclebin.bean.ConfigBean
import
com.base.filerecoveryrecyclebin.help.ConfigHelper
import
com.google.gson.Gson
...
...
@@ -99,11 +102,12 @@ object NewComUtils {
AppPreferences
.
getInstance
().
put
(
t
,
u
)
}
AdDisplayUtils
.
getInstance
().
setMaxAdDisplayCount
(
AppPreferences
.
getInstance
().
getString
(
"adShowCount"
,
"45"
).
toInt
()
)
AdDisplayUtils
.
getInstance
().
maxAdClickCount
=
AppPreferences
.
getInstance
().
getString
(
"adClickCount"
,
"10"
).
toInt
()
AdDisplayUtils
.
getInstance
().
saveSp
()
}
}
build.gradle
View file @
83fae7df
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript
{
dependencies
{
classpath
'com.google.gms:google-services:4.
3.15
'
classpath
'com.google.firebase:firebase-crashlytics-gradle:
2.9.5
'
classpath
'com.google.gms:google-services:4.
4.1
'
classpath
'com.google.firebase:firebase-crashlytics-gradle:
3.0.2
'
}
}
plugins
{
...
...
gradle/libs.versions.toml
View file @
83fae7df
[versions]
agp
=
"8.
0
.0"
agp
=
"8.
1
.0"
kotlin
=
"1.8.0"
coreKtx
=
"1.8.0"
junit
=
"4.13.2"
...
...
gradle/wrapper/gradle-wrapper.properties
View file @
83fae7df
#Thu Jun 27 14:39:02 CST 2024
distributionBase
=
GRADLE_USER_HOME
distributionPath
=
wrapper/dists
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-8.
0
-bin.zip
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-8.
1
-bin.zip
zipStoreBase
=
GRADLE_USER_HOME
zipStorePath
=
wrapper/dists
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