返家過節,家人分享了 android app 手電筒給我把玩,說真的偶爾還挺實用的,甚至一些 feature phone 都也有這種設計(基本上是真的裝了一個燈)。但我仔細看了一下該 app 的權限,卻開了一堆有的沒有的權限,假設把這個行為丟給國內知名防毒大廠的偵測系統進行偵測,那應該就會被判斷成病毒了。所以我就順手練習一下了 XD
而 android app 的概念則是使用相機的閃光燈,讓閃光燈的狀態停留在 FLASH_MODE_TORCH 時,就可以當做手電筒使用了。然而真正實作上的細節,則必須先開啟相機才能使用閃光燈,也就是用閃光燈之前必須開啟鏡頭並且也會開始把鏡頭收到的影像傳給系統了。簡言之,使用閃光燈其實會操到鏡頭跟系統資料,等同於有資料不停地從鏡頭收進來。
簡單的實作:
layout/main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/background"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/camera_preview"
android:layout_width="1dip"
android:layout_height="1dip"/>
<TextView
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="center"
android:text="@string/light"
android:textColor="#AAA"
android:textSize="50dp" />
</RelativeLayout>
AndroidManifest.xml:(事實上可以只需android.permission.CAMERA即可,其他只是最佳化的效果)
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
Code:
import java.io.IOException;
import android.graphics.Color;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.RelativeLayout;
public class MyFlashLightActivity extends Activity implements SurfaceHolder.Callback {
boolean have_light = false;
Camera mCamera = null;
SurfaceView mSurfaceView;
SurfaceHolder mSurfaceHolder;
WakeLock mWakeLock;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_flash_light);
if( ( have_light = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH) ) ) {
try {
mCamera = Camera.open();
mSurfaceView = (SurfaceView) findViewById(R.id.PREVIEW);
if(mSurfaceView!= null) {
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
Parameters mParameters = mCamera.getParameters();
mParameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
mCamera.setParameters(mParameters);
mCamera.startPreview();
}
} catch( Exception e ) {
e.printStackTrace();
}
} else {
RelativeLayout mRelativeLayout = (RelativeLayout)findViewById(R.id.background);
if(mRelativeLayout!=null)
mRelativeLayout.setBackgroundColor(Color.WHITE);
}
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if( have_light ) {
mCamera.stopPreview();
mCamera.release();
}
System.out.println("[D] finish");
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
if( mWakeLock != null )
mWakeLock.release();
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
if( mWakeLock == null ) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WAKE_LOCK_TAG");
}
mWakeLock.acquire();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
System.out.println("[i] surfaceChanged");
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
System.out.println("[i] surfaceCreated");
try {
mCamera.setPreviewDisplay(holder);
holder.addCallback(MyFlashLightActivity.this);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
System.out.println("[i] surfaceDestroyed");
mCamera.stopPreview();
mSurfaceHolder = null;
}
}
此外,有興趣的人,強烈建議去翻一下 Torch, an Android flashlight application 這個 open source ,算是找資料驗證時無意間發現的好物。