添加犯困表情
This commit is contained in:
parent
e01fd86961
commit
2efff01dcd
@ -22,6 +22,7 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
|
||||
<!-- BLE功能特性 -->
|
||||
<uses-feature
|
||||
|
@ -144,13 +144,13 @@ public class MainActivity extends AppCompatActivity {
|
||||
// 初始化UI控件
|
||||
ivFace = (ImageView) this.findViewById(R.id.iv_face);
|
||||
|
||||
// 初始化动画管理器
|
||||
animationManager = new RobotFaceAnimationManager(this, ivFace);
|
||||
// 初始化动画管理器单例
|
||||
animationManager = RobotFaceAnimationManager.getInstance(this, ivFace);
|
||||
|
||||
// 初始化长按检测器
|
||||
initLongPressDetector();
|
||||
|
||||
// 预加载所有动画资源
|
||||
// 预加载动画资源
|
||||
animationManager.loadFaceAnimation(RobotFaceAnimationManager.FACE_LOOP_0);
|
||||
// playRandomFaceAnimation();
|
||||
// new Thread(() -> {
|
||||
@ -1069,9 +1069,11 @@ public class MainActivity extends AppCompatActivity {
|
||||
handleConversationStarted();
|
||||
break;
|
||||
case EVENT_HUMAN_SPEAKING_DETAIL:
|
||||
Log.d(TAG_AI, "EVENT_HUMAN_SPEAKING_DETAIL");
|
||||
handleSpeakingDetail(event.getResponse(), true);
|
||||
break;
|
||||
case EVENT_RESPONDING_DETAIL:
|
||||
Log.d(TAG_AI, "EVENT_RESPONDING_DETAIL");
|
||||
handleSpeakingDetail(event.getResponse(), false);
|
||||
handleResponseCommand(event.getResponse());
|
||||
break;
|
||||
@ -1116,6 +1118,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
private void handleResponseCommand(String response) {
|
||||
String command = parseResponseCommand(response);
|
||||
if (command != null && authParams.getChainMode() == Constant.ChainMode.WEBSOCKET) {
|
||||
Log.d(TAG_AI, "command:" + command);
|
||||
isExecutingCommand = true;
|
||||
ThreadPoolUtil.runOnSubThread(() -> executeCommand(command));
|
||||
}
|
||||
@ -1206,6 +1209,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
JSONObject extraInfo = new JSONObject(output.getString("extra_info"));
|
||||
if (extraInfo.has("commands")) {
|
||||
String commands = extraInfo.getString("commands");
|
||||
Log.d(TAG_AI, "commands len:" + commands.length());
|
||||
if (commands.length() > 6) { // 过滤空命令
|
||||
return commands;
|
||||
}
|
||||
@ -1240,11 +1244,11 @@ public class MainActivity extends AppCompatActivity {
|
||||
/////////////////////////////////////// 命令执行 ///////////////////////////////////////
|
||||
|
||||
private void executeCommand(String command) {
|
||||
Log.d(TAG, "执行命令: " + command);
|
||||
Log.d(TAG_AI, "执行命令: " + command);
|
||||
|
||||
try {
|
||||
String cmdName = new JSONArray(command).getJSONObject(0).getString("name");
|
||||
Log.d(TAG, "执行命令: " + cmdName);
|
||||
Log.d(TAG_AI, "执行命令: " + cmdName);
|
||||
switch (cmdName) {
|
||||
case "check_battery":
|
||||
multiModalDialog.requestToRespond("transcript", "当前电量为87%", null);
|
||||
|
@ -16,6 +16,7 @@ import android.view.WindowManager;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import com.ismart.ib86.app.R;
|
||||
import com.ismart.ib86.robotFace.RobotFaceAnimationManager;
|
||||
|
||||
/**
|
||||
* 通知弹窗DialogFragment
|
||||
@ -286,6 +287,27 @@ public class NotificationDialogFragment extends DialogFragment {
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
// 记录当前销毁的NotificationType
|
||||
if (notificationType != null) {
|
||||
Log.d(TAG, "NotificationDialogFragment destroyed, NotificationType: " + notificationType);
|
||||
RobotFaceAnimationManager animationManager = RobotFaceAnimationManager.getInstance();
|
||||
if (animationManager != null) {
|
||||
if (notificationType.equals(NotificationType.NETWORK_LOST.name())) {
|
||||
// 网络连接失败时,加载 sad 表情
|
||||
Log.d(TAG, "Loading sad face animation for network lost");
|
||||
animationManager.loadFaceAnimation(RobotFaceAnimationManager.FACE_SAD, false, 1);
|
||||
} else if (notificationType.equals(NotificationType.NETWORK_CONNECTED.name())) {
|
||||
// 网络连接成功时,加载 happy 表情
|
||||
Log.d(TAG, "Loading happy face animation for network connected");
|
||||
animationManager.loadFaceAnimation(RobotFaceAnimationManager.FACE_HAPPY, false, 1);
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "RobotFaceAnimationManager instance is null");
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "NotificationDialogFragment destroyed, NotificationType is null");
|
||||
}
|
||||
|
||||
// 通知NotificationManager重置显示状态
|
||||
if (getActivity() != null) {
|
||||
android.content.Intent intent = new android.content.Intent(ACTION_NOTIFICATION_CLOSED);
|
||||
|
@ -0,0 +1,152 @@
|
||||
package com.ismart.ib86.feature.audio;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* 系统音量控制器
|
||||
* 提供读取当前系统媒体音量、静音、调节音量大小等功能
|
||||
*/
|
||||
public class SystemVolumeController {
|
||||
private static final String TAG = "SystemVolumeController";
|
||||
|
||||
private AudioManager audioManager;
|
||||
private int maxVolume;
|
||||
private int currentVolume;
|
||||
private boolean isMuted = false;
|
||||
private int streamType = AudioManager.STREAM_MUSIC;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param context 上下文
|
||||
*/
|
||||
public SystemVolumeController(Context context) {
|
||||
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
if (audioManager != null) {
|
||||
maxVolume = audioManager.getStreamMaxVolume(streamType);
|
||||
currentVolume = audioManager.getStreamVolume(streamType);
|
||||
} else {
|
||||
Log.e(TAG, "无法获取AudioManager服务");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前媒体音量
|
||||
* @return 当前音量值
|
||||
*/
|
||||
public int getCurrentVolume() {
|
||||
if (audioManager != null) {
|
||||
currentVolume = audioManager.getStreamVolume(streamType);
|
||||
return currentVolume;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最大音量
|
||||
* @return 最大音量值
|
||||
*/
|
||||
public int getMaxVolume() {
|
||||
return maxVolume;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置音量
|
||||
* @param volume 音量值
|
||||
* @param showUI 是否显示系统音量UI
|
||||
*/
|
||||
public void setVolume(int volume, boolean showUI) {
|
||||
if (audioManager != null) {
|
||||
// 限制音量在有效范围内
|
||||
if (volume < 0) volume = 0;
|
||||
if (volume > maxVolume) volume = maxVolume;
|
||||
|
||||
int flags = 0;
|
||||
if (showUI) {
|
||||
flags |= AudioManager.FLAG_SHOW_UI;
|
||||
}
|
||||
|
||||
audioManager.setStreamVolume(streamType, volume, flags);
|
||||
currentVolume = volume;
|
||||
isMuted = (volume == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调节音量(增加或减少)
|
||||
* @param delta 音量变化量,正数为增加,负数为减少
|
||||
* @param showUI 是否显示系统音量UI
|
||||
*/
|
||||
public void adjustVolume(int delta, boolean showUI) {
|
||||
if (audioManager != null) {
|
||||
int flags = AudioManager.FLAG_PLAY_SOUND;
|
||||
if (showUI) {
|
||||
flags |= AudioManager.FLAG_SHOW_UI;
|
||||
}
|
||||
|
||||
audioManager.adjustStreamVolume(streamType, delta > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER, flags);
|
||||
currentVolume = audioManager.getStreamVolume(streamType);
|
||||
isMuted = (currentVolume == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 静音/取消静音
|
||||
* @param mute true为静音,false为取消静音
|
||||
*/
|
||||
public void mute(boolean mute) {
|
||||
if (audioManager != null) {
|
||||
if (mute) {
|
||||
// 保存当前音量后再设置为0
|
||||
if (currentVolume > 0) {
|
||||
audioManager.setStreamVolume(streamType, 0, 0);
|
||||
isMuted = true;
|
||||
}
|
||||
} else {
|
||||
// 恢复音量
|
||||
int restoreVolume = (currentVolume > 0) ? currentVolume : maxVolume / 2;
|
||||
audioManager.setStreamVolume(streamType, restoreVolume, 0);
|
||||
currentVolume = restoreVolume;
|
||||
isMuted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换静音状态
|
||||
*/
|
||||
public void toggleMute() {
|
||||
mute(!isMuted);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否处于静音状态
|
||||
* @return true为静音,false为非静音
|
||||
*/
|
||||
public boolean isMuted() {
|
||||
return isMuted;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取音量百分比
|
||||
* @return 音量百分比 (0-100)
|
||||
*/
|
||||
public int getVolumePercentage() {
|
||||
if (maxVolume <= 0) return 0;
|
||||
return (int) ((currentVolume * 100.0f) / maxVolume);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据百分比设置音量
|
||||
* @param percentage 音量百分比 (0-100)
|
||||
* @param showUI 是否显示系统音量UI
|
||||
*/
|
||||
public void setVolumeByPercentage(int percentage, boolean showUI) {
|
||||
if (percentage < 0) percentage = 0;
|
||||
if (percentage > 100) percentage = 100;
|
||||
|
||||
int volume = (int) ((percentage * maxVolume) / 100.0f);
|
||||
setVolume(volume, showUI);
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.ismart.ib86.feature.audio;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* 音量控制使用示例
|
||||
*/
|
||||
public class VolumeControlExample {
|
||||
private static final String TAG = "VolumeControlExample";
|
||||
|
||||
private SystemVolumeController volumeController;
|
||||
|
||||
public VolumeControlExample(Context context) {
|
||||
volumeController = new SystemVolumeController(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 演示音量控制功能
|
||||
*/
|
||||
public void demonstrateVolumeControl() {
|
||||
// 获取当前音量
|
||||
int currentVolume = volumeController.getCurrentVolume();
|
||||
Log.d(TAG, "当前音量: " + currentVolume);
|
||||
|
||||
// 获取最大音量
|
||||
int maxVolume = volumeController.getMaxVolume();
|
||||
Log.d(TAG, "最大音量: " + maxVolume);
|
||||
|
||||
// 获取音量百分比
|
||||
int volumePercentage = volumeController.getVolumePercentage();
|
||||
Log.d(TAG, "音量百分比: " + volumePercentage + "%");
|
||||
|
||||
// 增加音量
|
||||
volumeController.adjustVolume(1, true);
|
||||
Log.d(TAG, "增加音量后当前音量: " + volumeController.getCurrentVolume());
|
||||
|
||||
// 减少音量
|
||||
volumeController.adjustVolume(-1, true);
|
||||
Log.d(TAG, "减少音量后当前音量: " + volumeController.getCurrentVolume());
|
||||
|
||||
// 设置特定音量值
|
||||
volumeController.setVolume(maxVolume / 2, true);
|
||||
Log.d(TAG, "设置音量为一半: " + volumeController.getCurrentVolume());
|
||||
|
||||
// 根据百分比设置音量
|
||||
volumeController.setVolumeByPercentage(80, true);
|
||||
Log.d(TAG, "设置音量为80%: " + volumeController.getCurrentVolume());
|
||||
|
||||
// 静音
|
||||
volumeController.mute(true);
|
||||
Log.d(TAG, "静音后当前音量: " + volumeController.getCurrentVolume() + ", 是否静音: " + volumeController.isMuted());
|
||||
|
||||
// 取消静音
|
||||
volumeController.mute(false);
|
||||
Log.d(TAG, "取消静音后当前音量: " + volumeController.getCurrentVolume() + ", 是否静音: " + volumeController.isMuted());
|
||||
|
||||
// 切换静音状态
|
||||
volumeController.toggleMute();
|
||||
Log.d(TAG, "切换静音状态后当前音量: " + volumeController.getCurrentVolume() + ", 是否静音: " + volumeController.isMuted());
|
||||
|
||||
// 再次切换静音状态
|
||||
volumeController.toggleMute();
|
||||
Log.d(TAG, "再次切换静音状态后当前音量: " + volumeController.getCurrentVolume() + ", 是否静音: " + volumeController.isMuted());
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ import com.ismart.ib86.app.R;
|
||||
import com.ismart.ib86.common.notification.NotificationType;
|
||||
import com.ismart.ib86.common.notification.NotificationManager;
|
||||
import com.ismart.ib86.common.notification.NotificationPriority;
|
||||
import com.ismart.ib86.robotFace.RobotFaceAnimationManager;
|
||||
|
||||
/**
|
||||
* 网络状态管理器
|
||||
@ -41,7 +42,8 @@ public class NetworkStateManager {
|
||||
public void onNetworkLost() {
|
||||
Log.d(TAG, "onNetworkLost called");
|
||||
// 网络断开使用高优先级
|
||||
showNotification(NotificationType.NETWORK_LOST, "设备已断开网络连接。", R.drawable.ic_network_lost, 10, NotificationPriority.HIGH);
|
||||
showNotification(NotificationType.NETWORK_LOST, "设备已断开网络连接。", R.drawable.ic_network_lost, 5, NotificationPriority.HIGH);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -12,10 +12,13 @@ import com.ismart.ib86.app.R;
|
||||
/**
|
||||
* 机器人表情动画管理器
|
||||
* 负责加载、控制和切换不同的表情动画
|
||||
* 提供单例模式访问
|
||||
*/
|
||||
public class RobotFaceAnimationManager {
|
||||
// 单例实例
|
||||
private static RobotFaceAnimationManager instance;
|
||||
private static final String TAG = "RobotFaceAnimManager";
|
||||
// 动画类型常量
|
||||
|
||||
public static final int FACE_LOOP_0 = 0; // 循环表情0
|
||||
public static final int FACE_LOOP_1 = 1; // 循环表情1
|
||||
public static final int FACE_LOOP_2 = 2; // 循环表情2
|
||||
@ -26,7 +29,6 @@ public class RobotFaceAnimationManager {
|
||||
|
||||
// 动画资源ID数组
|
||||
private static final int[] FACE_ANIMATIONS = {
|
||||
|
||||
R.drawable.anim_face_xunhuan, // 循环表情0
|
||||
R.drawable.anim_face_xunhuan1, // 循环表情1
|
||||
R.drawable.anim_face_xunhuan2, // 循环表情2
|
||||
@ -66,13 +68,48 @@ public class RobotFaceAnimationManager {
|
||||
this.handler = new Handler(Looper.getMainLooper());
|
||||
}
|
||||
|
||||
private static final String TAG = "RobotFaceAnimManager";
|
||||
/**
|
||||
* 获取单例实例
|
||||
* @param context 上下文
|
||||
* @param imageView 用于显示动画的ImageView
|
||||
* @return RobotFaceAnimationManager 实例
|
||||
*/
|
||||
public static synchronized RobotFaceAnimationManager getInstance(Context context, ImageView imageView) {
|
||||
if (instance == null) {
|
||||
instance = new RobotFaceAnimationManager(context, imageView);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单例实例(需要先调用带参数的getInstance方法初始化)
|
||||
* @return RobotFaceAnimationManager 实例
|
||||
*/
|
||||
public static synchronized RobotFaceAnimationManager getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 加载指定类型的表情动画
|
||||
* @param faceType 表情类型
|
||||
*/
|
||||
/**
|
||||
* 加载指定类型的表情动画
|
||||
* @param faceType 表情类型
|
||||
*/
|
||||
public void loadFaceAnimation(int faceType) {
|
||||
loadFaceAnimation(faceType, true, -1); // 默认循环播放,无限次数
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载指定类型的表情动画
|
||||
* @param faceType 表情类型
|
||||
* @param loop 是否循环播放
|
||||
* @param repeatCount 重复次数,-1表示无限循环
|
||||
*/
|
||||
public void loadFaceAnimation(int faceType, boolean loop, int repeatCount) {
|
||||
if (faceType < 0 || faceType >= FACE_ANIMATIONS.length) {
|
||||
faceType = FACE_LOOP_0;
|
||||
}
|
||||
@ -96,6 +133,9 @@ public class RobotFaceAnimationManager {
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置循环属性
|
||||
currentAnimation.setOneShot(!loop);
|
||||
|
||||
// 应用速度设置
|
||||
// if (speedFactor != 1.0f) {
|
||||
// applySpeed(speedFactor);
|
||||
@ -107,6 +147,11 @@ public class RobotFaceAnimationManager {
|
||||
// 如果不是暂停状态,则开始播放
|
||||
if (!isPaused) {
|
||||
currentAnimation.start();
|
||||
|
||||
// 如果指定了重复次数且不为无限循环,则在指定次数后停止动画
|
||||
if (!loop && repeatCount > 0) {
|
||||
scheduleStopAfterRepeats(repeatCount);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "加载表情动画失败: " + FACE_NAMES[faceType], e);
|
||||
@ -226,6 +271,37 @@ public class RobotFaceAnimationManager {
|
||||
imageView.setImageDrawable(currentAnimation);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定重复次数后停止动画,并随机选择一个循环表情继续播放
|
||||
* @param repeatCount 重复次数
|
||||
*/
|
||||
private void scheduleStopAfterRepeats(int repeatCount) {
|
||||
if (currentAnimation == null) return;
|
||||
|
||||
// 计算总持续时间
|
||||
long totalDuration = 0;
|
||||
int frameCount = currentAnimation.getNumberOfFrames();
|
||||
for (int i = 0; i < frameCount; i++) {
|
||||
totalDuration += currentAnimation.getDuration(i);
|
||||
}
|
||||
|
||||
// 总时间 = 单次播放时间 * 重复次数
|
||||
long delay = totalDuration * repeatCount;
|
||||
|
||||
// 使用Handler在指定时间后停止动画并随机选择循环表情
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (currentAnimation != null && currentAnimation.isRunning()) {
|
||||
currentAnimation.stop();
|
||||
Log.d(TAG, "动画已播放完成指定次数: " + repeatCount);
|
||||
|
||||
loadFaceAnimation(FACE_LOOP_0, true, -1); // 循环播放,无限次数
|
||||
}
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换到下一个表情
|
||||
* @return 新表情的名称
|
||||
@ -310,5 +386,8 @@ public class RobotFaceAnimationManager {
|
||||
context = null;
|
||||
imageView = null;
|
||||
handler = null;
|
||||
|
||||
// 清除单例实例
|
||||
instance = null;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user