本文已在個人公衆號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
(能夠給我留言你想學習的文章,支持投稿)