最新版(航线保存,航线执行,投弹,设置-载荷,安全,遥控器..页面基本完成)

This commit is contained in:
cuijingzhou 2025-09-03 15:53:49 +08:00
parent 0a346baa01
commit d9ea281387
95 changed files with 10729 additions and 1536 deletions

View File

@ -4,10 +4,10 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-06-27T06:06:37.137599900Z">
<DropdownSelection timestamp="2025-08-18T01:38:39.489587200Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=235cb949" />
<DeviceId pluginId="PhysicalDevice" identifier="serial=3571a890" />
</handle>
</Target>
</DropdownSelection>

View File

@ -69,6 +69,9 @@ dependencies {
implementation files("libs/rcsdk-v1.2.1.aar")
implementation files("libs/isoparser-1.1.9.jar")//H264封装为MP4
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
implementation 'com.squareup.okio:okio:3.2.0'
// implementation 'com.github.licheedev.Android-SerialPort-API:serialport:2.0.0'

View File

@ -18,30 +18,26 @@
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:hardwareAccelerated="true"
android:icon="@mipmap/logo"
android:label="LYUAV"
android:roundIcon="@mipmap/logo"
android:supportsRtl="true"
android:theme="@style/Theme.LongYiGroundStation"
tools:targetApi="31"
android:hardwareAccelerated="true">
tools:targetApi="31">
<activity
android:name=".Main.Activity.PlayBackActivity"
android:exported="false" />
<activity
android:name=".Funcation.Activity.FuncationActivity"
android:exported="true" >
</activity>
android:exported="true"></activity>
<activity
android:name=".Main.Setting.Activity.SettingActivity"
android:exported="true" >
</activity>
android:exported="true"></activity>
<activity
android:name=".MainActivity2"
android:exported="true"></activity>
android:exported="true"
android:screenOrientation="landscape"></activity>
<meta-data
android:name="com.amap.api.v2.apikey"
@ -52,13 +48,11 @@
android:name=".Login.Activity.LoginActivity"
android:exported="true"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".Main.Activity.MainActivity"

View File

@ -75,6 +75,7 @@ public class FuncationActivity extends AppCompatActivity {
intents.putExtra("port", intent.getStringExtra("port"));
}
startActivity(intents);
finish();
});
}

View File

@ -12,6 +12,9 @@ import com.example.longyi_groundstation.MAVLink.Messages.MAVLinkPayload;
import com.example.longyi_groundstation.MAVLink.Messages.Units;
import com.example.longyi_groundstation.MAVLink.Messages.Description;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Reports the current commanded attitude of the vehicle as specified by the autopilot. This should match the commands sent in a SET_ATTITUDE_TARGET message if the vehicle is being controlled this way.
*/
@ -189,7 +192,37 @@ public class msg_attitude_target extends MAVLinkMessage {
*/
@Override
public String toString() {
return "MAVLINK_MSG_ID_ATTITUDE_TARGET - sysid:"+sysid+" compid:"+compid+" time_boot_ms:"+time_boot_ms+" q:"+q+" body_roll_rate:"+body_roll_rate+" body_pitch_rate:"+body_pitch_rate+" body_yaw_rate:"+body_yaw_rate+" thrust:"+thrust+" type_mask:"+type_mask+"";
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("msgid",MAVLINK_MSG_ID_ATTITUDE_TARGET);
jsonObject.put("sysid",sysid);
jsonObject.put("compid",compid);
jsonObject.put("time_boot_ms",time_boot_ms);
jsonObject.put("q",q);
jsonObject.put("body_roll_rate",body_roll_rate);
jsonObject.put("body_pitch_rate",body_pitch_rate);
jsonObject.put("body_yaw_rate",body_yaw_rate);
jsonObject.put("thrust",thrust);
jsonObject.put("type_mask",type_mask);
return jsonObject.toString();
} catch (JSONException e) {
return null;
}
// return "MAVLINK_MSG_ID_ATTITUDE_TARGET - sysid:"+
// sysid+" compid:"+
// compid+" time_boot_ms:"+
// time_boot_ms+" q:"+
// q+" body_roll_rate:"+
// body_roll_rate+" body_pitch_rate:"+
// body_pitch_rate+" body_yaw_rate:"+
// body_yaw_rate+" thrust:"+
// thrust+" type_mask:"+
// type_mask+"";
}
/**

View File

@ -0,0 +1,87 @@
package com.example.longyi_groundstation.Main.Activity;
import android.os.Bundle;
import android.util.Log;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.example.longyi_groundstation.Main.View.CustomSeekBar;
import com.example.longyi_groundstation.Main.Void.MyTool;
import com.example.longyi_groundstation.R;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class PlayBackActivity extends AppCompatActivity {
// 在类成员变量中添加
private CustomSeekBar customSeekBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_play_back);
MyTool.hideBottomNavigationBar(this);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
initData();
initView();
initOnClick();
}
/**
* 方法初始化数据
*
* @cuijingzhou
*/
private void initData() {
}
/**
* 方法初始化视图
*
* @cuijingzhou
*/
private void initView() {
// 初始化自定义进度条
customSeekBar = findViewById(R.id.custom_seekbar);
// 设置默认进度例如50%
customSeekBar.setProgress(0.5f);
}
/**
* 方法初始化点击事件
*
* @cuijingzhou
*/
private void initOnClick() {
// 设置进度变化监听器
customSeekBar.setOnProgressChangeListener(new CustomSeekBar.OnProgressChangeListener() {
@Override
public void onProgressChanged(float progress) {
// 这里可以获取到保留两位小数的进度值
// 例如如果进度是0.1099会显示为10.99%
BigDecimal bd = new BigDecimal(progress * 100);
bd = bd.setScale(2, RoundingMode.HALF_UP);
String progressText = bd.toString() + "%";
// 可以在这里处理进度变化的逻辑
Log.d("CustomSeekBar", "Progress: " + progressText);
}
});
}
}

View File

@ -0,0 +1,150 @@
package com.example.longyi_groundstation.Main.Adapter;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.longyi_groundstation.Main.Base.CreateLink;
import com.example.longyi_groundstation.Main.Void.SQLClass;
import com.example.longyi_groundstation.R;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class AllLinkAdapter extends RecyclerView.Adapter<AllLinkAdapter.AllLinkViewHolder> {
private static final String TAG = "AllLinkAdapter";
private Context context;
private List<SQLClass.LinkListInfo> linkListInfoList;
private SQLClass sqlClass;
private OnItemClickListener onItemClickListener;
public AllLinkAdapter(Context context, List<SQLClass.LinkListInfo> linkListInfoList, SQLClass sqlClass) {
this.context = context;
this.linkListInfoList = linkListInfoList;
this.sqlClass = sqlClass;
}
@NonNull
@Override
public AllLinkViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_all_link_item, parent, false);
return new AllLinkViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull AllLinkViewHolder holder, int position) {
SQLClass.LinkListInfo linkListInfo = linkListInfoList.get(position);
// 显示航线名称
holder.tv_title.setText(linkListInfo.getListName());
// 显示创建时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
String createTime = sdf.format(new Date(linkListInfo.getCreatedTime()));
holder.tv_time.setText(createTime);
// 获取点位数量
ArrayList<CreateLink> createLinkList = sqlClass.getCreateLinkList(linkListInfo.getListId());
int waypointCount = (createLinkList != null) ? createLinkList.size() : 0;
holder.tv_number.setText( waypointCount+"");
// 设置删除按钮点击事件
holder.tv_del.setOnClickListener(v -> {
deleteLinkList(position);
List<SQLClass.LinkListInfo> updatedList = sqlClass.getAllLinkListInfo();
updateDataList(updatedList);
});
// 设置整个item的点击事件
holder.itemView.setOnClickListener(v -> {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(linkListInfo.getListId(), position);
}
});
}
@Override
public int getItemCount() {
return linkListInfoList != null ? linkListInfoList.size() : 0;
}
/**
* 删除指定位置的航线列表
* @param position 要删除的位置
*/
private void deleteLinkList(int position) {
if (position < 0 || position >= linkListInfoList.size()) {
return;
}
SQLClass.LinkListInfo linkListInfo = linkListInfoList.get(position);
int listId = linkListInfo.getListId();
// 从数据库中删除
boolean isDeleted = sqlClass.deleteCreateLinkList(listId);
if (isDeleted) {
// 从列表中移除
linkListInfoList.remove(position);
// 通知适配器数据已更改
notifyItemRemoved(position);
notifyItemRangeChanged(position, linkListInfoList.size());
Toast.makeText(context, "航线删除成功", Toast.LENGTH_SHORT).show();
} else {
Log.e(TAG, "删除航线失败列表ID: " + listId);
Toast.makeText(context, "航线删除失败", Toast.LENGTH_SHORT).show();
}
}
/**
* 更新数据列表
* @param newLinkListInfoList 新的数据列表
*/
public void updateDataList(List<SQLClass.LinkListInfo> newLinkListInfoList) {
this.linkListInfoList = newLinkListInfoList;
notifyDataSetChanged();
}
/**
* 设置item点击监听器
* @param listener 监听器
*/
public void setOnItemClickListener(OnItemClickListener listener) {
this.onItemClickListener = listener;
}
static class AllLinkViewHolder extends RecyclerView.ViewHolder {
TextView tv_title;
TextView tv_time;
TextView tv_number;
TextView tv_del;
public AllLinkViewHolder(@NonNull View itemView) {
super(itemView);
tv_title = itemView.findViewById(R.id.tv_title);
tv_time = itemView.findViewById(R.id.tv_time);
tv_number = itemView.findViewById(R.id.tv_number);
tv_del = itemView.findViewById(R.id.tv_del);
}
}
/**
* Item点击监听器接口
*/
public interface OnItemClickListener {
void onItemClick(int listId, int position);
}
}

View File

@ -0,0 +1,108 @@
// 文件: CreateLinkAdapter.java
package com.example.longyi_groundstation.Main.Adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.longyi_groundstation.Main.Base.CreateLink;
import com.example.longyi_groundstation.R;
import java.util.ArrayList;
import java.util.List;
public class CreateLinkAdapter extends RecyclerView.Adapter<CreateLinkAdapter.ViewHolder> {
private List<CreateLink> createLinkList;
private OnItemClickListener onItemClickListener;
public interface OnItemClickListener {
void onDeleteClick(int position);
}
public CreateLinkAdapter() {
this.createLinkList = new ArrayList<>();
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.onItemClickListener = listener;
}
public void setCreateLinkList(List<CreateLink> createLinkList) {
this.createLinkList = createLinkList;
notifyDataSetChanged();
}
public List<CreateLink> getCreateLinkList() {
return createLinkList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_create_link_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
CreateLink createLink = createLinkList.get(position);
holder.bind(createLink, position);
}
@Override
public int getItemCount() {
return createLinkList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView tvDel,tv_title;
private EditText etHeight;
private EditText etSpeed;
public ViewHolder(@NonNull View itemView) {
super(itemView);
tvDel = itemView.findViewById(R.id.tv_del);
tv_title = itemView.findViewById(R.id.tv_title);
etHeight = itemView.findViewById(R.id.et_height);
etSpeed = itemView.findViewById(R.id.et_speed);
}
public void bind(CreateLink createLink, int position) {
etHeight.setText(String.valueOf((int) createLink.getHeight()));
etSpeed.setText(String.valueOf((int) createLink.getSpeed()));
tv_title.setText(createLink.getName());
tvDel.setOnClickListener(v -> {
if (onItemClickListener != null) {
onItemClickListener.onDeleteClick(position);
}
});
// 可以添加文本变化监听器来更新数据
etHeight.setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
try {
createLink.setHeight(Double.parseDouble(etHeight.getText().toString()));
} catch (NumberFormatException e) {
etHeight.setText(String.valueOf((int) createLink.getHeight()));
}
}
});
etSpeed.setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
try {
createLink.setSpeed(Double.parseDouble(etSpeed.getText().toString()));
} catch (NumberFormatException e) {
etSpeed.setText(String.valueOf((int) createLink.getSpeed()));
}
}
});
}
}
}

View File

@ -43,26 +43,46 @@ public class TypeAdapter extends RecyclerView.Adapter<TypeAdapter.TypeViewHolder
case "relative_alt":
holder.textView.setText("融合高度:" + (Integer.parseInt(item.getMsg()) / 1000) + " m");
holder.textView.setMaxWidth(Integer.MAX_VALUE); // 移除最大宽度限制
holder.textView.setMinimumWidth(0); // 移除最小宽度限制
break;
case "alt":
holder.textView.setText("海拔高度:" + (Integer.parseInt(item.getMsg()) / 1000) + " m");
holder.textView.setMaxWidth(Integer.MAX_VALUE); // 移除最大宽度限制
holder.textView.setMinimumWidth(0); // 移除最小宽度限制
break;
case "time_boot_ms":
holder.textView.setText("飞行时间:" + Tool.formatMillisecondsLong(Long.parseLong(item.getMsg())));
holder.textView.setMaxWidth(Integer.MAX_VALUE); // 移除最大宽度限制
holder.textView.setMinimumWidth(0); // 移除最小宽度限制
break;
case "lat":
holder.textView.setText("纬度:" + item.getMsg());
// 设置纬度显示的最大宽度确保能完整显示坐标值
holder.textView.setMaxWidth(Integer.MAX_VALUE);
holder.textView.setMinimumWidth(400); // 设置最小宽度确保足够显示
break;
case "lon":
holder.textView.setText("经度:" + item.getMsg());
// 设置经度显示的最大宽度确保能完整显示坐标值
holder.textView.setMaxWidth(Integer.MAX_VALUE);
holder.textView.setMinimumWidth(400); // 设置最小宽度确保足够显示
break;
case "throttle":
holder.textView.setText("油门量:" + item.getMsg());
holder.textView.setMaxWidth(Integer.MAX_VALUE); // 移除最大宽度限制
holder.textView.setMinimumWidth(0); // 移除最小宽度限制
break;
default:
holder.textView.setText("距家距离:"+item.getMsg());
holder.textView.setMaxWidth(Integer.MAX_VALUE); // 移除最大宽度限制
holder.textView.setMinimumWidth(0); // 移除最小宽度限制
break;
}
@ -72,9 +92,9 @@ public class TypeAdapter extends RecyclerView.Adapter<TypeAdapter.TypeViewHolder
}else {
holder.ll_main.setVisibility(GONE);
}
}
@Override
public int getItemCount() {
return dataList.size();

View File

@ -0,0 +1,60 @@
// 文件: CreateLink.java
package com.example.longyi_groundstation.Main.Base;
import com.amap.api.maps.model.LatLng;
public class CreateLink {
private String name;
private double height;
private double speed;
private int waypointIndex;
private LatLng latLng;
public CreateLink(String name, double height, double speed, int waypointIndex, LatLng latLng) {
this.name = name;
this.height = height;
this.speed = speed;
this.waypointIndex = waypointIndex;
this.latLng = latLng;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
public int getWaypointIndex() {
return waypointIndex;
}
public void setWaypointIndex(int waypointIndex) {
this.waypointIndex = waypointIndex;
}
public LatLng getLatLng() {
return latLng;
}
public void setLatLng(LatLng latLng) {
this.latLng = latLng;
}
}

View File

@ -1,16 +1,22 @@
package com.example.longyi_groundstation.Main.Service;
import static com.example.longyi_groundstation.MAVLink.common.msg_attitude.MAVLINK_MSG_ID_ATTITUDE;
import static com.example.longyi_groundstation.MAVLink.common.msg_attitude_target.MAVLINK_MSG_ID_ATTITUDE_TARGET;
import static com.example.longyi_groundstation.MAVLink.common.msg_global_position_int.MAVLINK_MSG_ID_GLOBAL_POSITION_INT;
import static com.example.longyi_groundstation.MAVLink.common.msg_gps_raw_int.MAVLINK_MSG_ID_GPS_RAW_INT;
import static com.example.longyi_groundstation.MAVLink.common.msg_param_request_list.MAVLINK_MSG_ID_PARAM_REQUEST_LIST;
import static com.example.longyi_groundstation.MAVLink.common.msg_param_request_read.MAVLINK_MSG_ID_PARAM_REQUEST_READ;
import static com.example.longyi_groundstation.MAVLink.common.msg_param_value.MAVLINK_MSG_ID_PARAM_VALUE;
import static com.example.longyi_groundstation.MAVLink.common.msg_power_status.MAVLINK_MSG_ID_POWER_STATUS;
import static com.example.longyi_groundstation.MAVLink.common.msg_rc_channels.MAVLINK_MSG_ID_RC_CHANNELS;
import static com.example.longyi_groundstation.MAVLink.common.msg_rc_channels_raw.MAVLINK_MSG_ID_RC_CHANNELS_RAW;
import static com.example.longyi_groundstation.MAVLink.common.msg_statustext.MAVLINK_MSG_ID_STATUSTEXT;
import static com.example.longyi_groundstation.MAVLink.common.msg_sys_status.MAVLINK_MSG_ID_SYS_STATUS;
import static com.example.longyi_groundstation.MAVLink.common.msg_vfr_hud.MAVLINK_MSG_ID_VFR_HUD;
import static com.example.longyi_groundstation.MAVLink.enums.MAV_DATA_STREAM.MAV_DATA_STREAM_ALL;
import static com.example.longyi_groundstation.MAVLink.minimal.msg_heartbeat.MAVLINK_MSG_ID_HEARTBEAT;
import static com.example.longyi_groundstation.Main.Void.SerialTool.bytesToHex;
import static com.example.longyi_groundstation.Main.Void.SerialTool.parseSerialData;
import android.app.Service;
import android.content.Intent;
@ -31,6 +37,7 @@ import com.example.longyi_groundstation.MAVLink.common.msg_request_data_stream;
import com.example.longyi_groundstation.Main.Base.MLData;
import com.example.longyi_groundstation.Main.Setting.Base.Param;
import com.example.longyi_groundstation.Main.Void.FlyVoid;
import com.example.longyi_groundstation.Main.Void.LogCat.LogUtil;
import com.example.longyi_groundstation.Main.Void.MyTool;
import com.example.longyi_groundstation.Util.BroadcastUtil;
import com.example.longyi_groundstation.Util.Tool;
@ -61,6 +68,8 @@ public class MyBoundService extends Service {
private static final String TAG = "UDPServer";
private TextView tv_text;
public static DatagramSocket serverSocket;
public static DatagramSocket serverSocket2;
private boolean isRunning = false;
private String serverPort = "14551"; // 服务端监听端口
@ -99,7 +108,7 @@ public class MyBoundService extends Service {
}
public static SerialHelper serialHelper;
public static SerialHelper serialHelper, serialHelper2;
private Parser parser = new Parser();
private MAVLinkMessage msgOld = null;
@ -173,9 +182,67 @@ public class MyBoundService extends Service {
wordT();
}
/**
* 方法连接串口2获取高度或一些其他的硬件设施
*
* @cuijingzhou
*/
private void getDataSerial() {
if (type == 0){
serialHelper2 = new SerialHelper("/dev/ttyHS2", 9600) {
@Override
protected void onDataReceived(final ComBean comBean) {
// Log.d("cuijingzhou", Tool.bytesToHex(comBean.bRec));
// 接收数据
byte[] receivedData = comBean.bRec;
int[] parseSerialData = parseSerialData(receivedData);
// 保存接收到的数据
FlyVoid.parseSerialData = parseSerialData;
Log.d("cuijingzhou_getDataSerial", parseSerialData[0]+"-"+parseSerialData[1]);
// dataWork(receivedData, receivedData.length);
}
};
try {
serialHelper2.open();
// wordT1();
} catch (IOException e) {
// throw new RuntimeException(e);
Log.d(TAG, e.toString());
}
}else {
new Thread(() -> {
try {
serverSocket2 = new DatagramSocket(13551);
byte[] buffer = new byte[1024];
while (isRunning) {
try {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
serverSocket2.receive(packet);
// 获取客户端IP和端口
int[] parseSerialData = parseSerialData(packet.getData());
// 保存接收到的数据
FlyVoid.parseSerialData = parseSerialData;
Log.d("cuijingzhou_getDataSerial", parseSerialData[0]+"-"+parseSerialData[1]);
// Log.e("cuijingzhou-IP:", logMsg);
} catch (Exception e) {
Log.e(TAG, "接收数据错误: " + e.getMessage());
}
}
} catch (SocketException e) {
Log.e(TAG, "启动服务端失败: " + e.getMessage());
} finally {
stopUdpServer();
}
}).start();
}
}
/**
* 发送请求姿态数据的MAVLink指令
* 方法发送请求姿态数据的MAVLink指令
*/
public void requestAttitudeData() {
// 构造REQUEST_DATA_STREAM消息
@ -268,6 +335,8 @@ public class MyBoundService extends Service {
//判断当前索引下的数据是否有变动如过没有变动就不储存用一个判断增加性能
if (!msg.toString().equals(MsgList.get(msg.msgid))) {
// Log.d("cuijigzhou_msg_all", msg.toString());
LogUtil.d("cuijigzhou_msg_all", msg.toString());
MsgList.set(msg.msgid, msg.toString());
if (msgOld == null) {
@ -279,7 +348,6 @@ public class MyBoundService extends Service {
msgOld = msg;
}
}
}
}
@ -313,6 +381,16 @@ public class MyBoundService extends Service {
if (MsgList.get(MAVLINK_MSG_ID_HEARTBEAT) != null) {
BroadcastUtil.Broadcast_HEARTBEAT(getApplication(), MsgList.get(MAVLINK_MSG_ID_HEARTBEAT));
}
if (MsgList.get(MAVLINK_MSG_ID_RC_CHANNELS) != null) {
BroadcastUtil.Broadcast_RC_CHANNELS(getApplication(), MsgList.get(MAVLINK_MSG_ID_RC_CHANNELS));
}
if (MsgList.get(MAVLINK_MSG_ID_RC_CHANNELS_RAW) != null) {
BroadcastUtil.Broadcast_RC_CHANNELS_RAW(getApplication(), MsgList.get(MAVLINK_MSG_ID_RC_CHANNELS_RAW));
}
if (MsgList.get(MAVLINK_MSG_ID_VFR_HUD) != null) {
// Log.e("MAVLINK_MSG_ID_ATTITUDE_TARGET", 1+"");
BroadcastUtil.Broadcast_VFR_HUD(getApplication(), MsgList.get(MAVLINK_MSG_ID_VFR_HUD));
}
Thread.sleep(50);
}
@ -354,7 +432,6 @@ public class MyBoundService extends Service {
FlyVoid.setParamUpdateComplete(false);
}
default:
// Log.d("cuijigzhou_msg_all_id", "不做处理:"+msg.msgid);
@ -384,6 +461,7 @@ public class MyBoundService extends Service {
// 初始化服务逻辑
initList();
getData();
getDataSerial();
return binder;

View File

@ -1,11 +1,14 @@
// SettingActivity.java
package com.example.longyi_groundstation.Main.Setting.Activity;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;
import android.view.View;
import android.view.WindowManager;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
@ -29,7 +32,6 @@ import com.example.longyi_groundstation.R;
public class SettingActivity extends AppCompatActivity {
private FlyVoid flyVoid = new FlyVoid();
private AllView allView;
private FoundationFragment foundationFragment;
private ControlFragment controlFragment;
private FlyFragment flyFragment;
@ -39,9 +41,30 @@ public class SettingActivity extends AppCompatActivity {
private SensorFragment sensorFragment;
private SettingsFragment settingsFragment;
// 添加参数加载对话框
private ProgressDialog paramLoadingDialog;
// 添加Handler引用以便在销毁时移除回调
private Handler uiHandler = new Handler(Looper.getMainLooper());
// 添加参数更新检查的Runnable
private Runnable paramUpdateChecker = new Runnable() {
@Override
public void run() {
if (FlyVoid.isParamUpdateComplete()) {
// 参数更新完成关闭对话框并初始化界面
if (paramLoadingDialog != null && paramLoadingDialog.isShowing()) {
paramLoadingDialog.dismiss();
}
initView();
initOnClick();
} else {
// 参数未更新完成继续等待并定期检查
uiHandler.postDelayed(this, 500); // 500毫秒后再次检查
}
}
};
//广播接收器
@Override
@ -49,19 +72,34 @@ public class SettingActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_setting);
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_FULLSCREEN // 隐藏状态栏
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY // 启用沉浸式粘滞模式
);
// 设置导航栏背景为黑色
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
getWindow().setNavigationBarColor(Color.BLACK);
}
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
MyTool.hideBottomNavigationBar(this);
initData();
if (FlyVoid.isParamUpdateComplete()){
initView();
initOnClick();
} else {
// 显示参数加载对话框
showParamLoadingDialog();
// 开始检查参数更新状态
uiHandler.postDelayed(paramUpdateChecker, 500);
}
}
/**
* 方法初始化数据
@ -81,38 +119,12 @@ public class SettingActivity extends AppCompatActivity {
private void initView() {
allView = new AllView(this);
// 预加载所有 Fragment
// 只预加载默认的 MotorFragment
androidx.fragment.app.FragmentManager fragmentManager = getSupportFragmentManager();
androidx.fragment.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
foundationFragment = new FoundationFragment();
controlFragment = new ControlFragment();
flyFragment = new FlyFragment();
secureFragment = new SecureFragment();
motorFragment = new MotorFragment();
loadFragment = new LoadFragment();
sensorFragment = new SensorFragment();
settingsFragment = new SettingsFragment();
// 添加所有 Fragment但只显示默认的 MotorFragment
transaction.add(R.id.fragment_container, motorFragment, "MotorFragment")
.add(R.id.fragment_container, foundationFragment, "FoundationFragment")
.add(R.id.fragment_container, controlFragment, "ControlFragment")
.add(R.id.fragment_container, flyFragment, "FlyFragment")
.add(R.id.fragment_container, secureFragment, "SecureFragment")
.add(R.id.fragment_container, loadFragment, "LoadFragment")
.add(R.id.fragment_container, sensorFragment, "SensorFragment")
.add(R.id.fragment_container, settingsFragment, "SettingsFragment");
// 隐藏除 MotorFragment 外的其他 Fragment
transaction.hide(motorFragment)
.hide(controlFragment)
.hide(flyFragment)
.hide(secureFragment)
.hide(loadFragment)
.hide(sensorFragment)
.hide(settingsFragment);
transaction.add(R.id.fragment_container, foundationFragment, "FoundationFragment");
transaction.commit();
}
@ -122,19 +134,6 @@ public class SettingActivity extends AppCompatActivity {
* @cuijingzhou
*/
private void initOnClick() {
// msg_param_set paramSet = new msg_param_set();
// paramSet.target_system = 1; // 目标系统ID (飞控)
// paramSet.target_component = 1; // 目标组件ID
// String paramId = "RTL_OPTIONS";
// // 设置参数ID (最多16字符)
// byte[] paramIdBytes = paramId.getBytes();
// System.arraycopy(paramIdBytes, 0, paramSet.param_id, 0, Math.min(paramIdBytes.length, 16));
// paramSet.param_value = Float.parseFloat("0");// 参数值
// paramSet.param_type = 1; // 参数类型
// // 发送命令
// flyVoid.sendMavlinkMessage(MyBoundService.type,paramSet);
allView.iv_back.setOnClickListener(v -> {
finish();
});
@ -145,7 +144,6 @@ public class SettingActivity extends AppCompatActivity {
selectItem(finalI);
});
}
}
/**
@ -175,59 +173,117 @@ public class SettingActivity extends AppCompatActivity {
androidx.fragment.app.FragmentManager fragmentManager = getSupportFragmentManager();
androidx.fragment.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
// 隐藏所有 Fragment
transaction.hide(foundationFragment)
.hide(controlFragment)
.hide(flyFragment)
.hide(secureFragment)
.hide(motorFragment)
.hide(loadFragment)
.hide(sensorFragment)
.hide(settingsFragment);
// 隐藏当前显示的Fragment
if (foundationFragment != null && foundationFragment.isVisible()) {
transaction.hide(foundationFragment);
}
if (controlFragment != null && controlFragment.isVisible()) {
transaction.hide(controlFragment);
}
if (flyFragment != null && flyFragment.isVisible()) {
transaction.hide(flyFragment);
}
if (secureFragment != null && secureFragment.isVisible()) {
transaction.hide(secureFragment);
}
if (motorFragment != null && motorFragment.isVisible()) {
transaction.hide(motorFragment);
}
if (loadFragment != null && loadFragment.isVisible()) {
transaction.hide(loadFragment);
}
if (sensorFragment != null && sensorFragment.isVisible()) {
transaction.hide(sensorFragment);
}
if (settingsFragment != null && settingsFragment.isVisible()) {
transaction.hide(settingsFragment);
}
// 根据 index 显示对应的 Fragment
// 根据 index 动态加载并显示对应的 Fragment
switch (index) {
case 0:
if (foundationFragment == null) {
foundationFragment = new FoundationFragment();
transaction.add(R.id.fragment_container, foundationFragment, "FoundationFragment");
} else {
transaction.show(foundationFragment);
}
break;
case 1:
if (controlFragment == null) {
controlFragment = new ControlFragment();
transaction.add(R.id.fragment_container, controlFragment, "ControlFragment");
} else {
transaction.show(controlFragment);
}
break;
case 2:
if (flyFragment == null) {
flyFragment = new FlyFragment();
transaction.add(R.id.fragment_container, flyFragment, "FlyFragment");
} else {
transaction.show(flyFragment);
}
break;
case 3:
if (secureFragment == null) {
secureFragment = new SecureFragment();
transaction.add(R.id.fragment_container, secureFragment, "SecureFragment");
} else {
transaction.show(secureFragment);
}
break;
case 4:
if (motorFragment == null) {
motorFragment = new MotorFragment();
transaction.add(R.id.fragment_container, motorFragment, "MotorFragment");
} else {
transaction.show(motorFragment);
}
break;
case 5:
if (loadFragment == null) {
loadFragment = new LoadFragment();
transaction.add(R.id.fragment_container, loadFragment, "LoadFragment");
} else {
transaction.show(loadFragment);
}
break;
case 6:
if (sensorFragment == null) {
sensorFragment = new SensorFragment();
transaction.add(R.id.fragment_container, sensorFragment, "SensorFragment");
} else {
transaction.show(sensorFragment);
}
break;
default:
default: // settingsFragment现在是索引7
if (settingsFragment == null) {
settingsFragment = new SettingsFragment();
transaction.add(R.id.fragment_container, settingsFragment, "SettingsFragment");
} else {
transaction.show(settingsFragment);
}
break;
}
transaction.commitAllowingStateLoss(); // 使用commitAllowingStateLoss防止状态异常
}
private void initReceiver() {
/**
* 显示参数加载对话框
*/
private void showParamLoadingDialog() {
paramLoadingDialog = new ProgressDialog(this);
paramLoadingDialog.setMessage("参数加载中,请稍候...");
paramLoadingDialog.setCancelable(false); // 设置为不可取消
paramLoadingDialog.setIndeterminate(true); // 设置为不确定进度
paramLoadingDialog.show();
}
@Override
protected void onResume() {
super.onResume();
initView();
initOnClick();
initReceiver();
}
@Override

View File

@ -0,0 +1,38 @@
package com.example.longyi_groundstation.Main.Setting.Adapter;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import com.example.longyi_groundstation.Main.Setting.Fragment.Foundation.FlyModelFragment;
import com.example.longyi_groundstation.Main.Setting.Fragment.Foundation.FlyInstallFragment;
import com.example.longyi_groundstation.Main.Setting.Fragment.Foundation.FlyAccelerationFragment;
import com.example.longyi_groundstation.Main.Setting.Fragment.Foundation.FlyMagnetometerFragment;
public class FoundationPagerAdapter extends FragmentStateAdapter {
public FoundationPagerAdapter(FragmentActivity fragmentActivity) {
super(fragmentActivity);
}
@Override
public Fragment createFragment(int position) {
switch (position) {
case 0:
return new FlyModelFragment();
case 1:
return new FlyInstallFragment();
case 2:
return new FlyAccelerationFragment();
case 3:
return new FlyMagnetometerFragment();
default:
return new FlyModelFragment();
}
}
@Override
public int getItemCount() {
return 4; // 四个选项卡
}
}

View File

@ -1,9 +1,11 @@
// 新文件E:\AndroidProject\LongYiGroundStation\app\src\main\java\com\example\longyi_groundstation\Adapter\ParamGridAdapter.java
package com.example.longyi_groundstation.Main.Setting.Adapter;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -33,29 +35,66 @@ public class ParamGridAdapter extends RecyclerView.Adapter<ParamGridAdapter.Para
public void onBindViewHolder(@NonNull ParamViewHolder holder, int position) {
ParamItem item = paramItems.get(position);
holder.tvParamName.setText(item.getParamName());
holder.tvMaxValue.setText(String.format("最大值: %s", item.getMaxValue()));
holder.tvMinValue.setText(String.format("最小值: %s", item.getMinValue()));
holder.tvCurrentValue.setText(String.format("%s", item.getCurrentValue()));
holder.tvMaxDesc.setText("("+item.getMaxDesc()+")");
holder.tvMinDesc.setText("("+item.getMinDesc()+")");
// 限制值在1000-2000范围内
int clampedValue = Integer.parseInt(item.getCurrentValue());
// 计算进度比例 (1000-2000映射到0-100%)
// 1500为中心点左边是1000-1500右边是1500-2000
if (clampedValue <= 1500) {
// 值在左侧范围(1000-1500)
float leftRatio = (float)(clampedValue - 1000) / 500; // 0.0 - 1.0
float rightRatio = 1.0f;
// 设置权重
LinearLayout.LayoutParams leftParams = (LinearLayout.LayoutParams) holder.leftProgress.getLayoutParams();
LinearLayout.LayoutParams rightParams = (LinearLayout.LayoutParams) holder.rightProgress.getLayoutParams();
leftParams.weight = leftRatio;
rightParams.weight = rightRatio;
holder.leftProgress.setLayoutParams(leftParams);
holder.rightProgress.setLayoutParams(rightParams);
// 设置颜色
holder.leftProgress.setBackgroundColor(Color.parseColor("#62a7f0")); // 蓝色
holder.rightProgress.setBackgroundColor(Color.parseColor("#cccccc")); // 灰色
} else {
// 值在右侧范围(1500-2000)
float leftRatio = 1.0f;
float rightRatio = (float)(2000 - clampedValue) / 500; // 1.0 - 0.0
// 设置权重
LinearLayout.LayoutParams leftParams = (LinearLayout.LayoutParams) holder.leftProgress.getLayoutParams();
LinearLayout.LayoutParams rightParams = (LinearLayout.LayoutParams) holder.rightProgress.getLayoutParams();
leftParams.weight = leftRatio;
rightParams.weight = rightRatio;
holder.leftProgress.setLayoutParams(leftParams);
holder.rightProgress.setLayoutParams(rightParams);
// 设置颜色
holder.leftProgress.setBackgroundColor(Color.parseColor("#62a7f0")); // 蓝色
holder.rightProgress.setBackgroundColor(Color.parseColor("#cccccc")); // 灰色
}
}
@Override
public int getItemCount() {
return paramItems != null ? paramItems.size() : 0;
return paramItems.size();
}
public static class ParamViewHolder extends RecyclerView.ViewHolder {
TextView tvParamName, tvMaxValue, tvMinValue, tvCurrentValue, tvMaxDesc, tvMinDesc;
TextView tvParamName, tvCurrentValue;
View leftProgress, rightProgress;
public ParamViewHolder(@NonNull View itemView) {
super(itemView);
tvParamName = itemView.findViewById(R.id.tv_param_name);
tvMaxValue = itemView.findViewById(R.id.tv_max_value);
tvMinValue = itemView.findViewById(R.id.tv_min_value);
tvCurrentValue = itemView.findViewById(R.id.tv_current_value);
tvMaxDesc = itemView.findViewById(R.id.tv_max_desc);
tvMinDesc = itemView.findViewById(R.id.tv_min_desc);
leftProgress = itemView.findViewById(R.id.view_left_progress);
rightProgress = itemView.findViewById(R.id.view_right_progress);
}
}
@ -101,5 +140,29 @@ public class ParamGridAdapter extends RecyclerView.Adapter<ParamGridAdapter.Para
public String getMinDesc() {
return minDesc;
}
public void setParamName(String paramName) {
this.paramName = paramName;
}
public void setMaxValue(String maxValue) {
this.maxValue = maxValue;
}
public void setMinValue(String minValue) {
this.minValue = minValue;
}
public void setCurrentValue(String currentValue) {
this.currentValue = currentValue;
}
public void setMaxDesc(String maxDesc) {
this.maxDesc = maxDesc;
}
public void setMinDesc(String minDesc) {
this.minDesc = minDesc;
}
}
}

View File

@ -0,0 +1,27 @@
package com.example.longyi_groundstation.Main.Setting.Base;
public class AirplaneModel {
private int imageResId;
private String modelName;
public AirplaneModel(int imageResId, String modelName) {
this.imageResId = imageResId;
this.modelName = modelName;
}
public int getImageResId() {
return imageResId;
}
public void setImageResId(int imageResId) {
this.imageResId = imageResId;
}
public String getModelName() {
return modelName;
}
public void setModelName(String modelName) {
this.modelName = modelName;
}
}

View File

@ -0,0 +1,25 @@
package com.example.longyi_groundstation.Main.Setting.Base;
// 在LoadFragment.java中添加这个内部类
public class ChannelItem {
private String text;
private int value;
public ChannelItem(String text, int value) {
this.text = text;
this.value = value;
}
public String getText() {
return text;
}
public int getValue() {
return value;
}
@Override
public String toString() {
return text; // Spinner显示的内容
}
}

View File

@ -1,5 +1,8 @@
package com.example.longyi_groundstation.Main.Setting.Fragment;
import android.content.Context;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
@ -7,14 +10,18 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.longyi_groundstation.Main.Setting.Adapter.ParamGridAdapter;
import com.example.longyi_groundstation.Main.Void.FlyVoid;
import com.example.longyi_groundstation.Main.Void.MyReceiver;
import com.example.longyi_groundstation.R;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
@ -27,8 +34,7 @@ public class ControlFragment extends Fragment {
private ParamGridAdapter adapter;
private FlyVoid flyVoid = new FlyVoid();
private List<ParamGridAdapter.ParamItem> paramItems = new ArrayList<>();
private boolean isClear = true;
private MyReceiver mBroadcast_RC_CHANNELS, mBroadcast_RC_CHANNELS_RAW;
@Override
@ -40,6 +46,8 @@ public class ControlFragment extends Fragment {
initData();
initView(view);
initOnClick();
initReceiver();
return view;
}
@ -50,8 +58,16 @@ public class ControlFragment extends Fragment {
* @cuijingzhou
*/
private void initData() {
adapter = new ParamGridAdapter(paramItems);
updata();
//开启广播监听-RC通道
mBroadcast_RC_CHANNELS = new MyReceiver();
IntentFilter filter8 = new IntentFilter("Broadcast_RC_CHANNELS");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
getActivity().registerReceiver(mBroadcast_RC_CHANNELS, filter8, Context.RECEIVER_EXPORTED);
} else {
ContextCompat.registerReceiver(getActivity(), mBroadcast_RC_CHANNELS, filter8, ContextCompat.RECEIVER_NOT_EXPORTED);
}
}
/**
@ -63,8 +79,10 @@ public class ControlFragment extends Fragment {
rv_data = view.findViewById(R.id.rv_data);
tv_calibration = view.findViewById(R.id.tv_calibration);
adapter = new ParamGridAdapter(paramItems);
updata();
// 设置GridLayoutManager每行显示2个item
rv_data.setLayoutManager(new GridLayoutManager(getContext(), 2));
rv_data.setLayoutManager(new GridLayoutManager(getContext(), 3));
rv_data.setAdapter(adapter);
}
@ -77,30 +95,38 @@ public class ControlFragment extends Fragment {
}
/**
* 方法初始化广播
*
* @cuijingzhou
*/
private void initReceiver() {
//广播接收-RcChannelsRawlistener
mBroadcast_RC_CHANNELS.setRcChannelsRawlistener(data -> {
Log.d("cuijingzhou_ctrl", data.toString());
try {
JSONObject jsonObject = new JSONObject(data.toString());
for (int i = 0; i < 12; i++){
paramItems.get(i).setCurrentValue(jsonObject.optString("chan" + (i + 1) + "_raw"));
}
}catch (Exception e){
Log.d("cuijingzhou_ctrl_E", e.toString());
}
adapter.notifyDataSetChanged();
});
}
private void updata() {
new Thread(new Runnable() {
@Override
public void run() {
while (isClear){
try {
for (int i = 1; i <= 12; i++) {
flyVoid.requestParamRead("RC"+i+"_MAX");
Thread.sleep(100);
flyVoid.requestParamRead("RC"+i+"_MIN");
Thread.sleep(100);
flyVoid.requestParamRead("RC"+i+"_TRIM");
Thread.sleep(100);
}
if (!flyVoid.isParamUpdateComplete()){
Thread.sleep(1000);
getList();
adapter.notifyDataSetChanged();
Log.d("cuijingzhou", "一直更新");
}
}catch (Exception e){
} catch (Exception e) {
Log.d("cuijingzhou", "没事");
}
}
}
}).start();
@ -113,7 +139,7 @@ public class ControlFragment extends Fragment {
*
* @cuijingzhou
*/
private void getList(){
private void getList() {
paramItems.clear();
// 添加数据
paramItems.add(new ParamGridAdapter.ParamItem(
@ -216,7 +242,6 @@ public class ControlFragment extends Fragment {
@Override
public void onDestroy() {
super.onDestroy();
isClear = false;
}
@Override

View File

@ -4,14 +4,41 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.fragment.app.Fragment;
import com.example.longyi_groundstation.Main.Void.FlyVoid;
import com.example.longyi_groundstation.R;
public class FlyFragment extends Fragment {
private TextView tv_flight_speed_minus;
private SeekBar seekBar_flight_speed;
private TextView tv_flight_speed_add;
private TextView tv_flight_speed;
private TextView tv_climb_speed_minus;
private SeekBar seekBar_climb_speed;
private TextView tv_climb_speed_add;
private TextView tv_climb_speed;
private TextView tv_decline_speed_minus;
private SeekBar seekBar_decline_speed;
private TextView tv_decline_speed_add;
private TextView tv_decline_speed;
private TextView tv_horizontal_angle_minus;
private SeekBar seekBar_horizontal_angle;
private TextView tv_horizontal_angle_add;
private TextView tv_horizontal_angle;
private TextView tv_rotation_rate_minus;
private SeekBar seekBar_rotation_rate;
private TextView tv_rotation_rate_add;
private TextView tv_rotation_rate;
private TextView tv_save;
private TextView tv_default;
private FlyVoid flyVoid = new FlyVoid();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@ -19,10 +46,12 @@ public class FlyFragment extends Fragment {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_fly, container, false);
initData();
initView();
initOnClick();
if (FlyVoid.isParamUpdateComplete()){
initData();
initView(view);
initOnClick();
}
return view;
}
@ -40,7 +69,34 @@ public class FlyFragment extends Fragment {
*
* @cuijingzhou
*/
private void initView() {
private void initView(View view) {
tv_flight_speed_minus = view.findViewById(R.id.tv_flight_speed_minus);
seekBar_flight_speed = view.findViewById(R.id.seekBar_flight_speed);
tv_flight_speed_add = view.findViewById(R.id.tv_flight_speed_add);
tv_flight_speed = view.findViewById(R.id.tv_flight_speed);
tv_climb_speed_minus = view.findViewById(R.id.tv_climb_speed_minus);
seekBar_climb_speed = view.findViewById(R.id.seekBar_climb_speed);
tv_climb_speed_add = view.findViewById(R.id.tv_climb_speed_add);
tv_climb_speed = view.findViewById(R.id.tv_climb_speed);
tv_decline_speed_minus = view.findViewById(R.id.tv_decline_speed_minus);
seekBar_decline_speed = view.findViewById(R.id.seekBar_decline_speed);
tv_decline_speed_add = view.findViewById(R.id.tv_decline_speed_add);
tv_decline_speed = view.findViewById(R.id.tv_decline_speed);
tv_horizontal_angle_minus = view.findViewById(R.id.tv_horizontal_angle_minus);
seekBar_horizontal_angle = view.findViewById(R.id.seekBar_horizontal_angle);
tv_horizontal_angle_add = view.findViewById(R.id.tv_horizontal_angle_add);
tv_horizontal_angle = view.findViewById(R.id.tv_horizontal_angle);
tv_rotation_rate_minus = view.findViewById(R.id.tv_rotation_rate_minus);
seekBar_rotation_rate = view.findViewById(R.id.seekBar_rotation_rate);
tv_rotation_rate_add = view.findViewById(R.id.tv_rotation_rate_add);
tv_rotation_rate = view.findViewById(R.id.tv_rotation_rate);
tv_save = view.findViewById(R.id.tv_save);
tv_default = view.findViewById(R.id.tv_default);
}
@ -50,8 +106,216 @@ public class FlyFragment extends Fragment {
* @cuijingzhou
*/
private void initOnClick() {
// 最大平飞速度
tv_flight_speed_minus.setOnClickListener(v -> {
int progress = seekBar_flight_speed.getProgress();
if (progress > 20) {
seekBar_flight_speed.setProgress(progress - 10);
tv_flight_speed.setText(((double)seekBar_flight_speed.getProgress()/100) + "m/s");
}
});
tv_flight_speed_add.setOnClickListener(v -> {
int progress = seekBar_flight_speed.getProgress();
if (progress < seekBar_flight_speed.getMax()) {
seekBar_flight_speed.setProgress(progress + 10);
tv_flight_speed.setText(((double)seekBar_flight_speed.getProgress()/100) + "m/s");
}
});
seekBar_flight_speed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
tv_flight_speed.setText(((double)seekBar_flight_speed.getProgress()/100) + "m/s");
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
// 最大爬升速度
tv_climb_speed_minus.setOnClickListener(v -> {
int progress = seekBar_climb_speed.getProgress();
if (progress > 50) {
seekBar_climb_speed.setProgress(progress - 10);
tv_climb_speed.setText(((double)seekBar_climb_speed.getProgress()/100) + "m/s");
}
});
tv_climb_speed_add.setOnClickListener(v -> {
int progress = seekBar_climb_speed.getProgress();
if (progress < seekBar_climb_speed.getMax()) {
seekBar_climb_speed.setProgress(progress + 10);
tv_climb_speed.setText(((double)seekBar_climb_speed.getProgress()/100) + "m/s");
}
});
seekBar_climb_speed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
tv_climb_speed.setText(((double)seekBar_climb_speed.getProgress()/100) + "m/s");
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
// 最大下降速度
tv_decline_speed_minus.setOnClickListener(v -> {
int progress = seekBar_decline_speed.getProgress();
if (progress > 0) {
seekBar_decline_speed.setProgress(progress - 10);
tv_decline_speed.setText(((double)seekBar_decline_speed.getProgress()/100) + "m/s");
}
});
tv_decline_speed_add.setOnClickListener(v -> {
int progress = seekBar_decline_speed.getProgress();
if (progress < seekBar_decline_speed.getMax()) {
seekBar_decline_speed.setProgress(progress + 10);
tv_decline_speed.setText(((double)seekBar_decline_speed.getProgress()/100) + "m/s");
}
});
seekBar_decline_speed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
tv_decline_speed.setText(((double)seekBar_decline_speed.getProgress()/100) + "m/s");
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
// 最大水平角度
tv_horizontal_angle_minus.setOnClickListener(v -> {
int progress = seekBar_horizontal_angle.getProgress();
if (progress > 1000) {
seekBar_horizontal_angle.setProgress(progress - 100);
tv_horizontal_angle.setText(seekBar_horizontal_angle.getProgress() + "cdeg");
}
});
tv_horizontal_angle_add.setOnClickListener(v -> {
int progress = seekBar_horizontal_angle.getProgress();
if (progress < seekBar_horizontal_angle.getMax()) {
seekBar_horizontal_angle.setProgress(progress + 100);
tv_horizontal_angle.setText(seekBar_horizontal_angle.getProgress() + "cdeg");
}
});
seekBar_horizontal_angle.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
tv_horizontal_angle.setText(progress + "");
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
// 最大旋转速率
tv_rotation_rate_minus.setOnClickListener(v -> {
int progress = seekBar_rotation_rate.getProgress();
if (progress > 1) {
seekBar_rotation_rate.setProgress(progress - 1);
tv_rotation_rate.setText(((double)seekBar_rotation_rate.getProgress()/10) + "度/s");
}
});
tv_rotation_rate_add.setOnClickListener(v -> {
int progress = seekBar_rotation_rate.getProgress();
if (progress < seekBar_rotation_rate.getMax()) {
seekBar_rotation_rate.setProgress(progress + 1);
tv_rotation_rate.setText(((double)seekBar_rotation_rate.getProgress()/10) + "度/s");
}
});
seekBar_rotation_rate.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
tv_rotation_rate.setText(((double)progress/10) + "度/s");
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
//保存
tv_save.setOnClickListener( v -> {
save();
Toast.makeText(getActivity(), "保存成功!", Toast.LENGTH_SHORT).show();
});
tv_default.setOnClickListener(v -> {
save();
seekBar_flight_speed.setProgress(1250);
tv_flight_speed.setText(seekBar_flight_speed.getProgress() + "m/s");
seekBar_climb_speed.setProgress(250);
tv_climb_speed.setText(seekBar_climb_speed.getProgress() + "m/s");
seekBar_decline_speed.setProgress(0);
tv_decline_speed.setText(seekBar_decline_speed.getProgress() + "m/s");
seekBar_horizontal_angle.setProgress(3000);
tv_horizontal_angle.setText(seekBar_horizontal_angle.getProgress() + "cdeg");
seekBar_rotation_rate.setProgress(2025);
tv_rotation_rate.setText(((double)seekBar_rotation_rate.getProgress()/10) + "度/s");
Toast.makeText(getActivity(), "初始化完成", Toast.LENGTH_SHORT).show();
});
}
/**
* 方法获取当前所有的参数
*
* @cuijingzhou
*/
private void getData(){
seekBar_flight_speed.setProgress(Integer.parseInt(FlyVoid.paramList.get("LOIT_SPEED").getParam_value()));
tv_flight_speed.setText(((double)seekBar_flight_speed.getProgress()/100) + "m/s");
seekBar_climb_speed.setProgress(Integer.parseInt(FlyVoid.paramList.get("PILOT_SPEED_UP").getParam_value()));
tv_climb_speed.setText(((double)seekBar_climb_speed.getProgress()/100) + "m/s");
seekBar_decline_speed.setProgress(Integer.parseInt(FlyVoid.paramList.get("PILOT_SPEED_DN").getParam_value()));
tv_decline_speed.setText(seekBar_decline_speed.getProgress() + "m/s");
seekBar_horizontal_angle.setProgress(Integer.parseInt(FlyVoid.paramList.get("ANGLE_MAX").getParam_value()));
tv_horizontal_angle.setText(seekBar_horizontal_angle.getProgress() + "cdeg");
//旋转速率单独运算一下
float rotation_rate = Float.parseFloat(FlyVoid.paramList.get("PILOT_Y_RATE").getParam_value())*10;
seekBar_rotation_rate.setProgress((int) rotation_rate);
tv_rotation_rate.setText(((double)seekBar_rotation_rate.getProgress()/10) + "度/s");
}
/**
* 方法保存
*
* @cuijingzhou
*/
private void save(){
flyVoid.requestParamSet("LOIT_SPEED", String.valueOf(seekBar_flight_speed.getProgress()));
flyVoid.requestParamSet("PILOT_SPEED_UP", String.valueOf(seekBar_climb_speed.getProgress()));
flyVoid.requestParamSet("PILOT_SPEED_DN", String.valueOf(seekBar_decline_speed.getProgress()));
flyVoid.requestParamSet("ANGLE_MAX", String.valueOf(seekBar_horizontal_angle.getProgress()));
flyVoid.requestParamSet("PILOT_Y_RATE", String.valueOf((double)seekBar_rotation_rate.getProgress()/10));
}
@Override
public void onStart() {
super.onStart();
getData();
}
}

View File

@ -0,0 +1,71 @@
package com.example.longyi_groundstation.Main.Setting.Fragment.Foundation;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import com.example.longyi_groundstation.R;
// 简单的载荷Fragment用于显示不同载荷的内容
public class FlyAccelerationFragment extends Fragment {
View view;
public FlyAccelerationFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@SuppressLint("MissingInflatedId")
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_fly_acceleration, container, false);
initData();
initView();
initOnClick();
return view;
}
private void initData() {
}
/**
* 方法初始化视图
*
* @cuijingzhou
*/
private void initView() {
}
/**
* 方法初始化点击事件
*
* @cuijingzhou
*/
private void initOnClick() {
}
}

View File

@ -0,0 +1,71 @@
package com.example.longyi_groundstation.Main.Setting.Fragment.Foundation;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import com.example.longyi_groundstation.R;
// 简单的载荷Fragment用于显示不同载荷的内容
public class FlyInstallFragment extends Fragment {
View view;
public FlyInstallFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@SuppressLint("MissingInflatedId")
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_fly_install, container, false);
initData();
initView();
initOnClick();
return view;
}
private void initData() {
}
/**
* 方法初始化视图
*
* @cuijingzhou
*/
private void initView() {
}
/**
* 方法初始化点击事件
*
* @cuijingzhou
*/
private void initOnClick() {
}
}

View File

@ -0,0 +1,71 @@
package com.example.longyi_groundstation.Main.Setting.Fragment.Foundation;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import com.example.longyi_groundstation.R;
// 简单的载荷Fragment用于显示不同载荷的内容
public class FlyMagnetometerFragment extends Fragment {
View view;
public FlyMagnetometerFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@SuppressLint("MissingInflatedId")
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_fly_magnetometer, container, false);
initData();
initView();
initOnClick();
return view;
}
private void initData() {
}
/**
* 方法初始化视图
*
* @cuijingzhou
*/
private void initView() {
}
/**
* 方法初始化点击事件
*
* @cuijingzhou
*/
private void initOnClick() {
}
}

View File

@ -0,0 +1,81 @@
package com.example.longyi_groundstation.Main.Setting.Fragment.Foundation;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.longyi_groundstation.Main.Setting.Adapter.SecureItemListAdapter;
import com.example.longyi_groundstation.Main.Setting.Base.Payload;
import com.example.longyi_groundstation.R;
import java.util.ArrayList;
import java.util.List;
// 简单的载荷Fragment用于显示不同载荷的内容
public class FlyModelFragment extends Fragment {
View view;
public FlyModelFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@SuppressLint("MissingInflatedId")
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_fly_model, container, false);
initData();
initView();
initOnClick();
return view;
}
private void initData() {
}
/**
* 方法初始化视图
*
* @cuijingzhou
*/
private void initView() {
}
/**
* 方法初始化点击事件
*
* @cuijingzhou
*/
private void initOnClick() {
}
}

View File

@ -6,18 +6,26 @@ import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;
import com.example.longyi_groundstation.Main.Setting.Adapter.SecurePagerAdapter;
import com.example.longyi_groundstation.R;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import com.example.longyi_groundstation.Main.Setting.Adapter.FoundationPagerAdapter;
public class FoundationFragment extends Fragment {
private View view;
private TabLayout tabLayout;
private ViewPager2 viewPager;
private TabLayoutMediator tabLayoutMediator;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_foundation, container, false);
view = inflater.inflate(R.layout.fragment_foundation, container, false);
initData();
initView();
@ -41,7 +49,48 @@ public class FoundationFragment extends Fragment {
* @cuijingzhou
*/
private void initView() {
viewPager = view.findViewById(R.id.view_pager);
tabLayout = view.findViewById(R.id.tab_layout);
// if (getActivity() != null) {
// viewPager.setAdapter(new FoundationPagerAdapter(getActivity()));
//
// // 先释放之前的TabLayoutMediator如果存在
// if (tabLayoutMediator != null) {
// tabLayoutMediator.detach();
// }
//
// tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager,
// (tab, position) -> {
// switch (position) {
// case 0:
// tab.setText("机型设置");
// break;
// case 1:
// tab.setText("安装设置");
// break;
// case 2:
// tab.setText("加速度计");
// break;
// case 3:
// tab.setText("磁力计");
// break;
// }
// }
// );
// tabLayoutMediator.attach();
//
// // 为Tab之间添加间距
// for (int i = 0; i < tabLayout.getTabCount(); i++) {
// View tab = (((ViewGroup) tabLayout.getChildAt(0)).getChildAt(i));
// ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) tab.getLayoutParams();
// layoutParams.setMargins(6, 0, 6, 0); // 左右各16dp的间距
// tab.setLayoutParams(layoutParams);
// }
//
//
// }
}
/**
@ -53,5 +102,27 @@ public class FoundationFragment extends Fragment {
}
@Override
public void onResume() {
super.onResume();
// // 使用post方法将initData()推迟到下一个UI循环执行避免FragmentManager冲突
// getView().post(new Runnable() {
// @Override
// public void run() {
// initData();
// initView();
// initOnClick();
// }
// });
}
@Override
public void onDestroyView() {
super.onDestroyView();
// 清理TabLayoutMediator资源
if (tabLayoutMediator != null) {
tabLayoutMediator.detach();
tabLayoutMediator = null;
}
}
}

View File

@ -1,29 +1,106 @@
package com.example.longyi_groundstation.Main.Setting.Fragment;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;
import com.example.longyi_groundstation.Main.Setting.Adapter.SecurePagerAdapter;
import com.example.longyi_groundstation.Main.Setting.Void.ViewTool;
import com.example.longyi_groundstation.Main.Setting.Base.ChannelItem;
import com.example.longyi_groundstation.Main.Void.FlyVoid;
import com.example.longyi_groundstation.R;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import java.util.ArrayList;
import java.util.List;
public class LoadFragment extends Fragment {
private View view;
private TabLayout tabLayout;
private ViewPager2 viewPager;
private TabLayoutMediator tabLayoutMediator;
private TextView tv_save;
private TextView tv_ctrl_m7;
private TextView tv_fly_m7;
private Spinner sp_m7;
private TextView tv_value_minus_m7;
private EditText et_value_m7;
private TextView tv_value_add_m7;
private TextView tv_off_minus_m7;
private EditText et_off_m7;
private TextView tv_off_add_m7;
private TextView tv_ctrl_m8;
private TextView tv_fly_m8;
private Spinner sp_m8;
private TextView tv_value_minus_m8;
private EditText et_value_m8;
private TextView tv_value_add_m8;
private TextView tv_off_minus_m8;
private EditText et_off_m8;
private TextView tv_off_add_m8;
private TextView tv_ctrl_m9;
private TextView tv_fly_m9;
private Spinner sp_m9;
private TextView tv_value_minus_m9;
private EditText et_value_m9;
private TextView tv_value_add_m9;
private TextView tv_off_minus_m9;
private EditText et_off_m9;
private TextView tv_off_add_m9;
private TextView tv_ctrl_m10;
private TextView tv_fly_m10;
private Spinner sp_m10;
private TextView tv_value_minus_m10;
private EditText et_value_m10;
private TextView tv_value_add_m10;
private TextView tv_off_minus_m10;
private EditText et_off_m10;
private TextView tv_off_add_m10;
private TextView tv_ctrl_m11;
private TextView tv_fly_m11;
private Spinner sp_m11;
private TextView tv_value_minus_m11;
private EditText et_value_m11;
private TextView tv_value_add_m11;
private TextView tv_off_minus_m11;
private EditText et_off_m11;
private TextView tv_off_add_m11;
private TextView tv_ctrl_m12;
private TextView tv_fly_m12;
private Spinner sp_m12;
private TextView tv_value_minus_m12;
private EditText et_value_m12;
private TextView tv_value_add_m12;
private TextView tv_off_minus_m12;
private EditText et_off_m12;
private TextView tv_off_add_m12;
private TextView tv_ctrl_m13;
private TextView tv_fly_m13;
private Spinner sp_m13;
private TextView tv_value_minus_m13;
private EditText et_value_m13;
private TextView tv_value_add_m13;
private TextView tv_off_minus_m13;
private EditText et_off_m13;
private TextView tv_off_add_m13;
// 在Fragment或Activity中声明EditText变量
private EditText[] valueEditTexts;
private EditText[] offEditTexts;
private TextView[] flyTextViews;
private FlyVoid flyVoid = new FlyVoid();
@SuppressLint("MissingInflatedId")
@ -33,57 +110,27 @@ public class LoadFragment extends Fragment {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_load, container, false);
tabLayout = view.findViewById(R.id.tab_layout);
viewPager = view.findViewById(R.id.view_pager);
initData();
initView();
initOnClick();
// 初始化数据
initDataView();
return view;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
/**
* 方法初始化数据
*
* @cuijingzhou
*/
private void initData() {
if (getActivity() != null) {
viewPager.setAdapter(new SecurePagerAdapter(getActivity()));
// 先释放之前的TabLayoutMediator如果存在
if (tabLayoutMediator != null) {
tabLayoutMediator.detach();
}
tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager,
(tab, position) -> {
switch (position) {
case 0:
tab.setText("灭火弹");
break;
case 1:
tab.setText("缓降器");
break;
case 2:
tab.setText("抛投勾");
break;
case 3:
tab.setText("其他载荷");
break;
}
}
);
tabLayoutMediator.attach();
// 为Tab之间添加间距
for (int i = 0; i < tabLayout.getTabCount(); i++) {
View tab = (((ViewGroup) tabLayout.getChildAt(0)).getChildAt(i));
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) tab.getLayoutParams();
layoutParams.setMargins(6, 0, 6, 0); // 左右各16dp的间距
tab.setLayoutParams(layoutParams);
}
}
}
/**
@ -92,6 +139,84 @@ public class LoadFragment extends Fragment {
* @cuijingzhou
*/
private void initView() {
tv_save = view.findViewById(R.id.tv_save);
tv_ctrl_m7 = view.findViewById(R.id.tv_ctrl_m7);
tv_fly_m7 = view.findViewById(R.id.tv_fly_m7);
sp_m7 = view.findViewById(R.id.sp_m7);
tv_value_minus_m7 = view.findViewById(R.id.tv_value_minus_m7);
et_value_m7 = view.findViewById(R.id.et_value_m7);
tv_value_add_m7 = view.findViewById(R.id.tv_value_add_m7);
tv_off_minus_m7 = view.findViewById(R.id.tv_off_minus_m7);
et_off_m7 = view.findViewById(R.id.et_off_m7);
tv_off_add_m7 = view.findViewById(R.id.tv_off_add_m7);
tv_ctrl_m8 = view.findViewById(R.id.tv_ctrl_m8);
tv_fly_m8 = view.findViewById(R.id.tv_fly_m8);
sp_m8 = view.findViewById(R.id.sp_m8);
tv_value_minus_m8 = view.findViewById(R.id.tv_value_minus_m8);
et_value_m8 = view.findViewById(R.id.et_value_m8);
tv_value_add_m8 = view.findViewById(R.id.tv_value_add_m8);
tv_off_minus_m8 = view.findViewById(R.id.tv_off_minus_m8);
et_off_m8 = view.findViewById(R.id.et_off_m8);
tv_off_add_m8 = view.findViewById(R.id.tv_off_add_m8);
tv_ctrl_m9 = view.findViewById(R.id.tv_ctrl_m9);
tv_fly_m9 = view.findViewById(R.id.tv_fly_m9);
sp_m9 = view.findViewById(R.id.sp_m9);
tv_value_minus_m9 = view.findViewById(R.id.tv_value_minus_m9);
et_value_m9 = view.findViewById(R.id.et_value_m9);
tv_value_add_m9 = view.findViewById(R.id.tv_value_add_m9);
tv_off_minus_m9 = view.findViewById(R.id.tv_off_minus_m9);
et_off_m9 = view.findViewById(R.id.et_off_m9);
tv_off_add_m9 = view.findViewById(R.id.tv_off_add_m9);
tv_ctrl_m10 = view.findViewById(R.id.tv_ctrl_m10);
tv_fly_m10 = view.findViewById(R.id.tv_fly_m10);
sp_m10 = view.findViewById(R.id.sp_m10);
tv_value_minus_m10 = view.findViewById(R.id.tv_value_minus_m10);
et_value_m10 = view.findViewById(R.id.et_value_m10);
tv_value_add_m10 = view.findViewById(R.id.tv_value_add_m10);
tv_off_minus_m10 = view.findViewById(R.id.tv_off_minus_m10);
et_off_m10 = view.findViewById(R.id.et_off_m10);
tv_off_add_m10 = view.findViewById(R.id.tv_off_add_m10);
tv_ctrl_m11 = view.findViewById(R.id.tv_ctrl_m11);
tv_fly_m11 = view.findViewById(R.id.tv_fly_m11);
sp_m11 = view.findViewById(R.id.sp_m11);
tv_value_minus_m11 = view.findViewById(R.id.tv_value_minus_m11);
et_value_m11 = view.findViewById(R.id.et_value_m11);
tv_value_add_m11 = view.findViewById(R.id.tv_value_add_m11);
tv_off_minus_m11 = view.findViewById(R.id.tv_off_minus_m11);
et_off_m11 = view.findViewById(R.id.et_off_m11);
tv_off_add_m11 = view.findViewById(R.id.tv_off_add_m11);
tv_ctrl_m12 = view.findViewById(R.id.tv_ctrl_m12);
tv_fly_m12 = view.findViewById(R.id.tv_fly_m12);
sp_m12 = view.findViewById(R.id.sp_m12);
tv_value_minus_m12 = view.findViewById(R.id.tv_value_minus_m12);
et_value_m12 = view.findViewById(R.id.et_value_m12);
tv_value_add_m12 = view.findViewById(R.id.tv_value_add_m12);
tv_off_minus_m12 = view.findViewById(R.id.tv_off_minus_m12);
et_off_m12 = view.findViewById(R.id.et_off_m12);
tv_off_add_m12 = view.findViewById(R.id.tv_off_add_m12);
tv_ctrl_m13 = view.findViewById(R.id.tv_ctrl_m13);
tv_fly_m13 = view.findViewById(R.id.tv_fly_m13);
sp_m13 = view.findViewById(R.id.sp_m13);
tv_value_minus_m13 = view.findViewById(R.id.tv_value_minus_m13);
et_value_m13 = view.findViewById(R.id.et_value_m13);
tv_value_add_m13 = view.findViewById(R.id.tv_value_add_m13);
tv_off_minus_m13 = view.findViewById(R.id.tv_off_minus_m13);
et_off_m13 = view.findViewById(R.id.et_off_m13);
tv_off_add_m13 = view.findViewById(R.id.tv_off_add_m13);
// 初始化所有Spinner数据
initSpinnerData();
// 初始化所有EditText,TextView
initTexts(view);
// 为所有EditText设置输入限制
setupInputFilters();
// 给flyTextViews里面所有的view添加点击事件点击后会打开对应的Spinner
initFlyTextViewClickListeners();
}
@ -102,29 +227,621 @@ public class LoadFragment extends Fragment {
*/
private void initOnClick() {
tv_value_minus_m7.setOnClickListener(v -> {
if (Integer.parseInt(et_value_m7.getText().toString()) >= 1200) {
et_value_m7.setText(String.valueOf(Integer.parseInt(et_value_m7.getText().toString()) - 100));
} else {
et_value_m7.setText("1100");
}
});
tv_value_add_m7.setOnClickListener(v -> {
if (Integer.parseInt(et_value_m7.getText().toString()) <= 1800) {
et_value_m7.setText(String.valueOf(Integer.parseInt(et_value_m7.getText().toString()) + 100));
} else {
et_value_m7.setText("1900");
}
});
tv_off_minus_m7.setOnClickListener(v -> {
if (Integer.parseInt(et_off_m7.getText().toString()) >= 1200) {
et_off_m7.setText(String.valueOf(Integer.parseInt(et_off_m7.getText().toString()) - 100));
} else {
et_off_m7.setText("1100");
}
});
tv_off_add_m7.setOnClickListener(v -> {
if (Integer.parseInt(et_off_m7.getText().toString()) <= 1800) {
et_off_m7.setText(String.valueOf(Integer.parseInt(et_off_m7.getText().toString()) + 100));
} else {
et_off_m7.setText("1900");
}
});
tv_value_minus_m8.setOnClickListener(v -> {
if (Integer.parseInt(et_value_m8.getText().toString()) >= 1200) {
et_value_m8.setText(String.valueOf(Integer.parseInt(et_value_m8.getText().toString()) - 100));
} else {
et_value_m8.setText("1100");
}
});
tv_value_add_m8.setOnClickListener(v -> {
if (Integer.parseInt(et_value_m8.getText().toString()) <= 1800) {
et_value_m8.setText(String.valueOf(Integer.parseInt(et_value_m8.getText().toString()) + 100));
} else {
et_value_m8.setText("1900");
}
});
tv_off_minus_m8.setOnClickListener(v -> {
if (Integer.parseInt(et_off_m8.getText().toString()) >= 1200) {
et_off_m8.setText(String.valueOf(Integer.parseInt(et_off_m8.getText().toString()) - 100));
} else {
et_off_m8.setText("1100");
}
});
tv_off_add_m8.setOnClickListener(v -> {
if (Integer.parseInt(et_off_m8.getText().toString()) <= 1800) {
et_off_m8.setText(String.valueOf(Integer.parseInt(et_off_m8.getText().toString()) + 100));
} else {
et_off_m8.setText("1900");
}
});
tv_value_minus_m9.setOnClickListener(v -> {
if (Integer.parseInt(et_value_m9.getText().toString()) >= 1200) {
et_value_m9.setText(String.valueOf(Integer.parseInt(et_value_m9.getText().toString()) - 100));
} else {
et_value_m9.setText("1100");
}
});
tv_value_add_m9.setOnClickListener(v -> {
if (Integer.parseInt(et_value_m9.getText().toString()) <= 1800) {
et_value_m9.setText(String.valueOf(Integer.parseInt(et_value_m9.getText().toString()) + 100));
} else {
et_value_m9.setText("1900");
}
});
tv_off_minus_m9.setOnClickListener(v -> {
if (Integer.parseInt(et_off_m9.getText().toString()) >= 1200) {
et_off_m9.setText(String.valueOf(Integer.parseInt(et_off_m9.getText().toString()) - 100));
} else {
et_off_m9.setText("1100");
}
});
tv_off_add_m9.setOnClickListener(v -> {
if (Integer.parseInt(et_off_m9.getText().toString()) <= 1800) {
et_off_m9.setText(String.valueOf(Integer.parseInt(et_off_m9.getText().toString()) + 100));
} else {
et_off_m9.setText("1900");
}
});
tv_value_minus_m10.setOnClickListener(v -> {
if (Integer.parseInt(et_value_m10.getText().toString()) >= 1200) {
et_value_m10.setText(String.valueOf(Integer.parseInt(et_value_m10.getText().toString()) - 100));
} else {
et_value_m10.setText("1100");
}
});
tv_value_add_m10.setOnClickListener(v -> {
if (Integer.parseInt(et_value_m10.getText().toString()) <= 1800) {
et_value_m10.setText(String.valueOf(Integer.parseInt(et_value_m10.getText().toString()) + 100));
} else {
et_value_m10.setText("1900");
}
});
tv_off_minus_m10.setOnClickListener(v -> {
if (Integer.parseInt(et_off_m10.getText().toString()) >= 1200) {
et_off_m10.setText(String.valueOf(Integer.parseInt(et_off_m10.getText().toString()) - 100));
} else {
et_off_m10.setText("1100");
}
});
tv_off_add_m10.setOnClickListener(v -> {
if (Integer.parseInt(et_off_m10.getText().toString()) <= 1800) {
et_off_m10.setText(String.valueOf(Integer.parseInt(et_off_m10.getText().toString()) + 100));
} else {
et_off_m10.setText("1900");
}
});
tv_value_minus_m11.setOnClickListener(v -> {
if (Integer.parseInt(et_value_m11.getText().toString()) >= 1200) {
et_value_m11.setText(String.valueOf(Integer.parseInt(et_value_m11.getText().toString()) - 100));
} else {
et_value_m11.setText("1100");
}
});
tv_value_add_m11.setOnClickListener(v -> {
if (Integer.parseInt(et_value_m11.getText().toString()) <= 1800) {
et_value_m11.setText(String.valueOf(Integer.parseInt(et_value_m11.getText().toString()) + 100));
} else {
et_value_m11.setText("1900");
}
});
tv_off_minus_m11.setOnClickListener(v -> {
if (Integer.parseInt(et_off_m11.getText().toString()) >= 1200) {
et_off_m11.setText(String.valueOf(Integer.parseInt(et_off_m11.getText().toString()) - 100));
} else {
et_off_m11.setText("1100");
}
});
tv_off_add_m11.setOnClickListener(v -> {
if (Integer.parseInt(et_off_m11.getText().toString()) <= 1800) {
et_off_m11.setText(String.valueOf(Integer.parseInt(et_off_m11.getText().toString()) + 100));
} else {
et_off_m11.setText("1900");
}
});
tv_value_minus_m12.setOnClickListener(v -> {
if (Integer.parseInt(et_value_m12.getText().toString()) >= 1200) {
et_value_m12.setText(String.valueOf(Integer.parseInt(et_value_m12.getText().toString()) - 100));
} else {
et_value_m12.setText("1100");
}
});
tv_value_add_m12.setOnClickListener(v -> {
if (Integer.parseInt(et_value_m12.getText().toString()) <= 1800) {
et_value_m12.setText(String.valueOf(Integer.parseInt(et_value_m12.getText().toString()) + 100));
} else {
et_value_m12.setText("1900");
}
});
tv_off_minus_m12.setOnClickListener(v -> {
if (Integer.parseInt(et_off_m12.getText().toString()) >= 1200) {
et_off_m12.setText(String.valueOf(Integer.parseInt(et_off_m12.getText().toString()) - 100));
} else {
et_off_m12.setText("1100");
}
});
tv_off_add_m12.setOnClickListener(v -> {
if (Integer.parseInt(et_off_m12.getText().toString()) <= 1800) {
et_off_m12.setText(String.valueOf(Integer.parseInt(et_off_m12.getText().toString()) + 100));
} else {
et_off_m12.setText("1900");
}
});
tv_value_minus_m13.setOnClickListener(v -> {
if (Integer.parseInt(et_value_m13.getText().toString()) >= 1200) {
et_value_m13.setText(String.valueOf(Integer.parseInt(et_value_m13.getText().toString()) - 100));
} else {
et_value_m13.setText("1100");
}
});
tv_value_add_m13.setOnClickListener(v -> {
if (Integer.parseInt(et_value_m13.getText().toString()) <= 1800) {
et_value_m13.setText(String.valueOf(Integer.parseInt(et_value_m13.getText().toString()) + 100));
} else {
et_value_m13.setText("1900");
}
});
tv_off_minus_m13.setOnClickListener(v -> {
if (Integer.parseInt(et_off_m13.getText().toString()) >= 1200) {
et_off_m13.setText(String.valueOf(Integer.parseInt(et_off_m13.getText().toString()) - 100));
} else {
et_off_m13.setText("1100");
}
});
tv_off_add_m13.setOnClickListener(v -> {
if (Integer.parseInt(et_off_m13.getText().toString()) <= 1800) {
et_off_m13.setText(String.valueOf(Integer.parseInt(et_off_m13.getText().toString()) + 100));
} else {
et_off_m13.setText("1900");
}
});
// 修改所有的Spinner监听器以sp_m7为例
sp_m7.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@SuppressLint("SetTextI18n")
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Log.d("无事发生", "onItemSelected: sp_m7");
tv_fly_m7.setText( parent.getSelectedItem().toString());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
Log.d("无事发生", "onNothingSelected: sp_m7");
}
});
// 对其他Spinner也做同样处理例如sp_m8:
sp_m8.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@SuppressLint("SetTextI18n")
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Log.d("无事发生", "onItemSelected: sp_m8");
tv_fly_m8.setText( parent.getSelectedItem().toString());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
Log.d("无事发生", "onNothingSelected: sp_m8");
}
});
// 对sp_m9到sp_m13都做相同处理
sp_m9.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@SuppressLint("SetTextI18n")
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
tv_fly_m9.setText( parent.getSelectedItem().toString());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
sp_m10.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@SuppressLint("SetTextI18n")
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
tv_fly_m10.setText( parent.getSelectedItem().toString());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
sp_m11.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@SuppressLint("SetTextI18n")
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
tv_fly_m11.setText( parent.getSelectedItem().toString());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
sp_m12.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@SuppressLint("SetTextI18n")
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
tv_fly_m12.setText( parent.getSelectedItem().toString());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
sp_m13.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@SuppressLint("SetTextI18n")
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
tv_fly_m13.setText( parent.getSelectedItem().toString());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
//保存
tv_save.setOnClickListener(v -> {
save();
});
}
/**
* 方法初始化flyTextView点击事件
* 点击TextView后会打开对应的Spinner
*
* @cuijingzhou
*/
private void initFlyTextViewClickListeners() {
TextView[] flyTextViews = {
tv_fly_m7, tv_fly_m8, tv_fly_m9, tv_fly_m10,
tv_fly_m11, tv_fly_m12, tv_fly_m13
};
Spinner[] correspondingSpinners = {
sp_m7, sp_m8, sp_m9, sp_m10,
sp_m11, sp_m12, sp_m13
};
for (int i = 0; i < flyTextViews.length; i++) {
final Spinner correspondingSpinner = correspondingSpinners[i];
if (flyTextViews[i] != null && correspondingSpinner != null) {
flyTextViews[i].setOnClickListener(v -> {
// 点击TextView后打开对应的Spinner
correspondingSpinner.performClick();
});
}
}
}
/**
* 方法初始化Spinner数据
*
* @cuijingzhou
*/
private void initSpinnerData() {
// 创建通道数据列表
List<ChannelItem> channelList = new ArrayList<>();
for (int i = 7; i <= 14; i++) {
channelList.add(new ChannelItem("通道" + i, 51 + (i - 7)));
}
// 创建适配器
ArrayAdapter<ChannelItem> adapter = new ArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, channelList);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// 为所有Spinner设置适配器
Spinner[] spinners = {sp_m7, sp_m8, sp_m9, sp_m10, sp_m11, sp_m12, sp_m13};
for (Spinner spinner : spinners) {
if (spinner != null) {
spinner.setAdapter(adapter);
}
}
}
/**
* 方法初始化Spinner选择监听器
*
* @cuijingzhou
*/
private void initSpinnerListeners() {
// 为所有Spinner设置选择监听器
// Spinner[] spinners = {sp_m7, sp_m8, sp_m9, sp_m10, sp_m11, sp_m12, sp_m13};
//
// AdapterView.OnItemSelectedListener spinnerListener = new AdapterView.OnItemSelectedListener() {
// @Override
// public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// Spinner spinner = (Spinner) parent;
// ChannelItem selectedItem = (ChannelItem) parent.getItemAtPosition(position);
// // 更新对应的TextView显示选中的通道
// updateChannelTextView(spinner, selectedItem);
// }
//
// @Override
// public void onNothingSelected(AdapterView<?> parent) {
// // 什么都不做
// }
// };
//
// // 为每个Spinner设置监听器
// for (Spinner spinner : spinners) {
// if (spinner != null) {
// spinner.setOnItemSelectedListener(spinnerListener);
// }
// }
}
// 示例获取sp_m7选中的值
private int getSelectedChannelValue(Spinner spinner) {
if (spinner.getSelectedItem() instanceof ChannelItem) {
ChannelItem item = (ChannelItem) spinner.getSelectedItem();
return item.getValue();
}
return 0; // 默认值
}
// 示例设置Spinner选中项
private void setSelectedChannel(Spinner spinner, int value) {
ArrayAdapter<ChannelItem> adapter = (ArrayAdapter<ChannelItem>) spinner.getAdapter();
for (int i = 0; i < adapter.getCount(); i++) {
ChannelItem item = adapter.getItem(i);
if (item != null && item.getValue() == value) {
spinner.setSelection(i);
break;
}
}
}
private void initTexts(View view) {
// 打开值EditText数组
flyTextViews = new TextView[]{
tv_fly_m7,
tv_fly_m8,
tv_fly_m9,
tv_fly_m10,
tv_fly_m11,
tv_fly_m12,
tv_fly_m13
};
// 打开值EditText数组
valueEditTexts = new EditText[]{
view.findViewById(R.id.et_value_m7),
view.findViewById(R.id.et_value_m8),
view.findViewById(R.id.et_value_m9),
view.findViewById(R.id.et_value_m10),
view.findViewById(R.id.et_value_m11),
view.findViewById(R.id.et_value_m12),
view.findViewById(R.id.et_value_m13)
};
// 关闭值EditText数组
offEditTexts = new EditText[]{
view.findViewById(R.id.et_off_m7),
view.findViewById(R.id.et_off_m8),
view.findViewById(R.id.et_off_m9),
view.findViewById(R.id.et_off_m10),
view.findViewById(R.id.et_off_m11),
view.findViewById(R.id.et_off_m12),
view.findViewById(R.id.et_off_m13)
};
}
private void setupInputFilters() {
// 为所有EditText设置输入过滤器
for (EditText et : valueEditTexts) {
if (et != null) {
setInputFilter(et);
}
}
for (EditText et : offEditTexts) {
if (et != null) {
setInputFilter(et);
}
}
}
private void setInputFilter(EditText editText) {
// 设置输入类型为数字
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
// 添加文本监听器验证范围
editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) { // 失去焦点时验证
validateAndCorrectInput(editText);
}
}
});
// 添加文本变化监听器
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
// 可以在这里添加实时验证逻辑
}
});
}
private void validateAndCorrectInput(EditText editText) {
String input = editText.getText().toString().trim();
// 如果输入为空设置默认值
if (input.isEmpty()) {
editText.setText("1100");
return;
}
try {
int value = Integer.parseInt(input);
// 检查范围
if (value < 1100) {
editText.setText("1100");
} else if (value > 1900) {
editText.setText("1900");
}
} catch (NumberFormatException e) {
// 如果解析失败设置默认值
editText.setText("1100");
}
}
private void initDataView() {
for (int i = 0; i < valueEditTexts.length; i++) {
valueEditTexts[i].setText(flyVoid.paramList.get("SERVO" + (i + 7) + "_MAX").getParam_value());
}
for (int i = 0; i < offEditTexts.length; i++) {
offEditTexts[i].setText(flyVoid.paramList.get("SERVO" + (i + 7) + "_MIN").getParam_value());
}
for (int i = 0; i < flyTextViews.length; i++) {
String flyText = flyVoid.paramList.get("SERVO" + (i + 7) + "_FUNCTION").getParam_value();
Log.d("flyTextViews", i + "++" + flyText);
switch (flyText) {
case "51":
setSelectedChannel(sp_m7, Integer.parseInt(flyText));
flyTextViews[i].setText("通道7");
break;
case "52":
setSelectedChannel(sp_m8, Integer.parseInt(flyText));
flyTextViews[i].setText("通道8");
break;
case "53":
setSelectedChannel(sp_m9, Integer.parseInt(flyText));
flyTextViews[i].setText("通道9");
break;
case "54":
setSelectedChannel(sp_m10, Integer.parseInt(flyText));
flyTextViews[i].setText("通道10");
break;
case "55":
setSelectedChannel(sp_m11, Integer.parseInt(flyText));
flyTextViews[i].setText("通道11");
break;
case "56":
setSelectedChannel(sp_m12, Integer.parseInt(flyText));
flyTextViews[i].setText("通道12");
break;
default:
setSelectedChannel(sp_m13, Integer.parseInt(flyText));
flyTextViews[i].setText("通道13");
break;
}
}
Log.d("无事发生", "加载完成: ");
}
/**
* 方法保存数据
*
* @cuijingzhou
*/
private void save() {
flyVoid.requestParamSet("SERVO7_FUNCTION", getSelectedChannelValue(sp_m7) + "");
flyVoid.requestParamSet("SERVO7_MAX", et_value_m7.getText().toString());
flyVoid.requestParamSet("SERVO7_MIN", et_value_m7.getText().toString());
flyVoid.requestParamSet("SERVO8_FUNCTION", getSelectedChannelValue(sp_m8) + "");
flyVoid.requestParamSet("SERVO8_MAX", et_value_m8.getText().toString());
flyVoid.requestParamSet("SERVO8_MIN", et_value_m8.getText().toString());
flyVoid.requestParamSet("SERVO9_FUNCTION", getSelectedChannelValue(sp_m9) + "");
flyVoid.requestParamSet("SERVO9_MAX", et_value_m9.getText().toString());
flyVoid.requestParamSet("SERVO9_MIN", et_value_m9.getText().toString());
flyVoid.requestParamSet("SERVO10_FUNCTION", getSelectedChannelValue(sp_m10) + "");
flyVoid.requestParamSet("SERVO10_MAX", et_value_m10.getText().toString());
flyVoid.requestParamSet("SERVO10_MIN", et_value_m10.getText().toString());
flyVoid.requestParamSet("SERVO11_FUNCTION", getSelectedChannelValue(sp_m11) + "");
flyVoid.requestParamSet("SERVO11_MAX", et_value_m11.getText().toString());
flyVoid.requestParamSet("SERVO11_MIN", et_value_m11.getText().toString());
flyVoid.requestParamSet("SERVO12_FUNCTION", getSelectedChannelValue(sp_m12) + "");
flyVoid.requestParamSet("SERVO12_MAX", et_value_m12.getText().toString());
flyVoid.requestParamSet("SERVO12_MIN", et_value_m12.getText().toString());
flyVoid.requestParamSet("SERVO13_FUNCTION", getSelectedChannelValue(sp_m13) + "");
flyVoid.requestParamSet("SERVO13_MAX", et_value_m13.getText().toString());
flyVoid.requestParamSet("SERVO13_MIN", et_value_m13.getText().toString());
Toast.makeText(getActivity(), "保存成功!", Toast.LENGTH_SHORT).show();
}
@Override
public void onResume() {
super.onResume();
// 使用post方法将initData()推迟到下一个UI循环执行避免FragmentManager冲突
getView().post(new Runnable() {
@Override
public void run() {
initData();
initView();
initOnClick();
}
});
}
@Override
public void onDestroyView() {
super.onDestroyView();
// 清理TabLayoutMediator资源
if (tabLayoutMediator != null) {
tabLayoutMediator.detach();
tabLayoutMediator = null;
}
}
}

View File

@ -49,7 +49,9 @@ public class MotorFragment extends Fragment {
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_motor, container, false);
initData();
initView(view);
initOnClick();
return view;
@ -221,8 +223,6 @@ public class MotorFragment extends Fragment {
@Override
public void onResume() {
super.onResume();
initData();
initView(view);
initOnClick();
}
}

View File

@ -5,24 +5,39 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.example.longyi_groundstation.Main.Setting.Adapter.SecurePagerAdapter;
import com.example.longyi_groundstation.Main.Setting.Fragment.Secure.PayloadFragment;
import com.example.longyi_groundstation.Main.Void.MyTool;
import com.example.longyi_groundstation.R;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
public class SecureFragment extends Fragment {
private View view;
private TextView tv_one_power_minus;
private SeekBar seekBar_one_power;
private TextView tv_one_power_add;
private TextView tv_one_power;
private TextView tv_two_power_minus;
private SeekBar seekBar_two_power;
private TextView tv_two_power_add;
private TextView tv_two_power;
private TextView tv_link_minus;
private EditText et_link;
private TextView tv_link_add;
private TextView tv_link;
private Spinner sp_one_power_protect;
private Spinner sp_two_power_protect;
private Spinner sp_link_protect;
private TextView tv_one_power_protect;
private TextView tv_two_power_protect;
private TextView tv_link_protect;
@SuppressLint("MissingInflatedId")
@ -31,7 +46,9 @@ public class SecureFragment extends Fragment {
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_secure, container, false);
initData();
initView(view);
initOnClick();
return view;
}
@ -49,7 +66,28 @@ public class SecureFragment extends Fragment {
*
* @cuijingzhou
*/
private void initView() {
private void initView(View view) {
tv_one_power_minus = view.findViewById(R.id.tv_one_power_minus);
seekBar_one_power = view.findViewById(R.id.seekBar_one_power);
tv_one_power_add = view.findViewById(R.id.tv_one_power_add);
tv_one_power = view.findViewById(R.id.tv_one_power);
tv_two_power_minus = view.findViewById(R.id.tv_two_power_minus);
seekBar_two_power = view.findViewById(R.id.seekBar_two_power);
tv_two_power_add = view.findViewById(R.id.tv_two_power_add);
tv_two_power = view.findViewById(R.id.tv_two_power);
tv_link_minus = view.findViewById(R.id.tv_link_minus);
et_link = view.findViewById(R.id.et_link);
tv_link_add = view.findViewById(R.id.tv_link_add);
tv_link = view.findViewById(R.id.tv_link);
sp_one_power_protect = view.findViewById(R.id.sp_one_power_protect);
sp_two_power_protect = view.findViewById(R.id.sp_two_power_protect);
sp_link_protect = view.findViewById(R.id.sp_link_protect);
tv_one_power_protect = view.findViewById(R.id.tv_one_power_protect);
tv_two_power_protect = view.findViewById(R.id.tv_two_power_protect);
tv_link_protect = view.findViewById(R.id.tv_link_protect);
//初始化
initSpinners();
}
@ -60,13 +98,204 @@ public class SecureFragment extends Fragment {
*/
private void initOnClick() {
// 修改一级电压的加减按钮和SeekBar监听事件
tv_one_power_minus.setOnClickListener(v -> {
int progress = seekBar_one_power.getProgress();
if (progress > 0) {
seekBar_one_power.setProgress(progress - 1);
// 直接更新文本显示
double voltage = (progress - 1) * 0.5;
tv_one_power.setText(String.format("%.1fV", voltage));
}
});
tv_one_power_add.setOnClickListener(v -> {
int progress = seekBar_one_power.getProgress();
if (progress < 100) {
seekBar_one_power.setProgress(progress + 1);
// 直接更新文本显示
double voltage = (progress + 1) * 0.5;
tv_one_power.setText(String.format("%.1fV", voltage));
}
});
seekBar_one_power.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// 将进度(0-100)转换为电压值(0-50.0V)
double voltage = progress * 0.5;
tv_one_power.setText(String.format("%.1fV", voltage));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
// 修改二级电压的加减按钮和SeekBar监听事件
tv_two_power_minus.setOnClickListener(v -> {
int progress = seekBar_two_power.getProgress();
if (progress > 0) {
seekBar_two_power.setProgress(progress - 1);
// 直接更新文本显示
double voltage = (progress - 1) * 0.5;
tv_two_power.setText(String.format("%.1fV", voltage));
}
});
tv_two_power_add.setOnClickListener(v -> {
int progress = seekBar_two_power.getProgress();
if (progress < 100) {
seekBar_two_power.setProgress(progress + 1);
// 直接更新文本显示
double voltage = (progress + 1) * 0.5;
tv_two_power.setText(String.format("%.1fV", voltage));
}
});
seekBar_two_power.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// 将进度(0-100)转换为电压值(0-50.0V)
double voltage = progress * 0.5;
tv_two_power.setText(String.format("%.1fV", voltage));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
tv_link_minus.setOnClickListener(v -> {
try {
String currentText = et_link.getText().toString().trim();
if (!currentText.isEmpty()) {
int currentValue = Integer.parseInt(currentText);
if (currentValue > 0) { // 防止出现负数可根据需要调整
et_link.setText(String.valueOf(currentValue - 1));
}
} else {
et_link.setText("0");
}
} catch (NumberFormatException e) {
et_link.setText("0");
}
});
tv_link_add.setOnClickListener(v -> {
try {
String currentText = et_link.getText().toString().trim();
if (!currentText.isEmpty()) {
int currentValue = Integer.parseInt(currentText);
et_link.setText(String.valueOf(currentValue + 1));
} else {
et_link.setText("1");
}
} catch (NumberFormatException e) {
et_link.setText("1");
}
});
// 为Spinner设置选择监听器
sp_one_power_protect.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
tv_one_power_protect.setText(parent.getItemAtPosition(position).toString());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// 什么都不做
}
});
sp_two_power_protect.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
tv_two_power_protect.setText(parent.getItemAtPosition(position).toString());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// 什么都不做
}
});
sp_link_protect.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
tv_link_protect.setText(parent.getItemAtPosition(position).toString());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// 什么都不做
}
});
tv_one_power_protect.setOnClickListener(v -> {
sp_one_power_protect.performClick();
});
tv_two_power_protect.setOnClickListener(v -> {
sp_two_power_protect.performClick();
});
tv_link_protect.setOnClickListener(v -> {
sp_link_protect.performClick();
});
}
private void initSpinners() {
// 一级电压保护动作Spinner
String[] onePowerOptions = {"返航", "降落", "继续飞行"};
ArrayAdapter<String> onePowerAdapter = new ArrayAdapter<>(getContext(),
android.R.layout.simple_spinner_item, onePowerOptions);
onePowerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
sp_one_power_protect.setAdapter(onePowerAdapter);
// 二级电压保护动作Spinner
String[] twoPowerOptions = {"降落"};
ArrayAdapter<String> twoPowerAdapter = new ArrayAdapter<>(getContext(),
android.R.layout.simple_spinner_item, twoPowerOptions);
twoPowerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
sp_two_power_protect.setAdapter(twoPowerAdapter);
// 链路保护动作Spinner
String[] linkOptions = {"返航", "继续飞行"};
ArrayAdapter<String> linkAdapter = new ArrayAdapter<>(getContext(),
android.R.layout.simple_spinner_item, linkOptions);
linkAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
sp_link_protect.setAdapter(linkAdapter);
}
@Override
public void onResume() {
super.onResume();
initData();
initView();
initOnClick();
}
}

View File

@ -34,7 +34,9 @@ public class SensorFragment extends Fragment {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_sensor, container, false);
initData();
initView(view);
initOnClick();
return view;
}
@ -785,9 +787,7 @@ public class SensorFragment extends Fragment {
@Override
public void onResume() {
super.onResume();
initData();
initView(view);
initOnClick();
}
}

View File

@ -86,9 +86,9 @@ public class SettingsFragment extends Fragment {
view = inflater.inflate(R.layout.fragment_settings, container, false);
initData();
initView(view);
initOnClick();
return view;
}
@ -140,7 +140,6 @@ public class SettingsFragment extends Fragment {
selectIndex_item = 0;
paramsList.get(0).setSelect(true);
if (paramAdapter != null) {
MyTool.hideBottomNavigationBar(getActivity());
paramAdapter.notifyDataSetChanged();
}
@ -338,7 +337,7 @@ public class SettingsFragment extends Fragment {
rl_password.setVisibility(View.GONE);
ViewTool.closeKeyboard(getActivity());
}
MyTool.hideBottomNavigationBar(getActivity());
}
}
@ -377,7 +376,7 @@ public class SettingsFragment extends Fragment {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
MyTool.hideBottomNavigationBar(getActivity());
}
return false;
}
@ -448,7 +447,7 @@ public class SettingsFragment extends Fragment {
}
}
if (getActivity() != null) {
MyTool.hideBottomNavigationBar(getActivity());
}
ProgressDialogUtil.dismissProgressDialog();
} catch (InterruptedException e) {
@ -471,9 +470,7 @@ public class SettingsFragment extends Fragment {
// myReceiver_PARAM_VALUE.isReceiverRegistered = false;
// }
initData();
initView(view);
initOnClick();
}

View File

@ -0,0 +1,111 @@
package com.example.longyi_groundstation.Main.View;
import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_TAKEOFF;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.example.longyi_groundstation.MAVLink.common.msg_command_long;
import com.example.longyi_groundstation.Main.Service.MyBoundService;
import com.example.longyi_groundstation.Main.Void.FlyVoid;
import com.example.longyi_groundstation.Main.Void.MyTool;
import com.example.longyi_groundstation.R;
public class BombingDialog {
private final Activity context;
private String title;
private String message;
private String positiveButtonText;
private FlyVoid flyVoid = new FlyVoid();
public BombingDialog(Activity context) {
this.context = context;
this.title = "投弹";
this.message = "";
this.positiveButtonText = "确定";
}
// 设置弹窗标题
public BombingDialog setTitle(String title) {
this.title = title;
return this;
}
// 设置弹窗内容
public BombingDialog setMessage(String message) {
this.message = message;
return this;
}
// 设置确认按钮文字
public BombingDialog setPositiveButtonText(String text) {
this.positiveButtonText = text;
return this;
}
// 显示弹窗
public void show() {
MyTool.hideBottomNavigationBar( context);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
// 使用自定义布局
View view = LayoutInflater.from(context).inflate(R.layout.dialog_bombing, null);
@SuppressLint({"MissingInflatedId", "LocalSuppress"}) TextView tvMessage = view.findViewById(R.id.tv_message);
// 滑动模块
@SuppressLint({"MissingInflatedId", "LocalSuppress"}) SlideToUnlockView unlockView = view.findViewById(R.id.unlockView);
// 高度输入
@SuppressLint({"MissingInflatedId", "LocalSuppress"}) EditText et_height = view.findViewById(R.id.et_height);
// 添加日志
builder.setView(view);
AlertDialog dialog = builder.create();
dialog.show();
// 设置宽高
Window window = dialog.getWindow();
if (window != null) {
WindowManager.LayoutParams layoutParams = window.getAttributes();
layoutParams.width = MyTool.dpToPx(context, 300); // 或具体像素值
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; // 或具体像素值
window.setAttributes(layoutParams);
window.setBackgroundDrawableResource(R.drawable.ffffffff_4round_bg);
}
unlockView.setText("滑动执行");
unlockView.setOnUnlockListener(new SlideToUnlockView.OnUnlockListener() {
@Override
public void onUnlock() {
// 发送命令
// flyVoid.sendMavlinkMessage(MyBoundService.type,command);
flyVoid.requestBombing(et_height.getText().toString());
dialog.dismiss();
// 滑动到阈值后触发如关闭对话框或执行操作
Toast.makeText(context, "操作已确认", Toast.LENGTH_SHORT).show();
MyTool.hideBottomNavigationBar(context);
}
});
;
//取消按钮
tvMessage.setOnClickListener(v -> {
dialog.dismiss();
MyTool.hideBottomNavigationBar(context);
});
}
}

View File

@ -0,0 +1,136 @@
// 修改 CustomSeekBar.java 文件
package com.example.longyi_groundstation.Main.View;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class CustomSeekBar extends View {
private Paint backgroundPaint;
private Paint progressPaint;
private Paint thumbPaint;
private Paint progressBgPaint;
private float progress = 0f; // 0.0f to 1.0f
private float thumbRadius = 15f; // 减小拖拽按钮半径从30f改为15f
private float barHeight = 8f; // 减小进度条高度从12f改为8f
private float cornerRadius = 4f; // 调整圆角半径
private OnProgressChangeListener listener;
public interface OnProgressChangeListener {
void onProgressChanged(float progress);
}
public CustomSeekBar(Context context) {
super(context);
init();
}
public CustomSeekBar(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomSeekBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
// 背景画笔进度条背景
backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
backgroundPaint.setColor(Color.parseColor("#404040"));
// 进度背景画笔
progressBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
progressBgPaint.setColor(Color.parseColor("#606060"));
// 进度画笔
progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
progressPaint.setColor(Color.parseColor("#4CAF50")); // 绿色进度条
// 拖拽按钮画笔
thumbPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
thumbPaint.setColor(Color.WHITE);
thumbPaint.setShadowLayer(4.0f, 0.0f, 2.0f, Color.argb(100, 0, 0, 0)); // 添加阴影效果
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float width = getWidth();
float height = getHeight();
float centerY = height / 2f;
// 绘制进度条背景
RectF bgRect = new RectF(thumbRadius, centerY - barHeight/2, width - thumbRadius, centerY + barHeight/2);
canvas.drawRoundRect(bgRect, cornerRadius, cornerRadius, backgroundPaint);
// 绘制进度背景
float progressWidth = (width - 2 * thumbRadius) * progress;
if (progressWidth > 0) {
RectF progressRect = new RectF(thumbRadius, centerY - barHeight/2, thumbRadius + progressWidth, centerY + barHeight/2);
canvas.drawRoundRect(progressRect, cornerRadius, cornerRadius, progressPaint);
}
// 绘制拖拽按钮
float thumbX = thumbRadius + progressWidth;
canvas.drawCircle(thumbX, centerY, thumbRadius, thumbPaint);
// 注意这里移除了百分比文字的绘制
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float width = getWidth();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
// 限制x在有效范围内
x = Math.max(thumbRadius, Math.min(width - thumbRadius, x));
progress = (x - thumbRadius) / (width - 2 * thumbRadius);
// 确保进度在0-1范围内
progress = Math.max(0f, Math.min(1f, progress));
invalidate();
if (listener != null) {
listener.onProgressChanged(progress);
}
return true;
}
return super.onTouchEvent(event);
}
public void setProgress(float progress) {
this.progress = Math.max(0f, Math.min(1f, progress));
invalidate();
}
public float getProgress() {
return progress;
}
public void setOnProgressChangeListener(OnProgressChangeListener listener) {
this.listener = listener;
}
}

View File

@ -0,0 +1,319 @@
package com.example.longyi_groundstation.Main.View;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
public class DpadView extends View {
private Paint paint;
private Path upButtonPath;
private Path downButtonPath;
private Path leftButtonPath;
private Path rightButtonPath;
// Regions for touch detection
private Region upButtonRegion;
private Region downButtonRegion;
private Region leftButtonRegion;
private Region rightButtonRegion;
private int upButtonColor = Color.GRAY;
private int downButtonColor = Color.GRAY;
private int leftButtonColor = Color.GRAY;
private int rightButtonColor = Color.GRAY;
private OnDpadButtonClickListener listener;
// Button states (pressed or not)
private boolean upPressed = false;
private boolean downPressed = false;
private boolean leftPressed = false;
private boolean rightPressed = false;
public DpadView(Context context) {
super(context);
init();
}
public DpadView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public DpadView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
upButtonPath = new Path();
downButtonPath = new Path();
leftButtonPath = new Path();
rightButtonPath = new Path();
upButtonRegion = new Region();
downButtonRegion = new Region();
leftButtonRegion = new Region();
rightButtonRegion = new Region();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
int centerX = width / 2;
int centerY = height / 2;
int buttonWidth = Math.min(width, height) / 5;
int buttonHeight = Math.min(width, height) / 3;
// Clear paths
upButtonPath.reset();
downButtonPath.reset();
leftButtonPath.reset();
rightButtonPath.reset();
// Draw up button (rectangle)
upButtonPath.addRect(
centerX - buttonWidth/2,
centerY - buttonHeight/2 - buttonHeight/3,
centerX + buttonWidth/2,
centerY - buttonHeight/2 + buttonHeight/3,
Path.Direction.CW
);
paint.setColor(upPressed ? darkenColor(upButtonColor) : upButtonColor);
canvas.drawPath(upButtonPath, paint);
// Draw down button (rectangle)
downButtonPath.addRect(
centerX - buttonWidth/2,
centerY + buttonHeight/2 - buttonHeight/3,
centerX + buttonWidth/2,
centerY + buttonHeight/2 + buttonHeight/3,
Path.Direction.CW
);
paint.setColor(downPressed ? darkenColor(downButtonColor) : downButtonColor);
canvas.drawPath(downButtonPath, paint);
// Draw left button (rectangle)
leftButtonPath.addRect(
centerX - buttonHeight/2 - buttonHeight/3,
centerY - buttonWidth/2,
centerX - buttonHeight/2 + buttonHeight/3,
centerY + buttonWidth/2,
Path.Direction.CW
);
paint.setColor(leftPressed ? darkenColor(leftButtonColor) : leftButtonColor);
canvas.drawPath(leftButtonPath, paint);
// Draw right button (rectangle)
rightButtonPath.addRect(
centerX + buttonHeight/2 - buttonHeight/3,
centerY - buttonWidth/2,
centerX + buttonHeight/2 + buttonHeight/3,
centerY + buttonWidth/2,
Path.Direction.CW
);
paint.setColor(rightPressed ? darkenColor(rightButtonColor) : rightButtonColor);
canvas.drawPath(rightButtonPath, paint);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// Update regions when size changes
updateButtonRegions();
}
private void updateButtonRegions() {
int width = getWidth();
int height = getHeight();
int centerX = width / 2;
int centerY = height / 2;
int buttonWidth = Math.min(width, height) / 5;
int buttonHeight = Math.min(width, height) / 3;
// Define regions for touch detection
Path tempPath = new Path();
// Up button region
tempPath.reset();
tempPath.addRect(
centerX - buttonWidth/2,
centerY - buttonHeight/2 - buttonHeight/3,
centerX + buttonWidth/2,
centerY - buttonHeight/2 + buttonHeight/3,
Path.Direction.CW
);
upButtonRegion.setPath(tempPath, new Region(0, 0, getWidth(), getHeight()));
// Down button region
tempPath.reset();
tempPath.addRect(
centerX - buttonWidth/2,
centerY + buttonHeight/2 - buttonHeight/3,
centerX + buttonWidth/2,
centerY + buttonHeight/2 + buttonHeight/3,
Path.Direction.CW
);
downButtonRegion.setPath(tempPath, new Region(0, 0, getWidth(), getHeight()));
// Left button region
tempPath.reset();
tempPath.addRect(
centerX - buttonHeight/2 - buttonHeight/3,
centerY - buttonWidth/2,
centerX - buttonHeight/2 + buttonHeight/3,
centerY + buttonWidth/2,
Path.Direction.CW
);
leftButtonRegion.setPath(tempPath, new Region(0, 0, getWidth(), getHeight()));
// Right button region
tempPath.reset();
tempPath.addRect(
centerX + buttonHeight/2 - buttonHeight/3,
centerY - buttonWidth/2,
centerX + buttonHeight/2 + buttonHeight/3,
centerY + buttonWidth/2,
Path.Direction.CW
);
rightButtonRegion.setPath(tempPath, new Region(0, 0, getWidth(), getHeight()));
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
handleTouch(x, y, true);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
handleTouch(x, y, false);
// Reset all buttons
upPressed = false;
downPressed = false;
leftPressed = false;
rightPressed = false;
invalidate();
break;
}
return true;
}
private void handleTouch(float x, float y, boolean pressed) {
boolean upWasPressed = upPressed;
boolean downWasPressed = downPressed;
boolean leftWasPressed = leftPressed;
boolean rightWasPressed = rightPressed;
// Check which button is pressed using regions
upPressed = upButtonRegion.contains((int)x, (int)y) && pressed;
downPressed = downButtonRegion.contains((int)x, (int)y) && pressed;
leftPressed = leftButtonRegion.contains((int)x, (int)y) && pressed;
rightPressed = rightButtonRegion.contains((int)x, (int)y) && pressed;
// Notify listeners of changes
if (listener != null) {
if (upPressed && !upWasPressed) {
listener.onUpButtonClicked();
} else if (!upPressed && upWasPressed) {
listener.onUpButtonReleased();
}
if (downPressed && !downWasPressed) {
listener.onDownButtonClicked();
} else if (!downPressed && downWasPressed) {
listener.onDownButtonReleased();
}
if (leftPressed && !leftWasPressed) {
listener.onLeftButtonClicked();
} else if (!leftPressed && leftWasPressed) {
listener.onLeftButtonReleased();
}
if (rightPressed && !rightWasPressed) {
listener.onRightButtonClicked();
} else if (!rightPressed && rightWasPressed) {
listener.onRightButtonReleased();
}
}
// Redraw if any state changed
if (upWasPressed != upPressed || downWasPressed != downPressed ||
leftWasPressed != leftPressed || rightWasPressed != rightPressed) {
invalidate();
}
}
// Helper method to darken color when pressed
private int darkenColor(int color) {
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] *= 0.8f; // Reduce brightness
return Color.HSVToColor(hsv);
}
// Set button colors
public void setUpButtonColor(int color) {
this.upButtonColor = color;
invalidate();
}
public void setDownButtonColor(int color) {
this.downButtonColor = color;
invalidate();
}
public void setLeftButtonColor(int color) {
this.leftButtonColor = color;
invalidate();
}
public void setRightButtonColor(int color) {
this.rightButtonColor = color;
invalidate();
}
// Set click listener
public void setOnDpadButtonClickListener(OnDpadButtonClickListener listener) {
this.listener = listener;
}
// Interface for button click events
public interface OnDpadButtonClickListener {
void onUpButtonClicked();
void onUpButtonReleased();
void onDownButtonClicked();
void onDownButtonReleased();
void onLeftButtonClicked();
void onLeftButtonReleased();
void onRightButtonClicked();
void onRightButtonReleased();
}
}

View File

@ -81,27 +81,12 @@ public class LandDialog {
}
unlockView.setText("滑动返航");
unlockView.setText("滑动降落");
unlockView.setOnUnlockListener(new SlideToUnlockView.OnUnlockListener() {
@Override
public void onUnlock() {
// 构造命令
// msg_command_long command = new msg_command_long();
// command.target_system = 1; // 目标系统ID飞控
// command.target_component = 1; // 目标组件ID
// command.command = MAV_CMD_NAV_RETURN_TO_LAUNCH; // 返航命令
// command.confirmation = 0; // 确认位
// command.param1 = 0; // 通常不需要参数
// command.param2 = 0;
// command.param3 = 0;
// command.param4 = 0;
// command.param5 = 0;
// command.param6 = 0;
// command.param7 = 0;
//
// // 发送命令
// flyVoid.sendMavlinkMessage(MyBoundService.type, command);
flyVoid.requestLand();
MyTool.hideBottomNavigationBar( context);
dialog.dismiss();
// 滑动到阈值后触发如关闭对话框或执行操作

View File

@ -16,7 +16,7 @@ public class SlideToUnlockView extends View {
private RectF thumbRect = new RectF();
private OnUnlockListener listener;
private int bgColor = Color.parseColor("#cfcfcf");
private int activeColor = Color.parseColor("#49B6E7");
private int activeColor = Color.parseColor("#029A45");
private float thumbSize; // 滑块尺寸
private float minX, maxX; // 滑块X轴边界
@ -44,7 +44,7 @@ public class SlideToUnlockView extends View {
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(dpToPx(14));
textPaint.setTextSize(dpToPx(12));
textPaint.setTextAlign(Paint.Align.CENTER);
reboundAnimator = ValueAnimator.ofFloat(0, 1);

View File

@ -94,22 +94,21 @@ public class TakeOffDialog {
unlockView.setOnUnlockListener(new SlideToUnlockView.OnUnlockListener() {
@Override
public void onUnlock() {
msg_command_long command = new msg_command_long();
command.target_system = 1;
command.target_component = 1;
command.command = MAV_CMD_NAV_TAKEOFF;
command.confirmation = 0;
command.param1 = 0;
command.param2 = 0;
command.param3 = 0;
command.param4 = 0;
command.param5 = 0;
command.param6 = 0;
command.param7 = Float.parseFloat(et_height.getText().toString());
// 发送命令
flyVoid.sendMavlinkMessage(MyBoundService.type,command);
// msg_command_long command = new msg_command_long();
// command.target_system = 1;
// command.target_component = 1;
// command.command = MAV_CMD_NAV_TAKEOFF;
// command.confirmation = 0;
// command.param1 = 0;
// command.param2 = 0;
// command.param3 = 0;
// command.param4 = 0;
// command.param5 = 0;
// command.param6 = 0;
// command.param7 = Float.parseFloat(et_height.getText().toString());
// // 发送命令
// flyVoid.sendMavlinkMessage(MyBoundService.type,command);
flyVoid.requestTakeOff(et_height.getText().toString());
dialog.dismiss();
// 滑动到阈值后触发如关闭对话框或执行操作
Toast.makeText(context, "操作已确认", Toast.LENGTH_SHORT).show();

View File

@ -89,25 +89,26 @@ public class TurnBackDialog {
}
unlockView.setText("滑动降落");
unlockView.setText("滑动返航");
unlockView.setOnUnlockListener(new SlideToUnlockView.OnUnlockListener() {
@Override
public void onUnlock() {
// 构造命令
msg_command_long command = new msg_command_long();
command.target_system = 1;
command.target_component = 1;
command.command = MAV_CMD_NAV_LAND;
command.confirmation = 0;
command.param1 = 0;
command.param2 = 0;
command.param3 = 0;
command.param4 = 0;
command.param5 = 0;
command.param6 = 0;
command.param7 = 0;
// 发送命令
flyVoid.sendMavlinkMessage(MyBoundService.type, command);
// // 构造命令
// msg_command_long command = new msg_command_long();
// command.target_system = 1;
// command.target_component = 1;
// command.command = MAV_CMD_NAV_LAND;
// command.confirmation = 0;
// command.param1 = 0;
// command.param2 = 0;
// command.param3 = 0;
// command.param4 = 0;
// command.param5 = 0;
// command.param6 = 0;
// command.param7 = 0;
// // 发送命令
// flyVoid.sendMavlinkMessage(MyBoundService.type, command);
flyVoid.requestTurnBack();
MyTool.hideBottomNavigationBar( context);
dialog.dismiss();
// 滑动到阈值后触发如关闭对话框或执行操作

View File

@ -13,6 +13,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.amap.api.maps.MapView;
import com.example.longyi_groundstation.Main.View.AttitudeIndicatorView;
import com.example.longyi_groundstation.Main.View.CircularLinearLayout;
import com.example.longyi_groundstation.Main.View.DpadView;
import com.example.longyi_groundstation.R;
import com.skydroid.fpvplayer.FPVWidget;
@ -46,7 +47,7 @@ public class AllView {
public LinearLayout ll_icon_land;
public LinearLayout ll_mode_select;
public RecyclerView rv_error_list;
public LinearLayout ll_left_layout;
public LinearLayout ll_left_error_layout;
public LinearLayout ll_setting;
public ImageView iv_logo;
public TextView tv_param_load;
@ -64,6 +65,34 @@ public class AllView {
public LinearLayout ll_searchlight;
public LinearLayout ll_thoroughfare;
public LinearLayout ll_hook;
public ImageView iv_ptz_top;
public ImageView iv_ptz_left;
public ImageView iv_ptz_right;
public ImageView iv_ptz_bottom;
public LinearLayout ll_PTZ_one_center;
public LinearLayout ll_PTZ_amplify;
public LinearLayout ll_PTZ_reduce;
public LinearLayout ll_PTZ_focus_amplify;
public LinearLayout ll_PTZ_focus_reduce;
public LinearLayout ll_ptz_ctrl;
public LinearLayout ll_ptz_fun;
public LinearLayout ll_PTZ_one_bottom;
public LinearLayout ll_open_layout;
public LinearLayout ll_text;
public LinearLayout ll_link;
public LinearLayout ll_link_save;
public LinearLayout ll_link_fun1;
public LinearLayout ll_link_fun2;
public LinearLayout ll_link_back;
public LinearLayout ll_create_link_layout;
public RecyclerView rv_create_link_list;
public LinearLayout ll_all_link_layout;
public RecyclerView rv_all_link_list;
public LinearLayout ll_link_start;
public LinearLayout ll_link_start_fun1;
public LinearLayout ll_link_start_fun2;
public LinearLayout ll_link_start_back;
public AllView(Activity activity) {
@ -97,7 +126,7 @@ public class AllView {
ll_icon_land = activity.findViewById(R.id.ll_icon_land);
ll_mode_select = activity.findViewById(R.id.ll_mode_select);
rv_error_list = activity.findViewById(R.id.rv_error_list);
ll_left_layout = activity.findViewById(R.id.ll_left_layout);
ll_left_error_layout = activity.findViewById(R.id.ll_left_error_layout);
ll_setting = activity.findViewById(R.id.ll_setting);
iv_logo = activity.findViewById(R.id.iv_logo);
tv_param_load = activity.findViewById(R.id.tv_param_load);
@ -115,10 +144,34 @@ public class AllView {
ll_searchlight = activity.findViewById(R.id.ll_searchlight);
ll_thoroughfare = activity.findViewById(R.id.ll_thoroughfare);
ll_hook = activity.findViewById(R.id.ll_hook);
iv_ptz_top = activity.findViewById(R.id.iv_ptz_top);
iv_ptz_left = activity.findViewById(R.id.iv_ptz_left);
iv_ptz_right = activity.findViewById(R.id.iv_ptz_right);
iv_ptz_bottom = activity.findViewById(R.id.iv_ptz_bottom);
ll_PTZ_one_center = activity.findViewById(R.id.ll_PTZ_one_center);
ll_PTZ_amplify = activity.findViewById(R.id.ll_PTZ_amplify);
ll_PTZ_reduce = activity.findViewById(R.id.ll_PTZ_reduce);
ll_PTZ_focus_amplify = activity.findViewById(R.id.ll_PTZ_focus_amplify);
ll_PTZ_focus_reduce = activity.findViewById(R.id.ll_PTZ_focus_reduce);
ll_ptz_ctrl = activity.findViewById(R.id.ll_ptz_ctrl);
ll_ptz_fun = activity.findViewById(R.id.ll_ptz_fun);
ll_PTZ_one_bottom = activity.findViewById(R.id.ll_PTZ_one_bottom);
ll_open_layout = activity.findViewById(R.id.ll_open_layout);
ll_text= activity.findViewById(R.id.ll_text);
ll_link = activity.findViewById(R.id.ll_link);
ll_link_save = activity.findViewById(R.id.ll_link_save);
ll_link_fun1 = activity.findViewById(R.id.ll_link_fun1);
ll_link_fun2 = activity.findViewById(R.id.ll_link_fun2);
ll_link_back = activity.findViewById(R.id.ll_link_back);
ll_create_link_layout = activity.findViewById(R.id.ll_create_link_layout);
rv_create_link_list = activity.findViewById(R.id.rv_create_link_list);
ll_all_link_layout = activity.findViewById(R.id.ll_all_link_layout);
rv_all_link_list = activity.findViewById(R.id.rv_all_link_list);
ll_link_start = activity.findViewById(R.id.ll_link_start);
ll_link_start_fun1 = activity.findViewById(R.id.ll_link_start_fun1);
ll_link_start_fun2 = activity.findViewById(R.id.ll_link_start_fun2);
ll_link_start_back = activity.findViewById(R.id.ll_link_start_back);
// iv_line_fly = activity.findViewById(R.id.iv_line_fly);
}
}

View File

@ -0,0 +1,65 @@
package com.example.longyi_groundstation.Main.Void;
import android.util.Log;
import android.widget.Toast;
import com.example.longyi_groundstation.Main.Adapter.AllLinkAdapter;
import com.example.longyi_groundstation.Main.Void.XiangTuo.TcpClientUtil;
import java.util.List;
public class AllVoid {
/**
* 带重试机制的云台TCP连接方法
* 如果连接失败等待5秒后重试最多重试3次
*
* @param tcpClient TcpClientUtil实例
* @param host 主机地址
* @param port 端口号
* @param context 上下文对象用于显示Toast提示
* @param tag 日志标签
*/
public static void connectToPTZWithRetry(TcpClientUtil tcpClient, String host, int port, android.content.Context context, String tag) {
new Thread(() -> {
int maxRetries = 3;
int retryCount = 0;
while (retryCount < maxRetries) {
try {
if (tcpClient != null) {
tcpClient.connect(host, port);
// 连接成功跳出循环
((android.app.Activity) context).runOnUiThread(() -> {
Toast.makeText(context, "云台连接成功", Toast.LENGTH_SHORT).show();
});
break;
}
} catch (Exception e) {
retryCount++;
Log.e(tag, "云台连接失败,第" + retryCount + "次重试", e);
if (retryCount < maxRetries) {
((android.app.Activity) context).runOnUiThread(() -> {
Toast.makeText(context, "云台连接失败5秒后重试...", Toast.LENGTH_SHORT).show();
});
try {
Thread.sleep(5000); // 等待5秒
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
break;
}
} else {
// 最后一次重试也失败了
((android.app.Activity) context).runOnUiThread(() -> {
Toast.makeText(context, "云台连接失败,请检查设备", Toast.LENGTH_SHORT).show();
});
}
}
}
}).start();
}
}

View File

@ -1,5 +1,8 @@
package com.example.longyi_groundstation.Main.Void;
import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_LAND;
import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_RETURN_TO_LAUNCH;
import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_TAKEOFF;
import static com.example.longyi_groundstation.Main.Service.MyBoundService.type;
import android.content.Context;
@ -40,6 +43,8 @@ public class FlyVoid {
// 新增字段表示参数是否更新完成
private static volatile boolean isParamUpdateComplete = false;
public static int[] parseSerialData = null;
// 提供一个获取状态的方法
public static boolean isParamUpdateComplete() {
return isParamUpdateComplete;
@ -72,31 +77,6 @@ public class FlyVoid {
}
/**
* 通用MAVLink消息发送方法
*/
public void sendMavlinkMessage(int type,MAVLinkMessage msg) {
MAVLinkPacket packet = msg.pack();
if (type == 0) { // 串口
if (MyBoundService.serialHelper != null) {
MyBoundService.serialHelper.send(packet.encodePacket());
}
} else { // UDP
try {
InetAddress targetAddress = InetAddress.getByName("127.0.0.1"); // 改为飞控IP
DatagramPacket udpPacket = new DatagramPacket(
packet.encodePacket(),
packet.encodePacket().length,
targetAddress,
14553 // MAVLink标准端口
);
MyBoundService.serverSocket.send(udpPacket);
} catch (Exception e) {
Log.e("cuijinggzhou-发送", "发送失败: " + e.getMessage());
}
}
}
/**
@ -116,9 +96,8 @@ public class FlyVoid {
sendMavlinkMessage(type,request);
}
/**
* 设置参数 (MAVLINK_MSG_ID_PARAM_SET)
* 方法设置参数 (MAVLINK_MSG_ID_PARAM_SET)
*
* @cuijingzhou
*/
@ -133,8 +112,27 @@ public class FlyVoid {
paramSet.param_type = Short.parseShort(paramType); // 参数类型
// 发送命令
sendMavlinkMessage(MyBoundService.type,paramSet);
paramList.get(paramId).setParam_value(paramValue);
}
/**
* 方法设置参数 (MAVLINK_MSG_ID_PARAM_SET)
*
* @cuijingzhou
*/
public void requestParamSet(String paramId,String paramValue) {
msg_param_set paramSet = new msg_param_set();
paramSet.target_system = 1; // 目标系统ID (飞控)
paramSet.target_component = 1; // 目标组件ID
// 设置参数ID (最多16字符)
byte[] paramIdBytes = paramId.getBytes();
System.arraycopy(paramIdBytes, 0, paramSet.param_id, 0, Math.min(paramIdBytes.length, 16));
paramSet.param_value = Float.parseFloat(paramValue);// 参数值
paramSet.param_type = Short.parseShort(paramList.get(paramId).getParam_type()); // 参数类型
// 发送命令
sendMavlinkMessage(MyBoundService.type,paramSet);
paramList.get(paramId).setParam_value(paramValue);
}
/**
* 方法控制电机旋转 param1=电机ID param3=转速 param4=超时
@ -163,13 +161,159 @@ public class FlyVoid {
}
/**
* 方法起飞指令
*
* @cuijingzhou
*/
public void requestTakeOff(String height) {
msg_command_long command = new msg_command_long();
command.target_system = 1;
command.target_component = 1;
command.command = MAV_CMD_NAV_TAKEOFF;
command.confirmation = 0;
command.param1 = 0;
command.param2 = 0;
command.param3 = 0;
command.param4 = 0;
command.param5 = 0;
command.param6 = 0;
command.param7 = Float.parseFloat(height);
// 发送命令
sendMavlinkMessage(MyBoundService.type,command);
}
/**
* 方法返航指令
*
* @cuijingzhou
*/
public void requestTurnBack() {
// 构造命令
msg_command_long command = new msg_command_long();
command.target_system = 1;
command.target_component = 1;
command.command = MAV_CMD_NAV_RETURN_TO_LAUNCH;
command.confirmation = 0;
command.param1 = 0;
command.param2 = 0;
command.param3 = 0;
command.param4 = 0;
command.param5 = 0;
command.param6 = 0;
command.param7 = 0;
// 发送命令
sendMavlinkMessage(MyBoundService.type,command);
}
/**
* 方法降落指令
*
* @cuijingzhou
*/
public void requestLand() {
// 构造命令
msg_command_long command = new msg_command_long();
command.target_system = 1; // 目标系统ID飞控
command.target_component = 1; // 目标组件ID
command.command = MAV_CMD_NAV_LAND; // 返航命令
command.confirmation = 0; // 确认位
command.param1 = 0; // 通常不需要参数
command.param2 = 0;
command.param3 = 0;
command.param4 = 0;
command.param5 = 0;
command.param6 = 0;
command.param7 = 0;
// 发送命令
sendMavlinkMessage(MyBoundService.type,command);
}
/**
* 方法投弹
*
* @cuijingzhou
*/
public void requestBombing(String str) {
// 构造命令
byte byteData = SerialTool.decStringToHexByte(str);
byte byteData2 = SerialTool.calculateChecksum(byteData);
byte[] testData = new byte[]{(byte) 0xFF, byteData, byteData2};
Log.d("串口2发送的数据", SerialTool.bytesToHex(testData));
// 发送命令
sendMessage_com2(MyBoundService.type,testData);
}
/**
* 通用MAVLink消息发送方法-串口1 mavlink通道
*/
public void sendMavlinkMessage(int type,MAVLinkMessage msg) {
MAVLinkPacket packet = msg.pack();
if (type == 0) { // 串口
if (MyBoundService.serialHelper != null) {
MyBoundService.serialHelper.send(packet.encodePacket());
}
} else { // UDP
try {
InetAddress targetAddress = InetAddress.getByName("127.0.0.1"); // 改为飞控IP
DatagramPacket udpPacket = new DatagramPacket(
packet.encodePacket(),
packet.encodePacket().length,
targetAddress,
14553 // MAVLink标准端口
);
MyBoundService.serverSocket.send(udpPacket);
} catch (Exception e) {
Log.e("cuijinggzhou-发送", "发送失败: " + e.getMessage());
}
}
}
/**
* 通用MAVLink消息发送方法-串口2 其它硬件通道
*/
public void sendMessage_com2(int type,byte[] testData) {
if (type == 0) { // 串口
if (MyBoundService.serialHelper2 != null) {
MyBoundService.serialHelper2.send(testData);
Log.e("cuijinggzhou-发送", "发送成功 " );
}
} else { // UDP
try {
if (MyBoundService.serverSocket2 != null) {
InetAddress targetAddress = InetAddress.getByName("127.0.0.1"); // IP
DatagramPacket udpPacket = new DatagramPacket(
testData,
testData.length,
targetAddress,
13553 // 标准端口
);
MyBoundService.serverSocket2.send(udpPacket);
Log.e("cuijinggzhou-发送", "发送成功 " );
}
} catch (Exception e) {
Log.e("cuijinggzhou-发送", "发送失败: " + e.getMessage());
}
}
}
/**
* 启动定时任务用于检查 paramList 的加载进度并更新 tv_param_load 显示
*/
private static Handler handler = new Handler(Looper.getMainLooper());
private static Runnable updateProgressRunnable;
private static TextView tvParamLoad; // 假设 tvParamLoad 是用于显示进度的 TextView
public static void startParamLoadMonitoring(TextView tvParamLoad) {
FlyVoid.tvParamLoad = tvParamLoad;
@ -201,4 +345,6 @@ public class FlyVoid {
}

View File

@ -0,0 +1,121 @@
package com.example.longyi_groundstation.Main.Void;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import com.example.longyi_groundstation.R;
public class FpvGestureHandler implements View.OnTouchListener {
private GestureDetector gestureDetector;
private ScaleGestureDetector scaleGestureDetector;
private OnFpvGestureListener gestureListener;
private boolean isSwiping = false; // 标记是否正在滑动
private float startX, startY; // 记录初始触摸点
public FpvGestureHandler(View view) {
gestureDetector = new GestureDetector(view.getContext(), new GestureListener());
scaleGestureDetector = new ScaleGestureDetector(view.getContext(), new ScaleListener());
view.setOnTouchListener(this);
view.setLongClickable(true);
}
public void setOnFpvGestureListener(OnFpvGestureListener listener) {
this.gestureListener = listener;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
boolean result = scaleGestureDetector.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
if (gestureListener != null) {
float endX = event.getX();
float endY = event.getY();
float distanceX = endX - startX;
float distanceY = endY - startY;
// 检查是否是滑动操作避免微小的移动被识别为滑动
if (Math.abs(distanceX) > 20 || Math.abs(distanceY) > 20) {
if (!isSwiping) {
isSwiping = true;
}
gestureListener.onSwipe(startX, startY, endX, endY, distanceX, distanceY);
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (isSwiping && gestureListener != null) {
gestureListener.onSwipeEnd();
}
isSwiping = false;
startX = 0;
startY = 0;
break;
}
result = gestureDetector.onTouchEvent(event) || result;
return result;
}
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
if (gestureListener != null) {
gestureListener.onTap(e.getX(), e.getY());
}
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
if (gestureListener != null) {
gestureListener.onDoubleTap(e.getX(), e.getY());
}
return true;
}
@Override
public void onLongPress(MotionEvent e) {
if (gestureListener != null) {
gestureListener.onLongPress(e.getX(), e.getY());
}
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// 我们在onTouch中处理滑动这里不再处理
return true;
}
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
if (gestureListener != null) {
gestureListener.onZoom(detector.getScaleFactor());
}
return true;
}
}
public interface OnFpvGestureListener {
void onTap(float x, float y);
void onDoubleTap(float x, float y);
void onLongPress(float x, float y);
void onSwipe(float startX, float startY, float endX, float endY, float distanceX, float distanceY);
void onSwipeUp();
void onSwipeDown();
void onSwipeLeft();
void onSwipeRight();
void onZoom(float scaleFactor);
void onSwipeEnd(); // 添加滑动结束抬起事件
}
}

View File

@ -0,0 +1,163 @@
// LogManager.java
package com.example.longyi_groundstation.Main.Void.LogCat;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
import android.util.Log;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
public class LogManager {
private static final String TAG = "LogManager";
private static LogManager instance;
private HandlerThread logThread;
private Handler logHandler;
private File logDir;
private SimpleDateFormat dateFormat;
private SimpleDateFormat fileDateFormat;
private String currentDateString;
private LogManager() {
// 初始化日志线程
logThread = new HandlerThread("LogThread", Process.THREAD_PRIORITY_BACKGROUND);
logThread.start();
logHandler = new Handler(logThread.getLooper());
// 设置日志目录
logDir = new File(android.os.Environment.getExternalStorageDirectory(), "LongYiLogs");
if (!logDir.exists()) {
boolean created = logDir.mkdirs();
if (!created) {
Log.e(TAG, "Failed to create log directory: " + logDir.getAbsolutePath());
}
}
dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault());
fileDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
currentDateString = fileDateFormat.format(new Date());
}
public static synchronized LogManager getInstance() {
if (instance == null) {
instance = new LogManager();
}
return instance;
}
public void saveLog(final String tag, final String msg) {
// 直接在日志线程中处理避免创建额外的Runnables
logHandler.post(new Runnable() {
@Override
public void run() {
performSaveLog(tag, msg);
}
});
}
private void performSaveLog(String tag, String msg) {
String time = dateFormat.format(new Date());
String logEntry = time + " " + tag + ": " + msg + "\n";
// 检查是否需要创建新文件新的一天
String dateStr = fileDateFormat.format(new Date());
if (!dateStr.equals(currentDateString)) {
currentDateString = dateStr;
}
try {
// 确保目录存在
if (!logDir.exists()) {
boolean created = logDir.mkdirs();
if (!created) {
Log.e(TAG, "Failed to create log directory: " + logDir.getAbsolutePath());
return;
}
}
File logFile = new File(logDir, "log_" + currentDateString + ".txt");
// 确保文件存在
if (!logFile.exists()) {
try {
boolean created = logFile.createNewFile();
if (!created) {
Log.e(TAG, "Failed to create log file: " + logFile.getAbsolutePath());
return;
}
} catch (IOException e) {
Log.e(TAG, "IOException when creating log file: " + logFile.getAbsolutePath(), e);
return;
}
}
BufferedWriter writer = new BufferedWriter(new FileWriter(logFile, true));
writer.write(logEntry);
writer.close();
} catch (IOException e) {
Log.e(TAG, "Failed to write log entry", e);
}
}
public File getLogFile(String date) {
File logFile = new File(logDir, "log_" + date + ".txt");
// 检查文件是否存在
if (!logFile.exists()) {
return null;
}
return logFile;
}
public File getCurrentLogFile() {
File logFile = new File(logDir, "log_" + currentDateString + ".txt");
// 检查文件是否存在
if (!logFile.exists()) {
return null;
}
return logFile;
}
public List<String> getAvailableDates() {
List<String> dates = new ArrayList<>();
// 检查目录是否存在
if (!logDir.exists()) {
return dates;
}
File[] files = logDir.listFiles();
if (files != null) {
for (File file : files) {
String name = file.getName();
if (name.startsWith("log_") && name.endsWith(".txt")) {
String date = name.substring(4, name.length() - 4); // 提取日期部分
dates.add(date);
}
}
}
// 按日期倒序排列最新的在前
Collections.sort(dates, Collections.reverseOrder());
return dates;
}
public boolean isLogDirAvailable() {
return logDir != null && logDir.exists();
}
public void shutdown() {
if (logThread != null) {
logThread.quitSafely();
}
}
}

View File

@ -0,0 +1,16 @@
// LogUtil.java
package com.example.longyi_groundstation.Main.Void.LogCat;
import android.util.Log;
public class LogUtil {
public static void d(String tag, String msg) {
// 正常打印日志
// Log.d(tag, msg);
// 保存日志到文件
LogManager.getInstance().saveLog(tag, msg);
}
// 可以添加其他级别的日志方法 (e, w, i等)
}

View File

@ -1,19 +1,29 @@
package com.example.longyi_groundstation.Main.Void;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.amap.api.maps.AMap;
import com.amap.api.maps.AMapUtils;
import com.amap.api.maps.MapView;
import com.amap.api.maps.MapsInitializer;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.MyLocationStyle;
import com.amap.api.maps.model.Polyline;
import com.amap.api.maps.model.PolylineOptions;
import com.example.longyi_groundstation.MAVLink.Messages.MAVLinkPayload;
import com.example.longyi_groundstation.Main.Activity.MainActivity;
import com.example.longyi_groundstation.R;
@ -32,12 +42,18 @@ public class MapVoid {
public AMap aMap = null;
//初始化地图控制器对象
//画线
public Polyline polyline;
//画线
public List<LatLng> latLngss;
public List<Marker> waypointMarkers = new ArrayList<>();
public List<LatLng> waypointPositions = new ArrayList<>();
public Polyline polyline; // 用于保存航线
public int waypointCounter = 1;
public List<LatLng> flyPointList = new ArrayList<>();
public List<Marker> textMarkers = new ArrayList<>();
public MapVoid(Activity activity) {
this.activity = activity;
@ -45,20 +61,22 @@ public class MapVoid {
}
public void init() {
//高德地图用户协议不能删除
// 高德地图用户协议不能删除
MapsInitializer.updatePrivacyShow(activity, true, true);
MapsInitializer.updatePrivacyAgree(activity, true);
allView = new AllView(activity);
//在activity执行onCreate时执行mMapView.onCreate(savedInstanceState)创建地图
// 在activity执行onCreate时执行mMapView.onCreate(savedInstanceState)创建地图
allView.map.onCreate(savedInstanceState);
aMap = allView.map.getMap();
// 禁用POI点击
aMap.setMapType(AMap.MAP_TYPE_SATELLITE);// 设置卫星地图模式aMap是地图控制器对象
aMap.getUiSettings().setZoomControlsEnabled(false);// 隐藏地图上的缩放控件+ - 按钮
// 隐藏地图上的所有文字标注地名道路名等
aMap.showMapText(false);
MyLocationStyle myLocationStyle;
myLocationStyle = new MyLocationStyle();//初始化定位蓝点样式类
myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATE);//定位一次且将视角移动到地图中心点
aMap.setMyLocationStyle(myLocationStyle);//设置定位蓝点的Style
myLocationStyle = new MyLocationStyle();// 初始化定位蓝点样式类
myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATE);// 定位一次且将视角移动到地图中心点
aMap.setMyLocationStyle(myLocationStyle);// 设置定位蓝点的Style
aMap.setMyLocationEnabled(false);// 设置为true表示启动显示定位蓝点false表示隐藏定位蓝点并不进行定位默认是false
aMap.setOnMyLocationChangeListener(new AMap.OnMyLocationChangeListener() {
@Override
@ -67,42 +85,18 @@ public class MapVoid {
}
});
//画大地图飞行线
polyline = aMap.addPolyline(new PolylineOptions()
.width(10)
.color(
Color.argb(255, 1, 1, 1))
);
polyline.setVisible(true);
latLngss = new ArrayList<>();
upLine();
}
/**
* 方法更新线路的线程
*
* @cuijingzhou
*/
public void upLine() {
new Thread(new Runnable() {
// 添加marker点击监听器确保点击时显示信息窗口
aMap.setOnMarkerClickListener(new AMap.OnMarkerClickListener() {
@Override
public void run() {
while (aMap != null){
try {
polyline.setPoints(latLngss);
Thread.sleep(1000);
// polyline.setVisible(true);
} catch (InterruptedException e) {
e.printStackTrace();
public boolean onMarkerClick(Marker marker) {
// 检查是否是航点marker
if (waypointMarkers.contains(marker)) {
marker.showInfoWindow();
return true;
}
return false;
}
}
}).start();
}
public void showLine(boolean isShow) {
polyline.setVisible(isShow);
});
}
@ -121,4 +115,12 @@ public class MapVoid {
// 保留两位小数
return Math.round(distance * 100.0) / 100.0;
}
}

View File

@ -18,6 +18,9 @@ public class MyReceiver extends BroadcastReceiver {
public static JSONObject STATUSTEXT_json = null;//告警
public static JSONObject HEARTBEAT_json = null;//飞机基础飞行模式
public static JSONObject PARAM_VALUE_json = null;//飞机基础飞行模式
public static JSONObject RC_CHANNELS_json = null;//RC通道监控
public static JSONObject VFR_HUD_json = null;//油门量
//ATTITUDE
@ -68,6 +71,18 @@ public class MyReceiver extends BroadcastReceiver {
}
private OnParamValueListener ParamValuelistener;
public interface OnRcChannelsListener {
void onRcChannels(JSONObject data);
}
private OnRcChannelsListener RcChannelslistener;
public interface OnVfrHudListener {
void onVfrHud(JSONObject data);
}
private OnVfrHudListener VfrHudlistener;
public void setATTITUDEListener(OnATTITUDEListener listener) {
this.ATTITUDElistener = listener;
}
@ -93,6 +108,14 @@ public class MyReceiver extends BroadcastReceiver {
this.ParamValuelistener = listener;
}
public void setRcChannelsRawlistener(OnRcChannelsListener listener) {
this.RcChannelslistener = listener;
}
public void setVfrHudlistener(OnVfrHudListener listener) {
this.VfrHudlistener = listener;
}
@Override
public void onReceive(Context context, Intent intent) {
@ -111,7 +134,7 @@ public class MyReceiver extends BroadcastReceiver {
}
} catch (Exception e) {
Log.e("cuijingzhou-e", e.toString());
Log.e("cuijingzhou-e Broadcast_ATTITUDE", e.toString());
}
}
@ -130,7 +153,7 @@ public class MyReceiver extends BroadcastReceiver {
}
} catch (Exception e) {
Log.e("cuijingzhou-e", e.toString());
Log.e("cuijingzhou-e Broadcast_GPS_RAW_INT", e.toString());
}
}
@ -148,7 +171,7 @@ public class MyReceiver extends BroadcastReceiver {
}
} catch (Exception e) {
Log.e("cuijingzhou-e", e.toString());
// Log.e("cuijingzhou-e Broadcast_GLOBAL_POSITION_INT", e.toString());
}
}
@ -166,7 +189,7 @@ public class MyReceiver extends BroadcastReceiver {
}
} catch (Exception e) {
Log.e("cuijingzhou-e", e.toString());
Log.e("cuijingzhou-e Broadcast_POWER_STATUS", e.toString());
}
}
@ -185,7 +208,7 @@ public class MyReceiver extends BroadcastReceiver {
}
} catch (Exception e) {
Log.e("cuijingzhou-e", e.toString());
Log.e("cuijingzhou-e Broadcast_SYS_STATUS", e.toString());
}
}
@ -203,7 +226,7 @@ public class MyReceiver extends BroadcastReceiver {
}
} catch (Exception e) {
Log.e("cuijingzhou-e", e.toString());
Log.e("cuijingzhou-e Broadcast_STATUSTEXT", e.toString());
}
}
@ -221,7 +244,7 @@ public class MyReceiver extends BroadcastReceiver {
}
} catch (Exception e) {
Log.e("cuijingzhou-e", e.toString());
Log.e("cuijingzhou-e Broadcast_HEARTBEAT", e.toString());
}
}
@ -239,11 +262,46 @@ public class MyReceiver extends BroadcastReceiver {
}
} catch (Exception e) {
Log.e("cuijingzhou-e", e.toString());
Log.e("cuijingzhou-e Broadcast_PARAM_VALUE", e.toString());
}
}
if ("Broadcast_RC_CHANNELS".equals(intent.getAction())) {
try {
String receivedData = intent.getStringExtra("data");
if (receivedData != null) {
RC_CHANNELS_json = new JSONObject(receivedData);
RC_CHANNELS_json.optString("jsonObject");
// Log.d("cuijingzhou", "onReceive: " + receivedData);
// 触发回调
if (RcChannelslistener != null) {
RcChannelslistener.onRcChannels(RC_CHANNELS_json);
}
}
} catch (Exception e) {
Log.e("cuijingzhou-e Broadcast_RC_CHANNELS_RAW", e.toString());
}
}
if ("Broadcast_VFR_HUD".equals(intent.getAction())) {
try {
String receivedData = intent.getStringExtra("data");
if (receivedData != null) {
VFR_HUD_json = new JSONObject(receivedData);
VFR_HUD_json.optString("jsonObject");
// Log.d("cuijingzhou", "onReceive: " + receivedData);
// 触发回调
if (VfrHudlistener != null) {
VfrHudlistener.onVfrHud(VFR_HUD_json);
}
}
} catch (Exception e) {
Log.e("cuijingzhou-e Broadcast_RC_CHANNELS_RAW", e.toString());
}
}
}
}

View File

@ -102,9 +102,61 @@ public class MyTool {
}
/**
* 方法油门量公式
*
* @cuijingzhou
*/
public static double getThrottle(double spin_mins, double spin_maxs, double thrust_curve_expos, double thrusts, double lift_maxs) {
double thr_out = 0;//油门量
double spin_min = 0.95;//对应MOT_SPIN_MIN没获取到就用默认的
double spin_max = 0.2;//对应MOT_SPIN_MAX没获取到就用默认的
double throttle_curve = 0;
double thrust_curve_expo = 0.65;//曲线指数
double thrust = 0;//获取到的油门
double lift_max = 1;//获取到的油门
if (spin_mins != 0){
spin_min = spin_mins;
}
if (spin_maxs != 0){
spin_max = spin_maxs;
}
if (thrust_curve_expos != 0){
thrust_curve_expo = thrust_curve_expos;
}
if (thrusts != 0){
thrust = thrusts;
}
if (lift_maxs != 0){
lift_max = lift_maxs;
}
//公式一
throttle_curve = ((thrust_curve_expo - 1.0) + safe_sqrt(
(1.0 - thrust_curve_expo) * (1.0 - thrust_curve_expo) + 4.0 * thrust_curve_expo * lift_max * thrust)) / (2.0 * thrust_curve_expo);//对应MOT_SPIN_MIN没获取到就用默认的
//公式二
thr_out = spin_min + (spin_max - spin_min) //油门量公式运算
* throttle_curve;
return thr_out;
}
/**
* 方法安全平方根计算
* 防止对负数开方导致异常
*
* @param value 需要开方的数值
* @return 开方结果如果输入为负数则返回0
* @cuijingzhou
*/
public static double safe_sqrt(double value) {
if (value < 0) {
return 0.0;
}
return Math.sqrt(value);
}
}

View File

@ -0,0 +1,441 @@
package com.example.longyi_groundstation.Main.Void;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.amap.api.maps.model.LatLng;
import com.example.longyi_groundstation.Main.Base.CreateLink;
import java.util.ArrayList;
import java.util.List;
/**
* 方法SQLClass 飞行航线本地数据库
* // 初始化数据库
* SQLClass sqlClass = new SQLClass(context);
*
* // 添加一个CreateLink列表
* ArrayList<CreateLink> createLinkList = new ArrayList<>();
* // ... 添加CreateLink对象到列表中
* boolean success = sqlClass.addCreateLinkList("路线1", createLinkList);
*
* // 获取所有列表信息
* List<SQLClass.LinkListInfo> listInfos = sqlClass.getAllLinkListInfo();
*
* // 获取指定ID的完整列表
* ArrayList<CreateLink> retrievedList = sqlClass.getCreateLinkList(1);
*
* // 更新列表
* sqlClass.updateCreateLinkList(1, "新路线名称", updatedCreateLinkList);
*
* // 删除列表
* sqlClass.deleteCreateLinkList(1);
*
* // 获取列表数量
* int count = sqlClass.getLinkListCount();
*
* @cuijingzhou
*/
public class SQLClass extends SQLiteOpenHelper {
private static final String TAG = "SQLClass";
// 数据库名称和版本
private static final String DATABASE_NAME = "create_link_list.db";
private static final int DATABASE_VERSION = 1;
// 主表 - 存储列表信息
private static final String TABLE_LINK_LIST = "link_list";
private static final String COLUMN_LIST_ID = "list_id";
private static final String COLUMN_LIST_NAME = "list_name";
private static final String COLUMN_CREATED_TIME = "created_time";
// 详情表 - 存储每个列表中的CreateLink项
private static final String TABLE_LINK_ITEMS = "link_items";
private static final String COLUMN_ITEM_ID = "item_id";
private static final String COLUMN_LIST_REF_ID = "list_ref_id"; // 外键关联到列表ID
private static final String COLUMN_NAME = "name";
private static final String COLUMN_HEIGHT = "height";
private static final String COLUMN_SPEED = "speed";
private static final String COLUMN_WAYPOINT_INDEX = "waypoint_index";
private static final String COLUMN_LATITUDE = "latitude";
private static final String COLUMN_LONGITUDE = "longitude";
private static final String COLUMN_ITEM_ORDER = "item_order"; // 项在列表中的顺序
// 创建主表的SQL语句
private static final String CREATE_LIST_TABLE_SQL =
"CREATE TABLE " + TABLE_LINK_LIST + " (" +
COLUMN_LIST_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COLUMN_LIST_NAME + " TEXT NOT NULL, " +
COLUMN_CREATED_TIME + " INTEGER NOT NULL)";
// 创建详情表的SQL语句
private static final String CREATE_ITEMS_TABLE_SQL =
"CREATE TABLE " + TABLE_LINK_ITEMS + " (" +
COLUMN_ITEM_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COLUMN_LIST_REF_ID + " INTEGER NOT NULL, " +
COLUMN_NAME + " TEXT NOT NULL, " +
COLUMN_HEIGHT + " REAL NOT NULL, " +
COLUMN_SPEED + " REAL NOT NULL, " +
COLUMN_WAYPOINT_INDEX + " INTEGER NOT NULL, " +
COLUMN_LATITUDE + " REAL, " +
COLUMN_LONGITUDE + " REAL, " +
COLUMN_ITEM_ORDER + " INTEGER NOT NULL, " +
"FOREIGN KEY(" + COLUMN_LIST_REF_ID + ") REFERENCES " +
TABLE_LINK_LIST + "(" + COLUMN_LIST_ID + ") ON DELETE CASCADE)";
public SQLClass(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_LIST_TABLE_SQL);
db.execSQL(CREATE_ITEMS_TABLE_SQL);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_LINK_ITEMS);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_LINK_LIST);
onCreate(db);
}
@Override
public void onConfigure(SQLiteDatabase db) {
super.onConfigure(db);
db.setForeignKeyConstraintsEnabled(true); // 启用外键约束
}
/**
* 添加一个CreateLink列表
* @param listName 列表名称
* @param createLinkList CreateLink列表
* @return 添加成功返回true否则返回false
*/
public boolean addCreateLinkList(String listName, ArrayList<CreateLink> createLinkList) {
// 检查是否已达到最大数量限制
if (getLinkListCount() >= 10) {
Log.w(TAG, "已达到最大存储数量限制(10个列表),无法添加新列表");
return false;
}
SQLiteDatabase db = this.getWritableDatabase();
db.beginTransaction(); // 开始事务以确保数据一致性
try {
// 插入列表信息
ContentValues listValues = new ContentValues();
listValues.put(COLUMN_LIST_NAME, listName);
listValues.put(COLUMN_CREATED_TIME, System.currentTimeMillis());
long listId = db.insert(TABLE_LINK_LIST, null, listValues);
if (listId == -1) {
db.endTransaction();
return false;
}
// 插入列表中的每个CreateLink项
for (int i = 0; i < createLinkList.size(); i++) {
CreateLink createLink = createLinkList.get(i);
ContentValues itemValues = new ContentValues();
itemValues.put(COLUMN_LIST_REF_ID, listId);
itemValues.put(COLUMN_NAME, createLink.getName());
itemValues.put(COLUMN_HEIGHT, createLink.getHeight());
itemValues.put(COLUMN_SPEED, createLink.getSpeed());
itemValues.put(COLUMN_WAYPOINT_INDEX, createLink.getWaypointIndex());
if (createLink.getLatLng() != null) {
itemValues.put(COLUMN_LATITUDE, createLink.getLatLng().latitude);
itemValues.put(COLUMN_LONGITUDE, createLink.getLatLng().longitude);
} else {
itemValues.put(COLUMN_LATITUDE, 0.0);
itemValues.put(COLUMN_LONGITUDE, 0.0);
}
itemValues.put(COLUMN_ITEM_ORDER, i);
long itemId = db.insert(TABLE_LINK_ITEMS, null, itemValues);
if (itemId == -1) {
db.endTransaction();
return false;
}
}
db.setTransactionSuccessful(); // 标记事务成功
return true;
} catch (Exception e) {
Log.e(TAG, "添加CreateLink列表时出错", e);
return false;
} finally {
db.endTransaction(); // 结束事务
db.close();
}
}
/**
* 获取所有列表的基本信息不包含列表内容
* @return 包含列表ID和名称的列表
*/
public List<LinkListInfo> getAllLinkListInfo() {
List<LinkListInfo> listInfoList = new ArrayList<>();
String selectQuery = "SELECT " + COLUMN_LIST_ID + ", " + COLUMN_LIST_NAME +
", " + COLUMN_CREATED_TIME +
" FROM " + TABLE_LINK_LIST +
" ORDER BY " + COLUMN_CREATED_TIME + " DESC";
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
if (cursor.moveToFirst()) {
do {
int listId = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_LIST_ID));
String listName = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_LIST_NAME));
long createdTime = cursor.getLong(cursor.getColumnIndexOrThrow(COLUMN_CREATED_TIME));
listInfoList.add(new LinkListInfo(listId, listName, createdTime));
} while (cursor.moveToNext());
}
cursor.close();
db.close();
return listInfoList;
}
/**
* 根据列表ID获取完整的CreateLink列表
* @param listId 列表ID
* @return CreateLink列表如果不存在返回null
*/
public ArrayList<CreateLink> getCreateLinkList(int listId) {
// 首先检查列表是否存在
if (!isLinkListExists(listId)) {
return null;
}
ArrayList<CreateLink> createLinkList = new ArrayList<>();
String selectQuery = "SELECT * FROM " + TABLE_LINK_ITEMS +
" WHERE " + COLUMN_LIST_REF_ID + " = ?" +
" ORDER BY " + COLUMN_ITEM_ORDER;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery, new String[]{String.valueOf(listId)});
if (cursor.moveToFirst()) {
do {
String name = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_NAME));
double height = cursor.getDouble(cursor.getColumnIndexOrThrow(COLUMN_HEIGHT));
double speed = cursor.getDouble(cursor.getColumnIndexOrThrow(COLUMN_SPEED));
int waypointIndex = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_WAYPOINT_INDEX));
double latitude = cursor.getDouble(cursor.getColumnIndexOrThrow(COLUMN_LATITUDE));
double longitude = cursor.getDouble(cursor.getColumnIndexOrThrow(COLUMN_LONGITUDE));
LatLng latLng = new LatLng(latitude, longitude);
CreateLink createLink = new CreateLink(name, height, speed, waypointIndex, latLng);
createLinkList.add(createLink);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
return createLinkList;
}
/**
* 更新指定ID的CreateLink列表
* @param listId 列表ID
* @param listName 新的列表名称
* @param createLinkList 新的CreateLink列表
* @return 更新成功返回true否则返回false
*/
public boolean updateCreateLinkList(int listId, String listName, ArrayList<CreateLink> createLinkList) {
// 检查列表是否存在
if (!isLinkListExists(listId)) {
Log.w(TAG, "列表ID " + listId + " 不存在,无法更新");
return false;
}
SQLiteDatabase db = this.getWritableDatabase();
db.beginTransaction(); // 开始事务以确保数据一致性
try {
// 更新列表名称
ContentValues listValues = new ContentValues();
listValues.put(COLUMN_LIST_NAME, listName);
int updateResult = db.update(TABLE_LINK_LIST, listValues,
COLUMN_LIST_ID + " = ?",
new String[]{String.valueOf(listId)});
if (updateResult <= 0) {
db.endTransaction();
return false;
}
// 删除原有的列表项
db.delete(TABLE_LINK_ITEMS, COLUMN_LIST_REF_ID + " = ?",
new String[]{String.valueOf(listId)});
// 插入新的列表项
for (int i = 0; i < createLinkList.size(); i++) {
CreateLink createLink = createLinkList.get(i);
ContentValues itemValues = new ContentValues();
itemValues.put(COLUMN_LIST_REF_ID, listId);
itemValues.put(COLUMN_NAME, createLink.getName());
itemValues.put(COLUMN_HEIGHT, createLink.getHeight());
itemValues.put(COLUMN_SPEED, createLink.getSpeed());
itemValues.put(COLUMN_WAYPOINT_INDEX, createLink.getWaypointIndex());
if (createLink.getLatLng() != null) {
itemValues.put(COLUMN_LATITUDE, createLink.getLatLng().latitude);
itemValues.put(COLUMN_LONGITUDE, createLink.getLatLng().longitude);
} else {
itemValues.put(COLUMN_LATITUDE, 0.0);
itemValues.put(COLUMN_LONGITUDE, 0.0);
}
itemValues.put(COLUMN_ITEM_ORDER, i);
long itemId = db.insert(TABLE_LINK_ITEMS, null, itemValues);
if (itemId == -1) {
db.endTransaction();
return false;
}
}
db.setTransactionSuccessful(); // 标记事务成功
return true;
} catch (Exception e) {
Log.e(TAG, "更新CreateLink列表时出错", e);
return false;
} finally {
db.endTransaction(); // 结束事务
db.close();
}
}
/**
* 根据列表ID删除CreateLink列表
* @param listId 列表ID
* @return 删除成功返回true否则返回false
*/
public boolean deleteCreateLinkList(int listId) {
SQLiteDatabase db = this.getWritableDatabase();
db.beginTransaction(); // 开始事务
try {
// 删除列表项
db.delete(TABLE_LINK_ITEMS, COLUMN_LIST_REF_ID + " = ?",
new String[]{String.valueOf(listId)});
// 删除列表
int result = db.delete(TABLE_LINK_LIST, COLUMN_LIST_ID + " = ?",
new String[]{String.valueOf(listId)});
db.setTransactionSuccessful(); // 标记事务成功
return result > 0;
} catch (Exception e) {
Log.e(TAG, "删除CreateLink列表时出错", e);
return false;
} finally {
db.endTransaction(); // 结束事务
db.close();
}
}
/**
* 删除所有CreateLink列表
* @return 删除成功返回true否则返回false
*/
public boolean deleteAllCreateLinkLists() {
SQLiteDatabase db = this.getWritableDatabase();
db.beginTransaction(); // 开始事务
try {
// 删除所有列表项
db.delete(TABLE_LINK_ITEMS, null, null);
// 删除所有列表
db.delete(TABLE_LINK_LIST, null, null);
db.setTransactionSuccessful(); // 标记事务成功
return true;
} catch (Exception e) {
Log.e(TAG, "删除所有CreateLink列表时出错", e);
return false;
} finally {
db.endTransaction(); // 结束事务
db.close();
}
}
/**
* 获取存储的列表数量
* @return 列表数量
*/
public int getLinkListCount() {
String countQuery = "SELECT COUNT(*) FROM " + TABLE_LINK_LIST;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
int count = 0;
if (cursor.moveToFirst()) {
count = cursor.getInt(0);
}
cursor.close();
db.close();
return count;
}
/**
* 检查指定ID的列表是否存在
* @param listId 列表ID
* @return 存在返回true否则返回false
*/
public boolean isLinkListExists(int listId) {
String query = "SELECT 1 FROM " + TABLE_LINK_LIST +
" WHERE " + COLUMN_LIST_ID + " = ? LIMIT 1";
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(query, new String[]{String.valueOf(listId)});
boolean exists = cursor.getCount() > 0;
cursor.close();
db.close();
return exists;
}
/**
* 列表信息内部类
*/
public static class LinkListInfo {
private int listId;
private String listName;
private long createdTime;
public LinkListInfo(int listId, String listName, long createdTime) {
this.listId = listId;
this.listName = listName;
this.createdTime = createdTime;
}
public int getListId() {
return listId;
}
public String getListName() {
return listName;
}
public long getCreatedTime() {
return createdTime;
}
}
}

View File

@ -0,0 +1,105 @@
package com.example.longyi_groundstation.Main.Void;
public class SerialTool {
/**
* 将字节数组转换为Hex字符串
*
* @param bytes 字节数组
* @return Hex字符串
*/
public static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02X", b));
}
return result.toString();
}
/**
* 将十进制字符串转换为十六进制byte
*
* @param decString 十进制字符串
* @return 十六进制byte值
* @throws IllegalArgumentException 当输入不是有效的十进制字符串或超出范围时
*/
public static byte decStringToHexByte(String decString) {
if (decString == null || decString.isEmpty()) {
throw new IllegalArgumentException("输入的十进制字符串不能为空");
}
try {
// 将十进制字符串解析为整数
int value = Integer.parseInt(decString);
// 检查范围是否在0-255之间单字节范围
if (value < 0 || value > 255) {
throw new IllegalArgumentException("十进制值超出byte范围(0-255): " + decString);
}
// 直接返回对应的byte值
return (byte) value;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("输入的不是有效的十进制字符串: " + decString);
}
}
/**
* 计算校验和
* 校验和 = 帧头(0xFF) + 发送设置高度取低8位
*
* @param heightSetting 发送设置高度的byte值
* @return 校验和的byte值
*/
public static byte calculateChecksum(byte heightSetting) {
// 帧头固定为0xFF
int frameHeader = 0xFF;
// 将byte转换为无符号整数进行计算
int heightValue = heightSetting & 0xFF;
// 计算校验和帧头 + 设置高度
int checksum = frameHeader + heightValue;
// 取低8位
checksum = checksum & 0xFF;
// 转换为byte返回
return (byte) checksum;
}
/**
* 解析串口数据提取特定字节并转换为十进制值
* 添加校验data第4个字节 = data第1个+data第2个+data第3个取低8位
*
* @param data 串口数据字节数组
* @return 包含解析结果的数组[0]为第23字节组合的值[1]为第4字节的值校验失败返回null
*/
public static int[] parseSerialData(byte[] data) {
if (data == null || data.length < 4) {
throw new IllegalArgumentException("数据长度不足,无法解析");
}
// 校验第4个字节应该等于前三个字节之和的低8位
int checksum = (data[0] & 0xFF) + (data[1] & 0xFF) + (data[2] & 0xFF);
checksum = checksum & 0xFF; // 取低8位
// 如果校验失败返回null
if ((data[3] & 0xFF) != checksum) {
return null;
}
// 提取第23字节组合成一个16位值 (例如: 01 2C -> 0x012C = 300)
int value1 = ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
// 提取第4字节转换为十进制 (例如: 12 -> 0x12 = 18)
int value2 = data[3] & 0xFF;
return new int[]{value1, value2};
}
}

View File

@ -0,0 +1,90 @@
package com.example.longyi_groundstation.Main.Void.XiangTuo;
public enum Instruction {
/**
* 云台控制指令
* PTZ_LEFT_AND_DOWN云台左下移动
* PTZ_RIGHT_AND_UP云台右上移动
* PTZ_RIGHT_AND_DOWN云台右下移动
* PTZ_LEFT_AND_UP云台左上移动
* MOTOR_STOP运动停止速度控制模式
* 角度控制指令
* PITCH_ANGLE_CONTROL俯仰角度控制
* YAW_ANGLE_CONTROL航向角度控制
* 点动/跟踪指令
* POINT_TO_MOVE指点移动画面XY坐标
* POINT_TO_TRACKING指点跟踪画面XY坐标
* STOP_TRACKING停止跟踪
* 模式切换指令
* FOLLOW_YAW_MODE航向跟随模式
* LOCK_YAW_MODE航向锁定模式
* VERTICAL_OVERLOOK垂直俯视一键按下90° overlook
* ONE_CLICK_RESET一键回中
* 拍照/录像指令
* TAKE_PICTURE拍照
* START_RECORDING开始录像
* STOP_RECORDING停止录像
* 可见光变焦指令
* VIS_LIGHT_ZOOM可见光变焦
* VIS_LIGHT_SPEED_ZOOM可见光速度变焦
* VIS_LIGHT_STOP_ZOOM可见光停止变焦
* VIS_LIGHT_SPEC_OPT_ZOOM可见光特殊光学变焦
* 可见光手动聚焦指令
* TURN_ON_VIS_LIGHT_MAN_FOCUS开启可见光手动聚焦
* TURN_OFF_VIS_LIGHT_MAN_FOCUS关闭可见光手动聚焦
* VIS_LIGHT_MAN_FOCUS_PLUS可见光手动聚焦远焦
* VIS_LIGHT_MAN_FOCUS_MINUS可见光手动聚焦近焦
* VIS_LIGHT_MAN_FOCUS_STOP可见光手动聚焦停止
* OSD显示指令
* TURN_ON_OSD打开OSD显示
* TURN_OFF_OSD关闭OSD显示
*
* @cuijingzhou
*/
PTZ_UP((byte) 0x00, (byte) 0x08),
PTZ_DOWN((byte) 0x00, (byte) 0x10),
PTZ_LEFT((byte) 0x00, (byte) 0x04),
PTZ_RIGHT((byte) 0x00, (byte) 0x02),
MOTOR_STOP((byte) 0x00, (byte) 0x00),
PITCH_ANGLE_CONTROL((byte) 0x10, (byte) 0x01),
YAW_ANGLE_CONTROL((byte) 0x10, (byte) 0x02),
POINT_TO_MOVE((byte) 0x10, (byte) 0x00),
POINT_TO_TRACKING((byte) 0x11, (byte) 0x00),
STOP_TRACKING((byte) 0x11, (byte) 0x01),
FOLLOW_YAW_MODE((byte) 0x13, (byte) 0x00),
LOCK_YAW_MODE((byte) 0x13, (byte) 0x01),
VERTICAL_OVERLOOK((byte) 0x13, (byte) 0x02),
ONE_CLICK_RESET((byte) 0x13, (byte) 0x03),
TAKE_PICTURE((byte) 0x12, (byte) 0x00),
START_RECORDING((byte) 0x12, (byte) 0x01),
STOP_RECORDING((byte) 0x12, (byte) 0x02),
VIS_LIGHT_ZOOM((byte) 0x00, (byte) 0x40),
VIS_LIGHT_SPEED_ZOOM((byte) 0x00, (byte) 0x20),
VIS_LIGHT_STOP_ZOOM((byte) 0x00, (byte) 0x60),
VIS_LIGHT_SPEC_OPT_ZOOM((byte) 0x1F, (byte) 0x00),
TURN_ON_VIS_LIGHT_MAN_FOCUS((byte) 0x1D, (byte) 0x00),
TURN_OFF_VIS_LIGHT_MAN_FOCUS((byte) 0x1D, (byte) 0x01),
VIS_LIGHT_MAN_FOCUS_PLUS((byte) 0x1D, (byte) 0x03),
VIS_LIGHT_MAN_FOCUS_MINUS((byte) 0x1D, (byte) 0x02),
VIS_LIGHT_MAN_FOCUS_STOP((byte) 0x1D, (byte) 0x04),
TURN_ON_OSD((byte) 0x19, (byte) 0x00),
TURN_OFF_OSD((byte) 0x19, (byte) 0x01);
private final byte code1;
private final byte code2;
Instruction(byte code1, byte code2) {
this.code1 = code1;
this.code2 = code2;
}
public byte getCode1() {
return code1;
}
public byte getCode2() {
return code2;
}
}

View File

@ -0,0 +1,54 @@
package com.example.longyi_groundstation.Main.Void.XiangTuo;
public class Protocol {
private static final int SYNC_BYTE = 0xFF;
private byte addressCode;
private byte instructionCode1;
private byte instructionCode2;
private byte dataCode1;
private byte dataCode2;
private byte checkCode;
public Protocol(byte addressCode, byte instructionCode1, byte instructionCode2, byte dataCode1, byte dataCode2) {
this.addressCode = addressCode;
this.instructionCode1 = instructionCode1;
this.instructionCode2 = instructionCode2;
this.dataCode1 = dataCode1;
this.dataCode2 = dataCode2;
// this.checkCode = calculateCheckCode();
}
public static byte calculateCheckCode(byte addressCode, byte instructionCode1, byte instructionCode2, byte dataCode1, byte dataCode2) {
// 校验码计算逻辑字节2 + 字节3 + 字节4 + 字节5 + 字节6
int sum = addressCode & 0xFF;
sum += instructionCode1 & 0xFF;
sum += instructionCode2 & 0xFF;
sum += dataCode1 & 0xFF;
sum += dataCode2 & 0xFF;
return (byte) (sum & 0xFF);
}
public byte[] toBytes() {
return new byte[]{
(byte) SYNC_BYTE,
addressCode,
instructionCode1,
instructionCode2,
dataCode1,
dataCode2,
checkCode
};
}
public String toHexBytes() {
String hexString = String.format("%02X", SYNC_BYTE) + " " +
String.format("%02X", addressCode) + " " +
String.format("%02X", instructionCode1) + " " +
String.format("%02X", instructionCode2) + " " +
String.format("%02X", dataCode1) + " " +
String.format("%02X", dataCode2) + " " +
String.format("%02X", checkCode);
return hexString;
}
}

View File

@ -0,0 +1,295 @@
package com.example.longyi_groundstation.Main.Void.XiangTuo;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.TextView;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import okio.Buffer;
import okio.Okio;
import okio.Sink;
import okio.Source;
public class TcpClientUtil {
private static final String TAG = "TcpClientUtil";
private Socket socket;
private Source source;
private Sink sink;
private ExecutorService executorService;
private Handler mainHandler;
private boolean isConnected = false;
private TextView infoTextView;
public TcpClientUtil() {
executorService = Executors.newSingleThreadExecutor();
mainHandler = new Handler(Looper.getMainLooper());
}
/**
* 连接到TCP服务器
*
* @param host 服务器地址
* @param port 服务器端口
*/
public void connect(String host, int port) {
updateInfoTextView("正在连接到 " + host + ":" + port + "...");
executorService.execute(() -> {
try {
socket = new Socket();
// 设置Socket选项以提高性能
socket.setTcpNoDelay(true);
socket.setSoTimeout(100000000); // 10秒读取超时
socket.connect(new InetSocketAddress(host, port), 5000); // 5秒连接超时
source = Okio.source(socket.getInputStream());
sink = Okio.sink(socket.getOutputStream());
isConnected = true;
Log.d(TAG, "连接成功: " + host + ":" + port);
updateInfoTextView("连接成功: " + host + ":" + port);
// 启动接收数据线程
// startReceiving();
} catch (IOException e) {
Log.e(TAG, "连接失败: " + e.getMessage());
isConnected = false;
updateInfoTextView("连接失败: " + e.getMessage());
}
});
}
/**
* 断开连接
*/
public void disconnect() {
updateInfoTextView("正在断开连接...");
executorService.execute(() -> {
try {
isConnected = false;
if (source != null) {
source.close();
}
if (sink != null) {
sink.close();
}
if (socket != null) {
socket.close();
}
Log.d(TAG, "连接已断开");
updateInfoTextView("连接已断开");
} catch (IOException e) {
Log.e(TAG, "断开连接时出错: " + e.getMessage());
updateInfoTextView("断开连接时出错: " + e.getMessage());
}
});
}
/**
* 发送Hex数据
*
* @param hexData 以Hex格式表示的数据
*/
public void sendHexData(String hexData) {
if (!isConnected) {
Log.e(TAG, "未连接到服务器");
updateInfoTextView("错误: 未连接到服务器");
return;
}
executorService.execute(() -> {
try {
// 将Hex字符串转换为字节数组
byte[] data = hexStringToByteArray(hexData);
// 发送数据
Buffer buffer = new Buffer();
buffer.write(data);
sink.write(buffer, data.length);
sink.flush();
Log.d(TAG, "发送数据: " + hexData);
updateInfoTextView("发送: " + hexData);
} catch (Exception e) {
Log.e(TAG, "发送数据失败: " + e.getMessage());
updateInfoTextView("发送失败: " + e.getMessage());
} catch (OutOfMemoryError e) {
Log.e(TAG, "发送数据时内存不足: " + e.getMessage());
updateInfoTextView("发送失败: 内存不足");
}
});
}
/**
* 发送字节数组
*
* @param data 字节数组
*/
public void sendBytes(byte[] data) {
if (!isConnected) {
Log.e(TAG, "未连接到服务器");
updateInfoTextView("错误: 未连接到服务器");
return;
}
executorService.execute(() -> {
try {
if (data == null || data.length == 0) {
Log.w(TAG, "尝试发送空数据");
updateInfoTextView("警告: 尝试发送空数据");
return;
}
Buffer buffer = new Buffer();
buffer.write(data);
sink.write(buffer, data.length);
sink.flush();
String hexData = bytesToHex(data);
Log.d(TAG, "发送数据: " + hexData + " (长度: " + data.length + " 字节)");
updateInfoTextView("发送: " + hexData + " (" + data.length + " 字节)");
} catch (Exception e) {
Log.e(TAG, "发送数据失败: " + e.getMessage(), e);
updateInfoTextView("发送失败: " + e.getMessage());
} catch (OutOfMemoryError e) {
Log.e(TAG, "发送数据时内存不足: " + e.getMessage());
updateInfoTextView("发送失败: 内存不足");
}
});
}
/**
* 开始接收数据
*/
private void startReceiving() {
executorService.execute(() -> {
try {
Buffer buffer = new Buffer();
while (isConnected && socket != null && !socket.isClosed() && !socket.isInputShutdown()) {
// 读取数据
long bytesRead = source.read(buffer, 1024);
if (bytesRead > 0) {
byte[] data = buffer.readByteArray();
String hexData = bytesToHex(data);
// 在主线程更新UI
updateInfoTextView("接收: " + hexData + " (" + data.length + " 字节)");
Log.d(TAG, "接收到数据: " + hexData + " (长度: " + data.length + " 字节)");
} else if (bytesRead == -1) {
// 连接已关闭
isConnected = false;
updateInfoTextView("连接已关闭");
Log.d(TAG, "连接已关闭");
break;
}
}
} catch (Exception e) {
if (isConnected) {
Log.e(TAG, "接收数据时出错: " + e.getMessage());
updateInfoTextView("接收数据时出错: " + e.getMessage());
isConnected = false;
}
}
});
}
/**
* 设置用于显示信息的TextView
*
* @param textView TextView控件
*/
public void setInfoTextView(TextView textView) {
this.infoTextView = textView;
}
/**
* 更新TextView显示内容
*
* @param data 要显示的数据
*/
private void updateInfoTextView(String data) {
if (infoTextView != null) {
mainHandler.post(() -> {
String currentText = infoTextView.getText().toString();
// 添加时间戳
String timestamp = java.text.DateFormat.getTimeInstance().format(new java.util.Date());
String newText = currentText + "\n[" + timestamp + "] " + data;
// 限制文本长度避免内存问题
if (newText.length() > 10000) {
newText = newText.substring(newText.length() - 10000);
}
infoTextView.setText(newText);
// 自动滚动到底部
infoTextView.post(() -> {
if (infoTextView.getLayout() != null) {
int scrollAmount = infoTextView.getLayout().getLineTop(infoTextView.getLineCount()) - infoTextView.getHeight();
if (scrollAmount > 0) {
infoTextView.scrollTo(0, scrollAmount);
} else {
infoTextView.scrollTo(0, 0);
}
}
});
});
}
}
/**
* 将Hex字符串转换为字节数组
*
* @param hexString Hex字符串
* @return 字节数组
*/
private byte[] hexStringToByteArray(String hexString) {
int len = hexString.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
+ Character.digit(hexString.charAt(i+1), 16));
}
return data;
}
/**
* 将字节数组转换为Hex字符串
*
* @param bytes 字节数组
* @return Hex字符串
*/
private String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02X", b));
}
return result.toString();
}
/**
* 检查是否已连接
*
* @return 连接状态
*/
public boolean isConnected() {
return isConnected;
}
/**
* 获取Socket状态
*
* @return Socket状态信息
*/
public String getSocketStatus() {
if (socket == null) {
return "Socket未初始化";
}
return String.format("Socket状态 - 已连接: %s, 已关闭: %s, 输入关闭: %s, 输出关闭: %s",
isConnected, socket.isClosed(), socket.isInputShutdown(), socket.isOutputShutdown());
}
}

View File

@ -1,11 +1,12 @@
package com.example.longyi_groundstation;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Message;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
@ -13,33 +14,17 @@ import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.example.longyi_groundstation.MAVLink.MAVLinkPacket;
import com.example.longyi_groundstation.MAVLink.Messages.MAVLinkMessage;
import com.example.longyi_groundstation.MAVLink.Parser;
import com.example.longyi_groundstation.Util.Serial.SerialPortUtil;
import com.example.longyi_groundstation.Util.Tool;
import com.example.longyi_groundstation.Util.UdpClient;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Locale;
import tp.xmaihh.serialport.SerialHelper;
import tp.xmaihh.serialport.bean.ComBean;
import com.example.longyi_groundstation.Main.Void.XiangTuo.Instruction;
import com.example.longyi_groundstation.Main.Void.XiangTuo.Protocol;
import com.example.longyi_groundstation.Main.Void.XiangTuo.TcpClientUtil;
public class MainActivity2 extends AppCompatActivity {
private static final String TAG = "MainActivity2";
private static final String TAG = "UDPServer";
private TextView tv_text;
private DatagramSocket serverSocket;
private boolean isRunning = true;
private int serverPort = 14550; // 服务端监听端口
private UdpClient udpClient;
private TcpClientUtil tcpClient;
private TextView tvInfo;
private Button btnConnect;
private Button btnDisconnect;
@SuppressLint("MissingInflatedId")
@Override
@ -53,52 +38,148 @@ public class MainActivity2 extends AppCompatActivity {
return insets;
});
tv_text = findViewById(R.id.tv_text);
try {
udpClient = new UdpClient("127.0.0.1", 14551); // 服务器的IP地址和端口号
isRunning = true;
udpClient.send("AA01");
getDataTR();
} catch (SocketException | UnknownHostException e) {
// throw new RuntimeException(e);
Log.d(TAG, e + "");
} catch (IOException e) {
throw new RuntimeException(e);
initViews();
initTcpClient();
}
private void initViews() {
tvInfo = findViewById(R.id.tv_info);
btnConnect = findViewById(R.id.btn_connect);
btnDisconnect = findViewById(R.id.btn_disconnect);
if (btnConnect != null) {
btnConnect.setOnClickListener(v -> connectToServer());
}
//接收数据线程
private void getDataTR() {
if (btnDisconnect != null) {
btnDisconnect.setOnClickListener(v -> disconnectFromServer());
}
// 添加测试按钮用于测试发送数据
Button btn_left = findViewById(R.id.btn_left);
btn_left.setOnClickListener(v -> {
if (!tcpClient.isConnected()) {
Toast.makeText(this, "未连接到服务器", Toast.LENGTH_SHORT).show();
return;
}
new Thread(() -> {
byte[] buffer = new byte[1024];
while (true) {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
try {
if (udpClient != null) {
udpClient.socket.receive(packet);
//转成Hex
String receivedData = Tool.bytesToHex(packet.getData());
Log.d(TAG, receivedData);
}
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "getDataTR: stop");
// Log.e(TAG, " "+ e );
}
// 发送测试数据
byte[] testData = new byte[]{(byte) 0xFF, 0x01, 0x00, 0x04, (byte) 0xFF, 0x00, 0x04};
tcpClient.sendBytes(testData);
Thread.sleep(200);
// 发送测试数据
byte[] testData1 = new byte[]{(byte) 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01};
tcpClient.sendBytes(testData1);
Log.d(TAG, "发送测试数据: " + bytesToHex(testData));
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
);
// 添加测试按钮用于测试发送数据
Button btn_right = findViewById(R.id.btn_right);
btn_right.setOnClickListener(v -> {
if (!tcpClient.isConnected()) {
Toast.makeText(this, "未连接到服务器", Toast.LENGTH_SHORT).show();
return;
}
new Thread(() -> {
try {
// 发送测试数据
byte[] testData = new byte[]{(byte) 0xFF, 0x01, 0x00, 0x02, (byte) 0xFF, 0x00, 0x02};
tcpClient.sendBytes(testData);
Thread.sleep(200);
// 发送测试数据
byte[] testData1 = new byte[]{(byte) 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01};
tcpClient.sendBytes(testData1);
Log.d(TAG, "发送测试数据: " + bytesToHex(testData));
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
);
// 添加测试按钮用于测试发送数据
Button btn_centre = findViewById(R.id.btn_centre);
btn_centre.setOnClickListener(v -> {
if (!tcpClient.isConnected()) {
Toast.makeText(this, "未连接到服务器", Toast.LENGTH_SHORT).show();
return;
}
// 发送测试数据
byte[] testData = new byte[]{(byte) 0xFF, 0x01, 0x13, 0x03, 0x00, 0x00, 0x17};
tcpClient.sendBytes(testData);
Log.d(TAG, "发送测试数据: " + bytesToHex(testData));
}
);
// // 添加测试按钮用于测试发送数据
// Button btnTestSend = findViewById(R.id.btn_left);
// // 添加测试按钮用于测试发送数据
// Button btnTestSend = findViewById(R.id.btn_left);
}
private void initTcpClient() {
tcpClient = new TcpClientUtil();
// 设置用于显示信息的TextView
if (tvInfo != null) {
tcpClient.setInfoTextView(tvInfo);
}
}
private void connectToServer() {
// 这里使用示例IP和端口需要根据实际情况修改
tcpClient.connect("192.168.144.119", 2000);
}
private void disconnectFromServer() {
tcpClient.disconnect();
}
private void testSendData() {
}
private String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02X ", b));
}
return result.toString().trim();
}
@Override
protected void onDestroy() {
super.onDestroy();
isRunning = false;
if (tcpClient != null) {
tcpClient.disconnect();
}
}
// 示例方法发送云台控制指令
// private void sendPTZCommand(Instruction instruction) {
// if (!tcpClient.isConnected()) {
// Toast.makeText(this, "未连接到服务器", Toast.LENGTH_SHORT).show();
// return;
// }
//
// Protocol protocol = new Protocol(
// ADDRESS_CODE,
// instruction.getCode1(),
// instruction.getCode2(),
// (byte) 0x00,
// (byte) 0x00
// );
// byte[] bytes = protocol.toBytes();
// tcpClient.sendBytes(bytes);
// Log.d(TAG, "发送指令: " + instruction.name() + ", 数据: " + bytesToHex(bytes));
// }
}

View File

@ -106,5 +106,45 @@ public class BroadcastUtil {
intent.clone();
}
/**
* MAVLINK_MSG_ID_RC_CHANNELS
*
* @param context 上下文
* @param data 数据-json
*/
public static void Broadcast_RC_CHANNELS(Context context, String data) {
Intent intent = new Intent("Broadcast_RC_CHANNELS");
intent.putExtra("data", data);
context.sendBroadcast(intent);
intent.clone();
}
/**
* MAVLINK_MSG_ID_RC_CHANNELS_RAW
*
* @param context 上下文
* @param data 数据-json
*/
public static void Broadcast_RC_CHANNELS_RAW(Context context, String data) {
Intent intent = new Intent("Broadcast_RC_CHANNELS_RAW");
intent.putExtra("data", data);
context.sendBroadcast(intent);
intent.clone();
}
/**
* MAVLINK_MSG_ID_VFR_HUD
*
* @param context 上下文
* @param data 数据-json
*/
public static void Broadcast_VFR_HUD(Context context, String data) {
Intent intent = new Intent("Broadcast_VFR_HUD");
intent.putExtra("data", data);
context.sendBroadcast(intent);
intent.clone();
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFFFFF" />
<stroke
android:width="1dp"
android:color="#CCCCCC" />
<corners android:radius="8dp" />
</shape>

View File

@ -3,6 +3,6 @@
<corners android:topLeftRadius="4dp" android:topRightRadius="4dp"/>
<solid android:color="#49B6E7"/>
<solid android:color="#029A45"/>
</shape>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="4dp"/>
<corners android:radius="2dp"/>
<solid android:color="#8DECEC"/>

View File

@ -27,7 +27,7 @@
android:layout_marginBottom="10dp"/>
<EditText
android:text="admin"
android:text="admin1"
android:textSize="12sp"
android:id="@+id/et_username"
android:layout_width="match_parent"

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout 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"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity2">
<TextView
android:gravity="center"
android:text="text"
android:textColor="#303030"
android:id="@+id/tv_text"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- 添加TCP连接控制按钮 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp">
<Button
android:id="@+id/btn_connect"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="连接"
android:layout_marginEnd="4dp"/>
<Button
android:id="@+id/btn_disconnect"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="断开"
android:layout_marginStart="4dp"/>
</LinearLayout>
<!-- 添加TCP连接控制按钮 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp">
<Button
android:id="@+id/btn_left"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="左"
android:layout_marginEnd="4dp"/>
<Button
android:id="@+id/btn_right"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="右"
android:layout_marginEnd="4dp"/>
<Button
android:id="@+id/btn_centre"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="回中"
android:layout_marginEnd="4dp"/>
<Button
android:id="@+id/btn_up"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="上"
android:layout_marginStart="4dp"/>
<Button
android:id="@+id/btn_down"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="下"
android:layout_marginStart="4dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 添加用于显示TCP数据的TextView -->
<TextView
android:id="@+id/tv_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/black"
android:textColor="@android:color/holo_green_light"
android:padding="8dp"
android:textSize="12sp"
android:scrollbars="vertical"
android:maxLines="10"
android:layout_margin="8dp"/>
</LinearLayout>
</ScrollView>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,591 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Main.Activity.PlayBackActivity">
<com.amap.api.maps.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00ffffff"
android:elevation="10dp">
<!-- 标题栏 -->
<LinearLayout
android:id="@+id/ll_title"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_marginTop="-1dp"
android:background="@mipmap/icon_title_bg">
<ImageView
android:id="@+id/iv_logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dp"
android:src="@mipmap/logo_w" />
<TextView
android:id="@+id/tv_connect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="8dp"
android:text="未知模式"
android:textColor="#ffffff"
android:textSize="9sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="26dp"
android:layout_gravity="center_vertical"
android:gravity="end|center_vertical"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="26dp"
android:background="@drawable/b2ffffff_4round_1stroke_bg"
android:gravity="center"
android:padding="5dp">
<ImageView
android:layout_width="15dp"
android:layout_height="15dp"
android:src="@mipmap/icon_satellite" />
<TextView
android:id="@+id/tv_satellite"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="-.-"
android:textColor="#D8E481"
android:textSize="9sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="26dp"
android:background="@drawable/b2ffffff_4round_1stroke_bg"
android:gravity="center_vertical"
android:padding="5dp">
<ImageView
android:layout_width="15dp"
android:layout_height="15dp"
android:src="@mipmap/icon_power" />
<TextView
android:id="@+id/tv_power"
android:layout_width="36dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="-.-"
android:textColor="#D8E481"
android:textSize="8sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="26dp"
android:background="@drawable/b2ffffff_4round_1stroke_bg"
android:gravity="center"
android:padding="5dp"
android:visibility="gone">
<ImageView
android:layout_width="15dp"
android:layout_height="15dp"
android:src="@mipmap/icon_speed" />
<TextView
android:id="@+id/tv_vel"
android:layout_width="36dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="-.-"
android:textColor="#D8E481"
android:textSize="8sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="26dp"
android:background="@drawable/b2ffffff_4round_1stroke_bg"
android:gravity="center_vertical"
android:padding="5dp">
<ImageView
android:layout_width="15dp"
android:layout_height="15dp"
android:src="@mipmap/icon_height_fly" />
<TextView
android:id="@+id/tv_height"
android:layout_width="36dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="-.-"
android:textColor="#D8E481"
android:textSize="8sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- 左侧功能布局 -->
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/ll_title"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="110dp">
<LinearLayout
android:id="@+id/ll_left_error_layout"
android:layout_width="wrap_content"
android:layout_height="110dp"
android:layout_marginTop="3dp"
android:background="@drawable/xbb303030_4round_bg"
android:orientation="vertical"
android:visibility="gone">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_error_list"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
</com.amap.api.maps.MapView>
<!-- 偏航文字 -->
<TextView
android:id="@+id/tv_yaw"
android:layout_width="25dp"
android:layout_height="wrap_content"
android:layout_above="@+id/ll_text"
android:layout_alignParentRight="true"
android:layout_marginRight="226dp"
android:layout_marginBottom="5dp"
android:background="@drawable/xbb303030_4round_bg"
android:elevation="10dp"
android:gravity="center"
android:padding="3dp"
android:text="0°"
android:textColor="#ffffff"
android:textSize="8sp" />
<!-- 底部数据栏 -->
<RelativeLayout
android:id="@+id/ll_text"
android:layout_width="match_parent"
android:layout_height="110dp"
android:layout_alignParentBottom="true"
android:elevation="10dp"
android:orientation="horizontal"
android:visibility="visible">
<LinearLayout
android:layout_margin="5dp"
android:orientation="vertical"
android:layout_alignParentBottom="true"
android:layout_marginRight="20dp"
android:background="@drawable/x80000000_4round_bg"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<!-- 自定义进度条 -->
<com.example.longyi_groundstation.Main.View.CustomSeekBar
android:id="@+id/custom_seekbar"
android:layout_width="300dp"
android:layout_height="35dp"
android:layout_weight="1"
android:layout_margin="5dp" />
<!-- 路线规划 -->
<LinearLayout
android:layout_gravity="center_horizontal"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:id="@+id/ll_link"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/ll_title"
android:layout_alignParentRight="true"
android:orientation="horizontal"
android:visibility="visible">
<LinearLayout
android:id="@+id/ll_link_save"
android:layout_width="60dp"
android:layout_height="25dp"
android:background="@drawable/b2101010_4round_1stroke_bg"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="25dp"
android:gravity="center"
android:text="开始/暂停"
android:textColor="#ffffff"
android:textSize="8sp" />
</LinearLayout>
<LinearLayout
android:layout_marginLeft="10dp"
android:id="@+id/ll_link_fun1"
android:layout_width="60dp"
android:layout_height="25dp"
android:background="@drawable/b2101010_4round_1stroke_bg"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="25dp"
android:gravity="center"
android:text="X 1.5"
android:textColor="#ffffff"
android:textSize="8sp" />
</LinearLayout>
<LinearLayout
android:layout_marginLeft="10dp"
android:id="@+id/ll_link_fun2"
android:layout_width="60dp"
android:layout_height="25dp"
android:background="@drawable/b2101010_4round_1stroke_bg"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="25dp"
android:gravity="center"
android:text="X 2.0"
android:textColor="#ffffff"
android:textSize="8sp" />
</LinearLayout>
<LinearLayout
android:layout_marginLeft="10dp"
android:id="@+id/ll_link_back"
android:layout_width="60dp"
android:layout_height="25dp"
android:background="@drawable/b2101010_4round_1stroke_bg"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="25dp"
android:gravity="center"
android:text="重新播放"
android:textColor="#ffffff"
android:textSize="8sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_margin="5dp"
android:layout_alignParentBottom="true"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:layout_alignParentRight="true"
android:background="@drawable/ff101010_120round_bg"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="5dp">
<RelativeLayout
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_marginLeft="2dp">
<!-- 天地仪 -->
<com.example.longyi_groundstation.Main.View.CircularLinearLayout
android:id="@+id/cll_layout"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_centerInParent="true"
android:orientation="vertical"
android:visibility="invisible">
<RelativeLayout
android:layout_width="72dp"
android:layout_height="72dp">
<!-- 天地-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:id="@+id/v_welkin"
android:layout_width="match_parent"
android:layout_height="35dp"
android:background="#B875C5DB" />
</LinearLayout>
<!-- 俯仰 -->
<LinearLayout
android:id="@+id/ll_pitch"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="0dp"
android:gravity="center_horizontal"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="3dp"
android:text="45"
android:textColor="#ffffff"
android:textSize="4sp" />
<View
android:layout_width="14dp"
android:layout_height="1dp"
android:layout_marginRight="7dp"
android:background="#ffffff" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="3dp"
android:text="30"
android:textColor="#ffffff"
android:textSize="4sp" />
<View
android:layout_width="22dp"
android:layout_height="1dp"
android:layout_marginRight="6dp"
android:background="#ffffff" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="3dp"
android:text="15"
android:textColor="#ffffff"
android:textSize="4sp" />
<View
android:layout_width="30dp"
android:layout_height="1dp"
android:layout_marginRight="6dp"
android:background="#ffffff" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="4dp"
android:text="0"
android:textColor="#ffffff"
android:textSize="4sp" />
<View
android:layout_width="40dp"
android:layout_height="1.5dp"
android:layout_marginRight="6dp"
android:background="#DBCE16" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="3dp"
android:text="15"
android:textColor="#ffffff"
android:textSize="4sp" />
<View
android:layout_width="30dp"
android:layout_height="1dp"
android:layout_marginRight="6dp"
android:background="#ffffff" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="3dp"
android:text="30"
android:textColor="#ffffff"
android:textSize="4sp" />
<View
android:layout_width="22dp"
android:layout_height="1dp"
android:layout_marginRight="6dp"
android:background="#ffffff" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="3dp"
android:text="45"
android:textColor="#ffffff"
android:textSize="4sp" />
<View
android:layout_width="14dp"
android:layout_height="1dp"
android:layout_marginRight="7dp"
android:background="#ffffff" />
</LinearLayout>
</LinearLayout>
<!-- 翻滚 -->
<ImageView
android:id="@+id/iv_roll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:src="@mipmap/icon_instrument_roll" />
</RelativeLayout>
</com.example.longyi_groundstation.Main.View.CircularLinearLayout>
<ImageView
android:id="@+id/iv_yaw"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_centerInParent="true"
android:src="@mipmap/icon_instrument_yaw" />
<!-- 小飞机 -->
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_centerInParent="true"
android:paddingBottom="3dp"
android:src="@mipmap/icon_instrument_fly" />
<LinearLayout
android:layout_width="90dp"
android:layout_height="90dp"
android:gravity="center_horizontal"
android:padding="16dp">
<ImageView
android:layout_width="5dp"
android:layout_height="5dp"
android:src="@mipmap/icon_instrument_pitch_z" />
</LinearLayout>
</RelativeLayout>
<!-- 底部状态栏 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:gravity="right"
android:orientation="horizontal"
tools:ignore="RtlHardcoded">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_type_list"
android:layout_width="160dp"
android:layout_height="match_parent"
android:layout_marginLeft="5dp"
android:layout_marginRight="10dp"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
<!-- 主页面 -->
</RelativeLayout>

View File

@ -65,7 +65,7 @@
<TextView
android:textSize="12sp"
android:layout_marginTop="3dp"
android:layout_marginTop="1dp"
android:background="@drawable/b2303030_4round_1stroke_bg"
android:textColor="#303030"
android:id="@+id/tv_control"
@ -76,7 +76,7 @@
<TextView
android:textSize="12sp"
android:layout_marginTop="3dp"
android:layout_marginTop="1dp"
android:background="@drawable/b2303030_4round_1stroke_bg"
android:textColor="#303030"
android:id="@+id/tv_fly"
@ -87,7 +87,7 @@
<TextView
android:textSize="12sp"
android:layout_marginTop="3dp"
android:layout_marginTop="1dp"
android:background="@drawable/b2303030_4round_1stroke_bg"
android:textColor="#303030"
android:id="@+id/tv_secure"
@ -98,7 +98,7 @@
<TextView
android:textSize="12sp"
android:layout_marginTop="3dp"
android:layout_marginTop="1dp"
android:background="@drawable/b2303030_4round_1stroke_bg"
android:textColor="#303030"
android:id="@+id/tv_motor"
@ -109,7 +109,7 @@
<TextView
android:textSize="12sp"
android:layout_marginTop="3dp"
android:layout_marginTop="1dp"
android:background="@drawable/b2303030_4round_1stroke_bg"
android:textColor="#303030"
android:id="@+id/tv_load"
@ -118,9 +118,10 @@
android:layout_width="match_parent"
android:layout_height="35dp"/>
<TextView
android:textSize="12sp"
android:layout_marginTop="3dp"
android:layout_marginTop="1dp"
android:background="@drawable/b2303030_4round_1stroke_bg"
android:textColor="#303030"
android:id="@+id/tv_sensor"
@ -129,10 +130,11 @@
android:layout_width="match_parent"
android:layout_height="35dp"/>
<TextView
android:textSize="12sp"
android:id="@+id/tv_parameter"
android:layout_marginTop="3dp"
android:layout_marginTop="1dp"
android:background="@drawable/b2303030_4round_1stroke_bg"
android:textColor="#303030"
android:gravity="center"

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="180dp"
android:background="@drawable/x80000000_4round_bg"
android:padding="5dp"
android:orientation="vertical"
android:layout_margin="3dp"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_title"
android:gravity="center"
android:textStyle="bold"
android:textColor="#ffffff"
android:textSize="9sp"
android:text="名称:"
android:layout_width="wrap_content"
android:layout_height="22dp"/>
<TextView
android:layout_alignParentRight="true"
android:id="@+id/tv_del"
android:layout_marginLeft="10dp"
android:gravity="center"
android:textColor="#ffffff"
android:background="@drawable/ffdd635a_4round_1stroke_bg"
android:textSize="9sp"
android:text="删除"
android:layout_width="42dp"
android:layout_height="20dp"/>
</RelativeLayout>
<LinearLayout
android:orientation="vertical"
android:padding="8dp"
android:background="@drawable/ffffffff_4round_bg"
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_marginLeft="10dp"
android:textColor="#303030"
android:textSize="8sp"
android:text="创建时间:"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tv_time"
android:layout_marginLeft="10dp"
android:textColor="#303030"
android:textSize="7sp"
android:text="2010-10-10 12:00:00"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_marginLeft="10dp"
android:textColor="#303030"
android:textSize="8sp"
android:text="点位数量:"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tv_number"
android:layout_marginLeft="10dp"
android:textColor="#303030"
android:textSize="7sp"
android:text="12个"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_margin="6dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp">
@ -11,7 +11,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
android:padding="8dp">
<RelativeLayout
android:orientation="horizontal"
@ -28,6 +28,7 @@
android:textStyle="bold" />
<TextView
android:layout_centerVertical="true"
android:textStyle="bold"
android:layout_alignParentRight="true"
android:id="@+id/tv_current_value"
@ -35,63 +36,40 @@
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginRight="10dp"
android:text="1200"
android:text="00"
android:textColor="#62a7f0"
android:textSize="11sp" />
</RelativeLayout>
<!-- 添加条形图 -->
<LinearLayout
android:id="@+id/ll_progress_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_height="8dp"
android:layout_marginTop="6dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_max_desc"
<View
android:id="@+id/view_left_progress"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="最大值说明: "
android:textColor="#888"
android:textSize="10sp" />
android:background="#62a7f0" />
<TextView
android:id="@+id/tv_min_desc"
<View
android:id="@+id/view_right_progress"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="最小值说明: "
android:textColor="#888"
android:textSize="10sp" />
android:background="#cccccc" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<TextView
android:textSize="11sp"
android:id="@+id/tv_max_value"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="最大值: "
android:textColor="#666" />
<TextView
android:textSize="11sp"
android:id="@+id/tv_min_value"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="最小值: "
android:textColor="#666" />
</LinearLayout>

View File

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="160dp"
android:background="@drawable/x80000000_4round_bg"
android:padding="5dp"
android:orientation="vertical"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_title"
android:gravity="center"
android:textStyle="bold"
android:textColor="#ffffff"
android:textSize="11sp"
android:text="名称:"
android:layout_width="wrap_content"
android:layout_height="22dp"/>
<TextView
android:layout_alignParentRight="true"
android:id="@+id/tv_del"
android:layout_marginLeft="10dp"
android:gravity="center"
android:textColor="#ffffff"
android:background="@drawable/ffdd635a_4round_1stroke_bg"
android:textSize="9sp"
android:text="删除"
android:layout_width="42dp"
android:layout_height="20dp"/>
</RelativeLayout>
<LinearLayout
android:orientation="vertical"
android:padding="10dp"
android:background="@drawable/ffffffff_4round_bg"
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_marginLeft="10dp"
android:textColor="#303030"
android:textSize="9sp"
android:text="高度:"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<EditText
android:gravity="center"
android:layout_marginLeft="10dp"
android:text="30"
android:textSize="9sp"
android:background="#ffffff"
android:id="@+id/et_height"
android:layout_width="30dp"
android:layout_height="wrap_content"/>
<TextView
android:layout_marginLeft="10dp"
android:textColor="#303030"
android:textSize="9sp"
android:text="m"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_marginLeft="10dp"
android:textColor="#303030"
android:textSize="9sp"
android:text="速度:"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<EditText
android:gravity="center"
android:layout_marginLeft="10dp"
android:text="30"
android:textSize="9sp"
android:background="#ffffff"
android:id="@+id/et_speed"
android:layout_width="30dp"
android:layout_height="wrap_content"/>
<TextView
android:layout_marginLeft="10dp"
android:textColor="#303030"
android:textSize="9sp"
android:text="m/s"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -24,7 +24,7 @@
<LinearLayout
android:orientation="vertical"
android:layout_width="200dp"
android:layout_width="160dp"
android:layout_height="wrap_content">
<TextView

View File

@ -4,12 +4,13 @@
android:layout_height="wrap_content">
<TextView
android:gravity="center"
android:id="@+id/tv_item"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_margin="6dp"
android:textColor="@android:color/white"
android:textSize="16sp"
android:padding="12dp"/>
android:textSize="10sp"
android:padding="6dp"/>
</LinearLayout>

View File

@ -7,11 +7,15 @@
android:id="@+id/ll_main">
<TextView
android:textColor="#ffffff"
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="7sp"
android:textColor="#ffffff" />
android:textSize="8sp"
android:maxWidth="400dp"
android:minWidth="0dp"
android:singleLine="true"
android:ellipsize="none" />
</LinearLayout>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/custom_info_bubble"
android:orientation="vertical"
android:padding="8dp">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textColor="#000000"
android:textSize="14sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="4dp">
<Button
android:id="@+id/delete_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="删除"
android:textSize="12sp"
android:background="#FF5555"
android:textColor="#FFFFFF" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="30dp"
android:layout_height="40dp"
android:orientation="vertical"
android:gravity="center">
<!-- 自定义图标 -->
<ImageView
android:layout_centerHorizontal="true"
android:id="@+id/marker_icon"
android:layout_width="25dp"
android:layout_height="40dp"
android:src="@mipmap/icon_marker" />
<!-- 文字标签 -->
<TextView
android:layout_alignParentBottom="true"
android:id="@+id/marker_text"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:text="点位1"
android:textSize="7sp"
android:textColor="#ffffff"
android:background="@drawable/x80000000_4round_bg"
android:gravity="center" />
</RelativeLayout>

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="300dp"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:background="@drawable/ff029a45_4round_bg"
android:gravity="center"
android:padding="8dp"
android:text="投弹"
android:textColor="#fff"
android:textSize="13sp" />
<LinearLayout
android:layout_margin="8dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:textSize="12sp"
android:text="高度设置:"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<EditText
android:textSize="12sp"
android:padding="2dp"
android:id="@+id/et_height"
android:background="@drawable/b2303030_4round_1stroke_bg"
android:layout_width="50dp"
android:layout_height="wrap_content"/>
<TextView
android:textSize="12sp"
android:layout_marginLeft="3dp"
android:text="M"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<com.example.longyi_groundstation.Main.View.SlideToUnlockView
android:background="#ffffff"
android:id="@+id/unlockView"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:layout_margin="8dp" />
<TextView
android:id="@+id/tv_message"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_gravity="center"
android:background="#C3606060"
android:gravity="center"
android:text="取消"
android:textColor="#ffffff"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>

View File

@ -14,7 +14,7 @@
android:padding="8dp"
android:gravity="center"
android:text="警告"
android:background="@drawable/eb51518b_4round_bg"
android:background="@drawable/ff029a45_4round_bg"
android:layout_gravity="center_horizontal"
android:id="@+id/tv_title"
android:layout_width="match_parent"

View File

@ -14,7 +14,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:background="@drawable/eb51518b_4round_bg"
android:background="@drawable/ff029a45_4round_bg"
android:gravity="center"
android:padding="8dp"
android:text="返航"

View File

@ -14,7 +14,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:background="@drawable/eb51518b_4round_bg"
android:background="@drawable/ff029a45_4round_bg"
android:gravity="center"
android:padding="8dp"
android:text="起飞"

View File

@ -14,7 +14,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:background="@drawable/eb51518b_4round_bg"
android:background="@drawable/ff029a45_4round_bg"
android:gravity="center"
android:padding="8dp"
android:text="降落"

View File

@ -1,28 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#555f75"
android:background="#112446"
android:orientation="vertical"
tools:context=".Main.Setting.Fragment.MotorFragment">
<TextView
android:textSize="10sp"
android:layout_alignParentRight="true"
android:layout_margin="8dp"
android:layout_margin="6dp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"
android:textColor="#ffffff"
android:id="@+id/tv_calibration"
android:gravity="center"
android:text="参数校准"
android:layout_width="120dp"
android:layout_height="35dp"/>
android:layout_width="100dp"
android:padding="6dp"
android:layout_height="wrap_content"/>
<androidx.recyclerview.widget.RecyclerView
android:background="@drawable/ff112446_4round_bg"
android:id="@+id/rv_data"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="50dp"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginBottom="6dp"
android:padding="6dp"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
</LinearLayout>

View File

@ -1,13 +1,451 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#555f75"
android:background="#112446"
android:padding="8dp"
android:orientation="horizontal"
tools:context=".Main.Setting.Fragment.MotorFragment">
<LinearLayout
android:orientation="vertical"
android:layout_weight="2.5"
android:layout_width="0dp"
android:layout_height="match_parent">
<!-- 功能按钮 -->
<RelativeLayout
android:paddingRight="30dp"
android:paddingLeft="10dp"
android:layout_marginTop="16dp"
android:layout_gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:id="@+id/tv_default"
android:layout_marginLeft="5dp"
android:layout_marginRight="20dp"
android:gravity="center"
android:textColor="#ffffff"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"
android:textSize="10sp"
android:text="恢复默认"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:layout_width="wrap_content"
android:layout_height="22dp"/>
<TextView
android:layout_alignParentRight="true"
android:id="@+id/tv_save"
android:gravity="center"
android:textColor="#ffffff"
android:background="@drawable/ff60b964_4round_1stroke_bg"
android:textSize="10sp"
android:text="保存"
android:layout_width="42dp"
android:layout_height="22dp"/>
</RelativeLayout>
<!-- 最大平飞速度 -->
<LinearLayout
android:layout_marginTop="16dp"
android:layout_gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:gravity="right"
android:textSize="10sp"
android:text="最大平飞速度:"
android:textColor="#ffffff"
android:layout_width="80dp"
android:layout_height="wrap_content"/>
<!-- 减按钮 -->
<TextView
android:layout_marginLeft="5dp"
android:gravity="center"
android:id="@+id/tv_flight_speed_minus"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="-"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<!-- 滑动条 -->
<SeekBar
android:id="@+id/seekBar_flight_speed"
android:layout_width="140dp"
android:layout_marginRight="5dp"
android:layout_marginLeft="5dp"
android:layout_height="wrap_content"
android:max="3500"
android:min="20"
android:progress="0"
/>
<!-- 加按钮 -->
<TextView
android:gravity="center"
android:id="@+id/tv_flight_speed_add"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="+"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<TextView
android:layout_marginLeft="3dp"
android:textSize="10sp"
android:id="@+id/tv_flight_speed"
android:text="20cm/s"
android:textColor="#ffffff"
android:layout_width="50dp"
android:gravity="right"
android:layout_height="wrap_content"/>
</LinearLayout>
<!-- 最大平飞速度 -->
<LinearLayout
android:layout_marginTop="16dp"
android:layout_gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:gravity="right"
android:textSize="10sp"
android:text="最大爬升速度:"
android:textColor="#ffffff"
android:layout_width="80dp"
android:layout_height="wrap_content"/>
<!-- 减按钮 -->
<TextView
android:layout_marginLeft="5dp"
android:gravity="center"
android:id="@+id/tv_climb_speed_minus"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="-"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<!-- 滑动条 -->
<SeekBar
android:id="@+id/seekBar_climb_speed"
android:layout_width="140dp"
android:layout_marginRight="5dp"
android:layout_marginLeft="5dp"
android:layout_height="wrap_content"
android:max="500"
android:min="50"
android:progress="0"
/>
<!-- 加按钮 -->
<TextView
android:gravity="center"
android:id="@+id/tv_climb_speed_add"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="+"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<TextView
android:layout_marginLeft="3dp"
android:textSize="10sp"
android:id="@+id/tv_climb_speed"
android:text="50cm/s"
android:textColor="#ffffff"
android:layout_width="50dp"
android:gravity="right"
android:layout_height="wrap_content"/>
</LinearLayout>
<!-- 最大平飞速度 -->
<LinearLayout
android:layout_marginTop="16dp"
android:layout_gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:gravity="right"
android:textSize="10sp"
android:text="最大下降速度:"
android:textColor="#ffffff"
android:layout_width="80dp"
android:layout_height="wrap_content"/>
<!-- 减按钮 -->
<TextView
android:layout_marginLeft="5dp"
android:gravity="center"
android:id="@+id/tv_decline_speed_minus"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="-"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<!-- 滑动条 -->
<SeekBar
android:id="@+id/seekBar_decline_speed"
android:layout_width="140dp"
android:layout_marginRight="5dp"
android:layout_marginLeft="5dp"
android:layout_height="wrap_content"
android:max="500"
android:min="0"
android:progress="0"
/>
<!-- 加按钮 -->
<TextView
android:gravity="center"
android:id="@+id/tv_decline_speed_add"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="+"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<TextView
android:layout_marginLeft="3dp"
android:textSize="10sp"
android:id="@+id/tv_decline_speed"
android:text="0cm/s"
android:textColor="#ffffff"
android:layout_width="50dp"
android:gravity="right"
android:layout_height="wrap_content"/>
</LinearLayout>
<!-- 最大平飞速度 -->
<LinearLayout
android:layout_marginTop="16dp"
android:layout_gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:gravity="right"
android:textSize="10sp"
android:text="最大水平角度:"
android:textColor="#ffffff"
android:layout_width="80dp"
android:layout_height="wrap_content"/>
<!-- 减按钮 -->
<TextView
android:layout_marginLeft="5dp"
android:gravity="center"
android:id="@+id/tv_horizontal_angle_minus"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="-"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<!-- 滑动条 -->
<SeekBar
android:id="@+id/seekBar_horizontal_angle"
android:layout_width="140dp"
android:layout_marginRight="5dp"
android:layout_marginLeft="5dp"
android:layout_height="wrap_content"
android:max="8000"
android:min="1000"
android:progress="0"
/>
<!-- 加按钮 -->
<TextView
android:gravity="center"
android:id="@+id/tv_horizontal_angle_add"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="+"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<TextView
android:layout_marginLeft="3dp"
android:textSize="10sp"
android:id="@+id/tv_horizontal_angle"
android:text="1000cdeg"
android:textColor="#ffffff"
android:layout_width="50dp"
android:gravity="right"
android:layout_height="wrap_content"/>
</LinearLayout>
<!-- 最大平飞速度 -->
<LinearLayout
android:layout_marginTop="16dp"
android:layout_gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:gravity="right"
android:textSize="10sp"
android:text="最大旋转速率:"
android:textColor="#ffffff"
android:layout_width="80dp"
android:layout_height="wrap_content"/>
<!-- 减按钮 -->
<TextView
android:layout_marginLeft="5dp"
android:gravity="center"
android:id="@+id/tv_rotation_rate_minus"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="-"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<!-- 滑动条 -->
<SeekBar
android:id="@+id/seekBar_rotation_rate"
android:layout_width="140dp"
android:layout_marginRight="5dp"
android:layout_marginLeft="5dp"
android:layout_height="wrap_content"
android:max="3600"
android:progress="10"
/>
<!-- 加按钮 -->
<TextView
android:gravity="center"
android:id="@+id/tv_rotation_rate_add"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="+"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<TextView
android:layout_marginLeft="3dp"
android:textSize="10sp"
android:id="@+id/tv_rotation_rate"
android:text="1.0度/s"
android:textColor="#ffffff"
android:layout_width="50dp"
android:gravity="right"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:background="@drawable/ffffffff_4round_bg"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_margin="10dp"
android:text=" 1.最大平飞速度‌:指无人机在水平方向能达到的最高飞行速度。"
android:textColor="#606060"
android:textSize="12sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_margin="10dp"
android:text=" 2.最大爬升速度‌:指无人机垂直上升时的最高速率"
android:textColor="#606060"
android:textSize="12sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_margin="10dp"
android:text=" 3.最大下降速度‌:指无人机垂直下降时的最高安全速率"
android:textColor="#606060"
android:textSize="12sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_margin="10dp"
android:text=" 4.最大水平角度‌:指无人机倾斜飞行的最大角度(以度为单位),影响机动性和抗风能力"
android:textColor="#606060"
android:textSize="12sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_margin="10dp"
android:text=" 5.最大旋转速率‌:指无人机绕轴旋转的最高角速度(单位 m/秒),用于快速转向或姿态调整。"
android:textColor="#606060"
android:textSize="12sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</ScrollView>
</LinearLayout>
</RelativeLayout>
</LinearLayout>

View File

@ -0,0 +1,12 @@
<?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">
<TextView
android:textColor="#ffffff"
android:text="加速度"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>

View File

@ -0,0 +1,12 @@
<?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">
<TextView
android:textColor="#ffffff"
android:text="安装设置"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>

View File

@ -0,0 +1,12 @@
<?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">
<TextView
android:textColor="#ffffff"
android:text="磁力"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>

View File

@ -0,0 +1,13 @@
<?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:padding="6dp">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

View File

@ -1,16 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Main.Setting.Fragment.MotorFragment">
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#555f75"
android:orientation="vertical"
tools:context=".Main.Setting.Fragment.FoundationFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:background="#cdcdcd"
android:gravity="center"
android:text="维护中.."
android:background="#cdcdcd"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="正在维护.." />
android:layout_height="match_parent"/>
</FrameLayout>
<com.google.android.material.tabs.TabLayout
android:layout_marginTop="6dp"
android:layout_marginLeft="6dp"
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="26dp"
android:background="#555f75"
app:tabIndicatorHeight="0dp"
app:tabRippleColor="@null"
app:tabBackground="@drawable/tab_background_selector"
app:tabTextColor="@drawable/tab_text_color_selector"
app:tabTextAppearance="@style/CustomTabTextAppearance"
android:contentDescription="载荷选择" />
<androidx.viewpager2.widget.ViewPager2
android:background="@drawable/ff112446_4round_bg"
android:layout_margin="6dp"
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
<?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:orientation="vertical"
android:background="#ff112446">
<TextView
android:gravity="center"
android:text="维护中.."
android:background="#cdcdcd"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

View File

@ -3,17 +3,47 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#555f75"
android:background="#112446"
android:orientation="horizontal"
tools:context=".Main.Setting.Fragment.MotorFragment">
<LinearLayout
android:gravity="bottom"
android:orientation="vertical"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_marginTop="30dp"
android:layout_gravity="center"
android:src="@mipmap/icon_ft60"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_marginTop="16dp"
android:layout_gravity="center"
android:text="FT60"
android:textColor="#ffffff"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:gravity="bottom"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 持续时间控制区域 -->
<LinearLayout
android:layout_marginLeft="16dp"
@ -26,17 +56,18 @@
android:layout_marginBottom="24dp">
<TextView
android:textSize="10sp"
android:text="持续时间:"
android:textColor="#ffffff"
android:layout_width="70dp"
android:layout_width="60dp"
android:layout_height="wrap_content"/>
<!-- 减按钮 -->
<TextView
android:gravity="center"
android:id="@+id/tv_time_minus"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="-"
android:textColor="#ffffff"
android:textSize="10sp"
@ -59,8 +90,8 @@
<TextView
android:gravity="center"
android:id="@+id/tv_time_add"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="+"
android:textColor="#ffffff"
android:textSize="10sp"
@ -68,6 +99,7 @@
<TextView
android:textSize="10sp"
android:id="@+id/tv_time"
android:text="0秒"
android:textColor="#ffffff"
@ -88,17 +120,18 @@
android:layout_marginBottom="24dp">
<TextView
android:textSize="10sp"
android:text="油门量:"
android:textColor="#ffffff"
android:layout_width="70dp"
android:layout_width="60dp"
android:layout_height="wrap_content"/>
<!-- 减按钮 -->
<TextView
android:gravity="center"
android:id="@+id/tv_power_minus"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="-"
android:textColor="#ffffff"
android:textSize="10sp"
@ -119,8 +152,8 @@
<TextView
android:gravity="center"
android:id="@+id/tv_power_add"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="+"
android:textColor="#ffffff"
android:textSize="10sp"
@ -128,6 +161,7 @@
<TextView
android:textSize="10sp"
android:id="@+id/tv_power"
android:text="0%"
android:textColor="#ffffff"
@ -136,49 +170,68 @@
android:layout_height="wrap_content"/>
</LinearLayout>
<TextView
android:id="@+id/tv_all_test1"
android:textColor="#ffffff"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"
android:padding="5dp"
android:gravity="center"
android:text="全部旋转"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<TextView
android:id="@+id/tv_all_test2"
android:textColor="#ffffff"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"
android:padding="5dp"
android:gravity="center"
android:text="顺序旋转"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<RelativeLayout
<LinearLayout
android:gravity="center_horizontal"
android:layout_margin="6dp"
android:orientation="vertical"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:layout_alignParentRight="true"
android:layout_centerHorizontal="true"
android:id="@+id/rv_data"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="8dp"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</RelativeLayout>
<TextView
android:textSize="10sp"
android:id="@+id/tv_all_test1"
android:textColor="#ffffff"
android:background="@drawable/ff60b964_4round_1stroke_bg"
android:padding="5dp"
android:gravity="center"
android:text="全部旋转"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"/>
<TextView
android:textSize="10sp"
android:id="@+id/tv_all_test2"
android:textColor="#ffffff"
android:background="@drawable/ffdd635a_4round_1stroke_bg"
android:padding="5dp"
android:gravity="center"
android:text="顺序旋转"
android:layout_marginBottom="16dp"
android:layout_marginRight="16dp"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>

View File

@ -3,24 +3,470 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#555f75"
android:orientation="vertical"
android:padding="6dp"
android:background="#112446"
tools:context=".Main.Setting.Fragment.SecureFragment">
<com.google.android.material.tabs.TabLayout
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
android:id="@+id/tab_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#555f75"
android:contentDescription="载荷选择" />
<androidx.viewpager2.widget.ViewPager2
android:layout_margin="10dp"
android:id="@+id/view_pager"
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
android:layout_height="wrap_content">
<RelativeLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:layout_centerVertical="true"
android:background="@drawable/ffffffff_4round_bg"
android:layout_width="match_parent"
android:layout_height="1.5dp"/>
<TextView
android:background="@drawable/ff112446_4round_bg"
android:gravity="center"
android:layout_centerInParent="true"
android:layout_margin="6dp"
android:textStyle="bold"
android:textColor="#ffffff"
android:textSize="14sp"
android:text="电池"
android:layout_width="60dp"
android:layout_height="wrap_content"/>
</RelativeLayout>
<LinearLayout
android:padding="12dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- 一级电压 -->
<LinearLayout
android:layout_gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
>
<TextView
android:gravity="right"
android:textSize="10sp"
android:text="一级低电压:"
android:textColor="#ffffff"
android:layout_width="60dp"
android:layout_height="wrap_content"/>
<!-- 减按钮 -->
<TextView
android:layout_marginLeft="30dp"
android:gravity="center"
android:id="@+id/tv_one_power_minus"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="-"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<!-- 滑动条 -->
<SeekBar
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:id="@+id/seekBar_one_power"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:max="100"
android:progress="40"
/>
<!-- 加按钮 -->
<TextView
android:gravity="center"
android:id="@+id/tv_one_power_add"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="+"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<TextView
android:textSize="10sp"
android:id="@+id/tv_one_power"
android:text="20.0v"
android:textColor="#ffffff"
android:layout_width="40dp"
android:gravity="right"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:gravity="center_vertical"
android:layout_marginTop="12dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:gravity="right"
android:textSize="10sp"
android:text="保护动作:"
android:textColor="#ffffff"
android:layout_width="60dp"
android:layout_height="wrap_content"/>
<RelativeLayout
android:layout_marginLeft="55dp"
android:layout_width="80dp"
android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/rl_one_power_protect"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:background="@drawable/ff62a7f0_2round_1stroke_bg"
android:id="@+id/tv_one_power_protect"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="10sp"
android:text="返航"
android:layout_width="80dp"
android:padding="5dp"
android:layout_height="wrap_content"/>
<ImageView
android:layout_marginRight="5dp"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:src="@mipmap/icon_spinner_dowm"
android:layout_width="10dp"
android:layout_height="10dp"/>
</RelativeLayout>
<Spinner
android:layout_below="@+id/rl_one_power_protect"
android:id="@+id/sp_one_power_protect"
android:layout_width="80dp"
android:layout_height="0dp" />
</RelativeLayout>
</LinearLayout>
<!-- 二级电压 -->
<LinearLayout
android:layout_marginTop="20dp"
android:layout_gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
>
<TextView
android:gravity="right"
android:textSize="10sp"
android:text="二级低电压:"
android:textColor="#ffffff"
android:layout_width="60dp"
android:layout_height="wrap_content"/>
<!-- 减按钮 -->
<TextView
android:layout_marginLeft="30dp"
android:gravity="center"
android:id="@+id/tv_two_power_minus"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="-"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<!-- 滑动条 -->
<SeekBar
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:id="@+id/seekBar_two_power"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:max="100"
android:progress="20"
/>
<!-- 加按钮 -->
<TextView
android:gravity="center"
android:id="@+id/tv_two_power_add"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="+"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<TextView
android:textSize="10sp"
android:id="@+id/tv_two_power"
android:text="10.0v"
android:textColor="#ffffff"
android:layout_width="40dp"
android:gravity="right"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:layout_marginTop="12dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:gravity="right"
android:textSize="10sp"
android:text="保护动作:"
android:textColor="#ffffff"
android:layout_width="60dp"
android:layout_height="wrap_content"/>
<RelativeLayout
android:layout_marginLeft="55dp"
android:layout_width="80dp"
android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/rl_two_power_protect"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_two_power_protect"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="10sp"
android:text="返航"
android:layout_width="80dp"
android:padding="5dp"
android:layout_height="wrap_content"/>
<ImageView
android:layout_marginRight="5dp"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:src="@mipmap/icon_spinner_dowm"
android:layout_width="10dp"
android:layout_height="10dp"/>
</RelativeLayout>
<Spinner
android:id="@+id/sp_two_power_protect"
android:layout_below="@+id/rl_two_power_protect"
android:layout_width="80dp"
android:layout_height="0dp"/>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:layout_centerVertical="true"
android:background="@drawable/ffffffff_4round_bg"
android:layout_width="match_parent"
android:layout_height="1.5dp"/>
<TextView
android:background="@drawable/ff112446_4round_bg"
android:gravity="center"
android:layout_centerInParent="true"
android:layout_margin="6dp"
android:textStyle="bold"
android:textColor="#ffffff"
android:textSize="14sp"
android:text="链路保护"
android:layout_width="80dp"
android:layout_height="wrap_content"/>
</RelativeLayout>
<LinearLayout
android:padding="12dp"
android:layout_marginTop="6dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- 一级电压 -->
<LinearLayout
android:layout_gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
>
<TextView
android:gravity="right"
android:textSize="10sp"
android:text="通讯超时:"
android:textColor="#ffffff"
android:layout_width="60dp"
android:layout_height="wrap_content"/>
<!-- 减按钮 -->
<TextView
android:layout_marginLeft="30dp"
android:gravity="center"
android:id="@+id/tv_link_minus"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="-"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<EditText
android:id="@+id/et_link"
android:inputType="number"
android:gravity="center"
android:padding="5dp"
android:text="10"
android:textColor="#909090"
android:textSize="10sp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/ffffffff_4round_bg"
android:layout_width="100dp"
android:layout_height="wrap_content"/>
<!-- 加按钮 -->
<TextView
android:gravity="center"
android:id="@+id/tv_link_add"
android:layout_width="22dp"
android:layout_height="22dp"
android:text="+"
android:textColor="#ffffff"
android:textSize="10sp"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"/>
<TextView
android:textSize="10sp"
android:id="@+id/tv_link"
android:text="秒"
android:textColor="#ffffff"
android:layout_width="40dp"
android:gravity="right"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:layout_marginTop="12dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:gravity="right"
android:textSize="10sp"
android:text="保护动作:"
android:textColor="#ffffff"
android:layout_width="60dp"
android:layout_height="wrap_content"/>
<RelativeLayout
android:layout_marginLeft="55dp"
android:layout_width="80dp"
android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/rl_link_protect"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_link_protect"
android:background="@drawable/ff62a7f0_2round_1stroke_bg"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="10sp"
android:text="返航"
android:layout_width="80dp"
android:padding="5dp"
android:layout_height="wrap_content"/>
<ImageView
android:layout_marginRight="5dp"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:src="@mipmap/icon_spinner_dowm"
android:layout_width="10dp"
android:layout_height="10dp"/>
</RelativeLayout>
<Spinner
android:id="@+id/sp_link_protect"
android:layout_below="@+id/rl_link_protect"
android:layout_width="80dp"
android:layout_height="0dp"/>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 885 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B