menuitem 在15以前可以有string=属性,但在15中去除了string=属性

在Odoo的XML文件解析过程中,出现错误提示表明在Odoo 15版本中,<menuitem>标签的string属性已被移除。此变化影响了菜单项的定义,之前版本中可以使用的string属性在新版本中不再适用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Traceback (most recent call last):
  File "G:\od15\odoo\addons\base\models\ir_http.py", line 237, in _dispatch
    result = request.dispatch()
  File "G:\od15\odoo\http.py", line 694, in dispatch
    result = self._call_function(**self.params)
  File "G:\od15\odoo\http.py", line 365, in _call_function
    return checked_call(self.db, *args, **kwargs)
  File "G:\od15\odoo\service\model.py", line 94, in wrapper
    return f(dbname, *args, **kwargs)
  File "G:\od15\odoo\http.py", line 354, in checked_call
    result = self.endpoint(*a, **kw)
  File "G:\od15\odoo\http.py", line 923, in __call__
    return self.method(*args, **kw)
  File "G:\od15\odoo\http.py", line 541, in response_wrap
    response = f(*args, **kw)
  File "G:\od15\odoo\addons\web\controllers\main.py", line 1339, in call_
#include “menu.h” #include “main.h” // ??GPIO?? #define KEY_UP_PIN GPIO_PIN_2 #define KEY_DOWN_PIN GPIO_PIN_3 #define KEY_ENTER_PIN GPIO_PIN_4 #define KEY_BACK_PIN GPIO_PIN_5 // ??? #define KEY_PORT GPIOE // ??? static void Power_On(void); static void Power_Off(void); static void Set_Voltage_Value(void); static void Set_Current_Value(void); static void Save_Settings(void); static void Factory_Reset(void); // ??? static MenuItem voltageMenuItems[] = { {“Set Voltage”, Set_Voltage_Value, NULL}, {“Back”, Menu_BackToParent, NULL} }; // ??? static MenuItem currentMenuItems[] = { {“Set Current”, Set_Current_Value, NULL}, {“Back”, Menu_BackToParent, NULL} }; // ??? static MenuItem settingsMenuItems[] = { {“Save Settings”, Save_Settings, NULL}, {“Factory Reset”, Factory_Reset, NULL}, {“Back”, Menu_BackToParent, NULL} }; // ??? static MenuItem mainMenuItems[] = { {“Power On”, Power_On, NULL}, {“Power Off”, Power_Off, NULL}, {“Set Voltage”, NULL, &voltageMenu}, {“Set Current”, NULL, &currentMenu}, {“System Settings”, NULL, &settingsMenu} }; // ??? Menu voltageMenu = { .title = “VOLTAGE SETTING”, .items = voltageMenuItems, .count = sizeof(voltageMenuItems)/sizeof(MenuItem), .selected = 0, .parent = &mainMenu }; Menu currentMenu = { .title = “CURRENT SETTING”, .items = currentMenuItems, .count = sizeof(currentMenuItems)/sizeof(MenuItem), .selected = 0, .parent = &mainMenu }; Menu settingsMenu = { .title = “SYSTEM SETTINGS”, .items = settingsMenuItems, .count = sizeof(settingsMenuItems)/sizeof(MenuItem), .selected = 0, .parent = &mainMenu }; Menu mainMenu = { .title = “MAIN MENU”, .items = mainMenuItems, .count = sizeof(mainMenuItems)/sizeof(MenuItem), .selected = 0, .parent = NULL }; // ??? static Menu *currentMenuPtr = &mainMenu; void Menu_Init(void) { // ??? } void Menu_Draw(Menu *menu) { OLED_Clear(); OLED_ShowString((128 - strlen(menu->title)*6)/2, 0, menu->title); for(int i = 0; i < 128; i++) { OLED_ShowChar(i, 1, ‘-’); } uint8_t startIdx = 0; if(menu->selected > 3) { startIdx = menu->selected - 3; } uint8_t endIdx = startIdx + 4; if(endIdx > menu->count) { endIdx = menu->count; } for(uint8_t i = startIdx; i < endIdx; i++) { uint8_t displayLine = i - startIdx + 2; if(i == menu->selected) { OLED_ShowString(0, displayLine, ">"); OLED_ShowString(6, displayLine, menu->items[i].text); } else { OLED_ShowString(6, displayLine, menu->items[i].text); } if(menu->items[i].submenu != NULL) { OLED_ShowString(120, displayLine, ">"); } } // ????? if(menu->count > 4) { uint8_t barHeight = 32 * 4 / menu->count; uint8_t barPos = 32 * menu->selected / menu->count; for(uint8_t i = 0; i < barHeight; i++) { OLED_ShowChar(124, 2 + barPos + i, '|'); } } // ?????? if(menu->parent != NULL) { OLED_ShowString(0, 6, "B:Back"); } } KeyPress Menu_GetKey(void) { static uint8_t last_state = 0; uint8_t current_state = HAL_GPIO_ReadPin(KEY_PORT, KEY_UP_PIN) << 0 | HAL_GPIO_ReadPin(KEY_PORT, KEY_DOWN_PIN) << 1 | HAL_GPIO_ReadPin(KEY_PORT, KEY_ENTER_PIN) << 2 | HAL_GPIO_ReadPin(KEY_PORT, KEY_BACK_PIN) << 3; // ???? if(current_state != last_state) { HAL_Delay(20); current_state = HAL_GPIO_ReadPin(KEY_PORT, KEY_UP_PIN) << 0 | HAL_GPIO_ReadPin(KEY_PORT, KEY_DOWN_PIN) << 1 | HAL_GPIO_ReadPin(KEY_PORT, KEY_ENTER_PIN) << 2 | HAL_GPIO_ReadPin(KEY_PORT, KEY_BACK_PIN) << 3; } last_state = current_state; if(!HAL_GPIO_ReadPin(KEY_PORT, KEY_UP_PIN)) return KEY_UP; if(!HAL_GPIO_ReadPin(KEY_PORT, KEY_DOWN_PIN)) return KEY_DOWN; if(!HAL_GPIO_ReadPin(KEY_PORT, KEY_ENTER_PIN)) return KEY_ENTER; if(!HAL_GPIO_ReadPin(KEY_PORT, KEY_BACK_PIN)) return KEY_BACK; return KEY_NONE; } void Menu_Process(Menu **currentMenu) { KeyPress key = Menu_GetKey(); switch(key) { case KEY_UP: if((*currentMenu)->selected > 0) { (*currentMenu)->selected--; } break; case KEY_DOWN: if((*currentMenu)->selected < (*currentMenu)->count - 1) { (*currentMenu)->selected++; } break; case KEY_ENTER: if((*currentMenu)->items[(*currentMenu)->selected].submenu != NULL) { // ????? *currentMenu = (*currentMenu)->items[(*currentMenu)->selected].submenu; } else if((*currentMenu)->items[(*currentMenu)->selected].action != NULL) { // ??????? (*currentMenu)->items[(*currentMenu)->selected].action(); } break; case KEY_BACK: if((*currentMenu)->parent != NULL) { // ????? *currentMenu = (*currentMenu)->parent; } break; default: break; } } void Menu_EnterSubmenu(Menu *submenu) { currentMenuPtr = submenu; } void Menu_BackToParent(void) { if(currentMenuPtr->parent != NULL) { currentMenuPtr = currentMenuPtr->parent; } } // ??? static void Power_On(void) { OLED_Clear(); OLED_ShowString(20, 2, “Power ON”); OLED_ShowString(10, 4, “Selected”); // ??? // HAL_GPIO_WritePin(POWER_GPIO_Port, POWER_Pin, GPIO_PIN_SET); HAL_Delay(1000); } static void Power_Off(void) { OLED_Clear(); OLED_ShowString(20, 2, “Power OFF”); OLED_ShowString(10, 4, “Selected”); // ??? // HAL_GPIO_WritePin(POWER_GPIO_Port, POWER_Pin, GPIO_PIN_RESET); HAL_Delay(1000); } static void Set_Voltage_Value(void) { static uint16_t voltage = 0; uint8_t exitFlag = 0; OLED_Clear(); OLED_ShowString(20, 0, "SET VOLTAGE"); while(!exitFlag) { char buf[20]; sprintf(buf, "Voltage: %d.%dV", voltage/10, voltage%10); OLED_ShowString(10, 2, buf); OLED_ShowString(10, 4, "UP/DOWN: Adjust"); OLED_ShowString(10, 5, "ENTER: Confirm"); OLED_ShowString(10, 6, "BACK: Cancel"); KeyPress key = Menu_GetKey(); switch(key) { case KEY_UP: if(voltage < 300) voltage += 1; break; case KEY_DOWN: if(voltage > 0) voltage -= 1; break; case KEY_ENTER: // ?????? exitFlag = 1; OLED_ShowString(10, 3, "Setting saved!"); HAL_Delay(1000); break; case KEY_BACK: exitFlag = 1; break; default: break; } HAL_Delay(50); } } static void Set_Current_Value(void) { static uint16_t current = 0; uint8_t exitFlag = 0; OLED_Clear(); OLED_ShowString(20, 0, "SET CURRENT"); while(!exitFlag) { char buf[20]; sprintf(buf, "Current: %d.%dA", current/10, current%10); OLED_ShowString(10, 2, buf); OLED_ShowString(10, 4, "UP/DOWN: Adjust"); OLED_ShowString(10, 5, "ENTER: Confirm"); OLED_ShowString(10, 6, "BACK: Cancel"); KeyPress key = Menu_GetKey(); switch(key) { case KEY_UP: if(current < 50) current += 1; break; case KEY_DOWN: if(current > 0) current -= 1; break; case KEY_ENTER: // ?????? exitFlag = 1; OLED_ShowString(10, 3, "Setting saved!"); HAL_Delay(1000); break; case KEY_BACK: exitFlag = 1; break; default: break; } HAL_Delay(50); } } static void Save_Settings(void) { OLED_Clear(); OLED_ShowString(30, 2, “Saving…”); // ??? HAL_Delay(500); OLED_ShowString(20, 4, “Settings saved!”); HAL_Delay(1000); } static void Factory_Reset(void) { OLED_Clear(); OLED_ShowString(10, 2, “Factory Reset?”); OLED_ShowString(10, 4, “ENTER: Confirm”); OLED_ShowString(10, 5, “BACK: Cancel”); uint8_t exitFlag = 0; while(!exitFlag) { KeyPress key = Menu_GetKey(); switch(key) { case KEY_ENTER: // ???????? OLED_Clear(); OLED_ShowString(20, 3, "Resetting..."); HAL_Delay(1000); // ???????? exitFlag = 1; break; case KEY_BACK: exitFlag = 1; break; default: break; } HAL_Delay(50); } }…\Src\menu.c(89): error: #167: argument of type “const char *” is incompatible with parameter of type “char *” OLED_ShowString((128 - strlen(menu->title)*6)/2, 0, menu->title); …\Src\menu.c(108): error: #167: argument of type “const char *” is incompatible with parameter of type “char *” OLED_ShowString(6, displayLine, menu->items[i].text); …\Src\menu.c(110): error: #167: argument of type “const char *” is incompatible with parameter of type “char *” OLED_ShowString(6, displayLine, menu->items[i].text);帮我修改一下,然后输出完整的代码
07-11
#include "menu.h" #include "main.h" // ??GPIO?? #define KEY_UP_PIN GPIO_PIN_2 #define KEY_DOWN_PIN GPIO_PIN_3 #define KEY_ENTER_PIN GPIO_PIN_4 #define KEY_BACK_PIN GPIO_PIN_5 // ?????? #define KEY_PORT GPIOE // ???????? static void Power_On(void); static void Power_Off(void); static void Set_Voltage_Value(void); static void Set_Current_Value(void); static void Save_Settings(void); static void Factory_Reset(void); // ???????? static MenuItem voltageMenuItems[] = { {"Set Voltage", Set_Voltage_Value, NULL}, {"Back", Menu_BackToParent, NULL} }; // ???????? static MenuItem currentMenuItems[] = { {"Set Current", Set_Current_Value, NULL}, {"Back", Menu_BackToParent, NULL} }; // ???????? static MenuItem settingsMenuItems[] = { {"Save Settings", Save_Settings, NULL}, {"Factory Reset", Factory_Reset, NULL}, {"Back", Menu_BackToParent, NULL} }; // ???? static MenuItem mainMenuItems[] = { {"Power On", Power_On, NULL}, {"Power Off", Power_Off, NULL}, {"Set Voltage", NULL, &voltageMenu}, {"Set Current", NULL, &currentMenu}, {"System Settings", NULL, &settingsMenu} }; // ???? Menu voltageMenu = { .title = "VOLTAGE SETTING", .items = voltageMenuItems, .count = sizeof(voltageMenuItems)/sizeof(MenuItem), .selected = 0, .parent = &mainMenu }; Menu currentMenu = { .title = "CURRENT SETTING", .items = currentMenuItems, .count = sizeof(currentMenuItems)/sizeof(MenuItem), .selected = 0, .parent = &mainMenu }; Menu settingsMenu = { .title = "SYSTEM SETTINGS", .items = settingsMenuItems, .count = sizeof(settingsMenuItems)/sizeof(MenuItem), .selected = 0, .parent = &mainMenu }; Menu mainMenu = { .title = "MAIN MENU", .items = mainMenuItems, .count = sizeof(mainMenuItems)/sizeof(MenuItem), .selected = 0, .parent = NULL }; // ?????? static Menu *currentMenuPtr = &mainMenu; void Menu_Init(void) { // ??????????? } void Menu_Draw(Menu *menu) { OLED_Clear(); OLED_ShowString((128 - strlen(menu->title)*6)/2, 0, menu->title); for(int i = 0; i < 128; i++) { OLED_ShowChar(i, 1, '-'); } uint8_t startIdx = 0; if(menu->selected > 3) { startIdx = menu->selected - 3; } uint8_t endIdx = startIdx + 4; if(endIdx > menu->count) { endIdx = menu->count; } for(uint8_t i = startIdx; i < endIdx; i++) { uint8_t displayLine = i - startIdx + 2; if(i == menu->selected) { OLED_ShowString(0, displayLine, ">"); OLED_ShowString(6, displayLine, menu->items[i].text); } else { OLED_ShowString(6, displayLine, menu->items[i].text); } if(menu->items[i].submenu != NULL) { OLED_ShowString(120, displayLine, ">"); } } // ????? if(menu->count > 4) { uint8_t barHeight = 32 * 4 / menu->count; uint8_t barPos = 32 * menu->selected / menu->count; for(uint8_t i = 0; i < barHeight; i++) { OLED_ShowChar(124, 2 + barPos + i, '|'); } } // ?????? if(menu->parent != NULL) { OLED_ShowString(0, 6, "B:Back"); } } KeyPress Menu_GetKey(void) { static uint8_t last_state = 0; uint8_t current_state = HAL_GPIO_ReadPin(KEY_PORT, KEY_UP_PIN) << 0 | HAL_GPIO_ReadPin(KEY_PORT, KEY_DOWN_PIN) << 1 | HAL_GPIO_ReadPin(KEY_PORT, KEY_ENTER_PIN) << 2 | HAL_GPIO_ReadPin(KEY_PORT, KEY_BACK_PIN) << 3; // ???? if(current_state != last_state) { HAL_Delay(20); current_state = HAL_GPIO_ReadPin(KEY_PORT, KEY_UP_PIN) << 0 | HAL_GPIO_ReadPin(KEY_PORT, KEY_DOWN_PIN) << 1 | HAL_GPIO_ReadPin(KEY_PORT, KEY_ENTER_PIN) << 2 | HAL_GPIO_ReadPin(KEY_PORT, KEY_BACK_PIN) << 3; } last_state = current_state; if(!HAL_GPIO_ReadPin(KEY_PORT, KEY_UP_PIN)) return KEY_UP; if(!HAL_GPIO_ReadPin(KEY_PORT, KEY_DOWN_PIN)) return KEY_DOWN; if(!HAL_GPIO_ReadPin(KEY_PORT, KEY_ENTER_PIN)) return KEY_ENTER; if(!HAL_GPIO_ReadPin(KEY_PORT, KEY_BACK_PIN)) return KEY_BACK; return KEY_NONE; } void Menu_Process(Menu **currentMenu) { KeyPress key = Menu_GetKey(); switch(key) { case KEY_UP: if((*currentMenu)->selected > 0) { (*currentMenu)->selected--; } break; case KEY_DOWN: if((*currentMenu)->selected < (*currentMenu)->count - 1) { (*currentMenu)->selected++; } break; case KEY_ENTER: if((*currentMenu)->items[(*currentMenu)->selected].submenu != NULL) { // ????? *currentMenu = (*currentMenu)->items[(*currentMenu)->selected].submenu; } else if((*currentMenu)->items[(*currentMenu)->selected].action != NULL) { // ??????? (*currentMenu)->items[(*currentMenu)->selected].action(); } break; case KEY_BACK: if((*currentMenu)->parent != NULL) { // ????? *currentMenu = (*currentMenu)->parent; } break; default: break; } } void Menu_EnterSubmenu(Menu *submenu) { currentMenuPtr = submenu; } void Menu_BackToParent(void) { if(currentMenuPtr->parent != NULL) { currentMenuPtr = currentMenuPtr->parent; } } // ???????? static void Power_On(void) { OLED_Clear(); OLED_ShowString(20, 2, "Power ON"); OLED_ShowString(10, 4, "Selected"); // ???????? // HAL_GPIO_WritePin(POWER_GPIO_Port, POWER_Pin, GPIO_PIN_SET); HAL_Delay(1000); } static void Power_Off(void) { OLED_Clear(); OLED_ShowString(20, 2, "Power OFF"); OLED_ShowString(10, 4, "Selected"); // ???????? // HAL_GPIO_WritePin(POWER_GPIO_Port, POWER_Pin, GPIO_PIN_RESET); HAL_Delay(1000); } static void Set_Voltage_Value(void) { static uint16_t voltage = 0; uint8_t exitFlag = 0; OLED_Clear(); OLED_ShowString(20, 0, "SET VOLTAGE"); while(!exitFlag) { char buf[20]; sprintf(buf, "Voltage: %d.%dV", voltage/10, voltage%10); OLED_ShowString(10, 2, buf); OLED_ShowString(10, 4, "UP/DOWN: Adjust"); OLED_ShowString(10, 5, "ENTER: Confirm"); OLED_ShowString(10, 6, "BACK: Cancel"); KeyPress key = Menu_GetKey(); switch(key) { case KEY_UP: if(voltage < 300) voltage += 1; break; case KEY_DOWN: if(voltage > 0) voltage -= 1; break; case KEY_ENTER: // ?????? exitFlag = 1; OLED_ShowString(10, 3, "Setting saved!"); HAL_Delay(1000); break; case KEY_BACK: exitFlag = 1; break; default: break; } HAL_Delay(50); } } static void Set_Current_Value(void) { static uint16_t current = 0; uint8_t exitFlag = 0; OLED_Clear(); OLED_ShowString(20, 0, "SET CURRENT"); while(!exitFlag) { char buf[20]; sprintf(buf, "Current: %d.%dA", current/10, current%10); OLED_ShowString(10, 2, buf); OLED_ShowString(10, 4, "UP/DOWN: Adjust"); OLED_ShowString(10, 5, "ENTER: Confirm"); OLED_ShowString(10, 6, "BACK: Cancel"); KeyPress key = Menu_GetKey(); switch(key) { case KEY_UP: if(current < 50) current += 1; break; case KEY_DOWN: if(current > 0) current -= 1; break; case KEY_ENTER: // ?????? exitFlag = 1; OLED_ShowString(10, 3, "Setting saved!"); HAL_Delay(1000); break; case KEY_BACK: exitFlag = 1; break; default: break; } HAL_Delay(50); } } static void Save_Settings(void) { OLED_Clear(); OLED_ShowString(30, 2, "Saving..."); // ???????? HAL_Delay(500); OLED_ShowString(20, 4, "Settings saved!"); HAL_Delay(1000); } static void Factory_Reset(void) { OLED_Clear(); OLED_ShowString(10, 2, "Factory Reset?"); OLED_ShowString(10, 4, "ENTER: Confirm"); OLED_ShowString(10, 5, "BACK: Cancel"); uint8_t exitFlag = 0; while(!exitFlag) { KeyPress key = Menu_GetKey(); switch(key) { case KEY_ENTER: // ???????? OLED_Clear(); OLED_ShowString(20, 3, "Resetting..."); HAL_Delay(1000); // ???????? exitFlag = 1; break; case KEY_BACK: exitFlag = 1; break; default: break; } HAL_Delay(50); } }..\Src\menu.c(89): error: #167: argument of type "const char *" is incompatible with parameter of type "char *" OLED_ShowString((128 - strlen(menu->title)*6)/2, 0, menu->title); ..\Src\menu.c(108): error: #167: argument of type "const char *" is incompatible with parameter of type "char *" OLED_ShowString(6, displayLine, menu->items[i].text); ..\Src\menu.c(110): error: #167: argument of type "const char *" is incompatible with parameter of type "char *" OLED_ShowString(6, displayLine, menu->items[i].text);
07-11
build.gradle(app):apply plugin: 'com.android.application' android { compileSdkVersion 28 defaultConfig { applicationId "com.hik.netsdk.SimpleDemo" minSdkVersion 15 targetSdkVersion 28 versionCode 11 versionName "3.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true multiDexEnabled true ndk { abiFilters "armeabi-v7a","arm64-v8a" } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets { main { res.srcDirs = [ 'src/main/res', 'src/main/res/layout/DevMgtUI', 'src/main/res/layout/BusinessUI' ] jniLibs.srcDirs = ['libs'] } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } buildToolsVersion = '28.0.3' } dependencies { implementation files('libs/HCNetSDK.jar') implementation files('libs/PlayerSDK_hcnetsdk.jar') implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.squareup.okhttp3:okhttp:4.9.1' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.5.0' // 替代 design implementation 'androidx.constraintlayout:constraintlayout:2.1.3' implementation 'androidx.legacy:legacy-support-v4:1.0.0' // 替代 support-v4 testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.4.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' implementation 'io.github.ezviz-open:ezviz-sdk:5.20' // implementation 'com.ezviz:sdk:4.19.5' compile 'com.ezviz.sdk:ezuikit:2.2.1' implementation files('libs/PlayerSDK.jar') implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) implementation files('libs/ERTC_Android_SDK_1.5.0.1.aar') // 添加必要支持库 implementation 'com.squareup.okhttp3:okhttp:3.12.1' implementation 'com.google.code.gson:gson:2.8.5' // 海康SDK - 确保已添加 implementation files('libs/hikvision-sdk.jar') implementation "androidx.media3:media3-exoplayer:1.3.1" implementation "androidx.media3:media3-exoplayer-hls:1.3.1" implementation "androidx.media3:media3-ui:1.3.1" implementation "androidx.media3:media3-datasource-okhttp:1.3.1" // 确保添加了基础库 implementation "androidx.media3:media3-common:1.3.1" } build.gradle(project):// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'https://maven.aliyun.com/repository/jcenter' } maven { url 'https://maven.aliyun.com/repository/public' } // 其他仓库 jcenter() maven { url 'https://jitpack.io' } mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:3.4.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { // 添加 Google Maven 仓库 google() // 保留现有仓库 jcenter() maven { url 'https://jitpack.io' } maven { url 'https://www.jitpack.io' } maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'https://maven.aliyun.com/repository/jcenter' } maven { url 'https://maven.aliyun.com/repository/public' } flatDir { dirs 'app/libs' // 指定 aar 文件位置 } } } task clean(type: Delete) { delete rootProject.buildDir } MainActivity:package com.hik.netsdk.SimpleDemo.View; import android.app.AlertDialog; import android.content.Intent; import android.graphics.PixelFormat; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.ImageButton; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; // AndroidX Media3 导入 import androidx.media3.common.MediaItem; import androidx.media3.common.Player; import androidx.media3.common.PlaybackException; import androidx.media3.datasource.DataSource; import androidx.media3.datasource.DefaultHttpDataSource; import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.hls.HlsMediaSource; import androidx.media3.exoplayer.source.MediaSource; import com.hik.netsdk.SimpleDemo.R; import com.hik.netsdk.SimpleDemo.View.DevMgtUI.AddDevActivity; import com.videogo.openapi.EZConstants; import com.videogo.openapi.EZOpenSDK; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.util.concurrent.TimeUnit; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback { // 核心参数 private String mDeviceSerial; private String mVerifyCode; private int mCameraNo = 1; private boolean isEzDevice = false; // 萤石云相关参数 private String mAppKey = "a794d58c13154caeb7d2fbb5c3420c65"; private String mAccessToken = ""; // UI组件 private SurfaceView mPreviewSurface; private SurfaceHolder mSurfaceHolder; private Toolbar m_toolbar; private ProgressBar mProgressBar; private RelativeLayout mControlLayout; private ImageButton mRotateButton; // 播放器相关 private ExoPlayer mExoPlayer; private String mPlaybackUrl; private final OkHttpClient mHttpClient = new OkHttpClient.Builder() .connectTimeout(15, TimeUnit.SECONDS) .readTimeout(15, TimeUnit.SECONDS) .build(); // 播放器状态监听器 private final Player.Listener mPlayerListener = new Player.Listener() { @Override public void onPlaybackStateChanged(int state) { switch (state) { case Player.STATE_READY: mProgressBar.setVisibility(View.GONE); Log.d("ExoPlayer", "播放准备就绪"); break; case Player.STATE_BUFFERING: mProgressBar.setVisibility(View.VISIBLE); Log.d("ExoPlayer", "缓冲中..."); break; case Player.STATE_ENDED: Log.d("ExoPlayer", "播放结束"); break; case Player.STATE_IDLE: Log.d("ExoPlayer", "空闲状态"); break; } } @Override public void onPlayerError(PlaybackException error) { // 使用正确的异常类型 Log.e("ExoPlayer", "播放错误: " + error.getMessage()); handleError("播放错误: " + error.getMessage(), -1); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化UI组件 initUIComponents(); // 获取启动参数 parseIntentParams(); // 初始化SDK initSDK(); // 参数校验 if (mDeviceSerial == null || mDeviceSerial.isEmpty()) { showErrorAndFinish("设备序列号不能为空"); return; } Log.d("MainActivity", "onCreate完成: isEzDevice=" + isEzDevice); } private void initUIComponents() { // 基础UI m_toolbar = findViewById(R.id.toolbar); setSupportActionBar(m_toolbar); // 预览相关UI mPreviewSurface = findViewById(R.id.realplay_sv); mSurfaceHolder = mPreviewSurface.getHolder(); mSurfaceHolder.addCallback(this); mSurfaceHolder.setFormat(PixelFormat.TRANSLUCENT); mProgressBar = findViewById(R.id.liveProgressBar); mControlLayout = findViewById(R.id.rl_control); mRotateButton = findViewById(R.id.ib_rotate2); // 设置旋转按钮点击事件 mRotateButton.setOnClickListener(v -> changeScreen()); // 隐藏管理UI DrawerLayout drawer = findViewById(R.id.drawer_layout); if (drawer != null) { drawer.setVisibility(View.GONE); } if (m_toolbar != null) { m_toolbar.setVisibility(View.GONE); } // 初始化控制按钮 initControlButtons(); Log.d("UI", "UI组件初始化完成"); } private void parseIntentParams() { // 获取Intent参数 Intent intent = getIntent(); isEzDevice = true; // 只支持萤石设备 mAccessToken = intent.getStringExtra("accessToken"); // 优先使用bundle Bundle bundle = intent.getExtras(); if (bundle != null) { mDeviceSerial = bundle.getString("devSn"); mVerifyCode = bundle.getString("verifyCode"); mCameraNo = bundle.getInt("cameraNo", 1); } // 兼容直接Extra方式 if (mDeviceSerial == null) mDeviceSerial = intent.getStringExtra("devSn"); if (mVerifyCode == null) mVerifyCode = intent.getStringExtra("verifyCode"); if (mCameraNo == 0) mCameraNo = intent.getIntExtra("cameraNo", 1); Log.d("Params", "设备序列号: " + mDeviceSerial + ", 通道号: " + mCameraNo); } private void initSDK() { try { // 使用反射检查初始化状态 boolean isInitialized = false; try { // 尝试获取实例 EZOpenSDK instance = EZOpenSDK.getInstance(); if (instance != null) { isInitialized = true; } } catch (Exception e) { // 捕获未初始化的异常 isInitialized = false; } // 未初始化时进行初始化 if (!isInitialized) { EZOpenSDK.initLib(getApplication(), mAppKey); Log.d("EZSDK", "萤石SDK初始化完成"); } // 设置AccessToken if (mAccessToken != null && !mAccessToken.isEmpty()) { EZOpenSDK.getInstance().setAccessToken(mAccessToken); Log.d("EZToken", "AccessToken设置成功"); } else { Log.w("EZToken", "AccessToken缺失!"); } } catch (Exception e) { Log.e("EZSDK", "萤石SDK初始化失败", e); handleError("萤石SDK初始化失败: " + e.getMessage(), -1); } } private void initControlButtons() { // 云台控制按钮 findViewById(R.id.ptz_top_btn).setOnClickListener(v -> controlPTZ("UP")); findViewById(R.id.ptz_bottom_btn).setOnClickListener(v -> controlPTZ("DOWN")); findViewById(R.id.ptz_left_btn).setOnClickListener(v -> controlPTZ("LEFT")); findViewById(R.id.ptz_right_btn).setOnClickListener(v -> controlPTZ("RIGHT")); // 变焦控制 findViewById(R.id.focus_add).setOnClickListener(v -> controlZoom("ZOOM_IN")); findViewById(R.id.foucus_reduce).setOnClickListener(v -> controlZoom("ZOOM_OUT")); // 水平布局控制按钮 findViewById(R.id.ptz_top_btn2).setOnClickListener(v -> controlPTZ("UP")); findViewById(R.id.ptz_bottom_btn2).setOnClickListener(v -> controlPTZ("DOWN")); findViewById(R.id.ptz_left_btn2).setOnClickListener(v -> controlPTZ("LEFT")); findViewById(R.id.ptz_right_btn2).setOnClickListener(v -> controlPTZ("RIGHT")); // 添加萤石云特有功能按钮 // findViewById(R.id.btn_record).setOnClickListener(v -> startLocalRecord()); // findViewById(R.id.btn_stop_record).setOnClickListener(v -> stopLocalRecord()); // findViewById(R.id.btn_capture).setOnClickListener(v -> capturePicture()); Log.d("Controls", "控制按钮初始化完成"); } @Override public void surfaceCreated(SurfaceHolder holder) { Log.d("Surface", "Surface created"); // 获取播放地址并开始播放 new Thread(this::fetchPlaybackUrl).start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.d("Surface", "Surface changed: " + width + "x" + height); if (mExoPlayer != null) { mExoPlayer.setVideoSurfaceHolder(holder); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.d("Surface", "Surface destroyed"); stopPreview(); } // ======================== 播放地址获取与播放 ======================== private void fetchPlaybackUrl() { try { // 构建请求参数 JSONObject params = new JSONObject(); params.put("accessToken", mAccessToken); params.put("deviceSerial", mDeviceSerial); params.put("channelNo", mCameraNo); params.put("protocol", 2); // 使用HLS协议 if (mVerifyCode != null && !mVerifyCode.isEmpty()) { params.put("code", mVerifyCode); } params.put("expireTime", 7200); // 2小时有效期 // 创建请求体 RequestBody body = RequestBody.create( MediaType.parse("application/json"), params.toString() ); // 创建请求 Request request = new Request.Builder() .url("https://open.ys7.com/api/lapp/v2/live/address/get") .post(body) .build(); // 执行请求 try (Response response = mHttpClient.newCall(request).execute()) { if (!response.isSuccessful()) { handleError("获取播放地址失败: " + response.code(), response.code()); return; } // 解析响应 String responseBody = response.body().string(); JSONObject json = new JSONObject(responseBody); if ("200".equals(json.getString("code"))) { JSONObject data = json.getJSONObject("data"); mPlaybackUrl = data.getString("url"); Log.d("PlaybackURL", "获取到播放地址: " + mPlaybackUrl); // 在主线程初始化播放器 runOnUiThread(this::initExoPlayer); } else { handleError("API错误: " + json.getString("msg"), json.getInt("code")); } } } catch (JSONException | IOException e) { Log.e("FetchURL", "获取播放地址异常", e); handleError("获取播放地址异常: " + e.getMessage(), -1); } } private void initExoPlayer() { // 释放现有播放器 if (mExoPlayer != null) { mExoPlayer.release(); } // 使用正确的 Builder 创建播放器 mExoPlayer = new ExoPlayer.Builder(this).build(); mExoPlayer.addListener(mPlayerListener); // 设置视频渲染器 mExoPlayer.setVideoSurfaceHolder(mSurfaceHolder); // 创建媒体源 DataSource.Factory dataSourceFactory = new DefaultHttpDataSource.Factory(); MediaSource mediaSource = new HlsMediaSource.Factory(dataSourceFactory) .createMediaSource(MediaItem.fromUri(Uri.parse(mPlaybackUrl))); // 准备播放 mExoPlayer.setMediaSource(mediaSource); mExoPlayer.prepare(); mExoPlayer.setPlayWhenReady(true); mProgressBar.setVisibility(View.VISIBLE); Log.d("ExoPlayer", "播放器初始化完成,开始播放"); } // ======================== 萤石云控制方法 ======================== private int mapDirection(String direction) { switch (direction) { // case "UP": return EZCloudControl.DIRECTION_UP; // case "DOWN": return EZCloudControl.DIRECTION_DOWN; // case "LEFT": return EZCloudControl.DIRECTION_LEFT; // case "RIGHT": return EZCloudControl.DIRECTION_RIGHT; // case "ZOOM_IN": return EZCloudControl.DIRECTION_ZOOM_IN; // case "ZOOM_OUT": return EZCloudControl.DIRECTION_ZOOM_OUT; default: return -1; } } // 修改控制方法 private void controlPTZ(String direction) { int directionCode = mapDirection(direction); if (directionCode == -1) return; // 开始控制 // EZCloudControl.startPTZControl( // mAccessToken, // mDeviceSerial, // mCameraNo, // directionCode, // EZCloudControl.SPEED_MEDIUM, // 中等速度 // new EZCloudControl.ControlCallback() { // @Override // public void onSuccess(String response) { // Log.d("PTZControl", "开始云台控制成功: " + direction); // // // 300ms后停止控制 // new Handler(Looper.getMainLooper()).postDelayed(() -> { // stopPTZControl(directionCode); // }, 300); // } // // @Override // public void onFailure(String error) { // Log.e("PTZControl", "开始云台控制失败: " + error); // handleError("云台控制失败: " + error, -1); // } // }); } // private void stopPTZControl(int directionCode) { // EZCloudControl.stopPTZControl( // mAccessToken, // mDeviceSerial, // mCameraNo, // directionCode, // new EZCloudControl.ControlCallback() { // @Override // public void onSuccess(String response) { // Log.d("PTZControl", "停止云台控制成功"); // } // // @Override // public void onFailure(String error) { // Log.e("PTZControl", "停止云台控制失败: " + error); // // 可选择重试或其他处理 // } // }); // } private void controlZoom(String command) { String direction = "ZOOM_IN".equals(command) ? "ZOOM_IN" : "ZOOM_OUT"; controlPTZ(direction); } // ======================== 萤石云扩展功能 ======================== // 开始本地录像 private void startLocalRecord() { // 这里需要根据实际需求实现 Toast.makeText(this, "开始录像", Toast.LENGTH_SHORT).show(); } // 停止本地录像 private void stopLocalRecord() { // 这里需要根据实际需求实现 Toast.makeText(this, "停止录像", Toast.LENGTH_SHORT).show(); } // 截图 private void capturePicture() { // 这里需要根据实际需求实现 Toast.makeText(this, "截图已保存", Toast.LENGTH_SHORT).show(); } // ======================== 通用功能方法 ======================== public void changeScreen(View view) { changeScreen(); } private void changeScreen() { if (mControlLayout.getVisibility() == View.VISIBLE) { mControlLayout.setVisibility(View.GONE); } else { mControlLayout.setVisibility(View.VISIBLE); } } private void handleError(String message, int errorCode) { String fullMessage = message + " (错误码: " + errorCode + ")"; // 萤石云特有错误码处理 switch (errorCode) { case 400001: fullMessage = "AccessToken无效"; break; case 400002: fullMessage = "设备不存在"; break; case 400007: fullMessage = "设备不在线"; break; case 400034: fullMessage = "验证码错误"; break; case 400035: fullMessage = "设备已被自己添加"; break; case 400036: fullMessage = "设备已被别人添加"; break; default: fullMessage = "萤石云错误: " + errorCode; } new AlertDialog.Builder(this) .setTitle("预览失败") .setMessage(fullMessage) .setPositiveButton("确定", (d, w) -> finish()) .setCancelable(false) .show(); } private void showErrorAndFinish(String message) { Toast.makeText(this, message, Toast.LENGTH_LONG).show(); new Handler().postDelayed(this::finish, 3000); } private void stopPreview() { if (mExoPlayer != null) { mExoPlayer.release(); mExoPlayer = null; Log.d("Preview", "预览已停止"); } } @Override protected void onDestroy() { super.onDestroy(); stopPreview(); Log.d("Lifecycle", "onDestroy"); } @Override protected void onPause() { super.onPause(); if (mExoPlayer != null) { mExoPlayer.setPlayWhenReady(false); Log.d("Lifecycle", "暂停播放"); } } @Override protected void onResume() { super.onResume(); if (mExoPlayer != null) { mExoPlayer.setPlayWhenReady(true); Log.d("Lifecycle", "恢复播放"); } } @Override public void onBackPressed() { DrawerLayout drawer = findViewById(R.id.drawer_layout); if (drawer != null && drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); } else { super.onBackPressed(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main_opt, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.action_1) { startActivity(new Intent(this, AddDevActivity.class)); return true; } return super.onOptionsItemSelected(item); } } 依据上述依赖和代码解决下面5个报错:Cannot resolve symbol 'MediaType' Cannot resolve symbol 'OkHttpClient' Cannot resolve symbol 'Request' Cannot resolve symbol 'RequestBody' Cannot resolve symbol 'Response'
06-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信息化未来

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值