diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index c931bef..f27b501 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,20 +1,19 @@ - - - - - + + + + + - - - - - - + + + + + @@ -53,6 +52,12 @@ android:exported="false" android:screenOrientation="landscape" android:theme="@style/NormalTheme" /> + - + \ No newline at end of file diff --git a/android/app/src/main/java/co/steamcloud/game/Config.java b/android/app/src/main/java/co/steamcloud/game/Config.java index 74b058f..85bb00b 100644 --- a/android/app/src/main/java/co/steamcloud/game/Config.java +++ b/android/app/src/main/java/co/steamcloud/game/Config.java @@ -1,9 +1,15 @@ package co.steamcloud.game; +import android.bluetooth.BluetoothHidDevice; + +import co.steamcloud.game.utils.GamePara; + public class Config { public static String url = "https://api.onelight.vip/";//接口域名 public static String BsUrl = "https://os.zhijierongxing.com/";//游戏域名 + public static BluetoothHidDevice mBtHidDevice; + public static String channel_id = "d612a79436ef9ceeee4d6847d854b2e1"; public static String sign_key = "";//加密key public static String userToken = "";//用户token diff --git a/android/app/src/main/java/co/steamcloud/game/HandleActivity.java b/android/app/src/main/java/co/steamcloud/game/HandleActivity.java new file mode 100644 index 0000000..0655655 --- /dev/null +++ b/android/app/src/main/java/co/steamcloud/game/HandleActivity.java @@ -0,0 +1,478 @@ +package co.steamcloud.game; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.bluetooth.BluetoothDevice; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Bundle; +import android.os.Vibrator; +import android.text.TextUtils; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.HapticFeedbackConstants; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.RequiresApi; +import androidx.core.app.ActivityCompat; + +import org.simple.eventbus.EventBus; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import co.steamcloud.game.customize.JoystickView2; +import co.steamcloud.game.customize.MoveButton; +import co.steamcloud.game.utils.AppConfigFileImpl; +import co.steamcloud.game.utils.EventBusParams; +import co.steamcloud.game.utils.GamePad; +import co.steamcloud.game.utils.GamepadAction; +import co.steamcloud.game.utils.GamepadButton; +import co.steamcloud.game.utils.GsonJsonUtil; + +public class HandleActivity extends Activity implements GamepadAction { + + private final String TAG = "MainActivity"; + private int SCREEN_WIDTH = 1920; + private int SCREEN_HEIGHT = 1080; + + private boolean isShock = false;// 震动 + private FrameLayout visualAngle; + private MoveButton yaogan_left, direction_key, yaogan_right, Move_a, Move_b, Move_x, Move_y, Move_rs, Move_rt, + Move_rb, Move_lt, Move_lb, Move_ls, Move_back, Move_start; + ImageView dpad_up, dpad_right, dpad_up_left, dpad_left, dpad_down; + Map CustomButtonMap = new HashMap<>(); + + private float downJoystickX = 0, downJoystickY = 0, moveJoystickX, moveJoystickY; + + private Vibrator vibrator; + + private final ArrayList mDevices = new ArrayList<>(); + + public GamePad gamepad = new GamePad(this); + private TextView button_a, button_b, button_x, button_y, button_rs, button_rt, button_rb, button_lt, button_lb, button_ls, button_back, button_start; + private TextView tvExitHandle; + + @RequiresApi(api = Build.VERSION_CODES.P) + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + setContentView(R.layout.activity_handle); + + hideBottomUIMenu(); + initUI(); + } + + @SuppressLint("MissingPermission") + @RequiresApi(api = Build.VERSION_CODES.P) + @Override + protected void onResume() { + super.onResume(); + } + + + @SuppressLint("ClickableViewAccessibility") + private void initUI() { + // 判断屏幕大小 + DisplayMetrics dm = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(dm);// display = + // getWindowManager().getDefaultDisplay();display.getMetrics(dm)(把屏幕尺寸信息赋值给DisplayMetrics + // dm); + if (dm.widthPixels > dm.heightPixels) { + SCREEN_WIDTH = dm.widthPixels/*- getNavigationHeight(PlayGameActivity.this)*/; + SCREEN_HEIGHT = dm.heightPixels; + } else { + SCREEN_WIDTH = dm.heightPixels/*- getNavigationHeight(PlayGameActivity.this)*/; + SCREEN_HEIGHT = dm.widthPixels; + } + Globe.landscapeScaleWidht = ((float) SCREEN_WIDTH / Globe.landscapeSW); + Globe.landscapeScaleHeight = ((float) SCREEN_HEIGHT / Globe.landscapeSH); + + visualAngle = findViewById(R.id.visual_angle); + + String CustomButton = AppConfigFileImpl.getStringParams(getApplicationContext(), "CustomButton"); + if (!TextUtils.isEmpty(CustomButton)) { + Log.d("TAG", "CustomButton " + CustomButton); + CustomButtonMap = GsonJsonUtil.stringToMap(CustomButton); + } else { + initDefault();// 默认配置 + } + + tvExitHandle = findViewById(R.id.tv_exit_handle); + + tvExitHandle.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showDialog("退出手柄", "确定退出手柄吗?", "退出", "取消", new IDialogTwoView() { + @Override + public void cancel() { + hideBottomUIMenu(); + } + + @Override + public void onSure() { + finish(); + } + + @Override + public void returnApp() { + } + }); + + } + }); + + yaogan_left = findViewById(R.id.yaogan_left); + direction_key = findViewById(R.id.direction_key); + yaogan_right = findViewById(R.id.yaogan_right); + Move_a = findViewById(R.id.Move_a); + Move_b = findViewById(R.id.Move_b); + Move_x = findViewById(R.id.Move_x); + Move_y = findViewById(R.id.Move_y); + Move_rs = findViewById(R.id.Move_rs); + Move_rt = findViewById(R.id.Move_rt); + Move_rb = findViewById(R.id.Move_rb); + Move_lt = findViewById(R.id.Move_lt); + Move_lb = findViewById(R.id.Move_lb); + Move_ls = findViewById(R.id.Move_ls); + Move_back = findViewById(R.id.Move_back); + Move_start = findViewById(R.id.Move_start); + + + button_a = findViewById(R.id.button_a); + button_b = findViewById(R.id.button_b); + button_x = findViewById(R.id.button_x); + button_y = findViewById(R.id.button_y); + button_rs = findViewById(R.id.button_rs); + button_rt = findViewById(R.id.button_rt); + button_rb = findViewById(R.id.button_rb); + button_lt = findViewById(R.id.button_lt); + button_lb = findViewById(R.id.button_lb); + button_ls = findViewById(R.id.button_ls); + button_back = findViewById(R.id.button_back); + button_start = findViewById(R.id.button_start); + + + initButtonPosition(); + dpad_up = findViewById(R.id.dpad_up); + dpad_left = findViewById(R.id.dpad_left); + dpad_down = findViewById(R.id.dpad_down); + dpad_right = findViewById(R.id.dpad_right); + dpad_up_left = findViewById(R.id.dpad_up_left); + dpad_up.setClickable(true); + dpad_left.setClickable(true); + dpad_down.setClickable(true); + dpad_right.setClickable(true); + dpad_up_left.setClickable(true); + + JoystickView2 joystickLeft = findViewById(R.id.joystick_left); + JoystickView2 joystickRight = findViewById(R.id.joystick_right); + joystickLeft.setOnJoystickListener(new JoystickView2.OnJoystickListener() { + @SuppressLint("MissingPermission") + @RequiresApi(api = Build.VERSION_CODES.P) + @Override + public void onPosition(float x, float y) { + // Config.keyEvent_time = 0; + Log.w("TAG", "stick x=" + x + " y=" + y); + gamepad.SetLeftRemoteSensing(x, y); + // System.out.println("player1 setXY x="+x+"y="+y); + } + + @Override + public void onVibrator() { + // joystickLeft.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, + // HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + if (isShock) { + joystickLeft.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, + HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } + } + }); + joystickRight.setOnJoystickListener(new JoystickView2.OnJoystickListener() { + @SuppressLint("MissingPermission") + @RequiresApi(api = Build.VERSION_CODES.P) + @Override + public void onPosition(float x, float y) { + // Config.keyEvent_time = 0; + Log.w("TAG", "stick x=" + x + " y=" + y); + gamepad.SetRightRemoteSensing(x, y); + + } + + @Override + public void onVibrator() { + // joystickLeft.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, + // HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + if (isShock) { + joystickLeft.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, + HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } + } + }); + + setBtnKey(button_a, gamepad.BUTTON_A); + setBtnKey(button_b, gamepad.BUTTON_B); + setBtnKey(button_x, gamepad.BUTTON_X); + setBtnKey(button_y, gamepad.BUTTON_Y); + setBtnKey(button_lb, gamepad.BUTTON_L1); + setBtnKey(button_rb, gamepad.BUTTON_R1); + setBtnKey(button_lt, gamepad.BUTTON_L2); + setBtnKey(button_rt, gamepad.BUTTON_R2); + setBtnKey(button_start, gamepad.BUTTON_START); + setBtnKey(button_back, gamepad.BUTTON_SELECT); + setBtnKey(button_ls, gamepad.BUTTON_L3); + setBtnKey(button_rs, gamepad.BUTTON_R3); + setBtnKey(dpad_up, gamepad.BUTTON_DPAD_UP); + setBtnKey(dpad_right, gamepad.BUTTON_DPAD_RIGHT); + setBtnKey(dpad_down, gamepad.BUTTON_DPAD_DOWN); + setBtnKey(dpad_left, gamepad.BUTTON_DPAD_LEFT); + + setBtnKey(dpad_up_left, gamepad.BUTTON_DPAD_UP, gamepad.BUTTON_DPAD_LEFT); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + showDialog("退出手柄", "确定退出手柄吗?", "退出", "取消", new IDialogTwoView() { + @Override + public void cancel() { + hideBottomUIMenu(); + } + + @Override + public void onSure() { + finish(); + } + + @Override + public void returnApp() { + } + }); + return true; + } + return super.onKeyDown(keyCode, event); + + } + + public void showDialog(String title, String content, String cancelStr, String sureStr, final IDialogTwoView iDialogView) { + BaseAlertDialog baseAlertDialog = new BaseAlertDialog.Builder(this).show(title, content, cancelStr, sureStr, iDialogView).create(); + try { + baseAlertDialog.show(); + } catch (Exception e) { + } + } + + public void setBtnKey(TextView btn, GamepadButton gamepadButton) { + btn.setOnTouchListener(createButtonTouchListener(gamepadButton)); + } + + public void setBtnKey(ImageView btn, GamepadButton gamepadButton) { + btn.setOnTouchListener(createButtonTouchListener(gamepadButton)); + } + + public void setBtnKey(ImageView btn, GamepadButton gamepadButton, GamepadButton gamepadButton2) { + btn.setOnTouchListener(createButtonTouchListener(gamepadButton, gamepadButton2)); + } + + private byte testKeyCode = (byte) 0x01; + + public void initDefault() { + try { + CustomButtonMap.put("yaogan_left", 106 * Globe.landscapeScaleWidht + "@" + 653.5 * Globe.landscapeScaleHeight); + CustomButtonMap.put("direction_key", 565 * Globe.landscapeScaleWidht + "@" + 730.0 * Globe.landscapeScaleHeight); + CustomButtonMap.put("yaogan_right", 1248 * Globe.landscapeScaleWidht + "@" + 770 * Globe.landscapeScaleHeight); + CustomButtonMap.put("Move_a", 1645 * Globe.landscapeScaleWidht + "@" + 799 * Globe.landscapeScaleHeight); + CustomButtonMap.put("Move_b", 1774 * Globe.landscapeScaleWidht + "@" + 680 * Globe.landscapeScaleHeight); + CustomButtonMap.put("Move_x", 1521 * Globe.landscapeScaleWidht + "@" + 680 * Globe.landscapeScaleHeight); + CustomButtonMap.put("Move_y", 1645 * Globe.landscapeScaleWidht + "@" + 562 * Globe.landscapeScaleHeight); + CustomButtonMap.put("Move_rs", 1547 * Globe.landscapeScaleWidht + "@" + 300 * Globe.landscapeScaleHeight); + CustomButtonMap.put("Move_rt", 1698 * Globe.landscapeScaleWidht + "@" + 343 * Globe.landscapeScaleHeight); + CustomButtonMap.put("Move_rb", 1452 * Globe.landscapeScaleWidht + "@" + 453 * Globe.landscapeScaleHeight); + CustomButtonMap.put("Move_ls", 134 * Globe.landscapeScaleWidht + "@" + 303 * Globe.landscapeScaleHeight); + CustomButtonMap.put("Move_lt", 44 * Globe.landscapeScaleWidht + "@" + 480 * Globe.landscapeScaleHeight); + CustomButtonMap.put("Move_lb", 261 * Globe.landscapeScaleWidht + "@" + 404 * Globe.landscapeScaleHeight); + CustomButtonMap.put("Move_back", 1774 * Globe.landscapeScaleWidht + "@" + 30 * Globe.landscapeScaleHeight); + CustomButtonMap.put("Move_start", 1774 * Globe.landscapeScaleWidht + "@" + 149 * Globe.landscapeScaleHeight); + } catch (Exception e) { + e.printStackTrace(); + } + } + + // 调用前必须先初始化按钮 + public void initButtonPosition() { + try { + if (CustomButtonMap.get("yaogan_left") != null + && !TextUtils.isEmpty(CustomButtonMap.get("yaogan_left").toString())) { + String[] split = CustomButtonMap.get("yaogan_left").toString().split("@"); + yaogan_left.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + if (CustomButtonMap.get("direction_key") != null + && !TextUtils.isEmpty(CustomButtonMap.get("direction_key").toString())) { + String[] split = CustomButtonMap.get("direction_key").toString().split("@"); + direction_key.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + if (CustomButtonMap.get("yaogan_right") != null + && !TextUtils.isEmpty(CustomButtonMap.get("yaogan_right").toString())) { + String[] split = CustomButtonMap.get("yaogan_right").toString().split("@"); + yaogan_right.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + if (CustomButtonMap.get("Move_a") != null && !TextUtils.isEmpty(CustomButtonMap.get("Move_a").toString())) { + String[] split = CustomButtonMap.get("Move_a").toString().split("@"); + // Log.d(TAG, "initButtonPosition: aaaaaaaaaaaaaaaaaaaaaaaa"); + Move_a.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + if (CustomButtonMap.get("Move_b") != null && !TextUtils.isEmpty(CustomButtonMap.get("Move_b").toString())) { + String[] split = CustomButtonMap.get("Move_b").toString().split("@"); + Move_b.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + if (CustomButtonMap.get("Move_x") != null && !TextUtils.isEmpty(CustomButtonMap.get("Move_x").toString())) { + String[] split = CustomButtonMap.get("Move_x").toString().split("@"); + Move_x.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + if (CustomButtonMap.get("Move_y") != null && !TextUtils.isEmpty(CustomButtonMap.get("Move_y").toString())) { + String[] split = CustomButtonMap.get("Move_y").toString().split("@"); + Move_y.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + if (CustomButtonMap.get("Move_rs") != null + && !TextUtils.isEmpty(CustomButtonMap.get("Move_rs").toString())) { + String[] split = CustomButtonMap.get("Move_rs").toString().split("@"); + Move_rs.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + if (CustomButtonMap.get("Move_rt") != null + && !TextUtils.isEmpty(CustomButtonMap.get("Move_rt").toString())) { + String[] split = CustomButtonMap.get("Move_rt").toString().split("@"); + Move_rt.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + if (CustomButtonMap.get("Move_rb") != null + && !TextUtils.isEmpty(CustomButtonMap.get("Move_rb").toString())) { + String[] split = CustomButtonMap.get("Move_rb").toString().split("@"); + Move_rb.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + if (CustomButtonMap.get("Move_lt") != null + && !TextUtils.isEmpty(CustomButtonMap.get("Move_lt").toString())) { + String[] split = CustomButtonMap.get("Move_lt").toString().split("@"); + Move_lt.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + if (CustomButtonMap.get("Move_lb") != null + && !TextUtils.isEmpty(CustomButtonMap.get("Move_lb").toString())) { + String[] split = CustomButtonMap.get("Move_lb").toString().split("@"); + Move_lb.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + if (CustomButtonMap.get("Move_ls") != null + && !TextUtils.isEmpty(CustomButtonMap.get("Move_ls").toString())) { + String[] split = CustomButtonMap.get("Move_ls").toString().split("@"); + Move_ls.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + if (CustomButtonMap.get("Move_back") != null + && !TextUtils.isEmpty(CustomButtonMap.get("Move_back").toString())) { + String[] split = CustomButtonMap.get("Move_back").toString().split("@"); + Move_back.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + if (CustomButtonMap.get("Move_start") != null + && !TextUtils.isEmpty(CustomButtonMap.get("Move_start").toString())) { + String[] split = CustomButtonMap.get("Move_start").toString().split("@"); + Move_start.setPosition(Float.parseFloat(split[0]), Float.parseFloat(split[1])); + } + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + + protected void hideBottomUIMenu() { + // 隐藏虚拟按键,并且全屏 + if (Build.VERSION.SDK_INT <= 11 && Build.VERSION.SDK_INT < 19) { // lower api + View v = this.getWindow().getDecorView(); + v.setSystemUiVisibility(View.GONE); + } else if (Build.VERSION.SDK_INT > 19) { + // for new api versions. + View decorView = getWindow().getDecorView(); + int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN; + decorView.setSystemUiVisibility(uiOptions); + + } + } + + + private View.OnTouchListener createButtonTouchListener(GamepadButton gamepadButton) { + return new View.OnTouchListener() { + @RequiresApi(api = Build.VERSION_CODES.P) + @Override + public boolean onTouch(View v, MotionEvent event) { + Log.d(TAG, "Button event: " + event.getAction() + ",key="); + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + gamepad.KeyDown(gamepadButton); + break; + case MotionEvent.ACTION_UP: + gamepad.KeyUp(gamepadButton); + break; + case MotionEvent.ACTION_MOVE: + break; + default: + break; + } + return false; + } + }; + } + + private View.OnTouchListener createButtonTouchListener(GamepadButton gamepadButton, GamepadButton gamepadButton2) { + return new View.OnTouchListener() { + @RequiresApi(api = Build.VERSION_CODES.P) + @Override + public boolean onTouch(View v, MotionEvent event) { + Log.d(TAG, "Button event:2 " + event.getAction() + ",key="); + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + gamepad.KeyDown(gamepadButton); + gamepad.KeyDown(gamepadButton2); + break; + case MotionEvent.ACTION_UP: + gamepad.KeyUp(gamepadButton); + gamepad.KeyUp(gamepadButton2); + break; + case MotionEvent.ACTION_MOVE: + break; + default: + break; + } + return false; + } + }; + } + + /** + * 发送手柄数据 + * + * @param params 字节 + */ + @RequiresApi(api = Build.VERSION_CODES.P) + @Override + public void SendRequest(byte[] params) { + +// HashMap TagMap = new HashMap<>(); +// TagMap.put("tag", "SendRequest"); +// TagMap.put("params", params); +// EventBus.getDefault().post(TagMap, EventBusParams.MAIN); + + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { + return; + } + Log.d(TAG, "clickKey: =====>>>>" + Config.mBtHidDevice.getConnectedDevices().size()); + for (BluetoothDevice btDev : Config.mBtHidDevice.getConnectedDevices()) { + // 发送 HID 报文 + Config.mBtHidDevice.sendReport(btDev, 1, params); + } + + } +} \ No newline at end of file diff --git a/android/app/src/main/java/co/steamcloud/game/MainActivity.java b/android/app/src/main/java/co/steamcloud/game/MainActivity.java index e28f6b5..80ef7c1 100644 --- a/android/app/src/main/java/co/steamcloud/game/MainActivity.java +++ b/android/app/src/main/java/co/steamcloud/game/MainActivity.java @@ -1,18 +1,29 @@ package co.steamcloud.game; +import android.Manifest; import android.annotation.SuppressLint; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHidDevice; +import android.bluetooth.BluetoothHidDeviceAppQosSettings; +import android.bluetooth.BluetoothHidDeviceAppSdpSettings; +import android.bluetooth.BluetoothProfile; +import android.content.BroadcastReceiver; +import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.os.PersistableBundle; import android.text.TextUtils; import android.util.Log; -import android.view.KeyEvent; -import android.view.MotionEvent; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.core.app.ActivityCompat; import com.alipay.sdk.app.PayTask; import com.tencent.mm.opensdk.modelpay.PayReq; @@ -25,11 +36,16 @@ import org.json.JSONObject; import org.simple.eventbus.EventBus; import org.simple.eventbus.Subscriber; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executors; import co.steamcloud.game.pay.PayResult; import co.steamcloud.game.utils.AppUtil; +import co.steamcloud.game.utils.EventBusParams; import io.flutter.embedding.android.FlutterActivity; import io.flutter.embedding.engine.FlutterEngine; import io.flutter.plugin.common.MethodCall; @@ -39,40 +55,83 @@ import io.flutter.plugin.common.StandardMethodCodec; public class MainActivity extends FlutterActivity { private static final String TAG = "MainActivity"; private static final String CHANNEL = "samples.flutter.dev/battery"; - private MethodChannel nativeChannel; - private final int SDK_PAY_FLAG = 1; + private boolean setBtState = false; + + private static final int REQUEST_ENABLE_BT = 99; + + private final BluetoothAdapter mBtAdapter = BluetoothAdapter.getDefaultAdapter(); + + + + private BluetoothHidDeviceAppQosSettings mBluetoothHidDeviceAppQosSettings; + + private BluetoothDevice mBtDevice; + + private final ArrayList mDevices = new ArrayList<>();//蓝牙设备列表 + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); EventBus.getDefault().register(this); WhaleCloud.getInstance().isShowLog(true); + + IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); + registerReceiver(mBluetoothReceiver, filter); + } -// @Override -// public boolean dispatchGenericMotionEvent(MotionEvent ev) { -// return super.dispatchGenericMotionEvent(ev); -// -// } + // BroadcastReceiver实现 + private final BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { + final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); + switch (state) { + case BluetoothAdapter.STATE_OFF: + // 蓝牙已关闭 + Log.d(TAG, "onReceive: 蓝牙已关闭"); + Map map = new HashMap<>(); + map.put("isBtOpen", false); + nativeChannel.invokeMethod("isBtOpen", map); + break; + case BluetoothAdapter.STATE_TURNING_OFF: + // 蓝牙正在关闭 + Log.d(TAG, "onReceive: 蓝牙正在关闭"); -// @Override -// public boolean dispatchKeyEvent(KeyEvent event) { -// //Log.d(TAG, "dispatchKeyEvent1: event==" + event); -// if (event.getAction() == KeyEvent.ACTION_DOWN) { -// // 处理按键按下事件 -// int keyCode = event.getKeyCode(); -// // 根据keyCode进行相应处理 -// Log.d(TAG, "dispatchKeyEvent: keyCode==" + keyCode); -// } -// return super.dispatchKeyEvent(event); -// } + break; + case BluetoothAdapter.STATE_ON: + // 蓝牙已打开 + Log.d(TAG, "onReceive: 蓝牙已打开"); + Map BtMap = new HashMap<>(); + BtMap.put("isBtOpen", true); + nativeChannel.invokeMethod("isBtOpen", BtMap); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + btListDevices(); + } + break; + case BluetoothAdapter.STATE_TURNING_ON: + // 蓝牙正在打开 + Log.d(TAG, "onReceive: 蓝牙正在打开"); + break; + } + } + } + }; @Override protected void onDestroy() { EventBus.getDefault().unregister(this); + if (Config.mBtHidDevice != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + btConnect(null); // disconnect + } + } super.onDestroy(); } @@ -87,6 +146,8 @@ public class MainActivity extends FlutterActivity { exitGameMap.put("exitGame", "exitGame"); nativeChannel.invokeMethod("exitGame", exitGameMap); break; + + //微信支付回调 case "wxPaySuccess": Map map = new HashMap<>(); map.put("wxPaySuccess", "wxPaySuccess"); @@ -98,11 +159,22 @@ public class MainActivity extends FlutterActivity { mapError.put("payError", "payError"); nativeChannel.invokeMethod("payError", mapError); break; + + case "SendRequest": + byte[] params = TagMap.get("params").getBytes(); + Log.d(TAG, "Ev: SendRequest"); + + break; } } } + /** + * flutter to 原生 传递数据 + * + * @param flutterEngine The Flutter engine. + */ @Override public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { super.configureFlutterEngine(flutterEngine); @@ -112,7 +184,7 @@ public class MainActivity extends FlutterActivity { @Override public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { switch (call.method) { - case "initData": + case "initData": //初始化数据 Log.d(TAG, "onMethodCall: initData"); String gameToken = call.argument("gameToken"); Config.BsUrl = call.argument("BsUrl"); @@ -124,67 +196,266 @@ public class MainActivity extends FlutterActivity { Config.url = call.argument("Url"); initSdk(Config.BsUrl, Config.client_sid, gameToken, Config.sn); - Log.d(TAG, "onMethodCall: initData"); - Log.d(TAG, "onMethodCall: gameToken==" + gameToken); - Log.d(TAG, "onMethodCall: Config.client_sid==" + Config.client_sid); - Log.d(TAG, "onMethodCall: Config.BsUrl==" + Config.BsUrl); break; - case "playGame": + + case "setBt"://开启/关闭蓝牙 + setBtState = Boolean.TRUE.equals(call.argument("setBtState")); + Log.d(TAG, "onMethodCall: setBtState==" + setBtState); + if (setBtState) { + Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); + } else { + if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { + return; + } + mBtAdapter.disable(); + } + break; + + case "playGame": //开始游戏 Log.d("TAG", "onMethodCall: 66666666666"); Config.gameId = call.argument("gameId"); String playGameData = call.argument("playGameData"); String isReconPlay = call.argument("isReconPlay"); - - Log.d("TAG", "onMethodCall: gameId==" + Config.gameId); - Log.d("TAG", "onMethodCall: playGameData==" + playGameData); - Log.d("TAG", "onMethodCall: isReconPlay==" + isReconPlay); -// Config.gamePara.game_key = gameId; -// Config.gamePara.record_game_time = 5; -// Config.gamePara.start_resolution = "720p"; - -// initToken(); startGame(playGameData, isReconPlay); break; - case "getInfo": + case "getInfo": //获取设备信息 Map map = new HashMap<>(); Config.sn = AppUtil.getDeviceId(App.getInstance()); Config.Language = AppUtil.getSystemLanguage(); map.put("deviceID", Config.sn); map.put("Language", Config.Language); - result.success(map); - Log.d(TAG, "onMethodCall: getInfo"); + //蓝牙是否开启 + if (mBtAdapter.isEnabled()) { + map.put("isBtOpen", true); + } else { + map.put("isBtOpen", false); + } + result.success(map); break; case "WxPay"://微信支付 String orderInfoWx = call.argument("orderInfoWx"); - Log.d("TAG", "onMethodCall: orderInfoWx===" + orderInfoWx); - WxPay(orderInfoWx); - - break; case "Alipay"://支付宝支付 - - Log.d("TAG", "onMethodCall: Alipay"); - String orderInfoZfb = call.argument("orderInfoZfb"); Alipay(orderInfoZfb); - break; - case "test1": - Log.d("TAG1", "onMethodCall: 66666666666"); + case "getBtListDevices"://获取蓝牙设备 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + btListDevices(); + } + break; + + case "connectedDevice"://连接设备 + int deviceIndex = call.argument("deviceIndex"); + BluetoothDevice dev = mDevices.get(deviceIndex); + Log.d(TAG, "onItemSelected(): " + dev + " " + deviceIndex + " "); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + btConnect(dev); + } + break; + + case "enterGamePad"://进入蓝牙手柄界面 + Intent intent = new Intent(MainActivity.this, HandleActivity.class); + startActivity(intent); break; } } }); } + //设置蓝牙从设备 + public void getProxy() { + mBtAdapter.getProfileProxy(App.getInstance(), new BluetoothProfile.ServiceListener() { + @Override + @SuppressLint({"NewApi", "MissingPermission"}) + public void onServiceConnected(int profile, BluetoothProfile proxy) { + if (profile == BluetoothProfile.HID_DEVICE) { + Log.d(TAG, "Got HID device"); + Config.mBtHidDevice = (BluetoothHidDevice) proxy; + mBluetoothHidDeviceAppQosSettings = new BluetoothHidDeviceAppQosSettings(1, 800, 9, 0, 11250, -1); + BluetoothHidDeviceAppSdpSettings sdp = new BluetoothHidDeviceAppSdpSettings( + "虚拟蓝牙手柄", + "Android BLE HID Keyboard", + "Android", + (byte) 0x00, + AppUtil.gamePadDescriptor); + Config.mBtHidDevice.registerApp(sdp, null, mBluetoothHidDeviceAppQosSettings, + Executors.newSingleThreadExecutor(), new BluetoothHidDevice.Callback() { + @Override + public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) { + Log.v(TAG, "onGetReport: device=" + device + " type=" + type + + " id=" + id + " bufferSize=" + bufferSize); + } + + @Override + public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) { +// Log.v(TAG, "onSetReport: device=" + device + " type=" + type +// + " id=" + id + " data=" + data); + // 解析输出报告数据 + if (data.length >= 2) { + int leftMotorStrength = data[0] & 0xFF; + int rightMotorStrength = data[1] & 0xFF; +// handleVibration(leftMotorStrength, rightMotorStrength); + } + } + + @Override + public void onConnectionStateChanged(BluetoothDevice device, final int state) { + Log.v(TAG, "onConnectionStateChanged: device=" + device + " state=" + state); + if (device.equals(mBtDevice)) { + Log.d(TAG, "onConnectionStateChanged: state==" + state); + // 0 断开的 + // 1 连接中 + // 2 已连接 + // 3 正在断开连接… + //发送连接状态 + runOnUiThread(new Runnable() { + @Override + public void run() { + Map map = new HashMap<>(); + map.put("connectionStatus", state); + nativeChannel.invokeMethod("connectionStatus", map); + } + }); + + } + if (state == 2) { + Log.d(TAG, "onConnectionStateChanged:32132132132132===》 重新new对象"); +// gamepad.setCallback((b) -> { +// Log.d(TAG, "onConnectionStateChanged:32132132132132===》 " + b[0]); +// }); + } + } + }); + } + } + + @Override + public void onServiceDisconnected(int profile) { + if (profile == BluetoothProfile.HID_DEVICE) { + Log.d(TAG, "Lost HID device"); + } + } + }, BluetoothProfile.HID_DEVICE); + } + + //获取蓝牙设备 + @RequiresApi(api = Build.VERSION_CODES.P) + private void btListDevices() { + getProxy(); // 需要先启用蓝牙 + + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { + return; + } + Set pairedDevices = mBtAdapter.getBondedDevices(); + + // 将设备添加到适配器 + List names = new ArrayList<>(); + + for (BluetoothDevice btDev : pairedDevices) { + names.add(btDev.getName()); + mDevices.add(btDev); + Log.d(TAG, "btListDevices: btDev==" + btDev.getName()); + Log.d(TAG, "btListDevices: btDev==" + btDev.getAddress()); + Log.d(TAG, "btListDevices: btDev,getUuids==" + btDev.getUuids()); + } + + Map map = new HashMap<>(); + map.put("btDevices", names); + nativeChannel.invokeMethod("btDevices", map); + + } + + + //连接蓝牙设备 + @RequiresApi(api = Build.VERSION_CODES.P) + private void btConnect(BluetoothDevice device) { + Log.i(TAG, "btConnect: device=" + device); + Log.i(TAG, "btConnect: mBtHidDevice=" + Config.mBtHidDevice); + // disconnect from everything else + if (Config.mBtHidDevice != null) { + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { + return; + } + for (BluetoothDevice btDev : Config.mBtHidDevice.getDevicesMatchingConnectionStates(new int[]{ + // BluetoothProfile.STATE_CONNECTING, + BluetoothProfile.STATE_CONNECTED, + })) { + Config.mBtHidDevice.disconnect(btDev); + Log.i(TAG, "btConnect: disconnect"); + } + } + + if (device != null) { + mBtDevice = device; + Config.mBtHidDevice.connect(device); + } + } + + + /** + * 初始化游戏SDK + * + * @param bsUrl bsUrl + * @param channelId channelId + * @param token token + * @param sn 设备号 + */ + void initSdk(final String bsUrl, final String channelId, final String token, final String sn) { + WhaleCloud.getInstance().sdkLoading(getApplication(), channelId, bsUrl, token, sn, new WhaleCloud.OnSdkListener() { + @Override + public void onSdkFail(final int errCode, final String msg) { + runOnUiThread(new Runnable() { + @Override + public void run() { + Log.w(TAG, "鲸云 SDK 初始化失败|" + errCode + "|" + msg); + Map map = new HashMap<>(); + map.put("SDKSuccess", false); + nativeChannel.invokeMethod("SDKSuccess", map); + } + }); + } + + @Override + public void onSdkSucc() { + runOnUiThread(new Runnable() { + @Override + public void run() { + Log.w(TAG, "鲸云 SDK 初始化成功"); + Map map = new HashMap<>(); + map.put("SDKSuccess", true); + nativeChannel.invokeMethod("SDKSuccess", map); + } + }); + } + }); + } + + /** + * 启动游戏 + * + * @param gameData 游戏启动数据 + * @param isReconPlay 是否是重连 + */ + public void startGame(String gameData, String isReconPlay) { + String GameType = ""; + getIntent().putExtra("GameType", ""); + Config.is_Playing = true; + Intent intent = new Intent(this, PlayGameActivity.class); + intent.putExtra("GameData", gameData); + intent.putExtra("isReconPlay", isReconPlay); + startActivity(intent); + } + /** * 支付宝 支付结果回调 @@ -226,55 +497,6 @@ public class MainActivity extends FlutterActivity { }; - /** - * 初始化游戏SDK - * - * @param bsUrl bsUrl - * @param channelId channelId - * @param token token - * @param sn 设备号 - */ - void initSdk(final String bsUrl, final String channelId, final String token, final String sn) { - WhaleCloud.getInstance().sdkLoading(getApplication(), channelId, bsUrl, token, sn, new WhaleCloud.OnSdkListener() { - @Override - public void onSdkFail(final int errCode, final String msg) { - runOnUiThread(new Runnable() { - @Override - public void run() { - Log.w(TAG, "鲸云 SDK 初始化失败|" + errCode + "|" + msg); - Map map = new HashMap<>(); - map.put("SDKSuccess", false); - nativeChannel.invokeMethod("SDKSuccess", map); - } - }); - } - - @Override - public void onSdkSucc() { - runOnUiThread(new Runnable() { - @Override - public void run() { - Log.w(TAG, "鲸云 SDK 初始化成功"); - Map map = new HashMap<>(); - map.put("SDKSuccess", true); - nativeChannel.invokeMethod("SDKSuccess", map); - } - }); - } - }); - } - - public void startGame(String gameData, String isReconPlay) { - String GameType = ""; - getIntent().putExtra("GameType", ""); - Config.is_Playing = true; - Intent intent = new Intent(this, PlayGameActivity.class); - intent.putExtra("GameData", gameData); - intent.putExtra("isReconPlay", isReconPlay); - startActivity(intent); - } - - /** * 微信支付 * @@ -325,7 +547,6 @@ public class MainActivity extends FlutterActivity { msg.obj = result; mHandler.sendMessage(msg); }; - // 必须异步调用 Thread payThread = new Thread(payRunnable); payThread.start(); diff --git a/android/app/src/main/java/co/steamcloud/game/PlayGameActivity.java b/android/app/src/main/java/co/steamcloud/game/PlayGameActivity.java index e9aee9f..e5b6679 100644 --- a/android/app/src/main/java/co/steamcloud/game/PlayGameActivity.java +++ b/android/app/src/main/java/co/steamcloud/game/PlayGameActivity.java @@ -73,11 +73,23 @@ import java.util.Timer; import java.util.TimerTask; import co.steamcloud.game.HttpUtils.OpenApiRequest; +import co.steamcloud.game.customize.GameFrameLayOut; +import co.steamcloud.game.customize.JoystickView2; +import co.steamcloud.game.customize.KeyButton; +import co.steamcloud.game.customize.KeyboardUtil; +import co.steamcloud.game.customize.MoveButton; +import co.steamcloud.game.customize.MyButton; import co.steamcloud.game.entity.VirtualKeyListBean; import co.steamcloud.game.glide.GlideImageLoader; import co.steamcloud.game.time.SubscribeTimeManage; +import co.steamcloud.game.utils.ActivityCollector; import co.steamcloud.game.utils.AppConfigFileImpl; import co.steamcloud.game.utils.AppUtil; +import co.steamcloud.game.utils.CountDownTimerUtil; +import co.steamcloud.game.utils.EventBusParams; +import co.steamcloud.game.utils.GsonJsonUtil; +import co.steamcloud.game.utils.PeterTimeCountRefresh; +import co.steamcloud.game.utils.RoundCalculator; public class PlayGameActivity extends Activity { public static final String TAG = "PlayGameActivity"; diff --git a/android/app/src/main/java/co/steamcloud/game/GameFrameLayOut.java b/android/app/src/main/java/co/steamcloud/game/customize/GameFrameLayOut.java similarity index 75% rename from android/app/src/main/java/co/steamcloud/game/GameFrameLayOut.java rename to android/app/src/main/java/co/steamcloud/game/customize/GameFrameLayOut.java index 7856c74..676715a 100644 --- a/android/app/src/main/java/co/steamcloud/game/GameFrameLayOut.java +++ b/android/app/src/main/java/co/steamcloud/game/customize/GameFrameLayOut.java @@ -1,33 +1,34 @@ -package co.steamcloud.game; +package co.steamcloud.game.customize; import android.content.Context; import android.util.AttributeSet; import android.widget.FrameLayout; -public class GameFrameLayOut extends FrameLayout { +public class GameFrameLayOut extends FrameLayout { private String TAG = "GameFrameLayOut"; int MAX_WIDTH = 1; int MAX_HEIGHT = 1; int SCREEN_WIDTH = 1920; int SCREEN_HEIGHT = 1080; - public void setScreenSize(int width,int height){ + public void setScreenSize(int width, int height) { SCREEN_WIDTH = width; SCREEN_HEIGHT = height; } + public GameFrameLayOut(Context context) { - super((Context)context); + super((Context) context); } public GameFrameLayOut(Context context, AttributeSet attrs) { - super((Context)context, attrs); + super((Context) context, attrs); } public GameFrameLayOut(Context context, AttributeSet attrs, int defStyleAttr) { - super((Context)context, attrs, defStyleAttr); + super((Context) context, attrs, defStyleAttr); } @@ -37,6 +38,7 @@ public class GameFrameLayOut extends FrameLayout { super.onLayout(changed, left, top, right, bottom); } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); diff --git a/android/app/src/main/java/co/steamcloud/game/JoystickView2.java b/android/app/src/main/java/co/steamcloud/game/customize/JoystickView2.java similarity index 73% rename from android/app/src/main/java/co/steamcloud/game/JoystickView2.java rename to android/app/src/main/java/co/steamcloud/game/customize/JoystickView2.java index 165fe79..97da21b 100644 --- a/android/app/src/main/java/co/steamcloud/game/JoystickView2.java +++ b/android/app/src/main/java/co/steamcloud/game/customize/JoystickView2.java @@ -1,4 +1,4 @@ -package co.steamcloud.game; +package co.steamcloud.game.customize; import android.content.Context; import android.graphics.Bitmap; @@ -13,13 +13,17 @@ import android.view.View; import androidx.annotation.Nullable; +import co.steamcloud.game.Config; +import co.steamcloud.game.R; +import co.steamcloud.game.utils.RoundCalculator; + public class JoystickView2 extends View { - public float currentX ; - public float currentY ; - public float initX ; - public float initY ; - public float currentX2 ; - public float currentY2 ; + public float currentX; + public float currentY; + public float initX; + public float initY; + public float currentX2; + public float currentY2; float lastX; float lastY; float lastVibX; @@ -29,13 +33,14 @@ public class JoystickView2 extends View { private float viewSizeH; private float vibratorRanger; public int pointSize; - private float maxRanger=150; + private float maxRanger = 150; public float maxRanger2 = 150; public Context context; public Bitmap map; private Bitmap mDirectionBmp; public static Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); public OnJoystickListener mListener; + public JoystickView2(Context context) { super(context); this.context = context; @@ -50,11 +55,12 @@ public class JoystickView2 extends View { super(context, attrs, defStyleAttr); this.context = context; } + public Bitmap zoomImg(Bitmap bm, int newWidth, int newHeight) { int width = bm.getWidth(); int height = bm.getHeight(); - float scaleWidth = (float)newWidth / (float)width; - float scaleHeight = (float)newHeight / (float)height; + float scaleWidth = (float) newWidth / (float) width; + float scaleHeight = (float) newHeight / (float) height; Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true); @@ -67,23 +73,22 @@ public class JoystickView2 extends View { this.viewSize = this.getMeasuredWidth(); int var10000 = this.viewSize; this.pointSize = var10000 / 3; - viewSizeW=this.getMeasuredWidth(); - viewSizeH=this.getMeasuredHeight(); - vibratorRanger=viewSizeH/6; - if (maxRanger>viewSizeH/4) - { - maxRanger=viewSizeH/4; + viewSizeW = this.getMeasuredWidth(); + viewSizeH = this.getMeasuredHeight(); + vibratorRanger = viewSizeH / 6; + if (maxRanger > viewSizeH / 4) { + maxRanger = viewSizeH / 4; } - if (maxRanger2>viewSizeH/3) - { - maxRanger2=viewSizeH/3; + if (maxRanger2 > viewSizeH / 3) { + maxRanger2 = viewSizeH / 3; } this.init(); } + public void init() { - currentX = currentX2=initX=lastX=viewSizeW/2; - currentY= currentY2 =initY=lastY=viewSizeH/2; + currentX = currentX2 = initX = lastX = viewSizeW / 2; + currentY = currentY2 = initY = lastY = viewSizeH / 2; int var1 = this.pointSize; Bitmap var10000 = BitmapFactory.decodeResource(this.context.getResources(), R.mipmap.joystick_round); Bitmap mDirectionBmp1 = BitmapFactory.decodeResource(this.context.getResources(), R.mipmap.joystick_down); @@ -93,7 +98,7 @@ public class JoystickView2 extends View { } @Override - protected void onDraw(Canvas canvas){ + protected void onDraw(Canvas canvas) { super.onDraw(canvas); paint.setDither(true); canvas.drawBitmap(this.map, currentX2 - this.pointSize / 2, currentY2 - this.pointSize / 2, paint); @@ -106,7 +111,7 @@ public class JoystickView2 extends View { int offsetY = mDirectionBmp.getHeight() / 2; matrix.postTranslate(-offsetX, -offsetY); matrix.postRotate(270 - rotationDegree); - matrix.postTranslate(initX - mDirectionBmp.getWidth()/2 + offsetX, initY - mDirectionBmp.getHeight()/2 + offsetY); + matrix.postTranslate(initX - mDirectionBmp.getWidth() / 2 + offsetX, initY - mDirectionBmp.getHeight() / 2 + offsetY); canvas.drawBitmap(mDirectionBmp, matrix, null); } @@ -115,12 +120,13 @@ public class JoystickView2 extends View { public void setOnJoystickListener(OnJoystickListener listener) { this.mListener = listener; } + @Override public boolean onTouchEvent(MotionEvent event) { - if(Config.s_keyboard){ + if (Config.s_keyboard) { return false; } - if (event.getAction()==MotionEvent.ACTION_DOWN||event.getAction()==MotionEvent.ACTION_MOVE){ + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { /*if (event.getAction()==MotionEvent.ACTION_DOWN) { initX2 = event.getX(); @@ -133,19 +139,17 @@ public class JoystickView2 extends View { this.currentY2 = event.getY(); float tr = (float) RoundCalculator.calTwoPointDistant(initX, initY, event.getX(), event.getY()); - if (tr>maxRanger) - { + if (tr > maxRanger) { float dotCenterOnShow[] = RoundCalculator.calPointLocationByAngle( initX, initY, event.getX(), event.getY(), maxRanger); this.currentX = dotCenterOnShow[0]; this.currentY = dotCenterOnShow[1]; - Log.e("currentXY1","...x="+currentX2+",y="+currentY2+",maxRanger2="+maxRanger2); + Log.e("currentXY1", "...x=" + currentX2 + ",y=" + currentY2 + ",maxRanger2=" + maxRanger2); } float tr2 = (float) RoundCalculator.calTwoPointDistant(initX, initY, event.getX(), event.getY()); - if (tr2>maxRanger2) - { + if (tr2 > maxRanger2) { float dotCenterOnShow[] = RoundCalculator.calPointLocationByAngle( initX, initY, event.getX(), event.getY(), maxRanger2); this.currentX2 = dotCenterOnShow[0]; @@ -153,28 +157,27 @@ public class JoystickView2 extends View { } - }else { - this.currentX =initX; - this.currentY =initY; + } else { + this.currentX = initX; + this.currentY = initY; this.currentX2 = initX; this.currentY2 = initY; } - - if (mListener!=null){ + if (mListener != null) { //if (Math.abs(currentX-lastX)>3||Math.abs(currentY-lastY)>3){ - mListener.onPosition((currentX-initX)/(float)maxRanger,(currentY-initY)/(float)maxRanger); + mListener.onPosition((currentX - initX) / (float) maxRanger, (currentY - initY) / (float) maxRanger); - lastX=currentX; - lastY=currentY; + lastX = currentX; + lastY = currentY; // } - if (Math.abs(currentX-lastVibX)>vibratorRanger||Math.abs(currentY-lastVibY)>vibratorRanger){//用来震动 + if (Math.abs(currentX - lastVibX) > vibratorRanger || Math.abs(currentY - lastVibY) > vibratorRanger) {//用来震动 this.mListener.onVibrator(); - lastVibX=currentX; - lastVibY=currentY; + lastVibX = currentX; + lastVibY = currentY; } } diff --git a/android/app/src/main/java/co/steamcloud/game/KeyButton.java b/android/app/src/main/java/co/steamcloud/game/customize/KeyButton.java similarity index 87% rename from android/app/src/main/java/co/steamcloud/game/KeyButton.java rename to android/app/src/main/java/co/steamcloud/game/customize/KeyButton.java index 1753c91..08d9e00 100644 --- a/android/app/src/main/java/co/steamcloud/game/KeyButton.java +++ b/android/app/src/main/java/co/steamcloud/game/customize/KeyButton.java @@ -1,4 +1,4 @@ -package co.steamcloud.game; +package co.steamcloud.game.customize; import android.content.Context; import android.util.AttributeSet; @@ -8,6 +8,8 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import co.steamcloud.game.Config; + public class KeyButton extends androidx.appcompat.widget.AppCompatTextView { @@ -59,9 +61,10 @@ public class KeyButton extends androidx.appcompat.widget.AppCompatTextView { public float touchInitX; public float touchInitY; boolean isMove = false; + @Override public boolean onTouchEvent(MotionEvent event) { - Config.keyEvent_time=0; + Config.keyEvent_time = 0; /* if(!Config.s_keyboard){ return super.onTouchEvent(event); }*/ @@ -77,24 +80,22 @@ public class KeyButton extends androidx.appcompat.widget.AppCompatTextView { isMove = false; - if (mListener!=null){ + if (mListener != null) { mListener.onActionDown(event); } - - break; case MotionEvent.ACTION_MOVE: - if(Config.s_keyboard){ + if (Config.s_keyboard) { if (Math.abs(event.getX() - touchInitX) > 10 || Math.abs(event.getY() - touchInitY) > 10) { isMove = true; setX(mOriginalX + event.getRawX() - mOriginalRawX); setY(mOriginalY + event.getRawY() - mOriginalRawY); } - }else { + } else { if (Math.abs(event.getX() - touchInitX) > 10 || Math.abs(event.getY() - touchInitY) > 10) { - if (mListener!=null){ + if (mListener != null) { mListener.onActionMove(event); } /* setX(mOriginalX + event.getRawX() - mOriginalRawX); @@ -105,7 +106,7 @@ public class KeyButton extends androidx.appcompat.widget.AppCompatTextView { break; case MotionEvent.ACTION_UP: if (!isMove) { - if (mListener!=null){ + if (mListener != null) { mListener.onActionUp(); } } @@ -116,39 +117,46 @@ public class KeyButton extends androidx.appcompat.widget.AppCompatTextView { return true; } - public void setOnClickCallBackListener(OnClickCallBackListener listener){ - this.mListener=listener; + + public void setOnClickCallBackListener(OnClickCallBackListener listener) { + this.mListener = listener; } - public void keyBoardDelectListener(ViewChangMsgListener viewChangMsgListener){ - this.viewChangMsgListener =viewChangMsgListener; + public void keyBoardDelectListener(ViewChangMsgListener viewChangMsgListener) { + this.viewChangMsgListener = viewChangMsgListener; } - public interface OnClickCallBackListener{ + public interface OnClickCallBackListener { void onActionDown(MotionEvent event); + void onActionUp(); + void onActionMove(MotionEvent event); } - public void setPosition(float x,float y) { + public void setPosition(float x, float y) { this.setX(x); this.setY(y); } - public interface ViewChangMsgListener{ + public interface ViewChangMsgListener { void changTexture(String path); + void showDeletPopup(KeyButton view); + void showDeletPopup(String index); + void showFloatPopup(); } - public interface virtualHandleChangeListener{ + public interface virtualHandleChangeListener { void layerBtnSetVisible(int tag); } - public interface virtualKeyboardChangeListener - { + + public interface virtualKeyboardChangeListener { void removeChild(View child); + void hideDirection(); } diff --git a/android/app/src/main/java/co/steamcloud/game/KeyboardUtil.java b/android/app/src/main/java/co/steamcloud/game/customize/KeyboardUtil.java similarity index 99% rename from android/app/src/main/java/co/steamcloud/game/KeyboardUtil.java rename to android/app/src/main/java/co/steamcloud/game/customize/KeyboardUtil.java index 76c039e..4953f10 100644 --- a/android/app/src/main/java/co/steamcloud/game/KeyboardUtil.java +++ b/android/app/src/main/java/co/steamcloud/game/customize/KeyboardUtil.java @@ -1,4 +1,4 @@ -package co.steamcloud.game; +package co.steamcloud.game.customize; import android.app.Activity; import android.content.Context; @@ -15,6 +15,8 @@ import com.zjrx.jyengine.WhaleCloud; import java.util.List; +import co.steamcloud.game.R; + public class KeyboardUtil { private Context ctx; private Activity act; diff --git a/android/app/src/main/java/co/steamcloud/game/MoveButton.java b/android/app/src/main/java/co/steamcloud/game/customize/MoveButton.java similarity index 95% rename from android/app/src/main/java/co/steamcloud/game/MoveButton.java rename to android/app/src/main/java/co/steamcloud/game/customize/MoveButton.java index 3825e6d..6d04abe 100644 --- a/android/app/src/main/java/co/steamcloud/game/MoveButton.java +++ b/android/app/src/main/java/co/steamcloud/game/customize/MoveButton.java @@ -1,10 +1,12 @@ -package co.steamcloud.game; +package co.steamcloud.game.customize; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.RelativeLayout; +import co.steamcloud.game.Config; + public class MoveButton extends RelativeLayout { @@ -58,7 +60,7 @@ public class MoveButton extends RelativeLayout { setX(moveX); moveY = mOriginalY + event.getRawY() - mOriginalRawY; setY(mOriginalY + event.getRawY() - mOriginalRawY); - if (mListener != null){ + if (mListener != null) { mListener.onActionMove(moveX, moveY); } } diff --git a/android/app/src/main/java/co/steamcloud/game/MyButton.java b/android/app/src/main/java/co/steamcloud/game/customize/MyButton.java similarity index 84% rename from android/app/src/main/java/co/steamcloud/game/MyButton.java rename to android/app/src/main/java/co/steamcloud/game/customize/MyButton.java index fbf098c..e6194f9 100644 --- a/android/app/src/main/java/co/steamcloud/game/MyButton.java +++ b/android/app/src/main/java/co/steamcloud/game/customize/MyButton.java @@ -1,4 +1,4 @@ -package co.steamcloud.game; +package co.steamcloud.game.customize; import android.content.Context; import android.util.AttributeSet; @@ -23,6 +23,7 @@ public class MyButton extends androidx.appcompat.widget.AppCompatTextView { public MyButton(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } + private OnClickCallBackListener mListener; private ViewChangMsgListener viewChangMsgListener; @@ -43,6 +44,7 @@ public class MyButton extends androidx.appcompat.widget.AppCompatTextView { public float touchInitX; public float touchInitY; boolean isMove = false; + @Override public boolean onTouchEvent(MotionEvent event) { @@ -68,7 +70,7 @@ public class MyButton extends androidx.appcompat.widget.AppCompatTextView { break; case MotionEvent.ACTION_UP: if (!isMove) { - if (mListener!=null){ + if (mListener != null) { mListener.onActionDown(); } } @@ -79,37 +81,44 @@ public class MyButton extends androidx.appcompat.widget.AppCompatTextView { return true; } - public void setOnClickCallBackListener(OnClickCallBackListener listener){ - this.mListener=listener; + + public void setOnClickCallBackListener(OnClickCallBackListener listener) { + this.mListener = listener; } - public void keyBoardDelectListener(ViewChangMsgListener viewChangMsgListener){ - this.viewChangMsgListener =viewChangMsgListener; + public void keyBoardDelectListener(ViewChangMsgListener viewChangMsgListener) { + this.viewChangMsgListener = viewChangMsgListener; } - public interface OnClickCallBackListener{ + public interface OnClickCallBackListener { void onActionDown(); - void onActionMove(float x,float y); + + void onActionMove(float x, float y); } - public void setPosition(float x,float y) { + public void setPosition(float x, float y) { this.setX(x); this.setY(y); } - public interface ViewChangMsgListener{ + public interface ViewChangMsgListener { void changTexture(String path); + void showDeletPopup(MyButton view); + void showDeletPopup(String index); + void showFloatPopup(); } - public interface virtualHandleChangeListener{ + + public interface virtualHandleChangeListener { void layerBtnSetVisible(int tag); } - public interface virtualKeyboardChangeListener - { + + public interface virtualKeyboardChangeListener { void removeChild(View child); + void hideDirection(); } } diff --git a/android/app/src/main/java/co/steamcloud/game/ActivityCollector.java b/android/app/src/main/java/co/steamcloud/game/utils/ActivityCollector.java similarity index 95% rename from android/app/src/main/java/co/steamcloud/game/ActivityCollector.java rename to android/app/src/main/java/co/steamcloud/game/utils/ActivityCollector.java index 924af3d..0a37d7d 100644 --- a/android/app/src/main/java/co/steamcloud/game/ActivityCollector.java +++ b/android/app/src/main/java/co/steamcloud/game/utils/ActivityCollector.java @@ -1,4 +1,4 @@ -package co.steamcloud.game; +package co.steamcloud.game.utils; import android.app.Activity; diff --git a/android/app/src/main/java/co/steamcloud/game/utils/AppUtil.java b/android/app/src/main/java/co/steamcloud/game/utils/AppUtil.java index f526509..603b785 100644 --- a/android/app/src/main/java/co/steamcloud/game/utils/AppUtil.java +++ b/android/app/src/main/java/co/steamcloud/game/utils/AppUtil.java @@ -64,8 +64,75 @@ import co.steamcloud.game.App; */ public class AppUtil { + public static final byte[] gamePadDescriptor = new byte[]{ + // 游戏手柄的 HID 描述符 + 0x05, 0x01, // USAGE_PAGE (Game Controls) - 游戏控制设备 + 0x09, 0x05, // USAGE (Gamepad) - 游戏手柄 + (byte) 0xA1, 0x01, // COLLECTION (Application) - 应用集合 + (byte) 0xA1, 0x00, // COLLECTION (Physical) - 物理集合 + + // 按钮部分 + 0x05, 0x09, // USAGE_PAGE (Button) - 按钮输入 + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x10, // USAGE_MAXIMUM (Button 16) + 0x15, 0x00, // LOGICAL_MINIMUM (0) - 按钮的逻辑最小值 + 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 按钮的逻辑最大值 + 0x75, 0x01, // REPORT_SIZE (1) - 每个按钮占用 1 位 + (byte) 0x95, 0x10, // REPORT_COUNT (16) - 总共有 16 个按钮 + (byte) 0x81, 0x02, // INPUT (Data, Var, Abs) - 按钮输入,数据类型、变量、绝对值 + + // 左摇杆 + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) - 左摇杆水平轴 + 0x09, 0x31, // USAGE (Y) - 左摇杆垂直轴 + 0x15, 0x00, // LOGICAL_MINIMUM (0) - 摇杆的逻辑最小值 + 0x25, (byte) 0xFF, // LOGICAL_MAXIMUM (255) - 摇杆的逻辑最大值 + 0x75, 0x08, // REPORT_SIZE (8) + (byte) 0x95, 0x02, // REPORT_COUNT (2) + (byte) 0x81, 0x02, // INPUT (Data, Var, Abs) + +// // 右摇杆 + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) +// 0x09, 0x33, // USAGE (Rx) - 右摇杆水平轴 +// 0x09, 0x34, // USAGE (Ry) - 右摇杆垂直轴 + 0x09, 0x32, // USAGE (Z) - 右摇杆水平轴 + 0x09, 0x35, // USAGE (Rz) - 右摇杆垂直轴 + 0x15, 0x00, // LOGICAL_MINIMUM (0) - 摇杆的逻辑最小值 + 0x25, (byte) 0xFF, // LOGICAL_MAXIMUM (255) - 摇杆的逻辑最大值 + 0x75, 0x08, // REPORT_SIZE (8) + (byte) 0x95, 0x02, // REPORT_COUNT (2) + (byte) 0x81, 0x02, // INPUT (Data, Var, Abs) + + // 方向键(HAT switch) + 0x09, 0x39, // USAGE (Hat switch) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x07, // LOGICAL_MAXIMUM (7) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0x3B, 0x01, // PHYSICAL_MAXIMUM (315) + 0x65, 0x14, // UNIT (Eng Rot: Angular Pos) + 0x75, 0x04, // REPORT_SIZE (4) + (byte) 0x95, 0x01, // REPORT_COUNT (1) + (byte) 0x81, 0x42, // INPUT (Data, Var, Abs, Null) + + // 触发器(L2 和 R2) + 0x75, 0x04, // REPORT_SIZE (4) - 触发器占用 4 位 + (byte) 0x95, 0x01, // REPORT_COUNT (1) - 只有 1 个触发器 + (byte) 0x81, 0x01, // INPUT (Cnst, Ary, Abs) - 触发器输入,常量、数组、绝对值 + + // 震动输出报告 + 0x09, 0x70, // USAGE (Vibration) - 震动 + 0x15, 0x00, // LOGICAL_MINIMUM (0) - 震动强度的逻辑最小值 + 0x26, (byte) 0xFF, 0x00, // LOGICAL_MAXIMUM (255) - 震动强度的逻辑最大值 + 0x75, 0x08, // REPORT_SIZE (8) - 每个震动强度占用 8 位 + (byte) 0x95, 0x02, // REPORT_COUNT (2) - 左、右震动马达各 1 个字节 + (byte) 0x91, 0x02, // OUTPUT (Data, Var, Abs) - 震动输出,数据类型、变量、绝对值 + + // 结束集合 + (byte) 0xC0, // END_COLLECTION (Physical) - 结束物理集合 + (byte) 0xC0 // END_COLLECTION (Application) - 结束应用集合 + }; + /** - * * @param content 字符串内容 * @param width 二维码宽度 * @param height 二维码高度 @@ -79,8 +146,8 @@ public class AppUtil { * @return */ public static Bitmap createQRCodeBitmap(String content, int width, int height, String character_set, - String error_correction_level,String margin, int color_black, - int color_white,Bitmap logoBitmap, float logoPercent) { + String error_correction_level, String margin, int color_black, + int color_white, Bitmap logoBitmap, float logoPercent) { // 字符串内容判空 if (TextUtils.isEmpty(content)) { return null; @@ -125,7 +192,7 @@ public class AppUtil { bitmap.setPixels(pixels, 0, width, 0, 0, width, height); /** 5.为二维码添加logo图标 */ - if(logoBitmap != null){ + if (logoBitmap != null) { return addLogo(bitmap, logoBitmap, logoPercent); } return bitmap; diff --git a/android/app/src/main/java/co/steamcloud/game/CountDownTimerUtil.java b/android/app/src/main/java/co/steamcloud/game/utils/CountDownTimerUtil.java similarity index 98% rename from android/app/src/main/java/co/steamcloud/game/CountDownTimerUtil.java rename to android/app/src/main/java/co/steamcloud/game/utils/CountDownTimerUtil.java index f8805cc..5ddeba7 100644 --- a/android/app/src/main/java/co/steamcloud/game/CountDownTimerUtil.java +++ b/android/app/src/main/java/co/steamcloud/game/utils/CountDownTimerUtil.java @@ -1,4 +1,4 @@ -package co.steamcloud.game; +package co.steamcloud.game.utils; import android.os.CountDownTimer; import android.view.View; diff --git a/android/app/src/main/java/co/steamcloud/game/EventBusParams.java b/android/app/src/main/java/co/steamcloud/game/utils/EventBusParams.java similarity index 87% rename from android/app/src/main/java/co/steamcloud/game/EventBusParams.java rename to android/app/src/main/java/co/steamcloud/game/utils/EventBusParams.java index 19a6a6c..aa25fae 100644 --- a/android/app/src/main/java/co/steamcloud/game/EventBusParams.java +++ b/android/app/src/main/java/co/steamcloud/game/utils/EventBusParams.java @@ -1,4 +1,4 @@ -package co.steamcloud.game; +package co.steamcloud.game.utils; /** * diff --git a/android/app/src/main/java/co/steamcloud/game/utils/GamePad.java b/android/app/src/main/java/co/steamcloud/game/utils/GamePad.java new file mode 100644 index 0000000..2e882ba --- /dev/null +++ b/android/app/src/main/java/co/steamcloud/game/utils/GamePad.java @@ -0,0 +1,245 @@ +package co.steamcloud.game.utils; + +import android.util.Log; + +/** + * + */ +public class GamePad { + + private GamepadAction gamepadAction; + + public GamePad(GamepadAction action) { + this.gamepadAction = action; + } + + public void setCallback(GamepadAction callback) { + this.gamepadAction = callback; + } + + private final String TAG = "Gamepad"; + /** + * 按钮A + */ + public GamepadButton BUTTON_A = new GamepadButton("BUTTON_A"); + + /** + * 按钮B + */ + public GamepadButton BUTTON_B = new GamepadButton("BUTTON_B"); + + /** + * 按钮X + */ + public GamepadButton BUTTON_X = new GamepadButton("BUTTON_X"); + + /** + * 按钮Y + */ + public GamepadButton BUTTON_Y = new GamepadButton("BUTTON_Y"); + + /** + * 按钮L1 + */ + public GamepadButton BUTTON_L1 = new GamepadButton("BUTTON_L1"); + + /** + * 按钮R1 + */ + public GamepadButton BUTTON_R1 = new GamepadButton("BUTTON_R1"); + + /** + * 按钮L2 + */ + public GamepadButton BUTTON_L2 = new GamepadButton("BUTTON_L2"); + + /** + * 按钮R2 + */ + public GamepadButton BUTTON_R2 = new GamepadButton("BUTTON_R2"); + + /** + * 按钮Start + */ + public GamepadButton BUTTON_START = new GamepadButton("BUTTON_START"); + + /** + * 按钮Select + */ + public GamepadButton BUTTON_SELECT = new GamepadButton("BUTTON_SELECT"); + + /** + * 按钮L3 + */ + public GamepadButton BUTTON_L3 = new GamepadButton("BUTTON_L3"); + + /** + * 按钮R3 + */ + public GamepadButton BUTTON_R3 = new GamepadButton("BUTTON_R3"); + + /** + * 按钮DPad Up + */ + public GamepadButton BUTTON_DPAD_UP = new GamepadButton("BUTTON_DPAD_UP"); + + /** + * 按钮DPad Down + */ + public GamepadButton BUTTON_DPAD_DOWN = new GamepadButton("BUTTON_DPAD_DOWN"); + + /** + * 按钮DPad Left + */ + public GamepadButton BUTTON_DPAD_LEFT = new GamepadButton("BUTTON_DPAD_LEFT"); + + /** + * 按钮DPad Right + */ + public GamepadButton BUTTON_DPAD_RIGHT = new GamepadButton("BUTTON_DPAD_RIGHT"); + + public GamepadButton Placeholder = new GamepadButton(""); + + /** + * 第一位请求数据 + */ + + public boolean KeyDown(GamepadButton btn) { + Log.d(TAG, "KeyDown——old: " + btn.Name + "===<>>>" + btn.getStatus()); + btn.setStatus(true); + Log.d(TAG, "KeyDown: " + btn.Name + "===<>>>" + btn.getStatus()); + GenerateParams(); + return true; + } + + public boolean KeyUp(GamepadButton btn) { + Log.d(TAG, "KeyDown——-up-old: " + btn.Name + "===<>>>" + btn.getStatus()); + btn.setStatus(false); + Log.d(TAG, "KeyDown——-up: " + btn.Name + "===<>>>" + btn.getStatus()); + GenerateParams(); + return true; + } + + private byte report3 = 0x00; + private byte report4 = 0x00; + + private byte report5 = 0x00; + private byte report6 = 0x00; + + /** + * 设置坐标 + * + * @param x + * @param y + */ + public void SetLeftRemoteSensing(float x, float y) { + report3 = (byte) mapToJoystick(x); + report4 = (byte) mapToJoystick(y); +// Log.d(TAG, "SetLeftRemoteSensing: report3===>"+report3+"====>report4"+report4); + GenerateParams(); + } + + public void SetRightRemoteSensing(float x, float y) { + report5 = (byte) mapToJoystick(x); + report6 = (byte) mapToJoystick(y); + Log.d(TAG, "SetLeftRemoteSensing: report5===>" + report5 + "====>report6" + report6); + GenerateParams(); + } + + /** + * 将数组转换为二进制字符串 + * + * @param boolArray + * @return + */ + public String booleanArrayToBinaryString(GamepadButton[] boolArray) { + if (boolArray == null || boolArray.length != 8) { + throw new IllegalArgumentException("数组必须是8位长度的boolean数组"); + } + + StringBuilder sb = new StringBuilder(); + for (GamepadButton b : boolArray) { +// sb.append(b.getStatus() ? "1" : "0"); + sb.insert(0, b.getStatus() ? "1" : "0"); + } + + return sb.toString(); + } + + public GamepadButton[] report1GamepadButton = {BUTTON_A, BUTTON_B, Placeholder, BUTTON_X, BUTTON_Y, Placeholder, BUTTON_L1, BUTTON_R1}; + public GamepadButton[] report2GamepadButton = {BUTTON_L2, BUTTON_R2, BUTTON_SELECT, BUTTON_START, Placeholder, BUTTON_L3, BUTTON_R3, Placeholder}; + + /** + * 生产请求字节 + * + * @param boolArray + * @return + */ + public byte GetGenerateParams(GamepadButton[] boolArray) { + String binaryString = booleanArrayToBinaryString(boolArray); + // 将二进制字符串转换为整数 + int intValue = Integer.parseInt(binaryString, 2); // 第二个参数是基数(2表示二进制) + // 将整数转换为byte + byte byteValue = (byte) intValue; + return byteValue; + } + + public int mapToJoystick(float value) { + // 保证值在 [-1, 1] 范围内 + value = Math.max(-1, Math.min(1, value)); + return (int) ((value + 1) * 127.5); + } + + private byte dpadState = 0x08; // 默认中立状态 + + public void SetDpadState() { + if (BUTTON_DPAD_UP.getStatus()) { + if (BUTTON_DPAD_LEFT.getStatus()) { + dpadState = 0x07; // 左上 + } else if (BUTTON_DPAD_RIGHT.getStatus()) { + dpadState = 0x01; // 右上 + } else { + dpadState = 0x00; // 上 + } + } else if (BUTTON_DPAD_DOWN.getStatus()) { + if (BUTTON_DPAD_LEFT.getStatus()) { + dpadState = 0x05; // 左下 + } else if (BUTTON_DPAD_RIGHT.getStatus()) { + dpadState = 0x03; // 右下 + } else { + dpadState = 0x04; // 下 + } + } else if (BUTTON_DPAD_LEFT.getStatus()) { + dpadState = 0x06; // 左 + } else if (BUTTON_DPAD_RIGHT.getStatus()) { + dpadState = 0x02; // 右 + } else { + dpadState = 0x08; // 中立 + } + } + + public void GenerateParams() { + SetDpadState(); + //按钮1 + byte report1 = GetGenerateParams(report1GamepadButton); + byte report2 = GetGenerateParams(report2GamepadButton); + byte[] report = new byte[8]; + // 设置按钮 A 按下(假设 A 是第一个按钮) + report[0] = report1; // 0x01 表示 A 按下,0x00 表示释放 + report[1] = report2;//; // 其他按钮未按下 + // 设置摇杆为中立值 + report[2] = report3; // 左摇杆水平中立位置 + report[3] = report4; // 左摇杆垂直中立位置 + report[4] = report5; // 右摇杆水平中立位置 + report[5] = report6; // 右摇杆垂直中立位置 +// Log.d(TAG, "GenerateParams: report3==>"+report3+"===>report4===>"+report3); + // 设置触发器未按下 + report[6] = dpadState; // 左右触发器未按下 + // 保留字节 + report[7] = 0x00; // 保留字段 + Log.d(TAG, "SetLeftRemoteSensing: report7" + dpadState); + gamepadAction.SendRequest(report); + } + + +} diff --git a/android/app/src/main/java/co/steamcloud/game/GamePara.java b/android/app/src/main/java/co/steamcloud/game/utils/GamePara.java similarity index 89% rename from android/app/src/main/java/co/steamcloud/game/GamePara.java rename to android/app/src/main/java/co/steamcloud/game/utils/GamePara.java index eb783b5..04c20fb 100644 --- a/android/app/src/main/java/co/steamcloud/game/GamePara.java +++ b/android/app/src/main/java/co/steamcloud/game/utils/GamePara.java @@ -1,17 +1,17 @@ -package co.steamcloud.game; +package co.steamcloud.game.utils; import android.os.Build; public class GamePara { String game_key; - int display_grade; - int queue_grade; - int able_queue; + int display_grade; + int queue_grade; + int able_queue; String gs_name; String save_time; String room_name; String start_resolution; - int record_game_time; + int record_game_time; String model_name; String sc_id; String hangup_time; @@ -23,7 +23,7 @@ public class GamePara { int enable_restart;//是否支持重新启动游戏,可选, 1为支持,0为不支持,默认为0 String room_key; //设置字符串房间随机密码,只有使用相同密码的操控设备权限变更才能判定有效 - public GamePara(){ + public GamePara() { game_key = ""; display_grade = 1; queue_grade = 1; diff --git a/android/app/src/main/java/co/steamcloud/game/utils/GamepadAction.java b/android/app/src/main/java/co/steamcloud/game/utils/GamepadAction.java new file mode 100644 index 0000000..35c60bd --- /dev/null +++ b/android/app/src/main/java/co/steamcloud/game/utils/GamepadAction.java @@ -0,0 +1,14 @@ +package co.steamcloud.game.utils; + +/** + * 手柄请求方法 + */ + +@FunctionalInterface +public interface GamepadAction { + /** + * + * @return + */ + void SendRequest(byte[] params); +} diff --git a/android/app/src/main/java/co/steamcloud/game/utils/GamepadButton.java b/android/app/src/main/java/co/steamcloud/game/utils/GamepadButton.java new file mode 100644 index 0000000..ee5dcbe --- /dev/null +++ b/android/app/src/main/java/co/steamcloud/game/utils/GamepadButton.java @@ -0,0 +1,27 @@ +package co.steamcloud.game.utils; + +public class GamepadButton { + + public GamepadButton(String name) { + this.Name = name; + this.Status = false; + } + + /** + * 按钮名称 + */ + public String Name; + /** + * 按钮状态 + */ + public Boolean Status; + + + public Boolean getStatus() { + return Status; + } + + public void setStatus(boolean value) { + this.Status = value; + } +} diff --git a/android/app/src/main/java/co/steamcloud/game/GsonJsonUtil.java b/android/app/src/main/java/co/steamcloud/game/utils/GsonJsonUtil.java similarity index 96% rename from android/app/src/main/java/co/steamcloud/game/GsonJsonUtil.java rename to android/app/src/main/java/co/steamcloud/game/utils/GsonJsonUtil.java index f7c2864..f246c6f 100644 --- a/android/app/src/main/java/co/steamcloud/game/GsonJsonUtil.java +++ b/android/app/src/main/java/co/steamcloud/game/utils/GsonJsonUtil.java @@ -1,4 +1,4 @@ -package co.steamcloud.game; +package co.steamcloud.game.utils; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; @@ -54,7 +54,7 @@ public class GsonJsonUtil { * 转成list * * @param string 字符串 - * @param cls 类 + * @param cls 类 * @return list */ public static List stringToList(String string, Class cls) { diff --git a/android/app/src/main/java/co/steamcloud/game/PeterTimeCountRefresh.java b/android/app/src/main/java/co/steamcloud/game/utils/PeterTimeCountRefresh.java similarity index 97% rename from android/app/src/main/java/co/steamcloud/game/PeterTimeCountRefresh.java rename to android/app/src/main/java/co/steamcloud/game/utils/PeterTimeCountRefresh.java index 90ae816..3c57315 100644 --- a/android/app/src/main/java/co/steamcloud/game/PeterTimeCountRefresh.java +++ b/android/app/src/main/java/co/steamcloud/game/utils/PeterTimeCountRefresh.java @@ -1,4 +1,4 @@ -package co.steamcloud.game; +package co.steamcloud.game.utils; import android.os.CountDownTimer; diff --git a/android/app/src/main/java/co/steamcloud/game/RoundCalculator.java b/android/app/src/main/java/co/steamcloud/game/utils/RoundCalculator.java similarity index 97% rename from android/app/src/main/java/co/steamcloud/game/RoundCalculator.java rename to android/app/src/main/java/co/steamcloud/game/utils/RoundCalculator.java index 195bce2..79a138b 100644 --- a/android/app/src/main/java/co/steamcloud/game/RoundCalculator.java +++ b/android/app/src/main/java/co/steamcloud/game/utils/RoundCalculator.java @@ -1,4 +1,4 @@ -package co.steamcloud.game; +package co.steamcloud.game.utils; /** diff --git a/android/app/src/main/java/co/steamcloud/game/wxapi/WXPayEntryActivity.java b/android/app/src/main/java/co/steamcloud/game/wxapi/WXPayEntryActivity.java index 6a4eb8f..5c99ef4 100644 --- a/android/app/src/main/java/co/steamcloud/game/wxapi/WXPayEntryActivity.java +++ b/android/app/src/main/java/co/steamcloud/game/wxapi/WXPayEntryActivity.java @@ -17,7 +17,7 @@ import org.simple.eventbus.EventBus; import java.util.HashMap; -import co.steamcloud.game.EventBusParams; +import co.steamcloud.game.utils.EventBusParams; import co.steamcloud.game.MainActivity; diff --git a/android/app/src/main/res/layout/activity_game.xml b/android/app/src/main/res/layout/activity_game.xml index 6dc1b6d..498c1cc 100644 --- a/android/app/src/main/res/layout/activity_game.xml +++ b/android/app/src/main/res/layout/activity_game.xml @@ -7,7 +7,7 @@ android:layout_height="match_parent" android:background="#000000"> - - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/layout_handle.xml b/android/app/src/main/res/layout/layout_handle.xml index 5fa755d..836d46d 100644 --- a/android/app/src/main/res/layout/layout_handle.xml +++ b/android/app/src/main/res/layout/layout_handle.xml @@ -35,7 +35,7 @@ app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="1.0" /> - - - + - - + - - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + diff --git a/assets/images/ic_bt_device.png b/assets/images/ic_bt_device.png new file mode 100644 index 0000000..6d713fa Binary files /dev/null and b/assets/images/ic_bt_device.png differ diff --git a/assets/images/ic_bt_off.png b/assets/images/ic_bt_off.png new file mode 100644 index 0000000..d7e7bba Binary files /dev/null and b/assets/images/ic_bt_off.png differ diff --git a/assets/images/ic_bt_on.png b/assets/images/ic_bt_on.png new file mode 100644 index 0000000..7735e10 Binary files /dev/null and b/assets/images/ic_bt_on.png differ diff --git a/assets/images/ic_bt_refresh.png b/assets/images/ic_bt_refresh.png new file mode 100644 index 0000000..dc80c7b Binary files /dev/null and b/assets/images/ic_bt_refresh.png differ diff --git a/assets/images/ic_describe.png b/assets/images/ic_describe.png new file mode 100644 index 0000000..26d7155 Binary files /dev/null and b/assets/images/ic_describe.png differ diff --git a/lib/common/EventBusUtil.dart b/lib/common/EventBusUtil.dart index 7c0e5bf..f5cd635 100644 --- a/lib/common/EventBusUtil.dart +++ b/lib/common/EventBusUtil.dart @@ -54,3 +54,8 @@ class TabSwitch extends Event { TabSwitch(this.index); } + +//刷新蓝牙状态 +class RefreshBtState extends Event { + RefreshBtState(); +} diff --git a/lib/dialog/bt_description_dialog.dart b/lib/dialog/bt_description_dialog.dart new file mode 100644 index 0000000..4a050bb --- /dev/null +++ b/lib/dialog/bt_description_dialog.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; + +class BtDescriptionDialog extends StatefulWidget { + BtDescriptionDialog(); + + @override + State createState() => _BtDescriptionDialogState(); +} + +class _BtDescriptionDialogState extends State { + @override + Widget build(BuildContext context) { + final size = MediaQuery.of(context).size; + final l14 = size.width / 25.71428571428571; + final t20 = size.width / 18; + final s13 = size.width / 27.692307692307; + + return Material( + type: MaterialType.transparency, //透明类型 + color: Color(0x1A000000), + child: Center( + child: Container( + margin: EdgeInsets.only(right: l14, left: l14), + decoration: BoxDecoration(color: Color(0xFF202530), borderRadius: BorderRadius.all(Radius.circular(7))), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + alignment: Alignment.centerLeft, + margin: EdgeInsets.only(top: t20, left: l14), + child: Text( + "使用说明:", + style: TextStyle(fontSize: s13, color: Color(0xFF9D9D9D)), + ), + ), + Container( + alignment: Alignment.centerLeft, + margin: EdgeInsets.only(top: t20, left: l14, right: l14, bottom: t20), + child: Text( + "1. 本功能适用于蒸汽云游车机版,TV版,帮助用户在无实体手柄的情 况下尽可能还原手柄游戏体验。\n\n 2. 使用本功能前,请打开当前设备,游戏端设备的蓝牙开关。在搜索 列表中找到游戏端设备,点击连接,连接成功后即可正常游戏。", + style: TextStyle(fontSize: s13, color: Color(0xFF9D9D9D)), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index e4a5fb7..e529ff6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,6 +10,7 @@ import 'package:game/tools/home/my_home_page.dart'; import 'package:game/tools/home/search_page.dart'; import 'package:game/tools/home_page.dart'; import 'package:game/tools/login/login_page.dart'; +import 'package:game/tools/me/bt_game_pad_page.dart'; import 'package:game/tools/me/edit_info_page.dart'; import 'package:game/tools/me/feedback_page.dart'; import 'package:game/tools/me/game_history_page.dart'; @@ -77,6 +78,23 @@ class _MyAppState extends State { case "SDKSuccess": //游戏Sdk是否初始化成功 NetworkConfig.isGameSdk = methodCall.arguments['SDKSuccess']; break; + + case "isBtOpen": //蓝牙状态 + NetworkConfig.isBtOpen = methodCall.arguments['isBtOpen']; + EventBusUtil.fire(RefreshBtState()); + print("NetworkConfig.isBtOpen==${NetworkConfig.isBtOpen}"); + break; + + case "btDevices": //蓝牙设备集合 + NetworkConfig.btDevices = List.from(methodCall.arguments['btDevices']); + print("NetworkConfig.btDevices==${NetworkConfig.btDevices}"); + EventBusUtil.fire(RefreshBtState()); + break; + + case "connectionStatus": //蓝牙设备连接状态 + NetworkConfig.connectionStatus = methodCall.arguments['connectionStatus']; + EventBusUtil.fire(RefreshBtState()); + break; } } @@ -115,6 +133,7 @@ class _MyAppState extends State { '/GameHistoryPage': (BuildContext context) => GameHistoryPage(), '/FeedbackPage': (BuildContext context) => FeedbackPage(), '/MessageCenterPage': (BuildContext context) => MessageCenterPage(), + '/BtGamePadPage': (BuildContext context) => BtGamePadPage(), }, ); } diff --git a/lib/network/NetworkConfig.dart b/lib/network/NetworkConfig.dart index 9a2efd2..3a79f14 100644 --- a/lib/network/NetworkConfig.dart +++ b/lib/network/NetworkConfig.dart @@ -35,8 +35,11 @@ class NetworkConfig { static String orderId = ""; //订单号 static SignBean? signData; //签到 static ConfigBean? configBean; //app配置 - static bool isGameSdk = false; //游戏SDK是否启动成功 static String gameId = ""; //游戏SDK是否启动成功 + static bool isGameSdk = false; //游戏SDK是否启动成功 + static bool isBtOpen = false; //蓝牙是否启动 + static List btDevices = []; //蓝牙设备集合 + static int connectionStatus = 0; //蓝牙连接状态 static const String getAppConfig = "api/App/GetAppConfig"; //应用配置 @@ -115,5 +118,4 @@ class NetworkConfig { static const String accountLogOff = "api/Account/AccountLogOff"; //注销账号 static const String getGameUserInfo = "api/Game/GetGameUserInfo"; //获取用户游戏详情数据 - } diff --git a/lib/tools/me/bt_game_pad_page.dart b/lib/tools/me/bt_game_pad_page.dart new file mode 100644 index 0000000..7fd2dce --- /dev/null +++ b/lib/tools/me/bt_game_pad_page.dart @@ -0,0 +1,263 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; + +import '../../common/EventBusUtil.dart'; +import '../../common/Global.dart'; +import '../../common/func.dart'; +import '../../dialog/bt_description_dialog.dart'; +import '../../network/NetworkConfig.dart'; + +class BtGamePadPage extends StatefulWidget { + const BtGamePadPage({super.key}); + + @override + State createState() => _BtGamePadPageState(); +} + +class _BtGamePadPageState extends State { + late StreamSubscription _refreshBtStateEvent; + + int currentBtIndex = -1; + + @override + void initState() { + // TODO: implement initState + super.initState(); + + ///刷新用户信息 + _refreshBtStateEvent = EventBusUtil.listen((event) { + setState(() {}); + }); + + //蓝牙已打开,获取蓝牙设备列表 + if (NetworkConfig.isBtOpen) { + Map gameMap = { + "getBtListDevices": "getBtListDevices", + }; + + ///传值初始化游戏token + invokeNativeMethod("getBtListDevices", gameMap); + } + } + + @override + void dispose() { + // TODO: implement dispose + super.dispose(); + _refreshBtStateEvent.cancel(); + } + + @override + Widget build(BuildContext context) { + final size = MediaQuery.of(context).size; + final h50 = size.width / 7.2; + final s16 = size.width / 22.5; + final l14 = size.width / 25.71428571428571; + final w19 = size.width / 18.94736842105263; + final h26 = size.width / 13.84615384615385; + final w33 = size.width / 10.909090909090; + final h18 = size.width / 20; + final t20 = size.width / 18; + final s13 = size.width / 27.692307692307; + final w223 = size.width / 1.6143497757847; + final h44 = size.width / 8.1818181818181; + final w40 = size.width / 9; + + return Scaffold( + backgroundColor: const Color(0xFF17181A), + body: Column( + children: [ + Container( + width: size.width, + height: h50, + margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top), + child: Stack( + alignment: Alignment.center, + children: [ + Text( + "蓝牙手柄", + style: TextStyle(fontSize: s16, color: Color(0xFFD6D6D7)), + ), + Positioned( + left: l14, + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Image( + width: w19, + height: h26, + image: const AssetImage('assets/images/btn_fanhui.png'), + ), + ), + ), + Positioned( + right: l14, + child: GestureDetector( + onTap: () { + FunctionUtil.popDialog(context, BtDescriptionDialog()); + }, + child: Image( + width: w19, + height: h26, + image: const AssetImage('assets/images/ic_describe.png'), + ), + ), + ), + ], + ), + ), + Container( + margin: EdgeInsets.only(left: l14, right: l14, top: l14), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "开启蓝牙", + style: TextStyle(fontSize: l14, color: Color(0xFFD6D6D7)), + ), + GestureDetector( + onTap: () { + //蓝牙开关 + Map gameMap = { + "setBtState": !NetworkConfig.isBtOpen, + }; + invokeNativeMethod("setBt", gameMap); + }, + child: Image( + width: w33, + height: h18, + image: AssetImage(NetworkConfig.isBtOpen ? 'assets/images/ic_bt_on.png' : 'assets/images/ic_bt_off.png'), + ), + ) + ], + ), + ), + Container( + margin: EdgeInsets.only(left: l14, right: l14, top: t20), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "连接状态", + style: TextStyle(fontSize: l14, color: Color(0xFFD6D6D7)), + ), + Text( + NetworkConfig.connectionStatus == 0 + ? "未连接" + : NetworkConfig.connectionStatus == 1 + ? "连接中" + : NetworkConfig.connectionStatus == 2 + ? "已连接" + : "正在断开连接", + style: TextStyle(fontSize: l14, color: NetworkConfig.connectionStatus == 2 ? Colors.green : Color(0xFFD6D6D7)), + ), + ], + ), + ), + GestureDetector( + onTap: () { + if (NetworkConfig.connectionStatus == 2) { + //进入手柄界面 + Map map = { + "enterGamePad": "enterGamePad", + }; + invokeNativeMethod("enterGamePad", map); + } else { + EasyLoading.showToast("请先连接设备"); + } + }, + child: Container( + width: w223, + height: h44, + margin: EdgeInsets.only(top: t20), + alignment: Alignment.center, + decoration: BoxDecoration(color: Color(0xFF074CE7), borderRadius: BorderRadius.all(Radius.circular(22))), + child: Text( + "进入蓝牙手柄", + style: TextStyle(fontSize: l14, color: Colors.white), + ), + ), + ), + Container( + margin: EdgeInsets.only(left: l14, right: l14, top: l14), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "可用设备", + style: TextStyle(fontSize: l14, color: Color(0xFFD6D6D7)), + ), + Image( + width: w33, + height: w33, + image: AssetImage('assets/images/ic_bt_refresh.png'), + ) + ], + ), + ), + Expanded( + child: Container( + margin: EdgeInsets.only(left: l14, right: l14, top: l14), + child: ListView.builder( + padding: EdgeInsets.all(0), + itemCount: NetworkConfig.btDevices.length, + itemBuilder: (context, index) { + return _btItem(index, w40); + }), + )) + ], + ), + ); + } + + _btItem(index, w40) { + return GestureDetector( + onTap: () { + NetworkConfig.connectionStatus = 0; + currentBtIndex = index; + //点击连接设备 + Map gameMap = { + "deviceIndex": index, + }; + invokeNativeMethod("connectedDevice", gameMap); + setState(() {}); + }, + child: Container( + margin: EdgeInsets.only(bottom: 10), + padding: EdgeInsets.all(5), + decoration: BoxDecoration( + color: currentBtIndex == index ? Color(0xFF202530) : Color(0x00FFFFFF), + borderRadius: BorderRadius.all(Radius.circular(5)), + ), + child: Row( + children: [ + Image( + width: w40, + height: w40, + image: AssetImage('assets/images/ic_bt_device.png'), + ), + Container( + margin: EdgeInsets.only(left: 17), + child: Text( + "${NetworkConfig.btDevices[index]}", + style: TextStyle(color: Color(0xFFD6D6D7)), + ), + ), + ], + ), + ), + ); + } + + // 获取原生的值 + invokeNativeMethod(String method, Map map) async { + dynamic args; + try { + args = await Global.method.invokeMethod(method, map); + } on PlatformException catch (e) {} + } +} diff --git a/lib/tools/me/my_page.dart b/lib/tools/me/my_page.dart index 3524691..f572d00 100644 --- a/lib/tools/me/my_page.dart +++ b/lib/tools/me/my_page.dart @@ -629,6 +629,45 @@ class _MyPageState extends State with AutomaticKeepAliveClientMixin { ), ), ), + + ///蓝牙手柄 + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Navigator.pushNamed(context, "/BtGamePadPage"); + }, + child: SizedBox( + height: h60, + child: Row( + children: [ + Container( + margin: EdgeInsets.only(left: l23), + child: Image( + width: w20, + height: w20, + image: const AssetImage('assets/images/ic_set.png'), + ), + ), + Container( + margin: EdgeInsets.only(left: l14), + child: Text( + "蓝牙手柄", + style: TextStyle(fontSize: s14, color: Color(0xFFD6D6D7)), + ), + ), + Expanded(child: Container()), + Container( + margin: EdgeInsets.only(right: l23), + child: Image( + width: l4, + height: h8, + image: AssetImage('assets/images/ic_arrow.png'), + ), + ), + ], + ), + ), + ), ], ), ), diff --git a/lib/tools/start_page.dart b/lib/tools/start_page.dart index b563f1f..b8cde5a 100644 --- a/lib/tools/start_page.dart +++ b/lib/tools/start_page.dart @@ -80,11 +80,10 @@ class _StartPageState extends State { Map headersMap = Map.from(infoData); NetworkConfig.deviceID = headersMap["deviceID"]; NetworkConfig.Language = headersMap["Language"]; //系统语言 - print("deviceID==${NetworkConfig.deviceID}"); - print("Language==${NetworkConfig.Language}"); + NetworkConfig.isBtOpen = headersMap["isBtOpen"]; //蓝牙 + print("isBtOpen==${NetworkConfig.isBtOpen}"); AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; NetworkConfig.deviceName = androidInfo.model; - print("model==${androidInfo.model}"); } }