当前位置:  编程技术>移动开发
本页文章导读:
    ▪Qualcomm 8X camera daemon过程浅析        Qualcomm 8X camera daemon进程浅析 Camera 先看一下抽象层的主要流程: 首先启动一个守护进程 Main()(camdaemon.c) int qcamsvr_start(void)( qcamsvr.c) { 1.        server_fd = open(server_dev_name, O_RDWR);//打开服务对.........
    ▪ 挪动浏览器的开发会更加容易吗?—— Chrome 中的 content 模块        移动浏览器的开发会更加容易吗?—— Chrome 中的 content 模块 在编译运行了 android 版本的 content shell 之后,觉得Google 的意图是打造一个基本的基于多进程沙盒模型的浏览器雏形,也就是 conte.........
    ▪ PhoneGap 创办XCode工程       PhoneGap 创建XCode工程猴子原创,欢迎转载。转载请注明: 转载自Cocos2D开发网--Cocos2Dev.com,谢谢!原文地址: http://www.cocos2dev.com/?p=386今天有人问我PhoneGap怎么创建iOS程序,我记得去年写过一个.........

[1]Qualcomm 8X camera daemon过程浅析
    来源: 互联网  发布时间: 2014-02-18
Qualcomm 8X camera daemon进程浅析

Camera

先看一下抽象层的主要流程:

首先启动一个守护进程

Main()(camdaemon.c)

int qcamsvr_start(void)( qcamsvr.c)

{

1.        server_fd = open(server_dev_name, O_RDWR);//打开服务对应的文件节点

2.        if (mctl_load_comps()) //加载所有需要的组件

3.        rc = qcamsvr_load_gesture_lib(&gesture_info.gesture_lib);//加载手势库

4.        ez_server_socket_id = eztune_setup_server("127.0.0.1", "55555");

if (pipe(ez_cmd_pipe)

ez_prev_server_socket_id = eztune_setup_server("127.0.0.1", "55556");

if(pipe(ez_prev_cmd_pipe)

//创建两个socket端口,同时建立两个pipe文件对两个端口进行监控

5.        if (get_mctl_node_info(server_fd, &mctl_node_info))//通过服务节点获取服务的相关信息

{

//此处获取的是内核中调用msm_sensor_register()注册的sensor节点信息

}

6.        sub.type = V4L2_EVENT_ALL;

rc = ioctl(server_fd, VIDIOC_SUBSCRIBE_EVENT, &sub);//通过服务设备文件的ioctl接口,订阅所有的事件

7. config_arg.server_fd = server_fd;

  config_arg.ez_read_fd = ez_cmd_pipe[0];

  config_arg.ez_write_fd = ez_cmd_pipe[1];

  config_arg.ez_prev_read_fd = ez_prev_cmd_pipe[0];

  config_arg.ez_prev_write_fd = ez_prev_cmd_pipe[1];//初始化配置线程的参数

8.下面就是一个循环,对这几个文件进行poll

   do {

    fds[0].fd = server_fd;

    fds[0].events = POLLPRI;

    fds[1].fd = ez_server_socket_id;

    fds[1].events = POLLIN;

    fds[2].fd = ez_prev_server_socket_id;

    fds[2].events = POLLIN;

    rc = poll(fds, 3, timeoutms);

if (fds[0].revents & POLLPRI) { /* Server Node Wake Up *

 //对服务的设备文件进行监视,当遇到打开事件的时候,立即创建一个配置线程

      rc = qcamsvr_process_server_node_event(&config_arg, &mctl_node_info,

         &gesture_info);

}

//线面就是对两个socket进程监视和处理。

     if ((fds[1].revents & POLLIN) == POLLIN) { /* EzTune Server */

        int client_socket_id;

        client_socket_id = accept(ez_server_socket_id,

          (struct sockaddr *)&addr_client_inet, &addr_client_len);

          write(ez_cmd_pipe[1], &client_socket_id, sizeof(int));

        }

      }

 

      if ((fds[2].revents & POLLIN) == POLLIN) { /* EzTune Prev Server */

        int client_socket_id;

        client_socket_id = accept(ez_prev_server_socket_id,

          (struct sockaddr *)&addr_client_inet, &addr_client_len);

          write(ez_prev_cmd_pipe[1], &client_socket_id, sizeof(int));

        }

      }

    } /* Else for Poll rc */

  } while (1);

}

 

下面进入配置线程创建的流程:

   //取出服务节点产生的事件,然后根据配置节点的名称,分发给各自独立的主控制线程

1.        static int qcamsvr_process_server_node_event()

{

//下命令让服务模块的事件出队列进行处理

rc = ioctl(config_arg->server_fd, VIDIOC_DQEVENT, &v4l2_evt);

if (v4l2_evt.type == V4L2_EVENT_PRIVATE_START + MSM_GES_RESP_V4L2)

{

//如果是手势事件,则进行一系列的处理

if (ctrl->type == MSM_V4L2_GES_OPEN) {

//设置主控线程的接口

p_gesture_info->cam_mctl.svr_ops.launch_mctl_thread =

          create_v4l2_conf_thread;

//设置主控线程的退出接口

p_gesture_info->cam_mctl.svr_ops.release_mctl_thread =

          destroy_v4l2_cam_conf_thread;

//设置camera使能

p_gesture_info->cam_mctl.svr_ops.camera_available =

          qcamsvr_camera_available;

    //设置服务设备文件的文件句柄

p_gesture_info->cam_mctl.svr_ops.server_fd = config_arg->server_fd;

//创建手势服务

 status = p_gesture_info->gesture_lib.gesture_service_create(

          &p_gesture_info->cam_mctl, &p_gesture_info->observer);

}

else if (ctrl->type == MSM_V4L2_GES_CLOSE) {

//消亡手势服务

status = p_gesture_info->gesture_lib.gesture_service_send_data(ctrl)

}

if ((status == CAMERA_SUCCESS) &&

        (ctrl->type != MSM_V4L2_GES_CLOSE)) {

        //如果成功,且文件打开,则向手势服务发送数据

status = p_gesture_info->gesture_lib.gesture_service_send_data(ctrl);

        if (status != CAMERA_SUCCESS) {

          LOGE("gesture_service_send_data failed");

        }

 } else {

        if (ctrl->type == MSM_V4L2_GES_CLOSE) {

          ctrl->status = CAM_CTRL_SUCCESS;

        } else {

          LOGE("gesture send failure message");

          ctrl->status = CAM_CTRL_FAILED;

        }

//将操作结果反馈给camera服务

v4l2_ioctl.ioctl_ptr = ctrl;

qcamsvr_send_ctrl_cmd_done(config_arg->server_fd, &v4l2_ioctl);

//如果是camera事件,则进行一系列的处理

}

else if (v4l2_evt.type == V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_V4L2)

{

if (ctrl->type == MSM_V4L2_OPEN) {

//通过pipe进行一些初始化工作

//创建一个核心的线程

if ((tmp_mctl_struct->handle =

          create_v4l2_conf_thread(config_arg)) == NULL)

//反馈结果给camera服务端

ctrl->status = CAM_CTRL_SUCCESS;

        v4l2_ioctl.ioctl_ptr = ctrl;

        qcamsvr_send_ctrl_cmd_done(config_arg->server_fd, &v4l2_ioctl);

}

else if (ctrl->type == MSM_V4L2_CLOSE){

//进行一些消亡工作

//通过写一些pipe

if (destroy_v4l2_cam_conf_thread(tmp_mctl_struct->handle) < 0) //消亡只线程

ctrl->status = CAM_CTRL_SUCCESS;

        v4l2_ioctl.ioctl_ptr = ctrl;

//反馈结果给camera服务

qcamsvr_send_ctrl_cmd_done(config_arg->server_fd, &v4l2_ioctl);

}

else {

//通过pipe写一些命令,等待配置返回

}

}

 

//首先来看一下刚刚的线程创建函数

void *create_v4l2_conf_thread(struct config_thread_arguments* arg)

{

//核心工作就是创建了个线程

rc = pthread_create(&pme->cam_mctl_thread_id, NULL, cam_mctl_thread, pme);

}

//下面进入创建的配置线程的主函数:

static void *cam_mctl_thread(void *data)(mctl.c)

{

//首先初始化需要监控的文件句柄

  pipe_readfd = arg->read_fd;

  pipe_writefd = arg->write_fd;

  server_fd = arg->server_fd;

  ez_pipe_readfd = arg->ez_read_fd;

  ez_client_fd = -1;

  ez_prev_pipe_readfd = arg->ez_prev_read_fd;

  ez_prev_client_fd = -1;

//向对应的配置节点下命令监控所有事件(此文件句柄具体标识什么意思暂时还没搞清楚)

sub.type = V4L2_EVENT_ALL;

rc = ioctl(cam_fd, VIDIOC_SUBSCRIBE_EVENT, &sub);

//下面开始进入循环的监控

do {

    //文件句柄初始化

    fds[0].fd = cam_fd;

    fds[0].events = POLLPRI;

    fds[1].fd = pipe_readfd;

    fds[1].events = POLLPRI | POLLIN;

    fds[2].fd = ez_pipe_readfd;

    fds[2].events = POLLIN;

    fds[3].fd = ez_client_fd;

    fds[3].events = POLLIN;

    fds[4].fd = ez_prev_pipe_readfd;

    fds[4].events = POLLIN;

    fds[5].fd = ez_prev_client_fd;

fds[5].events = POLLIN;

/* evt/msg from qcam server */

if (ctrl->type == MSM_V4L2_CLOSE) {

//关闭所有的资源

config_shutdown_pp(pme->p_cfg_ctrl);

//反馈结果给服务

rc = mctl_send_ctrl_cmd_done(pme->p_cfg_ctrl, NULL, TRUE);

}

else {

     //此函数为用户控件的APP处理对应的命令

     if (mctl_proc_v4l2_request(pme, ctrl) < 0)

}

/* evt/msg from config node */

rc = ioctl(cam_fd, VIDIOC_DQEVENT, &v4l2_event);//下事件出队列的命令

if (v4l2_event.type ==

            V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_DIV_FRAME_EVT_MSG) {

//进程对应的帧转移

mctl_pp_divert_frame(p_cfg_ctrl,

              (void *)&(event_data.isp_data.div_frame));

}else if(v4l2_event.type ==

            V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_MCTL_PP_EVENT) {

//处理后置的事件

mctl_pp_proc_event(p_cfg_ctrl,

              (void *)&(event_data.isp_data.pp_event_info));

}

else if (v4l2_event.type ==

            V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_STAT_EVT_MSG) {

//处理正常的事件消息

mctl_proc_event_message (pme, isp_adsp);

}

else {

            CDBG_HIGH("%s: Error: should not be here", __func__);

}

 

/* evt/msg from eztune pipe */

if (ez_client_fd > 0)

        mctl_eztune_server_connect(pme, ez_client_fd);

/* evt/msg from eztune client */

if (ez_client_fd > 0) {

mctl_eztune_read_and_proc_cmd(EZ_MCTL_SOCKET_CMD);

 

/* evt/msg from eztune prev pipe */

if (ez_prev_client_fd > 0)

          mctl_eztune_prev_server_connect(pme, ez_prev_client_fd);

      }

 

/* evt/msg from eztune prev client */

 if ((fds[5].revents & POLLIN) == POLLIN) {

        if (ez_prev_client_fd > 0) {

         mctl_eztune_read_and_proc_cmd(EZ_MCTL_PREV_SOCKET_CMD);

        }

        }

}wile(TRUE)

//循环结束取消订阅所有消息

if (ioctl(cam_fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub) < 0)

}

先来看看camera在硬件抽象层的接口:

主要是三点:

1.        preview:预览

2.        recording 录像

3.        picture 拍照

模块接口函数:

  get_number_of_cameras: get_number_of_cameras,

  get_camera_info: get_camera_info,

 

camera_info_t:

typedef struct {

  int  modes_supported;//支持的模式

  int8_t camera_id;//id标识

  cam_position_t position;//前摄还是后摄

  uint32_t sensor_mount_angle;//角度

}camera_info_t;

 

我们目前使用的高通8X平台:

Camera模块:

此模块有一个全局的camera服务结构体实例,用于全局管理各种子系统设备。

子系统设备常见的有:

enum msm_cam_subdev_type {

CSIPHY_DEV,

CSID_DEV,

CSIC_DEV,

ISPIF_DEV,

VFE_DEV,

AXI_DEV,

VPE_DEV,

SENSOR_DEV,

ACTUATOR_DEV,

EEPROM_DEV,

GESTURE_DEV,

};

定义一个抽象的camera服务设备:

struct msm_cam_server_dev {

/* config node device*/

struct platform_device *server_pdev;

/* server node v4l2 device */

struct v4l2_device v4l2_dev;

struct video_device *video_dev;

struct media_device media_dev;

 

/* info of sensors successfully probed*/

struct msm_camera_info camera_info;

/* info of configs successfully created*/

struct msm_cam_config_dev_info config_info;

/* active working camera device - only one allowed at this time*/

struct msm_cam_v4l2_device *pcam_active;

/* number of camera devices opened*/

atomic_t number_pcam_active;

struct v4l2_queue_util server_command_queue;

 

/* This queue used by the config thread to send responses back to the

 * control thread.  It is accessed only from a process context.

 */

struct msm_cam_server_queue server_queue[MAX_NUM_ACTIVE_CAMERA];

uint32_t server_evt_id;

 

struct msm_cam_server_mctl_inst mctl[MAX_NUM_ACTIVE_CAMERA];

uint32_t mctl_handle_cnt;

 

int use_count;

/* all the registered ISP subdevice*/

struct msm_isp_ops *isp_subdev[MSM_MAX_CAMERA_CONFIGS];

/* info of MCTL nodes successfully probed*/

struct msm_mctl_node_info mctl_node_info;

struct mutex server_lock;

struct mutex server_queue_lock;

/*v4l2 subdevs*/

struct v4l2_subdev *csiphy_device[MAX_NUM_CSIPHY_DEV];

struct v4l2_subdev *csid_device[MAX_NUM_CSID_DEV];

struct v4l2_subdev *csic_device[MAX_NUM_CSIC_DEV];

struct v4l2_subdev *ispif_device;

struct v4l2_subdev *vfe_device[MAX_NUM_VFE_DEV];

struct v4l2_subdev *axi_device[MAX_NUM_AXI_DEV];

struct v4l2_subdev *vpe_device[MAX_NUM_VPE_DEV];

struct v4l2_subdev *gesture_device;

};

 

从控制流的角度来分析下camera的流程。

首先camera会启动一个daemon进程来进行核心的操作。

启动daemon进程的地方:

在init.target.rc文件中

#start camera server as daemon

service qcamerasvr /system/bin/mm-qcamera-daemon

        class late_start

        user system

        group system camera inet

生成此mm-qcamera-daemon bin档的地方:

android\vendor\qcom\proprietary\mm-camera\apps\appslib\Android.mk

此mk文件生成了mm-qcamera-daemon bin档

 

Daemon进程的入口函数:mian()(camdaemon.c)

一个camera的守护进程在init进程中,开启的一个service

此线程与具体的sensor相关联,负责对sensor进行具体细节的操作

此为daemon进程的主线程,从server node收集事件,纷发给mctl thread,根据config的name,与server节点进行队列,不断轮询其事件队列,获取command,进行全局处理

mctl_pp_poll_thread

mctl thread

main daemon thread

Daemon

 

 

 

此线程与kernel中config节点进行通信,轮询节点的消息队列中获得command,进行全局处理

(每一个config节点都对应一个mctl thread)

 

 

 

 

 

 

 

 

 

 

 

 


抽象层到内核层的大致流程:

抽象层主要通过server node和config node将command下到内核,对应的节点驱动将command通过事件队列进行管理。

而daemon进程通过开启对应的线程,不停的对事件队列进行轮询,处理上层下的command

 

在main daemon thread中重要的任务:

一:将sensor操作关联的硬件组件加载进来,还要加载一些必备的库,为camera的正式工作铺垫环境:

①   AXI_comp_create

②   sensor_comp_create

③   flash_led_comp_create

④   flash_strobe_comp_create

⑤   CAMIF_comp_create

⑥   VFE_comp_create

⑦   ACTUATOR_comp_create

⑧   eeprom_comp_create

⑨   mctl_load_stats_proc_lib

⑩   mctl_load_frame_proc_lib

二.线程的循环工作

线程,顾名思义,肯定有一个封闭的循环体,在循环体中做一些核心的操作

而Daemon进程的主线程轮询服务节点的event queue,获取事件,纷发给各自的mctl thread

Daemon进行的主线程主要处理一下基类事件“

①   MSM_GES_RESP_V4L2 :

Open:主要进行初始化,铺垫环境,开启处理camera细节活动的线程

Close:进行一些善后工作

②   MSM_CAM_RESP_V4L2:处理open和colse

Open:主要进行初始化,铺垫环境,开启处理camera细节活动的线程

Close:进行一些善后工作

③   其他一些事件都是通过pipe通信直接写入到①②两点创建的线程中(send command through pipe and wait for config to return)

在mctl thread中重要的任务:

一.   打开confing节点文件

二.   调用create_camfd_receive_socket猜测是与硬件抽象层进行直接通信的

三.   创建mctl_pp_poll_thread线程,

四.   初始化camera的几个feature:

  ①zoom_init_ctrl

  ②bestshot_init

  ③hdr_init

五.通过pipe通信获取server节点的控制事件,事件由Daemon进程的主控线程获取并且通过pipe传递过来

六.通过监测config节点的事件获取config节点对应的控制command

主要监测三类事件:

①   MSM_CAM_RESP_DIV_FRAME_EVT_MSG

②   MSM_CAM_RESP_MCTL_PP_EVENT

③   MSM_CAM_RESP_STAT_EVT_MSG

将这三个事件以command的形式,通过pipe通信发送到(一)中创建的PP线程中

在mctl_pp_poll_thread中重要的任务:

一:对几个pipe文件进行监测,与其他线程进行交互

几种事件:

①/* Events on pipe between mctl thread - mctl pp thread */

②/* Events on user created socket */

③/* Events on mctl pp node */

④/* Events on pipe between mctl pp thread and c2d thread */



    
[2] 挪动浏览器的开发会更加容易吗?—— Chrome 中的 content 模块
    来源: 互联网  发布时间: 2014-02-18
移动浏览器的开发会更加容易吗?—— Chrome 中的 content 模块

在编译运行了 android 版本的 content shell 之后,觉得Google 的意图是打造一个基本的基于多进程沙盒模型的浏览器雏形,也就是 content shell,可以方便其他浏览器厂商基于它来改造自己的浏览器。因为目前看,多进程沙盒模型会是浏览器的趋势所在,这样可能会使得浏览器的竞争出现一些变化。Chromium 是个开源项目,从道义上讲 Google 这么做是满足人心的,最重要的,我认为这么做和 Google 的根本利益没有产生冲突,相反,从打造更完善的 Web 平台角度来讲,这么做是服务于 Google 的长期利益的。
以下翻译了Content 组件
Content 模块 High-Level Overview
"content" 的代码在 src\content, 是使用多进程沙盒浏览器模型渲染页面的所需要的核心代码。它包含Web平台所有的功能(如HTML5) 和 GPU 加速. 但是它并不包括 Chrome 的功能,如 extensions,autofill,spelling 等。目的是让嵌入者可以从 content 开始构建一个浏览器,然后再从Chrome中选取功能点。
为什么会有 content
随着Chromeium 代码的增长,许多功能不可避免的被放到了错误的位置,导致软件层次之间产生本不应存在的冲突和依赖。就连开发人员也很难指出什么是最好的方式了,因为这些API(当他们存在是)和和功能代码都被放在相同的目录下了。为了避免这个的继续发生,同时也为了更加清晰的吧多进程渲染的核心代码隔离开来,大家最终达成一致意见,将Chrome的核心代码移到 src\content 目录下(并不是 chrome)。
Content 和 Chrome 的关系
从上述讨论可以看出, content 应该只包含渲染页面的核心代码。Chrome 功能使用 content 提供的 APIs 来接受 IPC 消息 和 他们所需事件的 notify。 How to Add New Features (without bloating RenderView/RenderViewHost/WebContents) 描述了如何做。
比如,下表罗列了一些只属于 Chrome 的功能,他们并不在 content 中。这意味着 content 的代码不应该需要了解这些功能的任何信息,只需要提供这些功能所依赖的普通 APIs 。
    • Extensions
    • ChromeFrame
    • SpellCheck
    • Autofill
    • Prerendering
    • Safe Browsing
    • Translate
对于一定要供应商提供的在线网络服务,这部分交互功能希望完全在 content 模块之外实现。比如上面列表中的 Safe Browsing, Translate, Sync 和 Autofill 都需要各种不同的网络服务才能够工作, chrome 层是封装这些功能的最好地方。对那些个别的案例,我们需要在 content 模块中添加网络服务代码来实现 HTML5 功能,嵌入者(chrome)必须完整定义要连接的端点,典型地可以通过注入服务的 URL。我们不不希望这些策略性的代码被添加到 content,再强调一下,保持 content 的通用性。
架构图
下图展示了各个模块所在的层次关系。一个模块可以包含更低层次的模块代码,但是不能包含比他层次更高的代码。这一点通过依赖规则强制保证。每个模块都可以实现内嵌的 APIs 来方便底层模块可以通过这些API来调用他们。比如 WebKit API 和 content API。

Content API
content 中的代码可以通过Content API间接调用 Chrome。 当可能的时候,Chome 的功能试图通过过滤 IPC 消息和监听事件的方式 hook 进来,参考 How to Add New Features (without bloating RenderView/RenderViewHost/WebContents) 。
当上下文不全的时候(比如缺少从WebKit返回的回调)或者当回调只是一次性的,我们还可以通过嵌入者( chrome )实现ContentClient 接口。ContentClient 在所有进程中都可以使用, 一些进程还可以拥有自己的回调API,比如 ContentBrowserClient, ContentRendererClient, ContentPluginClient.


当前状态和路线图

当前 content 没有依赖于 chrome。现在我们有一个基于 content 编译出来的基本的浏览器 content shell,它可以在所有平台上使用 content 来渲染页面。 这样就允许工作在 web 平台和核心代码的发人员只需要构建、测试 content 而不是 chrome 了。我们还有 content 的单元测试 content_unittests 和集成测试 content_browsertests。

    content 是以一个动态链接库的形式构建的,所以可以加快构建的过程。

    类似于 WebKit API,我们已经围绕 content 封装了一层 API。这样就隔离了嵌入者(chrome)和 content 的内部工作,并且使得实现那些嵌入者调用 content 内部方法的工作变得更加清晰。

    Content API 的工作已经接近尾声了。

    当这件事情做完之后,它也会对隔离 chrome 功能之间的依赖关系有所帮助。比如说,如果有人打算在 content 之上新增 拼写检查和翻译的功能,他们应该可以在不需要扩展的情况下完成构建。我还需要比较好的定义不同功能之间的API才有可能完成这个目标。


    
[3] PhoneGap 创办XCode工程
    来源: 互联网  发布时间: 2014-02-18
PhoneGap 创建XCode工程
猴子原创,欢迎转载。转载请注明: 转载自Cocos2D开发网--Cocos2Dev.com,谢谢!

原文地址: http://www.cocos2dev.com/?p=386


今天有人问我PhoneGap怎么创建iOS程序,我记得去年写过一个教程,可能创建不成功,现在有空,就写下怎么创建工程吧。


PhoneGap是干什么的?有什么好处,我就不说了,不清楚的自己Google下。


一、下载PhoneGap,

http://phonegap.com/download/


下载好压缩包后,解压目录:





二、创建PhoneGap的XCode工程

打开终端,我用的iTerm。cd到你的PhoneGap目录下的lib/ios/bin目录,运行create命令


$ ./create 存放目录 com.cocos2dev.app YourAppName

create命令的参数:

第一个是存放你工程的目录,第二个是BundleIdentifier,第三个是你工程的名字


比如我执行

$ ./create MyPro com.cocos2dev.app TestG


执行之后,在你刚才指定的目录会出现一个xcode工程。






三、运行工程


1、直接用xcode打开创建的工程即可。


2、或者使用PhoneGap提供的命令行编译运行


命令行编译:

进入刚才创建的工程的cordova目录,

$ ./build

出现 ** BUILD SUCCEEDED **  表示编译成功。


运行程序:

$ ./emulate

就可以看到了运行的结果了。

呵呵,放了个老黄历到www目录

    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3