未验证 提交 8525e5f4 编写于 作者: caixiangyi's avatar caixiangyi 提交者: GitHub

Merge pull request #26 from liyihz2008/master

上传移动端源代码

要显示的变更太多。

To preserve performance only 1000 of 1000+ files are displayed.
/PushSDK/build/
.DS_Store
/captures
.svn/
reports/
# Built application files
*.apk
*.ap_
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# Intellij
*.iml
.idea/
# VsCode
.vscode/
# Keystore files
*.jks
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
# Google Services (e.g. APIs or Firebase)
google-services.json
# Freeline
freeline.py
freeline/
freeline_project_description.json
#O2办公平台(O2OA)
[O2办公平台(O2OA)](https://www.pgyer.com/ZhiHe_android)是一个可以自定义的私有化高效云工作平台,私有安全,创意无限
/build
# VsCode
.vscode/
# RELEASE
O2PLATFORM/
huawei/
xiaomi/
connection.project.dir=
eclipse.preferences.version=1
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>O2-帮助</title>
<style type="text/css">
body {
padding: 10px;
}
</style>
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"></script>
</head>
<body>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"> 华为消息提醒设置说明 </h3>
</div>
<div class="panel-body">
<p class="p1">
华为手机需要开启O2自动启动、关闭锁屏清理应用和开启O2通知,主要是解决使用O2无法及时收到新的消息通知(需要重新打开O2才能收到新的消息提醒)。
</p>
<p>
<span style="color: rgb(255, 0, 0);">PS:如果你能接收消息通知,请忽略</span>
<br><br>
<strong>导致原因:</strong>
<br>
因为华为手机系统在黑屏待机后自动清理后台运行的软件,这样影响了我们正常接收新的消息,需要将O2设置为非清理应用。
</p>
<p class="p1">
<strong>如何设置:</strong>
</p>
<p class="p1">
<span class="s1">1.</span>关闭锁屏清理应用
</p>
<p class="p3">
<span class="s2">操作步骤:</span>
<span class="s3">设置-电池-锁屏清理应用,找到O2,关闭锁屏清理开关,参见下面的GIF动画:</span>
<br>
<img alt="" src="http://muliba.u.qiniudn.com/o2/20170920/%E9%94%81%E5%B1%8F%E6%B8%85%E7%90%86.gif"
style="width: 100%;">
</p>
<p class="p2">&nbsp;</p>
<p class="p1">
<span class="s1">2.</span>开启自动运行
</p>
<p class="p3">
<span class="s2">操作步骤:</span>
<span class="s3">找到手机管家-自启管理,找到O2并允许自启动,参见下面的GIF动画:</span>
<br>
<img alt="" src="http://muliba.u.qiniudn.com/o2/20170920/%E5%BC%80%E5%90%AF%E8%87%AA%E5%90%AF%E5%8A%A8.gif"
style="width: 100%;">
</p>
<p class="p2">&nbsp;</p>
<p class="p1"><span class="s1">3.</span>通知设置</p>
<p class="p1">
<span class="s2">操作步骤:</span>
<span class="s3">设置-通知和状态栏-通知管理,找到O2-开启允许通知及其他开关。参见下面的GIF动画:</span>
<br><img alt="" src="http://muliba.u.qiniudn.com/o2/20170920/%E9%80%9A%E7%9F%A5%E8%AE%BE%E7%BD%AE.gif"
style="width: 100%;">
</p>
<p class="p2">&nbsp;</p>
<p class="p1"><span class="s1">4.</span>多任务界面锁定O2</p>
<p class="p1">
<span class="s2">操作步骤:</span>
<span class="s3">点击手机右下角的功能键-进入多任务页面-找到O2,点击O2右上角锁图标锁定。参见下面的GIF动画:</span>
<br><img alt="" src="http://muliba.u.qiniudn.com/o2/20170920/%E5%A4%9A%E4%BB%BB%E5%8A%A1.gif"
style="width: 100%;">
</p>
<p class="p2">&nbsp;</p>
</div>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>O2-帮助</title>
<style type="text/css">
body {
padding: 10px;
}
</style>
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"></script>
</head>
<body>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"> 小米手机消息提醒设置说明 </h3>
</div>
<div class="panel-body">
<p>小米手机需要开启O2自动运行应用程序,主要是解决使用O2无法及时收到新的消息通知(需要重新打开O2才能收到新的消息提醒)。</p>
<p>
<span style="color: rgb(255, 0, 0);">PS:如果你能接收消息通知,请忽略</span>
<br><br>
<strong>导致原因:</strong>
<br>
因为小米手机系统在黑屏待机后自动清理后台运行的软件,这样影响了我们正常接收新的消息,需要将O2设置为自动运行应用程序。
</p>
<p class="p1">
<strong>如何设置:</strong>
</p>
<p class="p1">
<span class="s1">1.</span>开启自动启动
</p>
<p class="p3">
<span class="s2">操作步骤:</span>
<span class="s3">手机找到并点击 安全中心-授权管理-自启动管理-找到O2开启开关。参见下面的GIF动画:</span>
<br>
<img alt="" src="http://muliba.u.qiniudn.com/o2/20170921/%E5%B0%8F%E7%B1%B3%E8%87%AA%E5%90%AF%E5%8A%A8.gif"
style="width: 100%;">
</p>
<p class="p2">&nbsp;</p>
<p class="p1"><span class="s1">2.</span>神隐模式</p>
<p class="p1">
<span class="s2">操作步骤:</span>
<span class="s3">手机设置-电量和性能-神隐模式-应用配置-找到O2-点击无限制并允许定位。参见下面的GIF动画:</span>
<br><img alt="" src="http://muliba.u.qiniudn.com/o2/20170921/%E5%B0%8F%E7%B1%B3%E7%A5%9E%E9%9A%90%E6%A8%A1%E5%BC%8F.gif"
style="width: 100%;">
</p>
<p class="p2">&nbsp;</p>
<p class="p1"><span class="s1">3.</span>通知设置</p>
<p class="p1">
<span class="s2">操作步骤:</span>
<span class="s3">手机设置-通知和状态栏-通知管理-找到O2-开启允许通知和其他选项。参见下面的GIF动画:</span>
<br><img alt="" src="http://muliba.u.qiniudn.com/o2/20170921/%E5%B0%8F%E7%B1%B3%E9%80%9A%E7%9F%A5%E8%AE%BE%E7%BD%AE.gif"
style="width: 100%;">
</p>
<p class="p2">&nbsp;</p>
<p class="p1"><span class="s1">4.</span>多任务界面锁定O2</p>
<p class="p1">
<span class="s2">操作步骤:</span>
<span class="s3">点击手机左下角的功能键-进入多任务页面-找到O2-拖曳O2下滑-点击锁定任务。参见下面的GIF动画:</span>
<br><img alt="" src="http://muliba.u.qiniudn.com/o2/20170921/%E5%B0%8F%E7%B1%B3%E5%A4%9A%E4%BB%BB%E5%8A%A1.gif"
style="width: 100%;">
</p>
<p class="p2">&nbsp;</p>
</div>
</div>
</body>
</html>
\ No newline at end of file
(๑‾ ꇴ ‾๑)好哒
๑乛◡乛๑嘿嘿
(/ω·\*)捂脸
(๑⁼̴̀д⁼̴́๑)可恶
(๑•॒̀ ູ॒•́๑)啦啦啦
(づ ̄³ ̄)づ抱抱
("▔□▔)汗
<(ˉ^ˉ)>哼
( ꒪Д꒪)吓尿
( ・᷄д・᷅ )委屈
( ˃᷄˶˶̫˶˂᷅ )羞
눈_눈
Ծ‸Ծ
(๑˙ー˙๑)
( ´・ᴗ・` )
٩(˃̶͈̀௰˂̶͈́)و加油
(⺣◡⺣)♡喜欢哒
(= ̄ω ̄=)喵
(σ゚∀゚)σ呦呦
ԅ( ¯་། ¯ԅ)
◝( ˙ ꒳ ˙ )◜
(っ˘̩╭╮˘̩)っ
(⁍̥̥̥᷄д⁍̥̥̥᷅ ू )伤心
( ・᷄ ᵌ・᷅ )我要嘛
(ಥ_ಥ)爱不爱我
(◕‿◕✿)
╮( ̄⊿ ̄”)╭无奈
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
{
"id" : "o2CenterServer",
"name" : "dev",
"centerHost" : "dev.o2server.io",
"centerContext" : "/x_program_center",
"centerPort" : 20030,
"httpProtocol" : "http"
}
\ No newline at end of file
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'realm-android'
ext {
//定义变量
signingConfigKeyAlias = ""
signingConfigKeyPassword = ""
signingConfigStoreFilePath = ""
signingConfigStorePassword = ""
jpushAppKeyDebug = ""
pgyAppIdDebug = ""
baiduAppIdDebug = ""
baiduSecretDebug = ""
baiduAppKeyDebug = ""
jpushAppKeyRelease = ""
pgyAppIdRelease = ""
baiduAppIdRelease = ""
baiduSecretRelease = ""
baiduAppKeyRelease = ""
jpushIMPassword = ""
buglyAppId = ""
}
def loadProperties() {
// load properties
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
project.signingConfigKeyAlias = properties.getProperty("signingConfig.keyAlias")
project.signingConfigKeyPassword = properties.getProperty("signingConfig.keyPassword")
project.signingConfigStoreFilePath = properties.getProperty("signingConfig.storeFilePath")
project.signingConfigStorePassword = properties.getProperty("signingConfig.storePassword")
//debug key
//极光推送
project.jpushAppKeyDebug = properties.getProperty("JPUSH_APPKEY_DEBUG")
//蒲公英
project.pgyAppIdDebug = properties.getProperty("PGY_APP_ID_DEBUG")
//百度
project.baiduAppIdDebug = properties.getProperty("BAIDU_APPID_DEBUG")
project.baiduSecretDebug = properties.getProperty("BAIDU_SECRET_DEBUG")
project.baiduAppKeyDebug = properties.getProperty("BAIDU_APPKEY_DEBUG")
//release key
project.jpushAppKeyRelease = properties.getProperty("JPUSH_APPKEY_RELEASE")
project.pgyAppIdRelease = properties.getProperty("PGY_APP_ID_RELEASE")
project.baiduAppIdRelease = properties.getProperty("BAIDU_APPID_RELEASE")
project.baiduSecretRelease = properties.getProperty("BAIDU_SECRET_RELEASE")
project.baiduAppKeyRelease = properties.getProperty("BAIDU_APPKEY_RELEASE")
project.jpushIMPassword = properties.getProperty("JM_IM_USER_PASSWORD")
//bugly
project.buglyAppId = properties.getProperty("BUGLY_APPID")
}
loadProperties()
task printVersionName {
def v = project.property("o2.versionName").toString()
println( "${v}" )
}
android {
compileSdkVersion 26
buildToolsVersion "27.0.3"
sourceSets {
main {
jniLibs.srcDir 'libs'
assets.srcDirs = ['assets']
res.srcDirs = ['src/main/res', 'src/main/res/raw']
}
}
signingConfigs {
release {
v1SigningEnabled true
v2SigningEnabled true
keyAlias project.signingConfigKeyAlias
keyPassword project.signingConfigKeyPassword
storeFile file(project.signingConfigStoreFilePath)
storePassword project.signingConfigStorePassword
}
debug {
v1SigningEnabled true
v2SigningEnabled true
keyAlias 'androiddebugkey'
storeFile file('debug.keystore')
keyPassword 'android'
}
}
defaultConfig {
applicationId "net.zoneland.x.bpm.mobile.v1.zoneXBPM"
minSdkVersion 19
targetSdkVersion 26
versionCode project.property("o2.versionCode").toInteger()
versionName project.property("o2.versionName").toString()
multiDexEnabled true
ndk {
//选择要添加的对应cpu类型的.so库。
abiFilters 'armeabi', 'armeabi-v7a' //, 'arm64-v8a' //, 'x86', 'x86_64'
// 还可以添加 'x86', 'x86_64', 'mips', 'mips64'
}
multiDexKeepProguard file('multidex_keep_file.pro')
vectorDrawables.useSupportLibrary = true
}
buildTypes {
debug {
signingConfig signingConfigs.debug
buildConfigField "Boolean", "InnerServer", "false"
buildConfigField "Boolean", "LOG_ENABLE", "true"
buildConfigField "Boolean", "LOG_FILE", "true"
manifestPlaceholders = [JPUSH_PKGNAME: "net.zoneland.x.bpm.mobile.v1.zoneXBPM",
JPUSH_APPKEY : project.jpushAppKeyDebug,
JM_IM_USER_PASSWORD : project.jpushIMPassword,
PGY_APP_ID : project.pgyAppIdDebug,
BAIDU_APPID : project.baiduAppIdDebug,
BAIDU_SECRET : project.baiduSecretDebug,
BAIDU_APPKEY : project.baiduAppKeyDebug,
BUGLY_APPID : project.buglyAppId]
}
release {
signingConfig signingConfigs.release
buildConfigField "Boolean", "InnerServer", "false"
buildConfigField "Boolean", "LOG_ENABLE", "false"
buildConfigField "Boolean", "LOG_FILE", "true"
manifestPlaceholders = [JPUSH_PKGNAME: "net.zoneland.x.bpm.mobile.v1.zoneXBPM",
JPUSH_APPKEY : project.jpushAppKeyRelease,
JM_IM_USER_PASSWORD : project.jpushIMPassword,
PGY_APP_ID : project.pgyAppIdRelease,
BAIDU_APPID : project.baiduAppIdRelease,
BAIDU_SECRET : project.baiduSecretRelease,
BAIDU_APPKEY : project.baiduAppKeyRelease,
BUGLY_APPID : project.buglyAppId]
zipAlignEnabled true //Zipalign优化
minifyEnabled true //混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//apk包重命名
applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "${variant.productFlavors[0].name}-${variant.versionName}.apk"
}
}
}
}
dataBinding {
enabled true
}
android {
lintOptions {
abortOnError false
}
}
lintOptions {
checkReleaseBuilds false
abortOnError false
}
//All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com/r/tools/flavorDimensions-missing-error-message.html
flavorDimensions "type"
productFlavors {
O2PLATFORM {
manifestPlaceholders = [JPUSH_CHANNEL: "pgy"]
}
huawei {
manifestPlaceholders = [JPUSH_CHANNEL: "huawei"]
}
xiaomi {
manifestPlaceholders = [JPUSH_CHANNEL: "xiaomi"]
}
}
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
}
}
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
// implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation files('libs/o2_auth_sdk.jar')
implementation files('libs/BaiduLBS_Android.jar')
implementation files('libs/bdasr_V3_20180320_9066860.jar')
implementation files('libs/com.baidu.tts_2.3.1.20170808_e39ea89.jar')
implementation files('libs/pgyer_sdk_2.2.2.jar')
implementation files('libs/zxing.jar')
implementation files('libs/picasso-2.5.2.jar')
implementation files('libs/pinyin4j-2.5.0.jar')
implementation files('libs/universal-image-loader-1.9.5.jar')
implementation files('libs/tbs_sdk_thirdapp_v3.2.0.1104_43200.jar')
implementation(name: 'material-calendarview-fancy-1.1', ext: 'aar')
implementation(name: 'MGLicenseManagerSDK-0.3.1', ext: 'aar')
implementation(name: 'MGFaceppSDK-0.5.2', ext: 'aar')
//kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "org.jetbrains.anko:anko-common:$anko_version"
//support
implementation('com.android.support:support-v4:26.1.0') {
force = true
}
implementation('com.android.support:recyclerview-v7:26.1.0') {
exclude module: 'support-v4'
}
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support:cardview-v7:26.1.0'
implementation 'com.android.support:design:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:multidex:1.0.3'
implementation 'com.github.PhilJay:MPAndroidChart:v2.2.4'
implementation('com.github.bumptech.glide:glide:3.7.0') {
force = true
}
implementation 'com.afollestad.material-dialogs:core:0.8.5.9'
implementation 'net.muliba.fancyfilepickerlibrary:fancyfilepickerlibrary:3.0.2'
implementation 'net.muliba.changeskin:changeskin:1.2.2'
implementation 'io.o2oa:signatureview:1.0.0'
implementation 'net.zoneland.o2.calendarview:library:1.1.2'
implementation 'com.readystatesoftware.systembartint:systembartint:1.0.3'
implementation 'com.facebook.shimmer:shimmer:0.1.0@aar'
implementation 'com.borax12.materialdaterangepicker:library:1.9'
implementation 'com.yanzhenjie:recyclerview-swipe:1.1.4'
//http
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.2.0'
implementation 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
implementation 'io.reactivex:rxjava:1.1.6'
implementation 'io.reactivex:rxandroid:1.2.1'
//bugly
implementation 'com.tencent.bugly:crashreport:2.6.6'
//极光推送
implementation 'cn.jiguang.sdk:jpush:3.1.2'
implementation 'cn.jiguang.sdk:jmessage:2.5.0'
// 此处以JMessage 2.5.0 版本为例。
implementation 'cn.jiguang.sdk:jcore:1.1.9'
// 此处以JCore 1.1.9 版本为例。
//im
implementation 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'
implementation 'com.jakewharton:butterknife:8.4.0'
kapt 'com.jakewharton:butterknife-compiler:8.4.0'
implementation 'com.github.w446108264:AndroidEmoji:1.0.0'
implementation 'com.github.chrisbanes.photoview:library:1.2.4'
implementation 'com.facebook.fresco:fresco:0.8.1'
implementation 'org.greenrobot:eventbus:3.0.0'
implementation 'com.contrarywind:Android-PickerView:3.2.4'
//滚动选择器
implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1'
//google architecture component
def lifecycle_version = "1.1.1"
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
// alternatively - just ViewModel
implementation "android.arch.lifecycle:viewmodel:$lifecycle_version"
// use -ktx for Kotlin
// alternatively - just LiveData
implementation "android.arch.lifecycle:livedata:$lifecycle_version"
// alternatively - Lifecycles only (no ViewModel or LiveData).
// Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"
//noinspection GradleDependency
kapt "com.android.databinding:compiler:$gradle_version"
//test
testImplementation 'junit:junit:4.12'
}
tasks.whenTaskAdded { task ->
if (task.name == "lint") {
task.enabled = false
}
}
-keep public class com.tencent.bugly.**{*;}
\ No newline at end of file
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in E:\workApp\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
######################## 通用配置 ###################################
#指定代码的压缩级别
-optimizationpasses 5
#包明不混合大小写
-dontusemixedcaseclassnames
#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
#优化 不优化输入的类文件
-dontoptimize
#预校验
-dontpreverify
#混淆时是否记录日志
-verbose
# 混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
# 保持哪些类不被混淆
-keep public class * extends android.app.Fragment
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
#如果有引用v4包可以添加下面这行
-keep public class * extends android.support.v4.app.Fragment
#忽略警告
-ignorewarning
#如果引用了v4或者v7包
-dontwarn android.support.**
####混淆保护自己项目的部分代码以及引用的第三方jar包library-end####
#保持 native 方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
#保持自定义控件类不被混淆
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
#保持自定义控件类不被混淆
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
#保持 Parcelable 不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#保持 Serializable 不被混淆
-keepnames class * implements java.io.Serializable
#保持 Serializable 不被混淆并且enum 类也不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
#保持枚举 enum 类不被混淆
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclassmembers class * {
public void *ButtonClicked(android.view.View);
}
#不混淆资源类
-keepclassmembers class **.R$* {
public static <fields>;
}
#避免混淆泛型 如果混淆报错建议关掉
#-keepattributes Signature
####################### 常用第三方模块的混淆选项 ###################################
#gson
#如果用用到Gson解析包的,直接添加下面这几行就能成功混淆,不然会报错。
#保护注解
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.** { *; }
-keep class com.google.gson.stream.** { *; }
#butterknife
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {
@butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
@butterknife.* <methods>;
}
#Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-keep class com.bumptech.glide.** { *; }
#-keepresourcexmlelements manifest/application/meta-data@value=GlideModule
# 如果使用了Gson之类的工具要使被它解析的JavaBean类即实体类不被混淆。
-keep class net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.** { *; }
#rx
-keep class rx.** { *; }
#retrofit
-keep class retrofit2.** { *; }
#guava
-keep class com.google.common.base.** { *; }
#chart
-keep class com.github.PhilJay.** { *; }
#materialdialogs
-keep class com.afollestad.materialdialogs.** { *; }
#日历控件 github > material-calendarview
-keep class com.prolificinteractive.** { *; }
#pgy
-dontwarn com.pgyersdk.**
-keep class com.pgyersdk.** { *; }
#umeng
-keep class com.umeng.analytics.** { *; }
-dontwarn com.umeng.analytics.**
#log4j
-keep class org.apache.log4j.** { *; }
-dontwarn org.apache.log4j.**
#baidu
-keep class com.baidu.** {*;}
-keep class vi.com.** {*;}
-dontwarn com.baidu.**
#baidu yuyin
-keep class com.baidu.speech.**{*;}
-keep class com.baidu.tts.**{*;}
-keep class com.baidu.speechsynthesizer.**{*;}
##umeng push
-dontwarn com.taobao.**
-dontwarn anet.channel.**
-dontwarn anetwork.channel.**
-dontwarn org.android.**
-dontwarn org.apache.thrift.**
-dontwarn com.xiaomi.**
-dontwarn com.huawei.**
-keepattributes *Annotation*
-keep class com.taobao.** {*;}
-keep class org.android.** {*;}
-keep class anet.channel.** {*;}
-keep class com.umeng.** {*;}
-keep class com.xiaomi.** {*;}
-keep class com.huawei.** {*;}
-keep class org.apache.thrift.** {*;}
-keep class com.alibaba.sdk.android.**{*;}
-keep class com.ut.**{*;}
-keep class com.ta.**{*;}
-keep public class **.R$*{
public static final int *;
}
#bugly
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
#jiguang
-dontoptimize
-dontpreverify
-keepattributes EnclosingMethod,Signature
-dontwarn cn.jpush.**
-keep class cn.jpush.** { *; }
-dontwarn cn.jiguang.**
-keep class cn.jiguang.** { *; }
-keepclassmembers class ** {
public void onEvent*(**);
}
-keep class sj.qqkeyboard.** { *; }
-keep class com.sj.emoji.** { *; }
-keep class com.testemticon.** { *; }
-keep class jiguang.chat.** { *; }
#========================gson================================
-dontwarn com.google.**
-keep class com.google.gson.** {*;}
-keep class com.google.code.gson.** {*;}
#========================protobuf================================
-keep class com.google.protobuf.** {*;}
#-optimizationpasses 7
#-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-dontoptimize
-dontusemixedcaseclassnames
-verbose
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontwarn dalvik.**
-dontwarn com.tencent.smtt.**
#-overloadaggressively
# ------------------ Keep LineNumbers and properties ---------------- #
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
# --------------------------------------------------------------------------
# Addidional for x5.sdk classes for apps
-keep class com.tencent.smtt.export.external.**{
*;
}
-keep class com.tencent.tbs.video.interfaces.IUserStateChangedListener {
*;
}
-keep class com.tencent.smtt.sdk.CacheManager {
public *;
}
-keep class com.tencent.smtt.sdk.CookieManager {
public *;
}
-keep class com.tencent.smtt.sdk.WebHistoryItem {
public *;
}
-keep class com.tencent.smtt.sdk.WebViewDatabase {
public *;
}
-keep class com.tencent.smtt.sdk.WebBackForwardList {
public *;
}
-keep public class com.tencent.smtt.sdk.WebView {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.WebView$HitTestResult {
public static final <fields>;
public java.lang.String getExtra();
public int getType();
}
-keep public class com.tencent.smtt.sdk.WebView$WebViewTransport {
public <methods>;
}
-keep public class com.tencent.smtt.sdk.WebView$PictureListener {
public <fields>;
public <methods>;
}
-keepattributes InnerClasses
-keep public enum com.tencent.smtt.sdk.WebSettings$** {
*;
}
-keep public enum com.tencent.smtt.sdk.QbSdk$** {
*;
}
-keep public class com.tencent.smtt.sdk.WebSettings {
public *;
}
-keepattributes Signature
-keep public class com.tencent.smtt.sdk.ValueCallback {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.WebViewClient {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.DownloadListener {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.WebChromeClient {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.WebChromeClient$FileChooserParams {
public <fields>;
public <methods>;
}
-keep class com.tencent.smtt.sdk.SystemWebChromeClient{
public *;
}
# 1. extension interfaces should be apparent
-keep public class com.tencent.smtt.export.external.extension.interfaces.* {
public protected *;
}
# 2. interfaces should be apparent
-keep public class com.tencent.smtt.export.external.interfaces.* {
public protected *;
}
-keep public class com.tencent.smtt.sdk.WebViewCallbackClient {
public protected *;
}
-keep public class com.tencent.smtt.sdk.WebStorage$QuotaUpdater {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.WebIconDatabase {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.WebStorage {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.DownloadListener {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.QbSdk {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.QbSdk$PreInitCallback {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.CookieSyncManager {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.Tbs* {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.utils.LogFileUtils {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.utils.TbsLog {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.utils.TbsLogClient {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.CookieSyncManager {
public <fields>;
public <methods>;
}
# Added for game demos
-keep public class com.tencent.smtt.sdk.TBSGamePlayer {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.TBSGamePlayerClient* {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.TBSGamePlayerClientExtension {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.TBSGamePlayerService* {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.utils.Apn {
public <fields>;
public <methods>;
}
-keep class com.tencent.smtt.** {
*;
}
# end
-keep public class com.tencent.smtt.export.external.extension.proxy.ProxyWebViewClientExtension {
public <fields>;
public <methods>;
}
-keep class MTT.ThirdAppInfoNew {
*;
}
-keep class com.tencent.mtt.MttTraceEvent {
*;
}
# Game related
-keep public class com.tencent.smtt.gamesdk.* {
public protected *;
}
-keep public class com.tencent.smtt.sdk.TBSGameBooter {
public <fields>;
public <methods>;
}
-keep public class com.tencent.smtt.sdk.TBSGameBaseActivity {
public protected *;
}
-keep public class com.tencent.smtt.sdk.TBSGameBaseActivityProxy {
public protected *;
}
-keep public class com.tencent.smtt.gamesdk.internal.TBSGameServiceClient {
public *;
}
#---------------------------------------------------------------------------
#------------------ 下方是android平台自带的排除项,这里不要动 ----------------
-keep public class * extends android.app.Activity{
public <fields>;
public <methods>;
}
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepattributes *Annotation*
-keepclasseswithmembernames class *{
native <methods>;
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#------------------ 下方是共性的排除项目 ----------------
# 方法名中含有“JNI”字符的,认定是Java Native Interface方法,自动排除
# 方法名中含有“JRI”字符的,认定是Java Reflection Interface方法,自动排除
-keepclasseswithmembers class * {
... *JNI*(...);
}
-keepclasseswithmembernames class * {
... *JRI*(...);
}
-keep class **JNI* {*;}
package net.zoneland.x.bpm.mobile.v1.zoneXBPM;
import android.app.Application;
import android.test.ApplicationTestCase;
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.StringUtil;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
public void testClassUtil() {
String phone = "853090000";
if (StringUtil.isPhoneWithHKandMACAO(phone)) {
System.out.print(".............");
}else {
System.out.print("lllllllllllll");
}
}
}
\ No newline at end of file
此差异已折叠。
package com.baidu.android.tts;
import com.baidu.tts.client.SpeechSynthesizerListener;
import com.baidu.tts.client.TtsMode;
import java.util.Map;
/**
* 合成引擎的初始化参数
* <p>
* Created by fujiayi on 2017/9/13.
*/
public class InitConfig {
/**
* appId appKey 和 secretKey。注意如果需要离线合成功能,请在您申请的应用中填写包名。
* 本demo的包名是com.baidu.tts.sample,定义在build.gradle中。
*/
private String appId;
private String appKey;
private String secretKey;
/**
* 纯在线或者离在线融合
*/
private TtsMode ttsMode;
/**
* 初始化的其它参数,用于setParam
*/
private Map<String, String> params;
/**
* 合成引擎的回调
*/
private SpeechSynthesizerListener listener;
private InitConfig() {
}
public InitConfig(String appId, String appKey, String secretKey, TtsMode ttsMode,
Map<String, String> params, SpeechSynthesizerListener listener) {
this.appId = appId;
this.appKey = appKey;
this.secretKey = secretKey;
this.ttsMode = ttsMode;
this.params = params;
this.listener = listener;
}
public SpeechSynthesizerListener getListener() {
return listener;
}
public Map<String, String> getParams() {
return params;
}
public String getAppId() {
return appId;
}
public String getAppKey() {
return appKey;
}
public String getSecretKey() {
return secretKey;
}
public TtsMode getTtsMode() {
return ttsMode;
}
}
package com.baidu.android.tts;
/**
* Created by fujiayi on 2017/9/13.
*/
public interface MainHandlerConstant {
static final int PRINT = 0;
static final int UI_CHANGE_INPUT_TEXT_SELECTION = 1;
static final int UI_CHANGE_SYNTHES_TEXT_SELECTION = 2;
static final int INIT_SUCCESS = 2;
}
package com.baidu.android.tts;
import android.util.Log;
import com.baidu.tts.client.SpeechError;
import com.baidu.tts.client.SpeechSynthesizerListener;
/**
* SpeechSynthesizerListener 简单地实现,仅仅记录日志
* Created by fujiayi on 2017/5/19.
*/
public class MessageListener implements SpeechSynthesizerListener, MainHandlerConstant {
private static final String TAG = "MessageListener";
/**
* 播放开始,每句播放开始都会回调
*
* @param utteranceId
*/
@Override
public void onSynthesizeStart(String utteranceId) {
sendMessage("准备开始合成,序列号:" + utteranceId);
}
/**
* 语音流 16K采样率 16bits编码 单声道 。
*
* @param utteranceId
* @param bytes 二进制语音 ,注意可能有空data的情况,可以忽略
* @param progress 如合成“百度语音问题”这6个字, progress肯定是从0开始,到6结束。 但progress无法和合成到第几个字对应。
*/
@Override
public void onSynthesizeDataArrived(String utteranceId, byte[] bytes, int progress) {
// Log.i(TAG, "合成进度回调, progress:" + progress + ";序列号:" + utteranceId );
}
/**
* 合成正常结束,每句合成正常结束都会回调,如果过程中出错,则回调onError,不再回调此接口
*
* @param utteranceId
*/
@Override
public void onSynthesizeFinish(String utteranceId) {
sendMessage("合成结束回调, 序列号:" + utteranceId);
}
@Override
public void onSpeechStart(String utteranceId) {
sendMessage("播放开始回调, 序列号:" + utteranceId);
}
/**
* 播放进度回调接口,分多次回调
*
* @param utteranceId
* @param progress 如合成“百度语音问题”这6个字, progress肯定是从0开始,到6结束。 但progress无法保证和合成到第几个字对应。
*/
@Override
public void onSpeechProgressChanged(String utteranceId, int progress) {
// Log.i(TAG, "播放进度回调, progress:" + progress + ";序列号:" + utteranceId );
}
/**
* 播放正常结束,每句播放正常结束都会回调,如果过程中出错,则回调onError,不再回调此接口
*
* @param utteranceId
*/
@Override
public void onSpeechFinish(String utteranceId) {
sendMessage("播放结束回调, 序列号:" + utteranceId);
}
/**
* 当合成或者播放过程中出错时回调此接口
*
* @param utteranceId
* @param speechError 包含错误码和错误信息
*/
@Override
public void onError(String utteranceId, SpeechError speechError) {
sendErrorMessage("错误发生:" + speechError.description + ",错误编码:"
+ speechError.code + ",序列号:" + utteranceId);
}
private void sendErrorMessage(String message) {
sendMessage(message, true);
}
private void sendMessage(String message) {
sendMessage(message, false);
}
protected void sendMessage(String message, boolean isError) {
if (isError) {
Log.e(TAG, message);
} else {
Log.i(TAG, message);
}
}
}
package com.baidu.android.tts;
import android.content.Context;
import android.util.Log;
import android.util.Pair;
import com.baidu.tts.auth.AuthInfo;
import com.baidu.tts.client.SpeechSynthesizeBag;
import com.baidu.tts.client.SpeechSynthesizer;
import com.baidu.tts.client.TtsMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 该类是对SpeechSynthesizer的封装
* <p>
* Created by fujiayi on 2017/5/24.
*/
public class MySyntherizer implements MainHandlerConstant {
protected SpeechSynthesizer mSpeechSynthesizer;
protected Context context;
private static final String TAG = "NonBlockSyntherizer";
private static boolean isInitied = false;
private boolean isCheckFile = true;
public MySyntherizer(Context context, InitConfig initConfig) {
this(context);
init(initConfig);
}
protected MySyntherizer(Context context) {
if (isInitied) {
// SpeechSynthesizer.getInstance() 不要连续调用
throw new RuntimeException("MySynthesizer 类里面 SpeechSynthesizer还未释放,请勿新建一个新类");
}
this.context = context;
isInitied = true;
}
/**
* 注意该方法需要在新线程中调用。且该线程不能结束。详细请参见NonBlockSyntherizer的实现
*
* @param config
* @return
*/
protected boolean init(InitConfig config) {
sendToUiThread("初始化开始");
boolean isMix = config.getTtsMode().equals(TtsMode.MIX);
mSpeechSynthesizer = SpeechSynthesizer.getInstance();
mSpeechSynthesizer.setContext(context);
mSpeechSynthesizer.setSpeechSynthesizerListener(config.getListener());
// 请替换为语音开发者平台上注册应用得到的App ID ,AppKey ,Secret Key ,填写在SynthActivity的开始位置
mSpeechSynthesizer.setAppId(config.getAppId());
mSpeechSynthesizer.setApiKey(config.getAppKey(), config.getSecretKey());
if (isMix) {
// 授权检测接口(只是通过AuthInfo进行检验授权是否成功。选择纯在线可以不必调用auth方法。
AuthInfo authInfo = mSpeechSynthesizer.auth(config.getTtsMode());
if (!authInfo.isSuccess()) {
// 离线授权需要网站上的应用填写包名。本demo的包名是com.baidu.tts.sample,定义在build.gradle中
String errorMsg = authInfo.getTtsError().getDetailMessage();
sendToUiThread("鉴权失败 =" + errorMsg);
return false;
} else {
sendToUiThread("验证通过,离线正式授权文件存在。");
}
}
setParams(config.getParams());
// 初始化tts
int result = mSpeechSynthesizer.initTts(config.getTtsMode());
if (result != 0) {
sendToUiThread("【error】initTts 初始化失败 + errorCode:" + result);
return false;
}
// 此时可以调用 speak和synthesize方法
sendToUiThread(INIT_SUCCESS, "合成引擎初始化成功");
return true;
}
/**
* 合成并播放
*
* @param text 小于1024 GBK字节,即512个汉字或者字母数字
* @return
*/
public int speak(String text) {
Log.i(TAG, "speak text:" + text);
return mSpeechSynthesizer.speak(text);
}
/**
* 合成并播放
*
* @param text 小于1024 GBK字节,即512个汉字或者字母数字
* @param utteranceId 用于listener的回调,默认"0"
* @return
*/
public int speak(String text, String utteranceId) {
return mSpeechSynthesizer.speak(text, utteranceId);
}
/**
* 只合成不播放
*
* @param text
* @return
*/
public int synthesize(String text) {
return mSpeechSynthesizer.synthesize(text);
}
public int synthesize(String text, String utteranceId) {
return mSpeechSynthesizer.synthesize(text, utteranceId);
}
public int batchSpeak(List<Pair<String, String>> texts) {
List<SpeechSynthesizeBag> bags = new ArrayList<SpeechSynthesizeBag>();
for (Pair<String, String> pair : texts) {
SpeechSynthesizeBag speechSynthesizeBag = new SpeechSynthesizeBag();
speechSynthesizeBag.setText(pair.first);
if (pair.second != null) {
speechSynthesizeBag.setUtteranceId(pair.second);
}
bags.add(speechSynthesizeBag);
}
return mSpeechSynthesizer.batchSpeak(bags);
}
public void setParams(Map<String, String> params) {
if (params != null) {
for (Map.Entry<String, String> e : params.entrySet()) {
mSpeechSynthesizer.setParam(e.getKey(), e.getValue());
}
}
}
public int pause() {
return mSpeechSynthesizer.pause();
}
public int resume() {
return mSpeechSynthesizer.resume();
}
public int stop() {
return mSpeechSynthesizer.stop();
}
/**
* 引擎在合成时该方法不能调用!!!
* 注意 只有 TtsMode.MIX 才可以切换离线发音
*
* @return
*/
public int loadModel(String modelFilename, String textFilename) {
int res = mSpeechSynthesizer.loadModel(modelFilename, textFilename);
sendToUiThread("切换离线发音人成功。");
return res;
}
/**
* 设置播放音量,默认已经是最大声音
* 0.0f为最小音量,1.0f为最大音量
*
* @param leftVolume [0-1] 默认1.0f
* @param rightVolume [0-1] 默认1.0f
*/
public void setStereoVolume(float leftVolume, float rightVolume) {
mSpeechSynthesizer.setStereoVolume(leftVolume, rightVolume);
}
public void release() {
mSpeechSynthesizer.stop();
mSpeechSynthesizer.release();
mSpeechSynthesizer = null;
isInitied = false;
}
protected void sendToUiThread(String message) {
sendToUiThread(PRINT, message);
}
protected void sendToUiThread(int action, String message) {
Log.i(TAG, "what:"+action+"message:"+message);
}
}
package com.baidu.android.tts;
import android.content.Context;
import android.content.res.AssetManager;
import android.util.Log;
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.FileExtensionHelper;
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.FileUtil;
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.SDCardHelper;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import static android.content.ContentValues.TAG;
/**
* Created by fujiayi on 2017/5/19.
*/
public class OfflineResource {
public static final String VOICE_FEMALE = "F";
public static final String VOICE_MALE = "M";
public static final String VOICE_DUYY = "Y";
public static final String VOICE_DUXY = "X";
private static final String SAMPLE_DIR = "baiduTTS";
private AssetManager assets;
private String destPath;
private String textFilename;
private String modelFilename;
private static HashMap<String, Boolean> mapInitied = new HashMap<String, Boolean>();
public OfflineResource(Context context, String voiceType) throws IOException {
context = context.getApplicationContext();
this.assets = context.getApplicationContext().getAssets();
this.destPath = createTmpDir(context);
setOfflineVoiceType(voiceType);
}
private String createTmpDir(Context context) {
String sampleDir = "baiduASR";
String samplePath = FileExtensionHelper.getXBPMBaseFolder() + File.separator + sampleDir;
if (!SDCardHelper.INSTANCE.makeDir(samplePath)) {
samplePath = context.getExternalFilesDir(sampleDir).getAbsolutePath();
if (!SDCardHelper.INSTANCE.makeDir(samplePath)) {
//throw new RuntimeException("创建临时目录失败 :" + samplePath);
}
}
return samplePath;
}
public String getModelFilename() {
return modelFilename;
}
public String getTextFilename() {
return textFilename;
}
public void setOfflineVoiceType(String voiceType) throws IOException {
String text = "bd_etts_text.dat";
String model;
if (VOICE_MALE.equals(voiceType)) {
model = "bd_etts_common_speech_m15_mand_eng_high_am-mix_v3.0.0_20170505.dat";
} else if (VOICE_FEMALE.equals(voiceType)) {
model = "bd_etts_common_speech_f7_mand_eng_high_am-mix_v3.0.0_20170512.dat";
} else if (VOICE_DUXY.equals(voiceType)) {
model = "bd_etts_common_speech_yyjw_mand_eng_high_am-mix_v3.0.0_20170512.dat";
} else if (VOICE_DUYY.equals(voiceType)) {
model = "bd_etts_common_speech_as_mand_eng_high_am_v3.0.0_20170516.dat";
} else {
throw new RuntimeException("voice type is not in list");
}
textFilename = copyAssetsFile(text);
modelFilename = copyAssetsFile(model);
}
private String copyAssetsFile(String sourceFilename) throws IOException {
String destFilename = destPath + "/" + sourceFilename;
boolean recover = false;
Boolean existed = mapInitied.get(sourceFilename); // 启动时完全覆盖一次
if (existed == null || !existed) {
recover = true;
}
FileUtil.INSTANCE.copyFromAssets(assets, sourceFilename, destFilename, recover);
Log.i(TAG, "文件复制成功:" + destFilename);
return destFilename;
}
}
package com.baidu.android.voicedemo.control;
import android.speech.SpeechRecognizer;
/**
* Created by fujiayi on 2017/6/14.
*/
public class ErrorTranslation {
public static String recogError(int errorCode) {
String message;
switch (errorCode) {
case SpeechRecognizer.ERROR_AUDIO:
message = "音频问题";
break;
case SpeechRecognizer.ERROR_SPEECH_TIMEOUT:
message = "没有语音输入";
break;
case SpeechRecognizer.ERROR_CLIENT:
message = "其它客户端错误";
break;
case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS:
message = "权限不足";
break;
case SpeechRecognizer.ERROR_NETWORK:
message = "网络问题";
break;
case SpeechRecognizer.ERROR_NO_MATCH:
message = "没有匹配的识别结果";
break;
case SpeechRecognizer.ERROR_RECOGNIZER_BUSY:
message = "引擎忙";
break;
case SpeechRecognizer.ERROR_SERVER:
message = "服务端错误";
break;
case SpeechRecognizer.ERROR_NETWORK_TIMEOUT:
message = "连接超时";
break;
default:
message = "未知错误:" + errorCode;
break;
}
return message;
}
public static String wakeupError(int errorCode) {
String message = null;
switch (errorCode) {
case 1:
message = "参数错误";
break;
case 2:
message = "网络请求发生错误";
break;
case 3:
message = "服务器数据解析错误";
break;
case 4:
message = "网络不可用";
break;
default:
message = "未知错误:" + errorCode;
break;
}
return message;
}
}
package com.baidu.android.voicedemo.control;
import android.content.Context;
import android.util.Log;
import com.baidu.android.voicedemo.recognization.IRecogListener;
import com.baidu.android.voicedemo.recognization.RecogEventAdapter;
import com.baidu.speech.EventListener;
import com.baidu.speech.EventManager;
import com.baidu.speech.EventManagerFactory;
import com.baidu.speech.asr.SpeechConstant;
import org.json.JSONObject;
import java.util.Map;
/**
* Created by fujiayi on 2017/6/13.
* EventManager内的方法如send 都可以在主线程中进行,SDK中做过处理
*/
public class MyRecognizer {
/**
* SDK 内部核心 EventManager 类
*/
private EventManager asr;
/**
* SDK 内部核心 事件回调类, 用于开发者写自己的识别回调逻辑
*/
private EventListener eventListener;
private static boolean isOfflineEngineLoaded = false;
private static boolean isInited = false;
private static final String TAG = "MyRecognizer";
/**
* 初始化
*
* @param context
* @param recogListener 将EventListener结果做解析的DEMO回调。使用RecogEventAdapter 适配EventListener
*/
public MyRecognizer(Context context, IRecogListener recogListener) {
this(context, new RecogEventAdapter(recogListener));
}
/**
* 初始化 提供 EventManagerFactory需要的Context和EventListener
*
* @param context
* @param eventListener
*/
public MyRecognizer(Context context, EventListener eventListener) {
if (isInited) {
Log.e(TAG, "还未调用release(),请勿新建一个新类");
throw new RuntimeException("还未调用release(),请勿新建一个新类");
}
isInited = true;
this.eventListener = eventListener;
asr = EventManagerFactory.create(context, "asr");
asr.registerListener(eventListener);
}
/**
* @param params
*/
public void loadOfflineEngine(Map<String, Object> params) {
String json = new JSONObject(params).toString();
Log.i(TAG + ".Debug", "loadOfflineEngine params:" + json);
asr.send(SpeechConstant.ASR_KWS_LOAD_ENGINE, json, null, 0, 0);
isOfflineEngineLoaded = true;
// 没有ASR_KWS_LOAD_ENGINE这个回调表试失败,如缺少第一次联网时下载的正式授权文件。
}
public void start(Map<String, Object> params) {
String json = new JSONObject(params).toString();
Log.i(TAG + ".Debug", "asr params(识别参数,反馈请带上此行日志):" + json);
asr.send(SpeechConstant.ASR_START, json, null, 0, 0);
}
/**
* 提前结束录音等待识别结果。
*/
public void stop() {
Log.i(TAG, "停止录音");
asr.send(SpeechConstant.ASR_STOP, "{}", null, 0, 0);
}
/**
* 取消本次识别,取消后将立即停止不会返回识别结果。
* cancel 与stop的区别是 cancel在stop的基础上,完全停止整个识别流程,
*/
public void cancel() {
Log.i(TAG, "取消识别");
if (asr != null) {
asr.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0);
}
}
public void release() {
if (asr == null) {
return;
}
cancel();
if (isOfflineEngineLoaded) {
asr.send(SpeechConstant.ASR_KWS_UNLOAD_ENGINE, null, null, 0, 0);
isOfflineEngineLoaded = false;
}
asr.unregisterListener(eventListener);
asr = null;
isInited = false;
}
}
package com.baidu.android.voicedemo.recognization;
import java.util.ArrayList;
/**
* Created by fujiayi on 2017/10/18.
*/
public class ChainRecogListener implements IRecogListener {
private ArrayList<IRecogListener> listeners;
public ChainRecogListener() {
listeners = new ArrayList<IRecogListener>();
}
public void addListener(IRecogListener listener) {
listeners.add(listener);
}
/**
* ASR_START 输入事件调用后,引擎准备完毕
*/
@Override
public void onAsrReady() {
for (IRecogListener listener : listeners) {
listener.onAsrReady();
}
}
/**
* onAsrReady后检查到用户开始说话
*/
@Override
public void onAsrBegin() {
for (IRecogListener listener : listeners) {
listener.onAsrBegin();
}
}
/**
* 检查到用户开始说话停止,或者ASR_STOP 输入事件调用后,
*/
@Override
public void onAsrEnd() {
for (IRecogListener listener : listeners) {
listener.onAsrEnd();
}
}
/**
* onAsrBegin 后 随着用户的说话,返回的临时结果
*
* @param results 可能返回多个结果,请取第一个结果
* @param recogResult 完整的结果
*/
@Override
public void onAsrPartialResult(String[] results, RecogResult recogResult) {
for (IRecogListener listener : listeners) {
listener.onAsrPartialResult(results, recogResult);
}
}
/**
* 最终的识别结果
*
* @param results 可能返回多个结果,请取第一个结果
* @param recogResult 完整的结果
*/
@Override
public void onAsrFinalResult(String[] results, RecogResult recogResult) {
for (IRecogListener listener : listeners) {
listener.onAsrFinalResult(results, recogResult);
}
}
@Override
public void onAsrFinish(RecogResult recogResult) {
for (IRecogListener listener : listeners) {
listener.onAsrFinish(recogResult);
}
}
@Override
public void onAsrFinishError(int errorCode, int subErrorCode, String errorMessage, String descMessage,
RecogResult recogResult) {
for (IRecogListener listener : listeners) {
listener.onAsrFinishError(errorCode, subErrorCode, errorMessage, descMessage, recogResult);
}
}
/**
* 长语音识别结束
*/
@Override
public void onAsrLongFinish() {
for (IRecogListener listener : listeners) {
listener.onAsrLongFinish();
}
}
@Override
public void onAsrVolume(int volumePercent, int volume) {
for (IRecogListener listener : listeners) {
listener.onAsrVolume(volumePercent, volume);
}
}
@Override
public void onAsrAudio(byte[] data, int offset, int length) {
for (IRecogListener listener : listeners) {
listener.onAsrAudio(data, offset, length);
}
}
@Override
public void onAsrExit() {
for (IRecogListener listener : listeners) {
listener.onAsrExit();
}
}
@Override
public void onAsrOnlineNluResult(String nluResult) {
for (IRecogListener listener : listeners) {
listener.onAsrOnlineNluResult(nluResult);
}
}
@Override
public void onOfflineLoaded() {
for (IRecogListener listener : listeners) {
listener.onOfflineLoaded();
}
}
@Override
public void onOfflineUnLoaded() {
for (IRecogListener listener : listeners) {
listener.onOfflineUnLoaded();
}
}
}
package com.baidu.android.voicedemo.recognization;
import android.app.Activity;
import android.content.SharedPreferences;
import android.util.Log;
import com.baidu.speech.asr.SpeechConstant;
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.R;
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.FileExtensionHelper;
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.SDCardHelper;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* Created by fujiayi on 2017/6/20.
*/
public class CommonRecogParams {
protected String samplePath;
/**
* 字符串格式的参数
*/
protected ArrayList<String> stringParams = new ArrayList<String>();
/**
* int格式的参数
*/
protected ArrayList<String> intParams = new ArrayList<String>();
/**
* bool格式的参数
*/
protected ArrayList<String> boolParams = new ArrayList<String>();
private static final String TAG = "CommonRecogParams";
public CommonRecogParams(Activity context) {
stringParams.addAll(Arrays.asList(
SpeechConstant.VAD,
SpeechConstant.IN_FILE
));
intParams.addAll(Arrays.asList(
SpeechConstant.PID,
SpeechConstant.VAD_ENDPOINT_TIMEOUT
));
boolParams.addAll(Arrays.asList(
SpeechConstant.ACCEPT_AUDIO_DATA,
SpeechConstant.ACCEPT_AUDIO_VOLUME
));
initSamplePath(context);
}
/**
* 创建保存OUTFILE的临时目录. 仅用于OUTFILE参数。不使用demo中的OUTFILE参数可忽略此段
*
* @param context
*/
protected void initSamplePath(Activity context) {
String sampleDir = "baiduASR";
samplePath = FileExtensionHelper.getXBPMBaseFolder() + File.separator + sampleDir;
if (!SDCardHelper.INSTANCE.makeDir(samplePath)) {
samplePath = context.getApplication().getExternalFilesDir(sampleDir).getAbsolutePath();
if (!SDCardHelper.INSTANCE.makeDir(samplePath)) {
throw new RuntimeException("创建临时目录失败 :" + samplePath);
}
}
}
public Map<String, Object> fetch(SharedPreferences sp) {
Map<String, Object> map = new HashMap<String, Object>();
parseParamArr(sp, map);
if (sp.getBoolean("_tips_sound", false)) { // 声音回调
map.put(SpeechConstant.SOUND_START, R.raw.bdspeech_recognition_start);
map.put(SpeechConstant.SOUND_END, R.raw.bdspeech_speech_end);
map.put(SpeechConstant.SOUND_SUCCESS, R.raw.bdspeech_recognition_success);
map.put(SpeechConstant.SOUND_ERROR, R.raw.bdspeech_recognition_error);
map.put(SpeechConstant.SOUND_CANCEL, R.raw.bdspeech_recognition_cancel);
}
if (sp.getBoolean("_outfile", false)) { // 保存录音文件
map.put(SpeechConstant.ACCEPT_AUDIO_DATA, true); // 目前必须开启此回掉才嫩保存音频
map.put(SpeechConstant.OUT_FILE, samplePath + "/outfile.pcm");
Log.i(TAG, "语音录音文件将保存在:" + samplePath + "/outfile.pcm");
}
return map;
}
/**
* 根据 stringParams intParams boolParams中定义的参数名称,提取SharedPreferences相关字段
*
* @param sp
* @param map
*/
private void parseParamArr(SharedPreferences sp, Map<String, Object> map) {
for (String name : stringParams) {
if (sp.contains(name)) {
String tmp = sp.getString(name, "").replaceAll(",.*", "").trim();
if (null != tmp && !"".equals(tmp)) {
map.put(name, tmp);
}
}
}
for (String name : intParams) {
if (sp.contains(name)) {
String tmp = sp.getString(name, "").replaceAll(",.*", "").trim();
if (null != tmp && !"".equals(tmp)) {
map.put(name, Integer.parseInt(tmp));
}
}
}
for (String name : boolParams) {
if (sp.contains(name)) {
boolean res = sp.getBoolean(name, false);
if (res || name.equals(SpeechConstant.ACCEPT_AUDIO_VOLUME)){
map.put(name, res);
}
}
}
}
}
package com.baidu.android.voicedemo.recognization;
/**
* Created by fujiayi on 2017/6/14.
*/
public interface IRecogListener {
/**
* ASR_START 输入事件调用后,引擎准备完毕
*/
void onAsrReady();
/**
* onAsrReady后检查到用户开始说话
*/
void onAsrBegin();
/**
* 检查到用户开始说话停止,或者ASR_STOP 输入事件调用后,
*/
void onAsrEnd();
/**
* onAsrBegin 后 随着用户的说话,返回的临时结果
*
* @param results 可能返回多个结果,请取第一个结果
* @param recogResult 完整的结果
*/
void onAsrPartialResult(String[] results, RecogResult recogResult);
/**
* 最终的识别结果
*
* @param results 可能返回多个结果,请取第一个结果
* @param recogResult 完整的结果
*/
void onAsrFinalResult(String[] results, RecogResult recogResult);
void onAsrFinish(RecogResult recogResult);
void onAsrFinishError(int errorCode, int subErrorCode, String errorMessage, String descMessage,
RecogResult recogResult);
/**
* 长语音识别结束
*/
void onAsrLongFinish();
void onAsrVolume(int volumePercent, int volume);
void onAsrAudio(byte[] data, int offset, int length);
void onAsrExit();
void onAsrOnlineNluResult(String nluResult);
void onOfflineLoaded();
void onOfflineUnLoaded();
}
package com.baidu.android.voicedemo.recognization;
/**
* Created by fujiayi on 2017/6/14.
*/
public interface IStatus {
int STATUS_NONE = 2;
int STATUS_READY = 3;
int STATUS_SPEAKING = 4;
int STATUS_RECOGNITION = 5;
int STATUS_FINISHED = 6;
int STATUS_STOPPED = 10;
int STATUS_WAITING_READY = 8001;
int WHAT_MESSAGE_STATUS = 9001;
int STATUS_WAKEUP_SUCCESS = 7001;
int STATUS_WAKEUP_EXIT = 7003;
}
package com.baidu.android.voicedemo.recognization;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
/**
* Created by fujiayi on 2017/6/16.
*/
public class MessageStatusRecogListener extends StatusRecogListener {
private Handler handler;
private long speechEndTime;
private boolean needTime = true;
private static final String TAG = "MesStatusRecogListener";
public MessageStatusRecogListener(Handler handler) {
this.handler = handler;
}
@Override
public void onAsrReady() {
super.onAsrReady();
sendStatusMessage("引擎就绪,可以开始说话。");
}
@Override
public void onAsrBegin() {
super.onAsrBegin();
sendStatusMessage("检测到用户说话");
}
@Override
public void onAsrEnd() {
super.onAsrEnd();
speechEndTime = System.currentTimeMillis();
sendMessage("检测到用户说话结束");
}
@Override
public void onAsrPartialResult(String[] results, RecogResult recogResult) {
sendStatusMessage("临时识别结果,结果是“" + results[0] + "”;原始json:" + recogResult.getOrigalJson());
super.onAsrPartialResult(results, recogResult);
}
@Override
public void onAsrFinalResult(String[] results, RecogResult recogResult) {
super.onAsrFinalResult(results, recogResult);
String message = "识别结束,结果是”" + results[0] + "”";
sendStatusMessage(message + "“;原始json:" + recogResult.getOrigalJson());
if (speechEndTime > 0) {
long diffTime = System.currentTimeMillis() - speechEndTime;
message += ";说话结束到识别结束耗时【" + diffTime + "ms】";
}
speechEndTime = 0;
sendMessage(message, status, true);
}
@Override
public void onAsrFinishError(int errorCode, int subErrorCode, String errorMessage, String descMessage,
RecogResult recogResult) {
super.onAsrFinishError(errorCode, subErrorCode, errorMessage, descMessage, recogResult);
String message = "识别错误, 错误码:" + errorCode + " ," + subErrorCode + " ; " + descMessage;
sendStatusMessage(message + ";错误消息:" + errorMessage + ";描述信息:" + descMessage);
if (speechEndTime > 0) {
long diffTime = System.currentTimeMillis() - speechEndTime;
message += "。说话结束到识别结束耗时【" + diffTime + "ms】";
}
speechEndTime = 0;
sendMessage(message, status, true);
speechEndTime = 0;
}
@Override
public void onAsrOnlineNluResult(String nluResult) {
super.onAsrOnlineNluResult(nluResult);
if (!nluResult.isEmpty()) {
sendStatusMessage("原始语义识别结果json:" + nluResult);
}
}
@Override
public void onAsrFinish(RecogResult recogResult) {
super.onAsrFinish(recogResult);
sendStatusMessage("识别一段话结束。如果是长语音的情况会继续识别下段话。");
}
/**
* 长语音识别结束
*/
@Override
public void onAsrLongFinish() {
super.onAsrLongFinish();
sendStatusMessage("长语音识别结束。");
}
/**
* 使用离线命令词时,有该回调说明离线语法资源加载成功
*/
@Override
public void onOfflineLoaded() {
sendStatusMessage("【重要】asr.loaded:离线资源加载成功。没有此回调可能离线语法功能不能使用。");
}
/**
* 使用离线命令词时,有该回调说明离线语法资源加载成功
*/
@Override
public void onOfflineUnLoaded() {
sendStatusMessage(" 离线资源卸载成功。");
}
@Override
public void onAsrExit() {
super.onAsrExit();
sendStatusMessage("识别引擎结束并空闲中");
}
private void sendStatusMessage(String message) {
sendMessage(message, status);
}
private void sendMessage(String message) {
sendMessage(message, WHAT_MESSAGE_STATUS);
}
private void sendMessage(String message, int what) {
sendMessage(message, what, false);
}
private void sendMessage(String message, int what, boolean highlight) {
if (needTime && what != STATUS_FINISHED) {
message += " ;time=" + System.currentTimeMillis();
}
if (handler == null){
Log.i(TAG, message );
return;
}
Message msg = Message.obtain();
msg.what = what;
msg.arg1 = status;
if (highlight) {
msg.arg2 = 1;
}
msg.obj = message + "\n";
handler.sendMessage(msg);
}
}
package com.baidu.android.voicedemo.recognization;
import android.util.Log;
import com.baidu.android.voicedemo.control.ErrorTranslation;
import com.baidu.speech.EventListener;
import com.baidu.speech.asr.SpeechConstant;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Created by fujiayi on 2017/6/14.
*/
public class RecogEventAdapter implements EventListener {
private static final String TAG = "RecogEventAdapter";
private IRecogListener listener;
public RecogEventAdapter(IRecogListener listener) {
this.listener = listener;
}
protected String currentJson;
@Override
public void onEvent(String name, String params, byte[] data, int offset, int length) {
currentJson = params;
String logMessage = "name:" + name + "; params:" + params;
// logcat 中 搜索RecogEventAdapter,即可以看见下面一行的日志
Log.i(TAG, logMessage);
if (false) { // 可以调试,不需要后续逻辑
return;
}
if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_LOADED)) {
listener.onOfflineLoaded();
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_UNLOADED)) {
listener.onOfflineUnLoaded();
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_READY)) {
// 引擎准备就绪,可以开始说话
listener.onAsrReady();
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_BEGIN)) {
// 检测到用户的已经开始说话
listener.onAsrBegin();
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_END)) {
// 检测到用户的已经停止说话
listener.onAsrEnd();
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)) {
RecogResult recogResult = RecogResult.parseJson(params);
// 临时识别结果, 长语音模式需要从此消息中取出结果
String[] results = recogResult.getResultsRecognition();
if (recogResult.isFinalResult()) {
listener.onAsrFinalResult(results, recogResult);
} else if (recogResult.isPartialResult()) {
listener.onAsrPartialResult(results, recogResult);
} else if (recogResult.isNluResult()) {
listener.onAsrOnlineNluResult(new String(data, offset, length));
}
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_FINISH)) {
// 识别结束, 最终识别结果或可能的错误
RecogResult recogResult = RecogResult.parseJson(params);
if (recogResult.hasError()) {
int errorCode = recogResult.getError();
int subErrorCode = recogResult.getSubError();
Log.e(TAG, "asr error:" + params);
listener.onAsrFinishError(errorCode, subErrorCode, ErrorTranslation.recogError(errorCode), recogResult.getDesc(), recogResult);
} else {
listener.onAsrFinish(recogResult);
}
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_LONG_SPEECH)) { //长语音
listener.onAsrLongFinish();// 长语音
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_EXIT)) {
listener.onAsrExit();
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_VOLUME)) {
// Logger.info(TAG, "asr volume event:" + params);
Volume vol = parseVolumeJson(params);
listener.onAsrVolume(vol.volumePercent, vol.volume);
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_AUDIO)) {
if (data.length != length) {
Log.e(TAG, "internal error: asr.audio callback data length is not equal to length param");
}
listener.onAsrAudio(data, offset, length);
}
}
private Volume parseVolumeJson(String jsonStr) {
Volume vol = new Volume();
vol.origalJson = jsonStr;
try {
JSONObject json = new JSONObject(jsonStr);
vol.volumePercent = json.getInt("volume-percent");
vol.volume = json.getInt("volume");
} catch (JSONException e) {
e.printStackTrace();
}
return vol;
}
private class Volume {
private int volumePercent = -1;
private int volume = -1;
private String origalJson;
}
}
package com.baidu.android.voicedemo.recognization;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Created by fujiayi on 2017/6/24.
*/
public class RecogResult {
private static final int ERROR_NONE = 0;
private String origalJson;
private String[] resultsRecognition;
private String origalResult;
private String sn; // 日志id, 请求有问题请提问带上sn
private String desc;
private String resultType;
private int error = -1;
private int subError = -1;
public static RecogResult parseJson(String jsonStr) {
RecogResult result = new RecogResult();
result.setOrigalJson(jsonStr);
try {
JSONObject json = new JSONObject(jsonStr);
int error = json.optInt("error");
int subError = json.optInt("sub_error");
result.setError(error);
result.setDesc(json.optString("desc"));
result.setResultType(json.optString("result_type"));
result.setSubError(subError);
if (error == ERROR_NONE) {
result.setOrigalResult(json.getString("origin_result"));
JSONArray arr = json.optJSONArray("results_recognition");
if (arr != null) {
int size = arr.length();
String[] recogs = new String[size];
for (int i = 0; i < size; i++) {
recogs[i] = arr.getString(i);
}
result.setResultsRecognition(recogs);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return result;
}
public boolean hasError() {
return error != ERROR_NONE;
}
public boolean isFinalResult() {
return "final_result".equals(resultType);
}
public boolean isPartialResult() {
return "partial_result".equals(resultType);
}
public boolean isNluResult() {
return "nlu_result".equals(resultType);
}
public String getOrigalJson() {
return origalJson;
}
public void setOrigalJson(String origalJson) {
this.origalJson = origalJson;
}
public String[] getResultsRecognition() {
return resultsRecognition;
}
public void setResultsRecognition(String[] resultsRecognition) {
this.resultsRecognition = resultsRecognition;
}
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public int getError() {
return error;
}
public void setError(int error) {
this.error = error;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getOrigalResult() {
return origalResult;
}
public void setOrigalResult(String origalResult) {
this.origalResult = origalResult;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public int getSubError() {
return subError;
}
public void setSubError(int subError) {
this.subError = subError;
}
}
package com.baidu.android.voicedemo.recognization;
/**
* Created by fujiayi on 2017/6/14.
*/
import android.util.Log;
public class StatusRecogListener implements IRecogListener, IStatus {
private static final String TAG = "StatusRecogListener";
/**
* 识别的引擎当前的状态
*/
protected int status = STATUS_NONE;
@Override
public void onAsrReady() {
status = STATUS_READY;
}
@Override
public void onAsrBegin() {
status = STATUS_SPEAKING;
}
@Override
public void onAsrEnd() {
status = STATUS_RECOGNITION;
}
@Override
public void onAsrPartialResult(String[] results, RecogResult recogResult) {
}
@Override
public void onAsrFinalResult(String[] results, RecogResult recogResult) {
status = STATUS_FINISHED;
}
@Override
public void onAsrFinish(RecogResult recogResult) {
status = STATUS_FINISHED;
}
@Override
public void onAsrFinishError(int errorCode, int subErrorCode, String errorMessage, String descMessage,
RecogResult recogResult) {
status = STATUS_FINISHED;
}
/**
* 长语音识别结束
*/
@Override
public void onAsrLongFinish() {
status = STATUS_FINISHED;
}
@Override
public void onAsrVolume(int volumePercent, int volume) {
Log.i(TAG, "音量百分比" + volumePercent + " ; 音量" + volume);
}
@Override
public void onAsrAudio(byte[] data, int offset, int length) {
if (offset != 0 || data.length != length) {
byte[] actualData = new byte[length];
System.arraycopy(data, 0, actualData, 0, length);
data = actualData;
}
Log.i(TAG, "音频数据回调, length:" + data.length);
}
@Override
public void onAsrExit() {
status = STATUS_NONE;
}
@Override
public void onAsrOnlineNluResult(String nluResult) {
status = STATUS_FINISHED;
}
@Override
public void onOfflineLoaded() {
}
@Override
public void onOfflineUnLoaded() {
}
}
package com.baidu.android.voicedemo.recognization.all;
import android.app.Activity;
import com.baidu.android.voicedemo.recognization.CommonRecogParams;
import com.baidu.speech.asr.SpeechConstant;
import java.util.Arrays;
/**
* Created by fujiayi on 2017/6/24.
*/
public class AllRecogParams extends CommonRecogParams {
private static final String TAG = "NluRecogParams";
public AllRecogParams(Activity context) {
super(context);
stringParams.addAll(Arrays.asList(
SpeechConstant.NLU,
"_language",
"_model"));
intParams.addAll(Arrays.asList(
SpeechConstant.DECODER,
SpeechConstant.PROP));
boolParams.addAll(Arrays.asList(SpeechConstant.DISABLE_PUNCTUATION, "_nlu_online"));
// copyOfflineResource(context);
}
}
package com.baidu.android.voicedemo.recognization.inputstream;
import android.util.Log;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by fujiayi on 2017/11/27.
* <p>
* 解决大文件的输入问题。
*/
public class FileAudioInputStream extends InputStream {
private InputStream in;
private long nextSleepTime = -1;
private long totalSleepMs = 0;
private static final String TAG = "FileAudioInputStream";
public FileAudioInputStream(String file) throws FileNotFoundException {
in = new FileInputStream(file);
}
public FileAudioInputStream(InputStream in) {
this.in = in;
}
@Override
public int read() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
int bytePerMs = 16000 * 2 / 1000;
int count = bytePerMs * 20 ; // 10ms 音频数据
if (byteCount < count){
count = byteCount;
}
if (nextSleepTime > 0){
try {
long sleepMs = nextSleepTime - System.currentTimeMillis() ;
if (sleepMs > 0){
Log.i(TAG, "will sleep "+ sleepMs);
Thread.sleep(sleepMs);
totalSleepMs += sleepMs;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int r = in.read(buffer, byteOffset, count);
nextSleepTime = System.currentTimeMillis() + r/bytePerMs;
return r;
}
@Override
public void close() throws IOException {
super.close();
Log.i(TAG, "time sleeped "+ totalSleepMs);
if (null != in) {
in.close();
}
}
}
package com.baidu.android.voicedemo.recognization.inputstream;
import android.app.Activity;
import android.util.Log;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by fujiayi on 2017/6/20.
*/
public class InFileStream {
private static Activity context;
private static final String TAG = "InFileStream";
public static void setContext(Activity context) {
InFileStream.context = context;
}
private static String filename;
private static InputStream is;
public static void reset() {
filename = null;
is = null;
}
public static void setFileName(String filename) {
InFileStream.filename = filename;
}
public static void setInputStream(InputStream is2) {
is = is2;
}
public static InputStream create16kStream() {
if (is != null) {
return new FileAudioInputStream(is);
} else if (filename != null) {
try {
return new FileAudioInputStream(filename);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
} else {
return new FileAudioInputStream(createFileStream());
}
return null;
}
private static InputStream createFileStream() {
InputStream res = null;
try {
InputStream is = context.getAssets().open("outfile.pcm");
Log.i(TAG, "create input stream ok " + is.available());
res = new FileAudioInputStream(is);
} catch (IOException e) {
e.printStackTrace();
}
return res;
}
}
\ No newline at end of file
package com.baidu.android.voicedemo.recognization.inputstream;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.support.annotation.NonNull;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by fujiayi on 2017/11/27.
*/
public class MyMicrophoneInputStream extends InputStream {
private static AudioRecord audioRecord;
private static MyMicrophoneInputStream is;
private boolean isStarted = false;
private static final String TAG = "MyMicrophoneInputStream";
public MyMicrophoneInputStream() {
if (audioRecord == null) {
int bufferSize = AudioRecord.getMinBufferSize(16000,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT) * 16;
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
16000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
}
}
public static MyMicrophoneInputStream getInstance() {
if (is == null) {
synchronized (MyMicrophoneInputStream.class) {
if (is == null) {
is = new MyMicrophoneInputStream();
}
}
}
return is;
}
public void start() {
Log.i(TAG, " MyMicrophoneInputStream start recoding!");
try {
if (audioRecord == null
|| audioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
throw new IllegalStateException(
"startRecording() called on an uninitialized AudioRecord." + (audioRecord == null));
}
audioRecord.startRecording();
}catch(Exception e){
Log.e(TAG,e.getClass().getSimpleName(),e);
}
Log.i(TAG, " MyMicrophoneInputStream start recoding finished");
}
@Override
public int read() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public int read(@NonNull byte[] b, int off, int len) throws IOException {
if (!isStarted) {
start(); // 建议在CALLBACK_EVENT_ASR_READY事件中调用。
isStarted = true;
}
try{
int count = audioRecord.read(b, off, len);
// Log.i(TAG, " MyMicrophoneInputStream read count:" + count);
return count;
}catch (Exception e){
Log.e(TAG, e.getClass().getSimpleName(),e);
throw e;
}
}
@Override
public void close() throws IOException {
Log.i(TAG, " MyMicrophoneInputStream close");
if (audioRecord != null) {
audioRecord.stop();
// audioRecord.release(); 程序结束别忘记自行释放
isStarted = false;
}
}
}
package com.baidu.android.voicedemo.recognization.nlu;
import android.app.Activity;
import android.content.SharedPreferences;
import com.baidu.android.voicedemo.recognization.CommonRecogParams;
import com.baidu.android.voicedemo.recognization.offline.OfflineRecogParams;
import com.baidu.speech.asr.SpeechConstant;
import java.util.Arrays;
import java.util.Map;
/**
* Created by fujiayi on 2017/6/24.
*/
public class NluRecogParams extends CommonRecogParams {
private static final String TAG = "NluRecogParams";
public NluRecogParams(Activity context) {
super(context);
stringParams.addAll(Arrays.asList(SpeechConstant.NLU));
intParams.addAll(Arrays.asList(SpeechConstant.DECODER, SpeechConstant.PROP));
boolParams.addAll(Arrays.asList("_nlu_online"));
// copyOfflineResource(context);
}
public Map<String, Object> fetch(SharedPreferences sp) {
Map<String, Object> map = super.fetch(sp);
if (sp.getBoolean("_grammar", false)) {
Map<String, Object> offlineParams = OfflineRecogParams.fetchOfflineParams();
map.put(SpeechConstant.ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH,
offlineParams.get(SpeechConstant.ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH));
}
if (sp.getBoolean("_slot_data", false)) {
map.putAll(OfflineRecogParams.fetchSlotDataParam());
}
if (sp.getBoolean("_nlu_online", false)) {
map.put("_model", "search");
}
return map;
}
}
package com.baidu.android.voicedemo.recognization.offline;
import android.app.Activity;
import android.content.SharedPreferences;
import com.baidu.android.voicedemo.recognization.CommonRecogParams;
import com.baidu.speech.asr.SpeechConstant;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
/**
* Created by fujiayi on 2017/6/13.
*/
public class OfflineRecogParams extends CommonRecogParams {
private static final String TAG = "OnlineRecogParams";
public OfflineRecogParams(Activity context) {
super(context);
}
public Map<String, Object> fetch(SharedPreferences sp) {
Map<String, Object> map = super.fetch(sp);
map.put(SpeechConstant.DECODER, 2);
map.remove(SpeechConstant.PID); // 去除pid,只支持中文
return map;
}
public static Map<String, Object> fetchOfflineParams() {
Map<String, Object> map = new HashMap<String, Object>();
map.put(SpeechConstant.DECODER, 2);
map.put(SpeechConstant.ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH, "assets:///baidu_speech_grammar.bsg");
map.putAll(fetchSlotDataParam());
return map;
}
public static Map<String, Object> fetchSlotDataParam() {
Map<String, Object> map = new HashMap<String, Object>();
try {
JSONObject json = new JSONObject();
json.put("name", new JSONArray().put("妈妈").put("老伍"))
.put("appname", new JSONArray().put("手百").put("度秘"));
map.put(SpeechConstant.SLOT_DATA, json);
} catch (JSONException e) {
e.printStackTrace();
}
return map;
}
}
package com.baidu.android.voicedemo.recognization.online;
import android.app.Activity;
import com.baidu.android.voicedemo.recognization.CommonRecogParams;
import com.baidu.speech.asr.SpeechConstant;
import java.util.Arrays;
/**
* Created by fujiayi on 2017/6/13.
*/
public class OnlineRecogParams extends CommonRecogParams {
private static final String TAG = "OnlineRecogParams";
public OnlineRecogParams(Activity context) {
super(context);
stringParams.addAll(Arrays.asList(
"_language", // 用于生成PID参数
"_model" // 用于生成PID参数
));
intParams.addAll(Arrays.asList(SpeechConstant.PROP));
boolParams.addAll(Arrays.asList(SpeechConstant.DISABLE_PUNCTUATION));
}
}
package com.bigkoo.convenientbanner;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.PageTransformer;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.bigkoo.convenientbanner.adapter.CBPageAdapter;
import com.bigkoo.convenientbanner.holder.CBViewHolderCreator;
import com.bigkoo.convenientbanner.listener.CBPageChangeListener;
import com.bigkoo.convenientbanner.listener.OnItemClickListener;
import com.bigkoo.convenientbanner.transformer.ScaleYTransformer;
import com.bigkoo.convenientbanner.view.CBLoopViewPager;
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.R;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* 页面翻转控件,极方便的广告栏
* 支持无限循环,自动翻页,翻页特效
* @author Sai 支持自动翻页
*/
public class ConvenientBanner<T> extends LinearLayout {
private List<T> mDatas;
private int[] page_indicatorId;
private ArrayList<ImageView> mPointViews = new ArrayList<ImageView>();
private CBPageChangeListener pageChangeListener;
private ViewPager.OnPageChangeListener onPageChangeListener;
private CBPageAdapter pageAdapter;
private CBLoopViewPager viewPager;
private ViewPagerScroller scroller;
private ViewGroup loPageTurningPoint;
private long autoTurningTime;
private boolean turning;
private boolean canTurn = false;
private boolean manualPageable = true;
private boolean canLoop = true;
private boolean coverMode = false;
public enum PageIndicatorAlign{
ALIGN_PARENT_LEFT,ALIGN_PARENT_RIGHT,CENTER_HORIZONTAL
}
private AdSwitchTask adSwitchTask ;
public ConvenientBanner(Context context) {
super(context);
init(context);
}
public ConvenientBanner(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.ConvenientBanner);
canLoop = a.getBoolean(R.styleable.ConvenientBanner_canLoop,true);
coverMode = a.getBoolean(R.styleable.ConvenientBanner_coverMode,false);
a.recycle();
init(context);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public ConvenientBanner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.ConvenientBanner);
canLoop = a.getBoolean(R.styleable.ConvenientBanner_canLoop,true);
coverMode = a.getBoolean(R.styleable.ConvenientBanner_coverMode,false);
a.recycle();
init(context);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ConvenientBanner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.ConvenientBanner);
canLoop = a.getBoolean(R.styleable.ConvenientBanner_canLoop,true);
coverMode = a.getBoolean(R.styleable.ConvenientBanner_coverMode,false);
a.recycle();
init(context);
}
private void init(Context context) {
View hView;
if (coverMode){
hView = LayoutInflater.from(context).inflate(
R.layout.include_viewpager_cover_mode, this, true);
}else {
hView = LayoutInflater.from(context).inflate(
R.layout.include_viewpager, this, true);
}
viewPager = (CBLoopViewPager) hView.findViewById(R.id.cbLoopViewPager);
loPageTurningPoint = (ViewGroup) hView
.findViewById(R.id.loPageTurningPoint);
initViewPagerScroll();
adSwitchTask = new AdSwitchTask(this);
}
static class AdSwitchTask implements Runnable {
private final WeakReference<ConvenientBanner> reference;
AdSwitchTask(ConvenientBanner convenientBanner) {
this.reference = new WeakReference<ConvenientBanner>(convenientBanner);
}
@Override
public void run() {
ConvenientBanner convenientBanner = reference.get();
if(convenientBanner != null){
if (convenientBanner.viewPager != null && convenientBanner.turning) {
int page = convenientBanner.viewPager.getCurrentItem() + 1;
convenientBanner.viewPager.setCurrentItem(page);
convenientBanner.postDelayed(convenientBanner.adSwitchTask, convenientBanner.autoTurningTime);
}
}
}
}
public ConvenientBanner setPages(CBViewHolderCreator holderCreator,List<T> datas){
this.mDatas = datas;
if (coverMode){
viewPager.setPageTransformer(false,new ScaleYTransformer());
}
pageAdapter = new CBPageAdapter(holderCreator,mDatas);
viewPager.setAdapter(pageAdapter,canLoop);
if (page_indicatorId != null)
setPageIndicator(page_indicatorId);
return this;
}
/**
* 通知数据变化
* 如果只是增加数据建议使用 notifyDataSetAdd()
*/
public void notifyDataSetChanged(){
viewPager.getAdapter().notifyDataSetChanged();
if (page_indicatorId != null)
setPageIndicator(page_indicatorId);
}
/**
* 设置底部指示器是否可见
*
* @param visible
*/
public ConvenientBanner setPointViewVisible(boolean visible) {
loPageTurningPoint.setVisibility(visible ? View.VISIBLE : View.GONE);
return this;
}
/**
* 底部指示器资源图片
*
* @param page_indicatorId
*/
public ConvenientBanner setPageIndicator(int[] page_indicatorId) {
loPageTurningPoint.removeAllViews();
mPointViews.clear();
this.page_indicatorId = page_indicatorId;
if(mDatas==null)return this;
for (int count = 0; count < mDatas.size(); count++) {
// 翻页指示的点
ImageView pointView = new ImageView(getContext());
pointView.setPadding(5, 0, 5, 0);
if (mPointViews.isEmpty())
pointView.setImageResource(page_indicatorId[1]);
else
pointView.setImageResource(page_indicatorId[0]);
mPointViews.add(pointView);
loPageTurningPoint.addView(pointView);
}
pageChangeListener = new CBPageChangeListener(mPointViews,
page_indicatorId);
viewPager.setOnPageChangeListener(pageChangeListener);
pageChangeListener.onPageSelected(viewPager.getRealItem());
if(onPageChangeListener != null)pageChangeListener.setOnPageChangeListener(onPageChangeListener);
return this;
}
/**
* 指示器的方向
* @param align 三个方向:居左 (RelativeLayout.ALIGN_PARENT_LEFT),居中 (RelativeLayout.CENTER_HORIZONTAL),居右 (RelativeLayout.ALIGN_PARENT_RIGHT)
* @return
*/
public ConvenientBanner setPageIndicatorAlign(PageIndicatorAlign align) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) loPageTurningPoint.getLayoutParams();
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, align == PageIndicatorAlign.ALIGN_PARENT_LEFT ? RelativeLayout.TRUE : 0);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, align == PageIndicatorAlign.ALIGN_PARENT_RIGHT ? RelativeLayout.TRUE : 0);
layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL, align == PageIndicatorAlign.CENTER_HORIZONTAL ? RelativeLayout.TRUE : 0);
loPageTurningPoint.setLayoutParams(layoutParams);
return this;
}
/***
* 是否开启了翻页
* @return
*/
public boolean isTurning() {
return turning;
}
/***
* 开始翻页
* @param autoTurningTime 自动翻页时间
* @return
*/
public ConvenientBanner startTurning(long autoTurningTime) {
//如果是正在翻页的话先停掉
if(turning){
stopTurning();
}
//设置可以翻页并开启翻页
canTurn = true;
this.autoTurningTime = autoTurningTime;
turning = true;
postDelayed(adSwitchTask, autoTurningTime);
return this;
}
public void stopTurning() {
turning = false;
removeCallbacks(adSwitchTask);
}
/**
* 自定义翻页动画效果
*
* @param transformer
* @return
*/
public ConvenientBanner setPageTransformer(PageTransformer transformer) {
viewPager.setPageTransformer(true, transformer);
return this;
}
/**
* 设置ViewPager的滑动速度
* */
private void initViewPagerScroll() {
try {
Field mScroller = null;
mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
scroller = new ViewPagerScroller(
viewPager.getContext());
mScroller.set(viewPager, scroller);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public boolean isManualPageable() {
return viewPager.isCanScroll();
}
public void setManualPageable(boolean manualPageable) {
viewPager.setCanScroll(manualPageable);
}
//触碰控件的时候,翻页应该停止,离开的时候如果之前是开启了翻页的话则重新启动翻页
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
if (action == MotionEvent.ACTION_UP||action == MotionEvent.ACTION_CANCEL||action == MotionEvent.ACTION_OUTSIDE) {
// 开始翻页
if (canTurn)startTurning(autoTurningTime);
} else if (action == MotionEvent.ACTION_DOWN) {
// 停止翻页
if (canTurn)stopTurning();
}
return super.dispatchTouchEvent(ev);
}
//获取当前的页面index
public int getCurrentItem(){
if (viewPager!=null) {
return viewPager.getRealItem();
}
return -1;
}
//设置当前的页面index
public void setcurrentitem(int index){
if (viewPager!=null) {
viewPager.setCurrentItem(index);
}
}
public ViewPager.OnPageChangeListener getOnPageChangeListener() {
return onPageChangeListener;
}
/**
* 设置翻页监听器
* @param onPageChangeListener
* @return
*/
public ConvenientBanner setOnPageChangeListener(ViewPager.OnPageChangeListener onPageChangeListener) {
this.onPageChangeListener = onPageChangeListener;
//如果有默认的监听器(即是使用了默认的翻页指示器)则把用户设置的依附到默认的上面,否则就直接设置
if(pageChangeListener != null)pageChangeListener.setOnPageChangeListener(onPageChangeListener);
else viewPager.setOnPageChangeListener(onPageChangeListener);
return this;
}
public boolean isCanLoop() {
return viewPager.isCanLoop();
}
/**
* 监听item点击
* @param onItemClickListener
*/
public ConvenientBanner setOnItemClickListener(OnItemClickListener onItemClickListener) {
if (onItemClickListener == null) {
viewPager.setOnItemClickListener(null);
return this;
}
viewPager.setOnItemClickListener(onItemClickListener);
return this;
}
/**
* 设置ViewPager的滚动速度
* @param scrollDuration
*/
public void setScrollDuration(int scrollDuration){
scroller.setScrollDuration(scrollDuration);
}
public int getScrollDuration() {
return scroller.getScrollDuration();
}
public CBLoopViewPager getViewPager() {
return viewPager;
}
public void setCanLoop(boolean canLoop) {
this.canLoop = canLoop;
viewPager.setCanLoop(canLoop);
}
}
package com.bigkoo.convenientbanner;
import android.content.Context;
import android.view.animation.Interpolator;
import android.widget.Scroller;
public class ViewPagerScroller extends Scroller {
private int mScrollDuration = 800;// 滑动速度,值越大滑动越慢,滑动太快会使3d效果不明显
private boolean zero;
public ViewPagerScroller(Context context) {
super(context);
}
public ViewPagerScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
public ViewPagerScroller(Context context, Interpolator interpolator,
boolean flywheel) {
super(context, interpolator, flywheel);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, zero ? 0 : mScrollDuration);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy) {
super.startScroll(startX, startY, dx, dy, zero ? 0 : mScrollDuration);
}
public int getScrollDuration() {
return mScrollDuration;
}
public void setScrollDuration(int scrollDuration) {
this.mScrollDuration = scrollDuration;
}
public boolean isZero() {
return zero;
}
public void setZero(boolean zero) {
this.zero = zero;
}
}
\ No newline at end of file
package com.bigkoo.convenientbanner.adapter;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import com.bigkoo.convenientbanner.holder.CBViewHolderCreator;
import com.bigkoo.convenientbanner.holder.Holder;
import com.bigkoo.convenientbanner.view.CBLoopViewPager;
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.R;
import java.util.List;
/**
* Created by Sai on 15/7/29.
*/
public class CBPageAdapter<T> extends PagerAdapter {
protected List<T> mDatas;
protected CBViewHolderCreator holderCreator;
// private View.OnClickListener onItemClickListener;
private boolean canLoop = true;
private CBLoopViewPager viewPager;
private final int MULTIPLE_COUNT = 300;
public int toRealPosition(int position) {
int realCount = getRealCount();
if (realCount == 0)
return 0;
int realPosition = position % realCount;
return realPosition;
}
@Override
public int getCount() {
return canLoop ? getRealCount()*MULTIPLE_COUNT : getRealCount();
}
public int getRealCount() {
return mDatas == null ? 0 : mDatas.size();
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
int realPosition = toRealPosition(position);
View view = getView(realPosition, null, container);
// if(onItemClickListener != null) view.setOnClickListener(onItemClickListener);
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
View view = (View) object;
container.removeView(view);
}
@Override
public void finishUpdate(ViewGroup container) {
int position = viewPager.getCurrentItem();
if (position == 0) {
position = viewPager.getFristItem();
} else if (position == getCount() - 1) {
position = viewPager.getLastItem();
}
try {
viewPager.setCurrentItem(position, false);
}catch (IllegalStateException e){}
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
public void setCanLoop(boolean canLoop) {
this.canLoop = canLoop;
}
public void setViewPager(CBLoopViewPager viewPager) {
this.viewPager = viewPager;
}
public CBPageAdapter(CBViewHolderCreator holderCreator, List<T> datas) {
this.holderCreator = holderCreator;
this.mDatas = datas;
}
public View getView(int position, View view, ViewGroup container) {
Holder holder = null;
if (view == null) {
holder = (Holder) holderCreator.createHolder();
view = holder.createView(container.getContext());
view.setTag(R.id.cb_item_tag, holder);
} else {
holder = (Holder<T>) view.getTag(R.id.cb_item_tag);
}
if (mDatas != null && !mDatas.isEmpty())
holder.UpdateUI(container.getContext(), position, mDatas.get(position));
return view;
}
// public void setOnItemClickListener(View.OnClickListener onItemClickListener) {
// this.onItemClickListener = onItemClickListener;
// }
}
package com.bigkoo.convenientbanner.holder;
/**
* @ClassName : ViewHolderCreator
* @Description :
* @Author Sai
* @Date 2014年11月30日 下午3:29:34
*/
public interface CBViewHolderCreator<Holder> {
public Holder createHolder();
}
package com.bigkoo.convenientbanner.holder;
/**
* Created by Sai on 15/12/14.
* @param <T> 任何你指定的对象
*/
import android.content.Context;
import android.view.View;
public interface Holder<T>{
View createView(Context context);
void UpdateUI(Context context,int position,T data);
}
\ No newline at end of file
package com.bigkoo.convenientbanner.listener;
import android.support.v4.view.ViewPager;
import android.widget.ImageView;
import java.util.ArrayList;
/**
* Created by Sai on 15/7/29.
* 翻页指示器适配器
*/
public class CBPageChangeListener implements ViewPager.OnPageChangeListener {
private ArrayList<ImageView> pointViews;
private int[] page_indicatorId;
private ViewPager.OnPageChangeListener onPageChangeListener;
public CBPageChangeListener(ArrayList<ImageView> pointViews,int page_indicatorId[]){
this.pointViews=pointViews;
this.page_indicatorId = page_indicatorId;
}
@Override
public void onPageScrollStateChanged(int state) {
if(onPageChangeListener != null)onPageChangeListener.onPageScrollStateChanged(state);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(onPageChangeListener != null)onPageChangeListener.onPageScrolled(position,positionOffset,positionOffsetPixels);
}
@Override
public void onPageSelected(int index) {
for (int i = 0; i < pointViews.size(); i++) {
pointViews.get(index).setImageResource(page_indicatorId[1]);
if (index != i) {
pointViews.get(i).setImageResource(page_indicatorId[0]);
}
}
if(onPageChangeListener != null)onPageChangeListener.onPageSelected(index);
}
public void setOnPageChangeListener(ViewPager.OnPageChangeListener onPageChangeListener) {
this.onPageChangeListener = onPageChangeListener;
}
}
package com.bigkoo.convenientbanner.listener;
/**
* Created by Sai on 15/11/13.
*/
public interface OnItemClickListener {
public void onItemClick(int position);
}
package com.bigkoo.convenientbanner.transformer;
import android.support.v4.view.ViewPager;
import android.view.View;
/**
* Created by fancyLou on 2017/12/18.
* Copyright © 2017 O2. All rights reserved.
*/
public class ScaleYTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.9F;
@Override
public void transformPage(View page, float position) {
if(position < -1){
page.setScaleY(MIN_SCALE);
}else if(position<= 1){
//
float scale = Math.max(MIN_SCALE,1 - Math.abs(position));
page.setScaleY(scale);
}else{
page.setScaleY(MIN_SCALE);
}
}
}
package com.bigkoo.convenientbanner.view;
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import com.bigkoo.convenientbanner.adapter.CBPageAdapter;
import com.bigkoo.convenientbanner.listener.OnItemClickListener;
public class CBLoopViewPager extends ViewPager {
OnPageChangeListener mOuterPageChangeListener;
private OnItemClickListener onItemClickListener;
private CBPageAdapter mAdapter;
private boolean isCanScroll = true;
private boolean canLoop = true;
public void setAdapter(PagerAdapter adapter, boolean canLoop) {
mAdapter = (CBPageAdapter) adapter;
mAdapter.setCanLoop(canLoop);
mAdapter.setViewPager(this);
super.setAdapter(mAdapter);
setCurrentItem(getFristItem(), false);
}
public int getFristItem() {
return canLoop ? mAdapter.getRealCount() : 0;
}
public int getLastItem() {
return mAdapter.getRealCount() - 1;
}
public boolean isCanScroll() {
return isCanScroll;
}
public void setCanScroll(boolean isCanScroll) {
this.isCanScroll = isCanScroll;
}
private float oldX = 0, newX = 0;
private static final float sens = 5;
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (isCanScroll) {
if (onItemClickListener != null) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
oldX = ev.getX();
break;
case MotionEvent.ACTION_UP:
newX = ev.getX();
if (Math.abs(oldX - newX) < sens) {
onItemClickListener.onItemClick((getRealItem()));
}
oldX = 0;
newX = 0;
break;
}
}
return super.onTouchEvent(ev);
} else
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (isCanScroll)
return super.onInterceptTouchEvent(ev);
else
return false;
}
public CBPageAdapter getAdapter() {
return mAdapter;
}
public int getRealItem() {
return mAdapter != null ? mAdapter.toRealPosition(super.getCurrentItem()) : 0;
}
@Override
public void setOnPageChangeListener(OnPageChangeListener listener) {
mOuterPageChangeListener = listener;
}
public CBLoopViewPager(Context context) {
super(context);
init();
}
public CBLoopViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
super.setOnPageChangeListener(onPageChangeListener);
}
private OnPageChangeListener onPageChangeListener = new OnPageChangeListener() {
private float mPreviousPosition = -1;
@Override
public void onPageSelected(int position) {
int realPosition = mAdapter.toRealPosition(position);
if (mPreviousPosition != realPosition) {
mPreviousPosition = realPosition;
if (mOuterPageChangeListener != null) {
mOuterPageChangeListener.onPageSelected(realPosition);
}
}
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
int realPosition = position;
if (mOuterPageChangeListener != null) {
if (realPosition != mAdapter.getRealCount() - 1) {
mOuterPageChangeListener.onPageScrolled(realPosition,
positionOffset, positionOffsetPixels);
} else {
if (positionOffset > .5) {
mOuterPageChangeListener.onPageScrolled(0, 0, 0);
} else {
mOuterPageChangeListener.onPageScrolled(realPosition,
0, 0);
}
}
}
}
@Override
public void onPageScrollStateChanged(int state) {
if (mOuterPageChangeListener != null) {
mOuterPageChangeListener.onPageScrollStateChanged(state);
}
}
};
public boolean isCanLoop() {
return canLoop;
}
public void setCanLoop(boolean canLoop) {
this.canLoop = canLoop;
if (canLoop == false) {
setCurrentItem(getRealItem(), false);
}
if (mAdapter == null) return;
mAdapter.setCanLoop(canLoop);
mAdapter.notifyDataSetChanged();
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册