From 8af5a913f558f2bc9143cc06989278354c770bd0 Mon Sep 17 00:00:00 2001 From: CYZ <2782394648@qq.com> Date: Wed, 7 Jun 2023 01:39:08 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8E=E4=BC=A0=E6=84=9F=E5=99=A8=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E8=81=94=E9=80=9A=EF=BC=8C=E6=B7=BB=E5=8A=A0=E8=B5=B7?= =?UTF-8?q?=E9=A3=9E=E5=89=8D=E7=A1=AE=E8=AE=A4=E6=8E=A7=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../12963d86ac5c2888cc2a9ae459de5665bc06b01f | 5 + .../.idea/sonarlint/issuestore/index.pb | 4 +- src/sixaunyi/app/src/main/AndroidManifest.xml | 1 - .../com/example/sixaunyi/DetectActivity.java | 3 - .../com/example/sixaunyi/MainActivity.java | 161 ++++++- .../com/example/sixaunyi/VideoActivity.java | 399 +++++++++++++++--- .../main/res/layout-land/activity_control.xml | 5 + .../src/main/res/layout/dialog_takeoff.xml | 21 + .../app/src/main/res/values/attrs.xml | 11 + .../app/src/main/res/values/styles.xml | 16 + 10 files changed, 547 insertions(+), 79 deletions(-) create mode 100644 src/sixaunyi/.idea/sonarlint/issuestore/1/2/12963d86ac5c2888cc2a9ae459de5665bc06b01f create mode 100644 src/sixaunyi/app/src/main/res/layout/dialog_takeoff.xml create mode 100644 src/sixaunyi/app/src/main/res/values/attrs.xml create mode 100644 src/sixaunyi/app/src/main/res/values/styles.xml diff --git a/src/sixaunyi/.idea/sonarlint/issuestore/1/2/12963d86ac5c2888cc2a9ae459de5665bc06b01f b/src/sixaunyi/.idea/sonarlint/issuestore/1/2/12963d86ac5c2888cc2a9ae459de5665bc06b01f new file mode 100644 index 0000000..5d32c84 --- /dev/null +++ b/src/sixaunyi/.idea/sonarlint/issuestore/1/2/12963d86ac5c2888cc2a9ae459de5665bc06b01f @@ -0,0 +1,5 @@ + +> +java:S1604"(Make this anonymous inner class a lambda(ʆ +P +java:S1161":Add the "@Override" annotation above this method signature( \ No newline at end of file diff --git a/src/sixaunyi/.idea/sonarlint/issuestore/index.pb b/src/sixaunyi/.idea/sonarlint/issuestore/index.pb index 9d9b31f..15a33ca 100644 --- a/src/sixaunyi/.idea/sonarlint/issuestore/index.pb +++ b/src/sixaunyi/.idea/sonarlint/issuestore/index.pb @@ -16,4 +16,6 @@ i @ app/build.gradle,f\4\f4a01d6a4fcb971362ec00a83903fd3902f52164 k -;app/src/main/java/com/example/sixaunyi/ControlActivity.java,c\9\c99a584c2117ed2df42496451bb97ac1147f5ea0 \ No newline at end of file +;app/src/main/java/com/example/sixaunyi/ControlActivity.java,c\9\c99a584c2117ed2df42496451bb97ac1147f5ea0 +j +:app/src/main/java/com/example/sixaunyi/SecondFragment.java,1\2\12963d86ac5c2888cc2a9ae459de5665bc06b01f \ No newline at end of file diff --git a/src/sixaunyi/app/src/main/AndroidManifest.xml b/src/sixaunyi/app/src/main/AndroidManifest.xml index fcc33b4..2b1df5b 100644 --- a/src/sixaunyi/app/src/main/AndroidManifest.xml +++ b/src/sixaunyi/app/src/main/AndroidManifest.xml @@ -55,5 +55,4 @@ - \ No newline at end of file diff --git a/src/sixaunyi/app/src/main/java/com/example/sixaunyi/DetectActivity.java b/src/sixaunyi/app/src/main/java/com/example/sixaunyi/DetectActivity.java index 9f61cd3..1b676f5 100644 --- a/src/sixaunyi/app/src/main/java/com/example/sixaunyi/DetectActivity.java +++ b/src/sixaunyi/app/src/main/java/com/example/sixaunyi/DetectActivity.java @@ -208,14 +208,11 @@ public class DetectActivity extends AppCompatActivity { e.printStackTrace(); } } - } - public void send(String msg) { System.out.println("msg的值为: " + msg); list.add(msg); } - } } \ No newline at end of file diff --git a/src/sixaunyi/app/src/main/java/com/example/sixaunyi/MainActivity.java b/src/sixaunyi/app/src/main/java/com/example/sixaunyi/MainActivity.java index cd02c0e..7d9ec3e 100644 --- a/src/sixaunyi/app/src/main/java/com/example/sixaunyi/MainActivity.java +++ b/src/sixaunyi/app/src/main/java/com/example/sixaunyi/MainActivity.java @@ -2,6 +2,8 @@ package com.example.sixaunyi; import static androidx.constraintlayout.motion.utils.Oscillator.TAG; +import static java.lang.Math.PI; + import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; @@ -9,9 +11,12 @@ import android.Manifest; import android.annotation.SuppressLint; import android.content.Intent; import android.graphics.BitmapFactory; +import android.location.Location; import android.nfc.Tag; import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; import android.util.Log; import android.view.View; import android.widget.TextView; @@ -41,6 +46,12 @@ import com.amap.api.services.poisearch.PoiResult; import com.amap.api.services.poisearch.PoiSearch; import com.google.android.material.floatingactionbutton.FloatingActionButton; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; import java.util.ArrayList; import java.util.List; @@ -84,10 +95,17 @@ public class MainActivity extends AppCompatActivity implements AMapLocationListe private List markerList = new ArrayList<>(); //标识参数类 private MarkerOptions markerOption = new MarkerOptions(); - - - - + // + private DatagramSocket reveSocket; + private final static String Recieve_IP = "192.168.240.46"; + private final static int RECEIVE_PORT = 9999; + private boolean listenStatus = true; + private InetAddress serverAddr; + //private MainActivity.ReceiveHandler receiveHandler = new ReceiveHandler(); + private String Angle; + private String MonitorAngle; + private float distance; + private float MonitorDistance; @SuppressLint("MissingInflatedId") @Override @@ -107,6 +125,10 @@ public class MainActivity extends AppCompatActivity implements AMapLocationListe initMap(savedInstanceState); //检查安卓版本 checkingAndroidVersion(); + + UdpReceiveThread udpReceiveThread = new UdpReceiveThread(); + udpReceiveThread.startListening(); + } /** * 检查Android版本 @@ -320,10 +342,16 @@ public class MainActivity extends AppCompatActivity implements AMapLocationListe //LatLng 为高德地图包自带的存储坐标对象 @Override public void onMapLongClick(LatLng latLng) { - float distance = AMapUtils.calculateLineDistance(Current_latlng,latLng); + distance = AMapUtils.calculateLineDistance(Current_latlng,latLng); + LatLng Monitorlatlng = new LatLng(113.05370390725032,28.256794281117525); + MonitorDistance = AMapUtils.calculateLineDistance(Current_latlng,Monitorlatlng); + Angle = calcAngle(Current_latlng.latitude, Current_latlng.longitude, latLng.latitude,latLng.longitude); + MonitorAngle = calcAngle(Current_latlng.latitude, Current_latlng.longitude, 113.05370390725032,28.256794281117525); //showMsg("长按了地图,经度:"+latLng.longitude+",纬度:"+latLng.latitude); - showMsg("直线距离:"+distance+"米"); - //坐标转地址 + Log.i(TAG,String.valueOf(latLng.longitude)); + Log.i(TAG,String.valueOf(latLng.latitude)); + showMsg("直线距离:"+distance+"米"+"角度"+Angle); + //坐标转地址113.05370390725032 28.256794281117525 latlonToAddress(latLng); //添加标点 addMarker(latLng); @@ -453,20 +481,113 @@ public class MainActivity extends AppCompatActivity implements AMapLocationListe public void onGeocodeSearched(GeocodeResult geocodeResult, int i) { } -/* - @Override - public void onPoiSearched(PoiResult poiResult, int i) { - //解析result获取POI信息 - //获取POI组数列表 - ArrayList poiItems = poiResult.getPois(); - for (PoiItem poiItem : poiItems) { - Log.d("MainActivity", " Title:" + poiItem.getTitle() + " Snippet:" + poiItem.getSnippet()); + public class UdpReceiveThread extends Thread { + private static final String TAG = "UdpReceiveThread"; + private static final int RECEIVE_PORT = 9999; + private boolean mRunning; + private String mReceiveIp = Recieve_IP; + private String mExpectedData = "Motion detected!"; + private float mMonitorDistance = MonitorDistance; + private String mMonitorAngle = MonitorAngle; + + @Override + public void run() { + try { + DatagramSocket socket = new DatagramSocket(RECEIVE_PORT); + byte[] buffer = new byte[1024]; + DatagramPacket packet = new DatagramPacket(buffer, buffer.length); + while (mRunning) { + socket.receive(packet); + byte[] data = packet.getData(); + String receivedString = new String(data, 0, packet.getLength()); + Log.d(TAG, "Received data: " + receivedString); + if (receivedString.equals(mExpectedData)) { + Intent intent = new Intent(MainActivity.this, VideoActivity.class); + Bundle b = new Bundle(); + b.putString("Angle", mMonitorAngle); + b.putFloat("Distance", mMonitorDistance); + intent.putExtras(b); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + startActivity(intent); + mRunning = false; + } + } + socket.close(); + + } catch (SocketException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } } - }*/ - /* - @Override - public void (PoiItem poiItem, int i) { - }*/ + public void startListening() { + mRunning = true; + start(); + } + + public void stopListening() { + mRunning = false; + } + } + + //以北为0度 + public static String calcAngle(Double centerLat, Double centerLon, Double anotherLat, Double anotherLon) { + //差值 + double subLat = anotherLat - centerLat; + double subLon = anotherLon - centerLon; + double angle = 0; + + if (subLat == 0) { + //纬度差值为0 表示两点在同一高度 此时点必然在x轴右侧 或者 x轴左侧 + if (subLon > 0) { + //x轴右侧 + angle = 90; + } else if (subLon < 0) { + //x轴左侧 + angle = 270; + } + } else if (subLon == 0) { + //经度差值为0 说明点在y轴上方或者y轴下方 + if (subLat > 0) { + //y轴上方 + angle = 0; + } else if (subLat < 0) { + //y轴下方 + angle = 180; + } + } else { + //根据tan的值,求角度 subLon不能为0 纬度差值 除以 经度差值 = tan的值 + double v = subLat / subLon; + angle = Math.atan(v) * 180 / PI; + //angle的值在-180到180之间 + System.out.println("未处理的角度值:" + (angle)); + //第二种求角度的方法 + //angle = Math.atan2(subLat,subLon) * 180 / PI ; + //判断数据在第几象限 + //1、正切小于0 在二四象限 + if (angle < 0) { + if (subLon > 0) { + //此时的点在中心点的右下角 + angle = Math.abs(angle)+ 90; + } else if (subLon < 0) { + //此时的点在中心点的左上角 + angle = Math.abs(angle) + 270; + } + } + //2、正切大于0 在一三象限 + else if (angle > 0) { + if (subLon > 0) { + //此时的点在中心点的右上角 360-angle + angle = 90-angle; + } else if (subLat < 0) { + // 此时的点在中心点的左下角 + angle += 180; + } + } + } + return String.valueOf(angle); + } + } \ No newline at end of file diff --git a/src/sixaunyi/app/src/main/java/com/example/sixaunyi/VideoActivity.java b/src/sixaunyi/app/src/main/java/com/example/sixaunyi/VideoActivity.java index bd41882..eeb5145 100644 --- a/src/sixaunyi/app/src/main/java/com/example/sixaunyi/VideoActivity.java +++ b/src/sixaunyi/app/src/main/java/com/example/sixaunyi/VideoActivity.java @@ -4,14 +4,27 @@ import static androidx.constraintlayout.motion.utils.Oscillator.TAG; import androidx.appcompat.app.AppCompatActivity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; +import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.util.AttributeSet; import android.util.Log; +import android.view.MotionEvent; import android.view.View; +import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; @@ -29,23 +42,20 @@ import java.net.*; import android.os.Bundle; public class VideoActivity extends AppCompatActivity { - - - private final static String SEND_to_IP = "192.168.43.165"; //填写接收方IP - private final static String Recieve_IP = "192.168.43.165";//填服务器IP + private final static String SEND_to_IP = "192.168.39.47"; //填写接收方IP + private final static String Recieve_IP = "192.168.39.47";//填服务器IP,与send_to_IP为同一个 private final static int SEND_PORT = 8888; //发送端口号 private final static int RECEIVE_PORT = 9999; //接收端口号 - private boolean listenStatus = true; //接收线程的循环标识 + private static boolean listenStatus = true; //接收线程的循环标识 private byte[] buf; - Bitmap bp; - + static Bitmap bp; private DatagramSocket receiveSocket; private DatagramSocket sendSocket; - private DatagramSocket reveSocket; - private InetAddress serverAddr; + private static DatagramSocket reveSocket; + private static InetAddress serverAddr; private SendHandler sendHandler = new SendHandler(); - private ReceiveHandler receiveHandler = new ReceiveHandler(); + private static ReceiveHandler receiveHandler; private Button Trans_to_Detect; private ImageView imgShow; private Button btn; @@ -57,8 +67,11 @@ public class VideoActivity extends AppCompatActivity { private ImageButton Up_btn; private ImageButton TurnLeft_btn; private ImageButton TurnRight_btn; + private ImageButton Setting_btn; private ImageButton TakeOff_btn; private Button Landing_btn; + private String angle; + private float distance; @Override protected void onCreate(Bundle savedInstanceState) { @@ -74,28 +87,109 @@ public class VideoActivity extends AppCompatActivity { TurnLeft_btn = findViewById(R.id.rotate_left_button); TurnRight_btn = findViewById(R.id.rotate_right_button); TakeOff_btn = findViewById(R.id.takeoff_button); - //Trans_to_Detect = findViewById(R.id.transfer_to_detect); - TakeOff_btn.setOnClickListener(new View.OnClickListener() { + Setting_btn = findViewById(R.id.setting_button); + Button_Init(); + Intent i = getIntent(); + distance = i.getFloatExtra("Distance",0); + angle = i.getStringExtra("Angle"); + } + private void Button_Init(){ + Forward_btn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + InitUdpSend("FORWARD"); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + Log.i(TAG, "onClick: FFFFFFFForward"); + } + }); + Back_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - UdpSendThread udpSendThread = new UdpSendThread(); - udpSendThread.start(); - udpSendThread.Send("TakeOff"); - UdpReceiveThread udpReceiveThread = new UdpReceiveThread(); - udpReceiveThread.start(); - Log.i(TAG, "onClick: 2222222222222222222222222"); + try { + InitUdpSend("BACKWORD"); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + Log.i(TAG, "onClick: BBBBBBBBackward"); + } + }); + Left_btn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + InitUdpSend("LEFT"); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + Log.i(TAG, "onClick: LLLLLLLLLLLLeft"); + } + }); + Right_btn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + InitUdpSend("RIGHT"); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + Log.i(TAG, "onClick: RRRRRRRRRRight"); + } + }); + Down_btn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + InitUdpSend("DOWN"); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + Log.i(TAG, "onClick: DDDDDDDDDown"); + } + }); + Up_btn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + InitUdpSend("UP"); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + Log.i(TAG, "onClick: UUUUUUUUUUUUUUp"); } }); - /*Trans_to_Detect.setOnClickListener(new View.OnClickListener() { + TurnLeft_btn.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View view) { - Intent intent = new Intent(VideoActivity.this, DetectActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - startActivity(intent); + public void onClick(View v) { + try { + InitUdpSend("TURN_LEFT"); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + Log.i(TAG, "onClick: TTTTTTTTTurnLLLLLLLLLLeft"); } - });*/ + }); + TurnRight_btn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + InitUdpSend("TURN_RIGHT"); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + Log.i(TAG, "onClick: TTTTTTTTTTTTurnRRRRRRRRRRight"); + } + }); + Setting_btn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //Intent intent = new Intent(VideoActivity.this, SpeedActivity.class); + //startActivity(intent); + } + }); } - class ReceiveHandler extends Handler{ @Override public void handleMessage(Message msg) { @@ -114,7 +208,7 @@ public class VideoActivity extends AppCompatActivity { /* * UDP数据接受线程 * */ - public class UdpReceiveThread extends Thread + public static class UdpReceiveThread extends Thread { @Override public void run() @@ -149,43 +243,240 @@ public class VideoActivity extends AppCompatActivity { /* * UDP数据发送线程 * */ - public class UdpSendThread extends Thread { + public static class UdpSendThread extends Thread { + + private InetAddress sendToIP; // 目标 IP 地址 + private int sendPort; // 目标端口号 + private byte[] sendData; // 要发送的数据 + + public UdpSendThread(InetAddress sendToIP, int sendPort, byte[] sendData) { + this.sendToIP = sendToIP; + this.sendPort = sendPort; + this.sendData = sendData; + } + @Override public void run() { try { - buf ="test".getBytes(); - // 创建DatagramSocket对象,使用端口8888 - sendSocket = new DatagramSocket(8888); + DatagramSocket sendSocket = new DatagramSocket(); // 创建一个新的 DatagramSocket 对象 + DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, sendToIP, sendPort); // 将要发送的数据打包成一个 DatagramPacket 对象 + sendSocket.send(sendPacket); // 发送 DatagramPacket + sendSocket.close(); // 发送完毕后关闭 DatagramSocket + } catch (Exception e) { + e.printStackTrace(); + } + } + } + //初始化UDP发送线程 + private static void InitUdpSend(String Sendstr) throws UnknownHostException { + InetAddress sendIP = InetAddress.getByName(SEND_to_IP); // 目标 IP 地址 + int sendPort = 8888; // 目标端口号 + byte[] sendData = Sendstr.getBytes(); // 要发送的数据 + UdpSendThread sendThread = new UdpSendThread(sendIP, sendPort, sendData); // 创建新的线程对象 + sendThread.start(); // 启动线程发送数据 + } +//设置按钮 + public void showDialog(View view) { + Dialog dialog = new Dialog(VideoActivity.this); + dialog.setContentView(R.layout.dialog_takeoff); - serverAddr = InetAddress.getByName(SEND_to_IP); + SlideUnlockView slideUnlockView = (SlideUnlockView) dialog.findViewById(R.id.slide_unlock_view); + slideUnlockView.setOnUnlockListener(new SlideUnlockView.OnUnlockListener() { + @Override + public void onUnlock() { + // 在用户滑动解锁后执行操作 + try { + InitUdpSend("TAKEOFF"+"___"+angle+"___"+String.valueOf(distance)); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + UdpReceiveThread udpReceiveThread = new UdpReceiveThread(); + udpReceiveThread.start(); + Log.i(TAG, "onClick: 2222222222222222222222222"); - DatagramPacket outPacket = new DatagramPacket(buf, buf.length, serverAddr, SEND_PORT); - sendSocket.send(outPacket); + } + }); + dialog.show(); + } +//////////////////////////////滑动开关////////////////////////////// + public static class SlideUnlockView extends View{ - sendSocket.close(); - sendHandler.sendEmptyMessage(1); - Log.i(TAG, "run: 111111111111111111111111111111111111111111111111"); - } catch (Exception e) { - e.printStackTrace(); + private final int BG_COLOR = Color.parseColor("#2D2E32"); // 背景颜色 + private static final int GUIDE_TEXT_COLOR = Color.WHITE; // 引导文本颜色 + private static final int GUIDE_TEXT_SIZE = 100; // 引导文本大小 + private static final int INDICATOR_COLOR = Color.WHITE; // 指示器颜色 + private static final int INDICATOR_RADIUS = 40; // 指示器半径 + private static final int INDICATOR_GAP = 300; // 指示器间距 + private static final int ARROW_COLOR = Color.WHITE; // 箭头颜色 + private static final int ARROW_SIZE = 20; // 箭头大小 + + private static final int STATE_LOCKED = 0; // 锁屏状态 + private static final int STATE_DRAGGING = 1; // 拖动状态 + private static final int STATE_UNLOCKED = 2; // 解锁状态 + + private Paint mPaint; + private Path mPath; + private int mViewWidth; + private int mViewHeight; + private int mIndicatorCount; + private int mCurrentIndex; + private float mLastX; + private boolean mIsUnlocked; + private int mState; + + private OnUnlockListener mOnUnlockListener; + + public abstract static class OnUnlockListener { + public class SimpleOnUnlockListener extends OnUnlockListener { + @Override + public void onUnlock() { + // 默认空实现 + } } + public abstract void onUnlock(); } - public void Send(String str){ - try { - buf =str.getBytes(); - // 创建DatagramSocket对象,使用端口8888 - sendSocket = new DatagramSocket(8888); - serverAddr = InetAddress.getByName(SEND_to_IP); - DatagramPacket outPacket = new DatagramPacket(buf, buf.length, serverAddr, SEND_PORT); - sendSocket.send(outPacket); - - sendSocket.close(); - sendHandler.sendEmptyMessage(1); - Log.i(TAG, "run: 111111111111111111111111111111111111111111111111"); - } catch (Exception e) { - e.printStackTrace(); + + public void setOnUnlockListener(OnUnlockListener listener) { + this.mOnUnlockListener = listener; + } + + public SlideUnlockView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + mPaint = new Paint(); + mPaint.setAntiAlias(true); // 抗锯齿 + mPaint.setStyle(Paint.Style.FILL); + + mPath = new Path(); + + mIsUnlocked = false; + mState = STATE_LOCKED; + + // 指示器个数为 3 + mIndicatorCount = 3; + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + mViewWidth = w; + mViewHeight = h; + } + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + switch (mState) { + case STATE_LOCKED: + drawGuideText(canvas); + drawIndicatorCircles(canvas); + break; + case STATE_DRAGGING: + drawUnlockPath(canvas); + drawUnlockArrow(canvas); + break; + case STATE_UNLOCKED: + if (mOnUnlockListener != null) { + mOnUnlockListener.onUnlock(); + } + break; } } - } -} + private void drawGuideText(Canvas canvas) { + mPaint.setColor(BG_COLOR); + canvas.drawRect(0, 0, mViewWidth, mViewHeight, mPaint); + + mPaint.setColor(GUIDE_TEXT_COLOR); + mPaint.setTextSize(GUIDE_TEXT_SIZE); + String guideText = "即将起飞"; + float textWidth = mPaint.measureText(guideText); + float textX = mViewWidth / 2 - textWidth / 2; + float textY = mViewHeight * 2 / 3; + canvas.drawText(guideText, textX, textY, mPaint); + } + private void drawIndicatorCircles(Canvas canvas) { + mPaint.setColor(INDICATOR_COLOR); + float cy = mViewHeight / 2; + float startX = mViewWidth / 2 - INDICATOR_GAP * (mIndicatorCount - 1) / 2; + float radius = INDICATOR_RADIUS; + Path path = new Path(); + for (int i = 0; i < mIndicatorCount; i++) { + float cx = startX + INDICATOR_GAP * i; + path.addCircle(cx, cy, radius, Path.Direction.CCW); + } + canvas.drawPath(path, mPaint); + } + + private void drawUnlockPath(Canvas canvas) { + mPaint.setColor(INDICATOR_COLOR); + float cy = mViewHeight / 2; + float startX = mViewWidth / 2 - INDICATOR_GAP * (mIndicatorCount - 1) / 2; + float currentX = Math.max(Math.min(mLastX, mViewWidth - INDICATOR_RADIUS), startX + INDICATOR_GAP * mCurrentIndex); + Path path = new Path(); + path.moveTo(startX + INDICATOR_RADIUS, cy); + path.lineTo(currentX - INDICATOR_RADIUS, cy); + path.arcTo(new RectF(currentX - INDICATOR_RADIUS, cy - INDICATOR_RADIUS, + currentX + INDICATOR_RADIUS, cy + INDICATOR_RADIUS), -90, 180); + path.lineTo(startX + INDICATOR_GAP * (mIndicatorCount - 1), cy); + canvas.drawPath(path, mPaint); + } + + private void drawUnlockArrow(Canvas canvas) { + mPaint.setColor(ARROW_COLOR); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setStrokeWidth(5); + Path arrowPath = new Path(); + float x = Math.max(Math.min(mLastX, mViewWidth - INDICATOR_RADIUS - ARROW_SIZE), mViewWidth / 2 + INDICATOR_GAP * (mCurrentIndex - 1)); + float y = mViewHeight / 2; + arrowPath.moveTo(x - ARROW_SIZE, y - ARROW_SIZE); + arrowPath.lineTo(x, y); + arrowPath.lineTo(x - ARROW_SIZE, y + ARROW_SIZE); + canvas.drawPath(arrowPath, mPaint); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + float x = event.getX(); + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + if (mState == STATE_LOCKED) { + mState = STATE_DRAGGING; + mCurrentIndex = 0; + invalidate(); + return true; + } + break; + case MotionEvent.ACTION_MOVE: + if (mState == STATE_DRAGGING) { + mLastX = x; + int index = (int) ((x - mViewWidth / 2) / INDICATOR_GAP); + index = Math.max(Math.min(index, mIndicatorCount - 1), 0); + if (index != mCurrentIndex) { + mCurrentIndex = index; + invalidate(); + } + if (mCurrentIndex == mIndicatorCount - 1) { + mState = STATE_UNLOCKED; + mIsUnlocked = true; + } + return true; + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + if (mState == STATE_DRAGGING) { + mState = STATE_LOCKED; + mCurrentIndex = 0; + invalidate(); + return true; + } + break; + } + return super.onTouchEvent(event); + } + } +} \ No newline at end of file diff --git a/src/sixaunyi/app/src/main/res/layout-land/activity_control.xml b/src/sixaunyi/app/src/main/res/layout-land/activity_control.xml index 1fff7c2..2404caa 100644 --- a/src/sixaunyi/app/src/main/res/layout-land/activity_control.xml +++ b/src/sixaunyi/app/src/main/res/layout-land/activity_control.xml @@ -2,6 +2,8 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + @@ -229,3 +232,5 @@ + + diff --git a/src/sixaunyi/app/src/main/res/layout/dialog_takeoff.xml b/src/sixaunyi/app/src/main/res/layout/dialog_takeoff.xml new file mode 100644 index 0000000..f0075de --- /dev/null +++ b/src/sixaunyi/app/src/main/res/layout/dialog_takeoff.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/src/sixaunyi/app/src/main/res/values/attrs.xml b/src/sixaunyi/app/src/main/res/values/attrs.xml new file mode 100644 index 0000000..ef817d5 --- /dev/null +++ b/src/sixaunyi/app/src/main/res/values/attrs.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/sixaunyi/app/src/main/res/values/styles.xml b/src/sixaunyi/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..83c6f8d --- /dev/null +++ b/src/sixaunyi/app/src/main/res/values/styles.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file