Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
mmm-rain
AndroidUtilCode
提交
fdf8b3a4
A
AndroidUtilCode
项目概览
mmm-rain
/
AndroidUtilCode
与 Fork 源项目一致
从无法访问的项目Fork
通知
4
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
A
AndroidUtilCode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
fdf8b3a4
编写于
11月 01, 2018
作者:
B
Blankj
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
see 11/01 log
上级
1c36d1ed
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
1536 addition
and
533 deletion
+1536
-533
app/src/main/java/com/blankj/androidutilcode/base/BaseActivity.java
...in/java/com/blankj/androidutilcode/base/BaseActivity.java
+0
-2
utilcode-kotlin/src/main/java/com/blankj/utilcode/util/LogUtils.java
...tlin/src/main/java/com/blankj/utilcode/util/LogUtils.java
+0
-11
utilcode-kotlin/src/main/java/com/blankj/utilcode/util/LogUtils.kt
...kotlin/src/main/java/com/blankj/utilcode/util/LogUtils.kt
+1021
-0
utilcode-kotlin/src/main/java/com/blankj/utilcode/util/StringUtils.kt
...lin/src/main/java/com/blankj/utilcode/util/StringUtils.kt
+172
-160
utilcode-kotlin/src/main/java/com/blankj/utilcode/util/Utils.java
...-kotlin/src/main/java/com/blankj/utilcode/util/Utils.java
+0
-358
utilcode-kotlin/src/main/java/com/blankj/utilcode/util/Utils.kt
...de-kotlin/src/main/java/com/blankj/utilcode/util/Utils.kt
+317
-0
utilcode-kotlin/src/main/java/com/blankj/utilcode/util/ZipUtils.java
...tlin/src/main/java/com/blankj/utilcode/util/ZipUtils.java
+13
-1
utilcode/src/main/java/com/blankj/utilcode/util/ZipUtils.java
...code/src/main/java/com/blankj/utilcode/util/ZipUtils.java
+13
-1
未找到文件。
app/src/main/java/com/blankj/androidutilcode/base/BaseActivity.java
浏览文件 @
fdf8b3a4
...
...
@@ -8,8 +8,6 @@ import android.support.v7.app.AppCompatActivity;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
com.blankj.utilcode.util.ScreenUtils
;
/**
* <pre>
* author: Blankj
...
...
utilcode-kotlin/src/main/java/com/blankj/utilcode/util/LogUtils.java
浏览文件 @
fdf8b3a4
...
...
@@ -400,7 +400,6 @@ public final class LogUtils {
Log
.
println
(
type
,
tag
,
msg
);
return
;
}
StringBuilder
sb
=
new
StringBuilder
();
String
[]
lines
=
msg
.
split
(
LINE_SEP
);
for
(
String
line
:
lines
)
{
Log
.
println
(
type
,
tag
,
LEFT_BORDER
+
line
);
...
...
@@ -577,16 +576,6 @@ public final class LogUtils {
return
file
!=
null
&&
(
file
.
exists
()
?
file
.
isDirectory
()
:
file
.
mkdirs
());
}
private
static
boolean
isSpace
(
final
String
s
)
{
if
(
s
==
null
)
return
true
;
for
(
int
i
=
0
,
len
=
s
.
length
();
i
<
len
;
++
i
)
{
if
(!
Character
.
isWhitespace
(
s
.
charAt
(
i
)))
{
return
false
;
}
}
return
true
;
}
private
static
void
input2File
(
final
String
input
,
final
String
filePath
)
{
EXECUTOR
.
execute
(
new
Runnable
()
{
@Override
...
...
utilcode-kotlin/src/main/java/com/blankj/utilcode/util/LogUtils.kt
0 → 100644
浏览文件 @
fdf8b3a4
@
file
:
JvmName
(
"LogUtils"
)
package
com.blankj.utilcode.util
import
android.content.ClipData
import
android.content.Intent
import
android.content.pm.PackageManager
import
android.os.Build
import
android.os.Bundle
import
android.os.Environment
import
android.support.annotation.IntDef
import
android.support.annotation.IntRange
import
android.support.annotation.RequiresApi
import
android.support.v4.util.SimpleArrayMap
import
android.util.Log
import
org.json.JSONArray
import
org.json.JSONException
import
org.json.JSONObject
import
java.io.*
import
java.lang.reflect.ParameterizedType
import
java.lang.reflect.Type
import
java.net.UnknownHostException
import
java.text.ParseException
import
java.text.SimpleDateFormat
import
java.util.*
import
java.util.concurrent.Executors
import
javax.xml.transform.OutputKeys
import
javax.xml.transform.TransformerFactory
import
javax.xml.transform.stream.StreamResult
import
javax.xml.transform.stream.StreamSource
const
val
V
=
Log
.
VERBOSE
const
val
D
=
Log
.
DEBUG
const
val
I
=
Log
.
INFO
const
val
W
=
Log
.
WARN
const
val
E
=
Log
.
ERROR
const
val
A
=
Log
.
ASSERT
@IntDef
(
V
,
D
,
I
,
W
,
E
,
A
)
@Retention
(
AnnotationRetention
.
SOURCE
)
annotation
class
TYPE
private
val
T
=
charArrayOf
(
'V'
,
'D'
,
'I'
,
'W'
,
'E'
,
'A'
)
private
val
FILE
=
0x10
private
val
JSON
=
0x20
private
val
XML
=
0x30
private
const
val
TOP_CORNER
=
"┌"
private
const
val
MIDDLE_CORNER
=
"├"
private
const
val
LEFT_BORDER
=
"│ "
private
const
val
BOTTOM_CORNER
=
"└"
private
const
val
SIDE_DIVIDER
=
"────────────────────────────────────────────────────────"
private
const
val
MIDDLE_DIVIDER
=
"┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄"
private
const
val
TOP_BORDER
=
TOP_CORNER
+
SIDE_DIVIDER
+
SIDE_DIVIDER
private
const
val
MIDDLE_BORDER
=
MIDDLE_CORNER
+
MIDDLE_DIVIDER
+
MIDDLE_DIVIDER
private
const
val
BOTTOM_BORDER
=
BOTTOM_CORNER
+
SIDE_DIVIDER
+
SIDE_DIVIDER
private
const
val
MAX_LEN
=
3000
private
const
val
NOTHING
=
"log nothing"
private
const
val
NULL
=
"null"
private
const
val
ARGS
=
"args"
private
const
val
PLACEHOLDER
=
" "
private
val
FILE_SEP
=
System
.
getProperty
(
"file.separator"
)
private
val
LINE_SEP
=
System
.
getProperty
(
"line.separator"
)
private
val
FORMAT
=
SimpleDateFormat
(
"yyyy-MM-dd HH:mm:ss.SSS "
,
Locale
.
getDefault
())
private
val
CONFIG
=
Config
()
private
val
EXECUTOR
=
Executors
.
newSingleThreadExecutor
()
private
val
I_FORMATTER_MAP
=
SimpleArrayMap
<
Class
<
*
>,
IFormatter
<
*
>>()
fun
getConfig
():
Config
{
return
CONFIG
}
fun
v
(
vararg
contents
:
Any
)
{
log
(
V
,
CONFIG
.
mGlobalTag
,
*
contents
)
}
fun
vTag
(
tag
:
String
,
vararg
contents
:
Any
)
{
log
(
V
,
tag
,
*
contents
)
}
fun
d
(
vararg
contents
:
Any
)
{
log
(
D
,
CONFIG
.
mGlobalTag
,
*
contents
)
}
fun
dTag
(
tag
:
String
,
vararg
contents
:
Any
)
{
log
(
D
,
tag
,
*
contents
)
}
fun
i
(
vararg
contents
:
Any
)
{
log
(
I
,
CONFIG
.
mGlobalTag
,
*
contents
)
}
fun
iTag
(
tag
:
String
,
vararg
contents
:
Any
)
{
log
(
I
,
tag
,
*
contents
)
}
fun
w
(
vararg
contents
:
Any
)
{
log
(
W
,
CONFIG
.
mGlobalTag
,
*
contents
)
}
fun
wTag
(
tag
:
String
,
vararg
contents
:
Any
)
{
log
(
W
,
tag
,
*
contents
)
}
fun
e
(
vararg
contents
:
Any
)
{
log
(
E
,
CONFIG
.
mGlobalTag
,
*
contents
)
}
fun
eTag
(
tag
:
String
,
vararg
contents
:
Any
)
{
log
(
E
,
tag
,
*
contents
)
}
fun
a
(
vararg
contents
:
Any
)
{
log
(
A
,
CONFIG
.
mGlobalTag
,
*
contents
)
}
fun
aTag
(
tag
:
String
,
vararg
contents
:
Any
)
{
log
(
A
,
tag
,
*
contents
)
}
fun
file
(
content
:
Any
)
{
log
(
FILE
or
D
,
CONFIG
.
mGlobalTag
,
content
)
}
fun
file
(
@TYPE
type
:
Int
,
content
:
Any
)
{
log
(
FILE
or
type
,
CONFIG
.
mGlobalTag
,
content
)
}
fun
file
(
tag
:
String
,
content
:
Any
)
{
log
(
FILE
or
D
,
tag
,
content
)
}
fun
file
(
@TYPE
type
:
Int
,
tag
:
String
,
content
:
Any
)
{
log
(
FILE
or
type
,
tag
,
content
)
}
fun
json
(
content
:
String
)
{
log
(
JSON
or
D
,
CONFIG
.
mGlobalTag
,
content
)
}
fun
json
(
@TYPE
type
:
Int
,
content
:
String
)
{
log
(
JSON
or
type
,
CONFIG
.
mGlobalTag
,
content
)
}
fun
json
(
tag
:
String
,
content
:
String
)
{
log
(
JSON
or
D
,
tag
,
content
)
}
fun
json
(
@TYPE
type
:
Int
,
tag
:
String
,
content
:
String
)
{
log
(
JSON
or
type
,
tag
,
content
)
}
fun
xml
(
content
:
String
)
{
log
(
XML
or
D
,
CONFIG
.
mGlobalTag
,
content
)
}
fun
xml
(
@TYPE
type
:
Int
,
content
:
String
)
{
log
(
XML
or
type
,
CONFIG
.
mGlobalTag
,
content
)
}
fun
xml
(
tag
:
String
,
content
:
String
)
{
log
(
XML
or
D
,
tag
,
content
)
}
fun
xml
(
@TYPE
type
:
Int
,
tag
:
String
,
content
:
String
)
{
log
(
XML
or
type
,
tag
,
content
)
}
fun
log
(
type
:
Int
,
tag
:
String
?,
vararg
contents
:
Any
)
{
if
(!
CONFIG
.
mLogSwitch
||
!
CONFIG
.
mLog2ConsoleSwitch
&&
!
CONFIG
.
mLog2FileSwitch
)
return
val
type_low
=
type
and
0x0f
val
type_high
=
type
and
0xf0
if
(
type_low
<
CONFIG
.
mConsoleFilter
&&
type_low
<
CONFIG
.
mFileFilter
)
return
val
tagHead
=
processTagAndHead
(
tag
)
val
body
=
processBody
(
type_high
,
*
contents
)
if
(
CONFIG
.
mLog2ConsoleSwitch
&&
type_low
>=
CONFIG
.
mConsoleFilter
&&
type_high
!=
FILE
)
{
print2Console
(
type_low
,
tagHead
.
tag
,
tagHead
.
consoleHead
,
body
)
}
if
((
CONFIG
.
mLog2FileSwitch
||
type_high
==
FILE
)
&&
type_low
>=
CONFIG
.
mFileFilter
)
{
print2File
(
type_low
,
tagHead
.
tag
,
tagHead
.
fileHead
+
body
)
}
}
private
fun
processTagAndHead
(
tag
:
String
?):
TagHead
{
var
tag
=
tag
if
(!
CONFIG
.
mTagIsSpace
&&
!
CONFIG
.
mLogHeadSwitch
)
{
tag
=
CONFIG
.
mGlobalTag
}
else
{
val
stackTrace
=
Throwable
().
stackTrace
val
stackIndex
=
3
+
CONFIG
.
mStackOffset
if
(
stackIndex
>=
stackTrace
.
size
)
{
val
targetElement
=
stackTrace
[
3
]
val
fileName
=
getFileName
(
targetElement
)
if
(
CONFIG
.
mTagIsSpace
&&
isSpace
(
tag
))
{
val
index
=
fileName
.
indexOf
(
'.'
)
// Use proguard may not find '.'.
tag
=
if
(
index
==
-
1
)
fileName
else
fileName
.
substring
(
0
,
index
)
}
return
TagHead
(
tag
,
null
,
": "
)
}
var
targetElement
=
stackTrace
[
stackIndex
]
val
fileName
=
getFileName
(
targetElement
)
if
(
CONFIG
.
mTagIsSpace
&&
isSpace
(
tag
))
{
val
index
=
fileName
.
indexOf
(
'.'
)
// Use proguard may not find '.'.
tag
=
if
(
index
==
-
1
)
fileName
else
fileName
.
substring
(
0
,
index
)
}
if
(
CONFIG
.
mLogHeadSwitch
)
{
val
tName
=
Thread
.
currentThread
().
name
val
head
=
Formatter
()
.
format
(
"%s, %s.%s(%s:%d)"
,
tName
,
targetElement
.
className
,
targetElement
.
methodName
,
fileName
,
targetElement
.
lineNumber
)
.
toString
()
val
fileHead
=
" [$head]: "
if
(
CONFIG
.
mStackDeep
<=
1
)
{
return
TagHead
(
tag
,
arrayOf
(
head
),
fileHead
)
}
else
{
val
consoleHead
=
arrayOfNulls
<
String
>(
Math
.
min
(
CONFIG
.
mStackDeep
,
stackTrace
.
size
-
stackIndex
))
consoleHead
[
0
]
=
head
val
spaceLen
=
tName
.
length
+
2
val
space
=
Formatter
().
format
(
"%"
+
spaceLen
+
"s"
,
""
).
toString
()
var
i
=
1
val
len
=
consoleHead
.
size
while
(
i
<
len
)
{
targetElement
=
stackTrace
[
i
+
stackIndex
]
consoleHead
[
i
]
=
Formatter
()
.
format
(
"%s%s.%s(%s:%d)"
,
space
,
targetElement
.
className
,
targetElement
.
methodName
,
getFileName
(
targetElement
),
targetElement
.
lineNumber
)
.
toString
()
++
i
}
return
TagHead
(
tag
,
consoleHead
,
fileHead
)
}
}
}
return
TagHead
(
tag
,
null
,
": "
)
}
private
fun
getFileName
(
targetElement
:
StackTraceElement
):
String
{
val
fileName
=
targetElement
.
fileName
if
(
fileName
!=
null
)
return
fileName
// If name of file is null, should add
// "-keepattributes SourceFile,LineNumberTable" in proguard file.
var
className
=
targetElement
.
className
val
classNameInfo
=
className
.
split
(
"\\."
.
toRegex
()).
dropLastWhile
{
it
.
isEmpty
()
}.
toTypedArray
()
if
(
classNameInfo
.
size
>
0
)
{
className
=
classNameInfo
[
classNameInfo
.
size
-
1
]
}
val
index
=
className
.
indexOf
(
'$'
)
if
(
index
!=
-
1
)
{
className
=
className
.
substring
(
0
,
index
)
}
return
"$className.java"
}
private
fun
processBody
(
type
:
Int
,
vararg
contents
:
Any
):
String
{
var
body
=
NULL
if
(
contents
!=
null
)
{
if
(
contents
.
size
==
1
)
{
body
=
formatObject
(
type
,
contents
[
0
])
}
else
{
val
sb
=
StringBuilder
()
var
i
=
0
val
len
=
contents
.
size
while
(
i
<
len
)
{
val
content
=
contents
[
i
]
sb
.
append
(
ARGS
)
.
append
(
"["
)
.
append
(
i
)
.
append
(
"]"
)
.
append
(
" = "
)
.
append
(
formatObject
(
content
))
.
append
(
LINE_SEP
)
++
i
}
body
=
sb
.
toString
()
}
}
return
if
(
body
.
length
==
0
)
NOTHING
else
body
}
private
fun
formatObject
(
type
:
Int
,
obj
:
Any
?):
String
{
if
(
obj
==
null
)
return
NULL
if
(
type
==
JSON
)
return
LogFormatter
.
formatJson
(
obj
.
toString
())
return
if
(
type
==
XML
)
LogFormatter
.
formatXml
(
obj
.
toString
())
else
formatObject
(
obj
)
}
private
fun
formatObject
(
obj
:
Any
?):
String
{
if
(
obj
==
null
)
return
NULL
if
(!
I_FORMATTER_MAP
.
isEmpty
)
{
val
iFormatter
=
I_FORMATTER_MAP
.
get
(
getClassFromObject
(
obj
))
if
(
iFormatter
!=
null
)
{
return
iFormatter
.
format
(
obj
)
}
}
if
(
obj
.
javaClass
.
isArray
)
return
LogFormatter
.
array2String
(
obj
)
if
(
obj
is
Throwable
)
return
LogFormatter
.
throwable2String
(
obj
as
Throwable
?)
if
(
obj
is
Bundle
)
return
LogFormatter
.
bundle2String
((
obj
as
Bundle
?)
!!
)
return
if
(
obj
is
Intent
)
LogFormatter
.
intent2String
((
obj
as
Intent
?)
!!
)
else
obj
.
toString
()
}
private
fun
print2Console
(
type
:
Int
,
tag
:
String
,
head
:
Array
<
String
>,
msg
:
String
)
{
if
(
CONFIG
.
mSingleTagSwitch
)
{
printSingleTagMsg
(
type
,
tag
,
processSingleTagMsg
(
type
,
tag
,
head
,
msg
))
}
else
{
printBorder
(
type
,
tag
,
true
)
printHead
(
type
,
tag
,
head
)
printMsg
(
type
,
tag
,
msg
)
printBorder
(
type
,
tag
,
false
)
}
}
private
fun
printBorder
(
type
:
Int
,
tag
:
String
,
isTop
:
Boolean
)
{
if
(
CONFIG
.
mLogBorderSwitch
)
{
Log
.
println
(
type
,
tag
,
if
(
isTop
)
TOP_BORDER
else
BOTTOM_BORDER
)
}
}
private
fun
printHead
(
type
:
Int
,
tag
:
String
,
head
:
Array
<
String
>?)
{
if
(
head
!=
null
)
{
for
(
aHead
in
head
)
{
Log
.
println
(
type
,
tag
,
if
(
CONFIG
.
mLogBorderSwitch
)
LEFT_BORDER
+
aHead
else
aHead
)
}
if
(
CONFIG
.
mLogBorderSwitch
)
Log
.
println
(
type
,
tag
,
MIDDLE_BORDER
)
}
}
private
fun
printMsg
(
type
:
Int
,
tag
:
String
,
msg
:
String
)
{
val
len
=
msg
.
length
val
countOfSub
=
len
/
MAX_LEN
if
(
countOfSub
>
0
)
{
var
index
=
0
for
(
i
in
0
until
countOfSub
)
{
printSubMsg
(
type
,
tag
,
msg
.
substring
(
index
,
index
+
MAX_LEN
))
index
+=
MAX_LEN
}
if
(
index
!=
len
)
{
printSubMsg
(
type
,
tag
,
msg
.
substring
(
index
,
len
))
}
}
else
{
printSubMsg
(
type
,
tag
,
msg
)
}
}
private
fun
printSubMsg
(
type
:
Int
,
tag
:
String
,
msg
:
String
)
{
if
(!
CONFIG
.
mLogBorderSwitch
)
{
Log
.
println
(
type
,
tag
,
msg
)
return
}
val
sb
=
StringBuilder
()
val
lines
=
msg
.
split
(
LINE_SEP
.
toRegex
()).
dropLastWhile
{
it
.
isEmpty
()
}.
toTypedArray
()
for
(
line
in
lines
)
{
Log
.
println
(
type
,
tag
,
LEFT_BORDER
+
line
)
}
}
private
fun
processSingleTagMsg
(
type
:
Int
,
tag
:
String
,
head
:
Array
<
String
>?,
msg
:
String
):
String
{
val
sb
=
StringBuilder
()
sb
.
append
(
PLACEHOLDER
).
append
(
LINE_SEP
)
if
(
CONFIG
.
mLogBorderSwitch
)
{
sb
.
append
(
TOP_BORDER
).
append
(
LINE_SEP
)
if
(
head
!=
null
)
{
for
(
aHead
in
head
)
{
sb
.
append
(
LEFT_BORDER
).
append
(
aHead
).
append
(
LINE_SEP
)
}
sb
.
append
(
MIDDLE_BORDER
).
append
(
LINE_SEP
)
}
for
(
line
in
msg
.
split
(
LINE_SEP
.
toRegex
()).
dropLastWhile
{
it
.
isEmpty
()
}.
toTypedArray
())
{
sb
.
append
(
LEFT_BORDER
).
append
(
line
).
append
(
LINE_SEP
)
}
sb
.
append
(
BOTTOM_BORDER
)
}
else
{
if
(
head
!=
null
)
{
for
(
aHead
in
head
)
{
sb
.
append
(
aHead
).
append
(
LINE_SEP
)
}
}
sb
.
append
(
msg
)
}
return
sb
.
toString
()
}
private
fun
printSingleTagMsg
(
type
:
Int
,
tag
:
String
,
msg
:
String
)
{
val
len
=
msg
.
length
val
countOfSub
=
len
/
MAX_LEN
if
(
countOfSub
>
0
)
{
if
(
CONFIG
.
mLogBorderSwitch
)
{
Log
.
println
(
type
,
tag
,
msg
.
substring
(
0
,
MAX_LEN
)
+
LINE_SEP
+
BOTTOM_BORDER
)
var
index
=
MAX_LEN
for
(
i
in
1
until
countOfSub
)
{
Log
.
println
(
type
,
tag
,
PLACEHOLDER
+
LINE_SEP
+
TOP_BORDER
+
LINE_SEP
+
LEFT_BORDER
+
msg
.
substring
(
index
,
index
+
MAX_LEN
)
+
LINE_SEP
+
BOTTOM_BORDER
)
index
+=
MAX_LEN
}
if
(
index
!=
len
)
{
Log
.
println
(
type
,
tag
,
PLACEHOLDER
+
LINE_SEP
+
TOP_BORDER
+
LINE_SEP
+
LEFT_BORDER
+
msg
.
substring
(
index
,
len
))
}
}
else
{
Log
.
println
(
type
,
tag
,
msg
.
substring
(
0
,
MAX_LEN
))
var
index
=
MAX_LEN
for
(
i
in
1
until
countOfSub
)
{
Log
.
println
(
type
,
tag
,
PLACEHOLDER
+
LINE_SEP
+
msg
.
substring
(
index
,
index
+
MAX_LEN
))
index
+=
MAX_LEN
}
if
(
index
!=
len
)
{
Log
.
println
(
type
,
tag
,
PLACEHOLDER
+
LINE_SEP
+
msg
.
substring
(
index
,
len
))
}
}
}
else
{
Log
.
println
(
type
,
tag
,
msg
)
}
}
private
fun
print2File
(
type
:
Int
,
tag
:
String
,
msg
:
String
)
{
val
now
=
Date
(
System
.
currentTimeMillis
())
val
format
=
FORMAT
.
format
(
now
)
val
date
=
format
.
substring
(
0
,
10
)
val
time
=
format
.
substring
(
11
)
val
fullPath
=
((
if
(
CONFIG
.
mDir
==
null
)
CONFIG
.
mDefaultDir
else
CONFIG
.
mDir
)
+
CONFIG
.
mFilePrefix
+
"-"
+
date
+
".txt"
)
if
(!
createOrExistsFile
(
fullPath
))
{
Log
.
e
(
"LogUtils"
,
"create $fullPath failed!"
)
return
}
val
sb
=
StringBuilder
()
sb
.
append
(
time
)
.
append
(
T
[
type
-
V
])
.
append
(
"/"
)
.
append
(
tag
)
.
append
(
msg
)
.
append
(
LINE_SEP
)
val
content
=
sb
.
toString
()
input2File
(
content
,
fullPath
)
}
private
fun
createOrExistsFile
(
filePath
:
String
):
Boolean
{
val
file
=
File
(
filePath
)
if
(
file
.
exists
())
return
file
.
isFile
()
if
(!
createOrExistsDir
(
file
.
getParentFile
()))
return
false
try
{
deleteDueLogs
(
filePath
)
val
isCreate
=
file
.
createNewFile
()
if
(
isCreate
)
{
printDeviceInfo
(
filePath
)
}
return
isCreate
}
catch
(
e
:
IOException
)
{
e
.
printStackTrace
()
return
false
}
}
private
fun
deleteDueLogs
(
filePath
:
String
)
{
val
file
=
File
(
filePath
)
val
parentFile
=
file
.
getParentFile
()
val
files
=
parentFile
.
listFiles
(
object
:
FilenameFilter
()
{
fun
accept
(
dir
:
File
,
name
:
String
):
Boolean
{
return
name
.
matches
((
"^"
+
CONFIG
.
mFilePrefix
+
"-[0-9]{4}-[0-9]{2}-[0-9]{2}.txt$"
).
toRegex
())
}
})
if
(
files
.
size
<=
0
)
return
val
length
=
filePath
.
length
val
sdf
=
SimpleDateFormat
(
"yyyy-MM-dd"
,
Locale
.
getDefault
())
try
{
val
curDay
=
filePath
.
substring
(
length
-
14
,
length
-
4
)
val
dueMillis
=
sdf
.
parse
(
curDay
).
getTime
()
-
CONFIG
.
mSaveDays
*
86400000L
for
(
aFile
in
files
)
{
val
name
=
aFile
.
getName
()
val
l
=
name
.
length
val
logDay
=
name
.
substring
(
l
-
14
,
l
-
4
)
if
(
sdf
.
parse
(
logDay
).
getTime
()
<=
dueMillis
)
{
EXECUTOR
.
execute
(
Runnable
{
val
delete
=
aFile
.
delete
()
if
(!
delete
)
{
Log
.
e
(
"LogUtils"
,
"delete $aFile failed!"
)
}
})
}
}
}
catch
(
e
:
ParseException
)
{
e
.
printStackTrace
()
}
}
private
fun
printDeviceInfo
(
filePath
:
String
)
{
var
versionName
=
""
var
versionCode
=
0
try
{
val
pi
=
Utils
.
getApp
()
.
getPackageManager
()
.
getPackageInfo
(
Utils
.
getApp
().
getPackageName
(),
0
)
if
(
pi
!=
null
)
{
versionName
=
pi
!!
.
versionName
versionCode
=
pi
!!
.
versionCode
}
}
catch
(
e
:
PackageManager
.
NameNotFoundException
)
{
e
.
printStackTrace
()
}
val
time
=
filePath
.
substring
(
filePath
.
length
-
14
,
filePath
.
length
-
4
)
val
head
=
"************* Log Head ****************"
+
"\nDate of Log : "
+
time
+
"\nDevice Manufacturer: "
+
Build
.
MANUFACTURER
+
"\nDevice Model : "
+
Build
.
MODEL
+
"\nAndroid Version : "
+
Build
.
VERSION
.
RELEASE
+
"\nAndroid SDK : "
+
Build
.
VERSION
.
SDK_INT
+
"\nApp VersionName : "
+
versionName
+
"\nApp VersionCode : "
+
versionCode
+
"\n************* Log Head ****************\n\n"
input2File
(
head
,
filePath
)
}
private
fun
createOrExistsDir
(
file
:
File
?):
Boolean
{
return
file
!=
null
&&
if
(
file
!!
.
exists
())
file
!!
.
isDirectory
()
else
file
!!
.
mkdirs
()
}
private
fun
input2File
(
input
:
String
,
filePath
:
String
)
{
EXECUTOR
.
execute
(
Runnable
{
var
bw
:
BufferedWriter
?
=
null
try
{
bw
=
BufferedWriter
(
FileWriter
(
filePath
,
true
))
bw
!!
.
write
(
input
)
}
catch
(
e
:
IOException
)
{
e
.
printStackTrace
()
Log
.
e
(
"LogUtils"
,
"log to $filePath failed!"
)
}
finally
{
try
{
if
(
bw
!=
null
)
{
bw
!!
.
close
()
}
}
catch
(
e
:
IOException
)
{
e
.
printStackTrace
()
}
}
})
}
class
Config
internal
constructor
()
{
var
mDefaultDir
:
String
?
=
null
// The default storage directory of log.
var
mDir
:
String
?
=
null
// The storage directory of log.
var
mFilePrefix
=
"util"
// The file prefix of log.
var
mLogSwitch
=
true
// The switch of log.
var
mLog2ConsoleSwitch
=
true
// The logcat's switch of log.
var
mGlobalTag
:
String
?
=
null
// The global tag of log.
var
mTagIsSpace
=
true
// The global tag is space.
var
mLogHeadSwitch
=
true
// The head's switch of log.
var
mLog2FileSwitch
=
false
// The file's switch of log.
var
mLogBorderSwitch
=
true
// The border's switch of log.
var
mSingleTagSwitch
=
true
// The single tag of log.
var
mConsoleFilter
=
V
// The console's filter of log.
var
mFileFilter
=
V
// The file's filter of log.
var
mStackDeep
=
1
// The stack's deep of log.
var
mStackOffset
=
0
// The stack's offset of log.
var
mSaveDays
=
-
1
// The save days of log.
init
{
if
(
mDefaultDir
!=
null
)
return
if
(
Environment
.
MEDIA_MOUNTED
.
equals
(
Environment
.
getExternalStorageState
())
&&
Utils
.
getApp
().
getExternalCacheDir
()
!=
null
)
mDefaultDir
=
Utils
.
getApp
().
getExternalCacheDir
()
+
FILE_SEP
+
"log"
+
FILE_SEP
else
{
mDefaultDir
=
Utils
.
getApp
().
getCacheDir
()
+
FILE_SEP
+
"log"
+
FILE_SEP
}
}
fun
setLogSwitch
(
logSwitch
:
Boolean
):
Config
{
mLogSwitch
=
logSwitch
return
this
}
fun
setConsoleSwitch
(
consoleSwitch
:
Boolean
):
Config
{
mLog2ConsoleSwitch
=
consoleSwitch
return
this
}
fun
setGlobalTag
(
tag
:
String
):
Config
{
if
(
isSpace
(
tag
))
{
mGlobalTag
=
""
mTagIsSpace
=
true
}
else
{
mGlobalTag
=
tag
mTagIsSpace
=
false
}
return
this
}
fun
setLogHeadSwitch
(
logHeadSwitch
:
Boolean
):
Config
{
mLogHeadSwitch
=
logHeadSwitch
return
this
}
fun
setLog2FileSwitch
(
log2FileSwitch
:
Boolean
):
Config
{
mLog2FileSwitch
=
log2FileSwitch
return
this
}
fun
setDir
(
dir
:
String
):
Config
{
if
(
isSpace
(
dir
))
{
mDir
=
null
}
else
{
mDir
=
if
(
dir
.
endsWith
(
FILE_SEP
))
dir
else
dir
+
FILE_SEP
}
return
this
}
fun
setDir
(
dir
:
File
?):
Config
{
mDir
=
if
(
dir
==
null
)
null
else
dir
!!
.
getAbsolutePath
()
+
FILE_SEP
return
this
}
fun
setFilePrefix
(
filePrefix
:
String
):
Config
{
if
(
isSpace
(
filePrefix
))
{
mFilePrefix
=
"util"
}
else
{
mFilePrefix
=
filePrefix
}
return
this
}
fun
setBorderSwitch
(
borderSwitch
:
Boolean
):
Config
{
mLogBorderSwitch
=
borderSwitch
return
this
}
fun
setSingleTagSwitch
(
singleTagSwitch
:
Boolean
):
Config
{
mSingleTagSwitch
=
singleTagSwitch
return
this
}
fun
setConsoleFilter
(
@TYPE
consoleFilter
:
Int
):
Config
{
mConsoleFilter
=
consoleFilter
return
this
}
fun
setFileFilter
(
@TYPE
fileFilter
:
Int
):
Config
{
mFileFilter
=
fileFilter
return
this
}
fun
setStackDeep
(
@IntRange
(
from
=
1
)
stackDeep
:
Int
):
Config
{
mStackDeep
=
stackDeep
return
this
}
fun
setStackOffset
(
@IntRange
(
from
=
0
)
stackOffset
:
Int
):
Config
{
mStackOffset
=
stackOffset
return
this
}
fun
setSaveDays
(
@IntRange
(
from
=
1
)
saveDays
:
Int
):
Config
{
mSaveDays
=
saveDays
return
this
}
fun
<
T
>
addFormatter
(
iFormatter
:
IFormatter
<
T
>?):
Config
{
if
(
iFormatter
!=
null
)
{
I_FORMATTER_MAP
.
put
(
getTypeClassFromParadigm
(
iFormatter
),
iFormatter
)
}
return
this
}
override
fun
toString
():
String
{
return
(
"switch: "
+
mLogSwitch
+
LINE_SEP
+
"console: "
+
mLog2ConsoleSwitch
+
LINE_SEP
+
"tag: "
+
(
if
(
mTagIsSpace
)
"null"
else
mGlobalTag
)
+
LINE_SEP
+
"head: "
+
mLogHeadSwitch
+
LINE_SEP
+
"file: "
+
mLog2FileSwitch
+
LINE_SEP
+
"dir: "
+
(
if
(
mDir
==
null
)
mDefaultDir
else
mDir
)
+
LINE_SEP
+
"filePrefix: "
+
mFilePrefix
+
LINE_SEP
+
"border: "
+
mLogBorderSwitch
+
LINE_SEP
+
"singleTag: "
+
mSingleTagSwitch
+
LINE_SEP
+
"consoleFilter: "
+
T
[
mConsoleFilter
-
V
]
+
LINE_SEP
+
"fileFilter: "
+
T
[
mFileFilter
-
V
]
+
LINE_SEP
+
"stackDeep: "
+
mStackDeep
+
LINE_SEP
+
"stackOffset: "
+
mStackOffset
+
LINE_SEP
+
"saveDays: "
+
mSaveDays
+
LINE_SEP
+
"formatter: "
+
I_FORMATTER_MAP
)
}
}
abstract
class
IFormatter
<
T
>
{
abstract
fun
format
(
t
:
T
):
String
}
private
class
TagHead
internal
constructor
(
internal
var
tag
:
String
,
internal
var
consoleHead
:
Array
<
String
>,
internal
var
fileHead
:
String
)
private
object
LogFormatter
{
internal
fun
formatJson
(
json
:
String
):
String
{
var
json
=
json
try
{
if
(
json
.
startsWith
(
"{"
))
{
json
=
JSONObject
(
json
).
toString
(
4
)
}
else
if
(
json
.
startsWith
(
"["
))
{
json
=
JSONArray
(
json
).
toString
(
4
)
}
}
catch
(
e
:
JSONException
)
{
e
.
printStackTrace
()
}
return
json
}
internal
fun
formatXml
(
xml
:
String
):
String
{
var
xml
=
xml
try
{
val
xmlInput
=
StreamSource
(
StringReader
(
xml
))
val
xmlOutput
=
StreamResult
(
StringWriter
())
val
transformer
=
TransformerFactory
.
newInstance
().
newTransformer
()
transformer
.
setOutputProperty
(
OutputKeys
.
INDENT
,
"yes"
)
transformer
.
setOutputProperty
(
"{http://xml.apache.org/xslt}indent-amount"
,
"4"
)
transformer
.
transform
(
xmlInput
,
xmlOutput
)
xml
=
xmlOutput
.
getWriter
().
toString
().
replaceFirst
(
">"
,
">$LINE_SEP"
)
}
catch
(
e
:
Exception
)
{
e
.
printStackTrace
()
}
return
xml
}
internal
fun
array2String
(
obj
:
Any
):
String
{
if
(
obj
is
Array
<
*
>)
{
return
Arrays
.
deepToString
(
obj
)
}
else
if
(
obj
is
BooleanArray
)
{
return
Arrays
.
toString
(
obj
)
}
else
if
(
obj
is
ByteArray
)
{
return
Arrays
.
toString
(
obj
)
}
else
if
(
obj
is
CharArray
)
{
return
Arrays
.
toString
(
obj
)
}
else
if
(
obj
is
DoubleArray
)
{
return
Arrays
.
toString
(
obj
)
}
else
if
(
obj
is
FloatArray
)
{
return
Arrays
.
toString
(
obj
)
}
else
if
(
obj
is
IntArray
)
{
return
Arrays
.
toString
(
obj
)
}
else
if
(
obj
is
LongArray
)
{
return
Arrays
.
toString
(
obj
)
}
else
if
(
obj
is
ShortArray
)
{
return
Arrays
.
toString
(
obj
)
}
throw
IllegalArgumentException
(
"Array has incompatible type: "
+
obj
.
javaClass
)
}
internal
fun
throwable2String
(
e
:
Throwable
):
String
{
var
t
:
Throwable
?
=
e
while
(
t
!=
null
)
{
if
(
t
is
UnknownHostException
)
{
return
""
}
t
=
t
.
cause
}
val
sw
=
StringWriter
()
val
pw
=
PrintWriter
(
sw
)
e
.
printStackTrace
(
pw
)
var
cause
:
Throwable
?
=
e
.
cause
while
(
cause
!=
null
)
{
cause
.
printStackTrace
(
pw
)
cause
=
cause
.
cause
}
pw
.
flush
()
return
sw
.
toString
()
}
internal
fun
bundle2String
(
bundle
:
Bundle
):
String
{
val
iterator
=
bundle
.
keySet
().
iterator
()
if
(!
iterator
.
hasNext
())
{
return
"Bundle {}"
}
val
sb
=
StringBuilder
(
128
)
sb
.
append
(
"Bundle { "
)
while
(
true
)
{
val
key
=
iterator
.
next
()
val
value
=
bundle
.
get
(
key
)
sb
.
append
(
key
).
append
(
'='
)
if
(
value
!=
null
&&
value
is
Bundle
)
{
sb
.
append
(
if
(
value
===
bundle
)
"(this Bundle)"
else
bundle2String
(
value
))
}
else
{
sb
.
append
(
formatObject
(
value
))
}
if
(!
iterator
.
hasNext
())
return
sb
.
append
(
" }"
).
toString
()
sb
.
append
(
','
).
append
(
' '
)
}
}
internal
fun
intent2String
(
intent
:
Intent
):
String
{
val
sb
=
StringBuilder
(
128
)
sb
.
append
(
"Intent { "
)
var
first
=
true
val
mAction
=
intent
.
action
if
(
mAction
!=
null
)
{
sb
.
append
(
"act="
).
append
(
mAction
)
first
=
false
}
val
mCategories
=
intent
.
categories
if
(
mCategories
!=
null
)
{
if
(!
first
)
{
sb
.
append
(
' '
)
}
first
=
false
sb
.
append
(
"cat=["
)
var
firstCategory
=
true
for
(
c
in
mCategories
)
{
if
(!
firstCategory
)
{
sb
.
append
(
','
)
}
sb
.
append
(
c
)
firstCategory
=
false
}
sb
.
append
(
"]"
)
}
val
mData
=
intent
.
data
if
(
mData
!=
null
)
{
if
(!
first
)
{
sb
.
append
(
' '
)
}
first
=
false
sb
.
append
(
"dat="
).
append
(
mData
)
}
val
mType
=
intent
.
type
if
(
mType
!=
null
)
{
if
(!
first
)
{
sb
.
append
(
' '
)
}
first
=
false
sb
.
append
(
"typ="
).
append
(
mType
)
}
val
mFlags
=
intent
.
flags
if
(
mFlags
!=
0
)
{
if
(!
first
)
{
sb
.
append
(
' '
)
}
first
=
false
sb
.
append
(
"flg=0x"
).
append
(
Integer
.
toHexString
(
mFlags
))
}
val
mPackage
=
intent
.
getPackage
()
if
(
mPackage
!=
null
)
{
if
(!
first
)
{
sb
.
append
(
' '
)
}
first
=
false
sb
.
append
(
"pkg="
).
append
(
mPackage
)
}
val
mComponent
=
intent
.
component
if
(
mComponent
!=
null
)
{
if
(!
first
)
{
sb
.
append
(
' '
)
}
first
=
false
sb
.
append
(
"cmp="
).
append
(
mComponent
.
flattenToShortString
())
}
val
mSourceBounds
=
intent
.
sourceBounds
if
(
mSourceBounds
!=
null
)
{
if
(!
first
)
{
sb
.
append
(
' '
)
}
first
=
false
sb
.
append
(
"bnds="
).
append
(
mSourceBounds
.
toShortString
())
}
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
JELLY_BEAN
)
{
val
mClipData
=
intent
.
clipData
if
(
mClipData
!=
null
)
{
if
(!
first
)
{
sb
.
append
(
' '
)
}
first
=
false
clipData2String
(
mClipData
,
sb
)
}
}
val
mExtras
=
intent
.
extras
if
(
mExtras
!=
null
)
{
if
(!
first
)
{
sb
.
append
(
' '
)
}
first
=
false
sb
.
append
(
"extras={"
)
sb
.
append
(
bundle2String
(
mExtras
))
sb
.
append
(
'}'
)
}
if
(
Build
.
VERSION
.
SDK_INT
>=
android
.
os
.
Build
.
VERSION_CODES
.
ICE_CREAM_SANDWICH_MR1
)
{
val
mSelector
=
intent
.
selector
if
(
mSelector
!=
null
)
{
if
(!
first
)
{
sb
.
append
(
' '
)
}
first
=
false
sb
.
append
(
"sel={"
)
sb
.
append
(
if
(
mSelector
===
intent
)
"(this Intent)"
else
intent2String
(
mSelector
))
sb
.
append
(
"}"
)
}
}
sb
.
append
(
" }"
)
return
sb
.
toString
()
}
@RequiresApi
(
api
=
Build
.
VERSION_CODES
.
JELLY_BEAN
)
private
fun
clipData2String
(
clipData
:
ClipData
,
sb
:
StringBuilder
)
{
val
item
=
clipData
.
getItemAt
(
0
)
if
(
item
==
null
)
{
sb
.
append
(
"ClipData.Item {}"
)
return
}
sb
.
append
(
"ClipData.Item { "
)
val
mHtmlText
=
item
.
htmlText
if
(
mHtmlText
!=
null
)
{
sb
.
append
(
"H:"
)
sb
.
append
(
mHtmlText
)
sb
.
append
(
"}"
)
return
}
val
mText
=
item
.
text
if
(
mText
!=
null
)
{
sb
.
append
(
"T:"
)
sb
.
append
(
mText
)
sb
.
append
(
"}"
)
return
}
val
uri
=
item
.
uri
if
(
uri
!=
null
)
{
sb
.
append
(
"U:"
).
append
(
uri
)
sb
.
append
(
"}"
)
return
}
val
intent
=
item
.
intent
if
(
intent
!=
null
)
{
sb
.
append
(
"I:"
)
sb
.
append
(
intent2String
(
intent
))
sb
.
append
(
"}"
)
return
}
sb
.
append
(
"NULL"
)
sb
.
append
(
"}"
)
}
}
fun
<
T
>
getTypeClassFromParadigm
(
formatter
:
IFormatter
<
T
>):
Class
<
*
>?
{
val
genericInterfaces
=
formatter
.
javaClass
.
genericInterfaces
var
type
:
Type
if
(
genericInterfaces
.
size
==
1
)
{
type
=
genericInterfaces
[
0
]
}
else
{
type
=
formatter
.
javaClass
.
genericSuperclass
}
type
=
(
type
as
ParameterizedType
).
getActualTypeArguments
()[
0
]
while
(
type
is
ParameterizedType
)
{
type
=
(
type
as
ParameterizedType
).
getRawType
()
}
var
className
=
type
.
toString
()
if
(
className
.
startsWith
(
"class "
))
{
className
=
className
.
substring
(
6
)
}
else
if
(
className
.
startsWith
(
"interface "
))
{
className
=
className
.
substring
(
10
)
}
try
{
return
Class
.
forName
(
className
)
}
catch
(
e
:
ClassNotFoundException
)
{
e
.
printStackTrace
()
}
return
null
}
private
fun
getClassFromObject
(
obj
:
Any
):
Class
<
*
>
{
val
objClass
=
obj
.
javaClass
if
(
objClass
.
isAnonymousClass
||
objClass
.
isSynthetic
)
{
val
genericInterfaces
=
objClass
.
genericInterfaces
var
className
:
String
if
(
genericInterfaces
.
size
==
1
)
{
// interface
var
type
=
genericInterfaces
[
0
]
while
(
type
is
ParameterizedType
)
{
type
=
(
type
as
ParameterizedType
).
getRawType
()
}
className
=
type
.
toString
()
}
else
{
// abstract class or lambda
var
type
=
objClass
.
genericSuperclass
while
(
type
is
ParameterizedType
)
{
type
=
(
type
as
ParameterizedType
).
getRawType
()
}
className
=
type
.
toString
()
}
if
(
className
.
startsWith
(
"class "
))
{
className
=
className
.
substring
(
6
)
}
else
if
(
className
.
startsWith
(
"interface "
))
{
className
=
className
.
substring
(
10
)
}
try
{
return
Class
.
forName
(
className
)
}
catch
(
e
:
ClassNotFoundException
)
{
e
.
printStackTrace
()
}
}
return
objClass
}
\ No newline at end of file
utilcode-kotlin/src/main/java/com/blankj/utilcode/util/StringUtils.kt
浏览文件 @
fdf8b3a4
@
file
:
JvmName
(
"StringUtils"
)
package
com.blankj.utilcode.util
/**
* Return whether the string is null or 0-length.
*
* @param s The string.
* @return `true`: yes<br></br> `false`: no
*/
fun
isEmpty
(
s
:
CharSequence
?):
Boolean
{
return
s
==
null
||
s
.
isEmpty
()
}
object
StringUtils
{
/**
* Return whether the string is null or 0-length.
*
* @param s The string.
* @return `true`: yes<br></br> `false`: no
*/
@JvmStatic
fun
isEmpty
(
s
:
CharSequence
?):
Boolean
{
return
s
==
null
||
s
.
isEmpty
()
}
/**
* Return whether the string is null or whitespace.
*
* @param s The string.
* @return `true`: yes<br></br> `false`: no
*/
fun
isTrimEmpty
(
s
:
String
?):
Boolean
{
return
s
==
null
||
s
.
trim
{
it
<=
' '
}.
isEmpty
()
}
/**
* Return whether the string is null or whitespace.
*
* @param s The string.
* @return `true`: yes<br></br> `false`: no
*/
@JvmStatic
fun
isTrimEmpty
(
s
:
String
?):
Boolean
{
return
s
==
null
||
s
.
trim
{
it
<=
' '
}.
isEmpty
()
}
/**
* Return whether the string is null or white space.
*
* @param s The string.
* @return `true`: yes<br></br> `false`: no
*/
fun
isSpace
(
s
:
String
?):
Boolean
{
if
(
s
==
null
)
return
true
var
i
=
0
val
len
=
s
.
length
while
(
i
<
len
)
{
if
(!
Character
.
isWhitespace
(
s
[
i
]))
{
return
false
/**
* Return whether the string is null or white space.
*
* @param s The string.
* @return `true`: yes<br></br> `false`: no
*/
@JvmStatic
fun
isSpace
(
s
:
String
?):
Boolean
{
if
(
s
==
null
)
return
true
var
i
=
0
val
len
=
s
.
length
while
(
i
<
len
)
{
if
(!
Character
.
isWhitespace
(
s
[
i
]))
{
return
false
}
++
i
}
++
i
return
true
}
return
true
}
/**
* Return whether string1 is equals to string2.
*
* @param s1 The first string.
* @param s2 The second string.
* @return `true`: yes<br></br>`false`: no
*/
fun
equals
(
s1
:
CharSequence
?,
s2
:
CharSequence
?):
Boolean
{
if
(
s1
===
s2
)
return
true
if
(
s1
!=
null
&&
s2
!=
null
)
{
val
length
:
Int
=
s1
.
length
if
(
length
==
s2
.
length
)
{
if
(
s1
is
String
&&
s2
is
String
)
{
return
s1
==
s2
}
else
{
for
(
i
in
0
until
length
)
{
if
(
s1
[
i
]
!=
s2
[
i
])
return
false
/**
* Return whether string1 is equals to string2.
*
* @param s1 The first string.
* @param s2 The second string.
* @return `true`: yes<br></br>`false`: no
*/
@JvmStatic
fun
equals
(
s1
:
CharSequence
?,
s2
:
CharSequence
?):
Boolean
{
if
(
s1
===
s2
)
return
true
if
(
s1
!=
null
&&
s2
!=
null
)
{
val
length
:
Int
=
s1
.
length
if
(
length
==
s2
.
length
)
{
if
(
s1
is
String
&&
s2
is
String
)
{
return
s1
==
s2
}
else
{
for
(
i
in
0
until
length
)
{
if
(
s1
[
i
]
!=
s2
[
i
])
return
false
}
return
true
}
return
true
}
}
return
false
}
return
false
}
/**
* Return whether string1 is equals to string2, ignoring case considerations..
*
* @param s1 The first string.
* @param s2 The second string.
* @return `true`: yes<br></br>`false`: no
*/
fun
equalsIgnoreCase
(
s1
:
String
?,
s2
:
String
?):
Boolean
{
return
s1
.
equals
(
s2
,
ignoreCase
=
true
)
}
/**
* Return whether string1 is equals to string2, ignoring case considerations..
*
* @param s1 The first string.
* @param s2 The second string.
* @return `true`: yes<br></br>`false`: no
*/
@JvmStatic
fun
equalsIgnoreCase
(
s1
:
String
?,
s2
:
String
?):
Boolean
{
return
s1
.
equals
(
s2
,
ignoreCase
=
true
)
}
/**
* Return `""` if string equals null.
*
* @param s The string.
* @return `""` if string equals null
*/
fun
null2Length0
(
s
:
String
?):
String
{
return
s
?:
""
}
/**
* Return `""` if string equals null.
*
* @param s The string.
* @return `""` if string equals null
*/
@JvmStatic
fun
null2Length0
(
s
:
String
?):
String
{
return
s
?:
""
}
/**
* Return the length of string.
*
* @param s The string.
* @return the length of string
*/
fun
length
(
s
:
CharSequence
?):
Int
{
return
s
?.
length
?:
0
}
/**
* Return the length of string.
*
* @param s The string.
* @return the length of string
*/
@JvmStatic
fun
length
(
s
:
CharSequence
?):
Int
{
return
s
?.
length
?:
0
}
/**
* Set the first letter of string upper.
*
* @param s The string.
* @return the string with first letter upper.
*/
fun
upperFirstLetter
(
s
:
String
?):
String
{
if
(
s
==
null
||
s
.
isEmpty
())
return
""
return
if
(!
Character
.
isLowerCase
(
s
[
0
]))
s
else
(
s
[
0
].
toInt
()
-
32
).
toChar
().
toString
()
+
s
.
substring
(
1
)
}
/**
* Set the first letter of string upper.
*
* @param s The string.
* @return the string with first letter upper.
*/
@JvmStatic
fun
upperFirstLetter
(
s
:
String
?):
String
{
if
(
s
==
null
||
s
.
isEmpty
())
return
""
return
if
(!
Character
.
isLowerCase
(
s
[
0
]))
s
else
(
s
[
0
].
toInt
()
-
32
).
toChar
().
toString
()
+
s
.
substring
(
1
)
}
/**
* Set the first letter of string lower.
*
* @param s The string.
* @return the string with first letter lower.
*/
fun
lowerFirstLetter
(
s
:
String
?):
String
{
if
(
s
==
null
||
s
.
isEmpty
())
return
""
return
if
(!
Character
.
isUpperCase
(
s
[
0
]))
s
else
(
s
[
0
].
toInt
()
+
32
).
toChar
().
toString
()
+
s
.
substring
(
1
)
}
/**
* Set the first letter of string lower.
*
* @param s The string.
* @return the string with first letter lower.
*/
@JvmStatic
fun
lowerFirstLetter
(
s
:
String
?):
String
{
if
(
s
==
null
||
s
.
isEmpty
())
return
""
return
if
(!
Character
.
isUpperCase
(
s
[
0
]))
s
else
(
s
[
0
].
toInt
()
+
32
).
toChar
().
toString
()
+
s
.
substring
(
1
)
}
/**
* Reverse the string.
*
* @param s The string.
* @return the reverse string.
*/
fun
reverse
(
s
:
String
?):
String
{
if
(
s
==
null
)
return
""
val
len
=
s
.
length
if
(
len
<=
1
)
return
s
val
mid
=
len
shr
1
val
chars
=
s
.
toCharArray
()
var
c
:
Char
for
(
i
in
0
until
mid
)
{
c
=
chars
[
i
]
chars
[
i
]
=
chars
[
len
-
i
-
1
]
chars
[
len
-
i
-
1
]
=
c
/**
* Reverse the string.
*
* @param s The string.
* @return the reverse string.
*/
@JvmStatic
fun
reverse
(
s
:
String
?):
String
{
if
(
s
==
null
)
return
""
val
len
=
s
.
length
if
(
len
<=
1
)
return
s
val
mid
=
len
shr
1
val
chars
=
s
.
toCharArray
()
var
c
:
Char
for
(
i
in
0
until
mid
)
{
c
=
chars
[
i
]
chars
[
i
]
=
chars
[
len
-
i
-
1
]
chars
[
len
-
i
-
1
]
=
c
}
return
String
(
chars
)
}
return
String
(
chars
)
}
/**
* Convert string to DBC.
*
* @param s The string.
* @return the DBC string
*/
fun
toDBC
(
s
:
String
?):
String
{
if
(
s
==
null
||
s
.
isEmpty
())
return
""
val
chars
=
s
.
toCharArray
()
var
i
=
0
val
len
=
chars
.
size
while
(
i
<
len
)
{
when
{
chars
[
i
].
toInt
()
==
12288
->
chars
[
i
]
=
' '
chars
[
i
].
toInt
()
in
65281
..
65374
->
chars
[
i
]
=
(
chars
[
i
].
toInt
()
-
65248
).
toChar
()
else
->
chars
[
i
]
=
chars
[
i
]
/**
* Convert string to DBC.
*
* @param s The string.
* @return the DBC string
*/
@JvmStatic
fun
toDBC
(
s
:
String
?):
String
{
if
(
s
==
null
||
s
.
isEmpty
())
return
""
val
chars
=
s
.
toCharArray
()
var
i
=
0
val
len
=
chars
.
size
while
(
i
<
len
)
{
when
{
chars
[
i
].
toInt
()
==
12288
->
chars
[
i
]
=
' '
chars
[
i
].
toInt
()
in
65281
..
65374
->
chars
[
i
]
=
(
chars
[
i
].
toInt
()
-
65248
).
toChar
()
else
->
chars
[
i
]
=
chars
[
i
]
}
i
++
}
i
++
return
String
(
chars
)
}
return
String
(
chars
)
}
/**
* Convert string to SBC.
*
* @param s The string.
* @return the SBC string
*/
fun
toSBC
(
s
:
String
?):
String
{
if
(
s
==
null
||
s
.
isEmpty
())
return
""
val
chars
=
s
.
toCharArray
()
var
i
=
0
val
len
=
chars
.
size
while
(
i
<
len
)
{
when
{
chars
[
i
]
==
' '
->
chars
[
i
]
=
12288
.
toChar
()
chars
[
i
].
toInt
()
in
33
..
126
->
chars
[
i
]
=
(
chars
[
i
].
toInt
()
+
65248
).
toChar
()
else
->
chars
[
i
]
=
chars
[
i
]
/**
* Convert string to SBC.
*
* @param s The string.
* @return the SBC string
*/
@JvmStatic
fun
toSBC
(
s
:
String
?):
String
{
if
(
s
==
null
||
s
.
isEmpty
())
return
""
val
chars
=
s
.
toCharArray
()
var
i
=
0
val
len
=
chars
.
size
while
(
i
<
len
)
{
when
{
chars
[
i
]
==
' '
->
chars
[
i
]
=
12288
.
toChar
()
chars
[
i
].
toInt
()
in
33
..
126
->
chars
[
i
]
=
(
chars
[
i
].
toInt
()
+
65248
).
toChar
()
else
->
chars
[
i
]
=
chars
[
i
]
}
i
++
}
i
++
return
String
(
chars
)
}
return
String
(
chars
)
}
\ No newline at end of file
utilcode-kotlin/src/main/java/com/blankj/utilcode/util/Utils.java
已删除
100644 → 0
浏览文件 @
1c36d1ed
package
com.blankj.utilcode.util
;
import
android.annotation.SuppressLint
;
import
android.app.Activity
;
import
android.app.ActivityManager
;
import
android.app.Application
;
import
android.app.Application.ActivityLifecycleCallbacks
;
import
android.content.Context
;
import
android.content.res.Resources
;
import
android.os.Bundle
;
import
android.support.annotation.NonNull
;
import
android.support.annotation.Nullable
;
import
android.support.v4.content.FileProvider
;
import
android.util.DisplayMetrics
;
import
java.lang.reflect.Field
;
import
java.lang.reflect.InvocationTargetException
;
import
java.util.HashMap
;
import
java.util.LinkedList
;
import
java.util.List
;
import
java.util.Map
;
/**
* <pre>
* author:
* ___ ___ ___ ___
* _____ / /\ /__/\ /__/| / /\
* / /::\ / /::\ \ \:\ | |:| / /:/
* / /:/\:\ ___ ___ / /:/\:\ \ \:\ | |:| /__/::\
* / /:/~/::\ /__/\ / /\ / /:/~/::\ _____\__\:\ __| |:| \__\/\:\
* /__/:/ /:/\:| \ \:\ / /:/ /__/:/ /:/\:\ /__/::::::::\ /__/\_|:|____ \ \:\
* \ \:\/:/~/:/ \ \:\ /:/ \ \:\/:/__\/ \ \:\~~\~~\/ \ \:\/:::::/ \__\:\
* \ \::/ /:/ \ \:\/:/ \ \::/ \ \:\ ~~~ \ \::/~~~~ / /:/
* \ \:\/:/ \ \::/ \ \:\ \ \:\ \ \:\ /__/:/
* \ \::/ \__\/ \ \:\ \ \:\ \ \:\ \__\/
* \__\/ \__\/ \__\/ \__\/
* blog : http://blankj.com
* time : 16/12/08
* desc : utils about initialization
* </pre>
*/
public
final
class
Utils
{
@SuppressLint
(
"StaticFieldLeak"
)
private
static
Application
sApplication
;
private
static
final
ActivityLifecycleImpl
ACTIVITY_LIFECYCLE
=
new
ActivityLifecycleImpl
();
private
Utils
()
{
throw
new
UnsupportedOperationException
(
"u can't instantiate me..."
);
}
/**
* Init utils.
* <p>Init it in the class of Application.</p>
*
* @param context context
*/
public
static
void
init
(
final
Context
context
)
{
if
(
context
==
null
)
{
init
(
getApplicationByReflect
());
return
;
}
init
((
Application
)
context
.
getApplicationContext
());
}
/**
* Init utils.
* <p>Init it in the class of Application.</p>
*
* @param app application
*/
public
static
void
init
(
final
Application
app
)
{
if
(
sApplication
==
null
)
{
if
(
app
==
null
)
{
sApplication
=
getApplicationByReflect
();
}
else
{
sApplication
=
app
;
}
sApplication
.
registerActivityLifecycleCallbacks
(
ACTIVITY_LIFECYCLE
);
}
}
/**
* Return the context of Application object.
*
* @return the context of Application object
*/
public
static
Application
getApp
()
{
if
(
sApplication
!=
null
)
return
sApplication
;
Application
app
=
getApplicationByReflect
();
init
(
app
);
return
app
;
}
private
static
Application
getApplicationByReflect
()
{
try
{
@SuppressLint
(
"PrivateApi"
)
Class
<?>
activityThread
=
Class
.
forName
(
"android.app.ActivityThread"
);
Object
thread
=
activityThread
.
getMethod
(
"currentActivityThread"
).
invoke
(
null
);
Object
app
=
activityThread
.
getMethod
(
"getApplication"
).
invoke
(
thread
);
if
(
app
==
null
)
{
throw
new
NullPointerException
(
"u should init first"
);
}
return
(
Application
)
app
;
}
catch
(
NoSuchMethodException
e
)
{
e
.
printStackTrace
();
}
catch
(
IllegalAccessException
e
)
{
e
.
printStackTrace
();
}
catch
(
InvocationTargetException
e
)
{
e
.
printStackTrace
();
}
catch
(
ClassNotFoundException
e
)
{
e
.
printStackTrace
();
}
throw
new
NullPointerException
(
"u should init first"
);
}
static
ActivityLifecycleImpl
getActivityLifecycle
()
{
return
ACTIVITY_LIFECYCLE
;
}
static
LinkedList
<
Activity
>
getActivityList
()
{
return
ACTIVITY_LIFECYCLE
.
mActivityList
;
}
static
Context
getTopActivityOrApp
()
{
if
(
isAppForeground
())
{
Activity
topActivity
=
ACTIVITY_LIFECYCLE
.
getTopActivity
();
return
topActivity
==
null
?
Utils
.
getApp
()
:
topActivity
;
}
else
{
return
Utils
.
getApp
();
}
}
static
boolean
isAppForeground
()
{
ActivityManager
am
=
(
ActivityManager
)
Utils
.
getApp
().
getSystemService
(
Context
.
ACTIVITY_SERVICE
);
//noinspection ConstantConditions
List
<
ActivityManager
.
RunningAppProcessInfo
>
info
=
am
.
getRunningAppProcesses
();
if
(
info
==
null
||
info
.
size
()
==
0
)
return
false
;
for
(
ActivityManager
.
RunningAppProcessInfo
aInfo
:
info
)
{
if
(
aInfo
.
importance
==
ActivityManager
.
RunningAppProcessInfo
.
IMPORTANCE_FOREGROUND
)
{
return
aInfo
.
processName
.
equals
(
Utils
.
getApp
().
getPackageName
());
}
}
return
false
;
}
static
final
AdaptScreenArgs
ADAPT_SCREEN_ARGS
=
new
AdaptScreenArgs
();
static
void
restoreAdaptScreen
()
{
final
DisplayMetrics
systemDm
=
Resources
.
getSystem
().
getDisplayMetrics
();
final
DisplayMetrics
appDm
=
Utils
.
getApp
().
getResources
().
getDisplayMetrics
();
final
Activity
activity
=
ACTIVITY_LIFECYCLE
.
getTopActivity
();
if
(
activity
!=
null
)
{
final
DisplayMetrics
activityDm
=
activity
.
getResources
().
getDisplayMetrics
();
if
(
ADAPT_SCREEN_ARGS
.
isVerticalSlide
)
{
activityDm
.
density
=
activityDm
.
widthPixels
/
(
float
)
ADAPT_SCREEN_ARGS
.
sizeInPx
;
}
else
{
activityDm
.
density
=
activityDm
.
heightPixels
/
(
float
)
ADAPT_SCREEN_ARGS
.
sizeInPx
;
}
activityDm
.
scaledDensity
=
activityDm
.
density
*
(
systemDm
.
scaledDensity
/
systemDm
.
density
);
activityDm
.
densityDpi
=
(
int
)
(
160
*
activityDm
.
density
);
appDm
.
density
=
activityDm
.
density
;
appDm
.
scaledDensity
=
activityDm
.
scaledDensity
;
appDm
.
densityDpi
=
activityDm
.
densityDpi
;
}
else
{
if
(
ADAPT_SCREEN_ARGS
.
isVerticalSlide
)
{
appDm
.
density
=
appDm
.
widthPixels
/
(
float
)
ADAPT_SCREEN_ARGS
.
sizeInPx
;
}
else
{
appDm
.
density
=
appDm
.
heightPixels
/
(
float
)
ADAPT_SCREEN_ARGS
.
sizeInPx
;
}
appDm
.
scaledDensity
=
appDm
.
density
*
(
systemDm
.
scaledDensity
/
systemDm
.
density
);
appDm
.
densityDpi
=
(
int
)
(
160
*
appDm
.
density
);
}
}
static
void
cancelAdaptScreen
()
{
final
DisplayMetrics
systemDm
=
Resources
.
getSystem
().
getDisplayMetrics
();
final
DisplayMetrics
appDm
=
Utils
.
getApp
().
getResources
().
getDisplayMetrics
();
final
Activity
activity
=
ACTIVITY_LIFECYCLE
.
getTopActivity
();
if
(
activity
!=
null
)
{
final
DisplayMetrics
activityDm
=
activity
.
getResources
().
getDisplayMetrics
();
activityDm
.
density
=
systemDm
.
density
;
activityDm
.
scaledDensity
=
systemDm
.
scaledDensity
;
activityDm
.
densityDpi
=
systemDm
.
densityDpi
;
}
appDm
.
density
=
systemDm
.
density
;
appDm
.
scaledDensity
=
systemDm
.
scaledDensity
;
appDm
.
densityDpi
=
systemDm
.
densityDpi
;
}
static
boolean
isAdaptScreen
()
{
final
DisplayMetrics
systemDm
=
Resources
.
getSystem
().
getDisplayMetrics
();
final
DisplayMetrics
appDm
=
Utils
.
getApp
().
getResources
().
getDisplayMetrics
();
return
systemDm
.
density
!=
appDm
.
density
;
}
static
class
AdaptScreenArgs
{
int
sizeInPx
;
boolean
isVerticalSlide
;
}
static
class
ActivityLifecycleImpl
implements
ActivityLifecycleCallbacks
{
final
LinkedList
<
Activity
>
mActivityList
=
new
LinkedList
<>();
final
HashMap
<
Object
,
OnAppStatusChangedListener
>
mStatusListenerMap
=
new
HashMap
<>();
private
int
mForegroundCount
=
0
;
private
int
mConfigCount
=
0
;
void
addListener
(
final
Object
object
,
final
OnAppStatusChangedListener
listener
)
{
mStatusListenerMap
.
put
(
object
,
listener
);
}
void
removeListener
(
final
Object
object
)
{
mStatusListenerMap
.
remove
(
object
);
}
@Override
public
void
onActivityCreated
(
Activity
activity
,
Bundle
savedInstanceState
)
{
setTopActivity
(
activity
);
}
@Override
public
void
onActivityStarted
(
Activity
activity
)
{
setTopActivity
(
activity
);
if
(
mForegroundCount
<=
0
)
{
postStatus
(
true
);
}
if
(
mConfigCount
<
0
)
{
++
mConfigCount
;
}
else
{
++
mForegroundCount
;
}
}
@Override
public
void
onActivityResumed
(
Activity
activity
)
{
setTopActivity
(
activity
);
}
@Override
public
void
onActivityPaused
(
Activity
activity
)
{
/**/
}
@Override
public
void
onActivityStopped
(
Activity
activity
)
{
if
(
activity
.
isChangingConfigurations
())
{
--
mConfigCount
;
}
else
{
--
mForegroundCount
;
if
(
mForegroundCount
<=
0
)
{
postStatus
(
false
);
}
}
}
@Override
public
void
onActivitySaveInstanceState
(
Activity
activity
,
Bundle
outState
)
{
/**/
}
@Override
public
void
onActivityDestroyed
(
Activity
activity
)
{
mActivityList
.
remove
(
activity
);
}
private
void
postStatus
(
final
boolean
isForeground
)
{
if
(
mStatusListenerMap
.
isEmpty
())
return
;
for
(
OnAppStatusChangedListener
onAppStatusChangedListener
:
mStatusListenerMap
.
values
())
{
if
(
onAppStatusChangedListener
==
null
)
return
;
if
(
isForeground
)
{
onAppStatusChangedListener
.
onForeground
();
}
else
{
onAppStatusChangedListener
.
onBackground
();
}
}
}
private
void
setTopActivity
(
final
Activity
activity
)
{
if
(
activity
.
getClass
()
==
PermissionUtils
.
PermissionActivity
.
class
)
return
;
if
(
mActivityList
.
contains
(
activity
))
{
if
(!
mActivityList
.
getLast
().
equals
(
activity
))
{
mActivityList
.
remove
(
activity
);
mActivityList
.
addLast
(
activity
);
}
}
else
{
mActivityList
.
addLast
(
activity
);
}
}
Activity
getTopActivity
()
{
if
(!
mActivityList
.
isEmpty
())
{
final
Activity
topActivity
=
mActivityList
.
getLast
();
if
(
topActivity
!=
null
)
{
return
topActivity
;
}
}
Activity
topActivityByReflect
=
getTopActivityByReflect
();
if
(
topActivityByReflect
!=
null
)
{
setTopActivity
(
topActivityByReflect
);
}
return
topActivityByReflect
;
}
private
Activity
getTopActivityByReflect
()
{
try
{
@SuppressLint
(
"PrivateApi"
)
Class
<?>
activityThreadClass
=
Class
.
forName
(
"android.app.ActivityThread"
);
Object
activityThread
=
activityThreadClass
.
getMethod
(
"currentActivityThread"
).
invoke
(
null
);
Field
activitiesField
=
activityThreadClass
.
getDeclaredField
(
"mActivityList"
);
activitiesField
.
setAccessible
(
true
);
Map
activities
=
(
Map
)
activitiesField
.
get
(
activityThread
);
if
(
activities
==
null
)
return
null
;
for
(
Object
activityRecord
:
activities
.
values
())
{
Class
activityRecordClass
=
activityRecord
.
getClass
();
Field
pausedField
=
activityRecordClass
.
getDeclaredField
(
"paused"
);
pausedField
.
setAccessible
(
true
);
if
(!
pausedField
.
getBoolean
(
activityRecord
))
{
Field
activityField
=
activityRecordClass
.
getDeclaredField
(
"activity"
);
activityField
.
setAccessible
(
true
);
return
(
Activity
)
activityField
.
get
(
activityRecord
);
}
}
}
catch
(
ClassNotFoundException
e
)
{
e
.
printStackTrace
();
}
catch
(
IllegalAccessException
e
)
{
e
.
printStackTrace
();
}
catch
(
InvocationTargetException
e
)
{
e
.
printStackTrace
();
}
catch
(
NoSuchMethodException
e
)
{
e
.
printStackTrace
();
}
catch
(
NoSuchFieldException
e
)
{
e
.
printStackTrace
();
}
return
null
;
}
}
public
static
final
class
FileProvider4UtilCode
extends
FileProvider
{
@Override
public
boolean
onCreate
()
{
Utils
.
init
(
getContext
());
return
true
;
}
}
///////////////////////////////////////////////////////////////////////////
// interface
///////////////////////////////////////////////////////////////////////////
public
interface
OnAppStatusChangedListener
{
void
onForeground
();
void
onBackground
();
}
}
utilcode-kotlin/src/main/java/com/blankj/utilcode/util/Utils.kt
0 → 100644
浏览文件 @
fdf8b3a4
@
file
:
JvmName
(
"Utils"
)
package
com.blankj.utilcode.util
import
android.annotation.SuppressLint
import
android.app.Activity
import
android.app.ActivityManager
import
android.app.Application
import
android.app.Application.ActivityLifecycleCallbacks
import
android.content.Context
import
android.content.res.Resources
import
android.os.Bundle
import
android.support.v4.content.FileProvider
import
java.lang.reflect.InvocationTargetException
import
java.util.*
@SuppressLint
(
"StaticFieldLeak"
)
private
var
sApplication
:
Application
?
=
null
private
val
ACTIVITY_LIFECYCLE
=
ActivityLifecycleImpl
()
/**
* Init utils.
*
* Init it in the class of Application.
*
* @param context context
*/
fun
init
(
context
:
Context
?)
{
if
(
context
==
null
)
{
init
(
getApplicationByReflect
())
return
}
init
(
context
.
applicationContext
as
Application
)
}
/**
* Init utils.
*
* Init it in the class of Application.
*
* @param app application
*/
fun
init
(
app
:
Application
?)
{
if
(
sApplication
==
null
)
{
sApplication
=
app
?:
getApplicationByReflect
()
sApplication
!!
.
registerActivityLifecycleCallbacks
(
ACTIVITY_LIFECYCLE
)
}
}
/**
* Return the context of Application object.
*
* @return the context of Application object
*/
fun
getApp
():
Application
{
if
(
sApplication
!=
null
)
return
sApplication
as
Application
val
app
=
getApplicationByReflect
()
init
(
app
)
return
app
}
private
fun
getApplicationByReflect
():
Application
{
try
{
@SuppressLint
(
"PrivateApi"
)
val
activityThread
=
Class
.
forName
(
"android.app.ActivityThread"
)
val
thread
=
activityThread
.
getMethod
(
"currentActivityThread"
).
invoke
(
null
)
val
app
=
activityThread
.
getMethod
(
"getApplication"
).
invoke
(
thread
)
?:
throw
NullPointerException
(
"u should init first"
)
return
app
as
Application
}
catch
(
e
:
NoSuchMethodException
)
{
e
.
printStackTrace
()
}
catch
(
e
:
IllegalAccessException
)
{
e
.
printStackTrace
()
}
catch
(
e
:
InvocationTargetException
)
{
e
.
printStackTrace
()
}
catch
(
e
:
ClassNotFoundException
)
{
e
.
printStackTrace
()
}
throw
NullPointerException
(
"u should init first"
)
}
internal
fun
getActivityLifecycle
():
ActivityLifecycleImpl
{
return
ACTIVITY_LIFECYCLE
}
internal
fun
getActivityList
():
LinkedList
<
Activity
>
{
return
ACTIVITY_LIFECYCLE
.
mActivityList
}
fun
getTopActivityOrApp
():
Context
{
return
if
(
isAppForeground
())
{
val
topActivity
=
ACTIVITY_LIFECYCLE
.
topActivity
topActivity
?:
getApp
()
}
else
{
getApp
()
}
}
internal
fun
isAppForeground
():
Boolean
{
val
am
=
getApp
().
getSystemService
(
Context
.
ACTIVITY_SERVICE
)
as
ActivityManager
val
info
=
am
.
runningAppProcesses
if
(
info
==
null
||
info
.
size
==
0
)
return
false
for
(
aInfo
in
info
)
{
if
(
aInfo
.
importance
==
ActivityManager
.
RunningAppProcessInfo
.
IMPORTANCE_FOREGROUND
)
{
return
aInfo
.
processName
==
getApp
().
packageName
}
}
return
false
}
internal
val
ADAPT_SCREEN_ARGS
=
AdaptScreenArgs
()
internal
fun
restoreAdaptScreen
()
{
val
systemDm
=
Resources
.
getSystem
().
displayMetrics
val
appDm
=
getApp
().
resources
.
displayMetrics
val
activity
=
ACTIVITY_LIFECYCLE
.
topActivity
if
(
activity
!=
null
)
{
val
activityDm
=
activity
.
resources
.
displayMetrics
if
(
ADAPT_SCREEN_ARGS
.
isVerticalSlide
)
{
activityDm
.
density
=
activityDm
.
widthPixels
/
ADAPT_SCREEN_ARGS
.
sizeInPx
.
toFloat
()
}
else
{
activityDm
.
density
=
activityDm
.
heightPixels
/
ADAPT_SCREEN_ARGS
.
sizeInPx
.
toFloat
()
}
activityDm
.
scaledDensity
=
activityDm
.
density
*
(
systemDm
.
scaledDensity
/
systemDm
.
density
)
activityDm
.
densityDpi
=
(
160
*
activityDm
.
density
).
toInt
()
appDm
.
density
=
activityDm
.
density
appDm
.
scaledDensity
=
activityDm
.
scaledDensity
appDm
.
densityDpi
=
activityDm
.
densityDpi
}
else
{
if
(
ADAPT_SCREEN_ARGS
.
isVerticalSlide
)
{
appDm
.
density
=
appDm
.
widthPixels
/
ADAPT_SCREEN_ARGS
.
sizeInPx
.
toFloat
()
}
else
{
appDm
.
density
=
appDm
.
heightPixels
/
ADAPT_SCREEN_ARGS
.
sizeInPx
.
toFloat
()
}
appDm
.
scaledDensity
=
appDm
.
density
*
(
systemDm
.
scaledDensity
/
systemDm
.
density
)
appDm
.
densityDpi
=
(
160
*
appDm
.
density
).
toInt
()
}
}
internal
fun
cancelAdaptScreen
()
{
val
systemDm
=
Resources
.
getSystem
().
displayMetrics
val
appDm
=
getApp
().
resources
.
displayMetrics
val
activity
=
ACTIVITY_LIFECYCLE
.
topActivity
if
(
activity
!=
null
)
{
val
activityDm
=
activity
.
resources
.
displayMetrics
activityDm
.
density
=
systemDm
.
density
activityDm
.
scaledDensity
=
systemDm
.
scaledDensity
activityDm
.
densityDpi
=
systemDm
.
densityDpi
}
appDm
.
density
=
systemDm
.
density
appDm
.
scaledDensity
=
systemDm
.
scaledDensity
appDm
.
densityDpi
=
systemDm
.
densityDpi
}
internal
fun
isAdaptScreen
():
Boolean
{
val
systemDm
=
Resources
.
getSystem
().
displayMetrics
val
appDm
=
getApp
().
resources
.
displayMetrics
return
systemDm
.
density
!=
appDm
.
density
}
internal
class
AdaptScreenArgs
{
var
sizeInPx
:
Int
=
0
var
isVerticalSlide
:
Boolean
=
false
}
internal
class
ActivityLifecycleImpl
:
ActivityLifecycleCallbacks
{
val
mActivityList
:
LinkedList
<
Activity
>
=
LinkedList
()
private
val
mStatusListenerMap
:
HashMap
<
Any
,
OnAppStatusChangedListener
>
=
HashMap
()
private
var
mForegroundCount
=
0
private
var
mConfigCount
=
0
var
topActivity
:
Activity
?
get
()
{
if
(!
mActivityList
.
isEmpty
())
{
val
topActivity
=
mActivityList
.
last
if
(
topActivity
!=
null
)
{
return
topActivity
}
}
val
topActivityByReflect
=
topActivityByReflect
if
(
topActivityByReflect
!=
null
)
{
topActivity
=
topActivityByReflect
}
return
topActivityByReflect
}
private
set
(
activity
)
{
if
(
activity
?.
javaClass
==
PermissionUtils
.
PermissionActivity
::
class
.
java
)
return
if
(
mActivityList
.
contains
(
activity
))
{
if
(!
mActivityList
.
last
.
equals
(
activity
))
{
mActivityList
.
remove
(
activity
)
mActivityList
.
addLast
(
activity
)
}
}
else
{
mActivityList
.
addLast
(
activity
)
}
}
private
val
topActivityByReflect
:
Activity
?
get
()
{
try
{
@SuppressLint
(
"PrivateApi"
)
val
activityThreadClass
=
Class
.
forName
(
"android.app.ActivityThread"
)
val
activityThread
=
activityThreadClass
.
getMethod
(
"currentActivityThread"
).
invoke
(
null
)
val
activitiesField
=
activityThreadClass
.
getDeclaredField
(
"mActivityList"
)
activitiesField
.
isAccessible
=
true
val
activities
=
activitiesField
.
get
(
activityThread
)
as
Map
<
*
,
*
>
for
(
activityRecord
in
activities
.
values
)
{
if
(
activityRecord
==
null
)
continue
val
activityRecordClass
=
activityRecord
.
javaClass
val
pausedField
=
activityRecordClass
.
getDeclaredField
(
"paused"
)
pausedField
.
isAccessible
=
true
if
(!
pausedField
.
getBoolean
(
activityRecord
))
{
val
activityField
=
activityRecordClass
.
getDeclaredField
(
"activity"
)
activityField
.
isAccessible
=
true
return
activityField
.
get
(
activityRecord
)
as
Activity
}
}
}
catch
(
e
:
ClassNotFoundException
)
{
e
.
printStackTrace
()
}
catch
(
e
:
IllegalAccessException
)
{
e
.
printStackTrace
()
}
catch
(
e
:
InvocationTargetException
)
{
e
.
printStackTrace
()
}
catch
(
e
:
NoSuchMethodException
)
{
e
.
printStackTrace
()
}
catch
(
e
:
NoSuchFieldException
)
{
e
.
printStackTrace
()
}
return
null
}
fun
addListener
(
obj
:
Any
,
listener
:
OnAppStatusChangedListener
)
{
mStatusListenerMap
[
obj
]
=
listener
}
fun
removeListener
(
obj
:
Any
)
{
mStatusListenerMap
.
remove
(
obj
)
}
override
fun
onActivityCreated
(
activity
:
Activity
,
savedInstanceState
:
Bundle
)
{
topActivity
=
activity
}
override
fun
onActivityStarted
(
activity
:
Activity
)
{
topActivity
=
activity
if
(
mForegroundCount
<=
0
)
{
postStatus
(
true
)
}
if
(
mConfigCount
<
0
)
{
++
mConfigCount
}
else
{
++
mForegroundCount
}
}
override
fun
onActivityResumed
(
activity
:
Activity
)
{
topActivity
=
activity
}
override
fun
onActivityPaused
(
activity
:
Activity
)
{
/**/
}
override
fun
onActivityStopped
(
activity
:
Activity
)
{
if
(
activity
.
isChangingConfigurations
)
{
--
mConfigCount
}
else
{
--
mForegroundCount
if
(
mForegroundCount
<=
0
)
{
postStatus
(
false
)
}
}
}
override
fun
onActivitySaveInstanceState
(
activity
:
Activity
,
outState
:
Bundle
)
{
/**/
}
override
fun
onActivityDestroyed
(
activity
:
Activity
)
{
mActivityList
.
remove
(
activity
)
}
private
fun
postStatus
(
isForeground
:
Boolean
)
{
if
(
mStatusListenerMap
.
isEmpty
())
return
for
(
onAppStatusChangedListener
in
mStatusListenerMap
.
values
)
{
if
(
isForeground
)
{
onAppStatusChangedListener
.
onForeground
()
}
else
{
onAppStatusChangedListener
.
onBackground
()
}
}
}
}
class
FileProvider4UtilCode
:
FileProvider
()
{
override
fun
onCreate
():
Boolean
{
init
(
context
)
return
true
}
}
///////////////////////////////////////////////////////////////////////////
// interface
///////////////////////////////////////////////////////////////////////////
interface
OnAppStatusChangedListener
{
fun
onForeground
()
fun
onBackground
()
}
\ No newline at end of file
utilcode-kotlin/src/main/java/com/blankj/utilcode/util/ZipUtils.java
浏览文件 @
fdf8b3a4
package
com.blankj.utilcode.util
;
import
android.util.Log
;
import
java.io.BufferedInputStream
;
import
java.io.BufferedOutputStream
;
import
java.io.File
;
...
...
@@ -291,12 +293,22 @@ public final class ZipUtils {
if
(
isSpace
(
keyword
))
{
while
(
entries
.
hasMoreElements
())
{
ZipEntry
entry
=
((
ZipEntry
)
entries
.
nextElement
());
String
entryName
=
entry
.
getName
();
if
(
entryName
.
contains
(
"../"
))
{
Log
.
e
(
"ZipUtils"
,
"it's dangerous!"
);
return
files
;
}
if
(!
unzipChildFile
(
destDir
,
files
,
zip
,
entry
))
return
files
;
}
}
else
{
while
(
entries
.
hasMoreElements
())
{
ZipEntry
entry
=
((
ZipEntry
)
entries
.
nextElement
());
if
(
entry
.
getName
().
contains
(
keyword
))
{
String
entryName
=
entry
.
getName
();
if
(
entryName
.
contains
(
"../"
))
{
Log
.
e
(
"ZipUtils"
,
"it's dangerous!"
);
return
files
;
}
if
(
entryName
.
contains
(
keyword
))
{
if
(!
unzipChildFile
(
destDir
,
files
,
zip
,
entry
))
return
files
;
}
}
...
...
utilcode/src/main/java/com/blankj/utilcode/util/ZipUtils.java
浏览文件 @
fdf8b3a4
package
com.blankj.utilcode.util
;
import
android.util.Log
;
import
java.io.BufferedInputStream
;
import
java.io.BufferedOutputStream
;
import
java.io.File
;
...
...
@@ -291,12 +293,22 @@ public final class ZipUtils {
if
(
isSpace
(
keyword
))
{
while
(
entries
.
hasMoreElements
())
{
ZipEntry
entry
=
((
ZipEntry
)
entries
.
nextElement
());
String
entryName
=
entry
.
getName
();
if
(
entryName
.
contains
(
"../"
))
{
Log
.
e
(
"ZipUtils"
,
"it's dangerous!"
);
return
files
;
}
if
(!
unzipChildFile
(
destDir
,
files
,
zip
,
entry
))
return
files
;
}
}
else
{
while
(
entries
.
hasMoreElements
())
{
ZipEntry
entry
=
((
ZipEntry
)
entries
.
nextElement
());
if
(
entry
.
getName
().
contains
(
keyword
))
{
String
entryName
=
entry
.
getName
();
if
(
entryName
.
contains
(
"../"
))
{
Log
.
e
(
"ZipUtils"
,
"it's dangerous!"
);
return
files
;
}
if
(
entryName
.
contains
(
keyword
))
{
if
(!
unzipChildFile
(
destDir
,
files
,
zip
,
entry
))
return
files
;
}
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录