Android 悬浮窗口(一)

前言

这章主要介绍 悬浮窗口
主要分为2种
1:悬浮在所有窗口上
2:悬浮在当前窗口上
这章讲述 悬浮在所有窗口上

1 准备
Android studio 4.1.1 或以上
win7 或以上

2 悬浮在所有窗口上
1> 需要注册个service

AndroidManifest.xml 如下

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testfloatallwindow">

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <!--uses-permission android:name="android.permission.CAMERA" /-->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Testfloatallwindow">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".FloatingVideoService"></service>
    </application>


</manifest>

2> 布局
activity_main.xml

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical">
<TextView
        android:id="@+id/show_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="start"
    android:onClick="startbtn"/>

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="close"
    android:onClick="closebtn"/>

</LinearLayout>

video_display.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--androidx.camera.view.PreviewView
        android:id="@+id/video_display_surfaceview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" /-->
    <SurfaceView
        android:id="@+id/video_display_surfaceview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>


app下的build.gradle

```clike
plugins {
    id 'com.android.application'
}

android {
    compileSdkVersion 33
    buildToolsVersion "33.0.0"

    defaultConfig {
        applicationId "com.example.testfloatallwindow"
        minSdkVersion 23
        targetSdkVersion 33
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

    //附加的
    implementation 'org.apache.commons:commons-pool2:2.9.0'

    def camerax_version = "1.1.0-beta03"
// CameraX core library
    implementation "androidx.camera:camera-core:$camerax_version"
// CameraX Camera2 extensions[可选]拓展库可实现人像、HDR、夜间和美颜、滤镜但依赖于OEM
    implementation "androidx.camera:camera-camera2:$camerax_version"
// CameraX Lifecycle library[可选]避免手动在生命周期释放和销毁数据
    implementation "androidx.camera:camera-lifecycle:$camerax_version"
// CameraX View class[可选]最佳实践,最好用里面的PreviewView,它会自行判断用SurfaceView还是TextureView来实现
    implementation "androidx.camera:camera-view:$camerax_version"

    implementation "androidx.camera:camera-extensions:${camerax_version}"
}

app 下的 build.gradle

plugins {
    id 'com.android.application'
}

android {
    compileSdkVersion 33
    buildToolsVersion "33.0.0"

    defaultConfig {
        applicationId "com.example.testcamerax"
        minSdkVersion 23
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'


    def camerax_version = "1.2.0"    //"1.1.0-beta03"
// CameraX core library
    implementation "androidx.camera:camera-core:$camerax_version"
// CameraX Camera2 extensions[可选]拓展库可实现人像、HDR、夜间和美颜、滤镜但依赖于OEM
    implementation "androidx.camera:camera-camera2:$camerax_version"
// CameraX Lifecycle library[可选]避免手动在生命周期释放和销毁数据
    implementation "androidx.camera:camera-lifecycle:$camerax_version"
// CameraX View class[可选]最佳实践,最好用里面的PreviewView,它会自行判断用SurfaceView还是TextureView来实现
    implementation "androidx.camera:camera-view:$camerax_version"

    implementation "androidx.camera:camera-extensions:${camerax_version}"

    // If you want to additionally use the CameraX VideoCapture library
    implementation "androidx.camera:camera-video:${camerax_version}"


    // CameraX core library using the camera2 implementation
  //  def camerax_version = "1.2.0-alpha02" //1.2.0-alpha02
// The following line is optional, as the core library is included indirectly by camera-camera2
 /*   implementation "androidx.camera:camera-core:${camerax_version}"
    implementation "androidx.camera:camera-camera2:${camerax_version}"
// If you want to additionally use the CameraX Lifecycle library
    implementation "androidx.camera:camera-lifecycle:${camerax_version}"
// If you want to additionally use the CameraX VideoCapture library
    implementation "androidx.camera:camera-video:${camerax_version}"
// If you want to additionally use the CameraX View class
    implementation "androidx.camera:camera-view:${camerax_version}"
// If you want to additionally add CameraX ML Kit Vision Integration
    implementation "androidx.camera:camera-mlkit-vision:${camerax_version}"
// If you want to additionally use the CameraX Extensions library
    implementation "androidx.camera:camera-extensions:${camerax_version}"*/
}
3>代码
 MainActivity.java

```clike
package com.example.testfloatallwindow;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    //绑定方式 启动
//    private FloatingVideoService service = null;
//    private boolean isBound = false;
//
//    private ServiceConnection conn = new ServiceConnection() {
//        @Override
//        public void onServiceConnected(ComponentName name, IBinder binder) {
//            isBound = true;
//            FloatingVideoService.MyBinder myBinder = (FloatingVideoService.MyBinder)binder;
//            service = myBinder.getService();
//            Log.i("DemoLog", "ActivityA onServiceConnected");
//            //  int num = service.getRandomNumber();
//            //  Log.i("DemoLog", "ActivityA 中调用 TestService的getRandomNumber方法, 结果: " + num);
//        }
//
//        @Override
//        public void onServiceDisconnected(ComponentName name) {
//            isBound = false;
//            Log.i("DemoLog", "ActivityA onServiceDisconnected");
//        }
//    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void startbtn(View view) {
        if (FloatingVideoService.isStarted) {
            return;
        }
        if (!Settings.canDrawOverlays(this)) {
            Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT);
            startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 2);
        } else {
            startService(new Intent(MainActivity.this, FloatingVideoService.class));
        }


    }

    public  void closebtn(View view){
        //unbindService(conn);
        stopService(new Intent(MainActivity.this,FloatingVideoService.class));
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 0) {
            if (!Settings.canDrawOverlays(this)) {
                Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
                startService(new Intent(MainActivity.this, FloatingVideoService.class));
            }
        } else if (requestCode == 1) {
            if (!Settings.canDrawOverlays(this)) {
                Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
                startService(new Intent(MainActivity.this, FloatingVideoService.class));
            }
        } else if (requestCode == 2) {
            if (!Settings.canDrawOverlays(this)) {
                Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
                startService(new Intent(MainActivity.this, FloatingVideoService.class));
            }
        }
    }
}

FloatingVideoService.java

package com.example.testfloatallwindow;


import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;
import android.util.Size;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;

import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;

import com.google.common.util.concurrent.ListenableFuture;

import java.io.IOException;
import java.util.concurrent.ExecutorService;


public class FloatingVideoService extends Service {
    public static boolean isStarted = false;

    private WindowManager windowManager;
    private WindowManager.LayoutParams layoutParams;

    private MediaPlayer mediaPlayer;
    private View displayView;

    public static boolean bSetup = true;

    public static final int DMS_INPUT_IMG_W = 640;
    public static final int DMS_INPUT_IMG_H = 480;
    //
    private final String TAG = MainActivity.class.getName() ;
    private final int REQUEST_CODE_CONTACT = 1;
    private boolean isBackCamera =false;
    private ExecutorService cameraExecutor;
    private ProcessCameraProvider mCameraPRrovider = null;
    //
    //下面的可以去掉,bind connect 方式 服务
    public class MyBinder extends Binder{

        public FloatingVideoService getService(){
            return FloatingVideoService.this;
        }

    }

    //通过binder实现调用者client与Service之间的通信
    private MyBinder binder = new MyBinder();


    public void methodInService() {
        Log.i("MyService", "执行服务钟的methodInService()方法");
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i("MyService","jiebang ");
        return super.onUnbind(intent);

    }

    @Override
    public IBinder onBind(Intent intent) {

        Log.i("MyService","绑定服务");
        return null; //new MyBinder();
    }
    

    @Override
    public void onCreate() {
        super.onCreate();
        isStarted = true;
        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        layoutParams = new WindowManager.LayoutParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; //TYPE_APPLICATION_SUB_PANEL ; //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 = DMS_INPUT_IMG_W;
        layoutParams.height = DMS_INPUT_IMG_H;
        layoutParams.x = 300;
        layoutParams.y = 300;

        mediaPlayer = new MediaPlayer();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        showFloatingWindowVideo();
        return super.onStartCommand(intent, flags, startId);
    }

    private void showFloatingWindowVideo() {
        if (Settings.canDrawOverlays(this)) {
            LayoutInflater layoutInflater = LayoutInflater.from(this);
            displayView = layoutInflater.inflate(R.layout.video_display, null);
            displayView.setOnTouchListener(new FloatingOnTouchListener());
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            SurfaceView surfaceView = displayView.findViewById(R.id.video_display_surfaceview);
            final SurfaceHolder surfaceHolder = surfaceView.getHolder();
            surfaceHolder.addCallback(new SurfaceHolder.Callback() {
                @Override
                public void surfaceCreated(SurfaceHolder holder) {
                    mediaPlayer.setDisplay(surfaceHolder);
                }

                @Override
                public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

                }

                @Override
                public void surfaceDestroyed(SurfaceHolder holder) {

                }
            });
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    mediaPlayer.start();
                }
            });
            try {
                mediaPlayer.setDataSource(this, Uri.parse("视屏地址url"));
                mediaPlayer.prepareAsync();
            }
            catch (IOException e) {
                Toast.makeText(this, "打开失败", Toast.LENGTH_LONG).show();
            }
            windowManager.addView(displayView, layoutParams);
            bSetup = true ;
        }
    }

    private void showFloatingWindowCamera() {
        if (Settings.canDrawOverlays(this)) {
            LayoutInflater layoutInflater = LayoutInflater.from(this);
            displayView = layoutInflater.inflate(R.layout.video_display, null);
            displayView.setOnTouchListener(new FloatingOnTouchListener());
            SurfaceView surfaceView = displayView.findViewById(R.id.video_display_surfaceview);
            final SurfaceHolder surfaceHolder = surfaceView.getHolder();
            surfaceHolder.addCallback(new SurfaceHolder.Callback() {
                @Override
                public void surfaceCreated(SurfaceHolder holder) {
                }

                @Override
                public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

                }

                @Override
                public void surfaceDestroyed(SurfaceHolder holder) {

                }
            });
            windowManager.addView(displayView, layoutParams);
            bSetup = true ;
        }
    }

    private void setupCamera(){
            // 将Camera的生命周期和Activity绑定在一起(设定生命周期所有者),这样就不用手动控制相机的启动和关闭。
            ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);

            cameraProviderFuture.addListener(() -> {
                try {
                    // 将你的相机和当前生命周期的所有者绑定所需的对象
                    ProcessCameraProvider mCameraPRrovider = cameraProviderFuture.get();

                    //
                    //要预览开启下面3句 + processCameraProvider.bindToLifecycle(MainActivity.this, cameraSelector,
                    //                        imageAnalysis,preview);  preview 加上,不要预览就去跳
                    // 创建一个Preview 实例,并设置该实例的 surface 提供者(provider)。
                    LayoutInflater layoutInflater = LayoutInflater.from(this);
                    displayView = layoutInflater.inflate(R.layout.video_display, null);
                    displayView.setOnTouchListener(new FloatingOnTouchListener());

                    PreviewView viewFinder = displayView.findViewById(R.id.video_display_surfaceview);
                    //   PreviewView viewFinder = (PreviewView)findViewById(R.id.viewFinder);
                    Preview preview = new Preview.Builder()
                            .build();
                    preview.setSurfaceProvider(viewFinder.getSurfaceProvider());

                    windowManager.addView(displayView, layoutParams);
                    ///

                    // 选择前置摄像头作为默认摄像头
                    CameraSelector cameraSelector = isBackCamera?CameraSelector.DEFAULT_BACK_CAMERA:CameraSelector.DEFAULT_FRONT_CAMERA;

                    // 创建拍照所需的实例
                    //   imageCapture = new ImageCapture.Builder().build();

                    // 设置预览帧分析
//                ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
//                        .build();
                    //ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888
                    ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
                            .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
                            .setTargetResolution(new Size(DMS_INPUT_IMG_W, DMS_INPUT_IMG_H)) // 图片的建议尺寸
                            .setOutputImageRotationEnabled(true) // 是否旋转分析器中得到的图片
                            .setTargetRotation(Surface.ROTATION_0) // 允许旋转后 得到图片的旋转设置
                            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                            .setImageQueueDepth(1)
                            .build();
                    //  imageAnalysis.setAnalyzer(cameraExecutor, new MyAnalyzer());
                    imageAnalysis.setAnalyzer(cameraExecutor, imageProxy -> {
                        int picformat = imageProxy.getFormat();
                        if(imageProxy.getFormat() == ImageFormat.YUV_420_888){

//                        byte[] data = test2(imageProxy);
//                        onPreviewResult(data);
                            //  byte[] data = bitmap.
                            // byte[] data =  getUvData(imageProxy);
                            // onPreviewResult(data);
                            //  Image  image =  imageProxy.getImage();
                            // ImageProxy.PlaneProxy[] mPlanes = imageProxy.getPlanes();
                            //  byte[] data = YUV_420_888toNV21(mPlanes[0].getBuffer(),mPlanes[1].getBuffer(),mPlanes[2].getBuffer());
                            //  byte[] data = BitmapUtils.yuv420ThreePlanesToNV21(image.getPlanes(),DMS_INPUT_IMG_W,DMS_INPUT_IMG_H);
                            // onPreviewResult(data);
//                        ImageProxy.PlaneProxy mY = mPlanes[0];//Y分量
//                        ImageProxy.PlaneProxy mU = mPlanes[1];//U分量
//                        ImageProxy.PlaneProxy mV = mPlanes[2];//V风量
//                        Log.e(TAG, "planes0:" + mY.getPixelStride() + " planes1:" + mU.getPixelStride() + " planes2:" + mV.getPixelStride());
                        }else if(imageProxy.getFormat() == ImageFormat.FLEX_RGBA_8888 || picformat == PixelFormat.RGBA_8888){
//                        ImageProxy.PlaneProxy[] mPlanes = imageProxy.getPlanes();
//                        imageProxy.getPlanes()[0].getBuffer().get(0); //alpha透明度
//                        imageProxy.getPlanes()[0].getBuffer().get(1); //red红色
//                        imageProxy.getPlanes()[0].getBuffer().get(2); //green绿色
//                        imageProxy.getPlanes()[0].getBuffer().get(3); //blue蓝色
//                            @SuppressLint("UnsafeOptInUsageError") Bitmap bitmap = toBitmap(imageProxy.getImage());
//                            Bitmap bitmap1 = alterSizeBitmap(bitmap,DMS_INPUT_IMG_W,DMS_INPUT_IMG_H);
//                            byte[] data =  getNV21FromBitmap(bitmap1);
//                            onPreviewResult(data);
                        }

                        imageProxy.close(); // 最后要关闭这个
                    });

                    // 重新绑定用例前先解绑
                    mCameraPRrovider.unbindAll();

                    // 绑定用例至相机
                    //需要LifecycleOwner view
//                    mCameraPRrovider.bindToLifecycle(this, cameraSelector,
//                            imageAnalysis,preview);


                } catch (Exception e) {
                    Log.e(TAG, "用例绑定失败!" + e);
                }
            }, ContextCompat.getMainExecutor(this));

    }

    @Override
    public void onDestroy() {
        if(windowManager !=null && layoutParams !=null) {
            if(bSetup){
                windowManager.removeView(displayView);
                bSetup = false ;
                isStarted = false;
            }
        }
        super.onDestroy();

    }

    private class FloatingOnTouchListener implements View.OnTouchListener {
        private int x;
        private int y;

        @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 true;
        }
    }
}

//生命周期上的区别

//执行startService时,Service会经历onCreate->onStartCommand。当执行stopService时,直接调用onDestroy方法。调用者如果没有stopService,Service会一直在后台运行,下次调用者再起来仍然可以stopService。

//执行bindService时,Service会经历onCreate->onBind。这个时候调用者和Service绑定在一起。调用者调用unbindService方法或者调用者Context不存在了(如Activity被finish了),Service就会调用onUnbind->onDestroy。这里所谓的绑定在一起就是说两者共存亡了。


**3 运行结果**
视屏地址自行修改,当前地址瞎写,所以播放不出
![在这里插入图片描述](https://img-blog.csdnimg.cn/bae22975ec154dd8ab728bffc5a28503.png)

**4下章讲述悬浮在当前窗口上**





  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值