Przeglądaj źródła

add float window

x1ongzhu 6 lat temu
rodzic
commit
65c4114a4e

+ 21 - 0
android/app/src/main/java/com/izouma/mobilecybergames/MainActivity.java

@@ -1,5 +1,6 @@
 package com.izouma.mobilecybergames;
 
+import android.content.Intent;
 import android.os.Bundle;
 
 import com.mr.flutter.plugin.filepicker.FilePickerPlugin;
@@ -9,10 +10,30 @@ import io.flutter.plugin.common.MethodChannel;
 import io.flutter.plugins.GeneratedPluginRegistrant;
 
 public class MainActivity extends FlutterActivity {
+    public static final String APP_LIFECYCLE_ACTION = "APP_LIFECYCLE_ACTION";
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         GeneratedPluginRegistrant.registerWith(this);
         ScreenStreamPlugin.registerWith(registrarFor("com.izouma.mobilecybergames.ScreenStreamPlugin"));
     }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        Intent intent = new Intent();
+        intent.setAction(APP_LIFECYCLE_ACTION);
+        intent.putExtra("event", "onResume");
+        sendBroadcast(intent);
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        Intent intent = new Intent();
+        intent.setAction(APP_LIFECYCLE_ACTION);
+        intent.putExtra("event", "onPause");
+        sendBroadcast(intent);
+    }
 }

+ 133 - 11
android/app/src/main/java/com/izouma/mobilecybergames/ScreenStreamPlugin.java

@@ -1,8 +1,11 @@
 package com.izouma.mobilecybergames;
 
 import android.app.Activity;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Color;
 import android.graphics.PixelFormat;
 import android.media.projection.MediaProjectionManager;
 import android.net.Uri;
@@ -11,8 +14,10 @@ import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Gravity;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowManager;
+import android.widget.Button;
 import android.widget.Toast;
 
 import com.alivc.live.pusher.AlivcAudioAACProfileEnum;
@@ -36,7 +41,8 @@ import static android.content.Context.WINDOW_SERVICE;
 
 public class ScreenStreamPlugin implements MethodChannel.MethodCallHandler, PluginRegistry.ActivityResultListener {
     private static final String TAG                             = "ScreenStreamPlugin";
-    public static final  int    CAPTURE_PERMISSION_REQUEST_CODE = 0x1123;
+    private static final int    CAPTURE_PERMISSION_REQUEST_CODE = 0x1123;
+    private static final int    FLOATING_WINDOW_REQUEST_CODE    = 0x1124;
 
     private final PluginRegistry.Registrar registrar;
 
@@ -46,6 +52,10 @@ public class ScreenStreamPlugin implements MethodChannel.MethodCallHandler, Plug
     private String               url;
     private MethodChannel.Result result;
 
+    private WindowManager              windowManager;
+    private WindowManager.LayoutParams layoutParams;
+    private Button                     floatButton;
+
     public static void registerWith(PluginRegistry.Registrar registrar) {
         final MethodChannel channel = new MethodChannel(registrar.messenger(), "screen_stream");
         MethodChannel.MethodCallHandler methodCallHandler = new ScreenStreamPlugin(registrar);
@@ -55,6 +65,20 @@ public class ScreenStreamPlugin implements MethodChannel.MethodCallHandler, Plug
 
     public ScreenStreamPlugin(PluginRegistry.Registrar registrar) {
         this.registrar = registrar;
+        this.registrar.context().registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if ("onResume".equals(intent.getStringExtra("event"))) {
+                    if (floatButton != null) {
+                        floatButton.setVisibility(View.GONE);
+                    }
+                } else if ("onPause".equals(intent.getStringExtra("event"))) {
+                    if (floatButton != null) {
+                        floatButton.setVisibility(View.VISIBLE);
+                    }
+                }
+            }
+        }, new IntentFilter(MainActivity.APP_LIFECYCLE_ACTION));
         AlivcLivePushConfig.setMediaProjectionPermissionResultData(null);
         mAlivcLivePushConfig = new AlivcLivePushConfig();//初始化推流配置类
         mAlivcLivePushConfig.setResolution(AlivcResolutionEnum.RESOLUTION_720P);//分辨率540P,最大支持720P
@@ -63,6 +87,21 @@ public class ScreenStreamPlugin implements MethodChannel.MethodCallHandler, Plug
         mAlivcLivePushConfig.setPreviewOrientation(AlivcPreviewOrientationEnum.ORIENTATION_LANDSCAPE_HOME_RIGHT); // 默认为竖屏,可设置home键向左或向右横屏。
         mAlivcLivePushConfig.setAudioProfile(AlivcAudioAACProfileEnum.AAC_LC);//设置音频编码模式
         mAlivcLivePushConfig.setEnableBitrateControl(true);// 打开码率自适应,默认为true
+
+        windowManager = (WindowManager) this.registrar.context().getSystemService(WINDOW_SERVICE);
+        layoutParams = new WindowManager.LayoutParams();
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+        } else {
+            layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
+        }
+        layoutParams.format = PixelFormat.RGBA_8888;
+        layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+        layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        layoutParams.width = 200;
+        layoutParams.height = 100;
+        layoutParams.x = 300;
+        layoutParams.y = 300;
     }
 
     @Override
@@ -82,6 +121,14 @@ public class ScreenStreamPlugin implements MethodChannel.MethodCallHandler, Plug
         } else if ("stop".equals(methodCall.method)) {
             stop();
             result.success("success");
+        } else if ("checkPermission".equals(methodCall.method)) {
+            if (checkPermission()) {
+                result.success(true);
+            } else {
+                result.success(false);
+            }
+        } else if ("requestPermission".equals(methodCall.method)) {
+            requestPermission();
         }
     }
 
@@ -99,22 +146,44 @@ public class ScreenStreamPlugin implements MethodChannel.MethodCallHandler, Plug
         return false;
     }
 
-    private void checkPermission() {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//判断系统版本
+    private boolean checkPermission() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            return Settings.canDrawOverlays(registrar.context());
+        }
+        return true;
+    }
+
+    private void requestPermission() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
             if (!Settings.canDrawOverlays(registrar.context())) {
-                Toast.makeText(registrar.activity(), "当前无权限,请授权", Toast.LENGTH_SHORT).show();
-                registrar.activity().startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + registrar.context().getPackageName())), 0);
-            } else {
-                showFloatWindow();
+                registrar.activity().startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + registrar.context().getPackageName())), FLOATING_WINDOW_REQUEST_CODE);
+                return;
             }
-        } else {
-            showFloatWindow();
         }
+        result.success(true);
     }
 
     private void showFloatWindow() {
-        Intent intent = new Intent(registrar.context(), ScreenStreamService.class);
-        registrar.context().startService(intent);
+        if (floatButton != null) {
+            return;
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//判断系统版本
+            if (Settings.canDrawOverlays(registrar.context())) {
+                floatButton = new Button(registrar.context().getApplicationContext());
+                floatButton.setText("CLICK ME!");
+                floatButton.setBackgroundColor(Color.LTGRAY);
+                floatButton.setVisibility(View.GONE);
+                windowManager.addView(floatButton, layoutParams);
+                floatButton.setOnTouchListener(new FloatingOnTouchListener());
+            }
+        } else {
+            floatButton = new Button(registrar.context().getApplicationContext());
+            floatButton.setText("CLICK ME!");
+            floatButton.setBackgroundColor(Color.LTGRAY);
+            floatButton.setVisibility(View.GONE);
+            windowManager.addView(floatButton, layoutParams);
+            floatButton.setOnTouchListener(new FloatingOnTouchListener());
+        }
     }
 
     private boolean stop() {
@@ -125,6 +194,7 @@ public class ScreenStreamPlugin implements MethodChannel.MethodCallHandler, Plug
     }
 
     private void startPushWithoutSurface() {
+        showFloatWindow();
         mAlivcLivePusher = new AlivcLivePusher();
         try {
             mAlivcLivePusher.init(registrar.context(), mAlivcLivePushConfig);
@@ -294,8 +364,60 @@ public class ScreenStreamPlugin implements MethodChannel.MethodCallHandler, Plug
                     result.error("needs permission", "permission not granted", null);
                 }
             }
+            case FLOATING_WINDOW_REQUEST_CODE: {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                    if (!Settings.canDrawOverlays(registrar.context())) {
+                        if (result != null) {
+                            result.success(false);
+                        }
+                        return true;
+                    }
+                }
+                if (result != null) {
+                    result.success(false);
+                }
+            }
             break;
         }
         return false;
     }
+
+    private class FloatingOnTouchListener implements View.OnTouchListener {
+        private int  x;
+        private int  y;
+        private long ts;
+        boolean moved = false;
+
+        @Override
+        public boolean onTouch(View view, MotionEvent event) {
+            switch (event.getAction()) {
+                case MotionEvent.ACTION_DOWN:
+                    x = (int) event.getRawX();
+                    y = (int) event.getRawY();
+                    ts = System.currentTimeMillis();
+                    moved = false;
+                    break;
+                case MotionEvent.ACTION_MOVE:
+                    int nowX = (int) event.getRawX();
+                    int nowY = (int) event.getRawY();
+                    int movedX = nowX - x;
+                    int movedY = nowY - y;
+                    x = nowX;
+                    y = nowY;
+                    layoutParams.x = layoutParams.x + movedX;
+                    layoutParams.y = layoutParams.y + movedY;
+                    windowManager.updateViewLayout(view, layoutParams);
+                    moved = true;
+                    break;
+                case MotionEvent.ACTION_UP:
+                    if (System.currentTimeMillis() - ts < 300) {
+                        registrar.context().startActivity(new Intent(registrar.context(), MainActivity.class));
+                    }
+                    break;
+                default:
+                    break;
+            }
+            return false;
+        }
+    }
 }

+ 20 - 15
lib/pages/HomePage.dart

@@ -15,6 +15,7 @@ import 'package:flutter_redux/flutter_redux.dart';
 import '../redux/AppState.dart';
 import 'setting.dart';
 import '../widget/Dialog.dart';
+import '../plugins/ScreenStramPlugin.dart';
 
 class HomePage extends StatefulWidget {
   @override
@@ -43,7 +44,7 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
   }
 
   void showBackDialog() {
-     MyDialog.showDialog(context, '暂时没有进行中的房间,敬请期待...');
+    MyDialog.showDialog(context, '暂时没有进行中的房间,敬请期待...');
     // showDialog<Null>(
     //   context: context,
     //   barrierDismissible: false,
@@ -114,14 +115,6 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
     WidgetsBinding.instance.removeObserver(this);
   }
 
-
-  // @override
-  // void didChangeLocales(List<Locale> locale) {
-  //      print('1111111111111');
-  //   // TODO: implement didChangeLocales
-  //   super.didChangeLocales(locale);
-  // }
-
   @override
   void didChangeAppLifecycleState(AppLifecycleState state) {
     if (state == AppLifecycleState.resumed) {
@@ -168,7 +161,8 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
                             Navigator.push(
                                 context,
                                 new CupertinoPageRoute(
-                                    builder: (context) => new RankList(raceId: seasonList[index].competitionSeason.id, gameId: seasonList[index].competitionSeason.gameId)));
+                                    builder: (context) =>
+                                        new RankList(raceId: seasonList[index].competitionSeason.id, gameId: seasonList[index].competitionSeason.gameId)));
                           },
                           onIndexChanged: (index) {
                             setState(() {
@@ -226,6 +220,17 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
                                             // )
                                           ],
                                         ),
+                                      ),
+                                      Center(
+                                        child: MaterialButton(
+                                          child: Text('lalala'),
+                                          onPressed: () async {
+                                            bool success = await ScreenStreamPlugin.checkPermission();
+                                            print(success);
+                                            // bool success = await ScreenStreamPlugin.requestPermission();
+                                            // print(success);
+                                          },
+                                        ),
                                       )
                                     ],
                                   )),
@@ -299,9 +304,9 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
             double height = MediaQuery.of(context).size.height;
             double aspectRatio = 1;
             // if (height / width < 20 / 9) {
-             
+
             // }
-             aspectRatio = width / (height - 350);
+            aspectRatio = width / (height - 350);
             return Container(
               child: GridView.count(
                 physics: new BouncingScrollPhysics(),
@@ -344,9 +349,9 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
                   HomeMenu(
                     "images/home_icon_youjian.png",
                     "邮件",
-                    onTapHomeMenu: () async{
-                      bool result=await Navigator.push(context, new CupertinoPageRoute(builder: (context) => new TipList()));
-                      if(result){
+                    onTapHomeMenu: () async {
+                      bool result = await Navigator.push(context, new CupertinoPageRoute(builder: (context) => new TipList()));
+                      if (result) {
                         getUnreadMsg();
                       }
                     },

+ 25 - 3
lib/pages/openRoom.dart

@@ -16,6 +16,7 @@ import '../net/Result.dart';
 import 'package:dio/dio.dart';
 import '../model/GameInfo.dart';
 import '../model/HouseLevel.dart';
+import '../plugins/ScreenStramPlugin.dart';
 
 class OpenRoom extends StatefulWidget {
   OpenRoom({Key key, this.roomFlag}) : super(key: key);
@@ -68,6 +69,27 @@ class OpenRoomState extends State<OpenRoom> {
       Toast.show(context, '请录入游戏房间密码', 1500, 'info');
       return;
     }
+    bool hasPermission = await ScreenStreamPlugin.checkPermission();
+    if (!hasPermission) {
+      showDialog(
+        context: context,
+        builder: (context) => AlertDialog(
+              title: Text('需要悬浮窗权限'),
+              contentTextStyle: TextStyle(color: Colors.black87),
+              content: Text('请在点击确定后,勾选"允许显示在其他应用的上层"'),
+              actions: <Widget>[
+                FlatButton(
+                  child: Text('确定'),
+                  onPressed: () {
+                    Navigator.of(context).pop();
+                    ScreenStreamPlugin.requestPermission();
+                  },
+                ),
+              ],
+            ),
+      );
+      return;
+    }
     editRoomInfo['createUser'] = StoreProvider.of<AppState>(context).state.userInfo.id;
     Toast.show(context, '加载中', -1, 'loading');
     Result res = await HttpManager.post("houseInfo/save", data: editRoomInfo);
@@ -329,7 +351,7 @@ class OpenRoomState extends State<OpenRoom> {
                               child: Image.asset('images/icon_jinbi_da_bai.png', width: 20),
                             ),
                             Text(
-                              'X' + (chooseLevelInfo.entryCoin ?? 0).toString(),
+                              '×' + (chooseLevelInfo.entryCoin ?? 0).toString(),
                               style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500),
                             ),
                             Padding(
@@ -394,7 +416,7 @@ class OpenRoomState extends State<OpenRoom> {
             height: 1,
             color: BG_SUB_COLOR,
           ),
-          //游戏中房间密
+          //游戏中房间密��
           Container(
             height: 60,
             color: BG_COLOR,
@@ -530,7 +552,7 @@ class ChooseContent extends StatelessWidget {
                           child: Image.asset('images/icon_jinbi_da_bai.png', width: 20),
                         ),
                         Text(
-                          'X' + (chooseLevelInfo.entryCoin ?? 0).toString(),
+                          '×' + (chooseLevelInfo.entryCoin ?? 0).toString(),
                           style: TextStyle(color: Colors.white, fontSize: 15, fontWeight: FontWeight.w500),
                         )
                       ],

+ 3 - 3
lib/pages/roomInfo.dart

@@ -549,7 +549,7 @@ class RoomInfoState extends State<RoomInfo>
                               ),
                             ),
                             Text(
-                              'X' +
+                              '×' +
                                   (houseInfo != null
                                       ? houseInfo.bonus.toString()
                                       : '0'),
@@ -606,7 +606,7 @@ class RoomInfoState extends State<RoomInfo>
                 Container(
                   margin: EdgeInsets.only(left: 6),
                   child: Text(
-                    'X' + joinMoney.toString(),
+                    '×' + joinMoney.toString(),
                     style: TextStyle(
                         color: Colors.white,
                         fontSize: 16,
@@ -930,7 +930,7 @@ class RankContentState extends State<RankContent> {
             children: <Widget>[
               Image.asset('images/icon_jinbi_xiao_hong.png', width: 20),
               Text(
-                  'x' +
+                  '×' +
                       (topList[_num - 1].bonus != null
                           ? topList[_num - 1].bonus.toString()
                           : '0'),

+ 28 - 0
lib/plugins/ScreenStramPlugin.dart

@@ -1,3 +1,5 @@
+import 'dart:io';
+
 import 'package:flutter/services.dart';
 
 class ScreenStreamPlugin {
@@ -20,4 +22,30 @@ class ScreenStreamPlugin {
       return false;
     }
   }
+
+  static Future<bool> checkPermission() async {
+    if (Platform.isAndroid) {
+      try {
+        bool success = await _channel.invokeMethod("checkPermission", []);
+        return success;
+      } catch (e) {
+        return false;
+      }
+    } else {
+      return true;
+    }
+  }
+
+  static Future<bool> requestPermission() async {
+    if (Platform.isAndroid) {
+      try {
+        bool success = await _channel.invokeMethod("requestPermission", []);
+        return success;
+      } catch (e) {
+        return false;
+      }
+    } else {
+      return true;
+    }
+  }
 }

+ 1 - 1
pubspec.yaml

@@ -4,7 +4,7 @@ description: Universal mobile cyber games app
 version: 1.0.0+1
 
 environment:
-  sdk: ">=2.0.0-dev.68.0 <3.0.0"
+  sdk: ">=2.1.0 <3.0.0"
 
 
 dependencies: