今天这里贴出从应用层传出一个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~