android开发浅谈之窗口管理Z-Order

问题的描述:

软件版本为android 10.0, 测试提了一个bug,手机在不分屏时在输入法界面,toast正常显示;但是手机在分屏时,因为显示了输入法界面,toast虽然调用了,但是被输入法界面遮挡看不到。

问题分析:

那这个明显是窗口z-order管理问题,那我们先看看window的dumpsys信息:

adb shell dumpsys window windows

输入法window:

  Window #0 Window{1ac9429 u0 InputMethod}:
    mDisplayId=0 stackId=0 mSession=Session{805d144 3396:u0a10092} mClient=android.os.BinderProxy@7030cf3
    mOwnerUid=10092 mShowToOwnerOnly=true package=com.iflytek.inputmethod.custom appop=NONE
    mAttrs={(0,0)(fillxfill) gr=BOTTOM CENTER_VERTICAL sim={adjust=pan} ty=INPUT_METHOD fmt=TRANSPARENT wanim=0x1030315
      fl=NOT_FOCUSABLE LAYOUT_IN_SCREEN SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
      vsysui=LIGHT_NAVIGATION_BAR}
    Requested w=1920 h=1392 mLayoutSeq=1907
    mIsImWindow=true mIsWallpaper=false mIsFloatingLayer=true mWallpaperVisible=false
    mBaseLayer=151000 mSubLayer=0    mToken=WindowToken{36e543e android.os.Binder@de717c0}

Toast window:

  Window #8 Window{d8b3a0e u0 Toast}:
    mDisplayId=0 stackId=0 mSession=Session{c221ee 5661:u0a10065} mClient=android.os.BinderProxy@5e7f510
    mOwnerUid=10065 mShowToOwnerOnly=true package=com.royole.gallery appop=TOAST_WINDOW
    mAttrs={(0,144)(wrapxwrap) gr=BOTTOM CENTER sim={adjust=pan} ty=TOAST fmt=TRANSLUCENT wanim=0x1030004
      fl=NOT_FOCUSABLE NOT_TOUCHABLE HARDWARE_ACCELERATED}
    Requested w=290 h=89 mLayoutSeq=1907
    mBaseLayer=81000 mSubLayer=0    mToken=WindowToken{4652a4 android.os.Binder@696cd37}

我们可以看到输入法界面是排第0,mBaseLayer为151000,Toast窗口是排第8,mBaseLayer=81000。

那么我们知道窗口z-order是由mBaseLayer的值决定的,其值越大,在UI界面上越显示在前面,那输入法的mBaseLayer值大于Toast的mBaseLayer值,所以Toast必然被输入法窗口遮挡。

那我们追踪一下mBaseLayer的赋值:

WindowState.mBaseLayer其赋值计算:

WindowState.WindowState

if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
    // The multiplier here is to reserve space for multiple
    // windows in the same type layer.
    mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
            * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
    mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
    mIsChildWindow = true;
    .....
} else {
    // The multiplier here is to reserve space for multiple
    // windows in the same type layer.
    mBaseLayer = mPolicy.getWindowLayerLw(this)
            * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
    mSubLayer = 0;
    mIsChildWindow = false;

其:

static final int TYPE_LAYER_MULTIPLIER = 10000;
static final int TYPE_LAYER_OFFSET = 1000;
mBaseLayer = mPolicy.getWindowLayerLw(this)
            * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;

mBaseLayer = mPolicy.getWindowLayerLw(this)* 10000 + 1000;

WindowManagerPolicy.getWindowLayerLw方法为:

default int getWindowLayerLw(WindowState win) {
    return getWindowLayerFromTypeLw(win.getBaseType(), win.canAddInternalSystemWindow());
}

default int getWindowLayerFromTypeLw(int type) {
    if (isSystemAlertWindowType(type)) {
        throw new IllegalArgumentException("Use getWindowLayerFromTypeLw() or"
                + " getWindowLayerLw() for alert window types");
    }
    return getWindowLayerFromTypeLw(type, false /* canAddInternalSystemWindow */);
}

default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {
......
    switch (type) {
        case TYPE_WALLPAPER:
            // wallpaper is at the bottom, though the window manager may move it.
            return  1;
        case TYPE_PRESENTATION:
        case TYPE_PRIVATE_PRESENTATION:
            return  APPLICATION_LAYER;
        ......
        case TYPE_SYSTEM_DIALOG:
            return  7;
        case TYPE_TOAST://可以看到Toast返回的值是8
            // toasts and the plugged-in battery thing
            return  8;
        case TYPE_PRIORITY_PHONE:
            // SIM errors and unlock.  Not sure if this really should be in a high layer.
            return  9;
        ......
        case TYPE_INPUT_METHOD://可以看到输入法返回的值是15
            // on-screen keyboards and other such input method user interfaces go here.
            return  15;
        case TYPE_INPUT_METHOD_DIALOG:
            // on-screen keyboards and other such input method user interfaces go here.
            return  16;

问题解决:

那么原因我们知道了,那来吧,将Toast返回的值修改为比输入法16大的返回值,验证一下:

case TYPE_TOAST://可以看到Toast返回的值是8
    // toasts and the plugged-in battery thing
    return  18;

验证结果是Toast正常显示,此问题打完收工。

问题拓展:

(1)window类型的定义:

frameworks\base\core\java\android\view\WindowManager.java

application types window:

public static final int FIRST_APPLICATION_WINDOW = 1;
public static final int TYPE_BASE_APPLICATION   = 1;
public static final int TYPE_APPLICATION        = 2;
public static final int TYPE_APPLICATION_STARTING = 3;
public static final int TYPE_DRAWN_APPLICATION = 4;
public static final int LAST_APPLICATION_WINDOW = 99;

sub-windows types:

public static final int FIRST_SUB_WINDOW = 1000;
public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;
public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;
public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;
public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW + 4;
public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;
public static final int LAST_SUB_WINDOW = 1999;

system-specific window types:

public static final int FIRST_SYSTEM_WINDOW     = 2000;
public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;
public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;
public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;
public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;
public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;
public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;
public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;
public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;
public static final int TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8;
public static final int TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9;
public static final int TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10;
public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;
public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;
public static final int TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14;
public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;
public static final int TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16;
public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;
public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;
public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;
public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;
public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;
public static final int TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22;
public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;
public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;
public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;
public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;
public static final int TYPE_PRIVATE_PRESENTATION = FIRST_SYSTEM_WINDOW+30;
public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;
public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;
public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33;
public static final int TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34;
public static final int TYPE_QS_DIALOG = FIRST_SYSTEM_WINDOW+35;
public static final int TYPE_SCREENSHOT = FIRST_SYSTEM_WINDOW + 36;
public static final int TYPE_PRESENTATION = FIRST_SYSTEM_WINDOW + 37;
public static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38;
public static final int LAST_SYSTEM_WINDOW      = 2999;
public static final int INVALID_WINDOW_TYPE = -1;

(2)WindowManagerPolicy.getWindowLayerFromTypeLw的调用堆栈:

PhoneWindowManager.canBeHiddenByKeyguardLw–判断window是否可以被锁屏界面隐藏

WindowManagerPolicy: 	at com.android.server.policy.WindowManagerPolicy.getWindowLayerFromTypeLw(WindowManagerPolicy.java:809)
WindowManagerPolicy: 	at com.android.server.policy.WindowManagerPolicy.getWindowLayerFromTypeLw(WindowManagerPolicy.java:790)
WindowManagerPolicy: 	at com.android.server.policy.PhoneWindowManager.canBeHiddenByKeyguardLw(PhoneWindowManager.java:2661)
WindowManagerPolicy: 	at com.android.server.policy.PhoneWindowManager.applyKeyguardPolicyLw(PhoneWindowManager.java:3915)
WindowManagerPolicy: 	at com.android.server.wm.DisplayPolicy.applyPostLayoutPolicyLw(DisplayPolicy.java:2768)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent.lambda$new$7$DisplayContent(DisplayContent.java:801)
WindowManagerPolicy: 	at com.android.server.wm.-$$Lambda$DisplayContent$JibsaX4YnJd0ta_wiDDdSp-PjQk.accept(Unknown Source:4)
WindowManagerPolicy: 	at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:1189)
WindowManagerPolicy: 	at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:1179)
WindowManagerPolicy: 	at com.android.server.wm.WindowState.applyInOrderWithImeWindows(WindowState.java:4380)
WindowManagerPolicy: 	at com.android.server.wm.WindowState.forAllWindows(WindowState.java:4279)
WindowManagerPolicy: 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:888)
WindowManagerPolicy: 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:888)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent.forAllWindows(DisplayContent.java:2357)
WindowManagerPolicy: 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:905)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent.applySurfaceChangesTransaction(DisplayContent.java:3953)
WindowManagerPolicy: 	at com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction(RootWindowContainer.java:833)
WindowManagerPolicy: 	at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:610)
WindowManagerPolicy: 	at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:567)
WindowManagerPolicy: 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:159)
WindowManagerPolicy: 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:105)
WindowManagerPolicy: 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:95)
WindowManagerPolicy: 	at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:5108)

WindowToken.canLayerAboveSystemBars–判断window是否可以显示在systembar上

WindowManagerPolicy: 	at com.android.server.policy.WindowManagerPolicy.getWindowLayerFromTypeLw(WindowManagerPolicy.java:809)
WindowManagerPolicy: 	at com.android.server.wm.WindowToken.canLayerAboveSystemBars(WindowToken.java:338)
WindowManagerPolicy: 	at com.android.server.wm.WindowState.skipDecorCrop(WindowState.java:4664)
WindowManagerPolicy: 	at com.android.server.wm.WindowState.calculatePolicyCrop(WindowState.java:4684)
WindowManagerPolicy: 	at com.android.server.wm.WindowStateAnimator.calculateCrop(WindowStateAnimator.java:797)
WindowManagerPolicy: 	at com.android.server.wm.WindowStateAnimator.setSurfaceBoundariesLocked(WindowStateAnimator.java:870)
WindowManagerPolicy: 	at com.android.server.wm.WindowStateAnimator.prepareSurfaceLocked(WindowStateAnimator.java:1095)
WindowManagerPolicy: 	at com.android.server.wm.WindowState.prepareSurfaces(WindowState.java:5095)
WindowManagerPolicy: 	at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:1218)
WindowManagerPolicy: 	at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:1218)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent$NonAppWindowContainers.prepareSurfaces(DisplayContent.java:5022)
WindowManagerPolicy: 	at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:1218)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent.prepareSurfaces(DisplayContent.java:5180)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent.applySurfaceChangesTransaction(DisplayContent.java:3973)
WindowManagerPolicy: 	at com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction(RootWindowContainer.java:833)
WindowManagerPolicy: 	at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:610)
WindowManagerPolicy: 	at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:567)
WindowManagerPolicy: 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:159)
WindowManagerPolicy: 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:105)
WindowManagerPolicy: 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:95)
WindowManagerPolicy: 	at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:5108)

DisplayContent.addWindowToken–添加windowtoken时调用

WindowManagerPolicy: 	at com.android.server.policy.WindowManagerPolicy.getWindowLayerFromTypeLw(WindowManagerPolicy.java:809)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent$NonAppWindowContainers.lambda$new$0$DisplayContent$NonAppWindowContainers(DisplayContent.java:4927)
WindowManagerPolicy: 	at com.android.server.wm.-$$Lambda$DisplayContent$NonAppWindowContainers$nqCymC3xR9b3qaeohnnJJpSiajc.compare(Unknown Source:6)
WindowManagerPolicy: 	at com.android.server.wm.WindowContainer.addChild(WindowContainer.java:230)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent$NonAppWindowContainers.addChild(DisplayContent.java:4952)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent.addWindowToken(DisplayContent.java:1078)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent.reParentWindowToken(DisplayContent.java:1112)
WindowManagerPolicy: 	at com.android.server.wm.WindowToken.onDisplayChanged(WindowToken.java:263)
WindowManagerPolicy: 	at com.android.server.wm.WindowToken.<init>(WindowToken.java:124)
WindowManagerPolicy: 	at com.android.server.wm.WindowToken.<init>(WindowToken.java:110)
WindowManagerPolicy: 	at com.android.server.wm.WindowManagerService.addWindowToken(WindowManagerService.java:2608)
WindowManagerPolicy: 	at com.android.server.wm.WindowManagerService$LocalService.addWindowToken(WindowManagerService.java:7524)
WindowManagerPolicy: 	at com.android.server.notification.NotificationManagerService$10.enqueueToast(NotificationManagerService.java:2375)
WindowManagerPolicy: 	at android.app.INotificationManager$Stub.onTransact(INotificationManager.java:1114)
WindowManagerPolicy: 	at android.os.Binder.execTransactInternal(Binder.java:1021)
WindowManagerPolicy: 	at android.os.Binder.execTransact(Binder.java:994)

WindowContainer.assignChildLayers–处理子layer时调用

WindowManagerPolicy: 	at com.android.server.policy.WindowManagerPolicy.getWindowLayerFromTypeLw(WindowManagerPolicy.java:809)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent$AboveAppWindowContainers.assignChildLayers(DisplayContent.java:4899)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent$AboveAppWindowContainers.assignChildLayers(DisplayContent.java:4878)
WindowManagerPolicy: 	at com.android.server.wm.WindowContainer.assignChildLayers(WindowContainer.java:1129)
WindowManagerPolicy: 	at com.android.server.wm.WindowContainer.onParentChanged(WindowContainer.java:199)
WindowManagerPolicy: 	at com.android.server.wm.WindowContainer.setParent(WindowContainer.java:170)
WindowManagerPolicy: 	at com.android.server.wm.WindowContainer.addChild(WindowContainer.java:247)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent$NonAppWindowContainers.addChild(DisplayContent.java:4952)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent.addWindowToken(DisplayContent.java:1078)
WindowManagerPolicy: 	at com.android.server.wm.DisplayContent.reParentWindowToken(DisplayContent.java:1112)
WindowManagerPolicy: 	at com.android.server.wm.WindowToken.onDisplayChanged(WindowToken.java:263)
WindowManagerPolicy: 	at com.android.server.wm.WindowToken.<init>(WindowToken.java:124)
WindowManagerPolicy: 	at com.android.server.wm.WindowToken.<init>(WindowToken.java:110)
WindowManagerPolicy: 	at com.android.server.wm.WindowManagerService.addWindowToken(WindowManagerService.java:2608)
WindowManagerPolicy: 	at com.android.server.wm.WindowManagerService$LocalService.addWindowToken(WindowManagerService.java:7524)
WindowManagerPolicy: 	at com.android.server.notification.NotificationManagerService$10.enqueueToast(NotificationManagerService.java:2375)
WindowManagerPolicy: 	at android.app.INotificationManager$Stub.onTransact(INotificationManager.java:1114)
WindowManagerPolicy: 	at android.os.Binder.execTransactInternal(Binder.java:1021)
WindowManagerPolicy: 	at android.os.Binder.execTransact(Binder.java:994)

(3)WindowState.mSubLayer–子窗口

计算方法为:
WindowState.WindowState

mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);

WindowManagerPolicy.getSubWindowLayerFromTypeLw

/**
 * Return how to Z-order sub-windows in relation to the window they are attached to.
 * Return positive to have them ordered in front, negative for behind.
 *
 * @param type The sub-window type code.
 *
 * @return int Layer in relation to the attached window, where positive is
 *         above and negative is below.
 */
default int getSubWindowLayerFromTypeLw(int type) {
    switch (type) {
        case TYPE_APPLICATION_PANEL:
        case TYPE_APPLICATION_ATTACHED_DIALOG:
            return APPLICATION_PANEL_SUBLAYER;//1
        case TYPE_APPLICATION_MEDIA:
            return APPLICATION_MEDIA_SUBLAYER;//-2
        case TYPE_APPLICATION_MEDIA_OVERLAY:
            return APPLICATION_MEDIA_OVERLAY_SUBLAYER;//-1
        case TYPE_APPLICATION_SUB_PANEL:
            return APPLICATION_SUB_PANEL_SUBLAYER;//2
        case TYPE_APPLICATION_ABOVE_SUB_PANEL:
            return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER;//3
    }
    Slog.e("WindowManager", "Unknown sub-window type: " + type);
    return 0;
}

从注解可以看出返回正数就显示在前面,返回负数就显示在后面。

WindowManagerPolicyConstants.java

int APPLICATION_LAYER = 2;
int APPLICATION_MEDIA_SUBLAYER = -2;
int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
int APPLICATION_PANEL_SUBLAYER = 1;
int APPLICATION_SUB_PANEL_SUBLAYER = 2;
int APPLICATION_ABOVE_SUB_PANEL_SUBLAYER = 3;
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hfreeman2008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值