Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
sdk-public
sdk-demo
Commits
a8e3b987
Commit
a8e3b987
authored
Aug 18, 2022
by
zhengyingbing
Browse files
feat(app): 接入demo更新
parent
fd25d4fc
Changes
28
Hide whitespace changes
Inline
Side-by-side
app/build.gradle
View file @
a8e3b987
...
...
@@ -3,39 +3,14 @@ apply plugin: 'com.android.application'
android
{
compileSdkVersion
29
defaultConfig
{
// applicationId "com.hoolai.sdsxszycsgz"
applicationId
"com.hoolai.sdsxszycs"
minSdkVersion
19
applicationId
"com.hoolai.access.demo"
minSdkVersion
21
targetSdkVersion
29
versionCode
1
versionName
"1.0"
testInstrumentationRunner
"androidx.test.runner.AndroidJUnitRunner"
manifestPlaceholders
.
put
(
"APPLOG_SCHEME"
,
"rangersapplog.byAx6uYt"
.
toLowerCase
())
}
signingConfigs
{
release
{
//todo 需要换成正确的keystore
storeFile
file
(
"..\\keystoreFile\\sds.keystore"
)
keyPassword
'hoolai'
storePassword
'hoolai'
keyAlias
'ft'
}
test
{
//todo 需要换成正确的keystore
storeFile
file
(
"..\\keystoreFile\\sds_debug.keystore"
)
keyPassword
'hoolai321'
storePassword
'hoolai321'
keyAlias
'access-debug'
}
}
buildTypes
{
release
{
signingConfig
signingConfigs
.
release
minifyEnabled
false
proguardFiles
getDefaultProguardFile
(
'proguard-android-optimize.txt'
),
'proguard-rules.pro'
}
debug
{
signingConfig
signingConfigs
.
release
}
}
compileOptions
{
sourceCompatibility
JavaVersion
.
VERSION_1_8
targetCompatibility
JavaVersion
.
VERSION_1_8
...
...
@@ -43,6 +18,5 @@ android {
}
dependencies
{
//官网渠道
implementation
'com.hoolai.access.channel:hoolai-sdk:1.0.0.9'
implementation
'com.hoolai.access.open:hoolai-core:1.0.1.1'
}
\ No newline at end of file
app/src/androidTest/java/com/hl/account/ExampleInstrumentedTest.java
deleted
100644 → 0
View file @
fd25d4fc
package
com.hl.account
;
import
android.content.Context
;
import
androidx.test.platform.app.InstrumentationRegistry
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
static
org
.
junit
.
Assert
.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith
(
AndroidJUnit4
.
class
)
public
class
ExampleInstrumentedTest
{
@Test
public
void
useAppContext
()
{
// Context of the app under test.
Context
appContext
=
InstrumentationRegistry
.
getInstrumentation
().
getTargetContext
();
assertEquals
(
"com.hl.account"
,
appContext
.
getPackageName
());
}
}
app/src/main/AndroidManifest.xml
View file @
a8e3b987
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
package=
"com.hoolai.demo"
>
<!--hoolai sdk permission start-->
<uses-permission
android:name=
"android.permission.INTERNET"
/>
<uses-permission
android:name=
"android.permission.READ_SYNC_STATS"
/>
<uses-permission
android:name=
"android.permission.READ_PHONE_STATE"
/>
<uses-permission
android:name=
"android.permission.READ_CONTACTS"
/>
<uses-permission
android:name=
"android.permission.ACCESS_NETWORK_STATE"
/>
<uses-permission
android:name=
"android.permission.ACCESS_WIFI_STATE"
/>
<uses-permission
android:name=
"android.permission.WRITE_EXTERNAL_STORAGE"
/>
<uses-permission
android:name=
"android.permission.CHANGE_WIFI_STATE"
/>
<uses-permission
android:name=
"android.permission.CHANGE_NETWORK_STATE"
/>
<uses-permission
android:name=
"android.permission.READ_EXTERNAL_STORAGE"
/>
package=
"com.hl.demo"
>
<application
android:name=
"
com.hl.demo
.GameApplication"
android:name=
".GameApplication"
android:allowBackup=
"true"
android:label=
"@string/app_name"
android:theme=
"@android:style/Theme.NoTitleBar.Fullscreen"
android:icon=
"@mipmap/ic_launcher"
android:label=
"fastSdkDemo"
android:roundIcon=
"@mipmap/ic_launcher_round"
android:supportsRtl=
"true"
android:
networkSecurityConfig=
"@xml/network_security_config
"
android:
theme=
"@android:style/Theme.Translucent.NoTitleBar.Fullscreen
"
android:usesCleartextTraffic=
"true"
>
<activity
android:name=
"com.hl.demo.GameActivity"
android:configChanges=
"keyboardHidden|orientation|screenSize"
android:screenOrientation=
"portrait"
>
android:name=
".MainActivity"
android:exported=
"true"
>
<intent-filter>
<action
android:name=
"android.intent.action.MAIN"
/>
<category
android:name=
"android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
</application>
</manifest>
\ No newline at end of file
app/src/main/assets/channel_config.json
deleted
100644 → 0
View file @
fd25d4fc
MHZP
8
CM
4
NNqRrgaSiTk
8
XYroIMwKJVeLkdj
5
GZxI
7
y
9
kstf+a
3
YDUeEvsc
5
M/CIFf
5
SlzOYCw
7
KJ
1
SRv+BC
7
bzRbUwAsBlA
7
xUS
6
H
91
WdlEo
3
evStrXFC
3
mHjgbBudche
1
GuGdxubrnLkj
7
cBDi
7
hzjlw+Yv
5
ZikR
252
K
8
r
7
isKx
9
+zN
5
WLw
8
OXm
5
O
0
K
4
soIegPNNv
5
XhvYGiCHEKda
84
NDbFmIma
1
Ipq
22
cHZ/i
3
+omwSHxGhz
94
iUoChdiQ
6
f
5
l
6
cqtO+An
3
F
862
I
1
TVe
9
CkpfRolEhhaiqFElkKhK/rMIg
4
QGZIC
0
VVEAGU
8
HHtBEEvTxApvO
2
dYbeCE
1
fLmYZQ==
\ No newline at end of file
app/src/main/java/com/hl/account/AdvertisingIdClient.java
deleted
100644 → 0
View file @
fd25d4fc
package
com.hl.account
;
import
android.content.ComponentName
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.content.ServiceConnection
;
import
android.content.pm.PackageManager
;
import
android.os.IBinder
;
import
android.os.IInterface
;
import
android.os.Looper
;
import
android.os.Parcel
;
import
android.os.RemoteException
;
import
java.util.concurrent.LinkedBlockingQueue
;
public
class
AdvertisingIdClient
{
/**
* 这个方法是耗时的,不能在主线程调用
*/
public
static
String
getGoogleAdId
(
Context
context
)
throws
Exception
{
if
(
Looper
.
getMainLooper
()
==
Looper
.
myLooper
())
{
return
"Cannot call in the main thread, You must call in the other thread"
;
}
PackageManager
pm
=
context
.
getPackageManager
();
pm
.
getPackageInfo
(
"com.android.vending"
,
0
);
AdvertisingConnection
connection
=
new
AdvertisingConnection
();
Intent
intent
=
new
Intent
(
"com.google.android.gms.ads.identifier.service.START"
);
intent
.
setPackage
(
"com.google.android.gms"
);
if
(
context
.
bindService
(
intent
,
connection
,
Context
.
BIND_AUTO_CREATE
))
{
try
{
AdvertisingInterface
adInterface
=
new
AdvertisingInterface
(
connection
.
getBinder
());
return
adInterface
.
getId
();
}
finally
{
context
.
unbindService
(
connection
);
}
}
return
""
;
}
private
static
final
class
AdvertisingConnection
implements
ServiceConnection
{
boolean
retrieved
=
false
;
private
final
LinkedBlockingQueue
<
IBinder
>
queue
=
new
LinkedBlockingQueue
<>(
1
);
public
void
onServiceConnected
(
ComponentName
name
,
IBinder
service
)
{
try
{
this
.
queue
.
put
(
service
);
}
catch
(
InterruptedException
localInterruptedException
)
{
}
}
public
void
onServiceDisconnected
(
ComponentName
name
)
{
}
public
IBinder
getBinder
()
throws
InterruptedException
{
if
(
this
.
retrieved
)
throw
new
IllegalStateException
();
this
.
retrieved
=
true
;
return
this
.
queue
.
take
();
}
}
private
static
final
class
AdvertisingInterface
implements
IInterface
{
private
IBinder
binder
;
public
AdvertisingInterface
(
IBinder
pBinder
)
{
binder
=
pBinder
;
}
public
IBinder
asBinder
()
{
return
binder
;
}
public
String
getId
()
throws
RemoteException
{
Parcel
data
=
Parcel
.
obtain
();
Parcel
reply
=
Parcel
.
obtain
();
String
id
;
try
{
data
.
writeInterfaceToken
(
"com.google.android.gms.ads.identifier.internal.IAdvertisingIdService"
);
binder
.
transact
(
1
,
data
,
reply
,
0
);
reply
.
readException
();
id
=
reply
.
readString
();
}
finally
{
reply
.
recycle
();
data
.
recycle
();
}
return
id
;
}
public
boolean
isLimitAdTrackingEnabled
(
boolean
paramBoolean
)
throws
RemoteException
{
Parcel
data
=
Parcel
.
obtain
();
Parcel
reply
=
Parcel
.
obtain
();
boolean
limitAdTracking
;
try
{
data
.
writeInterfaceToken
(
"com.google.android.gms.ads.identifier.internal.IAdvertisingIdService"
);
data
.
writeInt
(
paramBoolean
?
1
:
0
);
binder
.
transact
(
2
,
data
,
reply
,
0
);
reply
.
readException
();
limitAdTracking
=
0
!=
reply
.
readInt
();
}
finally
{
reply
.
recycle
();
data
.
recycle
();
}
return
limitAdTracking
;
}
}
}
app/src/main/java/com/hl/account/AppUtil.java
deleted
100644 → 0
View file @
fd25d4fc
package
com.hl.account
;
import
android.content.Context
;
import
android.text.TextUtils
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
/**
* Created by Administrator on 2017/8/15.
*/
public
class
AppUtil
{
/**
* 判断email格式是否正确
*
* @param email
* @return true:是邮箱
*/
public
static
boolean
isEmail
(
String
email
)
{
if
(
TextUtils
.
isEmpty
(
email
))
{
return
false
;
}
String
str
=
"^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|("
+
""
+
"([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$"
;
Pattern
p
=
Pattern
.
compile
(
str
);
Matcher
m
=
p
.
matcher
(
email
);
return
m
.
matches
();
}
/**
* 判断密码是否合法
*/
public
static
String
isPwd
(
Context
context
,
String
pwd
)
{
if
(
TextUtils
.
isEmpty
(
pwd
))
{
return
context
.
getResources
().
getString
(
RTools
.
getString
(
context
,
"lksea_please_input_password"
));
}
if
(
pwd
.
contains
(
" "
)
||
isChinese
(
pwd
))
{
return
context
.
getString
(
RTools
.
getString
(
context
,
"lksea_password_not_comply_rules"
));
}
int
length
=
pwd
.
length
();
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
char
charAt
=
pwd
.
charAt
(
i
);
boolean
chinese
=
isChinese
(
charAt
);
if
(
chinese
)
{
return
context
.
getString
(
RTools
.
getString
(
context
,
"lksea_no_space"
));
}
}
if
(
length
<
6
||
length
>
31
)
{
return
context
.
getString
(
RTools
.
getString
(
context
,
"lksea_length_error"
));
}
String
reg
=
"^[a-zA-Z0-9]+[.a-zA-Z0-9@_-]*$"
;
Pattern
pattern
=
Pattern
.
compile
(
reg
);
Matcher
matcher
=
pattern
.
matcher
(
pwd
);
if
(!
matcher
.
matches
())
{
return
context
.
getString
(
RTools
.
getString
(
context
,
"lksea_format_error"
));
}
return
null
;
}
/**
* 判断字符串是否是中文
*
* @param str 字符串
*/
public
static
boolean
isChinese
(
String
str
)
{
char
[]
ch
=
str
.
toCharArray
();
for
(
int
i
=
0
;
i
<
ch
.
length
;
i
++)
{
char
c
=
ch
[
i
];
if
(
isChinese
(
c
))
{
return
true
;
}
}
return
false
;
}
// 根据Unicode编码完美的判断中文汉字和符号
private
static
boolean
isChinese
(
char
c
)
{
Character
.
UnicodeBlock
ub
=
Character
.
UnicodeBlock
.
of
(
c
);
if
(
ub
==
Character
.
UnicodeBlock
.
CJK_UNIFIED_IDEOGRAPHS
||
ub
==
Character
.
UnicodeBlock
.
CJK_COMPATIBILITY_IDEOGRAPHS
||
ub
==
Character
.
UnicodeBlock
.
CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
||
ub
==
Character
.
UnicodeBlock
.
CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
||
ub
==
Character
.
UnicodeBlock
.
CJK_SYMBOLS_AND_PUNCTUATION
||
ub
==
Character
.
UnicodeBlock
.
HALFWIDTH_AND_FULLWIDTH_FORMS
||
ub
==
Character
.
UnicodeBlock
.
GENERAL_PUNCTUATION
)
{
return
true
;
}
return
false
;
}
/**
* 判断手机格式是否正确
*
* @param mobiles
* @return true:是手机号
*/
public
static
boolean
isMobileNumber
(
String
mobiles
)
{
Pattern
p
=
Pattern
.
compile
(
"^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$"
);
Matcher
m
=
p
.
matcher
(
mobiles
);
return
m
.
matches
();
}
/**
* 判断验证码长度是否为6位,并且全为数字
*
* @param verificationCode
* @return 是否是验证码
*/
public
static
boolean
isVerification
(
String
verificationCode
)
{
if
(
verificationCode
.
length
()
!=
6
)
{
return
false
;
}
Pattern
pattern
=
Pattern
.
compile
(
"[0-9]*"
);
Matcher
matcher
=
pattern
.
matcher
(
verificationCode
);
return
matcher
.
matches
();
}
/**
* 账号部分用*代替,隐藏内容
*
* @param passport
* @return 186****1234
*/
public
static
String
showAccount
(
String
passport
)
{
int
flag
=
passport
.
indexOf
(
"@"
);
String
replaceSymbol
=
"*"
;
StringBuilder
stringBuilder
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
passport
.
length
();
i
++)
{
char
number
=
passport
.
charAt
(
i
);
if
(
i
>=
2
&&
i
<
flag
-
2
)
{
stringBuilder
.
append
(
replaceSymbol
);
}
else
{
stringBuilder
.
append
(
number
);
}
}
return
stringBuilder
.
toString
();
}
public
static
int
px2dip
(
Context
context
,
float
pxValue
)
{
final
float
scale
=
context
.
getResources
().
getDisplayMetrics
().
density
;
return
(
int
)
(
pxValue
/
scale
+
0.5f
);
}
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public
static
int
dip2px
(
Context
context
,
float
dpValue
)
{
final
float
scale
=
context
.
getResources
().
getDisplayMetrics
().
density
;
return
(
int
)
(
dpValue
*
scale
+
0.5f
);
}
}
app/src/main/java/com/hl/account/Base64Utils.java
deleted
100644 → 0
View file @
fd25d4fc
package
com.hl.account
;
import
java.io.UnsupportedEncodingException
;
/**
* Description:
* Author: Hansion
* Time: 2017/8/10 10:40
*/
public
class
Base64Utils
{
private
static
char
[]
base64EncodeChars
=
new
char
[]
{
'A'
,
'B'
,
'C'
,
'D'
,
'E'
,
'F'
,
'G'
,
'H'
,
'I'
,
'J'
,
'K'
,
'L'
,
'M'
,
'N'
,
'O'
,
'P'
,
'Q'
,
'R'
,
'S'
,
'T'
,
'U'
,
'V'
,
'W'
,
'X'
,
'Y'
,
'Z'
,
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
,
'g'
,
'h'
,
'i'
,
'j'
,
'k'
,
'l'
,
'm'
,
'n'
,
'o'
,
'p'
,
'q'
,
'r'
,
's'
,
't'
,
'u'
,
'v'
,
'w'
,
'x'
,
'y'
,
'z'
,
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
,
'+'
,
'/'
};
private
static
byte
[]
base64DecodeChars
=
new
byte
[]
{
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
62
,
-
1
,
-
1
,
-
1
,
63
,
52
,
53
,
54
,
55
,
56
,
57
,
58
,
59
,
60
,
61
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
,
11
,
12
,
13
,
14
,
15
,
16
,
17
,
18
,
19
,
20
,
21
,
22
,
23
,
24
,
25
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
26
,
27
,
28
,
29
,
30
,
31
,
32
,
33
,
34
,
35
,
36
,
37
,
38
,
39
,
40
,
41
,
42
,
43
,
44
,
45
,
46
,
47
,
48
,
49
,
50
,
51
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
};
/**
* 加密
*
* @param data
* @return 加密报文
*/
public
static
String
encode
(
byte
[]
data
)
{
StringBuffer
sb
=
new
StringBuffer
();
int
len
=
data
.
length
;
int
i
=
0
;
int
b1
,
b2
,
b3
;
while
(
i
<
len
)
{
b1
=
data
[
i
++]
&
0xff
;
if
(
i
==
len
)
{
sb
.
append
(
base64EncodeChars
[
b1
>>>
2
]);
sb
.
append
(
base64EncodeChars
[(
b1
&
0x3
)
<<
4
]);
sb
.
append
(
"=="
);
break
;
}
b2
=
data
[
i
++]
&
0xff
;
if
(
i
==
len
)
{
sb
.
append
(
base64EncodeChars
[
b1
>>>
2
]);
sb
.
append
(
base64EncodeChars
[((
b1
&
0x03
)
<<
4
)
|
((
b2
&
0xf0
)
>>>
4
)]);
sb
.
append
(
base64EncodeChars
[(
b2
&
0x0f
)
<<
2
]);
sb
.
append
(
"="
);
break
;
}
b3
=
data
[
i
++]
&
0xff
;
sb
.
append
(
base64EncodeChars
[
b1
>>>
2
]);
sb
.
append
(
base64EncodeChars
[((
b1
&
0x03
)
<<
4
)
|
((
b2
&
0xf0
)
>>>
4
)]);
sb
.
append
(
base64EncodeChars
[((
b2
&
0x0f
)
<<
2
)
|
((
b3
&
0xc0
)
>>>
6
)]);
sb
.
append
(
base64EncodeChars
[
b3
&
0x3f
]);
}
return
sb
.
toString
();
}
/**
* 解密
*
* @param str
* @return byte数组
*/
public
static
byte
[]
decode
(
String
str
)
{
try
{
return
decodePrivate
(
str
);
}
catch
(
UnsupportedEncodingException
e
)
{
e
.
printStackTrace
();
}
return
new
byte
[]
{};
}
private
static
byte
[]
decodePrivate
(
String
str
)
throws
UnsupportedEncodingException
{
StringBuffer
sb
=
new
StringBuffer
();
byte
[]
data
=
str
.
getBytes
(
"US-ASCII"
);
int
len
=
data
.
length
;
int
i
=
0
;
int
b1
,
b2
,
b3
,
b4
;
while
(
i
<
len
)
{
do
{
b1
=
base64DecodeChars
[
data
[
i
++]];
}
while
(
i
<
len
&&
b1
==
-
1
);
if
(
b1
==
-
1
)
break
;
do
{
b2
=
base64DecodeChars
[
data
[
i
++]];
}
while
(
i
<
len
&&
b2
==
-
1
);
if
(
b2
==
-
1
)
break
;
sb
.
append
((
char
)
((
b1
<<
2
)
|
((
b2
&
0x30
)
>>>
4
)));
do
{
b3
=
data
[
i
++];
if
(
b3
==
61
)
return
sb
.
toString
().
getBytes
(
"iso8859-1"
);
b3
=
base64DecodeChars
[
b3
];
}
while
(
i
<
len
&&
b3
==
-
1
);
if
(
b3
==
-
1
)
break
;
sb
.
append
((
char
)
(((
b2
&
0x0f
)
<<
4
)
|
((
b3
&
0x3c
)
>>>
2
)));
do
{
b4
=
data
[
i
++];
if
(
b4
==
61
)
return
sb
.
toString
().
getBytes
(
"iso8859-1"
);
b4
=
base64DecodeChars
[
b4
];
}
while
(
i
<
len
&&
b4
==
-
1
);
if
(
b4
==
-
1
)
break
;
sb
.
append
((
char
)
(((
b3
&
0x03
)
<<
6
)
|
b4
));
}
return
sb
.
toString
().
getBytes
(
"iso8859-1"
);
}
}
app/src/main/java/com/hl/account/CounterDownButton.java
deleted
100644 → 0
View file @
fd25d4fc
package
com.hl.account
;
import
android.annotation.SuppressLint
;
import
android.content.Context
;
import
android.os.CountDownTimer
;
import
android.util.AttributeSet
;
import
android.widget.Button
;
/**
* 倒计时按钮
*/
@SuppressLint
(
"AppCompatCustomView"
)
public
class
CounterDownButton
extends
Button
{
private
CounterDown
counterDown
;
private
Context
mContext
;
public
boolean
isRunning
=
false
;
public
CounterDownButton
(
Context
context
,
AttributeSet
attrs
,
int
defStyle
)
{
super
(
context
,
attrs
,
defStyle
);
mContext
=
context
;
init
();
}
public
CounterDownButton
(
Context
context
,
AttributeSet
attrs
)
{
super
(
context
,
attrs
);
mContext
=
context
;
init
();
}
public
CounterDownButton
(
Context
context
)
{
super
(
context
);
mContext
=
context
;
init
();
}
private
void
init
()
{
counterDown
=
new
CounterDown
(
60
*
1000
,
1000
);
}
public
void
start
()
{
if
(
counterDown
!=
null
)
{
counterDown
.
start
();
isRunning
=
true
;
}
setEnabled
(
false
);
}
public
void
cancle
()
{
if
(
counterDown
!=
null
)
{
counterDown
.
cancel
();
isRunning
=
false
;
}
setText
(
mContext
.
getResources
().
getString
(
RTools
.
getString
(
mContext
,
"lksea_send_again"
)));
setEnabled
(
true
);
}
private
class
CounterDown
extends
CountDownTimer
{
public
CounterDown
(
long
millisInFuture
,
long
countDownInterval
)
{
super
(
millisInFuture
,
countDownInterval
);
}
@Override
public
void
onFinish
()
{
setText
(
mContext
.
getResources
().
getString
(
RTools
.
getString
(
mContext
,
"lksea_send_again"
)));
setEnabled
(
true
);
isRunning
=
false
;
}
@Override
public
void
onTick
(
long
millisUntilFinished
)
{
String
format
=
mContext
.
getResources
().
getString
(
RTools
.
getString
(
mContext
,
"lksea_second_after_send_again"
));
setText
(
String
.
format
(
format
,
(
millisUntilFinished
/
1000
)));
}
}
}
app/src/main/java/com/hl/account/DeviceUtils.java
deleted
100644 → 0
View file @
fd25d4fc
package
com.hl.account
;
import
android.content.Context
;
import
android.provider.Settings.Secure
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.RandomAccessFile
;
import
java.util.UUID
;
public
class
DeviceUtils
{
/**
* 获取当前时间
* */
public
static
long
getNowTime
(){
return
System
.
currentTimeMillis
()
/
1000
;
}
/**************************** UUID框架 ***********************************/
private
static
String
sID
=
null
;
private
static
final
String
INSTALLATION
=
"INSTALLATION"
;
public
synchronized
static
String
id
(
Context
context
)
{
if
(
sID
==
null
)
{
File
installation
=
new
File
(
context
.
getFilesDir
(),
INSTALLATION
);
try
{
if
(!
installation
.
exists
())
{
writeInstallationFile
(
context
,
installation
);
}
sID
=
readInstallationFile
(
installation
);
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
e
);
}
}
return
sID
;
}
private
static
String
readInstallationFile
(
File
installation
)
throws
IOException
{
RandomAccessFile
f
=
new
RandomAccessFile
(
installation
,
"r"
);
byte
[]
bytes
=
new
byte
[(
int
)
f
.
length
()];
f
.
readFully
(
bytes
);
f
.
close
();
return
new
String
(
bytes
);
}
private
static
void
writeInstallationFile
(
Context
context
,
File
installation
)
throws
IOException
{
FileOutputStream
out
=
new
FileOutputStream
(
installation
);
String
id
;
final
String
androidId
=
Secure
.
getString
(
context
.
getContentResolver
(),
Secure
.
ANDROID_ID
);
if
(
androidId
==
null
)
{
id
=
UUID
.
randomUUID
().
toString
();
}
else
{
if
(!
"9774d56d682e549c"
.
equals
(
androidId
))
{
id
=
androidId
;
}
else
{
id
=
UUID
.
randomUUID
().
toString
();
}
}
out
.
write
(
id
.
getBytes
());
out
.
close
();
}
/**************************** UUID框架 ***********************************/
}
app/src/main/java/com/hl/account/LogoView.java
deleted
100644 → 0
View file @
fd25d4fc
package
com.hl.account
;
import
android.annotation.SuppressLint
;
import
android.content.Context
;
import
android.util.AttributeSet
;
import
android.view.View
;
import
android.view.View.OnClickListener
;
import
android.widget.ImageView
;
@SuppressLint
(
"AppCompatCustomView"
)
public
class
LogoView
extends
ImageView
implements
OnClickListener
{
// logo五次点击显示版本号
private
int
size
=
5
;
private
long
[]
clicks
=
new
long
[
size
];
private
Context
cxt
;
public
LogoView
(
Context
context
)
{
super
(
context
);
cxt
=
context
;
setOnClickListener
(
this
);
}
public
LogoView
(
Context
context
,
AttributeSet
attrs
)
{
super
(
context
,
attrs
);
cxt
=
context
;
setOnClickListener
(
this
);
}
public
LogoView
(
Context
context
,
AttributeSet
attrs
,
int
defStyle
)
{
super
(
context
,
attrs
,
defStyle
);
cxt
=
context
;
setOnClickListener
(
this
);
}
@Override
public
void
onClick
(
View
view
)
{
for
(
int
i
=
0
;
i
<
size
-
1
;
i
++)
{
clicks
[
i
]
=
clicks
[
i
+
1
];
}
clicks
[
size
-
1
]
=
System
.
currentTimeMillis
();
if
((
clicks
[
size
-
1
]
-
clicks
[
0
])
<
1500
)
{
// Toast.makeText(cxt, LKBuild.VERSION, Toast.LENGTH_LONG).show();
if
(
mClickFastListener
!=
null
){
mClickFastListener
.
onClickfast
();
}
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
clicks
[
i
]
=
0
;
}
}
}
private
OnClickFastListener
mClickFastListener
;
public
void
setClickFastListener
(
OnClickFastListener
listener
){
mClickFastListener
=
listener
;
}
public
interface
OnClickFastListener
{
void
onClickfast
();
}
}
\ No newline at end of file
app/src/main/java/com/hl/account/MainActivity.java
deleted
100644 → 0
View file @
fd25d4fc
package
com.hl.account
;
import
androidx.appcompat.app.AppCompatActivity
;
import
android.os.Bundle
;
import
com.hoolai.demo.R
;
public
class
MainActivity
extends
AppCompatActivity
{
@Override
protected
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
setContentView
(
R
.
layout
.
activity_main
);
}
}
app/src/main/java/com/hl/account/RSAUtils.java
deleted
100644 → 0
View file @
fd25d4fc
package
com.hl.account
;
import
java.security.KeyFactory
;
import
java.security.KeyPair
;
import
java.security.KeyPairGenerator
;
import
java.security.NoSuchAlgorithmException
;
import
java.security.PrivateKey
;
import
java.security.PublicKey
;
import
java.security.Signature
;
import
java.security.interfaces.RSAPrivateKey
;
import
java.security.interfaces.RSAPublicKey
;
import
java.security.spec.InvalidKeySpecException
;
import
java.security.spec.PKCS8EncodedKeySpec
;
import
java.security.spec.X509EncodedKeySpec
;
import
java.util.ArrayList
;
import
java.util.List
;
import
javax.crypto.Cipher
;
/**
* Description:
* Author: Hansion
* Time: 2017/8/10 10:34
*/
public
class
RSAUtils
{
public
static
final
int
DEFAULT_KEY_SIZE
=
2048
;
//秘钥默认长度
public
static
final
String
RSA
=
"RSA"
;
// 非对称加密密钥算法
public
static
final
String
ECB_PKCS1_PADDING
=
"RSA/ECB/PKCS1Padding"
;
//加密填充方式
public
static
final
byte
[]
DEFAULT_SPLIT
=
"#PART#"
.
getBytes
();
// 当要加密的内容超过bufferSize,则采用partSplit进行分块加密
public
static
final
int
DEFAULT_BUFFERSIZE
=
(
DEFAULT_KEY_SIZE
/
8
)
-
11
;
// 当前秘钥支持加密的最大字节数
public
static
final
String
SIGNATURE_ALGORITHM
=
"MD5withRSA"
;
private
static
RSAPublicKey
publicKey
=
null
;
/**
* RSA公钥
*/
public
static
final
String
PUBLIC_KEY
=
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHOjIs2536Hq15DJ+Rijp5aZrSxBVbgRqgW+z6\n"
+
"Bu/hZ3izKLRBIw8mLR79NgCi0zPNzVv8ppSVN25PIqbKmY09uI/gHXeyNDqq5nCrpZJ53IOLylZf\n"
+
"JHSS+RGAhA8+B54AMZQyaDyIdkdpG+dQUqqmY1yKPEX6TObt6rtjmG9mqwIDAQAB"
;
/**
* 从字符串中加载公钥
*/
public
static
void
loadPublicKey
()
{
try
{
byte
[]
buffer
=
Base64Utils
.
decode
(
PUBLIC_KEY
);
KeyFactory
keyFactory
=
KeyFactory
.
getInstance
(
RSA
);
X509EncodedKeySpec
keySpec
=
new
X509EncodedKeySpec
(
buffer
);
publicKey
=
(
RSAPublicKey
)
keyFactory
.
generatePublic
(
keySpec
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
/**
* 用公钥对字符串进行分段加密
*/
public
static
String
encryptByPublicKeyForSpilt
(
byte
[]
data
)
throws
Exception
{
int
dataLen
=
data
.
length
;
if
(
dataLen
<=
DEFAULT_BUFFERSIZE
)
{
return
Base64Utils
.
encode
(
encryptByPublicKey
(
data
,
publicKey
.
getEncoded
()));
}
List
<
Byte
>
allBytes
=
new
ArrayList
<
Byte
>(
2048
);
int
bufIndex
=
0
;
int
subDataLoop
=
0
;
byte
[]
buf
=
new
byte
[
DEFAULT_BUFFERSIZE
];
for
(
int
i
=
0
;
i
<
dataLen
;
i
++)
{
buf
[
bufIndex
]
=
data
[
i
];
if
(++
bufIndex
==
DEFAULT_BUFFERSIZE
||
i
==
dataLen
-
1
)
{
subDataLoop
++;
if
(
subDataLoop
!=
1
)
{
for
(
byte
b
:
DEFAULT_SPLIT
)
{
allBytes
.
add
(
b
);
}
}
byte
[]
encryptBytes
=
encryptByPublicKey
(
buf
,
publicKey
.
getEncoded
());
for
(
byte
b
:
encryptBytes
)
{
allBytes
.
add
(
b
);
}
bufIndex
=
0
;
if
(
i
==
dataLen
-
1
)
{
buf
=
null
;
}
else
{
buf
=
new
byte
[
Math
.
min
(
DEFAULT_BUFFERSIZE
,
dataLen
-
i
-
1
)];
}
}
}
byte
[]
bytes
=
new
byte
[
allBytes
.
size
()];
{
int
i
=
0
;
for
(
Byte
b
:
allBytes
)
{
bytes
[
i
++]
=
b
.
byteValue
();
}
}
return
Base64Utils
.
encode
(
bytes
);
}
/**
* 用公钥对字符串进行分段加密
*/
public
static
String
encryptByPublicKey
(
String
str
)
throws
Exception
{
byte
[]
data
=
str
.
getBytes
();
int
dataLen
=
data
.
length
;
if
(
dataLen
<=
DEFAULT_BUFFERSIZE
)
{
return
Base64Utils
.
encode
(
encryptByPublicKey
(
data
,
publicKey
.
getEncoded
()));
}
List
<
Byte
>
allBytes
=
new
ArrayList
<
Byte
>(
2048
);
int
bufIndex
=
0
;
int
subDataLoop
=
0
;
byte
[]
buf
=
new
byte
[
DEFAULT_BUFFERSIZE
];
for
(
int
i
=
0
;
i
<
dataLen
;
i
++)
{
buf
[
bufIndex
]
=
data
[
i
];
if
(++
bufIndex
==
DEFAULT_BUFFERSIZE
||
i
==
dataLen
-
1
)
{
subDataLoop
++;
if
(
subDataLoop
!=
1
)
{
for
(
byte
b
:
DEFAULT_SPLIT
)
{
allBytes
.
add
(
b
);
}
}
byte
[]
encryptBytes
=
encryptByPublicKey
(
buf
,
publicKey
.
getEncoded
());
for
(
byte
b
:
encryptBytes
)
{
allBytes
.
add
(
b
);
}
bufIndex
=
0
;
if
(
i
==
dataLen
-
1
)
{
buf
=
null
;
}
else
{
buf
=
new
byte
[
Math
.
min
(
DEFAULT_BUFFERSIZE
,
dataLen
-
i
-
1
)];
}
}
}
byte
[]
bytes
=
new
byte
[
allBytes
.
size
()];
{
int
i
=
0
;
for
(
Byte
b
:
allBytes
)
{
bytes
[
i
++]
=
b
.
byteValue
();
}
}
return
Base64Utils
.
encode
(
bytes
);
}
/**
* 随机生成RSA密钥对
*
* @param keyLength 密钥长度,范围:512~2048
* 一般1024
* @return
*/
public
static
KeyPair
generateRSAKeyPair
(
int
keyLength
)
{
try
{
KeyPairGenerator
kpg
=
KeyPairGenerator
.
getInstance
(
RSA
);
kpg
.
initialize
(
keyLength
);
return
kpg
.
genKeyPair
();
}
catch
(
NoSuchAlgorithmException
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
/**
* 用公钥对字符串进行加密
*
* @param data 原文
*/
public
static
byte
[]
encryptByPublicKey
(
byte
[]
data
,
byte
[]
publicKey
)
throws
Exception
{
// 得到公钥
X509EncodedKeySpec
keySpec
=
new
X509EncodedKeySpec
(
publicKey
);
KeyFactory
kf
=
KeyFactory
.
getInstance
(
RSA
);
PublicKey
keyPublic
=
kf
.
generatePublic
(
keySpec
);
// 加密数据
Cipher
cp
=
Cipher
.
getInstance
(
ECB_PKCS1_PADDING
);
cp
.
init
(
Cipher
.
ENCRYPT_MODE
,
keyPublic
);
return
cp
.
doFinal
(
data
);
}
/**
* 私钥加密
*
* @param data 待加密数据
* @param privateKey 密钥
* @return byte[] 加密数据
*/
public
static
byte
[]
encryptByPrivateKey
(
byte
[]
data
,
byte
[]
privateKey
)
throws
Exception
{
// 得到私钥
PKCS8EncodedKeySpec
keySpec
=
new
PKCS8EncodedKeySpec
(
privateKey
);
KeyFactory
kf
=
KeyFactory
.
getInstance
(
RSA
);
PrivateKey
keyPrivate
=
kf
.
generatePrivate
(
keySpec
);
// 数据加密
Cipher
cipher
=
Cipher
.
getInstance
(
ECB_PKCS1_PADDING
);
cipher
.
init
(
Cipher
.
ENCRYPT_MODE
,
keyPrivate
);
return
cipher
.
doFinal
(
data
);
}
/**
* 公钥解密
*
* @param data 待解密数据
* @param publicKey 密钥
* @return byte[] 解密数据
*/
public
static
byte
[]
decryptByPublicKey
(
byte
[]
data
,
byte
[]
publicKey
)
throws
Exception
{
// 得到公钥
X509EncodedKeySpec
keySpec
=
new
X509EncodedKeySpec
(
publicKey
);
KeyFactory
kf
=
KeyFactory
.
getInstance
(
RSA
);
PublicKey
keyPublic
=
kf
.
generatePublic
(
keySpec
);
// 数据解密
Cipher
cipher
=
Cipher
.
getInstance
(
ECB_PKCS1_PADDING
);
cipher
.
init
(
Cipher
.
DECRYPT_MODE
,
keyPublic
);
return
cipher
.
doFinal
(
data
);
}
/**
* 使用私钥进行解密
*/
public
static
byte
[]
decryptByPrivateKey
(
byte
[]
encrypted
,
byte
[]
privateKey
)
throws
Exception
{
// 得到私钥
PKCS8EncodedKeySpec
keySpec
=
new
PKCS8EncodedKeySpec
(
privateKey
);
KeyFactory
kf
=
KeyFactory
.
getInstance
(
RSA
);
PrivateKey
keyPrivate
=
kf
.
generatePrivate
(
keySpec
);
// 解密数据
Cipher
cp
=
Cipher
.
getInstance
(
ECB_PKCS1_PADDING
);
cp
.
init
(
Cipher
.
DECRYPT_MODE
,
keyPrivate
);
byte
[]
arr
=
cp
.
doFinal
(
encrypted
);
return
arr
;
}
/**
* 从字符串中加载私钥<br>
*
* @param privateKeyStr
* @return
* @throws Exception
*/
public
static
RSAPrivateKey
loadPrivateKey
(
String
privateKeyStr
)
throws
Exception
{
try
{
byte
[]
buffer
=
Base64Utils
.
decode
(
privateKeyStr
);
// X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
PKCS8EncodedKeySpec
keySpec
=
new
PKCS8EncodedKeySpec
(
buffer
);
KeyFactory
keyFactory
=
KeyFactory
.
getInstance
(
RSA
);
return
(
RSAPrivateKey
)
keyFactory
.
generatePrivate
(
keySpec
);
}
catch
(
NoSuchAlgorithmException
e
)
{
throw
new
Exception
(
"无此算法"
);
}
catch
(
InvalidKeySpecException
e
)
{
throw
new
Exception
(
"私钥非法"
);
}
catch
(
NullPointerException
e
)
{
throw
new
Exception
(
"私钥数据为空"
);
}
}
/**
* 用私钥对字符串进行分段加密
*
* @param data 要加密的原始数据
* @param privateKey 秘钥
*/
public
static
byte
[]
encryptByPrivateKeyForSpilt
(
byte
[]
data
,
byte
[]
privateKey
)
throws
Exception
{
int
dataLen
=
data
.
length
;
if
(
dataLen
<=
DEFAULT_BUFFERSIZE
)
{
return
encryptByPrivateKey
(
data
,
privateKey
);
}
List
<
Byte
>
allBytes
=
new
ArrayList
<
Byte
>(
2048
);
int
bufIndex
=
0
;
int
subDataLoop
=
0
;
byte
[]
buf
=
new
byte
[
DEFAULT_BUFFERSIZE
];
for
(
int
i
=
0
;
i
<
dataLen
;
i
++)
{
buf
[
bufIndex
]
=
data
[
i
];
if
(++
bufIndex
==
DEFAULT_BUFFERSIZE
||
i
==
dataLen
-
1
)
{
subDataLoop
++;
if
(
subDataLoop
!=
1
)
{
for
(
byte
b
:
DEFAULT_SPLIT
)
{
allBytes
.
add
(
b
);
}
}
byte
[]
encryptBytes
=
encryptByPrivateKey
(
buf
,
privateKey
);
for
(
byte
b
:
encryptBytes
)
{
allBytes
.
add
(
b
);
}
bufIndex
=
0
;
if
(
i
==
dataLen
-
1
)
{
buf
=
null
;
}
else
{
buf
=
new
byte
[
Math
.
min
(
DEFAULT_BUFFERSIZE
,
dataLen
-
i
-
1
)];
}
}
}
byte
[]
bytes
=
new
byte
[
allBytes
.
size
()];
{
int
i
=
0
;
for
(
Byte
b
:
allBytes
)
{
bytes
[
i
++]
=
b
.
byteValue
();
}
}
return
bytes
;
}
/**
* 公钥分段解密
*
* @param encrypted 待解密数据
* @param publicKey 密钥
*/
public
static
byte
[]
decryptByPublicKeyForSpilt
(
byte
[]
encrypted
,
byte
[]
publicKey
)
throws
Exception
{
int
splitLen
=
DEFAULT_SPLIT
.
length
;
if
(
splitLen
<=
0
)
{
return
decryptByPublicKey
(
encrypted
,
publicKey
);
}
int
dataLen
=
encrypted
.
length
;
List
<
Byte
>
allBytes
=
new
ArrayList
<
Byte
>(
1024
);
int
latestStartIndex
=
0
;
for
(
int
i
=
0
;
i
<
dataLen
;
i
++)
{
byte
bt
=
encrypted
[
i
];
boolean
isMatchSplit
=
false
;
if
(
i
==
dataLen
-
1
)
{
// 到data的最后了
byte
[]
part
=
new
byte
[
dataLen
-
latestStartIndex
];
System
.
arraycopy
(
encrypted
,
latestStartIndex
,
part
,
0
,
part
.
length
);
byte
[]
decryptPart
=
decryptByPublicKey
(
part
,
publicKey
);
for
(
byte
b
:
decryptPart
)
{
allBytes
.
add
(
b
);
}
latestStartIndex
=
i
+
splitLen
;
i
=
latestStartIndex
-
1
;
}
else
if
(
bt
==
DEFAULT_SPLIT
[
0
])
{
// 这个是以split[0]开头
if
(
splitLen
>
1
)
{
if
(
i
+
splitLen
<
dataLen
)
{
// 没有超出data的范围
for
(
int
j
=
1
;
j
<
splitLen
;
j
++)
{
if
(
DEFAULT_SPLIT
[
j
]
!=
encrypted
[
i
+
j
])
{
break
;
}
if
(
j
==
splitLen
-
1
)
{
// 验证到split的最后一位,都没有break,则表明已经确认是split段
isMatchSplit
=
true
;
}
}
}
}
else
{
// split只有一位,则已经匹配了
isMatchSplit
=
true
;
}
}
if
(
isMatchSplit
)
{
byte
[]
part
=
new
byte
[
i
-
latestStartIndex
];
System
.
arraycopy
(
encrypted
,
latestStartIndex
,
part
,
0
,
part
.
length
);
byte
[]
decryptPart
=
decryptByPublicKey
(
part
,
publicKey
);
for
(
byte
b
:
decryptPart
)
{
allBytes
.
add
(
b
);
}
latestStartIndex
=
i
+
splitLen
;
i
=
latestStartIndex
-
1
;
}
}
byte
[]
bytes
=
new
byte
[
allBytes
.
size
()];
{
int
i
=
0
;
for
(
Byte
b
:
allBytes
)
{
bytes
[
i
++]
=
b
.
byteValue
();
}
}
return
bytes
;
}
/**
* 使用私钥分段解密
*/
public
static
byte
[]
decryptByPrivateKeyForSpilt
(
byte
[]
encrypted
,
byte
[]
privateKey
)
throws
Exception
{
int
splitLen
=
DEFAULT_SPLIT
.
length
;
if
(
splitLen
<=
0
)
{
return
decryptByPrivateKey
(
encrypted
,
privateKey
);
}
int
dataLen
=
encrypted
.
length
;
List
<
Byte
>
allBytes
=
new
ArrayList
<
Byte
>(
1024
);
int
latestStartIndex
=
0
;
for
(
int
i
=
0
;
i
<
dataLen
;
i
++)
{
byte
bt
=
encrypted
[
i
];
boolean
isMatchSplit
=
false
;
if
(
i
==
dataLen
-
1
)
{
// 到data的最后了
byte
[]
part
=
new
byte
[
dataLen
-
latestStartIndex
];
System
.
arraycopy
(
encrypted
,
latestStartIndex
,
part
,
0
,
part
.
length
);
byte
[]
decryptPart
=
decryptByPrivateKey
(
part
,
privateKey
);
for
(
byte
b
:
decryptPart
)
{
allBytes
.
add
(
b
);
}
latestStartIndex
=
i
+
splitLen
;
i
=
latestStartIndex
-
1
;
}
else
if
(
bt
==
DEFAULT_SPLIT
[
0
])
{
// 这个是以split[0]开头
if
(
splitLen
>
1
)
{
if
(
i
+
splitLen
<
dataLen
)
{
// 没有超出data的范围
for
(
int
j
=
1
;
j
<
splitLen
;
j
++)
{
if
(
DEFAULT_SPLIT
[
j
]
!=
encrypted
[
i
+
j
])
{
break
;
}
if
(
j
==
splitLen
-
1
)
{
// 验证到split的最后一位,都没有break,则表明已经确认是split段
isMatchSplit
=
true
;
}
}
}
}
else
{
// split只有一位,则已经匹配了
isMatchSplit
=
true
;
}
}
if
(
isMatchSplit
)
{
byte
[]
part
=
new
byte
[
i
-
latestStartIndex
];
System
.
arraycopy
(
encrypted
,
latestStartIndex
,
part
,
0
,
part
.
length
);
byte
[]
decryptPart
=
decryptByPrivateKey
(
part
,
privateKey
);
for
(
byte
b
:
decryptPart
)
{
allBytes
.
add
(
b
);
}
latestStartIndex
=
i
+
splitLen
;
i
=
latestStartIndex
-
1
;
}
}
byte
[]
bytes
=
new
byte
[
allBytes
.
size
()];
{
int
i
=
0
;
for
(
Byte
b
:
allBytes
)
{
bytes
[
i
++]
=
b
.
byteValue
();
}
}
return
bytes
;
}
//***************************签名和验证*******************************
public
static
byte
[]
sign
(
byte
[]
data
,
PrivateKey
priK
)
throws
Exception
{
Signature
sig
=
Signature
.
getInstance
(
SIGNATURE_ALGORITHM
);
sig
.
initSign
(
priK
);
sig
.
update
(
data
);
return
sig
.
sign
();
}
public
static
boolean
verify
(
byte
[]
data
,
byte
[]
sign
,
PublicKey
pubK
)
throws
Exception
{
Signature
sig
=
Signature
.
getInstance
(
SIGNATURE_ALGORITHM
);
sig
.
initVerify
(
pubK
);
sig
.
update
(
data
);
return
sig
.
verify
(
sign
);
}
}
app/src/main/java/com/hl/account/RTools.java
deleted
100644 → 0
View file @
fd25d4fc
package
com.hl.account
;
import
android.content.Context
;
/**
* Created by Administrator on 2017/10/27.
*/
public
class
RTools
{
public
static
int
getString
(
Context
context
,
String
name
)
{
return
context
.
getResources
().
getIdentifier
(
name
,
"string"
,
context
.
getPackageName
());
}
public
static
int
getLayout
(
Context
context
,
String
name
)
{
return
context
.
getResources
().
getIdentifier
(
name
,
"layout"
,
context
.
getPackageName
());
}
public
static
int
getId
(
Context
context
,
String
name
)
{
return
context
.
getResources
().
getIdentifier
(
name
,
"id"
,
context
.
getPackageName
());
}
public
static
int
getDrawable
(
Context
context
,
String
name
)
{
return
context
.
getResources
().
getIdentifier
(
name
,
"drawable"
,
context
.
getPackageName
());
}
public
static
int
getStyle
(
Context
context
,
String
name
)
{
return
context
.
getResources
().
getIdentifier
(
name
,
"style"
,
context
.
getPackageName
());
}
public
static
int
getColor
(
Context
context
,
String
name
)
{
return
context
.
getResources
().
getIdentifier
(
name
,
"color"
,
context
.
getPackageName
());
}
public
static
int
getDimen
(
Context
context
,
String
name
)
{
return
context
.
getResources
().
getIdentifier
(
name
,
"dimen"
,
context
.
getPackageName
());
}
}
app/src/main/java/com/hl/account/ThreadPoolManager.java
deleted
100644 → 0
View file @
fd25d4fc
package
com.hl.account
;
import
java.util.concurrent.BlockingQueue
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.LinkedBlockingQueue
;
import
java.util.concurrent.ScheduledExecutorService
;
import
java.util.concurrent.ScheduledThreadPoolExecutor
;
import
java.util.concurrent.SynchronousQueue
;
import
java.util.concurrent.ThreadFactory
;
import
java.util.concurrent.ThreadPoolExecutor
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicInteger
;
/**
* 线程池管理类
*
* @author changcsw 2015-11-6
*
*/
public
final
class
ThreadPoolManager
{
// 获取CPU
private
static
final
int
CPU_COUNT
=
Runtime
.
getRuntime
().
availableProcessors
();
// 线程池中最少的线程的数量
private
static
final
int
CORE_POOL_SIZE
=
(
CPU_COUNT
+
1
)
>
3
?
(
CPU_COUNT
+
1
)
:
3
;
// 线程池中最多的线程的数量
private
static
final
int
MAXIMUM_POOL_SIZE
=
(
CPU_COUNT
>
1
)
?
(
CPU_COUNT
*
2
+
1
)
:
5
;
// 空闲线程的最长存活时间
private
static
final
long
KEEP_ALIVE
=
1L
;
// 工作队列-阻塞队列
private
static
final
BlockingQueue
<
Runnable
>
WORK_QUEUE
=
new
LinkedBlockingQueue
<
Runnable
>(
128
);
// 线程池中线程的创建工厂
private
static
final
ThreadFactory
THREAD_FACTORY
=
new
ThreadFactory
()
{
// 原子操作级别的整数,初始值是1
private
final
AtomicInteger
mCount
=
new
AtomicInteger
(
1
);
@Override
public
Thread
newThread
(
Runnable
r
)
{
Thread
thread
=
new
Thread
(
r
,
"Thread #"
+
mCount
.
getAndIncrement
());
// 线程名,前缀固定,后缀自增长
thread
.
setPriority
(
Thread
.
NORM_PRIORITY
);
// 正常优先级
return
thread
;
}
};
/************************************** 线程池中线程的执行的管理器 ******************************************/
// 普通的任务用这个执行器, 缺点:当没有任务是还会CORE_POOL_SIZE个线程占用资源,优点:无需频繁调度
public
static
final
ExecutorService
EXECUTOR
=
new
ThreadPoolExecutor
(
CORE_POOL_SIZE
,
MAXIMUM_POOL_SIZE
,
KEEP_ALIVE
,
TimeUnit
.
SECONDS
,
WORK_QUEUE
,
THREAD_FACTORY
,
new
ThreadPoolExecutor
.
DiscardPolicy
());
// 有新的任务就开启新的线程,当没有新任务时会自动回收线程,缺点:频繁调度, 优点:快速处理任务
public
static
final
ExecutorService
CACHED_EXECUTOR
=
new
ThreadPoolExecutor
(
CORE_POOL_SIZE
,
Integer
.
MAX_VALUE
,
60L
,
TimeUnit
.
SECONDS
,
new
SynchronousQueue
<
Runnable
>(),
THREAD_FACTORY
,
new
ThreadPoolExecutor
.
DiscardOldestPolicy
());
// 当有计划的执行一个任务时用,如检查版本更新,
public
static
final
ScheduledExecutorService
SCHEDULED_EXECUTOR
=
new
ScheduledThreadPoolExecutor
(
CORE_POOL_SIZE
,
THREAD_FACTORY
,
new
ThreadPoolExecutor
.
DiscardPolicy
());
/************************************** 线程池中线程的执行的管理器 ******************************************/
}
app/src/main/java/com/hl/demo/GameApplication.java
View file @
a8e3b987
...
...
@@ -3,15 +3,9 @@ package com.hl.demo;
import
android.app.Application
;
import
android.content.Context
;
import
android.content.res.Configuration
;
import
android.os.Process
;
import
android.text.TextUtils
;
import
com.hoolai.access.open.fastaccess.channel.FastSdk
;
import
java.io.BufferedReader
;
import
java.io.File
;
import
java.io.FileReader
;
public
class
GameApplication
extends
Application
{
@Override
...
...
@@ -40,33 +34,4 @@ public class GameApplication extends Application {
super
.
attachBaseContext
(
context
);
FastSdk
.
attachBaseContext
(
this
,
context
);
}
/**
* 多进程判断,sdk已经做了处理,游戏可不做处理
* @param application
* @return
*/
public
static
boolean
getProcessPerform
(
Application
application
){
String
processName
=
getProcessName
();
int
pid
=
Process
.
myPid
();
LogUtil
.
i
(
"my pid:"
+
pid
+
",processName:"
+
processName
);
if
(!
TextUtils
.
isEmpty
(
processName
)
&&
processName
.
equals
(
application
.
getPackageName
())){
return
true
;
}
return
false
;
}
public
static
String
getProcessName
()
{
try
{
File
file
=
new
File
(
"/proc/"
+
Process
.
myPid
()
+
"/"
+
"cmdline"
);
BufferedReader
mBufferedReader
=
new
BufferedReader
(
new
FileReader
(
file
));
String
processName
=
mBufferedReader
.
readLine
().
trim
();
mBufferedReader
.
close
();
return
processName
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
}
app/src/main/java/com/hl/demo/LogUtil.java
deleted
100644 → 0
View file @
fd25d4fc
package
com.hl.demo
;
import
android.util.Log
;
public
class
LogUtil
{
private
static
final
String
TAG
=
"HL_DEMO"
;
public
static
void
i
(
String
str
){
Log
.
i
(
TAG
,
str
);
}
}
app/src/main/java/com/hl/demo/
Game
Activity.java
→
app/src/main/java/com/hl/demo/
Main
Activity.java
View file @
a8e3b987
...
...
@@ -2,193 +2,62 @@ package com.hl.demo;
import
android.app.Activity
;
import
android.app.AlertDialog
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.content.res.Configuration
;
import
android.content.res.Resources
;
import
android.os.Bundle
;
import
android.text.TextUtils
;
import
android.view.View
;
import
android.widget.ArrayAdapter
;
import
android.widget.EditText
;
import
android.widget.ListView
;
import
android.widget.Button
;
import
android.widget.TextView
;
import
android.widget.Toast
;
import
com.chuanglan.shanyan_sdk.OneKeyLoginManager
;
import
com.hoolai.access.account.ui.WebviewActivity
;
import
com.hoolai.access.open.fastaccess.channel.FastSdk
;
import
com.hoolai.access.open.fastaccess.channel.request.EventType
;
import
com.hoolai.access.open.fastaccess.channel.request.GoodsInfo
;
import
com.hoolai.access.open.fastaccess.channel.request.PayParams
;
import
com.hoolai.access.open.fastaccess.channel.request.ProductParams
;
import
com.hoolai.access.open.fastaccess.channel.request.PlayerInfo
;
import
com.hoolai.access.open.fastaccess.channel.result.LoginResult
;
import
com.hoolai.access.open.fastaccess.interf.HLAccountListener
;
import
com.hoolai.access.open.fastaccess.interf.HLPaymentListener
;
import
com.hoolai.access.open.fastaccess.interf.HLProductInfoListener
;
import
com.hoolai.access.open.fastaccess.interf.HLRealNameListener
;
import
com.hoolai.access.open.fastaccess.interf.HLSystemListener
;
import
com.hoolai.access.open.fastaccess.utils.Logger
;
import
com.hoolai.access.open.fastaccess.utils.ToastUtils
;
import
com.hoolai.demo.R
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.UUID
;
/**
* Hoolai_sdk接入说明
* 接入文档地址 http://support.hoolai.com/docs/#/android/complete
*/
public
class
GameActivity
extends
Activity
{
private
TextView
contentTv
;
private
LoginResult
userResponse
;
private
EditText
et_tv
,
et_rpc
,
et_pwd
;
private
EditText
et_ip_host
,
et_ip_pwd
,
et_ip_port
;
public
class
MainActivity
extends
Activity
{
private
boolean
isInit
,
isLogin
;
private
TextView
textview
;
private
Button
initBtn
;
private
String
str
=
""
;
@Override
protected
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
setContentView
(
R
.
layout
.
activity_example
);
contentTv
=
findViewById
(
R
.
id
.
main_tv
);
et_tv
=
findViewById
(
R
.
id
.
et_main
);
et_rpc
=
findViewById
(
R
.
id
.
et_rpc
);
et_pwd
=
findViewById
(
R
.
id
.
et_pwd
);
et_ip_host
=
findViewById
(
R
.
id
.
et_ip_host
);
et_ip_port
=
findViewById
(
R
.
id
.
et_ip_port
);
et_ip_pwd
=
findViewById
(
R
.
id
.
et_ip_pwd
);
//hoolai sdk初始化操作
Map
<
String
,
String
>
map
=
new
HashMap
<>();
map
.
put
(
"aa"
,
"bbb"
);
OneKeyLoginManager
.
getInstance
().
setDebug
(
true
);
settingProxy
();
}
@Override
protected
void
onSaveInstanceState
(
Bundle
outState
)
{
super
.
onSaveInstanceState
(
outState
);
FastSdk
.
onSaveInstanceState
(
outState
);
}
@Override
protected
void
onStart
()
{
super
.
onStart
();
FastSdk
.
onStart
(
this
);
}
@Override
protected
void
onResume
()
{
super
.
onResume
();
FastSdk
.
onResume
(
this
);
}
@Override
protected
void
onStop
()
{
super
.
onStop
();
FastSdk
.
onStop
(
this
);
}
@Override
protected
void
onPause
()
{
super
.
onPause
();
FastSdk
.
onPause
(
this
);
}
@Override
protected
void
onRestart
()
{
super
.
onRestart
();
FastSdk
.
onRestart
(
this
);
}
@Override
protected
void
onDestroy
()
{
super
.
onDestroy
();
FastSdk
.
onDestroy
(
this
);
}
setContentView
(
R
.
layout
.
activity_main
);
textview
=
findViewById
(
R
.
id
.
textview
);
initBtn
=
findViewById
(
R
.
id
.
initBtn
);
@Override
protected
void
onNewIntent
(
Intent
intent
)
{
super
.
onNewIntent
(
intent
);
FastSdk
.
onNewIntent
(
intent
);
}
@Override
protected
void
onActivityResult
(
int
requestCode
,
int
resultCode
,
Intent
data
)
{
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
);
FastSdk
.
onActivityResult
(
this
,
requestCode
,
resultCode
,
data
);
}
@Override
public
void
onRequestPermissionsResult
(
int
requestCode
,
String
[]
permissions
,
int
[]
grantResults
)
{
super
.
onRequestPermissionsResult
(
requestCode
,
permissions
,
grantResults
);
FastSdk
.
onRequestPermissionsResult
(
requestCode
,
permissions
,
grantResults
);
}
@Override
public
void
onConfigurationChanged
(
Configuration
newConfig
)
{
super
.
onConfigurationChanged
(
newConfig
);
FastSdk
.
onConfigurationChanged
(
this
,
newConfig
,
getResources
());
}
@Override
public
void
onBackPressed
()
{
// super.onBackPressed();
//如果游戏需要捕获返回事件,请在这里做逻辑判断调用FastSdk.onBackPressed();
FastSdk
.
onBackPressed
();
exit
();
}
/**
* hoolai sdk初始化,必须放到onCreate中,并且在主线程中调用
*/
private
void
hoolaiSdkInit
()
{
//声明系统回调(初始化,退出,版本升级)监听
FastSdk
.
hlSystemListener
=
new
HLSystemListener
()
{
@Override
public
void
onInitSuccess
()
{
runOnUiThread
(
new
Runnable
()
{
@Override
public
void
run
()
{
if
(!
contentTv
.
getText
().
toString
().
contains
(
"登录成功"
))
{
contentTv
.
setText
(
"初始化成功!\n获取初始化返回配置\n"
);
}
LogUtil
.
i
(
"Hoolai sdk初始化成功:"
);
Toast
.
makeText
(
GameActivity
.
this
,
"初始化成功!"
,
Toast
.
LENGTH_SHORT
).
show
();
}
});
isInit
=
true
;
Logger
.
data
(
"fastsdkdemo"
,
"初始化成功"
);
setText
(
">>初始化成功"
);
initBtn
.
setVisibility
(
View
.
GONE
);
}
@Override
public
void
onInitFailed
(
String
reason
)
{
runOnUiThread
(
new
Runnable
()
{
@Override
public
void
run
()
{
LogUtil
.
i
(
"Hoolai sdk初始化失败:"
+
reason
);
Toast
.
makeText
(
GameActivity
.
this
,
"初始化失败:"
+
reason
,
Toast
.
LENGTH_SHORT
).
show
();
}
});
//sdk初始化失败
//注意初始化未成功不得调用sdk任何接口,游戏可在这里做提示或者重新初始化操作
Logger
.
data
(
"fastsdkdemo"
,
"初始化失败:"
+
reason
);
setText
(
">>初始化失败"
);
initBtn
.
setVisibility
(
View
.
VISIBLE
);
}
@Override
public
void
onCustomExit
()
{
Toast
.
makeText
(
GameActivity
.
this
,
"弹出游戏的退出界面"
,
Toast
.
LENGTH_SHORT
).
show
();
/**
* demo 只作为参考,游戏应该根据自己所需逻辑实现
* 渠道没有退出二次确认框
* 根据需要加二次确认框
*/
// 渠道不存在退出界面,如百度移动游戏等,此时需在此处弹出游戏退出确认界面,否则会出现渠道审核不通过情况
// 游戏实现自己的退出界面 ,实现退出逻辑,请勿直接照搬demo
// 根据需要加二次确认框
new
AlertDialog
.
Builder
(
GameActivity
.
this
)
Logger
.
data
(
"fastsdkdemo"
,
"弹出游戏的退出界面"
);
setText
(
">>弹出游戏的退出界面"
);
new
AlertDialog
.
Builder
(
MainActivity
.
this
)
.
setTitle
(
"游戏退出弹窗"
)
.
setMessage
(
"我是游戏的弹窗界面哦"
)
.
setNegativeButton
(
"取消"
,
null
)
...
...
@@ -212,331 +81,248 @@ public class GameActivity extends Activity {
@Override
public
void
onUpdate
(
String
data
)
{
Logger
.
data
(
"fastsdkdemo"
,
"升级:"
+
data
);
}
};
//声明账号回调监听
FastSdk
.
hlAccountListener
=
new
HLAccountListener
()
{
@Override
public
void
onRefreshUser
(
LoginResult
result
)
{
LogUtil
.
i
(
"Hoolai refreshUser:"
+
result
.
toString
());
Toast
.
makeText
(
GameActivity
.
this
,
"小号切换成功"
+
result
.
getNickName
(),
Toast
.
LENGTH_SHORT
).
show
();
contentTv
.
setText
(
"用户信息刷新:"
+
result
.
toString
());
//没有小号可忽略
}
@Override
public
void
onLoginSuccess
(
LoginResult
result
)
{
GameActivity
.
this
.
userResponse
=
result
;
contentTv
.
setText
(
"登录成功
:
"
+
result
.
toString
());
Logger
.
data
(
"fastsdkdemo"
,
"登录成功:"
+
result
)
;
setText
(
"
>>
登录成功
:
"
+
result
.
toString
()
+
""
);
isLogin
=
true
;
}
@Override
public
void
onLoginFailed
(
String
reason
)
{
LogUtil
.
i
(
"登录失败:"
+
reason
);
runOnUiThread
(()
->
{
contentTv
.
setText
(
reason
);
});
Logger
.
data
(
"fastsdkdemo"
,
"登录失败:"
+
reason
);
setText
(
">>登录失败"
);
}
@Override
public
void
onLogout
(
Object
...
var1
)
{
contentTv
.
setText
(
"已登出"
);
Logger
.
data
(
"fastsdkdemo"
,
"已登出"
);
setText
(
">>已登出"
);
isLogin
=
false
;
}
};
FastSdk
.
hlPaymentListener
=
new
HLPaymentListener
()
{
@Override
public
void
onPaySuccess
(
String
result
)
{
Logger
.
data
(
"fastsdkdemo"
,
"支付成功 "
+
result
);
setText
(
">>支付成功"
);
}
@Override
public
void
onPayFailed
(
String
reason
)
{
Logger
.
data
(
"fastsdkdemo"
,
"支付失败:"
+
reason
);
setText
(
">>支付失败"
);
}
@Override
public
void
onQuerySuccess
(
List
<
GoodsInfo
>
list
)
{
Logger
.
data
(
"fastsdkdemo"
,
"商品信息获取成功:"
+
list
.
toString
());
ProductUtils
.
showProducts
(
MainActivity
.
this
,
list
);
setText
(
">>商品信息获取成功"
);
}
};
FastSdk
.
onCreate
(
this
);
FastSdk
.
onCreate
(
MainActivity
.
this
);
setText
(
"调用初始化"
);
}
//=========================以下是模拟游戏调用,都是必接接口========================================
/**
* 登录调用,必接
*
* @param view
*/
public
void
onClickLogin
(
View
view
)
{
FastSdk
.
login
();
@Override
protected
void
onSaveInstanceState
(
Bundle
outState
)
{
super
.
onSaveInstanceState
(
outState
);
FastSdk
.
onSaveInstanceState
(
outState
);
}
/**
* 登出,必接
*/
public
void
onClickInit
(
View
view
)
{
hoolaiSdkInit
();
@Override
protected
void
onStart
()
{
super
.
onStart
();
FastSdk
.
onStart
(
this
);
}
public
void
logout
(
View
view
)
{
FastSdk
.
logout
();
if
(
userResponse
!=
null
)
{
}
else
{
Toast
.
makeText
(
GameActivity
.
this
,
"请先登录"
,
Toast
.
LENGTH_SHORT
).
show
();
}
@Override
protected
void
onResume
()
{
Logger
.
data
(
"fastsdkdemo"
,
"游戏页面onResume"
);
super
.
onResume
();
FastSdk
.
onResume
(
this
);
}
/**
* 海外版sdk需要通过此接口获取商品信息进行UI展示,商品信息会根据区域自动转化币种
* 上国内渠道此接口可不接入,海外版必接
*/
public
void
getPrceInfo
(
View
view
)
{
if
(
userResponse
==
null
)
{
Toast
.
makeText
(
this
,
"请先登录!"
,
Toast
.
LENGTH_SHORT
).
show
();
return
;
}
if
(
TextUtils
.
isEmpty
(
userResponse
.
getUid
()
+
""
))
{
Toast
.
makeText
(
this
,
"请先登录!"
,
Toast
.
LENGTH_SHORT
).
show
();
return
;
}
FastSdk
.
getProductInfo
(
null
,
new
HLProductInfoListener
()
{
@Override
public
void
onQuerySuccess
(
final
List
<
ProductParams
>
list
)
{
LogUtil
.
i
(
"商品信息获取成功:"
+
list
.
toString
());
if
(
list
.
size
()
==
0
)
{
Toast
.
makeText
(
GameActivity
.
this
,
"商品信息获取为空"
,
Toast
.
LENGTH_SHORT
).
show
();
return
;
}
//游戏获取到商品信息之后可以展示到游戏商品界面
//游戏需要有一套默认的商品信息配置,如果通过此接口获取不到商品信息时使用默认的商品配置
//---------------以下是demo代码-----------------------------------------------
Context
context
;
AlertDialog
.
Builder
builder
=
new
AlertDialog
.
Builder
(
GameActivity
.
this
);
ListView
listView
=
new
ListView
(
GameActivity
.
this
);
listView
.
setAdapter
(
new
ArrayAdapter
(
GameActivity
.
this
,
android
.
R
.
layout
.
simple_list_item_1
,
android
.
R
.
id
.
text1
,
list
));
listView
.
setOnItemClickListener
((
parent
,
view1
,
position
,
id
)
->
{
ProductParams
payInfo
=
list
.
get
(
position
);
// 游戏支付时需要传的参数 示例
PayParams
payParams
=
new
PayParams
();
payParams
.
setItemId
(
payInfo
.
getItemId
());
payParams
.
setItemName
(
payInfo
.
getPriceTag
());
payParams
.
setAmount
(
Integer
.
parseInt
(
payInfo
.
getPrice
()));
payParams
.
setCount
(
1
);
//扩展信息,回调时原样返回,因为各渠道回调参数限制不一致。回调参数暂时只支持长度50。callBackInfo中不要使用这些符号:“|”、“=”、“+”、“/”。
payParams
.
setCallbackInfo
(
"支付扩展信息,游戏透传参数"
+
UUID
.
randomUUID
().
toString
().
replace
(
"-"
,
""
));
payParams
.
addExtendParam
(
"isSupportThirdPayment"
,
"true"
);
//是否支持google之外的三方支付
payParams
.
addExtendParam
(
"payType"
,
"1"
);
// 1 钱包(默认此类型) 2 点卡,短代类支付,需要通过FastSdk.supportShortterm查询
payParams
.
addExtendParam
(
"currency"
,
payInfo
.
getPriceLocal
());
//币种
FastSdk
.
pay
(
GameActivity
.
this
,
payParams
);
});
builder
.
setView
(
listView
);
builder
.
show
();
}
@Override
public
void
onQueryFailed
(
String
s
)
{
LogUtil
.
i
(
"商品信息获取失败:"
+
s
);
Toast
.
makeText
(
GameActivity
.
this
,
"商品信息获取失败:"
+
s
,
Toast
.
LENGTH_SHORT
).
show
();
}
});
@Override
protected
void
onStop
()
{
super
.
onStop
();
FastSdk
.
onStop
(
this
);
}
/**
* 支付调用,必接
*/
public
void
onPay
(
View
view
)
{
pay
(
1
);
@Override
protected
void
onPause
()
{
super
.
onPause
();
FastSdk
.
onPause
(
this
);
}
@Override
protected
void
onRestart
()
{
super
.
onRestart
();
Logger
.
data
(
"fastsdkdemo"
,
"游戏页面onRestart"
);
FastSdk
.
onRestart
(
this
);
}
public
void
customPay
(
View
view
)
{
String
amount
=
String
.
valueOf
(
et_tv
.
getText
());
if
(
TextUtils
.
isEmpty
(
amount
))
{
Toast
.
makeText
(
GameActivity
.
this
,
"输入金额不能为空"
,
Toast
.
LENGTH_SHORT
).
show
();
return
;
}
pay
(
Integer
.
valueOf
(
amount
));
@Override
protected
void
onDestroy
()
{
super
.
onDestroy
();
FastSdk
.
onDestroy
(
this
);
}
private
void
pay
(
int
amount
)
{
if
(
userResponse
==
null
)
{
Toast
.
makeText
(
this
,
"请先登录!"
,
Toast
.
LENGTH_SHORT
).
show
(
);
return
;
}
@Override
protected
void
onNewIntent
(
Intent
intent
)
{
super
.
onNewIntent
(
intent
);
FastSdk
.
onNewIntent
(
intent
)
;
}
PayParams
payParams
=
new
PayParams
();
payParams
.
setItemId
(
"aaa.bbb.cc"
);
//商品,要保证游戏内各个商品唯一(可以不传)
//ItemName要求:这些特殊符号都不要有: + % # “ & / ? $ ^ *:) \ < > , |。否则会造成某些渠道支付报错如:华为渠道
payParams
.
setItemName
(
"钻石"
);
//购买物品名称
payParams
.
setAmount
(
amount
);
//金额(分)
payParams
.
setCount
(
1
);
//购买商品数量,例如50元宝,传值50
payParams
.
setCallbackInfo
(
"callbackInfo"
);
//扩展信息,回调时原样返回,因为各渠道回调参数限制不一致。回调参数暂时只支持长度50。callBackInfo中不要使用这些符号:“|”、“=”、“+”、“/”。
payParams
.
setCurrency
(
"CNY"
);
//国内可不传或CNY
FastSdk
.
pay
(
GameActivity
.
this
,
payParams
);
//支付服务端回调地址,请在产品信息里配置。
@Override
protected
void
onActivityResult
(
int
requestCode
,
int
resultCode
,
Intent
data
)
{
FastSdk
.
onActivityResult
(
this
,
requestCode
,
resultCode
,
data
);
}
@Override
public
void
onRequestPermissionsResult
(
int
requestCode
,
String
[]
permissions
,
int
[]
grantResults
)
{
super
.
onRequestPermissionsResult
(
requestCode
,
permissions
,
grantResults
);
FastSdk
.
onRequestPermissionsResult
(
requestCode
,
permissions
,
grantResults
);
}
/**
* 退出接口调用,必接
*/
public
void
onExit
(
View
view
)
{
exit
();
@Override
public
void
onConfigurationChanged
(
Configuration
newConfig
)
{
super
.
onConfigurationChanged
(
newConfig
);
FastSdk
.
onConfigurationChanged
(
this
,
newConfig
,
getResources
());
}
public
void
exit
()
{
@Override
public
void
onBackPressed
()
{
setText
(
"调用返回"
);
FastSdk
.
exit
();
}
/**
* 账号管理,母包没有点击效果,渠道包会展示账号管理界面
*
* @param view
*/
public
void
onClickAccountmanage
(
View
view
)
{
// 管理账号接口
WebviewActivity
.
start
(
this
);
// if(userResponse==null){
// Toast.makeText(this,"请先登录!",Toast.LENGTH_SHORT).show();
// return ;
// }
public
void
init
(
View
v
){
setText
(
"调用初始化"
);
FastSdk
.
onCreate
(
this
);
}
public
void
onRealName
(
View
view
)
{
if
(
userResponse
==
null
)
{
Toast
.
makeText
(
this
,
"请先登录!"
,
Toast
.
LENGTH_SHORT
).
show
();
return
;
public
void
login
(
View
v
){
if
(
isInit
){
setText
(
"调用登录"
);
FastSdk
.
login
();
}
else
{
ToastUtils
.
toast
(
"请先初始化"
);
}
/* *
* activity 游戏activity
* RealNameAuthCallBack 查询回调
* needRealNameAuth 预留字段暂未使用,未实名时是否需要引导玩家实名
*/
FastSdk
.
getRealNameAuth
(
new
HLRealNameListener
()
{
/**
* 已实名回调
* @param isAdult 是否成年,部分渠道未提供为null
* @param age 年龄,部分渠道未提供为null
* @param realName 真实姓名,部分渠道未提供为null
*/
@Override
public
void
onSuccess
(
Boolean
isAdult
,
Integer
age
,
String
realName
)
{
//游戏根据回调信息进行防沉迷处理
Toast
.
makeText
(
GameActivity
.
this
,
"已实名,已成年:"
+
isAdult
+
",年龄:"
+
age
+
",姓名:"
+
realName
,
Toast
.
LENGTH_SHORT
).
show
();
}
/**
* 未实名或查询异常
* @param msg 信息
*/
@Override
public
void
onFail
(
String
msg
)
{
//游戏进行防沉迷处理
Toast
.
makeText
(
GameActivity
.
this
,
"实名失败:"
+
msg
,
Toast
.
LENGTH_SHORT
).
show
();
}
/**
* 渠道不支持查询实名信息
*/
@Override
public
void
notSupport
()
{
//游戏进行防沉迷处理
Toast
.
makeText
(
GameActivity
.
this
,
"渠道不支持实名查询"
,
Toast
.
LENGTH_SHORT
).
show
();
}
},
true
);
}
/**
* 数据上报,必接
*
* @param view
*/
public
void
createRole
(
View
view
)
{
if
(
userResponse
==
null
)
{
Toast
.
makeText
(
this
,
"请先登录!"
,
Toast
.
LENGTH_SHORT
).
show
();
return
;
public
void
createRole
(
View
v
){
if
(
isLogin
){
setText
(
"创角报送"
);
FastSdk
.
report
(
EventType
.
CreateRole
,
getPlayerInfo
());
}
else
{
ToastUtils
.
toast
(
"请先登录"
);
}
Logger
.
i
(
"上报创角"
);
sendPlayRoleInfo
(
EventType
.
CreateRole
);
// sendPlayRoleInfo(EventType.CustomerAction);
}
public
void
enterSever
(
View
view
)
{
if
(
userResponse
==
null
)
{
Toast
.
makeText
(
this
,
"请先登录!"
,
Toast
.
LENGTH_SHORT
).
show
();
return
;
public
void
enterSever
(
View
v
){
if
(
isLogin
){
setText
(
"进服报送"
);
FastSdk
.
report
(
EventType
.
EnterServer
,
getPlayerInfo
());
}
else
{
ToastUtils
.
toast
(
"请先登录"
);
}
Logger
.
i
(
"上报进服"
);
sendPlayRoleInfo
(
EventType
.
EnterServer
);
}
public
void
levelUp
(
View
view
)
{
if
(
userResponse
==
null
)
{
Toast
.
makeText
(
this
,
"请先登录!"
,
Toast
.
LENGTH_SHORT
).
show
();
return
;
public
void
levelUp
(
View
v
){
if
(
isLogin
){
setText
(
"升级报送"
);
FastSdk
.
report
(
EventType
.
LevelUp
,
getPlayerInfo
());
}
else
{
ToastUtils
.
toast
(
"请先登录"
);
}
Logger
.
i
(
"上报升级"
);
sendPlayRoleInfo
(
EventType
.
LevelUp
);
}
private
void
sendPlayRoleInfo
(
EventType
eventType
)
{
PlayerInfo
playerInfo
=
new
PlayerInfo
();
playerInfo
.
setRoleId
(
"32424"
);
//角色唯一标识id
playerInfo
.
setRoleName
(
"昵称"
);
playerInfo
.
setRoleLevel
(
"6"
);
playerInfo
.
setZoneId
(
"1"
);
playerInfo
.
setZoneName
(
"华东大区"
);
playerInfo
.
setServerId
(
"1区"
);
playerInfo
.
setServerName
(
"区名称"
);
playerInfo
.
setBalance
(
"66"
);
playerInfo
.
setVip
(
"5"
);
playerInfo
.
setPartyName
(
"帮派名称"
);
playerInfo
.
setClassField
(
""
);
playerInfo
.
setExtendAction
(
"点位名称"
);
playerInfo
.
setExtra
(
"a:aaam,b:bbbb"
);
//扩展信息,格式:key:value,key:value
// playerInfo.setAppVersion("");
// playerInfo.setAppResVersion("");
// playerInfo.setRoleCreateTime("");
// playerInfo.setPhylum("");
//对于sdk海外版自定义事件报送,需要在传ACTION的时候做如下处理,中文版可以忽略
//userExtData.put(UserExtDataKeys.ACTION, "oversea_custom");
//userExtData.put(UserExtDataKeys.CUSTOM_KEY,"海外版自定义事件名称");
FastSdk
.
report
(
eventType
,
playerInfo
);
public
void
customTrack
(
View
v
){
if
(
isLogin
){
setText
(
"自定义报送"
);
FastSdk
.
report
(
EventType
.
CustomerAction
,
getPlayerInfo
());
}
else
{
ToastUtils
.
toast
(
"请先初始化"
);
}
}
public
void
setProxy
(
View
v
)
{
settingProxy
();
public
void
logout
(
View
v
){
if
(
isLogin
){
setText
(
"调用登出"
);
FastSdk
.
logout
();
}
else
{
ToastUtils
.
toast
(
"请先登录"
);
}
}
private
void
settingProxy
()
{
String
pwd
=
et_ip_pwd
.
getText
().
toString
();
String
host
=
et_ip_host
.
getText
().
toString
();
String
port
=
et_ip_port
.
getText
().
toString
();
if
(!
TextUtils
.
isEmpty
(
host
)
&&
!
TextUtils
.
isEmpty
(
pwd
)
&&
!
TextUtils
.
isEmpty
(
port
))
{
FastSdk
.
setProxy
(
pwd
,
host
,
port
);
ToastUtils
.
toast
(
"设置代理:"
+
host
+
",pwd:"
+
pwd
+
",prot:"
+
port
);
hoolaiSdkInit
();
}
else
{
hoolaiSdkInit
();
public
void
getPriceInfo
(
View
v
){
if
(
isLogin
){
setText
(
"查询商品"
);
FastSdk
.
queryGoodsInfo
();
}
else
{
ToastUtils
.
toast
(
"请先登录"
);
}
}
public
void
setRpc
(
View
v
)
{
String
pwd
=
et_pwd
.
getText
().
toString
();
String
host
=
et_rpc
.
getText
().
toString
();
if
(
TextUtils
.
isEmpty
(
host
)
||
TextUtils
.
isEmpty
(
pwd
))
{
ToastUtils
.
toast
(
"ip或密码不可为空"
);
return
;
public
void
doPay
(
View
v
){
if
(
isLogin
){
int
amount
=
1
;
//单位:分
setText
(
"调用支付"
);
FastSdk
.
pay
(
this
,
getPayParams
(
amount
));
}
else
{
ToastUtils
.
toast
(
"请先登录"
);
}
//FastSdk.setRpc(pwd, host);
}
public
void
onExit
(
View
v
){
setText
(
"调用退出"
);
FastSdk
.
exit
();
}
@Override
public
Resources
getResources
()
{
return
FastSdk
.
getResources
(
super
.
getResources
());
private
PlayerInfo
getPlayerInfo
(){
PlayerInfo
playerInfo
=
new
PlayerInfo
();
playerInfo
.
setRoleId
(
"1235761"
);
//角色唯一标识id
playerInfo
.
setRoleName
(
"昵称2"
);
playerInfo
.
setRoleLevel
(
"11"
);
playerInfo
.
setZoneId
(
"100"
);
playerInfo
.
setZoneName
(
"华东大区"
);
playerInfo
.
setServerId
(
"100"
);
playerInfo
.
setServerName
(
"大唐战机"
);
playerInfo
.
setBalance
(
"66"
);
playerInfo
.
setVip
(
"1"
);
playerInfo
.
setPartyName
(
"帮派名称"
);
playerInfo
.
setClassField
(
"aaaa"
);
playerInfo
.
setExtendAction
(
"aaaatest"
);
playerInfo
.
setExtra
(
"a:arm,b:bom"
);
//扩展信息,格式:key:value,key:value
playerInfo
.
setPhylum
(
"1"
);
return
playerInfo
;
}
private
PayParams
getPayParams
(
int
amount
){
PayParams
payParams
=
new
PayParams
();
payParams
.
setItemId
(
"aaa.bbb.cc"
);
//商品,要保证游戏内各个商品唯一(可以不传)
//ItemName要求:这些特殊符号都不要有: + % # “ & / ? $ ^ *:) \ < > , |。否则会造成某些渠道支付报错如:华为渠道
payParams
.
setItemName
(
"钻石"
);
//购买物品名称
payParams
.
setAmount
(
amount
);
//金额(分)
payParams
.
setCount
(
1
);
//购买商品数量,例如50元宝,传值50
payParams
.
setCallbackInfo
(
"callbackInfo"
);
//扩展信息,回调时原样返回,因为各渠道回调参数限制不一致。回调参数暂时只支持长度50。callBackInfo中不要使用这些符号:“|”、“=”、“+”、“/”。
payParams
.
setCurrency
(
"CNY"
);
//国内可不传或CNY
return
payParams
;
}
private
void
setText
(
String
temp
){
str
=
str
+
temp
+
"\n"
;
textview
.
setText
(
str
);
}
}
\ No newline at end of file
app/src/main/java/com/hl/demo/ProductUtils.java
0 → 100644
View file @
a8e3b987
package
com.hl.demo
;
import
android.app.Activity
;
import
android.app.AlertDialog
;
import
android.widget.ArrayAdapter
;
import
android.widget.ListView
;
import
android.widget.Toast
;
import
com.hoolai.access.open.fastaccess.channel.FastSdk
;
import
com.hoolai.access.open.fastaccess.channel.request.GoodsInfo
;
import
com.hoolai.access.open.fastaccess.channel.request.PayParams
;
import
java.util.List
;
import
java.util.UUID
;
public
class
ProductUtils
{
public
static
void
showProducts
(
Activity
activity
,
List
<
GoodsInfo
>
list
){
if
(
list
.
size
()
==
0
)
{
Toast
.
makeText
(
activity
,
"商品信息获取为空"
,
Toast
.
LENGTH_SHORT
).
show
();
return
;
}
AlertDialog
.
Builder
builder
=
new
AlertDialog
.
Builder
(
activity
);
ListView
listView
=
new
ListView
(
activity
);
listView
.
setAdapter
(
new
ArrayAdapter
(
activity
,
android
.
R
.
layout
.
simple_list_item_1
,
android
.
R
.
id
.
text1
,
list
));
listView
.
setOnItemClickListener
((
parent
,
view1
,
position
,
id
)
->
{
GoodsInfo
payInfo
=
list
.
get
(
position
);
// 游戏支付时需要传的参数 示例
PayParams
payParams
=
new
PayParams
();
payParams
.
setItemId
(
payInfo
.
getItemId
());
payParams
.
setItemName
(
payInfo
.
getItemName
());
payParams
.
setAmount
(
Integer
.
parseInt
(
payInfo
.
getItemPrice
()));
payParams
.
setCount
(
Integer
.
valueOf
(
payInfo
.
getItemCount
()));
//扩展信息,回调时原样返回,因为各渠道回调参数限制不一致。回调参数暂时只支持长度50。callBackInfo中不要使用这些符号:“|”、“=”、“+”、“/”。
payParams
.
setCallbackInfo
(
"支付扩展信息,游戏透传参数"
+
UUID
.
randomUUID
().
toString
().
replace
(
"-"
,
""
));
payParams
.
addExtendParam
(
"isSupportThirdPayment"
,
"true"
);
//是否支持google之外的三方支付
payParams
.
addExtendParam
(
"payType"
,
"1"
);
// 1 钱包(默认此类型) 2 点卡,短代类支付,需要通过FastSdk.supportShortterm查询
payParams
.
addExtendParam
(
"currency"
,
payInfo
.
getShowTag
());
//币种
FastSdk
.
pay
(
activity
,
payParams
);
});
builder
.
setView
(
listView
);
builder
.
show
();
}
}
app/src/main/res/layout/activity_example.xml
deleted
100644 → 0
View file @
fd25d4fc
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:background=
"#aaa"
android:orientation=
"vertical"
android:paddingTop=
"@dimen/hl_dp_40"
>
<ScrollView
android:layout_width=
"match_parent"
android:layout_height=
"0dp"
android:layout_weight=
"2"
android:padding=
"3dp"
>
<TextView
android:id=
"@+id/main_tv"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:layout_marginTop=
"5dp"
android:padding=
"5dp"
android:textColor=
"#333"
android:text=
"用户信息用户信息用户信息用户信息用户信息用户信"
android:textSize=
"18sp"
/>
</ScrollView>
<ScrollView
android:layout_width=
"match_parent"
android:layout_height=
"0dp"
android:layout_weight=
"3"
>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:orientation=
"vertical"
>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal"
>
<EditText
android:id=
"@+id/et_ip_host"
android:layout_width=
"match_parent"
android:layout_height=
"48dp"
android:layout_weight=
"1"
android:paddingLeft=
"20dp"
android:text=
"10.1.67.226"
android:textSize=
"14dp"
android:hint=
"ip地址"
/>
<EditText
android:id=
"@+id/et_ip_port"
android:layout_width=
"80dp"
android:layout_height=
"48dp"
android:paddingLeft=
"20dp"
android:text=
"8888"
android:textSize=
"14dp"
android:hint=
"8888"
/>
<EditText
android:id=
"@+id/et_ip_pwd"
android:layout_width=
"match_parent"
android:layout_height=
"48dp"
android:layout_weight=
"1"
android:inputType=
"textPassword"
android:paddingLeft=
"20dp"
android:textSize=
"14dp"
android:hint=
"密码"
/>
<Button
android:layout_width=
"80dp"
android:layout_height=
"48dp"
android:onClick=
"setProxy"
android:text=
"设置代理"
/>
</LinearLayout>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal"
>
<EditText
android:id=
"@+id/et_rpc"
android:layout_width=
"match_parent"
android:layout_height=
"48dp"
android:layout_weight=
"1"
android:paddingLeft=
"20dp"
android:text=
"10.1.4.172"
android:textSize=
"14dp"
android:hint=
"ip地址"
/>
<EditText
android:id=
"@+id/et_pwd"
android:layout_width=
"match_parent"
android:layout_height=
"48dp"
android:layout_weight=
"1"
android:inputType=
"textPassword"
android:paddingLeft=
"20dp"
android:textSize=
"14dp"
android:hint=
"密码"
/>
<Button
android:id=
"@+id/rpcBtn"
android:layout_width=
"80dp"
android:layout_height=
"48dp"
android:onClick=
"setRpc"
android:text=
"设置rpc"
/>
</LinearLayout>
<Button
android:id=
"@+id/init"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:onClick=
"onClickInit"
android:text=
"初始化"
/>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal"
>
<Button
android:id=
"@+id/fragment"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:layout_weight=
"1"
android:onClick=
"onClickLogin"
android:text=
"登录"
/>
<Button
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:onClick=
"logout"
android:layout_weight=
"1"
android:text=
"登出"
/>
</LinearLayout>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal"
>
<Button
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:layout_weight=
"1"
android:onClick=
"getPrceInfo"
android:text=
"商品信息(海外)"
/>
<Button
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:layout_weight=
"1"
android:onClick=
"onPay"
android:text=
"定额支付"
/>
<Button
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:layout_weight=
"1"
android:onClick=
"customPay"
android:text=
"自定义支付"
/>
<EditText
android:id=
"@+id/et_main"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_weight=
"1"
android:gravity=
"center"
android:hint=
"单位分"
android:numeric=
"integer"
android:textColor=
"@android:color/holo_red_light"
android:textSize=
"18sp"
/>
</LinearLayout>
<Button
android:id=
"@+id/fragment_accountmanage"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:onClick=
"onClickAccountmanage"
android:text=
"账号管理"
/>
<Button
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:onClick=
"onExit"
android:text=
"退出"
/>
<Button
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:onClick=
"onRealName"
android:text=
"实名"
/>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal"
>
<Button
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_weight=
"1"
android:layout_gravity=
"center"
android:onClick=
"createRole"
android:text=
"创角"
/>
<Button
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_weight=
"1"
android:layout_gravity=
"center"
android:onClick=
"enterSever"
android:text=
"进服"
/>
<Button
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_weight=
"1"
android:layout_gravity=
"center"
android:onClick=
"levelUp"
android:text=
"升级"
/>
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>
\ No newline at end of file
app/src/main/res/layout/activity_main.xml
0 → 100644
View file @
a8e3b987
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:background=
"#aaa"
android:orientation=
"vertical"
>
<ScrollView
android:layout_width=
"match_parent"
android:layout_height=
"0dp"
android:layout_weight=
"1"
android:layout_margin=
"10dp"
android:padding=
"20dp"
android:fadeScrollbars=
"false"
android:background=
"#eee"
android:fillViewport=
"true"
>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
<TextView
android:id=
"@+id/textview"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:layout_margin=
"4dp"
android:text=
"12"
android:textSize=
"12dp"
android:textColor=
"#111"
/>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"vertical"
>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"48dp"
android:orientation=
"horizontal"
>
<Button
android:id=
"@+id/initBtn"
android:layout_width=
"0dp"
android:layout_height=
"48dp"
android:layout_weight=
"1"
android:layout_gravity=
"center"
android:visibility=
"gone"
android:onClick=
"init"
android:text=
"初始化"
/>
<Button
android:layout_width=
"0dp"
android:layout_height=
"48dp"
android:layout_weight=
"1"
android:layout_gravity=
"center"
android:onClick=
"login"
android:text=
"登录"
/>
</LinearLayout>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"48dp"
android:orientation=
"horizontal"
>
<Button
android:layout_width=
"0dp"
android:layout_height=
"48dp"
android:layout_weight=
"1"
android:layout_gravity=
"center"
android:onClick=
"createRole"
android:text=
"创角"
/>
<Button
android:layout_width=
"0dp"
android:layout_height=
"48dp"
android:layout_weight=
"1"
android:layout_gravity=
"center"
android:onClick=
"enterSever"
android:text=
"进服"
/>
<Button
android:layout_width=
"0dp"
android:layout_height=
"48dp"
android:layout_weight=
"1"
android:layout_gravity=
"center"
android:onClick=
"levelUp"
android:text=
"升级"
/>
<Button
android:layout_width=
"0dp"
android:layout_height=
"48dp"
android:layout_weight=
"1"
android:layout_gravity=
"center"
android:onClick=
"customTrack"
android:text=
"自定义"
/>
</LinearLayout>
<Button
android:layout_width=
"match_parent"
android:layout_height=
"48dp"
android:layout_gravity=
"center"
android:onClick=
"logout"
android:text=
"登出"
/>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"48dp"
android:orientation=
"horizontal"
>
<Button
android:layout_width=
"0dp"
android:layout_height=
"48dp"
android:layout_gravity=
"center"
android:layout_weight=
"1"
android:onClick=
"getPriceInfo"
android:text=
"商品信息(海外)"
/>
<Button
android:layout_width=
"0dp"
android:layout_height=
"48dp"
android:layout_gravity=
"center"
android:layout_weight=
"1"
android:onClick=
"doPay"
android:text=
"定额支付"
/>
</LinearLayout>
<Button
android:layout_width=
"match_parent"
android:layout_height=
"48dp"
android:layout_gravity=
"center"
android:onClick=
"onExit"
android:text=
"退出"
/>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
Prev
1
2
Next
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