yangchong vor 4 Jahren
Ursprung
Commit
1cc9691f97

+ 2 - 2
Demo/build.gradle

@@ -62,7 +62,7 @@ dependencies {
 //    implementation project(path: ':VideoCache')
 //    implementation project(path: ':VideoPlayer')
 //    implementation project(path: ':VideoKernel')
-//    implementation project(path: ':VideoView')
+    implementation project(path: ':VideoView')
 //    implementation project(path: ':MusicPlayer')
 //    implementation project(path: ':VideoM3u8')
 //    implementation project(path: ':VideoSqlLite')
@@ -71,7 +71,7 @@ dependencies {
     implementation 'cn.yc:VideoPlayer:3.1.0'
     implementation 'cn.yc:VideoCache:3.0.5'
     implementation 'cn.yc:VideoKernel:3.0.6'
-    implementation 'cn.yc:VideoView:3.0.5'
+//    implementation 'cn.yc:VideoView:3.0.5'
     implementation 'cn.yc:VideoM3u8:1.0.0'
     implementation 'cn.yc:VideoSqlLite:1.0.2'
 

+ 1 - 1
Demo/src/main/AndroidManifest.xml

@@ -18,7 +18,7 @@
         android:networkSecurityConfig="@xml/network_security_config"
         android:theme="@style/AppTheme"
         tools:ignore="GoogleAppIndexingWarning">
-        <activity android:name="com.yc.ycvideoplayer.newPlayer.activity.TypeActivity"
+        <activity android:name="com.yc.ycvideoplayer.MainActivity"
             android:configChanges="orientation|keyboardHidden|screenSize"
             android:screenOrientation="portrait">
             <intent-filter>

+ 79 - 0
Demo/src/main/java/com/yc/ycvideoplayer/MainActivity.java

@@ -6,13 +6,19 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.graphics.Color;
+import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.provider.Settings;
 import android.view.View;
+import android.view.animation.BounceInterpolator;
+import android.widget.ImageView;
 import android.widget.TextView;
 
 
 import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
 import androidx.appcompat.app.AppCompatActivity;
 
 import org.yc.ycvideoplayer.R;
@@ -21,6 +27,10 @@ import com.yc.kernel.utils.VideoLogUtils;
 import com.yc.music.model.AudioBean;
 import com.yc.music.service.PlayService;
 import com.yc.music.tool.BaseAppHelper;
+import com.yc.videoview.FloatWindow;
+import com.yc.videoview.MoveType;
+import com.yc.videoview.WindowScreen;
+import com.yc.videoview.WindowUtil;
 import com.yc.ycvideoplayer.demo.DemoActivity;
 import com.yc.ycvideoplayer.m3u8.M3u8Activity;
 import com.yc.ycvideoplayer.music.MusicPlayerActivity;
@@ -49,6 +59,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
     private TextView mTv3;
     private TextView mTv4;
     private TextView mTv5;
+    private TextView mTv6;
     private PlayServiceConnection mPlayServiceConnection;
 
 
@@ -58,6 +69,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
             unbindService(mPlayServiceConnection);
         }
         super.onDestroy();
+        FloatWindow.destroy();
     }
 
     @Override
@@ -74,12 +86,14 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
         mTv3 = (TextView) findViewById(R.id.tv_3);
         mTv4 = (TextView) findViewById(R.id.tv_4);
         mTv5 = (TextView) findViewById(R.id.tv_5);
+        mTv6 = (TextView) findViewById(R.id.tv_6);
 
         mTv1.setOnClickListener(this);
         mTv2.setOnClickListener(this);
         mTv3.setOnClickListener(this);
         mTv4.setOnClickListener(this);
         mTv5.setOnClickListener(this);
+        mTv6.setOnClickListener(this);
     }
 
     @Override
@@ -101,6 +115,71 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
             case R.id.tv_5:
                 startActivity(M3u8Activity.class);
                 break;
+            case R.id.tv_6:
+                if (Build.VERSION.SDK_INT >= 23) {
+                    if (!WindowUtil.hasPermission(this)) {
+                        requestAlertWindowPermission();
+                    } else {
+                        windowDialog();
+                    }
+                }
+
+                break;
+        }
+    }
+
+    @RequiresApi(api = 23)
+    private void requestAlertWindowPermission() {
+        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
+                Uri.parse("package:" + getPackageName()));
+        startActivityForResult(intent, 1);
+    }
+
+    @RequiresApi(api = 23)
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (Build.VERSION.SDK_INT >= 23) {
+            if (WindowUtil.hasPermission(this)) {
+
+            } else {
+                this.finish();
+            }
+        }
+    }
+
+
+    private void windowDialog() {
+        ImageView imageView = new ImageView(this);
+        imageView.setBackgroundResource(R.drawable.ic_play_btn_loved);
+        FloatWindow
+                .with(getApplicationContext())
+                .setView(imageView)
+                //.setWidth(WindowScreen.WIDTH, 0.4f)
+                //.setHeight(WindowScreen.WIDTH, 0.3f)
+                //这个是设置位置
+                .setX(WindowScreen.WIDTH, 0.8f)
+                .setY(WindowScreen.HEIGHT, 0.3f)
+                .setMoveType(MoveType.slide)
+                .setFilter(false)
+                //.setFilter(true, WindowActivity.class, EmptyActivity.class)
+                .setMoveStyle(500, new BounceInterpolator())
+                .build();
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        if (FloatWindow.get()!=null){
+            FloatWindow.get().hide();
+        }
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        if (FloatWindow.get()!=null){
+            FloatWindow.get().show();
         }
     }
 

+ 8 - 0
Demo/src/main/res/layout/activity_main.xml

@@ -75,6 +75,14 @@
                 android:padding="10dp"
                 android:background="@color/colorAccent"
                 android:text="5.m3u8视频下载"/>
+            <TextView
+                android:id="@+id/tv_6"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="10dp"
+                android:padding="10dp"
+                android:background="@color/colorAccent"
+                android:text="6.悬浮窗"/>
         </LinearLayout>
     </ScrollView>
 

+ 10 - 4
VideoView/src/main/java/com/yc/videoview/IFloatWindowImpl.java

@@ -71,15 +71,21 @@ public class IFloatWindowImpl extends IFloatWindow {
             if (isShow) {
                 return;
             }
-            getView().setVisibility(View.VISIBLE);
-            isShow = true;
+            if (getView()!=null){
+                getView().setVisibility(View.VISIBLE);
+                isShow = true;
+            }
         }
     }
 
     @Override
     public void hide() {
-        if (once || !isShow) return;
-        getView().setVisibility(View.INVISIBLE);
+        if (once || !isShow) {
+            return;
+        }
+        if (getView()!=null){
+            getView().setVisibility(View.INVISIBLE);
+        }
         isShow = false;
     }
 

+ 112 - 0
VideoView/wiki/01.全局悬浮窗实践.md

@@ -0,0 +1,112 @@
+#### 目录介绍
+- 01.全局悬浮窗介绍
+- 02.悬浮窗注意要点
+- 03.绘制悬浮窗步骤
+
+
+
+
+### 01.全局悬浮窗介绍
+- 什么是悬浮窗
+    - 全局悬浮窗在许多应用中都能见到,点击Home键,小窗口仍然会在屏幕上显示。
+- 悬浮窗要能够全局显示就必须要申请权限:
+    ```
+     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
+            tools:ignore="ProtectedPermissions" />
+    ```
+- 当API Level>=23的时候就要动态的申请权限了,判断是否能够绘制悬浮窗:
+    ```
+    Settings.canDrawOverlays(this)
+    ```
+    - 返回为true就表明已同意权限,否则就表示没有全局绘制的权限。此处获取权限需要跳转设置用户手动打开:
+    ```
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
+        Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT);
+        Intent intent = new Intent();
+        intent.setAction(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
+        intent.setData(Uri.parse("package:" + getPackageName()));
+        startActivityForResult(intent, 0);
+    }
+    ```
+
+### 02.悬浮窗注意要点
+
+
+
+
+### 03.绘制悬浮窗步骤
+- 全局的悬浮窗是通过WindowManager来绘制已达到能够全局显示的效果,而WindowManager的addView方法还需要一个WindowManager.LayoutParam对象作为参数,此处Android 8.0之后的需要适配一下:
+    ```
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+      layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+    } else {
+      layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
+    }
+    ```
+- 为了能够使悬浮窗脱离activity全局显示,因此这里使用Service来启动悬浮窗。界面触发悬浮窗代码如下:
+    ```
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(this)) {
+        // 获取WindowManager服务
+        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
+        // 设置LayoutParam
+        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.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        //宽高自适应
+        layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
+        layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
+        //显示的位置
+        layoutParams.x = 300;
+        layoutParams.y = 300;
+    
+        // 新建悬浮窗控件
+        View view = LayoutInflater.from(this).inflate(R.layout.float_window, null);
+        view.setOnTouchListener(new FloatingOnTouchListener());
+        // 将悬浮窗控件添加到WindowManager
+        windowManager.addView(view, layoutParams);
+    }
+    ```
+- 手指滑动
+    ```
+    private class FloatingOnTouchListener implements View.OnTouchListener {
+        private int x;
+        private int y;
+    
+        @SuppressLint("ClickableViewAccessibility")
+        @Override
+        public boolean onTouch(View view, MotionEvent event) {
+            switch (event.getAction()) {
+                case MotionEvent.ACTION_DOWN:
+                    x = (int) event.getRawX();
+                    y = (int) event.getRawY();
+                    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);
+                    break;
+                default:
+                    break;
+            }
+            return false;
+        }
+    }
+    ```
+
+
+
+