下沉 tts 功能,分别实现"小智语音"和"小迪语音"
This commit is contained in:
4
.idea/gradle.xml
generated
4
.idea/gradle.xml
generated
@@ -71,6 +71,10 @@
|
||||
<option value="$PROJECT_DIR$/test/crashreport" />
|
||||
<option value="$PROJECT_DIR$/test/crashreport-bugly" />
|
||||
<option value="$PROJECT_DIR$/test/crashreport-noop" />
|
||||
<option value="$PROJECT_DIR$/tts" />
|
||||
<option value="$PROJECT_DIR$/tts/tts-base" />
|
||||
<option value="$PROJECT_DIR$/tts/tts-di" />
|
||||
<option value="$PROJECT_DIR$/tts/tts-zhi" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
|
||||
@@ -393,6 +393,7 @@ dependencies {
|
||||
apply from: "./functions/skin.gradle"
|
||||
apply from: "./functions/crashreport.gradle"
|
||||
apply from: "./functions/widgets.gradle"
|
||||
apply from: "./functions/tts.gradle"
|
||||
}
|
||||
|
||||
android.applicationVariants.all { variant ->
|
||||
|
||||
25
app/functions/tts.gradle
Normal file
25
app/functions/tts.gradle
Normal file
@@ -0,0 +1,25 @@
|
||||
project.dependencies {
|
||||
if (Boolean.valueOf(RELEASE)) {
|
||||
bydautoImplementation rootProject.ext.dependencies.ttszhi
|
||||
d82xImplementation rootProject.ext.dependencies.ttszhi
|
||||
em1Implementation rootProject.ext.dependencies.ttszhi
|
||||
em3Implementation rootProject.ext.dependencies.ttszhi
|
||||
d8xxImplementation rootProject.ext.dependencies.ttszhi
|
||||
d80xImplementation rootProject.ext.dependencies.ttszhi
|
||||
f8xxImplementation rootProject.ext.dependencies.ttszhi
|
||||
f80xImplementation rootProject.ext.dependencies.ttszhi
|
||||
em4Implementation rootProject.ext.dependencies.ttszhi
|
||||
e8xxImplementation rootProject.ext.dependencies.ttszhi
|
||||
} else {
|
||||
bydautoImplementation project(':tts:tts-zhi')
|
||||
d82xImplementation project(':tts:tts-zhi')
|
||||
em1Implementation project(':tts:tts-zhi')
|
||||
em3Implementation project(':tts:tts-zhi')
|
||||
d8xxImplementation project(':tts:tts-zhi')
|
||||
d80xImplementation project(':tts:tts-zhi')
|
||||
f8xxImplementation project(':tts:tts-zhi')
|
||||
f80xImplementation project(':tts:tts-zhi')
|
||||
em4Implementation project(':tts:tts-zhi')
|
||||
e8xxImplementation project(':tts:tts-zhi')
|
||||
}
|
||||
}
|
||||
@@ -207,6 +207,10 @@ targetSdkVersion : 22,
|
||||
skinsupportcardview : "com.mogo.skin:skin-support-cardview:${SKIN_SUPPORT_CARDVIEW_VERSION}",
|
||||
skinsupportconstraintlayout: "com.mogo.skin:skin-support-constraint-layout:${SKIN_SUPPORT_CONSTRAINT_LAYOUT_VERSION}",
|
||||
skinsupportdesign : "com.mogo.skin:skin-support-design:${SKIN_SUPPORT_DESIGN_VERSION}",
|
||||
|
||||
ttsbase : "com.mogo.tts:tts-base:${TTS_BASE_VERSION}",
|
||||
ttsdi : "com.mogo.tts:tts-di:${TTS_DI_VERSION}",
|
||||
ttszhi : "com.mogo.tts:tts-zhi:${TTS_ZHI_VERSION}",
|
||||
]
|
||||
|
||||
}
|
||||
@@ -36,8 +36,6 @@ android {
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
api rootProject.ext.dependencies.aiassist
|
||||
api rootProject.ext.dependencies.aiassistReplace
|
||||
api rootProject.ext.dependencies.androidxappcompat
|
||||
api rootProject.ext.dependencies.analytics
|
||||
implementation rootProject.ext.dependencies.arouter
|
||||
@@ -46,9 +44,11 @@ dependencies {
|
||||
implementation rootProject.ext.dependencies.accountsdk
|
||||
if (Boolean.valueOf(RELEASE)) {
|
||||
implementation rootProject.ext.dependencies.mogoutils
|
||||
api rootProject.ext.dependencies.ttsbase
|
||||
implementation rootProject.ext.dependencies.skinsupport
|
||||
} else {
|
||||
implementation project(":foudations:mogo-utils")
|
||||
api project(":tts:tts-base")
|
||||
implementation project(":skin:mogo-skin-support")
|
||||
}
|
||||
api 'org.greenrobot:eventbus:3.1.1'
|
||||
|
||||
@@ -14,7 +14,6 @@ import com.mogo.utils.DeviceIdUtils;
|
||||
import com.mogo.utils.WindowUtils;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
import com.mogo.utils.network.utils.GsonUtil;
|
||||
import com.zhidao.auto.platform.util.DeviceUtil;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
@@ -37,7 +36,7 @@ public class ParamsUtil {
|
||||
params.put( ServerParam.NET_TYPE, CommonUtils.getNetworkType( AbsMogoApplication.getApp() ) );
|
||||
params.put( ServerParam.CELL_ID, Utils.getCellId( AbsMogoApplication.getApp() ) );
|
||||
|
||||
params.put( ServerParam.DISPLAY_ID, DeviceUtil.getSystemVersion() );
|
||||
// params.put( ServerParam.DISPLAY_ID, DeviceUtil.getSystemVersion() );
|
||||
params.put( ServerParam.SN, Utils.getSn() );
|
||||
params.put( ServerParam.TICKET, SpStorage.getTicket() );
|
||||
|
||||
|
||||
@@ -1,25 +1,11 @@
|
||||
package com.mogo.commons.voice;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
import com.zhidao.auto.platform.voice.VoiceClient;
|
||||
import com.zhidao.voicesdk.MogoVoiceManager;
|
||||
import com.zhidao.voicesdk.MogoVoiceManagerImpl;
|
||||
import com.zhidao.voicesdk.callback.OnConnStatusListener;
|
||||
import com.zhidao.voicesdk.callback.OnTtsListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import com.alibaba.android.arouter.launcher.ARouter;
|
||||
import com.mogo.tts.base.IMogoTTS;
|
||||
import com.mogo.tts.base.MogoTTSConstants;
|
||||
import com.mogo.tts.base.PreemptType;
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
@@ -27,14 +13,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* <p>
|
||||
* 语音助手通信助手
|
||||
*/
|
||||
public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
|
||||
public class AIAssist {
|
||||
|
||||
private static final String TAG = "AIAssist";
|
||||
private static volatile AIAssist sInstance;
|
||||
private String mLastQAndASpeakText;
|
||||
|
||||
private boolean mHasFlush = false;
|
||||
private boolean mInitReady = false;
|
||||
private IMogoTTS mTTS;
|
||||
|
||||
public static AIAssist getInstance( Context context ) {
|
||||
if ( sInstance == null ) {
|
||||
@@ -48,61 +31,15 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
|
||||
}
|
||||
|
||||
public synchronized void release() {
|
||||
Logger.d( TAG, "release" );
|
||||
if ( mCmdMap != null && !mCmdMap.isEmpty() && mVoiceClient != null ) {
|
||||
for ( String cmd : mCmdMap.keySet() ) {
|
||||
mVoiceClient.unRegisterCustomWakeupCmd( cmd );
|
||||
}
|
||||
if ( mTTS != null ) {
|
||||
mTTS.release();
|
||||
}
|
||||
mQAndAMap.clear();
|
||||
mVoiceClient.release();
|
||||
mSpeakVoiceMap.clear();
|
||||
mCacheUnWakeupCommands.clear();
|
||||
sInstance = null;
|
||||
}
|
||||
|
||||
private final VoiceClient mVoiceClient;
|
||||
private MogoVoiceManager mogoVoiceManager;
|
||||
// 免唤醒指令
|
||||
private Map< String, List< IMogoVoiceCmdCallBack > > mCmdMap = new HashMap<>();
|
||||
// 问答指令
|
||||
private Map< String, IMogoVoiceCmdCallBack > mQAndAMap = new HashMap<>();
|
||||
// 单独的语音播放
|
||||
private Map< String, IMogoVoiceCmdCallBack > mSpeakVoiceMap = new HashMap<>();
|
||||
|
||||
private Map< String, String[] > mCacheUnWakeupCommands = new ConcurrentHashMap<>();
|
||||
|
||||
private AIAssist( Context context ) {
|
||||
// private constructor
|
||||
mVoiceClient = new VoiceClient( context.getApplicationContext() );
|
||||
mVoiceClient.setCallBack( this );
|
||||
initFlushStatus( context );
|
||||
initSpeech( context );
|
||||
Logger.w( TAG, "voice is ready = %s", mHasFlush );
|
||||
}
|
||||
|
||||
private void initFlushStatus( Context context ) {
|
||||
if ( !mHasFlush ) {
|
||||
mHasFlush = isVoiceServiceReady( context );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
private void initSpeech( Context context ) {
|
||||
mogoVoiceManager = MogoVoiceManagerImpl.getInstance();
|
||||
mogoVoiceManager.init( context, new OnConnStatusListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
mInitReady = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed() {
|
||||
|
||||
}
|
||||
} );
|
||||
mTTS = ( IMogoTTS ) ARouter.getInstance().build( MogoTTSConstants.API_PATH ).navigation( context.getApplicationContext() );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,83 +48,10 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
|
||||
* @return
|
||||
*/
|
||||
public boolean hasFlush() {
|
||||
return mHasFlush;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdSelected( String cmd ) {
|
||||
if ( !mCmdMap.containsKey( cmd ) ) {
|
||||
return;
|
||||
}
|
||||
Logger.d( TAG, "received command: %s", cmd );
|
||||
|
||||
Iterator< IMogoVoiceCmdCallBack > iterator = null;
|
||||
try {
|
||||
List< IMogoVoiceCmdCallBack > cmdCallBacks = mCmdMap.get( cmd );
|
||||
iterator = new ArrayList<>( cmdCallBacks ).iterator();
|
||||
} catch ( Exception e ) {
|
||||
|
||||
}
|
||||
while ( iterator != null && iterator.hasNext() ) {
|
||||
IMogoVoiceCmdCallBack callBack = iterator.next();
|
||||
if ( callBack != null ) {
|
||||
callBack.onCmdSelected( cmd );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdAction( String speakText ) {
|
||||
if ( !TextUtils.isEmpty( mLastQAndASpeakText ) ) {
|
||||
IMogoVoiceCmdCallBack cmdCallBack = mQAndAMap.remove( mLastQAndASpeakText );
|
||||
if ( cmdCallBack != null ) {
|
||||
cmdCallBack.onCmdAction( speakText );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdCancel( String speakText ) {
|
||||
if ( !TextUtils.isEmpty( mLastQAndASpeakText ) ) {
|
||||
IMogoVoiceCmdCallBack cmdCallBack = mQAndAMap.remove( mLastQAndASpeakText );
|
||||
if ( cmdCallBack != null ) {
|
||||
cmdCallBack.onCmdCancel( speakText );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakEnd( String speakText ) {
|
||||
if ( mQAndAMap.containsKey( speakText ) ) {
|
||||
mLastQAndASpeakText = speakText;
|
||||
IMogoVoiceCmdCallBack cmdCallBack = mQAndAMap.get( speakText );
|
||||
if ( cmdCallBack != null ) {
|
||||
cmdCallBack.onSpeakEnd( speakText );
|
||||
return;
|
||||
}
|
||||
}
|
||||
IMogoVoiceCmdCallBack callBack = mSpeakVoiceMap.remove( speakText );
|
||||
if ( callBack != null ) {
|
||||
callBack.onSpeakEnd( speakText );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakSelectTimeOut( String speakText ) {
|
||||
if ( mQAndAMap.containsKey( speakText ) ) {
|
||||
if ( TextUtils.equals( speakText, mLastQAndASpeakText ) ) {
|
||||
mLastQAndASpeakText = null;
|
||||
}
|
||||
IMogoVoiceCmdCallBack cmdCallBack = mQAndAMap.remove( speakText );
|
||||
if ( cmdCallBack != null ) {
|
||||
cmdCallBack.onSpeakSelectTimeOut( speakText );
|
||||
return;
|
||||
}
|
||||
}
|
||||
IMogoVoiceCmdCallBack callBack = mSpeakVoiceMap.remove( speakText );
|
||||
if ( callBack != null ) {
|
||||
callBack.onSpeakSelectTimeOut( speakText );
|
||||
if ( mTTS != null ) {
|
||||
return mTTS.hasFlush();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,13 +60,8 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
|
||||
* @param text
|
||||
*/
|
||||
public void speakTTSVoice( String text, IMogoVoiceCmdCallBack callBack ) {
|
||||
try {
|
||||
initFlushStatus( AbsMogoApplication.getApp() );
|
||||
if ( mHasFlush ) {
|
||||
mSpeakVoiceMap.put( text, callBack );
|
||||
mVoiceClient.speakDefault( text );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
if ( mTTS != null ) {
|
||||
mTTS.speakTTSVoice( text, callBack );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,12 +71,8 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
|
||||
* @param text
|
||||
*/
|
||||
public void speakTTSVoice( String text ) {
|
||||
try {
|
||||
initFlushStatus( AbsMogoApplication.getApp() );
|
||||
if ( mHasFlush ) {
|
||||
mVoiceClient.speakDefault( text );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
if ( mTTS != null ) {
|
||||
mTTS.speakTTSVoice( text );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,13 +83,25 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
|
||||
* @param type 播报策略
|
||||
*/
|
||||
public void speakTTSVoice( String text, VoicePreemptType type, IMogoVoiceCmdCallBack callBack ) {
|
||||
try {
|
||||
initFlushStatus( AbsMogoApplication.getApp() );
|
||||
if ( mHasFlush ) {
|
||||
mSpeakVoiceMap.put( text, callBack );
|
||||
mVoiceClient.speakTypeText( text, type.getPreemptType() );
|
||||
if ( mTTS != null ) {
|
||||
PreemptType preemptType = PreemptType.PREEMPT_TYPE_NONE;
|
||||
if ( type != null ) {
|
||||
switch ( type ) {
|
||||
case PREEMPT_TYPE_FLUSH:
|
||||
preemptType = PreemptType.PREEMPT_TYPE_FLUSH;
|
||||
break;
|
||||
case PREEMPT_TYPE_NEXT:
|
||||
preemptType = PreemptType.PREEMPT_TYPE_NEXT;
|
||||
break;
|
||||
case PREEMPT_TYPE_IMMEADIATELY:
|
||||
preemptType = PreemptType.PREEMPT_TYPE_IMMEDIATELY;
|
||||
break;
|
||||
case PREEMPT_TYPE_IMMEADIATELY_WITHOUT_CANCLE:
|
||||
preemptType = PreemptType.PREEMPT_TYPE_IMMEDIATELY_WITHOUT_CANCEL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
mTTS.speakTTSVoice( text, preemptType, callBack );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,10 +111,8 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
|
||||
* @param tts 播报内容
|
||||
*/
|
||||
public void speakQAndACmd( String tts, IMogoVoiceCmdCallBack callBack ) {
|
||||
initFlushStatus( AbsMogoApplication.getApp() );
|
||||
if ( mHasFlush ) {
|
||||
mQAndAMap.put( tts, callBack );
|
||||
mVoiceClient.speakTtsAndRegistCmd( tts );
|
||||
if ( mTTS != null ) {
|
||||
mTTS.speakQAndACmd( tts, callBack );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,10 +124,8 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
|
||||
* @param cancelCmds 取消命令唤醒词
|
||||
*/
|
||||
public void speakQAndACmd( String tts, String[] okCmds, String[] cancelCmds, IMogoVoiceCmdCallBack callBack ) {
|
||||
initFlushStatus( AbsMogoApplication.getApp() );
|
||||
if ( mHasFlush ) {
|
||||
mQAndAMap.put( tts, callBack );
|
||||
mVoiceClient.speakTtsAndRegistCmd( tts, okCmds, cancelCmds );
|
||||
if ( mTTS != null ) {
|
||||
mTTS.speakQAndACmd( tts, okCmds, cancelCmds, callBack );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,47 +137,9 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
|
||||
* @param callBack
|
||||
*/
|
||||
public void registerUnWakeupCommand( String cmd, String[] cmdWords, IMogoVoiceCmdCallBack callBack ) {
|
||||
if ( !mCmdMap.containsKey( cmd ) ) {
|
||||
mCmdMap.put( cmd, new ArrayList<>() );
|
||||
if ( mTTS != null ) {
|
||||
mTTS.registerUnWakeupCommand( cmd, cmdWords, callBack );
|
||||
}
|
||||
mCmdMap.get( cmd ).add( callBack );
|
||||
|
||||
initFlushStatus( AbsMogoApplication.getApp() );
|
||||
if ( mHasFlush ) {
|
||||
mVoiceClient.registerCustomWakeupCmd( cmd, cmdWords );
|
||||
mCacheUnWakeupCommands.remove( cmd );
|
||||
}
|
||||
Logger.i( TAG, "cache un wakeup command2. %s", cmd );
|
||||
mCacheUnWakeupCommands.put( cmd, cmdWords );
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册免唤醒命令
|
||||
*
|
||||
* @param cmd
|
||||
* @param cmdWords
|
||||
*/
|
||||
public void registerUnWakeupCommand( String cmd, String[] cmdWords ) {
|
||||
initFlushStatus( AbsMogoApplication.getApp() );
|
||||
if ( mHasFlush ) {
|
||||
mVoiceClient.registerCustomWakeupCmd( cmd, cmdWords );
|
||||
mCacheUnWakeupCommands.remove( cmd );
|
||||
}
|
||||
Logger.i( TAG, "cache un wakeup command. %s", cmd );
|
||||
mCacheUnWakeupCommands.put( cmd, cmdWords );
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册免唤醒命令回调
|
||||
*
|
||||
* @param cmd
|
||||
* @param callBack
|
||||
*/
|
||||
public synchronized void registerUnWakeupCommandCallback( String cmd, IMogoVoiceCmdCallBack callBack ) {
|
||||
if ( !mCmdMap.containsKey( cmd ) ) {
|
||||
mCmdMap.put( cmd, new ArrayList<>() );
|
||||
}
|
||||
mCmdMap.get( cmd ).add( callBack );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -323,9 +148,9 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
|
||||
* @param cmd
|
||||
*/
|
||||
public synchronized void unregisterUnWakeupCommand( String cmd ) {
|
||||
mCmdMap.remove( cmd );
|
||||
mVoiceClient.unRegisterCustomWakeupCmd( cmd );
|
||||
mCacheUnWakeupCommands.remove( cmd );
|
||||
if ( mTTS != null ) {
|
||||
mTTS.unregisterUnWakeupCommand( cmd );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -334,20 +159,12 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
|
||||
* @param cmd
|
||||
*/
|
||||
public synchronized void unregisterUnWakeupCommand( String cmd, IMogoVoiceCmdCallBack callBack ) {
|
||||
if ( mCmdMap.containsKey( cmd ) ) {
|
||||
List< IMogoVoiceCmdCallBack > callBacks = mCmdMap.get( cmd );
|
||||
if ( callBacks != null ) {
|
||||
callBacks.remove( callBack );
|
||||
}
|
||||
if ( callBacks.isEmpty() ) {
|
||||
mCmdMap.remove( cmd );
|
||||
mVoiceClient.unRegisterCustomWakeupCmd( cmd );
|
||||
mCacheUnWakeupCommands.remove( cmd );
|
||||
}
|
||||
if ( mTTS != null ) {
|
||||
mTTS.unregisterUnWakeupCommand( cmd, callBack );
|
||||
}
|
||||
}
|
||||
|
||||
public static void startAssistant( Context context ) {
|
||||
public void startAssistant( Context context ) {
|
||||
startAssistant( context, 1 );
|
||||
}
|
||||
|
||||
@@ -355,127 +172,33 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
|
||||
* @param context
|
||||
* @param status window_start_cancel 0 - 结束, 1 - 显示, 2 - 未激活调试进入
|
||||
*/
|
||||
public static void startAssistant( Context context, int status ) {
|
||||
final Intent intent = new Intent();
|
||||
intent.setFlags( Intent.FLAG_INCLUDE_STOPPED_PACKAGES );
|
||||
intent.setAction( "pvetec.intent.action.txz.switch" );
|
||||
intent.putExtra( "window_start_cancel", status );
|
||||
intent.putExtra( "extra_switch_type", "window_start_cancel" );
|
||||
Logger.d( TAG, "status = %d", status );
|
||||
context.sendBroadcast( intent );
|
||||
public void startAssistant( Context context, int status ) {
|
||||
if ( mTTS != null ) {
|
||||
mTTS.startAIAssist( context, status );
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void flush() {
|
||||
if ( mCacheUnWakeupCommands.isEmpty() ) {
|
||||
return;
|
||||
if ( mTTS != null ) {
|
||||
mTTS.flush();
|
||||
}
|
||||
mHasFlush = true;
|
||||
Logger.d( TAG, "flush cache voice command when voice service ready." );
|
||||
final Map< String, String[] > tmp = new HashMap<>( mCacheUnWakeupCommands );
|
||||
for ( String cmd : tmp.keySet() ) {
|
||||
registerUnWakeupCommand( cmd, tmp.get( cmd ) );
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isVoiceServiceReady( Context context ) {
|
||||
if ( isProcessRunning( context, getPackageUid( context, "com.zhidao.speech" ) )
|
||||
&& isProcessRunning( context, getPackageUid( context, "com.zhidao.speech.adapter" ) ) ) {
|
||||
return true;
|
||||
} else if (isProcessRunning(context, getPackageUid(context, "com.txznet.txz")) && isProcessRunning(context, getPackageUid(context, "com.txznet.adapter"))) {
|
||||
Logger.d(TAG, "txz is voiceServiceReady");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// private boolean isRunningTaskExist( Context context, String processName ) {
|
||||
//// ActivityManager am = ( ActivityManager ) context.getSystemService( Context.ACTIVITY_SERVICE );
|
||||
//// List< ActivityManager.RunningAppProcessInfo > processList = am.getRunningAppProcesses();
|
||||
//// for ( ActivityManager.RunningAppProcessInfo info : processList ) {
|
||||
//// if ( info.processName.equals( processName ) ) {
|
||||
//// return true;
|
||||
//// }
|
||||
//// }
|
||||
//// return false;
|
||||
//// }
|
||||
|
||||
/**
|
||||
* 方法描述:判断某一应用是否正在运行
|
||||
* Created by cafeting on 2017/2/4.
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param packageName 应用的包名
|
||||
* @return true 表示正在运行,false 表示没有运行
|
||||
*/
|
||||
public static boolean isAppRunning( Context context, String packageName ) {
|
||||
ActivityManager am = ( ActivityManager ) context.getSystemService( Context.ACTIVITY_SERVICE );
|
||||
List< ActivityManager.RunningTaskInfo > list = am.getRunningTasks( 100 );
|
||||
if ( list.size() <= 0 ) {
|
||||
return false;
|
||||
}
|
||||
for ( ActivityManager.RunningTaskInfo info : list ) {
|
||||
if ( info.baseActivity.getPackageName().equals( packageName ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//获取已安装应用的 uid,-1 表示未安装此应用或程序异常
|
||||
public static int getPackageUid( Context context, String packageName ) {
|
||||
try {
|
||||
ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo( packageName, 0 );
|
||||
if ( applicationInfo != null ) {
|
||||
return applicationInfo.uid;
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断某一 uid 的程序是否有正在运行的进程,即是否存活
|
||||
* Created by cafeting on 2017/2/4.
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param uid 已安装应用的 uid
|
||||
* @return true 表示正在运行,false 表示没有运行
|
||||
*/
|
||||
public static boolean isProcessRunning( Context context, int uid ) {
|
||||
ActivityManager am = ( ActivityManager ) context.getSystemService( Context.ACTIVITY_SERVICE );
|
||||
List< ActivityManager.RunningServiceInfo > runningServiceInfos = am.getRunningServices( 200 );
|
||||
if ( runningServiceInfos.size() > 0 ) {
|
||||
for ( ActivityManager.RunningServiceInfo appProcess : runningServiceInfos ) {
|
||||
if ( uid == appProcess.uid ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void speakTTSAndDuck( String text ) {
|
||||
speakTTSAndDuck( text, null );
|
||||
if ( mTTS != null ) {
|
||||
mTTS.speakTTSAndDuck( text );
|
||||
}
|
||||
}
|
||||
|
||||
public void speakTTSAndDuck( String text, IMogoVoiceCmdCallBack callBack ) {
|
||||
try {
|
||||
if ( mInitReady ) {
|
||||
mSpeakVoiceMap.put( text, callBack );
|
||||
mogoVoiceManager.toSpeak( text, -3, this );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
if ( mTTS != null ) {
|
||||
mTTS.speakTTSAndDuck( text, callBack );
|
||||
}
|
||||
}
|
||||
|
||||
public void shutUp( String ttsId, String text ) {
|
||||
try {
|
||||
mSpeakVoiceMap.remove( text );
|
||||
mogoVoiceManager.shutUp( ttsId );
|
||||
} catch ( Exception e ) {
|
||||
|
||||
if ( mTTS != null ) {
|
||||
mTTS.shutUp( ttsId, text );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,40 +206,15 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
|
||||
* 打断上一条正在播报的语音内容,仅在Speech上生效,TXZ为空实现
|
||||
* 语音SDK生效版本从1.0.8.4版本起
|
||||
*/
|
||||
public void breakOffSpeak(){
|
||||
mVoiceClient.breakOffSpeak();
|
||||
public void breakOffSpeak() {
|
||||
if ( mTTS != null ) {
|
||||
mTTS.breakOffSpeak();
|
||||
}
|
||||
}
|
||||
|
||||
public void clearTTSCallback( String text ) {
|
||||
try {
|
||||
mSpeakVoiceMap.remove( text );
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
if ( mTTS != null ) {
|
||||
mTTS.clearTTSCallback( text );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTtsStart( String ttsId, String text ) {
|
||||
IMogoVoiceCmdCallBack callBack = mSpeakVoiceMap.get( text );
|
||||
if ( callBack != null ) {
|
||||
callBack.onTTSStart( ttsId, text );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTtsFinish( String ttsId, String text ) {
|
||||
IMogoVoiceCmdCallBack callBack = mSpeakVoiceMap.remove( text );
|
||||
if ( callBack != null ) {
|
||||
callBack.onTTSEnd( ttsId, text );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTtsError( String ttsId, String text ) {
|
||||
IMogoVoiceCmdCallBack callBack = mSpeakVoiceMap.remove( text );
|
||||
if ( callBack != null ) {
|
||||
callBack.onTTSError( ttsId, text );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,66 +1,7 @@
|
||||
package com.mogo.commons.voice;
|
||||
|
||||
public interface IMogoVoiceCmdCallBack {
|
||||
import com.mogo.tts.base.IMogoTTSCallback;
|
||||
|
||||
/**
|
||||
* 新SDK接口
|
||||
*
|
||||
* @param ttsId
|
||||
* @param tts
|
||||
*/
|
||||
default void onTTSStart( String ttsId, String tts ) {
|
||||
}
|
||||
public interface IMogoVoiceCmdCallBack extends IMogoTTSCallback {
|
||||
|
||||
/**
|
||||
* 新SDK接口
|
||||
*
|
||||
* @param ttsId
|
||||
* @param tts
|
||||
*/
|
||||
default void onTTSEnd( String ttsId, String tts ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 新SDK接口
|
||||
*
|
||||
* @param ttsId
|
||||
* @param tts
|
||||
*/
|
||||
default void onTTSError( String ttsId, String tts ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 免唤醒命令响应回调
|
||||
*
|
||||
* @param cmd
|
||||
*/
|
||||
default void onCmdSelected( String cmd ){}
|
||||
|
||||
/**
|
||||
* 语音播报临时免唤醒“确定”命令
|
||||
*
|
||||
* @param speakText 播报内容
|
||||
*/
|
||||
default void onCmdAction( String speakText ){}
|
||||
|
||||
/**
|
||||
* 语音播报临时免唤醒“取消”命令
|
||||
*
|
||||
* @param speakText 播报内容
|
||||
*/
|
||||
default void onCmdCancel( String speakText ){}
|
||||
|
||||
/**
|
||||
* 语音播报完毕
|
||||
*
|
||||
* @param speakText 播报内容
|
||||
*/
|
||||
default void onSpeakEnd( String speakText ){}
|
||||
|
||||
/**
|
||||
* 语音播报完临时命令选择超时
|
||||
*
|
||||
* @param speakText 播报内容
|
||||
*/
|
||||
default void onSpeakSelectTimeOut( String speakText ){}
|
||||
}
|
||||
@@ -1,23 +1,9 @@
|
||||
package com.mogo.commons.voice;
|
||||
|
||||
import com.zhidao.auto.platform.voice.VoiceClient;
|
||||
|
||||
public enum VoicePreemptType {
|
||||
|
||||
|
||||
PREEMPT_TYPE_NONE( VoiceClient.PreemptType.PREEMPT_TYPE_NONE ), //不打断
|
||||
PREEMPT_TYPE_IMMEADIATELY( VoiceClient.PreemptType.PREEMPT_TYPE_IMMEADIATELY ), //立即打断,取消当前的tts插队播放
|
||||
PREEMPT_TYPE_NEXT( VoiceClient.PreemptType.PREEMPT_TYPE_NEXT ), //下一个插入,不取消当前的tts,插队下一个播放
|
||||
PREEMPT_TYPE_FLUSH( VoiceClient.PreemptType.PREEMPT_TYPE_FLUSH ), //清空队列
|
||||
PREEMPT_TYPE_IMMEADIATELY_WITHOUT_CANCLE( VoiceClient.PreemptType.PREEMPT_TYPE_IMMEADIATELY_WITHOUT_CANCLE ); //立即打断,不取消当前tts
|
||||
|
||||
public VoiceClient.PreemptType preemptType;
|
||||
|
||||
VoicePreemptType( VoiceClient.PreemptType preemptType ) {
|
||||
this.preemptType = preemptType;
|
||||
}
|
||||
|
||||
public VoiceClient.PreemptType getPreemptType() {
|
||||
return preemptType;
|
||||
}
|
||||
PREEMPT_TYPE_NONE, //不打断
|
||||
PREEMPT_TYPE_IMMEADIATELY, //立即打断,取消当前的tts插队播放
|
||||
PREEMPT_TYPE_NEXT, //下一个插入,不取消当前的tts,插队下一个播放
|
||||
PREEMPT_TYPE_FLUSH, //清空队列
|
||||
PREEMPT_TYPE_IMMEADIATELY_WITHOUT_CANCLE; //立即打断,不取消当前tts
|
||||
}
|
||||
@@ -87,4 +87,38 @@ public class AppUtils {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//获取已安装应用的 uid,-1 表示未安装此应用或程序异常
|
||||
public static int getPackageUid( Context context, String packageName ) {
|
||||
try {
|
||||
ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo( packageName, 0 );
|
||||
if ( applicationInfo != null ) {
|
||||
return applicationInfo.uid;
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断某一 uid 的程序是否有正在运行的进程,即是否存活
|
||||
* Created by cafeting on 2017/2/4.
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param uid 已安装应用的 uid
|
||||
* @return true 表示正在运行,false 表示没有运行
|
||||
*/
|
||||
public static boolean isProcessRunning( Context context, int uid ) {
|
||||
ActivityManager am = ( ActivityManager ) context.getSystemService( Context.ACTIVITY_SERVICE );
|
||||
List< ActivityManager.RunningServiceInfo > runningServiceInfos = am.getRunningServices( 200 );
|
||||
if ( runningServiceInfos.size() > 0 ) {
|
||||
for ( ActivityManager.RunningServiceInfo appProcess : runningServiceInfos ) {
|
||||
if ( uid == appProcess.uid ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +98,10 @@ MOGO_MODULE_MONITOR_VERSION=2.0.0
|
||||
CRASHREPORT_VERSION=2.0.0
|
||||
CRASHREPORT_BUGLY_VERSION=2.0.0
|
||||
CRASHREPORT_NOOP_VERSION=2.0.0
|
||||
## tts
|
||||
TTS_BASE_VERSION=1.0.0
|
||||
TTS_DI_VERSION=1.0.0
|
||||
TTS_ZHI_VERSION=1.0.0
|
||||
|
||||
######## 外部依赖引用
|
||||
# 车聊聊
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.text.TextUtils;
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.commons.voice.AIAssist;
|
||||
import com.mogo.commons.voice.IMogoVoiceCmdCallBack;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
@@ -16,7 +15,7 @@ import java.util.LinkedList;
|
||||
* <p>
|
||||
* 策略:队列缓存预播报的 tts,然后上一句播完后
|
||||
*/
|
||||
public class TTSSpeaker implements IMogoVoiceCmdCallBack {
|
||||
public class TTSSpeaker {
|
||||
|
||||
private static volatile TTSSpeaker sInstance;
|
||||
|
||||
@@ -48,7 +47,6 @@ public class TTSSpeaker implements IMogoVoiceCmdCallBack {
|
||||
return;
|
||||
}
|
||||
mWaiting.add( tts );
|
||||
peekAndSpeak();
|
||||
}
|
||||
|
||||
public synchronized void shutUp() {
|
||||
@@ -60,61 +58,5 @@ public class TTSSpeaker implements IMogoVoiceCmdCallBack {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdSelected( String cmd ) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdAction( String speakText ) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdCancel( String speakText ) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakEnd( String speakText ) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakSelectTimeOut( String speakText ) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTTSStart( String ttsId, String tts ) {
|
||||
if ( TextUtils.equals( mLastTts, tts ) ) {
|
||||
mLastTtsId = ttsId;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTTSEnd( String ttsId, String tts ) {
|
||||
mLastTtsId = null;
|
||||
peekAndSpeak();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTTSError( String ttsId, String tts ) {
|
||||
mLastTtsId = null;
|
||||
peekAndSpeak();
|
||||
}
|
||||
|
||||
private synchronized void peekAndSpeak() {
|
||||
if ( mWaiting.isEmpty() ) {
|
||||
mLastTts = null;
|
||||
mLastTtsId = null;
|
||||
return;
|
||||
}
|
||||
if ( mLastTtsId != null ) {
|
||||
// 上一句还没有播完
|
||||
return;
|
||||
}
|
||||
mLastTts = mWaiting.pop();
|
||||
AIAssist.getInstance( AbsMogoApplication.getApp() ).speakTTSAndDuck( mLastTts, this );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@ class OnAiAssistClickListener implements View.OnClickListener {
|
||||
@Override
|
||||
public void onClick( View v ) {
|
||||
if ( Devices.isBind() || !DebugConfig.isActiveAIAssistFlag() ) {
|
||||
AIAssist.startAssistant( v.getContext() );
|
||||
AIAssist.getInstance( v.getContext() ).startAssistant( v.getContext() );
|
||||
} else {
|
||||
if ( mDebugModeOpen ) {
|
||||
AIAssist.startAssistant( v.getContext(), 1 );
|
||||
AIAssist.getInstance( v.getContext() ).startAssistant( v.getContext(), 1 );
|
||||
return;
|
||||
}
|
||||
if ( mClickCounter == 0 ) {
|
||||
@@ -38,7 +38,7 @@ class OnAiAssistClickListener implements View.OnClickListener {
|
||||
mClickCounter++;
|
||||
} else {
|
||||
if ( mClickCounter == TOTAL_CLICK_AMOUNT ) {
|
||||
AIAssist.startAssistant( v.getContext(), 2 );
|
||||
AIAssist.getInstance( v.getContext() ).startAssistant( v.getContext(), 2 );
|
||||
TipToast.shortTip( "开启语音调试" );
|
||||
mClickCounter = 0;
|
||||
mLastClickTime = 0L;
|
||||
|
||||
@@ -8,6 +8,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.alibaba.android.arouter.facade.annotation.Route;
|
||||
import com.mogo.commons.debug.DebugConfig;
|
||||
import com.mogo.module.common.MogoApisHandler;
|
||||
import com.mogo.module.common.utils.CarSeries;
|
||||
import com.mogo.service.IMogoServiceApis;
|
||||
@@ -50,8 +51,19 @@ public class BackToLauncherModuleProvider implements IMogoModuleProvider {
|
||||
|
||||
@Override
|
||||
public void init( Context context ) {
|
||||
if ( CarSeries.getSeries() == CarSeries.CAR_SERIES_F80X ) {
|
||||
BackToMainHomeManager.addMainHomeView();
|
||||
final String product = DebugConfig.getProductFlavor();
|
||||
if ( product != null ) {
|
||||
switch ( product ) {
|
||||
case "f80x":
|
||||
case "f8xx":
|
||||
BackToMainHomeManager.addMainHomeView();
|
||||
break;
|
||||
case "changanauto":
|
||||
if ( DebugConfig.isDebug() ) {
|
||||
BackToMainHomeManager.addMainHomeView();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
mServiceApis = MogoApisHandler.getInstance().getApis();
|
||||
BackToMainHomeManager.init( mServiceApis );
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
package com.mogo.module.tanlu.voice
|
||||
|
||||
import com.zhidao.auto.platform.voice.VoiceClient
|
||||
|
||||
/**
|
||||
* @description 声音控制类
|
||||
*
|
||||
* @author lixiaopeng
|
||||
* @since 2019-11-01
|
||||
*/
|
||||
object VoiceController {
|
||||
private lateinit var voiceClient: VoiceClient
|
||||
|
||||
// fun initVoice() {
|
||||
// voiceClient = VoiceClient.getInstance(BaseApplication.getAppContext())
|
||||
// }
|
||||
|
||||
/**
|
||||
* 设置语音命令回调接口
|
||||
* @param callBack
|
||||
*/
|
||||
fun setCallBack(callBack: VoiceClient.VoiceCmdCallBack) {
|
||||
voiceClient.setCallBack(callBack)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param speakText 语音播报内容
|
||||
*/
|
||||
fun speakVoice(speakText: String) {
|
||||
voiceClient.speakDefault(speakText)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册免唤醒命令
|
||||
* @param customType 命令
|
||||
* @param customWakeupCmd 命令对应的唤醒词集合
|
||||
*/
|
||||
fun registerCustomWakeupCmd(customType: String, customWakeupCmd: Array<String>) {
|
||||
voiceClient.registerCustomWakeupCmd(customType, customWakeupCmd)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消免唤醒命令
|
||||
* @param customType 命令
|
||||
*/
|
||||
fun unRegisterCustomWakeupCmd(customType: String) {
|
||||
voiceClient.unRegisterCustomWakeupCmd(customType)
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放资源(界面销毁的时候调用)
|
||||
*/
|
||||
fun release() {
|
||||
voiceClient.release()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
include ':tts:tts-base'
|
||||
include ':tts:tts-di'
|
||||
include ':tts:tts-zhi'
|
||||
include ':test:crashreport'
|
||||
include ':test:crashreport-bugly'
|
||||
include ':test:crashreport-noop'
|
||||
@@ -58,3 +61,4 @@ include ':modules:mogo-module-tanlu'
|
||||
include ':libraries:tanlulib'
|
||||
include ':skin'
|
||||
include ':test'
|
||||
include ':tts'
|
||||
|
||||
1
tts/tts-base/.gitignore
vendored
Normal file
1
tts/tts-base/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
44
tts/tts-base/build.gradle
Normal file
44
tts/tts-base/build.gradle
Normal file
@@ -0,0 +1,44 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'com.alibaba.arouter'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.android.compileSdkVersion
|
||||
// buildToolsVersion rootProject.ext.android.buildToolsVersion
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.android.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.android.targetSdkVersion
|
||||
versionCode Integer.valueOf(VERSION_CODE)
|
||||
versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION")
|
||||
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments = [AROUTER_MODULE_NAME: project.getName()]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation rootProject.ext.dependencies.androidxappcompat
|
||||
implementation rootProject.ext.dependencies.arouter
|
||||
annotationProcessor rootProject.ext.dependencies.aroutercompiler
|
||||
}
|
||||
|
||||
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()
|
||||
0
tts/tts-base/consumer-rules.pro
Normal file
0
tts/tts-base/consumer-rules.pro
Normal file
3
tts/tts-base/gradle.properties
Normal file
3
tts/tts-base/gradle.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
GROUP=com.mogo.tts
|
||||
POM_ARTIFACT_ID=tts-base
|
||||
VERSION_CODE=1
|
||||
21
tts/tts-base/proguard-rules.pro
vendored
Normal file
21
tts/tts-base/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# 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 *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
5
tts/tts-base/src/main/AndroidManifest.xml
Normal file
5
tts/tts-base/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.tts.base">
|
||||
|
||||
/
|
||||
</manifest>
|
||||
153
tts/tts-base/src/main/java/com/mogo/tts/base/IMogoTTS.java
Normal file
153
tts/tts-base/src/main/java/com/mogo/tts/base/IMogoTTS.java
Normal file
@@ -0,0 +1,153 @@
|
||||
package com.mogo.tts.base;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.alibaba.android.arouter.facade.template.IProvider;
|
||||
|
||||
public
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2020/10/12
|
||||
*
|
||||
* 语音抽象
|
||||
*/
|
||||
interface IMogoTTS extends IProvider {
|
||||
|
||||
/**
|
||||
* 释放资源
|
||||
*/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* 缓存的语音指令注册状态
|
||||
*
|
||||
* @return true - 已注册、false - 未注册
|
||||
*/
|
||||
default boolean hasFlush() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将缓存的免唤醒指令全部注册一遍
|
||||
*/
|
||||
void flush();
|
||||
|
||||
/**
|
||||
* 播报 tts 语音
|
||||
*
|
||||
* @param tts 语音内容
|
||||
*/
|
||||
void speakTTSVoice( String tts );
|
||||
|
||||
/**
|
||||
* 播放 tts 语音
|
||||
*
|
||||
* @param tts 语音内容
|
||||
* @param callback 回调
|
||||
* {@link IMogoTTSCallback#onSpeakEnd(String)}
|
||||
*/
|
||||
void speakTTSVoice( String tts, IMogoTTSCallback callback );
|
||||
|
||||
/**
|
||||
* 播放 tts,并设置播报类型
|
||||
*
|
||||
* @param tts 语音内容
|
||||
* @param type 播报类型 {@link PreemptType}
|
||||
* @param callback 回调
|
||||
* {@link IMogoTTSCallback#onSpeakEnd(String)}
|
||||
*/
|
||||
void speakTTSVoice( String tts, PreemptType type, IMogoTTSCallback callback );
|
||||
|
||||
/**
|
||||
* 注册问答指令,默认恢复:确认、取消
|
||||
*
|
||||
* @param tts 播报内容
|
||||
* @param callback 回调
|
||||
* {@link IMogoTTSCallback#onCmdAction(String)}
|
||||
* {@link IMogoTTSCallback#onCmdCancel(String)} (String)}
|
||||
* {@link IMogoTTSCallback#onSpeakSelectTimeOut(String)} (String)}
|
||||
*/
|
||||
void speakQAndACmd( String tts, IMogoTTSCallback callback );
|
||||
|
||||
|
||||
/**
|
||||
* 注册问答指令,默认恢复:确认、取消
|
||||
*
|
||||
* @param tts 播报内容
|
||||
* @param okWords 确认指令唤醒词
|
||||
* @param cancelWords 取消指令唤醒词
|
||||
* @param callback 回调
|
||||
* {@link IMogoTTSCallback#onCmdAction(String)}
|
||||
* {@link IMogoTTSCallback#onCmdCancel(String)} (String)}
|
||||
* {@link IMogoTTSCallback#onSpeakSelectTimeOut(String)} (String)}
|
||||
*/
|
||||
void speakQAndACmd( String tts, String[] okWords, String[] cancelWords, IMogoTTSCallback callback );
|
||||
|
||||
|
||||
/**
|
||||
* 注册免唤醒指令
|
||||
*
|
||||
* @param cmd 免唤醒指令
|
||||
* @param cmdWords 免唤醒词组
|
||||
* @param callback 回调
|
||||
* {@link IMogoTTSCallback#onCmdSelected(String)}
|
||||
*/
|
||||
void registerUnWakeupCommand( String cmd, String[] cmdWords, IMogoTTSCallback callback );
|
||||
|
||||
/**
|
||||
* 注销免唤醒指令
|
||||
*
|
||||
* @param cmd 指令
|
||||
*/
|
||||
void unregisterUnWakeupCommand( String cmd );
|
||||
|
||||
/**
|
||||
* 注销免唤醒指令
|
||||
*
|
||||
* @param cmd 指令
|
||||
* @param callback 具体注销的回调对象(部分指令复用的情况)
|
||||
*/
|
||||
void unregisterUnWakeupCommand( String cmd, IMogoTTSCallback callback );
|
||||
|
||||
/**
|
||||
* 启动语音
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
void startAIAssist( Context context );
|
||||
|
||||
/**
|
||||
* 启动语音
|
||||
*
|
||||
* @param context
|
||||
* @param status window_start_cancel
|
||||
* 0 - 结束
|
||||
* 1 - 显示
|
||||
* 2 - 未激活调试进入
|
||||
*/
|
||||
|
||||
void startAIAssist( Context context, int status );
|
||||
|
||||
/**
|
||||
* 中断正在播报的语音内容
|
||||
*/
|
||||
void breakOffSpeak();
|
||||
|
||||
// Deprecated api, but should keep...
|
||||
|
||||
@Deprecated
|
||||
default void speakTTSAndDuck( String tts ) {
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
default void speakTTSAndDuck( String tts, IMogoTTSCallback callback ) {
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
default void shutUp( String ttsId, String text ) {
|
||||
|
||||
}
|
||||
|
||||
default void clearTTSCallback( String tts ) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.mogo.tts.base;
|
||||
|
||||
public
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2020/10/12
|
||||
*
|
||||
* 描述
|
||||
*/
|
||||
interface IMogoTTSCallback {
|
||||
|
||||
/**
|
||||
* 新SDK接口
|
||||
*
|
||||
* @param ttsId
|
||||
* @param tts
|
||||
*/
|
||||
@Deprecated
|
||||
default void onTTSStart( String ttsId, String tts ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 新SDK接口
|
||||
*
|
||||
* @param ttsId
|
||||
* @param tts
|
||||
*/
|
||||
@Deprecated
|
||||
default void onTTSEnd( String ttsId, String tts ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 新SDK接口
|
||||
*
|
||||
* @param ttsId
|
||||
* @param tts
|
||||
*/
|
||||
@Deprecated
|
||||
default void onTTSError( String ttsId, String tts ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 免唤醒命令响应回调
|
||||
*
|
||||
* @param cmd
|
||||
*/
|
||||
default void onCmdSelected( String cmd ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 语音播报临时免唤醒“确定”命令
|
||||
*
|
||||
* @param speakText 播报内容
|
||||
*/
|
||||
default void onCmdAction( String speakText ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 语音播报临时免唤醒“取消”命令
|
||||
*
|
||||
* @param speakText 播报内容
|
||||
*/
|
||||
default void onCmdCancel( String speakText ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 语音播报完毕
|
||||
*
|
||||
* @param speakText 播报内容
|
||||
*/
|
||||
default void onSpeakEnd( String speakText ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 语音播报完临时命令选择超时
|
||||
*
|
||||
* @param speakText 播报内容
|
||||
*/
|
||||
default void onSpeakSelectTimeOut( String speakText ) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.mogo.tts.base;
|
||||
|
||||
public
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2020/10/12
|
||||
* <p>
|
||||
* 描述
|
||||
*/
|
||||
interface MogoTTSConstants {
|
||||
|
||||
String API_PATH = "/tts/api";
|
||||
|
||||
String API_NAME = "TTS";
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.mogo.tts.base;
|
||||
|
||||
public
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2020/10/12
|
||||
*
|
||||
* 语音打算类型
|
||||
*/
|
||||
enum PreemptType {
|
||||
|
||||
/**
|
||||
* 不打断
|
||||
*/
|
||||
PREEMPT_TYPE_NONE,
|
||||
/**
|
||||
* 立即打断,取消当前的tts插队播放
|
||||
*/
|
||||
PREEMPT_TYPE_IMMEDIATELY,
|
||||
/**
|
||||
* 下一个插入,不取消当前的tts,插队下一个播放
|
||||
*/
|
||||
PREEMPT_TYPE_NEXT,
|
||||
/**
|
||||
* 清空队列
|
||||
*/
|
||||
PREEMPT_TYPE_FLUSH,
|
||||
/**
|
||||
* 立即打断,不取消当前tts
|
||||
*/
|
||||
PREEMPT_TYPE_IMMEDIATELY_WITHOUT_CANCEL
|
||||
}
|
||||
1
tts/tts-di/.gitignore
vendored
Normal file
1
tts/tts-di/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
50
tts/tts-di/build.gradle
Normal file
50
tts/tts-di/build.gradle
Normal file
@@ -0,0 +1,50 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'com.alibaba.arouter'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.android.compileSdkVersion
|
||||
// buildToolsVersion rootProject.ext.android.buildToolsVersion
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.android.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.android.targetSdkVersion
|
||||
versionCode Integer.valueOf(VERSION_CODE)
|
||||
versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION")
|
||||
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments = [AROUTER_MODULE_NAME: project.getName()]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation rootProject.ext.dependencies.androidxappcompat
|
||||
implementation rootProject.ext.dependencies.arouter
|
||||
annotationProcessor rootProject.ext.dependencies.aroutercompiler
|
||||
|
||||
if (Boolean.valueOf(RELEASE)) {
|
||||
implementation rootProject.ext.dependencies.ttsbase
|
||||
} else {
|
||||
implementation project(":tts:tts-base")
|
||||
}
|
||||
}
|
||||
|
||||
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()
|
||||
0
tts/tts-di/consumer-rules.pro
Normal file
0
tts/tts-di/consumer-rules.pro
Normal file
3
tts/tts-di/gradle.properties
Normal file
3
tts/tts-di/gradle.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
GROUP=com.mogo.tts
|
||||
POM_ARTIFACT_ID=tts-di
|
||||
VERSION_CODE=1
|
||||
21
tts/tts-di/proguard-rules.pro
vendored
Normal file
21
tts/tts-di/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# 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 *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
5
tts/tts-di/src/main/AndroidManifest.xml
Normal file
5
tts/tts-di/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.tts.di">
|
||||
|
||||
/
|
||||
</manifest>
|
||||
98
tts/tts-di/src/main/java/com/mogo/tts/di/DiTTS.java
Normal file
98
tts/tts-di/src/main/java/com/mogo/tts/di/DiTTS.java
Normal file
@@ -0,0 +1,98 @@
|
||||
package com.mogo.tts.di;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.alibaba.android.arouter.facade.annotation.Route;
|
||||
import com.mogo.tts.base.IMogoTTS;
|
||||
import com.mogo.tts.base.IMogoTTSCallback;
|
||||
import com.mogo.tts.base.MogoTTSConstants;
|
||||
import com.mogo.tts.base.PreemptType;
|
||||
|
||||
public
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2020/10/12
|
||||
*
|
||||
* 比亚迪语音播报
|
||||
*/
|
||||
@Route( path = MogoTTSConstants.API_PATH )
|
||||
class DiTTS implements IMogoTTS {
|
||||
|
||||
private static final String TAG = "DiTTS";
|
||||
|
||||
private Context mContext;
|
||||
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
mContext = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
Log.d( TAG, "noop - flush" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void speakTTSVoice( String tts ) {
|
||||
TTSManager.getInstance().speakTTS( mContext, tts );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void speakTTSVoice( String tts, IMogoTTSCallback callback ) {
|
||||
speakTTSVoice( tts );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void speakTTSVoice( String tts, PreemptType type, IMogoTTSCallback callback ) {
|
||||
speakTTSVoice( tts );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void speakQAndACmd( String tts, IMogoTTSCallback callback ) {
|
||||
Log.d( TAG, "noop - speakQAndACmd" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void speakQAndACmd( String tts, String[] okWords, String[] cancelWords, IMogoTTSCallback callback ) {
|
||||
Log.d( TAG, "noop - speakQAndACmd2" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerUnWakeupCommand( String cmd, String[] cmdWords, IMogoTTSCallback callback ) {
|
||||
Log.d( TAG, "noop - registerUnWakeupCommand" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterUnWakeupCommand( String cmd ) {
|
||||
Log.d( TAG, "noop - unregisterUnWakeupCommand" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterUnWakeupCommand( String cmd, IMogoTTSCallback callback ) {
|
||||
Log.d( TAG, "noop - unregisterUnWakeupCommand2" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startAIAssist( Context context ) {
|
||||
Log.d( TAG, "noop - startAIAssist" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startAIAssist( Context context, int status ) {
|
||||
Log.d( TAG, "noop - startAIAssist2" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void breakOffSpeak() {
|
||||
TTSManager.getInstance().breakOffSpeak( mContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init( Context context ) {
|
||||
if ( context != null ) {
|
||||
mContext = context.getApplicationContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
99
tts/tts-di/src/main/java/com/mogo/tts/di/TTSManager.java
Normal file
99
tts/tts-di/src/main/java/com/mogo/tts/di/TTSManager.java
Normal file
@@ -0,0 +1,99 @@
|
||||
package com.mogo.tts.di;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
public
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2020/10/12
|
||||
*
|
||||
* 语音播报
|
||||
*/
|
||||
class TTSManager {
|
||||
|
||||
/**
|
||||
* 语音播报广播 action
|
||||
*/
|
||||
public static final String ACTION_SPEAK_TTS = "com.byd.NotifyService.thirdTts";
|
||||
/**
|
||||
* 播报语音内容
|
||||
*/
|
||||
public static final String EXTRA_TTS_CONTENT = "thirdVoiceText";
|
||||
|
||||
/**
|
||||
* 发音人:“0”表示使用默认发音人,或设置为“1”表示吉祥物发音人
|
||||
*/
|
||||
public static final String EXTRA_TTS_SPEAKER = "thirdSpeaker";
|
||||
|
||||
/**
|
||||
* 值类型为String型,可以设置为“THIRD_PLAY”表示请求播报,或设置为“THIRD_STOP”表示终止播报
|
||||
*/
|
||||
public static final String EXTRA_TTS_ACTION = "thirdType";
|
||||
public final String VAL_THIRD_PLAY = "THIRD_PLAY";
|
||||
public final String VAL_THIRD_STOP = "THIRD_STOP";
|
||||
|
||||
/**
|
||||
* 值类型为Boolean 型,可以设置为 true,表示打开语音界面显示文字,并播报内容,或设置 为 false,表示后台播报内容。
|
||||
*/
|
||||
public static final String EXTRA_TTS_SHOW_UI = "booleanShowText";
|
||||
|
||||
private static volatile TTSManager sInstance;
|
||||
|
||||
private TTSManager() {
|
||||
}
|
||||
|
||||
public static TTSManager getInstance() {
|
||||
if ( sInstance == null ) {
|
||||
synchronized ( TTSManager.class ) {
|
||||
if ( sInstance == null ) {
|
||||
sInstance = new TTSManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public synchronized void release() {
|
||||
sInstance = null;
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
// 阻止反序列化,必须实现 Serializable 接口
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 播报 tts
|
||||
*
|
||||
* @param context
|
||||
* @param tts
|
||||
*/
|
||||
public void speakTTS( Context context, String tts ) {
|
||||
if ( context == null ) {
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent();
|
||||
intent.setAction( ACTION_SPEAK_TTS );
|
||||
intent.putExtra( EXTRA_TTS_CONTENT, tts );
|
||||
intent.putExtra( EXTRA_TTS_SPEAKER, 0 );
|
||||
intent.putExtra( EXTRA_TTS_ACTION, VAL_THIRD_PLAY );
|
||||
intent.putExtra( EXTRA_TTS_SHOW_UI, false );
|
||||
context.sendBroadcast( intent );
|
||||
}
|
||||
|
||||
/**
|
||||
* 打断播报
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
public void breakOffSpeak( Context context ) {
|
||||
if ( context == null ) {
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent();
|
||||
intent.setAction( ACTION_SPEAK_TTS );
|
||||
intent.putExtra( EXTRA_TTS_ACTION, VAL_THIRD_STOP );
|
||||
context.sendBroadcast( intent );
|
||||
}
|
||||
}
|
||||
1
tts/tts-zhi/.gitignore
vendored
Normal file
1
tts/tts-zhi/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
54
tts/tts-zhi/build.gradle
Normal file
54
tts/tts-zhi/build.gradle
Normal file
@@ -0,0 +1,54 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'com.alibaba.arouter'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.android.compileSdkVersion
|
||||
// buildToolsVersion rootProject.ext.android.buildToolsVersion
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.android.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.android.targetSdkVersion
|
||||
versionCode Integer.valueOf(VERSION_CODE)
|
||||
versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION")
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments = [AROUTER_MODULE_NAME: project.getName()]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation rootProject.ext.dependencies.androidxappcompat
|
||||
implementation rootProject.ext.dependencies.arouter
|
||||
annotationProcessor rootProject.ext.dependencies.aroutercompiler
|
||||
|
||||
api rootProject.ext.dependencies.aiassist
|
||||
api rootProject.ext.dependencies.aiassistReplace
|
||||
|
||||
if (Boolean.valueOf(RELEASE)) {
|
||||
implementation rootProject.ext.dependencies.ttsbase
|
||||
implementation rootProject.ext.dependencies.mogoutils
|
||||
} else {
|
||||
implementation project(":tts:tts-base")
|
||||
implementation project(":foudations:mogo-utils")
|
||||
}
|
||||
}
|
||||
|
||||
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()
|
||||
0
tts/tts-zhi/consumer-rules.pro
Normal file
0
tts/tts-zhi/consumer-rules.pro
Normal file
3
tts/tts-zhi/gradle.properties
Normal file
3
tts/tts-zhi/gradle.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
GROUP=com.mogo.tts
|
||||
POM_ARTIFACT_ID=tts-zhi
|
||||
VERSION_CODE=1
|
||||
21
tts/tts-zhi/proguard-rules.pro
vendored
Normal file
21
tts/tts-zhi/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# 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 *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
5
tts/tts-zhi/src/main/AndroidManifest.xml
Normal file
5
tts/tts-zhi/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.tts.zhi">
|
||||
|
||||
/
|
||||
</manifest>
|
||||
472
tts/tts-zhi/src/main/java/com/mogo/tts/zhi/ZhiTTS.java
Normal file
472
tts/tts-zhi/src/main/java/com/mogo/tts/zhi/ZhiTTS.java
Normal file
@@ -0,0 +1,472 @@
|
||||
package com.mogo.tts.zhi;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.alibaba.android.arouter.facade.annotation.Route;
|
||||
import com.mogo.tts.base.IMogoTTS;
|
||||
import com.mogo.tts.base.IMogoTTSCallback;
|
||||
import com.mogo.tts.base.MogoTTSConstants;
|
||||
import com.mogo.tts.base.PreemptType;
|
||||
import com.mogo.utils.AppUtils;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
import com.zhidao.auto.platform.voice.VoiceClient;
|
||||
import com.zhidao.voicesdk.MogoVoiceManager;
|
||||
import com.zhidao.voicesdk.MogoVoiceManagerImpl;
|
||||
import com.zhidao.voicesdk.callback.OnConnStatusListener;
|
||||
import com.zhidao.voicesdk.callback.OnTtsListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2020/10/12
|
||||
* <p>
|
||||
* 描述
|
||||
*/
|
||||
@Route( path = MogoTTSConstants.API_PATH )
|
||||
class ZhiTTS implements IMogoTTS, VoiceClient.VoiceCmdCallBack, OnTtsListener {
|
||||
|
||||
private static final String TAG = "ZhiTTS";
|
||||
private String mLastQAndASpeakText;
|
||||
|
||||
private boolean mHasFlush = false;
|
||||
private boolean mInitReady = false;
|
||||
private Context mContext;
|
||||
|
||||
public synchronized void release() {
|
||||
Logger.d( TAG, "release" );
|
||||
if ( mCmdMap != null && !mCmdMap.isEmpty() && mVoiceClient != null ) {
|
||||
for ( String cmd : mCmdMap.keySet() ) {
|
||||
mVoiceClient.unRegisterCustomWakeupCmd( cmd );
|
||||
}
|
||||
}
|
||||
mQAndAMap.clear();
|
||||
mVoiceClient.release();
|
||||
mSpeakVoiceMap.clear();
|
||||
mCacheUnWakeupCommands.clear();
|
||||
mContext = null;
|
||||
}
|
||||
|
||||
private VoiceClient mVoiceClient;
|
||||
private MogoVoiceManager mogoVoiceManager;
|
||||
// 免唤醒指令
|
||||
private Map< String, List< IMogoTTSCallback > > mCmdMap = new HashMap<>();
|
||||
// 问答指令
|
||||
private Map< String, IMogoTTSCallback > mQAndAMap = new HashMap<>();
|
||||
// 单独的语音播放
|
||||
private Map< String, IMogoTTSCallback > mSpeakVoiceMap = new HashMap<>();
|
||||
|
||||
private Map< String, String[] > mCacheUnWakeupCommands = new ConcurrentHashMap<>();
|
||||
|
||||
private void initFlushStatus() {
|
||||
if ( !mHasFlush ) {
|
||||
mHasFlush = isVoiceServiceReady( mContext );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
private void initSpeech( Context context ) {
|
||||
mogoVoiceManager = MogoVoiceManagerImpl.getInstance();
|
||||
mogoVoiceManager.init( context, new OnConnStatusListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
mInitReady = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed() {
|
||||
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否语音注册成功
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean hasFlush() {
|
||||
return mHasFlush;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdSelected( String cmd ) {
|
||||
if ( !mCmdMap.containsKey( cmd ) ) {
|
||||
return;
|
||||
}
|
||||
Logger.d( TAG, "received command: %s", cmd );
|
||||
|
||||
Iterator< IMogoTTSCallback > iterator = null;
|
||||
try {
|
||||
List< IMogoTTSCallback > cmdCallBacks = mCmdMap.get( cmd );
|
||||
iterator = new ArrayList<>( cmdCallBacks ).iterator();
|
||||
} catch ( Exception e ) {
|
||||
|
||||
}
|
||||
while ( iterator != null && iterator.hasNext() ) {
|
||||
IMogoTTSCallback callBack = iterator.next();
|
||||
if ( callBack != null ) {
|
||||
callBack.onCmdSelected( cmd );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdAction( String speakText ) {
|
||||
if ( !TextUtils.isEmpty( mLastQAndASpeakText ) ) {
|
||||
IMogoTTSCallback cmdCallBack = mQAndAMap.remove( mLastQAndASpeakText );
|
||||
if ( cmdCallBack != null ) {
|
||||
cmdCallBack.onCmdAction( speakText );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdCancel( String speakText ) {
|
||||
if ( !TextUtils.isEmpty( mLastQAndASpeakText ) ) {
|
||||
IMogoTTSCallback cmdCallBack = mQAndAMap.remove( mLastQAndASpeakText );
|
||||
if ( cmdCallBack != null ) {
|
||||
cmdCallBack.onCmdCancel( speakText );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakEnd( String speakText ) {
|
||||
if ( mQAndAMap.containsKey( speakText ) ) {
|
||||
mLastQAndASpeakText = speakText;
|
||||
IMogoTTSCallback cmdCallBack = mQAndAMap.get( speakText );
|
||||
if ( cmdCallBack != null ) {
|
||||
cmdCallBack.onSpeakEnd( speakText );
|
||||
return;
|
||||
}
|
||||
}
|
||||
IMogoTTSCallback callBack = mSpeakVoiceMap.remove( speakText );
|
||||
if ( callBack != null ) {
|
||||
callBack.onSpeakEnd( speakText );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakSelectTimeOut( String speakText ) {
|
||||
if ( mQAndAMap.containsKey( speakText ) ) {
|
||||
if ( TextUtils.equals( speakText, mLastQAndASpeakText ) ) {
|
||||
mLastQAndASpeakText = null;
|
||||
}
|
||||
IMogoTTSCallback cmdCallBack = mQAndAMap.remove( speakText );
|
||||
if ( cmdCallBack != null ) {
|
||||
cmdCallBack.onSpeakSelectTimeOut( speakText );
|
||||
return;
|
||||
}
|
||||
}
|
||||
IMogoTTSCallback callBack = mSpeakVoiceMap.remove( speakText );
|
||||
if ( callBack != null ) {
|
||||
callBack.onSpeakSelectTimeOut( speakText );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 语音播报
|
||||
*
|
||||
* @param text
|
||||
*/
|
||||
public void speakTTSVoice( String text, IMogoTTSCallback callBack ) {
|
||||
try {
|
||||
initFlushStatus();
|
||||
if ( mHasFlush ) {
|
||||
mSpeakVoiceMap.put( text, callBack );
|
||||
mVoiceClient.speakDefault( text );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 语音播报
|
||||
*
|
||||
* @param text
|
||||
*/
|
||||
public void speakTTSVoice( String text ) {
|
||||
try {
|
||||
initFlushStatus();
|
||||
if ( mHasFlush ) {
|
||||
mVoiceClient.speakDefault( text );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 语音播报
|
||||
*
|
||||
* @param text 播报内容
|
||||
* @param type 播报策略
|
||||
*/
|
||||
public void speakTTSVoice( String text, PreemptType type, IMogoTTSCallback callBack ) {
|
||||
try {
|
||||
initFlushStatus();
|
||||
if ( mHasFlush ) {
|
||||
mSpeakVoiceMap.put( text, callBack );
|
||||
VoiceClient.PreemptType preemptType = VoiceClient.PreemptType.PREEMPT_TYPE_NONE;
|
||||
if ( type != null ) {
|
||||
switch ( type ) {
|
||||
case PREEMPT_TYPE_NEXT:
|
||||
preemptType = VoiceClient.PreemptType.PREEMPT_TYPE_NEXT;
|
||||
break;
|
||||
case PREEMPT_TYPE_FLUSH:
|
||||
preemptType = VoiceClient.PreemptType.PREEMPT_TYPE_FLUSH;
|
||||
break;
|
||||
case PREEMPT_TYPE_IMMEDIATELY:
|
||||
preemptType = VoiceClient.PreemptType.PREEMPT_TYPE_IMMEADIATELY;
|
||||
break;
|
||||
case PREEMPT_TYPE_IMMEDIATELY_WITHOUT_CANCEL:
|
||||
preemptType = VoiceClient.PreemptType.PREEMPT_TYPE_IMMEADIATELY_WITHOUT_CANCLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mVoiceClient.speakTypeText( text, preemptType );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 问答类型语音注册:默认确认和取消
|
||||
*
|
||||
* @param tts 播报内容
|
||||
*/
|
||||
public void speakQAndACmd( String tts, IMogoTTSCallback callBack ) {
|
||||
initFlushStatus();
|
||||
if ( mHasFlush ) {
|
||||
mQAndAMap.put( tts, callBack );
|
||||
mVoiceClient.speakTtsAndRegistCmd( tts );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 问答类型语音注册
|
||||
*
|
||||
* @param tts 播报内容
|
||||
* @param okCmds 确认命令唤醒词
|
||||
* @param cancelCmds 取消命令唤醒词
|
||||
*/
|
||||
public void speakQAndACmd( String tts, String[] okCmds, String[] cancelCmds, IMogoTTSCallback callBack ) {
|
||||
initFlushStatus();
|
||||
if ( mHasFlush ) {
|
||||
mQAndAMap.put( tts, callBack );
|
||||
mVoiceClient.speakTtsAndRegistCmd( tts, okCmds, cancelCmds );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册免唤醒命令
|
||||
*
|
||||
* @param cmd
|
||||
* @param cmdWords
|
||||
* @param callBack
|
||||
*/
|
||||
public void registerUnWakeupCommand( String cmd, String[] cmdWords, IMogoTTSCallback callBack ) {
|
||||
if ( !mCmdMap.containsKey( cmd ) ) {
|
||||
mCmdMap.put( cmd, new ArrayList<>() );
|
||||
}
|
||||
mCmdMap.get( cmd ).add( callBack );
|
||||
|
||||
initFlushStatus();
|
||||
if ( mHasFlush ) {
|
||||
mVoiceClient.registerCustomWakeupCmd( cmd, cmdWords );
|
||||
mCacheUnWakeupCommands.remove( cmd );
|
||||
}
|
||||
Logger.i( TAG, "cache un wakeup command2. %s", cmd );
|
||||
mCacheUnWakeupCommands.put( cmd, cmdWords );
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册免唤醒命令
|
||||
*
|
||||
* @param cmd
|
||||
* @param cmdWords
|
||||
*/
|
||||
private void registerUnWakeupCommand( String cmd, String[] cmdWords ) {
|
||||
initFlushStatus();
|
||||
if ( mHasFlush ) {
|
||||
mVoiceClient.registerCustomWakeupCmd( cmd, cmdWords );
|
||||
mCacheUnWakeupCommands.remove( cmd );
|
||||
}
|
||||
Logger.i( TAG, "cache un wakeup command. %s", cmd );
|
||||
mCacheUnWakeupCommands.put( cmd, cmdWords );
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销免唤醒命令
|
||||
*
|
||||
* @param cmd
|
||||
*/
|
||||
public synchronized void unregisterUnWakeupCommand( String cmd ) {
|
||||
mCmdMap.remove( cmd );
|
||||
mVoiceClient.unRegisterCustomWakeupCmd( cmd );
|
||||
mCacheUnWakeupCommands.remove( cmd );
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销免唤醒命令
|
||||
*
|
||||
* @param cmd
|
||||
*/
|
||||
public synchronized void unregisterUnWakeupCommand( String cmd, IMogoTTSCallback callBack ) {
|
||||
if ( mCmdMap.containsKey( cmd ) ) {
|
||||
List< IMogoTTSCallback > callBacks = mCmdMap.get( cmd );
|
||||
if ( callBacks != null ) {
|
||||
callBacks.remove( callBack );
|
||||
}
|
||||
if ( callBacks.isEmpty() ) {
|
||||
mCmdMap.remove( cmd );
|
||||
mVoiceClient.unRegisterCustomWakeupCmd( cmd );
|
||||
mCacheUnWakeupCommands.remove( cmd );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void startAssistant( Context context ) {
|
||||
startAssistant( context, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @param status window_start_cancel 0 - 结束, 1 - 显示, 2 - 未激活调试进入
|
||||
*/
|
||||
public static void startAssistant( Context context, int status ) {
|
||||
final Intent intent = new Intent();
|
||||
intent.setFlags( Intent.FLAG_INCLUDE_STOPPED_PACKAGES );
|
||||
intent.setAction( "pvetec.intent.action.txz.switch" );
|
||||
intent.putExtra( "window_start_cancel", status );
|
||||
intent.putExtra( "extra_switch_type", "window_start_cancel" );
|
||||
Logger.d( TAG, "status = %d", status );
|
||||
context.sendBroadcast( intent );
|
||||
}
|
||||
|
||||
public synchronized void flush() {
|
||||
if ( mCacheUnWakeupCommands.isEmpty() ) {
|
||||
return;
|
||||
}
|
||||
mHasFlush = true;
|
||||
Logger.d( TAG, "flush cache voice command when voice service ready." );
|
||||
final Map< String, String[] > tmp = new HashMap<>( mCacheUnWakeupCommands );
|
||||
for ( String cmd : tmp.keySet() ) {
|
||||
registerUnWakeupCommand( cmd, tmp.get( cmd ) );
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isVoiceServiceReady( Context context ) {
|
||||
if ( AppUtils.isProcessRunning( context, AppUtils.getPackageUid( context, "com.zhidao.speech" ) )
|
||||
&& AppUtils.isProcessRunning( context, AppUtils.getPackageUid( context, "com.zhidao.speech.adapter" ) ) ) {
|
||||
return true;
|
||||
} else if ( AppUtils.isProcessRunning( context, AppUtils.getPackageUid( context, "com.txznet.txz" ) )
|
||||
&& AppUtils.isProcessRunning( context, AppUtils.getPackageUid( context, "com.txznet.adapter" ) ) ) {
|
||||
Logger.d( TAG, "txz is voiceServiceReady" );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void speakTTSAndDuck( String text ) {
|
||||
speakTTSAndDuck( text, null );
|
||||
}
|
||||
|
||||
public void speakTTSAndDuck( String text, IMogoTTSCallback callBack ) {
|
||||
try {
|
||||
if ( mInitReady ) {
|
||||
mSpeakVoiceMap.put( text, callBack );
|
||||
mogoVoiceManager.toSpeak( text, -3, this );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
}
|
||||
}
|
||||
|
||||
public void shutUp( String ttsId, String text ) {
|
||||
try {
|
||||
mSpeakVoiceMap.remove( text );
|
||||
mogoVoiceManager.shutUp( ttsId );
|
||||
} catch ( Exception e ) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打断上一条正在播报的语音内容,仅在Speech上生效,TXZ为空实现
|
||||
* 语音SDK生效版本从1.0.8.4版本起
|
||||
*/
|
||||
public void breakOffSpeak() {
|
||||
mVoiceClient.breakOffSpeak();
|
||||
}
|
||||
|
||||
public void clearTTSCallback( String text ) {
|
||||
try {
|
||||
mSpeakVoiceMap.remove( text );
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTtsStart( String ttsId, String text ) {
|
||||
IMogoTTSCallback callBack = mSpeakVoiceMap.get( text );
|
||||
if ( callBack != null ) {
|
||||
callBack.onTTSStart( ttsId, text );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTtsFinish( String ttsId, String text ) {
|
||||
IMogoTTSCallback callBack = mSpeakVoiceMap.remove( text );
|
||||
if ( callBack != null ) {
|
||||
callBack.onTTSEnd( ttsId, text );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTtsError( String ttsId, String text ) {
|
||||
IMogoTTSCallback callBack = mSpeakVoiceMap.remove( text );
|
||||
if ( callBack != null ) {
|
||||
callBack.onTTSError( ttsId, text );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init( Context context ) {
|
||||
if ( context != null ) {
|
||||
mContext = context.getApplicationContext();
|
||||
mVoiceClient = new VoiceClient( mContext );
|
||||
mVoiceClient.setCallBack( this );
|
||||
initFlushStatus();
|
||||
initSpeech( context );
|
||||
Logger.w( TAG, "voice is ready = %s", mHasFlush );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startAIAssist( Context context ) {
|
||||
startAssistant( context, 1 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startAIAssist( Context context, int status ) {
|
||||
final Intent intent = new Intent();
|
||||
intent.setFlags( Intent.FLAG_INCLUDE_STOPPED_PACKAGES );
|
||||
intent.setAction( "pvetec.intent.action.txz.switch" );
|
||||
intent.putExtra( "window_start_cancel", status );
|
||||
intent.putExtra( "extra_switch_type", "window_start_cancel" );
|
||||
Logger.d( TAG, "status = %d", status );
|
||||
context.sendBroadcast( intent );
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,12 @@
|
||||
if [ $? -ne 0 ];then exit; fi
|
||||
./gradlew :skin:mogo-skin-support:clean :skin:mogo-skin-support:uploadArchives
|
||||
if [ $? -ne 0 ]; then exit; fi
|
||||
./gradlew :tts:tts-base:clean :tts:tts-base:uploadArchives
|
||||
if [ $? -ne 0 ]; then exit; fi
|
||||
./gradlew :tts:tts-zhi:clean :tts:tts-zhi:uploadArchives
|
||||
if [ $? -ne 0 ]; then exit; fi
|
||||
./gradlew :tts:tts-di:clean :tts:tts-di:uploadArchives
|
||||
if [ $? -ne 0 ]; then exit; fi
|
||||
./gradlew :foudations:mogo-commons:clean :foudations:mogo-commons:uploadArchives
|
||||
if [ $? -ne 0 ]; then exit; fi
|
||||
./gradlew :libraries:mogo-map-api:clean :libraries:mogo-map-api:uploadArchives
|
||||
|
||||
Reference in New Issue
Block a user