初始化框架,完成扫描回调,语音接口

This commit is contained in:
2021-02-08 10:34:29 +08:00
commit 29af9af399
73 changed files with 2275 additions and 0 deletions

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

57
app/build.gradle Normal file
View File

@ -0,0 +1,57 @@
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 29
buildToolsVersion "30.0.2"
defaultConfig {
applicationId "chaoran.business.pda"
minSdkVersion 22
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
signingConfigs {
release {
storeFile file(RELEASE_STOREFILE);
storePassword RELEASE_STORE_PASSWORD;
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
}
}
buildTypes {
release {
minifyEnabled false //是否代码混淆
multiDexEnabled true //防止方法数量超过65536导致错误
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
//配置签名
signingConfig signingConfigs.release
}
}
//加载动态库
sourceSets {
main {
jniLibs.srcDir(['libs'])
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
//加载jar包
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.preference:preference:1.1.1'
}

26
app/jni/Android.mk Normal file
View File

@ -0,0 +1,26 @@
#
# Copyright 2009 Cedric Priscal
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
TARGET_PLATFORM := android-3
LOCAL_MODULE := rockchip
LOCAL_SRC_FILES := rockchip.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)

1
app/jni/Application.mk Normal file
View File

@ -0,0 +1 @@
APP_ABI := armeabi-v7a

163
app/jni/rockchip.c Normal file
View File

@ -0,0 +1,163 @@
/*
* Copyright 2009-2011 Cedric Priscal
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>
#include "rockchip.h"
#include "android/log.h"
static const char *TAG="RockChip";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)
static speed_t getBaudrate(jint baudrate)
{
switch(baudrate) {
case 0: return B0;
case 50: return B50;
case 75: return B75;
case 110: return B110;
case 134: return B134;
case 150: return B150;
case 200: return B200;
case 300: return B300;
case 600: return B600;
case 1200: return B1200;
case 1800: return B1800;
case 2400: return B2400;
case 4800: return B4800;
case 9600: return B9600;
case 19200: return B19200;
case 38400: return B38400;
case 57600: return B57600;
case 115200: return B115200;
case 230400: return B230400;
case 460800: return B460800;
case 500000: return B500000;
case 576000: return B576000;
case 921600: return B921600;
case 1000000: return B1000000;
case 1152000: return B1152000;
case 1500000: return B1500000;
case 2000000: return B2000000;
case 2500000: return B2500000;
case 3000000: return B3000000;
case 3500000: return B3500000;
case 4000000: return B4000000;
default: return -1;
}
}
/*
* Class: android_serialport_SerialPort
* Method: open
* Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
*/
JNIEXPORT jobject JNICALL Java_chaoran_business_adapter_RockChipAdapter_open
(JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags)
{
int fd;
speed_t speed;
jobject mFileDescriptor;
/* Check arguments */
{
speed = getBaudrate(baudrate);
if (speed == -1) {
LOGE("Invalid baudrate");
return NULL;
}
}
/* Opening device */
{
jboolean iscopy;
const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);
LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
fd = open(path_utf, O_RDWR | flags);
LOGD("open() fd = %d", fd);
(*env)->ReleaseStringUTFChars(env, path, path_utf);
if (fd == -1)
{
/* Throw an exception */
LOGE("Cannot open port");
return NULL;
}
}
/* Configure device */
{
struct termios cfg;
LOGD("Configuring serial port");
if (tcgetattr(fd, &cfg))
{
LOGE("tcgetattr() failed");
close(fd);
return NULL;
}
cfmakeraw(&cfg);
cfsetispeed(&cfg, speed);
cfsetospeed(&cfg, speed);
if (tcsetattr(fd, TCSANOW, &cfg))
{
LOGE("tcsetattr() failed");
close(fd);
return NULL;
}
}
/* Create a corresponding file descriptor */
{
jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");
jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V");
jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");
mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);
(*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);
}
return mFileDescriptor;
}
/*
* Class: cedric_serial_SerialPort
* Method: close
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_chaoran_business_adapter_RockChipAdapter_close
(JNIEnv *env, jobject thiz)
{
jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");
jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");
jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);
LOGD("close(fd = %d)", descriptor);
close(descriptor);
}

29
app/jni/rockchip.h Normal file
View File

@ -0,0 +1,29 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class chaoran_business_adapter_RockChipAdapter */
#ifndef _Included_chaoran_business_adapter_RockChipAdapter
#define _Included_chaoran_business_adapter_RockChipAdapter
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: chaoran_business_adapter_RockChipAdapter
* Method: open
* Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
*/
JNIEXPORT jobject JNICALL Java_chaoran_business_adapter_RockChipAdapter_open
(JNIEnv *, jclass, jstring, jint, jint);
/*
* Class: chaoran_business_adapter_RockChipAdapter
* Method: close
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_chaoran_business_adapter_RockChipAdapter_close
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif

Binary file not shown.

Binary file not shown.

BIN
app/libs/flytek.jar Normal file

Binary file not shown.

BIN
app/libs/idata.jar Normal file

Binary file not shown.

BIN
app/libs/urobo.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,5 @@
E:/AndroidStudioProject/pda-web/app/obj/local/armeabi-v7a/objs/rockchip/rockchip.o: \
E:\AndroidStudioProject\pda-web\app\jni\rockchip.c \
E:\AndroidStudioProject\pda-web\app\jni\rockchip.h
E:\AndroidStudioProject\pda-web\app\jni\rockchip.h:

21
app/proguard-rules.pro vendored Normal file
View 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

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="chaoran.business">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:name=".application.InitApplication"
android:theme="@style/Theme.PdaWeb"
android:usesCleartextTraffic="true">
<activity
android:name=".activity.NetworkSettingActivity"
android:label="@string/title_activity_setting_network" />
<activity
android:name=".activity.VoiceSettingActivity"
android:label="@string/title_activity_setting_voice" />
<activity
android:name=".activity.MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activity.AboutActivity"
android:label="@string/activity_about" />
</application>
</manifest>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,46 @@
package chaoran.business;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-01 FXY Created
**********************************************
*/
public enum BrandEnum {
//枚举名即为valueOf()
UROBO("优博讯", "urobo"),
ROCKCHIP("瑞芯微电子", "rockchip"),
TEST("测试设备", "test"),
IDATA("匿名设备", "idata"),
ALPS("阿尔卑斯", "alps");
private String name;
private String code;
BrandEnum(String name, String code) {
this.name = name;
this.code = code;
}
/**
* 通过设备型号代码获取设备信息
*
* @param code
* @return
*/
public static BrandEnum code(String code) {
if (null == code) {
code = new String();
}
for (BrandEnum brandEnum : values()) {
if (brandEnum.code.equals(code.toLowerCase())) {
return brandEnum;
}
}
return TEST;
}
}

View File

@ -0,0 +1,27 @@
package chaoran.business.activity;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-04 FXY Created
**********************************************
*/
import android.os.Bundle;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import chaoran.business.R;
public class AboutActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
setTitle(R.string.activity_about);
TextView textView = findViewById(R.id.about_content);
textView.setText(R.string.activity_about_content);
}
}

View File

@ -0,0 +1,128 @@
package chaoran.business.activity;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import chaoran.business.BrandEnum;
import chaoran.business.R;
import chaoran.business.adapter.*;
import chaoran.business.vioce.TekVoiceEngine;
import chaoran.business.vioce.VoiceEngine;
/**
* 流程:联网认证设备型号,验证通过,查找设备品牌进行调用驱动操作
*/
/**
* 提供文字转语音功能实时播报PDA状态
*/
public class MainActivity extends AppCompatActivity implements ResultListener {
private WebView webView;
private Adapter adapter;
private VoiceEngine voiceEngine;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initData() {
BrandEnum brand = BrandEnum.code(Build.MANUFACTURER);
Toast.makeText(this, Build.MANUFACTURER, Toast.LENGTH_LONG).show();
switch (brand) {
case UROBO:
adapter = new UroBoAdapter(this, this);
break;
case ROCKCHIP:
adapter = new RockChipAdapter(this, this);
break;
case IDATA:
adapter = new IDataAdapter(this, this);
break;
case ALPS:
adapter = new AlpsAdapter(this, this);
break;
}
if (null != adapter) {
adapter.start();
}
}
@SuppressLint("JavascriptInterface")
private void initView() {
setTitle(R.string.title_activity_main);
voiceEngine = new TekVoiceEngine(this);
webView = findViewById(R.id.webView);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
webView.addJavascriptInterface(voiceEngine, "VoiceEngine");
webView.loadUrl(url());
}
@Override
protected void onResume() {
//再次唤醒该页面时,重新加载页面和语音配置
webView.loadUrl(url());
voiceEngine.loadParam();
super.onResume();
}
@Override
@SuppressLint("SetJavaScriptEnabled")
public void result(String result) {
runOnUiThread(() -> webView.loadUrl("javascript:render(\'" + result + "\')"));
}
@Override
protected void onDestroy() {
adapter.stop();
super.onDestroy();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.action_setting_network:
startActivity(new Intent(this, NetworkSettingActivity.class));
break;
case R.id.action_setting_voice:
startActivity(new Intent(this, VoiceSettingActivity.class));
break;
case R.id.action_about:
startActivity(new Intent(this, AboutActivity.class));
break;
}
return super.onOptionsItemSelected(item);
}
private String url() {
SharedPreferences spf = this.getSharedPreferences("crtech", Context.MODE_PRIVATE);
String address = spf.getString("address", "").replaceAll(" ", "");
String path = spf.getString("path", "").replaceAll(" ", "");
Integer port = spf.getInt("port", -1);
String link = address.concat(":").concat(String.valueOf(port)).concat(path);
return link.startsWith("http://") ? link : "http://".concat(link);
}
}

View File

@ -0,0 +1,56 @@
package chaoran.business.activity;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-02 FXY Created
**********************************************
*/
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import chaoran.business.R;
public class NetworkSettingActivity extends AppCompatActivity {
private EditText address, path, port;
private Button save, cancel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setting_network);
initView();
}
private void initView() {
address = findViewById(R.id.address);
path = findViewById(R.id.path);
port = findViewById(R.id.port);
save = findViewById(R.id.save);
cancel = findViewById(R.id.cancel);
setTitle(R.string.title_activity_setting_network);
SharedPreferences sharedPreferences = this.getSharedPreferences("crtech", Context.MODE_PRIVATE);
address.setText(sharedPreferences.getString("address", ""));
path.setText(sharedPreferences.getString("path", ""));
port.setText(String.valueOf(sharedPreferences.getInt("port", -1)));
cancel.setOnClickListener((e) -> this.finish());
save.setOnClickListener((e) -> saveSetting());
}
private void saveSetting() {
SharedPreferences.Editor editor = this.getSharedPreferences("crtech", Context.MODE_PRIVATE).edit();
editor.putString("address", address.getText().toString().trim());
editor.putString("path", path.getText().toString().trim());
editor.putInt("port", Integer.parseInt(port.getText().toString().trim()));
editor.commit();
this.finish();
}
}

View File

@ -0,0 +1,23 @@
package chaoran.business.activity;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-01 FXY Created
**********************************************
*/
/**
* 结果监听器,用于回调结果
* 调用前端render()函数
*/
public interface ResultListener {
/**
* js 调用方法
*
* @param result
* @return
*/
public void result(String result);
}

View File

@ -0,0 +1,137 @@
package chaoran.business.activity;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-05 FXY Created
**********************************************
*/
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.*;
import chaoran.business.R;
import chaoran.business.vioce.TekVoiceEngine;
import chaoran.business.vioce.VoiceEngine;
/**
* 播报语音设置
*/
public class VoiceSettingActivity extends Activity {
private EditText testText;
private RadioButton voiceF, voiceY;
private SeekBar voiceSize, voiceSpeed, voiceIndicate;
private Button save, cancel;
private SharedPreferences sharedPreferences;
private RadioGroup voiceMemberGroup;
private VoiceEngine voiceEngine;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setting_voice);
initView();
initData();
initListener();
}
private void initView() {
testText = findViewById(R.id.voice_test_text);
voiceF = findViewById(R.id.voice_member_xiaofeng);
voiceY = findViewById(R.id.voice_member_xiaoyan);
voiceSize = findViewById(R.id.voice_size);
voiceSpeed = findViewById(R.id.voice_speed);
voiceIndicate = findViewById(R.id.voice_indicate);
save = findViewById(R.id.save_voice_setting);
cancel = findViewById(R.id.cancel_voice_setting);
voiceMemberGroup = findViewById(R.id.voice_member_group);
voiceEngine = new TekVoiceEngine(this);
}
private void initData() {
sharedPreferences = getSharedPreferences("voiceEngine", MODE_PRIVATE);
//设置测试文本
testText.setText(sharedPreferences.getString("testText", testText.getText().toString()));
//设置播报人员
String voiceMember = sharedPreferences.getString("voiceMember", "xiaofeng");
if (voiceMember.equals("xiaofeng")) {
voiceF.setChecked(true);
voiceY.setChecked(false);
} else {
voiceY.setChecked(true);
voiceF.setChecked(false);
}
//设置功能选项
voiceSize.setProgress(sharedPreferences.getInt("voiceSize", 100));
voiceSpeed.setProgress(sharedPreferences.getInt("voiceSpeed", 80));
voiceIndicate.setProgress(sharedPreferences.getInt("voiceIndicate", 50));
}
public void initListener() {
SeekBar.OnSeekBarChangeListener seekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
//停止播放
voiceEngine.stopSpeaking();
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
//播放语音
voiceEngine.setParam(voiceF.isChecked() ? "xiaofeng" : "xiaoyan", voiceSize.getProgress(), voiceIndicate.getProgress(), voiceSpeed.getProgress());
voiceEngine.startSpeaking(testText.getText().toString());
}
};
voiceSize.setOnSeekBarChangeListener(seekBarChangeListener);
voiceIndicate.setOnSeekBarChangeListener(seekBarChangeListener);
voiceSpeed.setOnSeekBarChangeListener(seekBarChangeListener);
SharedPreferences.Editor editor = sharedPreferences.edit();
save.setOnClickListener(a -> {
editor.putInt("voiceSize", voiceSize.getProgress());
editor.putInt("voiceIndicate", voiceIndicate.getProgress());
editor.putInt("voiceSpeed", voiceSpeed.getProgress());
editor.putString("testText", testText.getText().toString());
editor.putString("voiceMember", voiceF.isChecked() ? "xiaofeng" : "xiaoyan");
editor.commit();
voiceEngine.stopSpeaking();
voiceEngine.destroy();
Toast.makeText(this, "语音配置保存成功!", Toast.LENGTH_SHORT).show();
this.finish();
});
cancel.setOnClickListener(a -> {
voiceEngine.stopSpeaking();
voiceEngine.destroy();
this.finish();
});
voiceMemberGroup.setOnCheckedChangeListener((a, b) -> {
//播放语音
voiceEngine.setParam(voiceF.isChecked() ? "xiaofeng" : "xiaoyan", voiceSize.getProgress(), voiceIndicate.getProgress(), voiceSpeed.getProgress());
voiceEngine.startSpeaking(testText.getText().toString());
});
}
@Override
protected void onStart() {
super.onStart();
//初始化加载一次
voiceEngine.setParam(voiceF.isChecked() ? "xiaofeng" : "xiaoyan", voiceSize.getProgress(), voiceIndicate.getProgress(), voiceSpeed.getProgress());
voiceEngine.startSpeaking(testText.getText().toString());
}
@Override
protected void onDestroy() {
voiceEngine.stopSpeaking();
voiceEngine.destroy();
super.onDestroy();
}
}

View File

@ -0,0 +1,32 @@
package chaoran.business.adapter;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-01 FXY Created
**********************************************
*/
/**
* 适配器基类
* 同一品牌的设备,不论什么型号,用的是同一个适配器
* 设备按品牌区分,而不按具体型号区分
*/
public interface Adapter{
/**
* 开始扫描
*
* @return
*/
public void start();
/**
* 结束扫描
*
* @return
*/
public void stop();
}

View File

@ -0,0 +1,65 @@
package chaoran.business.adapter;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-03 FXY Created
**********************************************
*/
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Vibrator;
import chaoran.business.R;
import chaoran.business.activity.ResultListener;
import chaoran.business.strategy.Strategy;
/**
* 阿尔卑斯适配器
* CR-5W适用
*/
public class AlpsAdapter implements Adapter {
private Context context;
private Strategy strategy;
private ResultListener resultListener;
public AlpsAdapter(Context context, ResultListener resultListener) {
this.context = context;
this.resultListener = resultListener;
strategy = new Receiver();
}
@Override
public void start() {
strategy.executeStrategy(resultListener);
}
@Override
public void stop() {
strategy.exclusiveStrategy();
}
public class Receiver extends BroadcastReceiver implements Strategy {
@Override
public void onReceive(Context context, Intent intent) {
resultListener.result(intent.getStringExtra("BARCODE"));
}
@Override
public void executeStrategy(ResultListener resultListener) {
IntentFilter filter = new IntentFilter();
filter.addAction("com.barcode.sendBroadcast");
context.registerReceiver(this, filter);
}
@Override
public void exclusiveStrategy() {
context.unregisterReceiver(this);
}
}
}

View File

@ -0,0 +1,70 @@
package chaoran.business.adapter;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-02 FXY Created
**********************************************
*/
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import chaoran.business.activity.ResultListener;
import chaoran.business.strategy.Strategy;
import com.android.barcodescandemo.ScannerInerface;
/**
* idata 适配器
*/
public class IDataAdapter implements Adapter {
private Context context;
private ResultListener resultListener;
private Strategy strategy;
public IDataAdapter(Context context, ResultListener resultListener) {
this.context = context;
this.resultListener = resultListener;
strategy = new Receiver();
}
@Override
public void start() {
strategy.executeStrategy(resultListener);
}
@Override
public void stop() {
strategy.exclusiveStrategy();
}
public class Receiver extends BroadcastReceiver implements Strategy {
private ScannerInerface scannerInerface;
public Receiver() {
scannerInerface = new ScannerInerface(context);
scannerInerface.setOutputMode(1);
}
@Override
public void onReceive(Context context, Intent intent) {
resultListener.result(intent.getStringExtra("value"));
}
@Override
public void executeStrategy(ResultListener resultListener) {
scannerInerface.open();
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.SCANRESULT");
context.registerReceiver(this, filter);
}
@Override
public void exclusiveStrategy() {
context.unregisterReceiver(this);
scannerInerface.close();
}
}
}

View File

@ -0,0 +1,118 @@
package chaoran.business.adapter;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-01 FXY Created
**********************************************
*/
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Vibrator;
import chaoran.business.R;
import chaoran.business.activity.ResultListener;
import chaoran.business.strategy.Strategy;
import java.io.*;
/**
* 瑞芯适配器
*/
public class RockChipAdapter implements Adapter {
private Strategy strategy;
private ResultListener resultListener;
private Context context;
@Override
public void start() {
strategy.executeStrategy(resultListener);
}
@Override
public void stop() {
strategy.exclusiveStrategy();
}
public RockChipAdapter(Context context, ResultListener resultListener) {
this.resultListener = resultListener;
this.context = context;
this.strategy = new Reader(new File("/dev/ttyS1"), 115200, 0);
}
public class Reader implements Strategy {
private FileDescriptor mFd;
private FileInputStream mFileInputStream;
private boolean running = true;
public Reader(File device, int baudrate, int flags) {
if (!device.canRead() || !device.canWrite()) {
try {
Process su;
su = Runtime.getRuntime().exec("/system/bin/su");
String cmd = "chmod 777 " + device.getAbsolutePath() + "\n" + "exit\n";
su.getOutputStream().write(cmd.getBytes());
if ((su.waitFor() != 0) || !device.canRead() || !device.canWrite()) {
System.out.println("获取su命令权限失败,系统或许未root");
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("获取root权限失败");
}
}
mFd = open(device.getAbsolutePath(), baudrate, flags);
if (mFd == null) {
System.out.println("获取文件描述符失败!");
}
mFileInputStream = new FileInputStream(mFd);
}
@Override
public void executeStrategy(ResultListener resultListener) {
new Thread(() -> {
while (running) {
String data = data();
if (!data.equals("")) {
resultListener.result(data);
}
}
}).start();
}
@Override
public void exclusiveStrategy() {
running = false;
close();
}
private String data() {
if (mFileInputStream == null) return "";
try {
int size = mFileInputStream.available();
byte[] buffer = new byte[size];
size = mFileInputStream.read(buffer);
if (size > 0) {
return new String(buffer);
}
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}
static {
System.loadLibrary("rockchip");
}
private native static FileDescriptor open(String path, int baudrate, int flags);
public native void close();
}

View File

@ -0,0 +1,44 @@
package chaoran.business.adapter;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-01 FXY Created
**********************************************
*/
import chaoran.business.activity.ResultListener;
import static java.lang.Thread.sleep;
public class TestAdapter implements Adapter {
private ResultListener resultListener;
public TestAdapter(ResultListener resultListener) {
this.resultListener = resultListener;
}
@Override
public void start() {
new Thread(() -> {
int i = 0;
while (i < 10) {
resultListener.result(i + "");
i++;
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
@Override
public void stop() {
}
}

View File

@ -0,0 +1,86 @@
package chaoran.business.adapter;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-01 FXY Created
**********************************************
*/
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.device.ScanManager;
import android.device.scanner.configuration.Triggering;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Vibrator;
import chaoran.business.R;
import chaoran.business.activity.ResultListener;
import chaoran.business.strategy.Strategy;
/**
* 优博讯适配器
*/
public class UroBoAdapter implements Adapter {
private Strategy strategy;
private Context context;
private ResultListener resultListener;
public UroBoAdapter(Context context, ResultListener resultListener) {
this.context = context;
this.resultListener = resultListener;
this.strategy = new Receiver();
}
@Override
public void start() {
strategy.executeStrategy(resultListener);
}
@Override
public void stop() {
strategy.exclusiveStrategy();
}
/**
* 广播接受者
* 自省策略
*/
public class Receiver extends BroadcastReceiver implements Strategy {
private ScanManager mScanManager;
public Receiver() {
mScanManager = new ScanManager();
mScanManager.openScanner();
mScanManager.switchOutputMode(0);
if (mScanManager.getTriggerMode() != Triggering.CONTINUOUS)
mScanManager.setTriggerMode(Triggering.CONTINUOUS);
}
@Override
public void onReceive(Context context, Intent intent) {
String barcode = intent.getStringExtra("barcode_string");
resultListener.result(barcode);
}
@Override
public void executeStrategy(ResultListener resultListener) {
mScanManager.startDecode();
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.ACTION_DECODE_DATA");
context.registerReceiver(this, filter);
}
@Override
public void exclusiveStrategy() {
context.unregisterReceiver(this);
mScanManager.stopDecode();
}
}
}

View File

@ -0,0 +1,28 @@
package chaoran.business.application;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-08 FXY Created
**********************************************
*/
import android.app.Application;
import chaoran.business.R;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechUtility;
public class InitApplication extends Application {
@Override
public void onCreate() {
//讯飞离线语音配置
StringBuffer param = new StringBuffer();
param.append("appid=" + getString(R.string.app_id));
param.append(",");
// 设置使用v5+
param.append(SpeechConstant.ENGINE_MODE + "=" + SpeechConstant.MODE_MSC);
SpeechUtility.createUtility(this, param.toString());
super.onCreate();
}
}

View File

@ -0,0 +1,31 @@
package chaoran.business.strategy;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-01 FXY Created
**********************************************
*/
import chaoran.business.activity.ResultListener;
/**
* 策略接口
* 普通jar包调用时此接口没用
* 此包仅用于调用硬件相关驱动
*/
public interface Strategy {
/**
* 执行策略
*
* @param resultListener
*/
public void executeStrategy(ResultListener resultListener);
/**
* 排除策略
*/
public void exclusiveStrategy();
}

View File

@ -0,0 +1,222 @@
package chaoran.business.vioce;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.widget.Toast;
import chaoran.business.R;
import com.iflytek.cloud.*;
import com.iflytek.cloud.util.ResourceUtil;
import com.iflytek.cloud.util.ResourceUtil.RESOURCE_TYPE;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-05 FXY Created
**********************************************
*/
public class TekVoiceEngine implements VoiceEngine {
private static String TAG = "TekVoiceEngine";
// 语音合成对象
private SpeechSynthesizer mTts;
//缓冲进度
private int mPercentForBuffering = 0;
//播放进度
private int mPercentForPlaying = 0;
private Toast mToast;
private Context context;
public TekVoiceEngine(Context context) {
this.context = context;
// 初始化合成对象
mTts = SpeechSynthesizer.createSynthesizer(context, mTtsInitListener);
//设置合成引擎的参数
loadParam();
//初始化对话框
mToast = Toast.makeText(context, "", Toast.LENGTH_SHORT);
}
@Override
@JavascriptInterface
public void startSpeaking(String text) {
if (null == mTts) {
this.showTip("创建对象失败,请确认 libmsc.so 放置正确,\n 且有调用 createUtility 进行初始化");
}
if (mTts.isSpeaking())
stopSpeaking();
int code = mTts.startSpeaking(text, mTtsListener);
if (code != ErrorCode.SUCCESS) {
showTip("语音合成失败,错误码: " + code + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");
}
}
@Override
@JavascriptInterface
public void stopSpeaking() {
mTts.stopSpeaking();
}
/**
* 初始化监听
*/
private InitListener mTtsInitListener = code -> {
Log.d(TAG, "InitListener init() code = " + code);
if (code != ErrorCode.SUCCESS) {
showTip("初始化失败,错误码:" + code + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");
}
};
/**
* 合成回调监听。
*/
private SynthesizerListener mTtsListener = new SynthesizerListener() {
@Override
public void onSpeakBegin() {
Log.d(TAG, "开始播放:" + System.currentTimeMillis());
}
@Override
public void onSpeakPaused() {
showTip("暂停播放");
}
@Override
public void onSpeakResumed() {
showTip("继续播放");
}
@Override
public void onBufferProgress(int percent, int beginPos, int endPos,
String info) {
// 合成进度
mPercentForBuffering = percent;
showTip(String.format(context.getString(R.string.tts_toast_format),
mPercentForBuffering, mPercentForPlaying));
}
@Override
public void onSpeakProgress(int percent, int beginPos, int endPos) {
// 播放进度
mPercentForPlaying = percent;
showTip(String.format(context.getString(R.string.tts_toast_format),
mPercentForBuffering, mPercentForPlaying));
}
@Override
public void onCompleted(SpeechError error) {
if (error == null) {
showTip("播放完成");
} else if (error != null) {
showTip(error.getPlainDescription(true));
}
}
@Override
public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
// 以下代码用于获取与云端的会话id当业务出错时将会话id提供给技术支持人员可用于查询会话日志定位出错原因
// 若使用本地能力会话id为null
if (SpeechEvent.EVENT_SESSION_ID == eventType) {
String sid = obj.getString(SpeechEvent.KEY_EVENT_AUDIO_URL);
Log.d(TAG, "session id =" + sid);
}
}
};
public void loadParam() {
// 装载参数之前,先清空参数
mTts.setParameter(SpeechConstant.PARAMS, null);
SharedPreferences sharedPreferences = context.getSharedPreferences("voiceEngine", Context.MODE_PRIVATE);
//设置使用本地引擎
mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
//设置发音人资源路径
String voicerLocal = sharedPreferences.getString("voiceMember", "xiaofeng");
mTts.setParameter(ResourceUtil.TTS_RES_PATH, getResourcePath(voicerLocal));
//设置发音人
mTts.setParameter(SpeechConstant.VOICE_NAME, voicerLocal);
//设置合成语速
mTts.setParameter(SpeechConstant.SPEED, String.valueOf(sharedPreferences.getInt("voiceSpeed", 80)));
//设置合成音调
mTts.setParameter(SpeechConstant.PITCH, String.valueOf(sharedPreferences.getInt("voiceIndicate", 50)));
//设置合成音量
mTts.setParameter(SpeechConstant.VOLUME, String.valueOf(sharedPreferences.getInt("voiceSize", 100)));
//设置播放器音频流类型
mTts.setParameter(SpeechConstant.STREAM_TYPE, "3");
// 设置播放合成音频打断音乐播放默认为true
mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true");
// 设置音频保存路径保存音频格式支持pcm、wav设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
mTts.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/tts.wav");
}
@Override
public void setParam(String voiceMember, Integer voiceSize, Integer voiceIndicate, Integer voiceSpeed) {
if (null != voiceMember) {
//设置发音人资源路径
mTts.setParameter(ResourceUtil.TTS_RES_PATH, getResourcePath(voiceMember));
//设置发音人
mTts.setParameter(SpeechConstant.VOICE_NAME, voiceMember);
}
if (null != voiceSize) {
//设置合成音量
mTts.setParameter(SpeechConstant.VOLUME, String.valueOf(voiceSize));
}
if (null != voiceIndicate) {
//设置合成音调
mTts.setParameter(SpeechConstant.PITCH, String.valueOf(voiceIndicate));
}
if (null != voiceSpeed) {
//设置合成语速
mTts.setParameter(SpeechConstant.SPEED, String.valueOf(voiceSpeed));
}
}
private void showTip(String str) {
mToast.setText(str);
mToast.show();
}
//获取发音人资源路径
private String getResourcePath(String voiceMember) {
StringBuffer tempBuffer = new StringBuffer();
String type = "tts";
//合成通用资源
tempBuffer.append(ResourceUtil.generateResourcePath(context, RESOURCE_TYPE.assets, type.concat("/common.jet")));
tempBuffer.append(";");
tempBuffer.append(ResourceUtil.generateResourcePath(context, RESOURCE_TYPE.assets, type.concat("/").concat(voiceMember).concat(".jet")));
return tempBuffer.toString();
}
public void destroy() {
if (null != mTts) {
mTts.stopSpeaking();
// 退出时释放连接
mTts.destroy();
}
}
}

View File

@ -0,0 +1,27 @@
package chaoran.business.vioce;
/*
**********************************************
* DATE PERSON REASON
* 2021-02-05 FXY Created
**********************************************
*/
public interface VoiceEngine {
//开始说话
public void startSpeaking(String text);
//停止说话
public void stopSpeaking();
//销毁资源
public void destroy();
//装载参数,从配置文件中装载参数
public void loadParam();
//设置参数
public void setParam(String voiceMember, Integer voiceSize, Integer voiceIndicate, Integer voiceSpeed);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:id="@+id/about_content"
android:layout_height="match_parent" />
</LinearLayout>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/webView" />
</LinearLayout>

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:stretchColumns="0,3"
android:gravity="center_vertical"
android:id="@+id/table">
<TableRow>
<TextView />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="服务器地址:" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="150dp"
android:id="@+id/address"
android:singleLine="true"
android:hint="ip地址或者域名地址" />
<TextView />
</TableRow>
<TableRow>
<TextView />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="服务器端口:" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="150dp"
android:id="@+id/port"
android:singleLine="true"
android:hint="介于1024-65535之间的数字" />
<TextView />
</TableRow>
<TableRow>
<TextView />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="访问子路径:" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="150dp"
android:id="@+id/path"
android:singleLine="true"
android:hint="服务器子路径" />
<TextView />
</TableRow>
<TableRow>
<TextView />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/save"
android:text="保 存" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/cancel"
android:layout_marginLeft="10px"
android:text="取 消" />
<TextView />
</TableRow>
</TableLayout>

View File

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="3"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="left"
android:text="这是一段测试文本,可以进行编辑!"
android:id="@+id/voice_test_text"
android:layout_weight="2" />
<TableLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:stretchColumns="0,3"
android:layout_weight="1"
android:gravity="center_vertical"
android:id="@+id/table">
<TableRow android:layout_marginBottom="50px">
<TextView />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="15px"
android:paddingBottom="15px"
android:text="播报人员:" />
<RadioGroup
android:layout_width="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center"
android:id="@+id/voice_member_group"
android:layout_height="match_parent">
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="小峰"
android:id="@+id/voice_member_xiaofeng" />
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="小燕"
android:layout_marginLeft="150px"
android:id="@+id/voice_member_xiaoyan" />
</RadioGroup>
<TextView />
</TableRow>
<TableRow android:layout_marginBottom="50px">
<TextView />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="播报音量:" />
<SeekBar
android:id="@+id/voice_size"
android:layout_width="wrap_content"
android:max="100"
android:min="0"
android:layout_height="match_parent" />
<TextView />
</TableRow>
<TableRow android:layout_marginBottom="50px">
<TextView />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="播报音调:" />
<SeekBar
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:max="100"
android:min="0"
android:id="@+id/voice_indicate" />
<TextView />
</TableRow>
<TableRow android:layout_marginBottom="50px">
<TextView />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="播报音速:" />
<SeekBar
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:max="200"
android:min="100"
android:id="@+id/voice_speed" />
<TextView />
</TableRow>
<TableRow>
<TextView />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/save_voice_setting"
android:text="保 存" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/cancel_voice_setting"
android:layout_marginLeft="10px"
android:text="取 消" />
<TextView />
</TableRow>
</TableLayout>
</LinearLayout>

View File

@ -0,0 +1,22 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="chaoran.business.pda.chaoran.business.activity.MainActivity">
<item
android:id="@+id/action_setting_network"
android:title="@string/action_setting_network"
android:orderInCategory="100"
app:showAsAction="never" />
<item
android:id="@+id/action_setting_voice"
android:title="@string/action_setting_voice"
android:orderInCategory="100"
app:showAsAction="never" />
<item
android:id="@+id/action_about"
android:title="@string/activity_about"
android:orderInCategory="200"
app:showAsAction="never" />
</menu>

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,16 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.PdaWeb" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@ -0,0 +1,6 @@
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>

View File

@ -0,0 +1,12 @@
<resources>
<!-- Reply Preference -->
<string-array name="reply_entries">
<item>Reply</item>
<item>Reply to all</item>
</string-array>
<string-array name="reply_values">
<item>reply</item>
<item>reply_all</item>
</string-array>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@ -0,0 +1,5 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View File

@ -0,0 +1,16 @@
<resources>
<string name="app_name">超然扫描</string>
<string name="action_setting_network">网络设置</string>
<string name="title_activity_setting_network">网络设置界面</string>
<string name="action_setting_voice">语音设置</string>
<string name="title_activity_setting_voice">语音设置界面</string>
<string name="title_activity_main">主页</string>
<string name="activity_about">关于</string>
<string name="activity_about_content">这是关于界面的内容</string>
<!-- 讯飞离线语音appid-->
<string name="app_id">601c9ec6</string>
<!-- 讯飞离线语音弹出框格式-->
<string name="tts_toast_format" formatted="false">缓冲进度为%d%%,播放进度为%d%%</string>
</resources>

View File

@ -0,0 +1,16 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.PdaWeb" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>