diff --git a/.metadata b/.metadata index df45ecd..840c299 100644 --- a/.metadata +++ b/.metadata @@ -1,10 +1,30 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled and should not be manually edited. +# This file should be version controlled. version: - revision: b101bfe32f634566e7cb2791a9efe19cf8828b15 - channel: beta + revision: cd41fdd495f6944ecd3506c21e94c6567b073278 + channel: unknown project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 + base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 + - platform: android + create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 + base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/android/app/build.gradle b/android/app/build.gradle index 710d120..97a6fde 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -8,7 +8,7 @@ if (localPropertiesFile.exists()) { def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { - throw new Exception("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') @@ -28,24 +28,19 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { // compileSdkVersion flutter.compileSdkVersion compileSdkVersion 32 - ndkVersion "23.1.7779620" + ndkVersion flutter.ndkVersion compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "cn.com.motse.fengshui_compass" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. +// minSdkVersion flutter.minSdkVersion minSdkVersion 19 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() @@ -59,19 +54,8 @@ android { signingConfig signingConfigs.debug } } - - lintOptions { - disable 'InvalidPackage' - disable "Instantiatable" - checkReleaseBuilds false - abortOnError false - } } flutter { source '../..' } - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 44c27bd..a42f077 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,7 @@ - diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index fb44375..a328806 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -29,7 +29,6 @@ This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> diff --git a/android/app/src/main/java/cn/com/motse/fengshui_compass/ComShellUtils.java b/android/app/src/main/java/cn/com/motse/fengshui_compass/ComShellUtils.java new file mode 100644 index 0000000..4135831 --- /dev/null +++ b/android/app/src/main/java/cn/com/motse/fengshui_compass/ComShellUtils.java @@ -0,0 +1,142 @@ +package cn.com.motse.fengshui_compass; + +import android.util.Log; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2016/08/07
+ *     desc  : utils about shell
+ * 
+ */ +public final class ComShellUtils { + public static final String TAG = "CommandExecution"; + + public final static String COMMAND_SU = "su"; + public final static String COMMAND_SH = "sh"; + public final static String COMMAND_EXIT = "exit\n"; + public final static String COMMAND_LINE_END = "\n"; + + /** + * Command执行结果 + * + * @author Mountain + */ + public static class CommandResult { + public int result = -1; + public String errorMsg; + public String successMsg; + + @Override + public String toString() { + return "CommandResult{" + + "result=" + result + + ", errorMsg='" + errorMsg + '\'' + + ", successMsg='" + successMsg + '\'' + + '}'; + } + } + + /** + * 执行命令—单条 + * + * @param command + * @param isRoot + * @return + */ + public static CommandResult execCommand(String command, boolean isRoot) { + String[] commands = {command}; + return execCommand(commands, isRoot); + } + + /** + * 执行命令-多条 + * + * @param commands + * @param isRoot + * @return + */ + public static CommandResult execCommand(String[] commands, boolean isRoot) { + CommandResult commandResult = new CommandResult(); + if (commands == null || commands.length == 0) return commandResult; + Process process = null; + DataOutputStream os = null; + BufferedReader successResult = null; + BufferedReader errorResult = null; + StringBuilder successMsg = null; + StringBuilder errorMsg = null; + try { + process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH); + os = new DataOutputStream(process.getOutputStream()); + for (String command : commands) { + if (command != null) { + os.write(command.getBytes()); + os.writeBytes(COMMAND_LINE_END); + os.flush(); + } + } + os.writeBytes(COMMAND_EXIT); + os.flush(); + commandResult.result = process.waitFor(); + //获取错误信息 + successMsg = new StringBuilder(); + errorMsg = new StringBuilder(); + successResult = new BufferedReader(new InputStreamReader(process.getInputStream())); + errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream())); + String s; + while ((s = successResult.readLine()) != null) { + successMsg.append(s); + } + while ((s = errorResult.readLine()) != null) { + errorMsg.append(s); + } + commandResult.successMsg = successMsg.toString(); + commandResult.errorMsg = errorMsg.toString(); + Log.i(TAG, commandResult.result + " | " + commandResult.successMsg + + " | " + commandResult.errorMsg); + } catch (IOException e) { + String errmsg = e.getMessage(); + if (errmsg != null) { + Log.e(TAG, errmsg); + } else { + e.printStackTrace(); + } + } catch (Exception e) { + String errmsg = e.getMessage(); + if (errmsg != null) { + Log.e(TAG, errmsg); + } else { + e.printStackTrace(); + } + } finally { + try { + if (os != null) { + os.close(); + } + if (successResult != null) { + successResult.close(); + } + if (errorResult != null) { + errorResult.close(); + } + } catch (IOException e) { + String errmsg = e.getMessage(); + if (errmsg != null) { + Log.e(TAG, errmsg); + } else { + e.printStackTrace(); + } + } + if (process != null) { + process.destroy(); + } + } + return commandResult; + } +} diff --git a/android/app/src/main/java/cn/com/motse/fengshui_compass/MainActivity.java b/android/app/src/main/java/cn/com/motse/fengshui_compass/MainActivity.java new file mode 100644 index 0000000..749bfec --- /dev/null +++ b/android/app/src/main/java/cn/com/motse/fengshui_compass/MainActivity.java @@ -0,0 +1,45 @@ +package cn.com.motse.fengshui_compass; + + +import androidx.annotation.NonNull; + +import io.flutter.embedding.android.FlutterActivity; +import io.flutter.embedding.engine.FlutterEngine; +import io.flutter.plugin.common.MethodChannel; + +public class MainActivity extends FlutterActivity { + private static final String CHANNEL = "toggle_power"; + + @Override + public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { + super.configureFlutterEngine(flutterEngine); + new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL) + .setMethodCallHandler( + (call, result) -> { + if (call.method.equals("turnOnPower")) { + String state = "1"; + String ioValue = "236"; + String cmdStr1 = "echo " + ioValue + " > /sys/class/gpio/export"; + String cmdStr2 = "echo out > /sys/class/gpio/gpio" + ioValue + "/direction"; + String cmdStr3 = "echo " + state + " > /sys/class/gpio/gpio" + ioValue + "/value"; + ComShellUtils.execCommand(cmdStr1, false); + ComShellUtils.execCommand(cmdStr2, false); + ComShellUtils.execCommand(cmdStr3, false); + result.success("on"); + } else if (call.method.equals("turnOffPower")) { + String state = "0"; + String ioValue = "236"; + String cmdStr1 = "echo " + ioValue + " > /sys/class/gpio/export"; + String cmdStr2 = "echo out > /sys/class/gpio/gpio" + ioValue + "/direction"; + String cmdStr3 = "echo " + state + " > /sys/class/gpio/gpio" + ioValue + "/value"; + ComShellUtils.execCommand(cmdStr1, false); + ComShellUtils.execCommand(cmdStr2, false); + ComShellUtils.execCommand(cmdStr3, false); + result.success("off"); + } else { + result.notImplemented(); + } + } + ); + } +} diff --git a/android/app/src/main/kotlin/cn/com/motse/fengshui_compass/MainActivity.kt b/android/app/src/main/kotlin/cn/com/motse/fengshui_compass/MainActivity.kt deleted file mode 100644 index b511c1a..0000000 --- a/android/app/src/main/kotlin/cn/com/motse/fengshui_compass/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package cn.com.motse.fengshui_compass - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml index 94fd4e7..304732f 100644 --- a/android/app/src/main/res/drawable/launch_background.xml +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -1,12 +1,12 @@ - + - + diff --git a/android/app/src/main/res/drawable/launch_image.png b/android/app/src/main/res/drawable/launch_image.png deleted file mode 100644 index 27fdfb3..0000000 Binary files a/android/app/src/main/res/drawable/launch_image.png and /dev/null differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index 5d9544c..db77bb4 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index a171f27..17987b7 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 16e8821..09d4391 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 2124814..d5f1c8d 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index d8a3102..4d6372e 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml index 3db14bb..06952be 100644 --- a/android/app/src/main/res/values-night/styles.xml +++ b/android/app/src/main/res/values-night/styles.xml @@ -3,7 +3,7 @@ - #00000000 diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml index 44c27bd..a42f077 100644 --- a/android/app/src/profile/AndroidManifest.xml +++ b/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,7 @@ - diff --git a/android/build.gradle b/android/build.gradle index 4256f91..83ae220 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' + classpath 'com.android.tools.build:gradle:7.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index bc6a58a..cc5527d 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/lib/pages/compass_page.dart b/lib/pages/compass_page.dart index 59c1807..eaca110 100644 --- a/lib/pages/compass_page.dart +++ b/lib/pages/compass_page.dart @@ -7,6 +7,7 @@ import 'package:fengshui_compass/components/my_icon.dart'; import 'package:fengshui_compass/pages/login_page.dart'; import 'package:fengshui_compass/states/region.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_serial_port_api/flutter_serial_port_api.dart'; import 'package:image_picker/image_picker.dart'; import 'package:provider/provider.dart'; @@ -23,7 +24,7 @@ class CompassPage extends StatefulWidget { State createState() => _CompassState(); } -class _CompassState extends State { +class _CompassState extends State with WidgetsBindingObserver { // 串口相关 bool isPortOpened = false; SerialPort _serialPort; @@ -54,16 +55,53 @@ class _CompassState extends State { @override void initState() { super.initState(); + print("init"); + // 添加观察者以监听生命周期事件 + WidgetsBinding.instance?.addObserver(this); initPort(); } + @override + void dispose() { + turnOffPower(); + // 在小部件被销毁时移除观察者,以防止内存泄漏 + WidgetsBinding.instance?.removeObserver(this); + super.dispose(); + print("dispose"); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + // 在这里处理应用程序生命周期状态变化事件 + if (state == AppLifecycleState.paused) { + // 应用程序进入后台 + print('App entered background'); + turnOffPower(); + } else if (state == AppLifecycleState.resumed) { + // 应用程序回到前台 + print('App returned to foreground'); + initPort(); + } else if (state == AppLifecycleState.inactive) { + // 应用程序处于非活动状态(例如:锁屏、电话来电) + print('App in inactive state'); + turnOffPower(); + } + } + Future initPort() async { + await turnOnPower(); + // todo: + setState(() { + isLock = true; + isUpClose = true; + isSideClose = true; + }); // 20ms接收一次串口数据,防抖,定义接收缓存 final debounceTransformer = StreamTransformer.fromBind( (s) => s.transform(debounceBuffer(const Duration(milliseconds: 20)))); if (!isPortOpened) { - Device theDevice = Device("/dev/ttyS2", "/dev/ttyS2"); + Device theDevice = Device("/dev/ttyS3", "/dev/ttyS3"); var serialPort = await FlutterSerialPortApi.createSerialPort( theDevice, 115200, parity: 0, dataBits: 8, stopBit: 1); @@ -89,6 +127,24 @@ class _CompassState extends State { } } + Future turnOnPower() async { + const platform = MethodChannel('toggle_power'); + await platform.invokeMethod("turnOnPower"); + } + + Future turnOffPower() async { + const platform = MethodChannel('toggle_power'); + await platform.invokeMethod("turnOffPower"); + if (mounted) { + setState(() { + isLock = false; + isUpClose = false; + isSideClose = false; + isPortOpened = false; + }); + } + } + Future closePort() async { bool closeResult = await _serialPort.close(); setState(() { @@ -204,40 +260,50 @@ class _CompassState extends State { w_y_tmp = 0.5 - 0.07 * roll_tmp / 30.0; w_x_tmp = 0.5 - 0.07 * pitch_tmp / 30.0; } else if (w_total > 30) { - //todo - w_y_tmp = 0.5 - 0.07 * w_total / 30.0; - w_x_tmp = 0.5 - 0.07 * w_total / 30.0; + // //todo + // w_y_tmp = 0.5 - 0.07 * w_total / 30.0; + // w_x_tmp = 0.5 - 0.07 * w_total / 30.0; + var radius = sqrt(0.07 * 0.07 * 2); + //todo; + var _angle = atan2(roll_tmp, -pitch_tmp); + if (_angle < 0) { + _angle += 2 * pi; + } + w_y_tmp = 0.5 - radius * sin(_angle); + w_x_tmp = 0.5 + radius * cos(_angle); } // todo 其他情况 var meanValue; - if (lista.length < 20) { - lista.add(temp_myaw); - meanValue = null; - } else { - lista.removeAt(0); - lista.add(temp_myaw); - meanValue = lista.map((e) => e).reduce((a, b) => a + b) / lista.length; + // if (lista.length < 20) { + // lista.add(temp_myaw); + // meanValue = null; + // } else { + // lista.removeAt(0); + // lista.add(temp_myaw); + // meanValue = lista.map((e) => e).reduce((a, b) => a + b) / lista.length; + // } + + if (mounted) { + setState(() { + // print("roll: $roll_tmp pitch: $pitch_tmp"); + // print("w_x: $w_x_tmp, w_y: $w_y_tmp"); + // if (meanValue != null) { + // myaw = meanValue; + // } else { + // myaw = 0; + // } + myaw = temp_myaw; + + w_x = w_x_tmp; + w_y = w_y_tmp; + + // 水平仪 0.5+-0.07范围 + // x旋转y在动 y旋转x在动 roll改变y坐标,pitch改变x坐标 + }); } - - setState(() { - // print("roll: $roll_tmp pitch: $pitch_tmp"); - // print("w_x: $w_x_tmp, w_y: $w_y_tmp"); - // if (meanValue != null) { - // myaw = meanValue; - // } else { - // myaw = 0; - // } - myaw = temp_myaw; - - w_x = w_x_tmp; - w_y = w_y_tmp; - - // 水平仪 0.5+-0.07范围 - // x旋转y在动 y旋转x在动 roll改变y坐标,pitch改变x坐标 - }); } else if (str.contains("9E010401") && (str.length >= ((str.indexOf("9E010401") + 26)))) { var pos = str.indexOf("9E010401"); @@ -311,7 +377,8 @@ class _CompassState extends State { } else if (angle > 180) { result = angle - 180; } else { - result = 0.0; + // result = 0.0; + result = angle; } return result; }