光线传感器工具类,和仿微信扫一扫预览条码放大和光线检测

一、在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);
  }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值