浅谈视频壁纸

视频壁纸,对于动态壁纸开发,就得用到WallpaperService;

manifest配置:



    
    
        
    
    
    

注意:meta-data的 xml文件,主要是在 系统设置->显示->动态壁纸里面会显示icon和说明;


设置壁纸需要权限:

因为用到视频,所以要用到MediaPlayer;而MediaPlayer 播放本地视频,有时候莫名会黑屏(暂时没找到原因,可能原因IO问题);

暂时解决方案:OnError方法里面,先销毁,再清空壁纸,再重新设置壁纸;

package com.mill.wpengine;

import android.app.WallpaperInfo;
import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.service.wallpaper.WallpaperService;
import android.view.SurfaceHolder;
import android.widget.Toast;

import java.util.Date;

/**
 * 视频壁纸引擎服务
 *
 * 多进程sp访问,主工程里面调用:
 * SharedPreferences sp = context.getSharedPreferences(SP_EXPORT_FILE, Context.MODE_MULTI_PROCESS | Context.MODE_WORLD_READABLE);
    sp.edit().putString(SP_KEY_FIRST_SET_FILEPATH, videoFilePath).commit();

 */
public class VideoLiveWallpaper extends WallpaperService {
    public static final String TAG = "VideoLiveWallpaper";

    public static final String VIDEO_WP_ENGINE_PRE = "video_wp_engine";

    public static final String AP_APK_NAME = "<主工程包名>";

    public static final String SP_VIDEO_FILE_DEFAULT = "<默认视频路径,建议放远程路径>";
    public static final String SP_EXPORT_FILE = "plugin_vwp_export";
    public static final String SP_KEY_FIRST_SET_FILEPATH = "KEY_FIRST_SET_FILEPATH";
    public static final String SP_KEY_VIDEODESKTOP_USED_LAST_TIME = "VideoDesktop_Used_Last_Time";
    public static final String SP_KEY_ALIVE_AP_LAST_TIME = "alive_ap_last_time";

    public final static String THREAD_NAME_ALIVE_AP = "alive_thread";        // 视频壁纸引擎APK,拉活
    public static final String VIDEO_PARAMS_CONTROL_ACTION = "com.zhy.livewallpaper";
    public static final String KEY_VOLUME_WPSETTING = "KEY_Volume_WPSetting";
    public static final String KEY_ACTION = "action";
    public static final int ACTION_VOICE_SILENCE = 110;
    public static final int ACTION_VOICE_NORMAL = 111;

    private String mVideoFilePath = null;
    private VideoEngine mEngine;
    private MediaPlayer mMediaPlayer;

    //拉活 线程
    private HandlerThread mHandlerThread;
    private Handler mHandler;
    private Runnable mAliveRunnable;
    private boolean isAliveThreadRun = false;

    public Engine onCreateEngine() {
        mEngine = new VideoEngine();
        if (mVideoFilePath == null) {
            mVideoFilePath = getSPPath();
        }
        return mEngine;
    }

    /**
     * 获取本地存的路径
     */
    public String getSPPath() {
        String filePath = null;
        try {
            Context c = getApplicationContext().createPackageContext(AP_APK_NAME, Context.CONTEXT_IGNORE_SECURITY);
            SharedPreferences sp = c.getSharedPreferences(SP_EXPORT_FILE, Context.MODE_WORLD_READABLE | Context.MODE_MULTI_PROCESS);
            filePath = sp.getString(SP_KEY_FIRST_SET_FILEPATH, null);

            if (filePath != null) {
                getApplicationContext().getSharedPreferences(VideoLiveWallpaper.VIDEO_WP_ENGINE_PRE, MODE_PRIVATE).edit().putString(SP_KEY_FIRST_SET_FILEPATH, filePath).commit();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        /**
         * 引擎保存的SP里面取
         */
        if (filePath == null) {
            filePath = getApplicationContext().getSharedPreferences(VideoLiveWallpaper.VIDEO_WP_ENGINE_PRE, MODE_PRIVATE).getString(SP_KEY_FIRST_SET_FILEPATH, null);
        }

        /**
         * 默认壁纸
         * 暂时先放个网络路径
         * 防止系统设置-显示-动态壁纸,选择后是黑的
         */
        if (filePath == null) {
            filePath = SP_VIDEO_FILE_DEFAULT;
        }
        return filePath;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mHandlerThread = new HandlerThread(THREAD_NAME_ALIVE_AP);
        mHandlerThread.start();
        mHandler = new Handler(mHandlerThread.getLooper());
        mAliveRunnable = new Runnable() {
            @Override
            public void run() {
                // 拉活代码......
                isAliveThreadRun = false;
            }
        };
    }

    @Override
    public void onDestroy() {
        if (mEngine != null) {
            mEngine.destroy();
        }
        if (mHandlerThread != null) {
            mAliveRunnable = null;
            mHandler.removeCallbacksAndMessages(null);
            mHandler = null;
            mHandlerThread.quit();
            mHandlerThread = null;
        }
        super.onDestroy();
    }

    private class VideoEngine extends Engine implements MediaPlayer.OnErrorListener {

        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) {
                    int action = intent.getIntExtra(KEY_ACTION, -1);
                    getApplicationContext().getSharedPreferences(VideoLiveWallpaper.VIDEO_WP_ENGINE_PRE, MODE_PRIVATE).edit().putInt(KEY_VOLUME_WPSETTING, action).commit();
                    setVolumeByWPSetting();
                }
            }, intentFilter);
        }

        /**
         * 根据视频桌面插件里面的设置来判断
         * 本地存储下状态,方便开机时
         */
        private void setVolumeByWPSetting() {
            int action = getApplicationContext().getSharedPreferences(VideoLiveWallpaper.VIDEO_WP_ENGINE_PRE, MODE_PRIVATE).getInt(KEY_VOLUME_WPSETTING, -1);
            switch (action) {
                case ACTION_VOICE_NORMAL:
                    if (mMediaPlayer != null) {
                        mMediaPlayer.setVolume(1.0f, 1.0f);
                    }
                    break;
                case ACTION_VOICE_SILENCE:
                    if (mMediaPlayer != null) {
                        mMediaPlayer.setVolume(0, 0);
                    }
                    break;
            }
        }

        @Override
        public void onDestroy() {
            if (mVideoParamsControlReceiver != null) {
                unregisterReceiver(mVideoParamsControlReceiver);
            }
            super.onDestroy();
        }

        @Override
        public void onVisibilityChanged(boolean visible) {
            if (mMediaPlayer != null) {
                if (visible) {
                    aliveAp();
//                    checkAPInstalled();
                    stateUsed();
                    startCheckPath();
                } else {
                    mMediaPlayer.pause();
                }
            }
        }

        /**
         * 是否安装了pkgName
         *
         * @param pkgName
         * @return
         */
        private boolean isAppInstalled(String pkgName) {
            boolean result = false;
            try {
                result = getPackageManager().getPackageInfo(pkgName, PackageManager.GET_DISABLED_COMPONENTS) != null;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }

        /**
         * 检测主工程是否安装了,否则清掉视频壁纸
         */
        private void checkAPInstalled() {
            if (!isAppInstalled(AP_APK_NAME) && isLiveWallpaperRunning()) {
                //卸载了,则清掉视频壁纸
                try {
                    WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
                    wallpaperManager.clear();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        /**
         * 拉活 主工程
         */
        private void aliveAp() {
            //拉活
//            long lastTime = getApplicationContext().getSharedPreferences(VideoLiveWallpaper.VIDEO_WP_ENGINE_PRE, MODE_PRIVATE).getLong(SP_KEY_ALIVE_AP_LAST_TIME, 0);
//            if (!DateUtils.isToday(lastTime)) {
//                getApplicationContext().getSharedPreferences(VideoLiveWallpaper.VIDEO_WP_ENGINE_PRE, MODE_PRIVATE).edit().putLong(SP_KEY_ALIVE_AP_LAST_TIME, System.currentTimeMillis()).commit();
//            }
            if (mHandler != null) {
                if (!isAliveThreadRun) {
                    isAliveThreadRun = true;
                    mHandler.post(mAliveRunnable);
                }
            }
        }

        /**
         * 视频壁纸 是否启动了
         *
         * @return
         */
        private boolean isLiveWallpaperRunning() {
            WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());// 得到壁纸管理器
            WallpaperInfo wallpaperInfo = wallpaperManager.getWallpaperInfo();// 如果系统使用的壁纸是动态壁纸话则返回该动态壁纸的信息,否则会返回null
            if (wallpaperInfo != null) { // 如果是动态壁纸,则得到该动态壁纸的包名,并与想知道的动态壁纸包名做比较
                String currentLiveWallpaperPackageName = wallpaperInfo.getPackageName();
                if (currentLiveWallpaperPackageName.equals(getPackageName())) {
                    return true;
                }
            }
            return false;
        }

        /**
         * 每天打点一次,用户还在使用视频桌面
         */
        private void stateUsed() {
            if (isLiveWallpaperRunning()) {
                Date date = new Date();
                String curDate = date.getYear() + "-" + date.getMonth() + "-" + date.getDay();
                String lastDate = getApplicationContext().getSharedPreferences(VideoLiveWallpaper.VIDEO_WP_ENGINE_PRE, MODE_PRIVATE).getString(SP_KEY_VIDEODESKTOP_USED_LAST_TIME, null);
                if (!curDate.equals(lastDate)) {
                    getApplicationContext().getSharedPreferences(VideoLiveWallpaper.VIDEO_WP_ENGINE_PRE, MODE_PRIVATE).edit().putString(SP_KEY_VIDEODESKTOP_USED_LAST_TIME, curDate).commit();
                    //打点......
                }
            }
        }

        private void startCheckPath() {
            if (mMediaPlayer != null) {
                String spPath = getSPPath();
                if (spPath != null && !spPath.equals(mVideoFilePath)) {
                    mVideoFilePath = spPath;
                    try {
                        mMediaPlayer.reset();
                        mMediaPlayer.setDataSource(mVideoFilePath);
                        if (Build.VERSION.SDK_INT >= 16) {
                            mMediaPlayer.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
                        }
                        mMediaPlayer.setLooping(true);
                        setVolumeByWPSetting();
                        mMediaPlayer.prepare();
                        mMediaPlayer.start();
                    } catch (Exception e) {
                        e.printStackTrace();
                        onError(mMediaPlayer, 0, 0);
                    }
                } else {
                    mMediaPlayer.start();
                }
            }
        }


        @Override
        public void onSurfaceCreated(SurfaceHolder holder) {
            super.onSurfaceCreated(holder);
            destroy();
            if (mMediaPlayer == null) {
                mMediaPlayer = new MediaPlayer();
                mMediaPlayer.setOnErrorListener(this);
                mMediaPlayer.setSurface(holder.getSurface());
            }
            startCheckPath();
        }

        public boolean onError(MediaPlayer mp, int what, int extra) {
            //视频播放,莫名其妙 黑屏,重新设置;
            Toast.makeText(getApplicationContext(), R.string.video_wallpaper_play_error, Toast.LENGTH_LONG).show();
            try {
                //销毁内存
                destroy();

                //清除壁纸
                WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
                wallpaperManager.clear();

                //重新设置视频壁纸
                Intent localIntent = new Intent();
                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
                    localIntent.setAction(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
                    localIntent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT
                            , new ComponentName(getApplicationContext(), VideoLiveWallpaper.class));
                } else {
                    localIntent.setAction(WallpaperManager.ACTION_LIVE_WALLPAPER_CHOOSER);
                }
                localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                localIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
                getApplicationContext().startActivity(localIntent);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return true;
        }

        @Override
        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            super.onSurfaceChanged(holder, format, width, height);
        }

        @Override
        public void onSurfaceDestroyed(SurfaceHolder holder) {
            super.onSurfaceDestroyed(holder);
        }

        public void destroy() {
            if (mMediaPlayer != null) {
                mMediaPlayer.stop();
                mMediaPlayer.reset();
                mMediaPlayer.release();
                mMediaPlayer = null;
            }
            //path清空
            mVideoFilePath = null;
        }
    }

}

 

MediaPlayer的销毁,最好放到Service的OnDestroy里面,因为第一次设置动态壁纸,需要调起系统设置壁纸页面,设置成功的时候,Engine实际是有两个(一个系统设置页面的,一个桌面的),而Service只有一个,系统设置页面退出后onSurfaceDestroyed会延后调用;防止一些bug;

源码地址:https://github.com/miLLlulei/WallpaperEngine ,欢迎大家来star;

下面介绍一些其他方法:

/**
     * 获取系统默认图片壁纸
     *
     * @return
     */
    public static String getDefaultWallpaperInfo() {
        InputStream is = null;
        Bitmap bmWp = null;
        try {
            final String path = HideApiHelper.SystemProperties.get("ro.config.wallpaper");
            if (!TextUtils.isEmpty(path)) {
//                Log.d(TAG, "getDefaultWallpaperInfo path = " + path);
                final File file = new File(path);
                if (file.exists()) {
                    is = new FileInputStream(file);
                }
            } else {
                int resourceId = ContextUtils.getApplicationContext().getResources().getIdentifier("default_wallpaper", "drawable", "android");
                is = ContextUtils.getApplicationContext().getResources().openRawResource(resourceId);
            }
            if (is != null) {
                BitmapFactory.Options options = new BitmapFactory.Options();
                bmWp = BitmapFactory.decodeStream(is, null, options);
                return FLAG_WP_BITMAP + FLAG_WP_SPLIT + bmWp.getWidth()
                        + FLAG_WP_SPLIT + bmWp.getHeight()
                        + FLAG_WP_SPLIT + BitmapUtils.getBitmapSize(bmWp)
                        + FLAG_WP_SPLIT + bmWp.getPixel(1, 1)
                        ;
            }
        } catch (Throwable e) {
            Log.d(TAG, "Can't decode stream", e);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
            if (bmWp != null) {
                bmWp.recycle();
            }
        }
        return SP_KEY_WP_SETED_STR_DEFAULT;
    }


/**
     * 获取当前壁纸是什么
     */
    public static String getCurWallpaperStr() {
        String wpInfo = SP_KEY_WP_SETED_STR_DEFAULT;
        try {
            WallpaperManager wallpaperManager = WallpaperManager.getInstance(ContextUtils.getApplicationContext());
            WallpaperInfo liveWp = wallpaperManager.getWallpaperInfo();
            if (liveWp == null) {
                BitmapDrawable drWp = (BitmapDrawable) wallpaperManager.getDrawable();
                if (drWp != null) {
                    Bitmap bmWp = drWp.getBitmap();
                    wpInfo = FLAG_WP_BITMAP + FLAG_WP_SPLIT + bmWp.getWidth()
                            + FLAG_WP_SPLIT + bmWp.getHeight()
                            + FLAG_WP_SPLIT + BitmapUtils.getBitmapSize(bmWp)
                            + FLAG_WP_SPLIT + bmWp.getPixel(1, 1)
                            ;
                }
            } else {
                wpInfo = FLAG_WP_LIVE + FLAG_WP_SPLIT + liveWp.getPackageName() + FLAG_WP_SPLIT + liveWp.getServiceName();
            }
        } catch (Exception e) {
            //魅族手机,getCurrentWallpaperLocked()可能报错java.io.IOException: broken file descriptor
            e.printStackTrace();
        }
        return wpInfo;
    }

调起系统设置壁纸页面,动态壁纸的设置,必须调起系统的:

 

 

try {
    Intent localIntent = new Intent();
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {//ICE_CREAM_SANDWICH_MR1  15
        localIntent.setAction(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);//android.service.wallpaper.CHANGE_LIVE_WALLPAPER
        localIntent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT
                , new ComponentName(pkgName, className));
    } else {
        localIntent.setAction(WallpaperManager.ACTION_LIVE_WALLPAPER_CHOOSER);//android.service.wallpaper.LIVE_WALLPAPER_CHOOSER
    }
    localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    localIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
    context.startActivity(localIntent);
} catch (Exception e) {
    e.printStackTrace();
}

 

 

你可能感兴趣的:(Android)