文章目录

  • 前言
  • 一、震动器
    • 1.简介
    • 2.使用方法
  • 二、闪光灯
    • 1.简介
    • 2.使用方法
  • 三、各类传感器
    • 1.简介
    • 2.使用方法
  • 四、定位模块
    • 1.简介
    • 2.使用方法
  • 五、红外发射器
    • 1.简介
    • 2.使用方法
  • 总结

好时节,愿得年年,常见中秋月。____徐有贞《中秋月·中秋月》


前言

一台手机搭载了许多的硬件模块,而不同的手机厂商对同一功能模块配置的的硬件大多都不是一个型号,当然这些是Android底层开发人员担心的问题,对于普通开发者来说,Android系统已经帮我们实现了所有的硬件驱动,我们若要控制硬件,只需调用相应的API即可方便的使用了,而无需关心底层驱动。众所周知,一个普通的Android手机都会搭载以下的硬件:震动器、闪光灯、各类传感器、定位模块、红外发射器、扬声器、麦克风、摄像头、蓝牙、NFC等等。那么本小结的P1将由易到难总结前五种硬件的控制方法,剩余的五种将在P2中总结。


运行时动态权限管理:
现在有的APP真是离谱,一个看电影的软件恨不得把所有的权限都获取了,如果拒绝,好家伙,直接强行退出了,真离谱。

关于APP的权限管理,用户可以从系统设置里更改,对于开发者来说,可以在APP运行过程中动态检查所需要的权限。
这个功能需要用到到ContextCompat的方法:
public static int checkSelfPermission(Context context,String permission):检查是否拥有指定的permission,要求此permission必须在配置文件中声明。

ActivityCompat的方法:
public static void requestPermissions(final Activity activity,final String[] permissions, final int requestCode):向系统请求获取permissions数组里的权限,在指定的activity页面展示请求对话框。

Activity的方法:
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults):系统权限申请结果的回调方法。

动态权限管理是Android6.0引入的,所有要申请的权限都应在配置文件中申明,通用步骤是首先检查当前所用的Android版本是否是6.0以上,再调用ContextCompat的checkSelfPermission方法检查是否拥有权限,若没有,则可调用ActivityCompat的requestPermissions方法请求系统弹出权限申请对话框,最后开发者重写Activity的onRequestPermissionsResult方法来处理用户的允许/拒绝选择。
动态申请权限的通用方法如下:

    // 同时检查多个权限。返回true表示已完全启用权限,返回false表示未完全启用权限public static boolean checkMultiPermission(Activity act, String[] permissions, int requestCode) {boolean result = true;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//版本要>6.0int check = PackageManager.PERMISSION_GRANTED;// 通过权限数组检查是否都开启了这些权限for (String permission : permissions) {check = ContextCompat.checkSelfPermission(act, permission);if (check != PackageManager.PERMISSION_GRANTED) {break;}}if (check != PackageManager.PERMISSION_GRANTED) {// 未开启该权限,则请求系统弹窗,好让用户选择是否立即开启权限ActivityCompat.requestPermissions(act, permissions, requestCode);result = false;}}return result;}@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {//获取成功//TODO:} else {//TODO:

一、震动器

1.简介


俗称马达,手机上搭载的马达通常分为两类:低端机搭载转子马达,高端机搭载线性马达。转子马达通电转,断电停,转动速度受电流控制,价格便宜。线性马达启停快,速度可调且具有方向性,价格较贵。
对于开发者来说,Android系统屏蔽了硬件差异,Vibrator是一个管理震动器的类,它的实例对象需要从系统服务中获取,即调用Context的getSystemService方法,通常使用三个方法来控制震动器:
public void vibrate(VibrationEffect vibe)
public void vibrate(VibrationEffect vibe, AudioAttributes attributes) :按照设置的 VibrationEffect 效果来震动,并且执行AudioAttributes 设置的声音效果。
public abstract void cancel() :取消震动。

VibrationEffect用于指定震动效果,有三个方法来创建该实例:
public static VibrationEffect createOneShot(long milliseconds, int amplitude) :创建震动一次的震动效果,两参数分别表示震动持续时间(mS)和振动幅度(0-255)。
public static VibrationEffect createWaveform(long[] timings, int repeat) :创建矩形波的震动效果,参数timings表示启停时间节点,即到达节点时震动器状态翻转。
public static VibrationEffect createWaveform(long[] timings, int[] amplitudes, int repeat) :创建自定义的波形震动,可以在指定时间段timings里设置对应的振动幅度amplitudes。

2.使用方法

对于硬件控制,都需要在配置文件AndroidManifest.xml中声明相关的权限,比如震动器,需添加:

 <uses-permission android:name="android.permission.VIBRATE"/>

在代码中只需两句代码即可控制:

     Vibrator vibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);// 获取系统的Vibrator服务vibrator.vibrate(VibrationEffect.createOneShot(500, 200));// 控制手机振动500ms,振动幅度为200

二、闪光灯

1.简介


手机一般配置了两颗LED,分别发白光和黄光。对于这种结构简单的硬件,在代码里使用也很简单。
目前Android没有专门提供控制闪光灯的管理器类,不过我们可以使用相机管理器CameraManager来控制。使用CameraManager来控制相机的用法在下一P中总结,这里给出它与闪光灯有关的方法:
String[] getCameraIdList():返回当前手机可用的的相机设备列表。
void setTorchMode(String cameraId, boolean enabled):在不打开相机的情况下,设置指定ID相机设备的闪光灯组件的模式。
CameraCharacteristics getCameraCharacteristics(String cameraId):查询相机设备的功能。

相机特征CameraCharacteristics是一个描述相机功能的类,与闪光灯有关的属性有:
public static final Key< Boolean> FLASH_INFO_AVAILABLE:该相机设备是否具有闪光灯组件,true表示有。
相关的方法有:
< T> T get(Key key):获取当前相机设备的指定属性值。

2.使用方法

通用流程如下:
①在配置文件声明闪光灯权限FLASHLIGHT,通过系统服务CAMERA_SERVICE获取相机管理利器CameraManager的实例对象,调用它的getCameraIdList方法获取所有可用的的相机设备列表。
②遍历列表,调用CameraManager的getCameraCharacteristics方法获得每一个相机设备的功能CameraCharacteristics,调用它的get方法查询内部属性FLASH_INFO_AVAILABLE是否支持闪光灯。
③如果某一相机支持,则调用CameraManager对象的的setTorchMode方法打开该相机设备的闪光灯。
代码模板如下:

    //设置闪光灯状态public static void setFlashEnable(Context context,boolean enable){String[] cameraIdList;//可用的相机列表// 从系统服务中获取相机管理器CameraManager cMgr = (CameraManager)context.getSystemService(Context.CAMERA_SERVICE);try {//获取可用的相机列表cameraIdList=cMgr.getCameraIdList();for (String camera :cameraIdList) {//获取相机属性CameraCharacteristics chara = cMgr.getCameraCharacteristics(camera);if (chara.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)){//相机如果支持FLASH组件cMgr.setTorchMode(camera,enable);}}} catch (CameraAccessException e) {e.printStackTrace();}}

三、各类传感器

1.简介


传感器能感受到规定的被测量,并按照一定的规律转换成可用数据,通常由敏感元件和转换电路组成。Android支持许多类型的传感器,但具体到一个手机,搭载的传感器就没那么多了。
传感器管理类SensorManager提供了如下常用方法管理传感器:
Sensor getDefaultSensor(int type) :获取指定类型的传感器。
List< Sensor > getSensorList(int type) :获取特定类型的可用传感器列表。
boolean registerListener(SensorEventListener listener, Sensor sensor, int samplingPeriodUs):以给定的采样频率为传感器注册监听器。
void unregisterListener(SensorEventListener listener, Sensor sensor) :取消注册传感器的监听器。

传感器Sensor是一个传感器的抽象表示,其常用方法:
String getName ():获取该传感器的名称。
int getType ():获取该传感器的类型。
一般用到的的传感器类型如下:
TYPE_ALL:描述所有传感器类型。TYPE_ACCELEROMETER:加速度传感器类型。
TYPE_AMBIENT_TEMPERATURE:环境温度传感器类型。TYPE_GRAVITY:重力传感器类型。
TYPE_GYROSCOPE:陀螺仪传感器类型。TYPE_HEART_RATE:心率监视器类型。
TYPE_LIGHT:光线传感器类型。TYPE_LINEAR_ACCELERATION:线性加速度传感器类型。
TYPE_PRESSURE:压力传感器类型。TYPE_RELATIVE_HUMIDITY:相对湿度传感器类型。
TYPE_STEP_COUNTER:计步器传感器。TYPE_STEP_DETECTOR:步行检测器传感器。

传感器监听器SensorEventListener:当有新的传感器数据时,用于接收来自SensorManager的通知,提供了如下回调方法:
abstract void onAccuracyChanged(Sensor sensor, int accuracy):当注册传感器的精度发生变化时回调。
abstract void onSensorChanged(SensorEvent event):当有新的传感器事件时调用。

传感器事件SensorEvent :保存了传感器类型,时间戳,准确性,传感器采集的数据。
其属性值可直接访问:
public int accuracy:事件的准确性。
public Sensor sensor:生成此事件的传感器。
public long timestamp:事件发生的时间(nS)。
public final float[] values:采集到的数据。

传感器采集的数据使用的坐标系是相对于默认方向的手机屏幕(坐标原点在屏幕左上角)定义的,如图:

不同的传感器采集到的数据values数组大小不一样,说明如下:
①加速度传感器:返回三个值,分别代表加速度在X,Y,Z轴的分量(m/S^2)。
②陀螺仪传感器:返回三个值,分别代表手机绕X,Y,Z轴的旋转角度(rad)。
③磁场传感器:返回三个值,分别代表磁感应强度在X,Y,Z轴的分量(uT)。
④重力加速度传感器:返回三个值,分别代表重力加速度在X,Y,Z轴的分量。
⑤线性加速度传感器:返回三个值,分别代表加速度在X,Y,Z轴的分量(不含重力加速度)。
⑥温度,湿度,光照,压力,步行检测,步行计数传感器:返回一个值,代表相应标准单位的物理量。
获取了这些原始物理量数据,还需要一定的算法来处理这些数据才能开发出有用的APP。

2.使用方法

查看自己手机所搭载的传感器,可调用SensorManager的getSensorList方法,遍历获得的Sensor队列,调用Sensor对象的getType获取传感器类型,调用getName获取传感器名称。
对开发者来说,所有的传感器都采用相同的代码模板来获取数据,而且使用传感器也无需声明任何权限:
①通过系统服务SENSOR_SERVICE获取传感器管理器SensorManager的实例对象。
②调用该对象的getDefaultSensor获取指定类型的传感器。
③在Activity的onResume里调用该对象的registerListener注册传感器监听器,在onSensorChanged回调方法里获取采集的原始数据。
④在Activity的onPause里调用该对象的unregisterListener注销监听器。
那么基于以上流程,熟悉一下API吧:
页面布局如下:

由于获取传感器管理类,为每一个传感器注册/注销监听器很简单,故不再演示了,其他主要代码如下:

//获取支持的所有传感器private void showSensorInfo() {// 获取当前设备支持的传感器列表List<Sensor> sensorList = mSensorMgr.getSensorList(Sensor.TYPE_ALL);String sensorContent = "";for (Sensor sensor : sensorList) {String content = String.format("%s\n", sensor.getName());sensorContent += content;}tv_sensor.setText(sensorContent);}//当传感器精度改变时回调该方法,一般不做处理@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy){}//当传感器数据改变时回调该方法@Overridepublic void onSensorChanged(SensorEvent event){float[] rawDates = event.values;// 获取触发event的传感器类型int sensorType = event.sensor.getType();switch (sensorType){// 陀螺仪传感器case Sensor.TYPE_GYROSCOPE:String gyrContent = String.format("绕X轴旋转的角度:%f, 绕Y轴旋转的角度:%f,绕Z轴旋转的角度:%f",rawDates[0],rawDates[1],rawDates[2]);tv_Gyro.setText(gyrContent);break;// 磁场传感器case Sensor.TYPE_MAGNETIC_FIELD:String magContent = String.format("X轴方向上的磁感应强度:%f, Y轴方向上的磁感应强度:%f,Z轴方向上的磁感应强度:%f",rawDates[0],rawDates[1],rawDates[2]);tv_Magnetic.setText(magContent);break;// 重力传感器case Sensor.TYPE_GRAVITY:String graContent = String.format("X轴方向上的重力:%f, Y轴方向上的重力:%f,Z轴方向上的重力:%f",rawDates[0],rawDates[1],rawDates[2]);tv_Gravity.setText(graContent);break;// 线性加速度传感器case Sensor.TYPE_LINEAR_ACCELERATION:String linearAccContent = String.format("X轴方向上的线性加速度:%f, Y轴方向上的线性加速度:%f,Z轴方向上的线性加速度:%f",rawDates[0],rawDates[1],rawDates[2]);tv_LinearAcc.setText(linearAccContent);break;// 光传感器case Sensor.TYPE_LIGHT:String ligContent = String.format("当前光的强度为:%f",rawDates[0]);tv_Light.setText(ligContent);break;// 压力传感器case Sensor.TYPE_PRESSURE:String preContent = String.format("当前压力为:%f",rawDates[0]);tv_Pressure.setText(preContent);break;}}

那么效果如下:

四、定位模块

1.简介


手机的定位方法有网络定位和卫星定位两种,其中卫星定位包括中国的北斗,美国的GPS和俄国的格洛纳斯,网络定位包括基站定位和Wifi定位。虽然定位方法不同,不过对于开发者来说只需掌握几个类便可方便的开发与定位有关的应用了。
定位管理器LocationManager:该类提供对系统位置服务的管理,通过Context的getSystemService方法获取实例对象。它的常用方法如下:
List< String > getAllProviders() :返回所有已知的位置提供者的名称列表。
String getBestProvider(Criteria criteria, boolean enabledOnly):根据定位条件,返回最符合提供者的名称。
boolean isProviderEnabled(String provider):返回给定提供者是否可用。
void requestLocationUpdates(String provider, long minTime, float minDistance, PendingIntent intent):指定provider周期性获取位置信息,并通过intent启动相关组件。
Location getLastKnownLocation(String provider):返回一个给定位置提供者提供的最新的位。
void removeUpdates(LocationListener listener):删除指定的定位监听器。

位置提供者LocationProvider:有三种:GPS位置提供者GPS_PROVIDER,网络位置提供者NETWORK_PROVIDER,无法定位PASSIVE_PROVIDER。有常用方法如下:
String getName():返回此提供者的名称。
int getPowerRequirement():返回此提供者的电源要求。
boolean requiresCell()
boolean requiresNetwork()
boolean requiresSatellite()
:此提供者是否需要基站信息,访问数据网络,访问基于卫星的定位系统,需要则返回true,否则返回false。
boolean supportsAltitude()
boolean supportsBearing()
boolean supportsSpeed()
:提供者是否能够提供高度信息,方位信息,速度信息,能则返回true,否则返回false。

定位条件Criteria:用于设置定位的前提条件(如精度,速度,海拔,方位)来过滤定位提供者。常用方法如下:
void setAccuracy(int accuracy):设置定位精度,可取值:ACCURACY_FINE(高精度),ACCURACY_COARSE (一般)。 更准确的位置会消耗更多的电力,需要更长的时间。
void setSpeedAccuracy(int accuracy):设置所需的速度准确度,可取值:ACCURACY_LOW, ACCURACY_HIGH ,或NO_REQUIREMENT。
void setAltitudeRequired(boolean altitudeRequired):是否必须提供高度信息。
void setBearingRequired(boolean bearingRequired):是否需要方向信息。
void setSpeedRequired(boolean speedRequired):是否提供速度信息。
void setPowerRequirement(int level):设置所需的电源级别,可取值:NO_REQUIREMENT,POWER_LOW,POWER_MEDIUM或POWER_HIGH。

定位监听器LocationListener:用于监听定位事件,其有四个回调方法:
abstract void onLocationChanged(Location location):当位置发生变化时调用,可以在此处获取最新的位置信息。
abstract void onProviderDisabled(String provider):当提供者被用户禁用时调用。
abstract void onProviderEnabled(String provider):当提供者被用户启用时调用。
abstract void onStatusChanged(String provider, int status, Bundle extras):当提供者状态改变时调用。

位置Location:代表一个位置信息,常用方法如下:
float getAccuracy()
double getAltitude()
float getBearing()
double getLatitude()
double getLongitude()
float getSpeed()
long getTime():见名知意,分别获取定位精度,位置的高度,方向,纬度,经度,速度,时间戳。

2.使用方法

定位功能需要声明ACCESS_COARSE_LOCATION和ACCESS_FINE_LOCATION权限:

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

获取定位信息的步骤如下:
①获取LocationManager实例对象。
②使用该对象通过定位条件Criteria获取合适的位置提供者LocationProvider。
③使用LocationManager为LocationProvider注册定位监听器LocationListener。
④在LocationListener的回调方法中获取位置信息Location。

那么接下来举个例子来熟悉一下流程吧:布局界面只有一个TextView,activity中与定位有关的代码如下:

    private TextView tv_location;private String mLocation = "";private LocationManager mLocationMgr; // 声明一个定位管理器对象private Criteria mCriteria = new Criteria(); // 声明一个定位条件// 初始化定位服务private void initLocation() {//动态获取定位权限checkMultiPermission(this,new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_FINE_LOCATION},0);// 从系统服务中获取定位管理器mLocationMgr = (LocationManager) getSystemService(Context.LOCATION_SERVICE);// 设置定位精确度。Criteria.ACCURACY_COARSE表示粗略,Criteria.ACCURACY_FIN表示高精度mCriteria.setAccuracy(Criteria.ACCURACY_FINE);// 设置是否需要高度信息mCriteria.setAltitudeRequired(true);// 设置是否需要方位信息mCriteria.setBearingRequired(true);// 设置是否允许运营商收费mCriteria.setCostAllowed(true);// 设置对电源的需求mCriteria.setPowerRequirement(Criteria.POWER_LOW);// 获取定位管理器的最佳位置提供者String bestProvider = mLocationMgr.getBestProvider(mCriteria, true);if (mLocationMgr.isProviderEnabled(bestProvider)) { // 位置提供者当前可用tv_location.setText("正在由" + bestProvider + "提供定位服务");mLocation = String.format("定位类型=%s", bestProvider);beginLocation(bestProvider);} else { // 位置提供者暂不可用tv_location.setText("\n" + bestProvider + "定位不可用");}}// 开始定位private void beginLocation(String method) {// 检查当前设备是否已经开启了定位功能if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED) {Toast.makeText(this, "请授予定位权限并开启定位功能", Toast.LENGTH_SHORT).show();return;}// 设置定位管理器的位置变更监听器mLocationMgr.requestLocationUpdates(method, 300, 0, mLocationListener);}// 定义一个位置变更监听器private LocationListener mLocationListener = new LocationListener() {@Overridepublic void onLocationChanged(Location location) {if (location != null) {String desc = String.format("%s\n定位对象信息如下: " + "\n\t其中经度:%f,纬度:%f" +"\n\t其中高度:%d米,精度:%d米", mLocation,location.getLongitude(), location.getLatitude(),Math.round(location.getAltitude()), Math.round(location.getAccuracy()));tv_location.setText(desc);} else {tv_location.setText(mLocation + "\n暂未获取到定位对象");}}@Overridepublic void onProviderDisabled(String arg0) {}@Overridepublic void onProviderEnabled(String arg0) {}@Overridepublic void onStatusChanged(String arg0, int arg1, Bundle arg2) {}};@Overrideprotected void onDestroy() {if (mLocationMgr != null) {// 移除定位管理器的位置变更监听器mLocationMgr.removeUpdates(mLocationListener);}super.onDestroy();}

效果如下:

五、红外发射器

1.简介

红外遥控是一种无线、非接触式的控制技术,由红外发射器和红外接收器组成(发射器是透明的,另一个是黑色的,两者形状近似LED),采用近红外光传送遥控指令。手机上通常只搭载红外发射器,我们可以用来发射自定义的信号,也可以发送遥控器厂家规范的数据信号来实现模拟遥控器。

在实际的通信领域,原始信号一般有较宽的频谱,而且都是在比较低的频率段分布大量的能量,所以称之为基带信号,这种信号是不适合直接在信道中传输。为便于传输、提高抗干扰能力和有效的利用带宽,通常需要将信号调制到适合信道和噪声特性的频率范围内进行传输,这就叫做信号调制。在通信系统的接收端要对接收到的信号进行解调,恢复出原来的基带信号。
红外遥控器里的红外通信,通常是使用38KHz左右的载波进行调制的。就是用待传送信号去控制某个高频信号的幅度、相位、频率等参量变化的过程,即用一个信号去装载另一个信号。比如我们的红外遥控信号要发送的时候,先经过38K载波调制,如图所示:

红外信号调制原始信号就是我们要发送的一个数据“0”位或者一位数据“1”位,而所谓38K载波就是频率为38KHz的方波信号,调制后信号就是最终我们发射出去的波形。我们使用原始信号来控制38K载波,当信号是数据“0”的时候,38K载波毫无保留的全部发送出去,当信号是数据“1”的时候,不发送任何载波信号。
遥控器的基带通信协议很多,大概有几十种,常用的就有ITT协议、NEC协议、Sharp协议、Philips RC-5协议、Sony SIRC协议等,用的最多的就是NEC协议了。
NEC协议的数据格式包括了引导码、用户码、用户码(或者用户码反码)、按键键码和键码反码,均是 8 位数据格式, 按照低位在前, 高位在后的顺序发送。

NEC协议有很多的子协议,它的标准协议规定了:引导码由一个 9ms 的低电平和一个 4.5ms 的高电平组成,数据编码总共是4个字节32位,第一个字节是用户码,第二个字节可能也是用户码,或者是用户码的反码,具体由生产商决定,第三个字节就是当前按键的按键键码,而第四个字节是键码反码,可用于对数据的纠错。
NEC 码的位定义: 一个脉冲对应 560us 的连续载波, 一个逻辑 1 传输需要2.25ms(560us 脉冲+1680us 低电平), 一个逻辑 0 的传输需要 1.125ms(560us脉冲+560us 低电平) 。

红红外遥控管理器ConsumerIrManager:是Android提供的管理红外发射器的类,通过系统服务获取实例对象,有3个方法:
CarrierFrequencyRange[] getCarrierFrequencies():查询红外发射器支持的载波频率(Hz)。
boolean hasIrEmitter():检查手机是否有红外发射器。
void transmit(int carrierFrequency, int[] pattern):发射红外数据信号,carrierFrequency指定载波频率(Hz),pattern表示电平翻转的时间节点(uS),0uS到第一个节点表示低电平。

2.使用方法

其本身的使用方法很简单:声明红外权限TRANSMIT_IR–>获取ConsumerIrManager的实例对象–>调用其hasIrEmitter判断手机是否支持红外–>如果支持,则调用其transmit方法发送数据即可。
问题在于发什么样的数据,有以下两类使用场景:
①自定义的数据格式:发送未经编码的原始数据,比如pattern取值{100,200,300},那么在红外接收端也就得到一个100uS高电平+200uS低电平+300uS高电平的波形。
②规范的编码格式。比如美的空调遥控器采取的NEC的R05d子协议,网上找到说明书,先看波形规范:


再看编码规范,比如关机的编码:L,A,A’,B,B’,C,C’, S, L,A,A’,B,B’,C,C’, S, L,A,A’,Q,Q’,Y,Y’

说明书介绍的很详细,比如说立刻关机,则相应的字母取值:
L =4.4mS低电平+4.4mS高电平
A=1011 0010
A’=0100 1101
B=0111 1011
B’=1000 0100
C=1110 0000
C’=0001 1111
S :0.54mS低电平+ 5.22mS高电平
Q=0000 0000(0小时)
Q’=1111 1111
Y=0000 0000(0分钟)
Y’=1111 1111

那么举个简单的例子如下:
布局界面含有开关机按钮,主要代码如下:

 private ConsumerIrManager cim; // 声明一个红外遥控管理器对象// 初始化红外遥控管理器private void initInfrared() {// 从系统服务中获取红外遥控管理器cim = (ConsumerIrManager) getSystemService(Context.CONSUMER_IR_SERVICE);if (!cim.hasIrEmitter()) { // 判断当前设备是否支持红外功能Toast.makeText(this, "当前手机不支持红外遥控", Toast.LENGTH_SHORT).show();} else {Toast.makeText(this, "当前手机支持红外遥控", Toast.LENGTH_SHORT).show();}}int zeroLow = 540;int zeroHigh = 540;int oneLow = 540;int oneHigh = 1620;int[] powerOnPattern = {//数据格式:L,A,A',B,B',C,C', S, L,A,A',B,B',C,C',4400,4400,  //L//1011 0010 AoneLow,oneHigh,zeroLow,zeroHigh,oneLow,oneHigh,oneLow,oneHigh,          zeroLow,zeroHigh,zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,           //A//0100 1101 A'zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,      oneLow,oneHigh,oneLow,oneHigh,zeroLow,zeroHigh,oneLow,oneHigh,         //A'//1011 1111 BoneLow,oneHigh,zeroLow,zeroHigh,oneLow,oneHigh,oneLow,oneHigh,          oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,        //B//0100 0000 B'zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,       zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,            //B'//1011 1111 CzeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,    oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,           //C//0100 0000 C'zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,      zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,//C'540,5220,   //S4400,4400,  //L//1011 0010 AoneLow,oneHigh,zeroLow,zeroHigh,oneLow,oneHigh,oneLow,oneHigh,          zeroLow,zeroHigh,zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,           //A//0100 1101 A'zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,      oneLow,oneHigh,oneLow,oneHigh,zeroLow,zeroHigh,oneLow,oneHigh,         //A'//1011 1111 BoneLow,oneHigh,zeroLow,zeroHigh,oneLow,oneHigh,oneLow,oneHigh,          oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,        //B//0100 0000 B'zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,       zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,            //B'//1011 1111 CzeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,    oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,           //C//0100 0000 C'zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,      zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,//C'540     //end};int[] powerOffPattern = {//数据格式:L,A,A',B,B',C,C', S, L,A,A',B,B',C,C', S, L,A,A',Q,Q',Y,Y'4400,4400,  //L=4.4mS低电平+4.4mS高电平//A=1011 0010oneLow,oneHigh,zeroLow,zeroHigh,oneLow,oneHigh,oneLow,oneHigh, zeroLow,zeroHigh,zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,//A'=0100 1101zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh, oneLow,oneHigh,oneLow,oneHigh,zeroLow,zeroHigh,oneLow,oneHigh,//B=0111 1011zeroLow,zeroHigh,oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh, oneLow,oneHigh,zeroLow,zeroHigh,oneLow,oneHigh,oneLow,oneHigh,//B'=1000 0100oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh, zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,//C=1110 0000oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,zeroLow,zeroHigh, zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,//C'=0001 1111zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,oneLow,oneHigh, oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,540,5220,   //S=0.54mS低电平+ 5.22mS高电平4400,4400,  //L//A=1011 0010oneLow,oneHigh,zeroLow,zeroHigh,oneLow,oneHigh,oneLow,oneHigh, zeroLow,zeroHigh,zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,//A'=0100 1101zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh, oneLow,oneHigh,oneLow,oneHigh,zeroLow,zeroHigh,oneLow,oneHigh,//B=0111 1011zeroLow,zeroHigh,oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh, oneLow,oneHigh,zeroLow,zeroHigh,oneLow,oneHigh,oneLow,oneHigh,//B'=1000 0100oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh, zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,//C=1110 0000oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,zeroLow,zeroHigh, zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,//C'=0001 1111zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,oneLow,oneHigh, oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,540,5220,   //S//A=1011 0010oneLow,oneHigh,zeroLow,zeroHigh,oneLow,oneHigh,oneLow,oneHigh, zeroLow,zeroHigh,zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,//A'=0100 1101zeroLow,zeroHigh,oneLow,oneHigh,zeroLow,zeroHigh,zeroLow,zeroHigh, oneLow,oneHigh,oneLow,oneHigh,zeroLow,zeroHigh,oneLow,oneHigh,//Q=0000 0000(0小时)zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh, zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,//Q'=1111 1111oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh, oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,//Y=0000 0000(0分钟)zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh, zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,zeroLow,zeroHigh,//Y'=1111 1111oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh, oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,oneLow,oneHigh,540     //end};@Overridepublic void onClick(View v) {if (v.getId() == R.id.btn_powerOn) {cim.transmit(38000, powerOnPattern);} else if (v.getId() == R.id.btn_powerOff) {cim.transmit(38000, powerOffPattern);}Toast.makeText(this, "已发送红外信号,看空调是否有反应", Toast.LENGTH_SHORT).show();}

效果如下:

对这种空调试了一下,按的时候听到“滴”的声音,能实现关机,但是不能开机,可能是开机参数哪里搞错了,唉,我也懒得弄了。


总结

本文总结了在Android系统中如何控制5种简单的硬件:震动器、闪光灯、各类传感器、定位模块和红外发射器。最后,明天是八月十五,祝大家中秋节快乐,阖家团圆!

记录学习Android基础的心得07:硬件控制P1相关推荐

  1. 记录学习Android基础的心得00

    文章目录 前言 一.Android发展历史 二.IDE:Android Studio使用介绍 1.下载安装AS 2.AS使用技巧 总结 前言 时光荏苒犹如白驹过隙,学习Android前前后后都已经快一 ...

  2. 记录学习Android基础的心得08:常用控件(中级篇)P1

    文章目录 前言 一.图像类视图 1.图形基础 2.图像视图 3.图像按钮 补充:表格布局 二.列表类视图 1.列表视图 2.可展开的列表视图 3.循环视图 今日长缨在手,何时缚住苍龙?–<清平乐 ...

  3. 记录学习Android基础的心得05:常用控件(基础篇)

    文章目录 前言 一.复合按钮CompoundButton的常见子类 1.单选按钮RadioButton 2.复选框CheckBox 3.开关Switch 二.进度展示控件 1.进度条ProgressB ...

  4. Arduino基础入门篇07—按键控制LED灯

    前面介绍了Arduino数字I/O,通过控制数字引脚输出来控制LED灯亮灭.本篇将介绍数字I/O的输入功能,通过检测按键状态来控制LED灯亮灭,把LED的亮灭变成人为可控制的. 1. 实验材料 Uno ...

  5. 2015年最新Android基础入门教程目录(完结版)

    2015年最新Android基础入门教程目录(完结版) 标签(空格分隔): Android基础入门教程 前言: 关于<2015年最新Android基础入门教程目录>终于在今天落下了帷幕,全 ...

  6. 最新Android基础入门教程目录(完结版)

    第一章:环境搭建与开发相关(已完结 10/10) https://blog.csdn.net/coder_pig/article/details/50000773 Android基础入门教程--1.1 ...

  7. Android基础知识点学习总结

    Android基础知识点学习总结 安卓基础知识个人学习笔记分享~ 一.Android系统架构 Linux内核层→系统运行层→应用框架层→应用层 1.Linux内核层:Android系统是基于Linux ...

  8. Android学习笔记:Android基础知识点(不断更新中)

    1.Android学习笔记:OkHttp 2.Android学习笔记:更新UI的方法(UI线程和非UI线程) 3.Android学习笔记:Volley 4.Android学习笔记:Handler 5. ...

  9. 2022 最新 Android 基础教程,从开发入门到项目实战【b站动脑学院】学习笔记——第六章:数据存储

    第 6 章 数据存储 本章介绍Android 4种存储方式的用法,包括共享参数SharedPreferences.数据库SQLite.存储卡文 件.App的全局内存,另外介绍Android重要组件-应 ...

  10. Android基础总结: Camera2详解之一 API学习

    Camera2的API出来有些年头了,只是赶项目多次使用,没时间好好总结,年终了,正好结合google的官方Camera2demo 和开发中使用的情况,做个详细梳理,研究总结之后,才发现Camera2 ...

最新文章

  1. 跳出数据计算拯救人工智能之打败机器学习方法详解
  2. mabatisplus怎么给实体类自定义属性_如果你的角色属性可以自定义,你会怎么点?...
  3. React Native初始化项目0.47.1报错
  4. [转]Android输入法框的梳理
  5. 消息队列入门案例-编码
  6. 如何操控输入框中的placeholder属性
  7. npm install引起的项目崩溃(This is probably not a problem with npm,there is likely additional logging outp)
  8. 如何解决cellIndex在IE下兼容性问题
  9. 如何理解lower_bound/upper_bound
  10. php极速链,php PHP极速链 战群源码系列(全自动采集更新+引流神器无数据库版) WEB(ASP,PHP,...) 261万源代码下载- www.pudn.com...
  11. MySQL级联删除和级联修改
  12. [No000057]一个人默默背单词,小心被传染哦
  13. html把字体设置为繁体,XP下怎样将繁体字设置成系统字体?XP下把系统字体改为繁体的方法...
  14. 修改文件错误:E45: 'readonly' option is set (add ! to override)
  15. Styler类的变量
  16. 求和计算机教案,數列求和教案.doc
  17. ubuntu命令 图片 壁纸_[教程]Ubuntu下完整配置自动壁纸切换
  18. 禾匠二开系列之兑换码禁用以后启用功能
  19. C#锐利体验 第十六讲 映射
  20. 新媒体运营:如何策划出一场完整高效的活动方案?(一) | 黎想

热门文章

  1. 用计算机弹九八k谱子,拼音输出法(计算机).ppt
  2. Python分析00-90后的微信昵称,发现如下规律!
  3. V831基础-UART
  4. vue打卡日历_VUE也有自己的日历组件
  5. 由Tomcat 8005端口想到的...
  6. git bug分支管理
  7. 计算机教室盘点表,怎样用excel制作库存盘点表
  8. I-D-E-A中maven的常用指令
  9. 网页学习教程视频百度云下载,程序学习教程视频百度云下载(讲解非常的细,适合刚学习程序人员,从前端到后端都有,全看完你就是一名程序猿)
  10. C++ exception with description “bad optional access“ thrown in the test body.