diff --git a/robot_android_App/APP/UPBot/app/build.gradle b/robot_android_App/APP/UPBot/app/build.gradle index b3422f6..c85c58c 100644 --- a/robot_android_App/APP/UPBot/app/build.gradle +++ b/robot_android_App/APP/UPBot/app/build.gradle @@ -3,12 +3,13 @@ plugins { } android { - compileSdk 31 + namespace 'com.example.upbot' + compileSdk 33 defaultConfig { - applicationId "com.example.wifidemo" - minSdk 26 - targetSdk 31 + applicationId "com.example.upbot" + minSdk 24 + targetSdk 33 versionCode 1 versionName "1.0" @@ -26,13 +27,20 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } } - +repositories { + flatDir { + dirs 'libs' + } +} dependencies { - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'com.google.android.material:material:1.3.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - testImplementation 'junit:junit:4.+' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.8.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + implementation(name: 'AMap3DMap_10.0.700_AMapSearch_9.7.2_AMapLocation_6.4.5_20240508', ext: 'aar') + //Google推荐的EasyPermission库 + implementation 'pub.devrel:easypermissions:3.0.0' } \ No newline at end of file diff --git a/robot_android_App/APP/UPBot/app/libs/AMap3DMap_10.0.700_AMapSearch_9.7.2_AMapLocation_6.4.5_20240508.aar b/robot_android_App/APP/UPBot/app/libs/AMap3DMap_10.0.700_AMapSearch_9.7.2_AMapLocation_6.4.5_20240508.aar new file mode 100644 index 0000000..09a8db7 Binary files /dev/null and b/robot_android_App/APP/UPBot/app/libs/AMap3DMap_10.0.700_AMapSearch_9.7.2_AMapLocation_6.4.5_20240508.aar differ diff --git a/robot_android_App/APP/UPBot/app/release/app-release.apk b/robot_android_App/APP/UPBot/app/release/app-release.apk index dfcf09c..a4ae16b 100644 Binary files a/robot_android_App/APP/UPBot/app/release/app-release.apk and b/robot_android_App/APP/UPBot/app/release/app-release.apk differ diff --git a/robot_android_App/APP/UPBot/app/release/output-metadata.json b/robot_android_App/APP/UPBot/app/release/output-metadata.json index a1abaa9..73c118e 100644 --- a/robot_android_App/APP/UPBot/app/release/output-metadata.json +++ b/robot_android_App/APP/UPBot/app/release/output-metadata.json @@ -4,7 +4,7 @@ "type": "APK", "kind": "Directory" }, - "applicationId": "com.example.wifidemo", + "applicationId": "com.example.upbot", "variantName": "release", "elements": [ { diff --git a/robot_android_App/APP/UPBot/app/src/androidTest/java/com/example/upbot/ExampleInstrumentedTest.java b/robot_android_App/APP/UPBot/app/src/androidTest/java/com/example/upbot/ExampleInstrumentedTest.java new file mode 100644 index 0000000..b16b59a --- /dev/null +++ b/robot_android_App/APP/UPBot/app/src/androidTest/java/com/example/upbot/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.example.upbot; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("com.example.upbot", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/robot_android_App/APP/UPBot/app/src/main/AndroidManifest.xml b/robot_android_App/APP/UPBot/app/src/main/AndroidManifest.xml index 28715bd..80c4736 100644 --- a/robot_android_App/APP/UPBot/app/src/main/AndroidManifest.xml +++ b/robot_android_App/APP/UPBot/app/src/main/AndroidManifest.xml @@ -1,39 +1,55 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/ClientActivity.java b/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/ClientActivity.java new file mode 100644 index 0000000..1262821 --- /dev/null +++ b/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/ClientActivity.java @@ -0,0 +1,171 @@ +package com.example.upbot; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.Socket; + +public class ClientActivity extends AppCompatActivity { + + private EditText ipET; + private EditText msgET; + private Button confirmBtn; + private Button sendBtn; + private ActionBar actionBar; + private Socket mSocket; +// private OutputStream mOutStream; +// private InputStream mInStream; + private SocketConnectThread socketConnectThread; + private StringBuffer stringBuffer = new StringBuffer(); + private TextView msgTV; + + private final String TAG="WifiDemoLogClientActivity"; + + @SuppressLint("HandlerLeak") + public Handler handler = new Handler(Looper.myLooper()){ + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == 1){ + stringBuffer.append(msg.obj); + stringBuffer.append("\n"); + msgTV.setText(stringBuffer.toString()); + } + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_client); + actionBar = getSupportActionBar(); + assert actionBar != null; + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setTitle("机器人控制"); + + socketConnectThread = new SocketConnectThread(); + initView(); + setListener(); + } + + private void initView() { + ipET = (EditText) findViewById(R.id.ipET); + msgET = (EditText) findViewById(R.id.msgET); + sendBtn = findViewById(R.id.btn_send); + confirmBtn = findViewById(R.id.btn_confirm); + msgTV = (TextView) findViewById(R.id.msgTV); + } + + private void setListener() { + sendBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(mSocket==null) { + Toast.makeText(ClientActivity.this, "未进行连接", Toast.LENGTH_SHORT).show(); + return; + } + sendMessage(msgET.getText().toString()); + } + }); + confirmBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + socketConnectThread.start(); + confirmBtn.setEnabled(false);//连接只点一次 + } + }); + } + + /** + * 连接线程 + */ + class SocketConnectThread extends Thread{ + public void run(){ + try { + //指定ip地址和端口号 + mSocket = new Socket(ipET.getText().toString(), 1989); + //获取输出流、输入流 +// mOutStream = mSocket.getOutputStream(); +// mInStream = mSocket.getInputStream(); + } catch (Exception e) { + e.printStackTrace(); + return; + } + startReader(mSocket); + } + + } + + /** + * 发送消息 + * @param msg + */ + public void sendMessage(final String msg) { + if (msg.length() == 0){ + return; + } + new Thread() { + @Override + public void run() { + try { + DataOutputStream writer = new DataOutputStream(mSocket.getOutputStream()); + writer.writeUTF(msg); // 写一个UTF-8的信息 + } catch (IOException e) { + e.printStackTrace(); + } + } + }.start(); + } + + /** + * 接收消息 + */ + private void startReader(final Socket socket) { + new Thread(){ + @Override + public void run() { + DataInputStream reader; + try { + // 获取读取流 + reader = new DataInputStream(socket.getInputStream()); + while (true) { + // 读取数据 + String msg = reader.readUTF(); + Message message = new Message(); + message.what = 1; + message.obj=msg; + handler.sendMessage(message); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + }.start(); + } + + @Override + protected void onDestroy() { + if(mSocket!=null){ + try { + mSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + super.onDestroy(); + } +} \ No newline at end of file diff --git a/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/ESP8266ClientActivity.java b/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/ESP8266ClientActivity.java new file mode 100644 index 0000000..51e1aba --- /dev/null +++ b/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/ESP8266ClientActivity.java @@ -0,0 +1,141 @@ +package com.example.upbot; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +public class ESP8266ClientActivity extends AppCompatActivity { + + private String mIp;//硬件的IP + private int mPort = 5000;//硬件的端口 + private EditText et_ip;//输入硬件对应的IP + private EditText et_msg;//输入要发送的消息 + private Button btn_confirm;//进行连接 + private Button btn_send;//发送消息 +// Socket mSocket = null;//连接成功可得到的Socket +// OutputStream outputStream = null;//定义输出流 +// InputStream inputStream = null;//定义输入流 + private StringBuffer sb = new StringBuffer();//消息 + private TextView tv_msg;//显示消息 + private boolean connectFlage = true;//连接成功或连接3s后变false + private TextView connetStatusTextView;//显示连接状态 + private int ShowPointSum = 0;//连接时显示 连接中.. 后面点的计数 + + private final String TAG = "WifiDemoLogESP8266ClientActivity"; + private LocalBroadcastManager localBroadcastManager;//本地广播管理器 + private MyLocalBroadcastReceiver localBroadcastReceiver;//广播接收者 + private int connectingCount=0;//用来刷新 正在连接 与 正 在 连 接 + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_esp8266_client); + initView();//初始化控件 + setListener();//设置Button的点击事件 + registerBroadcastReceiver();//广播注册 + } + + /** + * 初始化控件 + */ + private void initView() { + et_ip = (EditText) findViewById(R.id.et_ipESP8266); + et_msg = (EditText) findViewById(R.id.et_msgESP8266); + btn_send = findViewById(R.id.btn_sendESP8266); + btn_confirm = findViewById(R.id.btn_confirmESP8266); + tv_msg = (TextView) findViewById(R.id.tv_msgESP8266); + connetStatusTextView = findViewById(R.id.connetStatusTV); + } + + /** + * 设置Button的点击事件 + */ + private void setListener() { + btn_confirm.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + btn_confirm.setEnabled(false);//防止正在连接时再次点击连接 + WiFiModeUtil.connectFlage=true; + mIp = et_ip.getText().toString();//得到IP + WiFiModeUtil.connetByTCP(mIp,mPort);//进行连接 + } + }); + btn_send.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (WiFiModeUtil.mSocket == null) { + Toast.makeText(ESP8266ClientActivity.this, "未连接任何设备~~", Toast.LENGTH_SHORT).show(); + return; + } + WiFiModeUtil.sendData(et_msg.getText().toString());//发送数据 + } + }); + } + + + @Override + protected void onDestroy() { + localBroadcastManager.unregisterReceiver(localBroadcastReceiver);//注销广播 + WiFiModeUtil.closeSocketAndStream();//关闭Socket释放资源 + super.onDestroy(); + } + + /** + * 广播注册 + */ + private void registerBroadcastReceiver() { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction("WiFiModeUtil.Connecting");//正在连接 + intentFilter.addAction("WiFiModeUtil.Connect.Succeed");//连接成功 + intentFilter.addAction("WiFiModeUtil.Connect.Fail");//连接失败 + intentFilter.addAction("WiFiModeUtil.Connect.ReceiveMessage");//接收到数据 + intentFilter.addAction("WiFiModeUtil.Disconnected");//接收到数据 + localBroadcastReceiver = new MyLocalBroadcastReceiver(); + localBroadcastManager = LocalBroadcastManager.getInstance(this); + WiFiModeUtil.localBroadcastManager=localBroadcastManager;//给WiFiModeUtil工具类中的本地广播管理器赋值 + localBroadcastManager.registerReceiver(localBroadcastReceiver,intentFilter); + } + + /** + * 本地广播接收者 + */ + class MyLocalBroadcastReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + switch (intent.getAction()) { + case "WiFiModeUtil.Connecting": + connectingCount++; + if(connectingCount%2==0) + connetStatusTextView.setText("正在连接"); + else + connetStatusTextView.setText("正 在 连 接"); + break; + case "WiFiModeUtil.Connect.Succeed": + connetStatusTextView.setText("连接成功"); + btn_confirm.setEnabled(true); + break; + case "WiFiModeUtil.Connect.Fail": + connetStatusTextView.setText("连接失败"); + btn_confirm.setEnabled(true); + break; + case "WiFiModeUtil.Connect.ReceiveMessage": + tv_msg.setText(WiFiModeUtil.DataRecivice.toString()); + break; + case "WiFiModeUtil.Disconnected": + tv_msg.setText("连接已断开,请重新进行连接"); + break; + } + } + } +} \ No newline at end of file diff --git a/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/MainActivity.java b/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/MainActivity.java new file mode 100644 index 0000000..d4973e2 --- /dev/null +++ b/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/MainActivity.java @@ -0,0 +1,307 @@ +package com.example.upbot; + +import android.content.Intent; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; + +import com.amap.api.location.AMapLocation; +import com.amap.api.location.AMapLocationClient; +import com.amap.api.location.AMapLocationClientOption; +import com.amap.api.location.AMapLocationListener; +import com.amap.api.maps.AMap; +import com.amap.api.maps.LocationSource; +import com.amap.api.maps.MapView; +import com.amap.api.maps.model.BitmapDescriptorFactory; +import com.amap.api.maps.model.MyLocationStyle; + +import pub.devrel.easypermissions.AfterPermissionGranted; +import pub.devrel.easypermissions.EasyPermissions; + +public class MainActivity extends AppCompatActivity implements AMapLocationListener, LocationSource{ + private MyLocationStyle myLocationStyle = new MyLocationStyle(); + + //声明AMapLocationClient类对象 + public AMapLocationClient mLocationClient = null; + //声明AMapLocationClientOption对象 + public AMapLocationClientOption mLocationOption = null; + //请求权限码 + private static final int REQUEST_PERMISSIONS = 9527; + //内容 + private MapView mapView; + + //地图控制器 + private AMap aMap = null; + //位置更改监听 + private OnLocationChangedListener mListener; + + private ActionBar actionBar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + actionBar = getSupportActionBar(); + assert actionBar != null; + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setTitle("深安割草机器人"); + mapView = findViewById(R.id.map_view); + mapView.onCreate(savedInstanceState); + initLocation(); + initMap(savedInstanceState); + checkingAndroidVersion(); + findViewById(R.id.base_config_layout).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent=new Intent(MainActivity.this, ServiceActivity.class); + startActivity(intent); + } + }); + + findViewById(R.id.mowing_layout).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent=new Intent(MainActivity.this,ClientActivity.class); + startActivity(intent); + } + }); + + + findViewById(R.id.client_mode_layout).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent=new Intent(MainActivity.this,ESP8266ClientActivity.class); + startActivity(intent); + } + }); + + } + + + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + if (item.getItemId() == android.R.id.home){ + Toast.makeText(this,"返回上一页",Toast.LENGTH_LONG).show(); + finish(); + }else if (item.getItemId() == R.id.action_more){ + Toast.makeText(this,"更多设置",Toast.LENGTH_LONG).show(); + } + return true; + } + public void activate(OnLocationChangedListener onLocationChangedListener) { + mListener = onLocationChangedListener; + if (mLocationClient != null) { + mLocationClient.startLocation();//启动定位 + } + } + + /** + * 停止定位 + */ + @Override + public void deactivate() { + mListener = null; + if (mLocationClient != null) { + mLocationClient.stopLocation(); + mLocationClient.onDestroy(); + } + mLocationClient = null; + } + + /** + * 初始化地图 + * @param savedInstanceState + */ + private void initMap(Bundle savedInstanceState) { + mapView = findViewById(R.id.map_view); + //在activity执行onCreate时执行mMapView.onCreate(savedInstanceState),创建地图 + mapView.onCreate(savedInstanceState); + //初始化地图控制器对象 + aMap = mapView.getMap(); + + //设置最小缩放等级为16 ,缩放级别范围为[3, 20] + aMap.setMinZoomLevel(12); + // 自定义定位蓝点图标 + myLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromResource(R.drawable.baseline_location_on_24)); + // 自定义精度范围的圆形边框颜色 都为0则透明 + myLocationStyle.strokeColor(Color.argb(0, 0, 0, 0)); + // 自定义精度范围的圆形边框宽度 0 无宽度 + myLocationStyle.strokeWidth(0); + // 设置圆形的填充颜色 都为0则透明 + myLocationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)); + + //设置定位蓝点的Style + aMap.setMyLocationStyle(myLocationStyle); + + // 设置定位监听 + aMap.setLocationSource(this); + // 设置为true表示显示定位层并可触发定位,false表示隐藏定位层并不可触发定位,默认是false + aMap.setMyLocationEnabled(true); + } + + /** + * 初始化定位 + */ + private void initLocation() { + //初始化定位 + try { + mLocationClient = new AMapLocationClient(getApplicationContext()); + } catch (Exception e) { + e.printStackTrace(); + } + if (mLocationClient != null) { + //设置定位回调监听 + mLocationClient.setLocationListener(this); + //初始化AMapLocationClientOption对象 + mLocationOption = new AMapLocationClientOption(); + //设置定位模式为AMapLocationMode.Hight_Accuracy,高精度模式。 + mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy); + //获取最近3s内精度最高的一次定位结果: + //设置setOnceLocationLatest(boolean b)接口为true,启动定位时SDK会返回最近3s内精度最高的一次定位结果。如果设置其为true,setOnceLocation(boolean b)接口也会被设置为true,反之不会,默认为false。 + mLocationOption.setOnceLocationLatest(true); + //设置是否返回地址信息(默认返回地址信息) + mLocationOption.setNeedAddress(true); + //设置定位请求超时时间,单位是毫秒,默认30000毫秒,建议超时时间不要低于8000毫秒。 + mLocationOption.setHttpTimeOut(20000); + //关闭缓存机制,高精度定位会产生缓存。 + mLocationOption.setLocationCacheEnable(false); + //给定位客户端对象设置定位参数 + mLocationClient.setLocationOption(mLocationOption); + } + } + + /** + * 接收异步返回的定位结果 + * + * @param aMapLocation + */ + @Override + public void onLocationChanged(AMapLocation aMapLocation) { + if (aMapLocation != null) { + if (aMapLocation.getErrorCode() == 0) { + //地址 + String address = aMapLocation.getAddress(); + double latitude = aMapLocation.getLatitude(); + double longitude = aMapLocation.getLongitude(); + StringBuilder stringBuffer = new StringBuilder(); + stringBuffer.append("纬度:").append(latitude).append("\n"); + stringBuffer.append("经度:").append(longitude).append("\n"); + stringBuffer.append("地址:").append(address).append("\n"); + Log.d("MainActivity",stringBuffer.toString()); + showMsg(address); + mLocationClient.stopLocation(); + if (mListener != null){ + mListener.onLocationChanged(aMapLocation); + } + + } else { + //定位失败时,可通过ErrCode(错误码)信息来确定失败的原因,errInfo是错误信息,详见错误码表。 + Log.e("AmapError", "location Error, ErrCode:" + + aMapLocation.getErrorCode() + ", errInfo:" + + aMapLocation.getErrorInfo()); + } + } + } + + /** + * 检查Android版本 + */ + private void checkingAndroidVersion() { + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ + //Android6.0及以上先获取权限再定位 + requestPermission(); + }else { + //Android6.0以下直接定位 + mLocationClient.startLocation(); + } + } + + /** + * 动态请求权限 + */ + @AfterPermissionGranted(REQUEST_PERMISSIONS) + private void requestPermission() { + String[] permissions = new String[]{ + "android.permission.ACCESS_COARSE_LOCATION", + "android.permission.ACCESS_FINE_LOCATION", + "android.permission.READ_PHONE_STATE", + "android.permission.WRITE_EXTERNAL_STORAGE" + }; + + if (EasyPermissions.hasPermissions(this, permissions)) { + //true 有权限 开始定位 + showMsg("已获得权限,可以定位啦!"); + mLocationClient.startLocation(); + } else { + //false 无权限 + EasyPermissions.requestPermissions(this, "需要权限", REQUEST_PERMISSIONS, permissions); + } + } + + /** + * 请求权限结果 + * @param requestCode + * @param permissions + * @param grantResults + */ + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + //设置权限请求结果 + EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); + } + + + /** + * Toast提示 + * @param msg 提示内容 + */ + private void showMsg(String msg){ + Toast.makeText(this,msg,Toast.LENGTH_SHORT).show(); + } + @Override + protected void onResume() { + super.onResume(); + //在activity执行onResume时执行mMapView.onResume (),重新绘制加载地图 + mapView.onResume(); + } + @Override + protected void onPause() { + super.onPause(); + //在activity执行onPause时执行mMapView.onPause (),暂停地图的绘制 + mapView.onPause(); + } + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + //在activity执行onSaveInstanceState时执行mMapView.onSaveInstanceState (outState),保存地图当前的状态 + mapView.onSaveInstanceState(outState); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + //销毁定位客户端,同时销毁本地定位服务。 + mLocationClient.onDestroy(); + mapView.onDestroy(); + } + +} \ No newline at end of file diff --git a/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/MapApplication.java b/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/MapApplication.java new file mode 100644 index 0000000..763cef7 --- /dev/null +++ b/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/MapApplication.java @@ -0,0 +1,25 @@ +package com.example.upbot; + +import android.app.Application; +import android.content.Context; + +import com.amap.api.location.AMapLocationClient; +import com.amap.api.maps.MapsInitializer; +import com.amap.api.services.core.ServiceSettings; + +public class MapApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + Context context = this; + //定位隐私政策同意 + AMapLocationClient.updatePrivacyShow(context,true,true); + AMapLocationClient.updatePrivacyAgree(context,true); + //地图隐私政策同意 + MapsInitializer.updatePrivacyShow(context,true,true); + MapsInitializer.updatePrivacyAgree(context,true); + //搜索隐私政策同意 + ServiceSettings.updatePrivacyShow(context,true,true); + ServiceSettings.updatePrivacyAgree(context,true); + } +} diff --git a/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/ServiceActivity.java b/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/ServiceActivity.java new file mode 100644 index 0000000..9e82ff6 --- /dev/null +++ b/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/ServiceActivity.java @@ -0,0 +1,205 @@ +package com.example.upbot; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +public class ServiceActivity extends AppCompatActivity { + + private Button clearBtn; + private Button showIPBtn; + private TextView ipTV; + private TextView msgTV; + private ServerSocket mServerSocket; + private Socket mSocket; + private StringBuffer stringBuffer = new StringBuffer(); + private final String TAG = "WifiDemoLogServiceActivity"; + + + @SuppressLint("HandlerLeak") + public Handler handler = new Handler(Looper.myLooper()) { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == 1) { + stringBuffer.append(msg.obj); + stringBuffer.append("\n"); + msgTV.setText(stringBuffer.toString()); + } + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_service); + initView(); + setListener(); + + try { + mServerSocket = new ServerSocket(5000);//端口号5000 + } catch (IOException e) { + e.printStackTrace(); + } + //启动服务线程 + SocketAcceptThread socketAcceptThread = new SocketAcceptThread(); + socketAcceptThread.start(); + } + + /** + * 获得控件实例 + */ + private void initView() { + clearBtn = findViewById(R.id.clearBtn); + showIPBtn = findViewById(R.id.showIPBtn); + ipTV = findViewById(R.id.ipTV); + msgTV = findViewById(R.id.msgTV); + } + + /** + * 为控件设置监听 + */ + private void setListener() { + clearBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + stringBuffer.setLength(0); + msgTV.setText(""); + } + }); + showIPBtn.setOnClickListener(new View.OnClickListener() { + @SuppressLint("SetTextI18n") + @Override + public void onClick(View v) { + ipTV.setText(getLocalIpAddress(ServiceActivity.this) + ":5000"); + } + }); + + } + + + /** + * 连接线程 + * 得到Socket + */ + class SocketAcceptThread extends Thread { + @Override + public void run() { + try { + //等待客户端的连接,Accept会阻塞,直到建立连接, + //所以需要放在子线程中运行 + mSocket = mServerSocket.accept(); + } catch (IOException e) { + e.printStackTrace(); + return; + } + //启动消息接收线程 + startReader(mSocket); + } + } + + /** + * 从参数的Socket里获取最新的消息 + */ + private void startReader(final Socket socket) { + + new Thread() { + @Override + public void run() { + DataInputStream reader; + try { + // 获取读取流 + reader = new DataInputStream(socket.getInputStream()); + while (true) { + // 读取数据 + String msg = reader.readUTF(); + Log.d(TAG, "客户端的信息:" + msg); + + //告知客户端消息收到 + DataOutputStream writer = new DataOutputStream(mSocket.getOutputStream()); + writer.writeUTF("收到:" + msg); // 写一个UTF-8的信息 + + //发消息更新UI + Message message = new Message(); + message.what = 1; + message.obj=msg; + handler.sendMessage(message); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + }.start(); + } + + @Override + protected void onDestroy() { + if (mServerSocket != null) { + try { + mServerSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if(mSocket!=null){ + try { + mSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + super.onDestroy(); + } + + /** + * 将ip的整数形式转换成ip形式 + * + * @param ipInt + * @return + */ + public static String int2ip(int ipInt) { + StringBuilder sb = new StringBuilder(); + sb.append(ipInt & 0xFF).append("."); + sb.append((ipInt >> 8) & 0xFF).append("."); + sb.append((ipInt >> 16) & 0xFF).append("."); + sb.append((ipInt >> 24) & 0xFF); + return sb.toString(); + } + + /** + * 获取当前ip地址 + * + * @param context + * @return + */ + public static String getLocalIpAddress(Context context) { + try { + + WifiManager wifiManager = (WifiManager) context + .getSystemService(Context.WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + int i = wifiInfo.getIpAddress(); + return int2ip(i); + } catch (Exception ex) { + return " 获取IP出错鸟!!!!请保证是WIFI,或者请重新打开网络!\n" + ex.getMessage(); + } + // return null; + } +} \ No newline at end of file diff --git a/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/SplashActivity.java b/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/SplashActivity.java new file mode 100644 index 0000000..ac7e05f --- /dev/null +++ b/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/SplashActivity.java @@ -0,0 +1,57 @@ +package com.example.upbot; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; +import android.view.View; +import android.view.WindowManager; + +import androidx.annotation.RequiresApi; +import androidx.appcompat.app.AppCompatActivity; + +@SuppressLint("CustomSplashScreen") +public class SplashActivity extends AppCompatActivity { + + @RequiresApi(api = Build.VERSION_CODES.P) + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + fullScreenDisplay(); + setContentView(R.layout.activity_splash); + //创建子线程 + Thread mThread=new Thread(){ + @Override + public void run() { + super.run(); + try { + sleep(3000);//使程序休眠3秒 + Intent intent=new Intent(getApplicationContext(),MainActivity.class); + startActivity(intent); + finish(); + }catch (Exception e){ + e.printStackTrace(); + } + } + }; + mThread.start();//启动线程 + } + @RequiresApi(api = Build.VERSION_CODES.P) + protected void fullScreenDisplay(){ + // 隐藏状态栏和ActionBar,实现全屏画面的效果 + //隐藏状态栏 + getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + //隐藏标题栏 + getSupportActionBar().hide(); + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_FULLSCREEN); + + WindowManager.LayoutParams lp = getWindow().getAttributes(); + + // 始终允许窗口延伸到屏幕短边上的刘海区域 + lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams. + LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; + + getWindow().setAttributes(lp); + } +} \ No newline at end of file diff --git a/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/WiFiModeUtil.java b/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/WiFiModeUtil.java new file mode 100644 index 0000000..5e00b32 --- /dev/null +++ b/robot_android_App/APP/UPBot/app/src/main/java/com/example/upbot/WiFiModeUtil.java @@ -0,0 +1,258 @@ +package com.example.upbot; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.os.CountDownTimer; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.Log; + +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.util.ArrayList; +import java.util.List; + +/** + * 正在连接广播Action:"WiFiModeUtil.Connecting" + * 连接失败广播Action:"WiFiModeUtil.Connect.Fail" + * 连接成功广播Action:"WiFiModeUtil.Connect.Succeed" + * 收到数据广播Action:"WiFiModeUtil.Connect.ReceiveMessage" + * 连接断开广播Action:"WiFiModeUtil.Disconnected" + */ +public class WiFiModeUtil { + private static String mIp;//硬件的IP + private static int mPort = 5000;//硬件的端口 + public static Socket mSocket = null;//连接成功可得到的Socket + public static OutputStream outputStream = null;//定义输出流 + public static InputStream inputStream = null;//定义输入流 + public static StringBuffer DataRecivice = new StringBuffer();//数据 + public static List DataList=new ArrayList<>();//数据 + public static boolean connectFlage = true;//连接成功或连接3s后变false + // private static int ShowPointSum = 0;//连接时显示 连接中.. 后面点的计数 + private static final String TAG = "WifiDemoLogESP8266ClientActivity"; + + /** + * 本地广播管理器 从外面用: + * WiFiModeUtil.localBroadcastManager=localBroadcastManager; + * 进行赋值 + */ + public static LocalBroadcastManager localBroadcastManager; + + /** + * 处理消息的Handler + */ + @SuppressLint("HandlerLeak") + public static Handler mHandler = new Handler(Looper.myLooper()) { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case 0://接收到数据 + DataRecivice.append(msg.obj.toString()); + DataRecivice.append("\n"); + DataList.add(msg.obj.toString());//添加数据 + Intent intent = new Intent("WiFiModeUtil.Connect.ReceiveMessage"); + localBroadcastManager.sendBroadcast(intent);//发送收到数据广播 + break; + case 1://连接成功 + Intent intent2 = new Intent("WiFiModeUtil.Connect.Succeed"); + localBroadcastManager.sendBroadcast(intent2);//发送连接成功广播 + readData();//开启接收线程 + connectFlage = true; + break; + case 2://连接断开 + Intent intent3 = new Intent("WiFiModeUtil.Disconnected"); + localBroadcastManager.sendBroadcast(intent3);//发送连接失败广播 + connectFlage = true; + break; + } + } + }; + + /*** + * 延时3s的定时器 + * 在开始连接时计时3s + * 3s未连接上视为连接失败 + */ + private final static CountDownTimer tcpClientCountDownTimer = new CountDownTimer(3000, 300) { + @Override + public void onTick(long millisUntilFinished) {//每隔300ms进入 + if (connectFlage) { + Intent intent = new Intent("WiFiModeUtil.Connecting"); + localBroadcastManager.sendBroadcast(intent); + } + } + + @Override + public void onFinish() {//3s后进入(没有取消定时器的情况下) + if (connectFlage) { + connectFlage = false;//连接失败 + closeSocketAndStream(); + } + tcpClientCountDownTimer.cancel();//关掉定时器 + Intent intent = new Intent("WiFiModeUtil.Connect.Fail"); + localBroadcastManager.sendBroadcast(intent); + Log.d(TAG,"连接失败"); + } + }; + + /** + * 关掉Socket和输入输出流 + */ + public static void closeSocketAndStream() { + if (outputStream != null) { + try { + outputStream.close(); + Log.d(TAG,"关闭输出流"); + } catch (IOException e) { + e.printStackTrace(); + } + outputStream = null; + } + if (inputStream != null) { + try { + inputStream.close(); + Log.d(TAG,"关闭输入流"); + } catch (IOException e) { + e.printStackTrace(); + } + inputStream = null; + } + if (mSocket != null) { + try { + mSocket.close(); + Log.d(TAG,"关闭Socket"); + } catch (IOException e) { + e.printStackTrace(); + } + mSocket = null; + } + } + + /** + * 连接服务器任务 + */ + static class ConnectSeverThread extends Thread { + @Override + public void run() { + Log.d(TAG,"连接线程开启"); + while (connectFlage) { + try { + Log.d(TAG,"正在连接..."); + mSocket = new Socket(mIp, mPort);//进行连接 + connectFlage = false;//已连接 + tcpClientCountDownTimer.cancel();//关掉计时器 + /*连接成功更新显示连接状态的UI*/ + Message msg = new Message(); + msg.what = 1; + mHandler.sendMessage(msg); + Log.d(TAG,"连接成功"); + inputStream = mSocket.getInputStream();//获取输入流 + Log.d(TAG,"获取输入流"); + outputStream = mSocket.getOutputStream();////获取输出流 + Log.d(TAG,"获取输出流"); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + Log.d(TAG,"连接过程中出错"); + } + } + } + } + + /** + * 传入硬件服务端IP建立TCP连接 + * 正在连接每200ms 发送一条‘正在连接’广播 + * 3秒后还未连接则连接失败 发送一条‘失败广播’ + * 连接成功会 发送一条‘成功广播’ + * + * @param IPAdress + */ + public static void connetByTCP(String IPAdress,int Port) { + mIp = IPAdress; + mPort=Port; + ConnectSeverThread connectSeverThread = new ConnectSeverThread(); + connectSeverThread.start(); + tcpClientCountDownTimer.start(); + } + + /** + * 向硬件发送数据 + */ + public static void sendData(String data) { + if(mSocket!=null){ + byte[] sendByte = data.getBytes(); + new Thread() { + @Override + public void run() { + try { + Log.d(TAG,"发送线程开启 正在发送中..."); + DataOutputStream writer = new DataOutputStream(outputStream); + writer.write(sendByte, 0, sendByte.length); + Log.d(TAG,"已发送数据:"+data); + } catch (IOException e) { + e.printStackTrace(); + } + Log.d(TAG,"发送线程结束"); + } + }.start(); + } + } + + /** + * 连接成功后开启 + * 接收硬件发送的数据 + */ + public static void readData() { + new Thread() { + @Override + public void run() { + Log.d(TAG,"接收线程开启"); + try { + while (true) { + Thread.sleep(200); + //如果连接断开 尝试重连 + try { + /* + sendUrgentData()方法 + 它会往输出流发送一个字节的数据, + 只要对方Socket的SO_OOBINLINE属性没有打开, + 就会自动舍弃这个字节, + 就会抛出异常, + 而SO_OOBINLINE属性默认情况下就是关闭的 + */ + mSocket.sendUrgentData(0xFF);//发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信 + } catch (Exception ex) { + Log.d(TAG,"连接已断开,请重新进行连接"); + Message msg=new Message(); + msg.what=2; + msg.obj="连接已断开,请重新进行连接"; + mHandler.sendMessage(msg); + } + DataInputStream reader = new DataInputStream(inputStream); + byte[] buffer = new byte[1024]; + int len; + while ((len = reader.read(buffer)) != -1) { + String data = new String(buffer, 0, len); + Log.d(TAG,"接收到数据:"+data); + Message msg = new Message(); + msg.what = 0; + msg.obj = data; + mHandler.sendMessage(msg); + } + } + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + Log.d(TAG,"接收线程结束"); + } + }.start(); + } +} diff --git a/robot_android_App/APP/UPBot/app/src/main/res/drawable/baseline_location_on_24.xml b/robot_android_App/APP/UPBot/app/src/main/res/drawable/baseline_location_on_24.xml new file mode 100644 index 0000000..40ef933 --- /dev/null +++ b/robot_android_App/APP/UPBot/app/src/main/res/drawable/baseline_location_on_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/robot_android_App/APP/UPBot/app/src/main/res/layout/activity_main.xml b/robot_android_App/APP/UPBot/app/src/main/res/layout/activity_main.xml index 7bd2813..9cfaf5b 100644 --- a/robot_android_App/APP/UPBot/app/src/main/res/layout/activity_main.xml +++ b/robot_android_App/APP/UPBot/app/src/main/res/layout/activity_main.xml @@ -8,12 +8,12 @@ android:orientation="vertical" tools:context=".MainActivity"> - + android:layout_weight="1" + android:layout_marginBottom="10dp"/> -