android底层实现鼠标状态的图标

今天这里贴出从应用层传出一个id或图片byte[]数组,通过aidl与service交互调用JNI,最后到Cursor.c实现画不同状态的光标。下面就给出Cursor.c的实现画图,前面的过程就不全给出了:

Cursor.c

#include <stdio.h>
#include <sys/mman.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include <linux/fb.h>
#include <hifb.h>

#include <cutils/ashmem.h>
#include <cutils/log.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include "hardware_legacy/cursor.h"

#define LOG_TAG "CursorHW"

typedef struct{
	int id;
	int width;
	int height;
	char *buf;
}CURSOR_BITMPA_S;

static CURSOR_BITMPA_S g_cursor_data[ID_MAX_BITMAP_NO];

static char g_cursor_name[ID_MAX_BITMAP_NO][32] = {
	"cursor_normal.bmp",
	"cursor_help.bmp",
	"cursor_bg.bmp",
	"cursor_busy.bmp",
	"cursor_accpos.bmp",
	"cursor_edit.bmp",
	"cursor_wait.bmp",
	"cursor_handwrite.bmp",
	"cursor_link.bmp",
	"cursor_disable.bmp",
};

static int s_cursorfd = -1;

//光标的绝对位置
static int s_cursor_x = 0;
static int s_cursor_y = 0;
static int s_screen_width = 0;

static int  s_memp_size = 0;
static char *s_memp_start = NULL;

#define CHECK_FD() do { if (s_cursorfd < 0) return -1; } while(0) 

#define HI_CURSOR_W  	32
#define HI_CURSOR_H  	32
#define HI_CURSOR_BPP 	32
#define HI_CURSOR_STRIDE (HI_CURSOR_BPP*HI_CURSOR_W/8)

static char s_Cursordata[12*20*4] = 
{
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, \
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, \
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, \
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, \
};

static int cursor_load_bitmap(int id);
static int cursor_unload_bitmap();

int cursor_open()
{
    int size = 0;
    int i;
    HIFB_ALPHA_S as;
    struct fb_fix_screeninfo finfo;
    struct fb_var_screeninfo info;

    /*我们让光标显示在高清图层,为了DDMS截图正确*/
    int fd = open("/dev/graphics/fb2", O_RDWR, 0);
    if(fd > 0)
    {
        LOGI("open fb0 ok. fd=%d\n", fd);
    }
    else
    {
        LOGE("open fb error:\n");
        return 1;
    }
    
    if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
    {
        LOGE("info error.\n");
        goto quit;
    }

    //设置光标大小,像素格式
    info.xres = info.xres_virtual = 12;
    info.yres = info.yres_virtual = 20;
    info.bits_per_pixel = HI_CURSOR_BPP;

    info.transp.length = 8;
    info.transp.msb_right = 0;
    info.transp.offset = 24;

    info.red.length = 8;
    info.red.msb_right = 0;
    info.red.offset = 16;

    info.green.length = 8;
    info.green.msb_right = 0;
    info.green.offset = 8;

    info.blue.length = 8;
    info.blue.msb_right = 0;
    info.blue.offset = 0;
	
    if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1)
    {
        LOGE("info error.\n");
        goto quit;
    }

    if (ioctl(fd, FBIOGET_ALPHA_HIFB, &as) < 0)
    {
        LOGE("get alpha error.\n");
        goto quit;
    }

    as.bAlphaEnable = HI_TRUE;
    if (ioctl(fd, FBIOPUT_ALPHA_HIFB, &as) < 0)
    {
        LOGE("get alpha error.\n");
        goto quit;
    }

    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
    {
        LOGE("finfo error.\n");
        goto quit;
    }
	
    //size = info.xres * info.yres * info.bits_per_pixel/8;  //----->12*20*32/8=960
    size = finfo.smem_len;
	LOGI("*******size = %d*******", size);
    s_memp_start = (char*)mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if((char*)-1 == s_memp_start)
    {
        LOGE("mmap error:\n");
        goto quit;
    }

    s_memp_size = size;
    s_cursorfd = fd;
    s_screen_width = finfo.line_length;
	
    //copy 光标位图到framebuffer上
    cursor_set_visible(0);

    memset(s_memp_start, 0x0, size);
    
    for (i= 0; i<20; i++)
	{
	   memcpy(s_memp_start + i*s_screen_width, s_Cursordata + 48*i, 48);
	}
	
    cursor_set_visible(1);
	
    return 0;
  
quit:
    cursor_close();
    return -1;    
}

int cursor_close()
{
   if (s_cursorfd > 0)
   {
   	  close(s_cursorfd);
	  s_cursorfd = -1;
   }
   
   cursor_unload_bitmap();
   
   return 0;
}

int cursor_set_visible(int flag)
{
	CHECK_FD();
	
    //需要考虑范围不要超过屏幕 todo
	
    if (ioctl(s_cursorfd, FBIOPUT_SHOW_HIFB, &flag) < 0)
    {
       LOGE("failed to %s cursor! \n", flag ? "show":"hide");
    }

   return 0;     
}

int cursor_set_sharp(const char *buf,int w,int h)
{
	int i=0;
    int width=w,height=h;
    char *buffer = (char*)buf;
    char *start = s_memp_start;

    if(width > HI_CURSOR_W)
        width = HI_CURSOR_W;

    if(height > HI_CURSOR_H)
        height = HI_CURSOR_H;

	LOGI("width=%d,height=%d",width,height);

	/* 1、先将光标隐藏掉 */
    cursor_set_visible(0);

    /* 2、将光标数据定入到fb中进行显示(操作共享区) */
	
    memset(s_memp_start, 0x00, s_memp_size);
    for (i=0; i<HI_CURSOR_H; i++)
	{
	   memcpy(s_memp_start + i*s_screen_width, buf + HI_CURSOR_STRIDE*i, HI_CURSOR_STRIDE);
	}
	
    /* 3、将光标重新显示 */
    cursor_set_visible(1);
    
    return 0;
}

int cursor_set_sharpID(const int id)
{
	int ret = -1;

	LOGI("cursor_set_sharpID:cursor_set_sharpID param: id=%d",id);

	if(id < 0 || id > ID_DISABLE_BITMAP){
		LOGE("cursor_set_sharpID error param: id=%d",id);
		return -1;
	}
	
	ret = cursor_load_bitmap(id);
	if(ret < 0){
		LOGE("cursor_load_bitmap load bitmap failed(id = %d)",id);
		return -1;
	}

	ret = cursor_set_sharp(g_cursor_data[id].buf,g_cursor_data[id].width,g_cursor_data[id].height);
	if(ret < 0){
		LOGE("cursor_set_sharpID set sharp failed");
		return -1;
	}
	
	return ret;
}

static int cursor_bitmpa_format_convert(CURSOR_BITMPA_S *cs,char *src){
	int i ,j ;
	int width = cs->width,height = cs->height;
	char *psrc = src ;
	char *pdst = cs->buf;
	char *p = psrc;
	int value = 0x00;

	/* 由于bmp存储是从后面往前面,所以需要倒序进行转换 */
	pdst += (width * height * 4);
	for(i=0;i<height;i++){
		p = psrc + (i+1) * width * 3;
		for(j=0;j<width;j++){
			pdst -= 4;
			p -= 3;
			pdst[0] = p[0];
			pdst[1] = p[1];
			pdst[2] = p[2];
			//pdst[3] = 0x00;

			value = *((int*)pdst);
			value = pdst[0];
			if(value == 0x00){
				pdst[3] = 0x00;
			}else{
				pdst[3] = 0xff;
			}
		}
	}

	return 0;
}



static int cursor_load_util_read(FILE *fp,char *buf,int len){
	int ret;
	if (len <= 0)
		return len;

	while ((ret = fread(buf,1,len,fp)) >= 0) {
		if (ret == 0) {
			cursor_sleep_millis(1);
			continue;
		}
		if ((len -= ret) == 0)
			return 0;
		buf = ((char*) buf) + ret;
	}
	return -1;
}

static int cursor_load_bitmap(int id){
	int ret = -1;
	char *cursor_path = "/system/usr/cursor";
	char file_path[128];
	FILE *fp = NULL;
	char bmp_header[54];
	int  flen , total_length = 0;
	char *bmp_buf = NULL;
	int n = 0;

	if(g_cursor_data[id].buf != NULL){
		LOGV("cursor_load_bitmap already load,success!");
		return 0;
	}

	memset(bmp_header,0x00,sizeof(bmp_header));

	/* 读取位图的前面开始的54字节数据 */
	snprintf(file_path,128,"%s/%s",cursor_path,g_cursor_name[id]);
	LOGI("file path = %s",file_path);

	fp = fopen(file_path,"rb");
	if(fp == NULL){
		LOGE("load > cursor file open failed");
		return -1;
	}

	/* 求解文件长度 */
	fseek(fp,0,SEEK_SET);
	fseek(fp,0,SEEK_END);
	flen = ftell(fp);

	bmp_buf = (char*)calloc(1,flen - 54);
	if(bmp_buf == NULL){
		LOGE("load > malloc bmp out of memory!");
		goto BAIL;
	}

	/* 再移位到文件头部 */
	fseek(fp,0,SEEK_SET);

	n = fread(bmp_header,1,54,fp);
	if(n != 54){
		LOGE("load > read bmp header failed failed");
		goto BAIL;
	}

	g_cursor_data[id].width  = bmp_header[18];
	g_cursor_data[id].height = bmp_header[22];
	LOGV("cursor_load_bitmap:load > bmp width = %d,heigth = %d",g_cursor_data[id].width,g_cursor_data[id].height);

	/* 24位位图 */
	total_length = g_cursor_data[id].width * g_cursor_data[id].height * 3;
	ret = cursor_load_util_read(fp,bmp_buf,total_length);
	if(ret != 0) {
		LOGE("load > read bmp body data failed");
		goto BAIL;
	}

	/* 32位显示 */
	total_length = g_cursor_data[id].width * g_cursor_data[id].height * 4;
	g_cursor_data[id].buf = (char*)calloc(1,total_length);
	if(g_cursor_data[id].buf == NULL){
		LOGE("load > malloc curosr buf failed");
		goto BAIL;
	}

	ret = cursor_bitmpa_format_convert(&g_cursor_data[id],bmp_buf);
	if(ret < 0){
		LOGE("load > convert bmp to cursor data failed");
		goto BAIL;
	}

	g_cursor_data[id].id = id;

	if(bmp_buf != NULL){
		free(bmp_buf);
		bmp_buf = NULL;
	}

	if(fp != NULL){
		fclose(fp);
		fp = NULL;
	}

	LOGI("cursor_load_bitmap:load > load bitmap success");
	return 0;

BAIL:
	if(bmp_buf != NULL){
		free(bmp_buf);
		bmp_buf = NULL;
	}

	if(fp != NULL){
		fclose(fp);
		fp = NULL;
	}

	LOGE("cursor_load_bitmap load bitmap failed");
	return -1;
}

static int cursor_unload_bitmap(){
	int i = 0,rid = -1;
	
	for(i=0;i<ID_MAX_BITMAP_NO;i++){
		rid = g_cursor_data[i].id;
		if(rid < 0)
			continue;
		
		g_cursor_data[i].id = -1;
		free(g_cursor_data[i].buf);
		g_cursor_data[i].buf = NULL;
	}
	
	return 0;
}

 注:

1.图片为32*32*24的bmp位图,字节长位3126byte,前54byte为头部信息,其中第16-19个和20-23个字节位为长和高

2.因为这里定义的是32位有透明色的位图,所以加载的24位位图需要转换成32位的-- cursor_bitmpa_format_convert这个方法

3.android java层也可以解析位图,然后传byte[]数据下来,cursor里面直接读取位图byte[]数据。android中的解析方法如下:

 

private void loadBmpData(){
		pic_Curs=new Pic_Cur[10];
		String[] cur_name=new String[]{
	    		"cursor_normal.bmp",
	    		"cursor_help.bmp",
	    		"cursor_bg.bmp",
	    		"cursor_busy.bmp",
	    		"cursor_accpos.bmp",
	    		"cursor_edit.bmp",
	    		"cursor_wait.bmp",
	    		"cursor_handwrite.bmp",
	    		"cursor_link.bmp",
	    		"cursor_disable.bmp"
	    };
		for(int i=0;i<pic_Curs.length;i++){
			String cur_path="/res/drawable-mdpi/"+cur_name[i];		
			try {
				InputStream in = getClass().getResourceAsStream(cur_path);
				// 获取文件的字节数
				int length = in.available();
				//System.out.println(length+"--bmp--"+i);
				// 创建byte数组
				byte[] buffer = new byte[length];
				// 将文件中的数据读到byte数组中
				in.read(buffer);
				pic_Curs[i]=new Pic_Cur();//初始化对象
				//在前54个字节中第16-19个和第20-23个字节表示长和宽
				int width=buffer[18];
				pic_Curs[i].setWidth(width);
				int height=buffer[22];
				pic_Curs[i].setHeight(height);
				//System.out.println("width is:"+pic_Curs[i].getWidth()+"height is:"+pic_Curs[i].getHeight());
				//buffer第54个后的为图像数据
				byte[] by1=Arrays.copyOfRange(buffer, 54, buffer.length);
				
				//24位图转32位,由于bmp存储是从后面往前面,所以需要倒序进行转换
				byte[] by2=new byte[width*height*4];
				for(int j=0;j<height;j++){
					for(int k=0;k<width;k++){
						by2[(height-j-1)*width*4+4*k]=by1[(j*width*3+3*k)];
						by2[(height-j-1)*width*4+4*k+1]=by1[(j*width*3+3*k+1)];
						by2[(height-j-1)*width*4+4*k+2]=by1[(j*width*3+3*k+2)];
						if(by2[(height-j-1)*width*4+4*k]==(byte) 0x00 &&
								by2[(height-j-1)*width*4+4*k+1]==(byte) 0x00 &&
								by2[(height-j-1)*width*4+4*k+2]==(byte) 0x00){
							by2[(height-j-1)*width*4+4*k+3]=(byte) 0x00;
						}else{
							by2[(height-j-1)*width*4+4*k+3]=(byte) 0xff;
						}
					}
				}			
				//System.out.println("data length is:"+by1.length+"buf length is:"+by2.length);
				
				pic_Curs[i].setCur_data(by2);
			} catch (Exception e) {
				e.printStackTrace();
			}

		}
		
	}

 中间省略aidl与service的交互、jni调用等;之后会在cursor.c里的

int cursor_set_sharp(const char *buf,int w,int h)

 把光标显示出来

注:bmp位图可以参考后面的一篇文章:bmp位图分析

……O(∩_∩)O~

转载于:https://my.oschina.net/blackylin/blog/71648

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值