本文已在个人公众号hongyangAndroid原创首发。php
上周个人微信公众号推送了一篇Android 实现"透明屏幕,当时我看到以后就以为特别感兴趣,也当即联系做者要了受权~~html
感兴趣的缘由是,我是内涵段子的资深用户,前段时间基本被一款叫火萤视频桌面的软件(就是将视频做为桌面)给刷屏了,因此看了下做者的代码,看到了SurfaceHolder,马上想到了,确定能够用来播放视频实现视频桌面的效果,因而周末尝试了下,果真很简单。java
因此本篇文章无限感谢Android 实现"透明屏幕一文,代码也部分参考自其提供的透明相机。android
效果图是这样的:github
注:本文的测试机为小米5s ,可能不一样手机会有一些兼容性问题,尝试解决下。微信
首先编写一个xml文件,用于描述wallpaper的thumbnail
、description
、settingsActivity
等,这里为了简单,仅设置了thumbnail。app
<?xml version="1.0" encoding="utf-8"?>
<wallpaper xmlns:android="http://schemas.android.com/apk/res/android" android:thumbnail="@mipmap/ic_launcher" />复制代码
Wallpaper须要在屏幕上一直显示,其背后实际上是一个Service,因此实现一个Wallpaper须要继承自WallpaperService
,实现其抽象方法onCreateEngine
,以下:ide
public class VideoLiveWallpaper extends WallpaperService {
public Engine onCreateEngine() {
return new VideoEngine();
}
//...
}复制代码
能够看到返回值是一个Engine,Engine为WallpaperService的内部类,其内部包含onSurfaceCreated
、onSurfaceChanged
、onSurfaceDestroyed
、onTouchEvent
等方法,看到这些方法,马上想到了SurfaceView,关于SurfaceView相关知识能够参考:oop
此外,你们还记得在Android播放视频吗?
常规的作法有经过VideoView,除此之外还有经过MediaPlayer配合SurfaceView配合来实现,今天这个例子相似后者。
咱们只须要经过MediaPlayer将解码的数据不断的输送到传入的Surface中便可。
class VideoEngine extends Engine {
private MediaPlayer mMediaPlayer;
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
L.d("VideoEngine#onSurfaceCreated ");
super.onSurfaceCreated(holder);
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setSurface(holder.getSurface());
try {
AssetManager assetMg = getApplicationContext().getAssets();
AssetFileDescriptor fileDescriptor = assetMg.openFd("test1.mp4");
mMediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),
fileDescriptor.getStartOffset(), fileDescriptor.getLength());
mMediaPlayer.setLooping(true);
mMediaPlayer.setVolume(0, 0);
mMediaPlayer.prepare();
mMediaPlayer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onVisibilityChanged(boolean visible) {
L.d("VideoEngine#onVisibilityChanged visible = " + visible);
if (visible) {
mMediaPlayer.start();
} else {
mMediaPlayer.pause();
}
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
L.d("VideoEngine#onSurfaceDestroyed ");
super.onSurfaceDestroyed(holder);
mMediaPlayer.release();
mMediaPlayer = null;
}复制代码
代码很是简单,在onSurfaceCreated中去初始化mMediaPlayer,核心代码即为设置setSurface方法,这里我默认设置了静音。
onVisibilityChanged,即当桌面不可见时,咱们要暂停播放,等回到桌面继续。
当onSurfaceDestroyed时释放资源~~
这样咱们的VideoLiveWallpaper就写好了,别忘了他是个Service,须要咱们去注册。
<service android:name=".VideoLiveWallpaper" android:label="@string/app_name" android:permission="android.permission.BIND_WALLPAPER" android:process=":wallpaper">
<!-- 配置intent-filter -->
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" />
</intent-filter>
<!-- 配置meta-data -->
<meta-data android:name="android.service.wallpaper" android:resource="@xml/livewallpaper" />
</service>复制代码
注册完成后,咱们在MainActivity中添加一个按钮点击设置为桌面背景,调用代码以下
public static void setToWallPaper(Context context) {
final Intent intent = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
new ComponentName(context, VideoLiveWallpaper.class));
context.startActivity(intent);
}复制代码
这样就完成了代码的初步编写啦~~
刚才咱们设置了默认是静音,可能有时候咱们会但愿可以动态去控制视频桌面的参数,正常应该尝试去使用settingsActivity
,不过我以为其实广播也挺合适的,无非就是Service(可能在独立的进程)和Activity等通讯嘛~~
这里咱们增长一个复选框,支持设置开启声音or关闭声音。
public static final String VIDEO_PARAMS_CONTROL_ACTION = "com.zhy.livewallpaper";
public static final String KEY_ACTION = "action";
public static final int ACTION_VOICE_SILENCE = 110;
public static final int ACTION_VOICE_NORMAL = 111;
class VideoEngine extends Engine {
// 省略其余代码
private BroadcastReceiver mVideoParamsControlReceiver;
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
IntentFilter intentFilter = new IntentFilter(VIDEO_PARAMS_CONTROL_ACTION);
registerReceiver(mVideoParamsControlReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
L.d("onReceive");
int action = intent.getIntExtra(KEY_ACTION, -1);
switch (action) {
case ACTION_VOICE_NORMAL:
mMediaPlayer.setVolume(1.0f, 1.0f);
break;
case ACTION_VOICE_SILENCE:
mMediaPlayer.setVolume(0, 0);
break;
}
}
}, intentFilter);
}
@Override
public void onDestroy() {
unregisterReceiver(mVideoParamsControlReceiver);
super.onDestroy();
}
}复制代码
Engine还有onCreate和onDestroy声明周期方法,能够在onCreate中注册动态广播,当接受到发送的action为ACTION_VOICE_NORMAL
则开启声音;接收到发送的ACTION_VOICE_SILENCE
则为静音状态。
最后直接在VideoLiveWallpaper中添加两个静态方法用于发送广播便可:
public static void voiceSilence(Context context) {
Intent intent = new Intent(VideoLiveWallpaper.VIDEO_PARAMS_CONTROL_ACTION);
intent.putExtra(VideoLiveWallpaper.KEY_ACTION, VideoLiveWallpaper.ACTION_VOICE_SILENCE);
context.sendBroadcast(intent);
}
public static void voiceNormal(Context context) {
Intent intent = new Intent(VideoLiveWallpaper.VIDEO_PARAMS_CONTROL_ACTION);
intent.putExtra(VideoLiveWallpaper.KEY_ACTION, VideoLiveWallpaper.ACTION_VOICE_NORMAL);
context.sendBroadcast(intent);
}复制代码
在Actiivty中:
public class MainActivity extends AppCompatActivity {
private CheckBox mCbVoice;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCbVoice = (CheckBox) findViewById(R.id.id_cb_voice);
mCbVoice.setOnCheckedChangeListener(
new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged( CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
// 静音
VideoLiveWallpaper.voiceSilence(getApplicationContext());
} else {
VideoLiveWallpaper.voiceNormal(getApplicationContext());
}
}
});
}
}复制代码
监听一下CheckBox状态,发送广播便可。
ok,这样一个简单的视频桌面就完成啦~~
源码地址:
直接将这个目录以项目形式导入。
支持个人话能够关注下个人公众号,天天都会推送新知识~
欢迎关注个人微信公众号:hongyangAndroid
(能够给我留言你想学习的文章,支持投稿)