From dd170bf880918ce00a1df68e8a3c621ada9b5820 Mon Sep 17 00:00:00 2001 From: whycq <913841844@qq.com> Date: 星期五, 07 二月 2025 13:54:30 +0800 Subject: [PATCH] # --- app/src/main/java/com/example/agvcontroller/action/LoginReset.java | 31 +++ app/src/main/java/com/example/agvcontroller/protocol/AGV_03_UP.java | 42 ++++ app/src/main/java/com/example/agvcontroller/protocol/HandleCmdType.java | 3 app/src/main/java/com/example/agvcontroller/MainActivity.java | 19 ++ app/src/main/java/com/example/agvcontroller/utils/ToDBC.java | 16 + app/src/main/res/layout/activity_log.xml | 27 +++ app/src/main/java/com/example/agvcontroller/AGVApplication.java | 33 +++ app/src/main/java/com/example/agvcontroller/LogActivity.java | 39 ++++ app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java | 63 ++++-- app/src/main/res/layout/activity_main.xml | 218 ++++++++++++++--------- app/src/main/res/drawable/new_logo.png | 0 11 files changed, 380 insertions(+), 111 deletions(-) diff --git a/app/src/main/java/com/example/agvcontroller/AGVApplication.java b/app/src/main/java/com/example/agvcontroller/AGVApplication.java new file mode 100644 index 0000000..e7df4b3 --- /dev/null +++ b/app/src/main/java/com/example/agvcontroller/AGVApplication.java @@ -0,0 +1,33 @@ +package com.example.agvcontroller; + +import android.app.Application; +import android.os.Handler; +import android.os.Looper; + +import java.util.ArrayList; +import java.util.List; + +public class AGVApplication extends Application { + private static List<String> logList = new ArrayList<>(); + + @Override + public void onCreate() { + super.onCreate(); + } + + @Override + public void onTerminate() { + super.onTerminate(); + // 娓呯┖鏃ュ織鍒楄〃 + logList.clear(); + } + + public static List<String> getLogList() { + return logList; + } + + public static void addLog(String log) { + logList.add(log); + } + +} diff --git a/app/src/main/java/com/example/agvcontroller/LogActivity.java b/app/src/main/java/com/example/agvcontroller/LogActivity.java new file mode 100644 index 0000000..6438c9c --- /dev/null +++ b/app/src/main/java/com/example/agvcontroller/LogActivity.java @@ -0,0 +1,39 @@ +package com.example.agvcontroller; + +import static com.example.agvcontroller.utils.ToDBC.toDBC; + +import android.os.Bundle; +import android.widget.TextView; +import java.util.List; + +import androidx.appcompat.app.AppCompatActivity; + +public class LogActivity extends AppCompatActivity { + + private TextView logTextView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_log); + + logTextView = findViewById(R.id.log_text_view); + + // 鑾峰彇浼犻�掔殑鏃ュ織鏁版嵁 + List<String> logList = getIntent().getStringArrayListExtra("log_list"); + + + + // 鏇存柊鏃ュ織鏄剧ず + updateLogTextView(logList); + } + + private void updateLogTextView(List<String> logList) { + StringBuilder logBuilder = new StringBuilder(); + for (String log : logList) { + logBuilder.append(log).append("\n"); + } + + logTextView.setText(toDBC(logBuilder.toString())); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/agvcontroller/MainActivity.java b/app/src/main/java/com/example/agvcontroller/MainActivity.java index 33187b5..0c45dd5 100644 --- a/app/src/main/java/com/example/agvcontroller/MainActivity.java +++ b/app/src/main/java/com/example/agvcontroller/MainActivity.java @@ -36,6 +36,7 @@ import com.example.agvcontroller.action.HandLift; import com.example.agvcontroller.action.LiftResetAction; import com.example.agvcontroller.action.LoadResetAction; +import com.example.agvcontroller.action.LoginReset; import com.example.agvcontroller.action.RotatopnLeftRight; import com.example.agvcontroller.action.SingleSwitchAction; import com.example.agvcontroller.action.SingleSwitchRunAction; @@ -68,6 +69,7 @@ private static final int MAX_RECENT_LOGS = 10; // 鏈�澶氭樉绀� 10 鏉℃渶鏂版棩蹇� private static TextView agvBattery; + private static TextView agvSocket; private static TextView agvNo; private static TextView agvStatus; private static TextView agvPositionId; @@ -77,6 +79,7 @@ private static TextView agvForkExtend; private static TextView agvForkAngle; private static TextView agvError; + private Button reLogin; @@ -406,6 +409,7 @@ setContentView(R.layout.activity_main); agvBattery = findViewById(R.id.agv_battery); + agvSocket = findViewById(R.id.socket); agvNo = findViewById(R.id.agv_no); agvStatus = findViewById(R.id.agv_status); agvPositionId = findViewById(R.id.agv_position_id); @@ -415,6 +419,8 @@ agvForkExtend = findViewById(R.id.agv_ford); agvForkAngle = findViewById(R.id.agv_ratio); agvError = findViewById(R.id.agv_error); + reLogin = findViewById(R.id.relogin_button); + @@ -524,6 +530,18 @@ Log.i("message1",clientId); + reLogin.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String substring = String.valueOf(new SnowflakeIdWorker().nextId()).substring(0,16); + AgvAction agvAction = new AgvAction<>(LoginReset.class) + .setAgvNo(AgvNo) + .setSerialNo(substring) + .setVal(1) + .bodySync((action) -> action.setPwd((short) 1)); + nettyServerHandler.sendMessageToClient(clientId, agvAction); // 鍙戦�佹秷鎭埌瀹㈡埛绔� + } + }); // 鍓嶆嫧鏉嗕几鍑� frontPaddleExtendBtn.setOnClickListener(new View.OnClickListener() { @Override @@ -1460,6 +1478,7 @@ AgvNo = agvCar.getAgvNo(); agvNo.setText("AGV缂栧彿锛�" + AgvNo); agvBattery.setText("鐢甸噺锛�" + agvCar.getBattery() + "%"); + agvSocket.setText(agvCar.getStatus() == 1 ? "宸茶繛鎺�" : "鏈繛鎺�"); agvStatus.setText("AGV鐘舵�侊細" + agvCar.getStatus()); agvPositionId.setText("ID锛�" + agvCar.getPositionID()); agvPositionX.setText("(X)锛�" + agvCar.getPositionX()); diff --git a/app/src/main/java/com/example/agvcontroller/action/LoginReset.java b/app/src/main/java/com/example/agvcontroller/action/LoginReset.java new file mode 100644 index 0000000..384ce98 --- /dev/null +++ b/app/src/main/java/com/example/agvcontroller/action/LoginReset.java @@ -0,0 +1,31 @@ +package com.example.agvcontroller.action; + +import com.example.agvcontroller.protocol.IActionBody; +import com.example.agvcontroller.socket.RadixTools; + +import java.io.Serializable; + +public class LoginReset implements IActionBody, Serializable { + private static final long serialVersionUID = -3250235107705010315L; + + private Short pwd; + + @Override + public byte[] writeToBytes() { + byte[] bytes = RadixTools.shortToByte(pwd); + return bytes; + } + + @Override + public void readFromBytes(byte[] messageBodyBytes) { + + } + + public Short getPwd() { + return pwd; + } + + public void setPwd(Short pwd) { + this.pwd = pwd; + } +} diff --git a/app/src/main/java/com/example/agvcontroller/protocol/AGV_03_UP.java b/app/src/main/java/com/example/agvcontroller/protocol/AGV_03_UP.java new file mode 100644 index 0000000..0d5b9d8 --- /dev/null +++ b/app/src/main/java/com/example/agvcontroller/protocol/AGV_03_UP.java @@ -0,0 +1,42 @@ +package com.example.agvcontroller.protocol; + +import com.example.agvcontroller.socket.RadixTools; + +import java.io.Serializable; + +public class AGV_03_UP implements IMessageBody, Serializable { + + private static final long serialVersionUID = -5588066188890649095L; + + @Override + public byte[] writeToBytes() { + return new byte[0]; + } + + @Override + public void readFromBytes(byte[] bytes) { + + this.battery = Utils.sliceWithReverse(bytes, 2, 1)[0]; + + this.error = Utils.sliceWithReverse(bytes, 26, 4)[0]; + + + + + } + + @Override + public String getSerialNo() { + return ""; + } + + private int battery; + + private int error; + public int getBattery() { + return battery; + } + public int getError() { + return error; + } +} diff --git a/app/src/main/java/com/example/agvcontroller/protocol/HandleCmdType.java b/app/src/main/java/com/example/agvcontroller/protocol/HandleCmdType.java index 1acdc25..660254e 100644 --- a/app/src/main/java/com/example/agvcontroller/protocol/HandleCmdType.java +++ b/app/src/main/java/com/example/agvcontroller/protocol/HandleCmdType.java @@ -16,6 +16,7 @@ import com.example.agvcontroller.action.HandOutAction; import com.example.agvcontroller.action.LiftResetAction; import com.example.agvcontroller.action.LoadResetAction; +import com.example.agvcontroller.action.LoginReset; import com.example.agvcontroller.action.RotatopnLeftRight; import com.example.agvcontroller.action.SingleSwitchAction; import com.example.agvcontroller.action.SingleSwitchRunAction; @@ -60,6 +61,8 @@ BACK_PADDLE(0x8A, "鎵嬪姩鎺у埗鍚庢嫧鏉�", BackPaddle.class), + LOGIN_RESET(0x80, "閲嶆柊鐧诲綍", LoginReset.class), + ; diff --git a/app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java b/app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java index 0c05544..bcc5bad 100644 --- a/app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java +++ b/app/src/main/java/com/example/agvcontroller/socket/NettyServerHandler.java @@ -46,6 +46,7 @@ private static final String TAG = "NettyServerHandler"; private static ConcurrentHashMap<String, Channel> channelMap = new ConcurrentHashMap<>(); private Map<String, Runnable> pendingRemovals = new HashMap<>(); + AGVCar agvCar; int battery = 0; int status = 0; int agvStatus = 0; @@ -58,6 +59,8 @@ int forkExtend = 0; int forkAngle = 0; int agvError = 0; + String agvNo = "--"; + String log; private Handler handler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { @@ -75,14 +78,19 @@ String ip = remoteAddress.getAddress().getHostAddress(); int port = remoteAddress.getPort(); channelMap.put(clientId, ctx.channel()); - EventBus.getDefault().post(new AGVCar(clientId,ip,port,"--",0)); - Log.d(TAG, "Client connected: " + clientId); + agvCar = new AGVCar(clientId, ip, port, agvNo, 1, battery,agvStatus,positionID,positionX,positionY,agvAngle,gyroAngle,forkHeight,forkExtend,forkAngle,agvError); - // 鍙栨秷寤惰繜鍒犻櫎鎿嶄綔 - if (pendingRemovals.containsKey(clientId)) { - handler.removeCallbacks(pendingRemovals.get(clientId)); - pendingRemovals.remove(clientId); - } + EventBus.getDefault().post(agvCar); +// Log.d(TAG, "Client connected: " + clientId); + log = formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " 涓婅: " + ip + "[tcp]>>>宸茶繛鎺�"; + Log.d("updown", log); + AGVApplication.addLog(log); + +// // 鍙栨秷寤惰繜鍒犻櫎鎿嶄綔 +// if (pendingRemovals.containsKey(clientId)) { +// handler.removeCallbacks(pendingRemovals.get(clientId)); +// pendingRemovals.remove(clientId); +// } } @@ -92,24 +100,38 @@ InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress(); String ip = remoteAddress.getAddress().getHostAddress(); int port = remoteAddress.getPort(); - channelMap.remove(clientId); +// channelMap.remove(clientId); EventBus.getDefault().post(clientId); - Log.d(TAG, "Client disconnected: " + clientId); +// Log.d(TAG, "Client disconnected: " + clientId); + agvCar = new AGVCar(clientId, ip, port, agvNo, 0, battery,agvStatus,positionID,positionX,positionY,agvAngle,gyroAngle,forkHeight,forkExtend,forkAngle,agvError); - // 鍚姩寤惰繜鍒犻櫎鎿嶄綔 - Runnable removalRunnable = new Runnable() { - @Override - public void run() { - removeItem(clientId); - } - }; - pendingRemovals.put(clientId, removalRunnable); - handler.postDelayed(removalRunnable, 20000); // 20绉掑悗鎵ц鍒犻櫎鎿嶄綔 + EventBus.getDefault().post(agvCar); +// Log.d(TAG, "Client connected: " + clientId); + log = formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " 涓婅: " + ip + "[tcp]>>>鏂紑杩炴帴"; + Log.d("updown", log); + AGVApplication.addLog(log); +// // 鍚姩寤惰繜鍒犻櫎鎿嶄綔 +// Runnable removalRunnable = new Runnable() { +// @Override +// public void run() { +// removeItem(clientId); +// } +// }; +// pendingRemovals.put(clientId, removalRunnable); +// handler.postDelayed(removalRunnable, 20000); // 20绉掑悗鎵ц鍒犻櫎鎿嶄綔 } private void removeItem(String clientId) { +// 鍘熷厛鏄鍒犻櫎鍚庣画涓轰簡鑳藉姩鎬佽嚜鍔ㄨ繛鎺ラ渶瑕佹洿鏂� +// if (channelMap.remove(clientId) != null) { +// Log.d(TAG, "Client removed after 20 seconds: " + clientId); +// EventBus.getDefault().post(clientId); +// } else { +// Log.d(TAG, "Client already reconnected or not found: " + clientId); +// } + if (channelMap.remove(clientId) != null) { Log.d(TAG, "Client removed after 20 seconds: " + clientId); EventBus.getDefault().post(clientId); @@ -150,11 +172,6 @@ // ack ProtocolType ackType = isNeedAck(pac); final String uniqueNo = pac.getHeader().getUniqueNo(); - String agvNo; - AGVCar agvCar; - - String log; - label : switch (pac.getHeader().getProtocolType()){ case ACTION_COMPLETE: // 鍔ㄤ綔瀹屾垚鏁版嵁鍖� AGV_11_UP agv_11_up = (AGV_11_UP) pac.getBody().getMessageBody(); diff --git a/app/src/main/java/com/example/agvcontroller/utils/ToDBC.java b/app/src/main/java/com/example/agvcontroller/utils/ToDBC.java new file mode 100644 index 0000000..63ffed9 --- /dev/null +++ b/app/src/main/java/com/example/agvcontroller/utils/ToDBC.java @@ -0,0 +1,16 @@ +package com.example.agvcontroller.utils; + +public class ToDBC { + public static String toDBC(String input) { + char[] chars = input.toCharArray(); + for (int i=0;i< chars.length; i++){ + if(chars[i]== 12288){ + chars[i]=(char)32; + continue; + } + if(chars[i]> 65280 && chars[i]< 65375) + chars[i]=(char)(chars[i]- 65248); + } + return new String(chars); + } +} diff --git a/app/src/main/res/drawable/new_logo.png b/app/src/main/res/drawable/new_logo.png new file mode 100644 index 0000000..ddec72c --- /dev/null +++ b/app/src/main/res/drawable/new_logo.png Binary files differ diff --git a/app/src/main/res/layout/activity_log.xml b/app/src/main/res/layout/activity_log.xml new file mode 100644 index 0000000..a096a15 --- /dev/null +++ b/app/src/main/res/layout/activity_log.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<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" + tools:context=".LogActivity"> + <ScrollView + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fillViewport="true"> + <TextView + android:id="@+id/log_text_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="12sp" + android:textColor="#FFFFFF" + android:background="#000000" + android:focusable="true" + android:singleLine="false" + android:focusableInTouchMode="true" + android:breakStrategy="high_quality" + android:hyphenationFrequency="normal" + android:scrollbars="vertical" /> + </ScrollView> +</LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index ba8cf23..773f12c 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -14,116 +14,157 @@ android:orientation="vertical" android:padding="10dp" android:layout_weight="4"> - <LinearLayout + <RelativeLayout android:layout_width="match_parent" android:layout_height="0dp" - android:layout_weight="2" - android:orientation="vertical"> - > - <TextView - android:id="@+id/agv_battery" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="" - android:textSize="14sp" - android:text="鐢甸噺锛�100%" - android:textColor="#FFFFFF" /> - <TextView - android:id="@+id/agv_no" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="" - android:textSize="14sp" - android:text="AGV缂栧彿锛�1" - android:textColor="#FFFFFF" /> - <TextView - android:id="@+id/agv_status" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="" - android:textSize="14sp" - android:text="AGV鐘舵�侊細绌洪棽" - android:textColor="#FFFFFF" /> + android:layout_weight="2"> <LinearLayout android:layout_width="match_parent" - android:layout_height="wrap_content" > + android:layout_height="match_parent" + android:orientation="vertical"> + > <TextView - android:layout_width="wrap_content" + android:id="@+id/agv_battery" + android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="" - android:textSize="12sp" - android:layout_marginRight="10dp" - android:text="褰撳墠浣嶇疆" + android:textSize="14sp" + android:text="鐢甸噺锛�100%" android:textColor="#FFFFFF" /> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + > + <TextView + android:id="@+id/agv_no" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="" + android:textSize="14sp" + android:text="AGV缂栧彿锛�1" + android:textColor="#FFFFFF" /> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="" + android:textSize="14sp" + android:text=" " + android:textColor="#FFFFFF" /> + <TextView + android:id="@+id/socket" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="" + android:textSize="14sp" + android:text="--" + android:textColor="#FFFFFF" /> + </LinearLayout> + <TextView - android:id="@+id/agv_position_id" - android:layout_width="wrap_content" + android:id="@+id/agv_status" + android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="" - android:textSize="12sp" - android:layout_marginRight="10dp" - android:text="ID锛�9987" + android:textSize="14sp" + android:text="AGV鐘舵�侊細绌洪棽" android:textColor="#FFFFFF" /> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" > + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="" + android:textSize="12sp" + android:layout_marginRight="10dp" + android:text="褰撳墠浣嶇疆" + android:textColor="#FFFFFF" /> + <TextView + android:id="@+id/agv_position_id" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="" + android:textSize="12sp" + android:layout_marginRight="10dp" + android:text="ID锛�9987" + android:textColor="#FFFFFF" /> + <TextView + android:id="@+id/agv_position_x" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="" + android:textSize="12sp" + android:layout_marginRight="10dp" + android:text="(X)锛�123087" + android:textColor="#FFFFFF" /> + <TextView + android:id="@+id/agv_position_y" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="" + android:textSize="12sp" + android:layout_marginRight="10dp" + android:text="(Y)锛�432311" + android:textColor="#FFFFFF" /> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" > + <TextView + android:id="@+id/agv_position_height" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="" + android:textSize="12sp" + android:layout_marginRight="10dp" + android:text="褰撳墠楂樺害锛�100mm" + android:textColor="#FFFFFF" /> + <TextView + android:id="@+id/agv_ford" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="" + android:textSize="12sp" + android:layout_marginRight="10dp" + android:text="璐у弶浼稿嚭璺濈锛�30mm" + android:textColor="#FFFFFF" /> + <TextView + android:id="@+id/agv_ratio" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="" + android:textSize="12sp" + android:layout_marginRight="10dp" + android:text="璐у弶鏃嬭浆瑙掑害锛�90掳" + android:textColor="#FFFFFF" /> + </LinearLayout> <TextView - android:id="@+id/agv_position_x" + android:id="@+id/agv_error" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="" android:textSize="12sp" android:layout_marginRight="10dp" - android:text="(X)锛�123087" - android:textColor="#FFFFFF" /> - <TextView - android:id="@+id/agv_position_y" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="" - android:textSize="12sp" - android:layout_marginRight="10dp" - android:text="(Y)锛�432311" + android:text="AGV鏁呴殰锛氬鑸晠闅� > 寰呮満鐘舵�佷笅涓㈢爜" android:textColor="#FFFFFF" /> </LinearLayout> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" > - <TextView - android:id="@+id/agv_position_height" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="" - android:textSize="12sp" - android:layout_marginRight="10dp" - android:text="褰撳墠楂樺害锛�100mm" - android:textColor="#FFFFFF" /> - <TextView - android:id="@+id/agv_ford" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="" - android:textSize="12sp" - android:layout_marginRight="10dp" - android:text="璐у弶浼稿嚭璺濈锛�30mm" - android:textColor="#FFFFFF" /> - <TextView - android:id="@+id/agv_ratio" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="" - android:textSize="12sp" - android:layout_marginRight="10dp" - android:text="璐у弶鏃嬭浆瑙掑害锛�90掳" - android:textColor="#FFFFFF" /> - </LinearLayout> - <TextView - android:id="@+id/agv_error" + <com.google.android.material.button.MaterialButton + android:id="@+id/relogin_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="" - android:textSize="12sp" - android:layout_marginRight="10dp" - android:text="AGV鏁呴殰锛氬鑸晠闅� > 寰呮満鐘舵�佷笅涓㈢爜" - android:textColor="#FFFFFF" /> - </LinearLayout> + android:layout_alignParentEnd="true" + android:layout_alignParentTop="true" + android:layout_marginLeft="20sp" + android:layout_centerVertical="true" + android:layout_marginRight="10sp" + android:backgroundTint="#2196F3" + android:minWidth="10dp" + android:paddingLeft="10dp" + android:paddingRight="10dp" + android:text="閲嶆柊鐧诲綍" + app:cornerRadius="5dp" /> + </RelativeLayout> + <RelativeLayout android:layout_width="match_parent" android:layout_height="0dp" @@ -136,6 +177,7 @@ android:id="@+id/recent_log_text_view" android:layout_width="match_parent" android:layout_height="match_parent" + android:scrollbars="vertical" /> <com.google.android.material.button.MaterialButton android:id="@+id/view_all_logs_button" -- Gitblit v1.9.1