Android6.0系统适配桌面歌词效果

在360手机助手及各家的音乐播放器软件上,都使用了桌面浮动窗功能,桌面歌词都是在音乐客户端显示在前台时隐藏,在用户把软件切换到后台后显示出来,此效果在Android 6.0以前,大部分都是使用系统的ActivityManager系统类的getRunningAppProcesses或getRunningTasks(Android5.0需要多判断一步)来进行软件前后台状态的判断,然后使用WindowManager进行浮动窗控件的增加和删除实现桌面歌词的显示与隐藏。但在Android6.0后,如果是使用SDK中6.0的编译工具编译的App,ActivityManager的方法和WindowManager的方法都有权限问题,不能简单直接的使用了。下面通过一个模仿桌面歌词效果的例子,来说明6.0上的实现。

首先讲一下6.0以前版本判断前后台状态方式:

private static void UpdateForgroundState() {
        boolean isForground = IS_FORGROUND;
        Context ctx = App.getInstance().getApplicationContext();
        ActivityManager activityManager = (ActivityManager)ctx.getSystemService(Context.ACTIVITY_SERVICE);
        String packageName = ctx.getPackageName();
        List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
        if (appProcesses == null) {         
            return;
        }
        for (RunningAppProcessInfo appProcess : appProcesses) {
            if (!appProcess.processName.equals(packageName)) {
                continue; //不是本程序的包名,跳过
            }
            isForground = CompatibleCheckAppState(ctx,activityManager,appProcess);
            break;
        }       
        if (IS_FORGROUND == isForground) {
            return;
        }
        IS_FORGROUND = isForground;
        if (isForground) {
            //通知程序桌面歌词类,当前是前台状态,你要隐藏起来
        } else {
            //通知桌面歌词类,当前是后台运行中,你要出来显示了
        }
    }

    private static boolean CompatibleCheckAppState(Context ctx,ActivityManager am,RunningAppProcessInfo pInfo){
        if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.KITKAT){  //Android5.0的判断前后台和以前版本不一样。要通过topActivity找包名判断,
            if(am==null){
                return false;
            }
            List<RunningTaskInfo> tasks = am.getRunningTasks(1);
            if (!tasks.isEmpty()) {
                ComponentName topActivity = tasks.get(0).topActivity;
                if (topActivity!=null&&ctx!=null&&topActivity.getPackageName().equals(ctx.getPackageName())) {
                    return true;
                }
            }
            return false;
        }else{
            //5.0以前的系统,可以直接通过RunningAppProcessInfo类的importance属性判断前后台状态
            return pInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
        }
    }

Android4.0–Android6.0可通用的判断前台后的方法

首先要自定义Application类,在类中进行ActivityLifecycleCallbacks的接口实现类进行注册与反注册

@Override
    public void onCreate() {
        super.onCreate();
        this.registerActivityLifecycleCallbacks(callbacks);
    }

    @Override
    public void onTerminate() {
        this.unregisterActivityLifecycleCallbacks(callbacks);
        super.onTerminate();
    }

然后在接口实现类中,实现如下代码,在全局进行状态标识更新

private Application.ActivityLifecycleCallbacks callbacks = new ActivityLifecycleCallbacks() {
        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        }

        @Override
        public void onActivityStarted(Activity activity) {
            activityShowingCount++;
            changeActivityFlag(activity,activityShowingCount>0);
        }

        @Override
        public void onActivityResumed(Activity activity) {         
        }

        @Override
        public void onActivityPaused(Activity activity) {
        }

        @Override
        public void onActivityStopped(Activity activity) {
            activityShowingCount--;
            changeActivityFlag(activity,activityShowingCount>0);            
        }

        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        }

        @Override
        public void onActivityDestroyed(Activity activity) {
        }
    };

上面需要注意的是,一定要把判断逻辑放到started和stopped回调事件中,而不能放到Resumed和paused事件中,因为这二个事件在应用有多个Activity进行交替打开时,桌面歌词会显一下。
上面这种方法不需要申请权限,简单安全。