最近看到个一个透明壁纸的应用,感觉很好玩,所以就想弄弄。
完整代码已经传到github上,地址是https://github.com/SZJing/Screen
应用下载地址https://pan.baidu.com/s/1smhfByP
其实他的思路很简单,就是打开手机摄像头的预览,让这个预览作为壁纸。因为一直打开这摄像头,所以又耗费资源又耗电。因此这个应用的实际用处并不大,只是比较新奇,做来玩玩的。
这个应用好像最初是在Google Play上的,而且下载量很高。有兴趣的可以看看。
接下来就是代码了,我也是看着别人的代码做的,有些甚至是直接copy的,但是我在原来的基础上又增加了双击拍照的功能,感觉有点类似偷拍的功能了。但是偷拍被打,概不负责。
首先是AndroidMainfest.xml文件
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"
android:label="@string/app_name"
android:permission="android.permission.BIND_WALLPAPER">
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService"/>
</intent-filer/>
<meta-data
android:name="android.service.wallpaper"
android:resource="@xml/livewallpaper" />
</service>
最后的xml/livewallpape文件是要自己在res目录下新建一个相应的xml文件,里面配置的是图标,具体可以看源码。
这是要申请的权限,不过要注意照相机和内存读取要进行运行时权限的设置,否则程序不能使用。当然这是6.0之后才有的。
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.SET_WALLPAPER"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
接下来就是service的代码部分了
public class MyService extends WallpaperService {
public MyService() {
}
@Override
public Engine onCreateEngine() {
return new CameraEngine();
}
class CameraEngine extends Engine implements android.hardware.Camera.PreviewCallback{
private Camera camera;
private int count = 0;
private long firClick = 0;
private long secClick = 0;
private final int interval = 500;
@Override
public void onCreate(SurfaceHolder surfaceHolder){
super.onCreate(surfaceHolder);
startPreview();
setTouchEventsEnabled(true);
}
@Override
public void onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_DOWN){
count++;
if (1 == count){
firClick = System.currentTimeMillis();
}else if (2 == count){
secClick = System.currentTimeMillis();
if (secClick - firClick
camera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
camera.takePicture(null,null,mPicture);
}
});
}else {
firClick = secClick;
count = 1;
}
secClick = 0;
}
}
// 时间处理:点击拍照,长按拍照
}
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".jpg");
try{
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
count = 0;
firClick = 0;
startPreview();
}catch (Exception e){
Log.i("qwdfdf","保存失败");
}
}
};
@Override
public void onDestroy() {
super.onDestroy();
stopPreview();
}
@Override
public void onVisibilityChanged(boolean visible) {
if (visible) {
startPreview();
} else {
stopPreview();
}
}
public void startPreview() {
camera = Camera.open();
camera.setDisplayOrientation(90);
try {
camera.setPreviewDisplay(getSurfaceHolder());
} catch (IOException e) {
e.printStackTrace();
}
camera.startPreview();
}
/**
* 停止预览
*/
public void stopPreview() {
if (camera != null) {
try {
camera.stopPreview();
camera.setPreviewCallback(null);
// camera.lock();
camera.release();
} catch (Exception e) {
e.printStackTrace();
}
camera = null;
}
}
@Override
public void onPreviewFrame(byte[] data, android.hardware.Camera camera) {
camera.addCallbackBuffer(data);
}
}
}
看着很多,但是其实好理解。首先是要继承WallpaperService,接下来是重写他的onCreateEngine方法,这个是必须重写的。我们在其中实例化自己的一个类,并让它继承Engine。
在这个类中我们就要设置预览,要预览就得有SurfaceHolder。同时我们也要设置他的点击事件,(这是我自己加的)在onTouchEvent中就是判断是否是两次连续的点击事件。这里注意的是,拍照用的是takePicture,他会回调PictureCallback,在这个回调完成之后我们需要重新开始预览,要不然留下的是我们拍照的照片。但是这也存在一些小问题,就是重新预览会有一点卡顿,这也是需要改进的地方。
最后我们在MainActivity中申请权限,开始服务就好了。这还有点注意的是启动服务高版本的只能用显示启动,不能隐式启动,否则会报错。
完整代码已经传到github上,地址是https://github.com/SZJing/Screen
网友评论