码迷,mamicode.com
首页 > 其他好文 > 详细

QQ音乐/酷狗音乐锁屏控制实现原理

时间:2015-08-31 01:12:31      阅读:903      评论:0      收藏:0      [点我收藏+]

标签:android   锁屏   qq音乐锁屏   酷狗音乐锁屏   锁屏控制   

我实现的效果

技术分享

混乱的锁屏控制

Android自4.0版本, 也就是API level 14开始, 加入了锁屏控制的功能, 相关的类是RemoteControlClient, 这个类在API level 21中被标记为deprecated, 被新的类MediaSession所替代. 我们的音乐App中最开始使用的是原生锁屏控制API, 说实话这个API不好用, 遇到了一些小坑, 最要命的是不同品牌的手机, 锁屏界面长的还不一样, 就连我自己都没见过原生4.0的锁屏控制界面是什么样的. 国内的手机厂商都自以为自己的审美很强, 设计了千奇百怪的锁屏控制界面, MIUI更奇怪, MIUI 6是在原生4.4.4的基础上改的, 竟然有一段时间都没有锁屏控制界面, 后来更新才有. 而原生Android在5.0时, 将锁屏和通知栏控制合并, 整个逻辑非常混乱. 我们还是决定像QQ音乐/酷狗音乐那样, 自己做一个锁屏控制页面

题外话: 给RemoteControlClient设置封面时, 参数是一个Bitmap, 这个参数传入后, 千万不要在其他地方使用这个Bitmap, 也不要持有它的引用, 更不要自作聪明调用它的recycle方法.

实现思路

锁屏应用: 大炮打蚊子

首先想到的因该是做一个锁屏, 也就是使用Android的API, 做一个锁屏应用, 和输入法等应用一样, 但这个方法成本很高. 国内的那些锁屏应用, 首先要做的就是引导用户设置锁屏应用, 步骤相当繁杂, 只是为了一个播放控制就用一个锁屏应用, 没有哪个用户会这么有耐心.

悬浮窗: 黑魔法

得益于我国程序员的脑洞, 我们有了第二种思路: 悬浮窗.
悬浮窗的一个比较严谨的名字叫系统警告窗口, 国内外的一些流氓厂商, 经常用悬浮窗弹一些广告, 这个悬浮窗是浮在正常的app的上面的, 所以如果它不消失, 很可能你连正常使用手机都有问题.
这是一个比较打扰用户的东西, 而且也有一定的安全风险. MIUI的权限管理默认是将悬浮窗关闭的, 而有道词典的复制查词功能, 就是用悬浮窗做的, 如果你没给有道词典打开这个权限, 复制查词这个功能就废了.

普通Activity伪造锁屏

文章开头的GIF图片展示的效果, 就是用一个普通Activity做的.
国内的app们, 最终都选择了这条道路, 不知道他们是谁抄的谁, 第一个想到使用普通Activity伪造一个锁屏的开发者, 我只能说非常有创造力.

监听锁屏事件

准确来说我们监听的是屏幕熄灭事件, 关屏事件的Intent是Intent.ACTION_SCREEN_OFF, 不需要任何权限就可以监听, 但是必须使用代码注册, 也就是说我们必须有一个Service在后台监听才行, 对音乐类app来说, 这不是问题, 音乐app本身就是使用Service来控制MediaPlayer的. 只需要在Service中注册监听Intent.ACTION_SCREEN_OFF就行. 监听到这个事件,

@Override
public void onReceive(Context context, Intent intent) {
    String action = intent.getAction();
    if (action.equals(Intent.ACTION_SCREEN_OFF)) {
        Intent lockscreen = new Intent(PlaybackService.this, LockScreenActivity.class);
        lockscreen.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(lockscreen);
    }
}

注意我们在Service中启动一个Activity, 需要加上Intent.FLAG_ACTIVITY_NEW_TASK这个flag才行.

透明背景

要想做到锁屏那样滑动解锁, 比如像图中的样子, 我们除了要根据手势移动View以外, 还要让Activity的背景透明, 比如将theme设置成下面这样.

<style name="LockScreenBase" parent="AppBaseTheme">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:colorBackgroundCacheHint">@null</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:backgroundDimEnabled">false</item>
    <item name="android:windowAnimationStyle">@null</item>
    <item name="android:windowContentOverlay">@null</item>
</style>

这个style其实做了很多东西, 大家根据自己的需要可以删减一部分, 比如状态栏透明, 不使用TitleBar之类的.

解锁屏幕与显示在锁屏之上

在显示我们的假锁屏的时候, 我们应当帮用户解锁, 这样我们才能冒充锁屏, 而不会出现用户”解锁”两次的情况, 但我们只能要求系统解锁没有密码的锁屏, 有密码的情况下, 我们是不能解锁屏幕的, 这时我们应该覆盖在锁屏界面上, 幸好, 在API level 5中就引入了两个Flag, FLAG_DISMISS_KEYGUARDFLAG_SHOW_WHEN_LOCKED
在锁屏Activity的onCreate方法中给Activity加上两个Flag

this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);

一定要两个一起用, 否则效果不大好, 当时测试了好久, 后来看了一下QQ音乐的实现, 才发现两个一起用效果才好, 否则会有一些奇怪的问题.

隐藏踪迹与独立的Task

作为一个锁屏界面, 应当是独立的, 也就是说, 我们这个Activity应当独立于我们的App存在, 至少看起来是这样. 从Android的角度来看, 我们app的主界面里的所有Activity, 应当在一个Task里, 而锁屏Activity, 应当在一个独立的Task里, 因此我们需要给锁屏Activity一个独立的Task, 而且无论何时, 都只有一个锁屏Activity实例存在.
另外, Android有查看近期任务的功能, 我们不希望锁屏界面这个独立的Task显示在里面, 所以锁屏Activity不能显示在近期任务中.
说了这么多, 要做很简单, 只需要在Manifest里面声明Activity时加入几个属性即可

<activity android:excludeFromRecents="true"
    android:exported="false"
    android:launchMode="singleInstance"
    android:name=".view.lockscreen.LockScreenActivity"
    android:screenOrientation="portrait"
    android:taskAffinity="com.package.name.lockscreen"
    android:theme="@style/LockScreenTheme">
</activity>

上面的属性中android:excludeFromRecents="true"让锁屏Activity不显示在近期任务中, android:launchMode="singleInstance"android:taskAffinity="com.package.name.lockscreen"保证锁屏Activity有一个单独的Task, 且这个Task里永远只有它一个实例.

不响应Back按键

锁屏界面当然不响应Back按键, 只需要重写Activity的onBackPressed方法即可

@Override
public void onBackPressed() {
    // do nothing
}

对Home按键的处理

我们无法监听Home按键, 但是可以改变因Home进入后台时的处理, 比如在Manifest的activity声明中加上

android:noHistory="true"

这样如果用户通过Home按键让我们的应用进入后台, 我们会让这个activity销毁, 就像我们被滑动关闭一样.
如果不加, 最好重写Activity的onNewIntent来应对因Home进入后台, 然后Service再次启动锁屏Activity的情况.

处理黑色闪屏

我们的锁屏Activity在滑动”解锁”之后, 理论上是直接进入下面的界面, 但有时如果下面不是launcher, 而是一个app, 有可能会闪一下黑屏, 这个其实是底下activity的入场动画导致的, 某些Android版本会对顶部activity透明时处理有些奇怪, 我们不能保证其他的应用不闪黑屏, 但是对自己的的应用还是可以的, 只需要在我们的主体activity的style中加上

<item name="android:windowAnimationStyle">@null</item>

就不会有这种情况发生了, 但是这样的话入场动画也没了, 总之如何取舍看大家了.

版权声明:本文为博主原创文章,未经博主允许不得转载。

QQ音乐/酷狗音乐锁屏控制实现原理

标签:android   锁屏   qq音乐锁屏   酷狗音乐锁屏   锁屏控制   

原文地址:http://blog.csdn.net/shaw1994/article/details/48116353

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!