一、在Android开发中,有时我们需要获知设备所在环境的光线强弱情况,当然这需要我们设备拥有光线传感器
下面是我简单封装的一个光线传感器管理类,主要提供了3个方法:
1.start():启动,在获取光照强度前调用。
2.stop():停止,在不再需要获取光照强度后调用。
3.getLux():获取光照强度,单位为勒克斯(lux)。
如果你需要额外的一些方法,可以根据返回的光照强度自行添加。下面是整个LightSensorManager类
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;
public class LightSensorManager {
private static final boolean DEBUG = true;
private static final String TAG = "LightSensor";
private static LightSensorManager instance;
private SensorManager mSensorManager;
private LightSensorListener mLightSensorListener;
private boolean mHasStarted = false;
private LightSensorManager() {
}
public static LightSensorManager getInstance() {
if (instance == null) {
instance = new LightSensorManager();
}
return instance;
}
public void start(Context context) {
if (mHasStarted) {
return;
}
mHasStarted = true;
mSensorManager = (SensorManager) context.getApplicationContext().getSystemService(Context.SENSOR_SERVICE);
Sensor lightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); // 获取光线传感器
if (lightSensor != null) { // 光线传感器存在时
mLightSensorListener = new LightSensorListener();
mSensorManager.registerListener(mLightSensorListener, lightSensor,
SensorManager.SENSOR_DELAY_NORMAL); // 注册事件监听
}
}
public void stop() {
if (!mHasStarted || mSensorManager == null) {
return;
}
mHasStarted = false;
mSensorManager.unregisterListener(mLightSensorListener);
}
/**
* 获取光线强度
*/
public float getLux() {
if (mLightSensorListener != null) {
return mLightSensorListener.lux;
}
return -1.0f; // 默认返回-1,表示设备无光线传感器或者为调用start()方法
}
private class LightSensorListener implements SensorEventListener {
private float lux; // 光线强度
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_LIGHT) {
// 获取光线强度
lux = event.values[0];
if (DEBUG) {
Log.d(TAG, "lux : " + lux);
}
}
}
}
}
对于这个光线强度的值。越暗数值越低,最低应该是0,在白天室内经测试有40-60左右,室外明亮地方有300-400左右,仅供参考。
二、仿微信扫一扫二维码放大和光线检测
1、CaptureActivity.java修改:
注册广播来接收光线变化,从而显示或隐藏手机上的手电筒按钮
IntentFilter mFilter = new IntentFilter("lightchanged");
LightListenReceiver mReceiver = new LightListenReceiver();
registerReceiver(mReceiver, mFilter);
class LightListenReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if ("lightchanged".equals(action)) {
if (Constant.isWeakLight) {
// 光线太暗
}
else {
// 光线正常
}
}
}
}
2、在Constant.java中添加:判断当前光线是否是弱光线
public static boolean isWeakLight = false;
3、CameraManager.java中添加如下代码:
public Camera getCamera() {
return camera;
}
4、DecodeHandler.java:
package com.wwwarehouse.common.tripartite_widget.zxing;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.wwwarehouse.common.R;
import com.wwwarehouse.common.activity.CaptureActivity;
import com.wwwarehouse.common.constant.Constant;
import java.text.DecimalFormat;
import java.util.Map;
final class DecodeHandler extends Handler {
private static final String TAG = DecodeHandler.class.getSimpleName();
private final CaptureActivity activity;
private final MultiFormatReader multiFormatReader;
private boolean running = true;
private int frameCount;
private long intervalTime;
private static final long INTERVAL = 30 * 1000L;
private boolean isResetTime = true;
private Rect frameRect;
DecodeHandler(Activity activity, Map<DecodeHintType, Object> hints) {
multiFormatReader = new MultiFormatReader();
multiFormatReader.setHints(hints);
this.activity = (CaptureActivity)activity;
frameRect = CameraManager.get().getFramingRect();
}
@Override
public void handleMessage(Message message) {
if (!running) {
return;
}
if (message.what == R.id.decode) {
decode((byte[]) message.obj, message.arg1, message.arg2);
} else if (message.what == R.id.quit) {
running = false;
Looper.myLooper().quit();
}
}
private void decode(byte[] data, int width, int height) {
byte[] rotatedData = new byte[data.length];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++)
rotatedData[x * height + height - y - 1] = data[x + y * width];
}
frameCount++;
//丢弃前2帧并每隔2帧分析下预览帧color值
if (frameCount > 2 && frameCount % 2 == 0) {
analysisBitmapColor(data, width, height);
}
long start = System.currentTimeMillis();
if (isResetTime) {
intervalTime = System.currentTimeMillis();
isResetTime = false;
}
Result rawResult = null;
final PlanarYUVLuminanceSource source = CameraManager.get().buildLuminanceSource(rotatedData, height, width);
if (source != null) {
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
rawResult = multiFormatReader.decodeWithState(bitmap);
} catch (ReaderException re) {
// continue
} finally {
multiFormatReader.reset();
}
}
final Handler handler = activity.getHandler();
if (rawResult != null) {
// Don't log the barcode contents for security.
long end = System.currentTimeMillis();
Log.d(TAG, "Found barcode in " + (end - start) + " ms");
if (handler != null) {
float point1X = rawResult.getResultPoints()[0].getX();
float point1Y = rawResult.getResultPoints()[0].getY();
float point2X = rawResult.getResultPoints()[1].getX();
float point2Y = rawResult.getResultPoints()[1].getY();
int len = (int) Math.sqrt(Math.abs(point1X - point2X) * Math.abs(point1X - point2X) + Math.abs(point1Y - point2Y) * Math.abs(point1Y - point2Y));
if (frameRect != null) {
int frameWidth = frameRect.right - frameRect.left;
Camera camera = CameraManager.get().getCamera();
Camera.Parameters parameters = camera.getParameters();
final int maxZoom = parameters.getMaxZoom();
int zoom = parameters.getZoom();
if (parameters.isZoomSupported()) {
if (len <= frameWidth / 4) {
if (zoom == 0) {
zoom = maxZoom / 3;
} else {
zoom = zoom + 10;
}
if (zoom > maxZoom) {
zoom = maxZoom;
}
parameters.setZoom(zoom);
camera.setParameters(parameters);
final Result finalRawResult = rawResult;
postDelayed(new Runnable() {
@Override
public void run() {
Message message = Message.obtain(handler, R.id.decode_succeeded, finalRawResult);
Bundle bundle = new Bundle();
bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
message.setData(bundle);
message.sendToTarget();
}
}, 1000);
} else {
Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult);
Bundle bundle = new Bundle();
bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
message.setData(bundle);
message.sendToTarget();
}
}
} else {
Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult);
Bundle bundle = new Bundle();
bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
message.setData(bundle);
message.sendToTarget();
}
}
} else {
if (handler != null) {
Message message = Message.obtain(handler, R.id.decode_failed);
message.sendToTarget();
}
}
}
private void analysisBitmapColor(byte[] data, int width, int height) {
int[] rgb = decodeYUV420SP(data, width, height);
Bitmap bmp = null;
if (null != frameRect) {
//取矩形扫描框frameRect的2分之一创建为bitmap来分析
bmp = Bitmap.createBitmap(rgb, frameRect.left + (frameRect.right - frameRect.left) / 4, frameRect.width() / 2, frameRect.width() / 2, frameRect.height() / 2, Bitmap.Config.ARGB_4444);
}
if (bmp != null) {
float color = getAverageColor(bmp);
DecimalFormat decimalFormat1 = new DecimalFormat("0.00");
String percent = decimalFormat1.format(color / -16777216);
float floatPercent = Float.parseFloat(percent);
Log.e(TAG, " color= " + color + " floatPercent= " + floatPercent + " bmp width= " + bmp.getWidth() + " bmp height= " + bmp.getHeight());
Constant.isWeakLight = (color == -16777216 || (floatPercent >= 0.85 && floatPercent <= 1.00));
bmp.recycle();
}
}
private int[] decodeYUV420SP(byte[] yuv420sp, int width, int height) {
final int frameSize = width * height;
int rgb[] = new int[width * height];
for (int j = 0, yp = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++, yp++) {
int y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0) y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0) r = 0;
else if (r > 262143) r = 262143;
if (g < 0) g = 0;
else if (g > 262143) g = 262143;
if (b < 0) b = 0;
else if (b > 262143) b = 262143;
rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) &
0xff00) | ((b >> 10) & 0xff);
}
}
return rgb;
}
private int getAverageColor(Bitmap bitmap) {
int redBucket = 0;
int greenBucket = 0;
int blueBucket = 0;
int pixelCount = 0;
for (int y = 0; y < bitmap.getHeight(); y++) {
for (int x = 0; x < bitmap.getWidth(); x++) {
int c = bitmap.getPixel(x, y);
pixelCount++;
redBucket += Color.red(c);
greenBucket += Color.green(c);
blueBucket += Color.blue(c);
}
}
int averageColor = Color.rgb(redBucket / pixelCount, greenBucket
/ pixelCount, blueBucket / pixelCount);
return averageColor;
}
}
5、ViewFinderView.java中的onDraw()最后面加入:
Context mContext;
@Override
public void onDraw(Canvas canvas) {
...
Intent it = new Intent("lightchanged");
mContext.sendBroadcast(it);
}