Android锁屏实现与总结

Android锁屏实现与总结(网易云阅读)

一、自定义锁屏基本原理

二、重要步骤

1、广播注册

2、Activity设置

3、按键的屏蔽

4、滑屏解锁

5、Event bus的使用

三、出现的问题

1、小米和魅族等手机锁屏权限问题

2、透明栏与沉浸模式

3、手机适配

4、处理黑色闪屏

5、线控耳机

6、Android上的「安全音量」

一、自定义锁屏基本原理

先上效果图:

实现锁屏的方式有多种(锁屏应用、悬浮窗、普通Activity伪造锁屏等等)。通过网络查找资料与反编译云音乐apk,本项目使用了国内比较主流并且被广泛应用的Activity伪造锁屏方式。

Activity实现自定义锁屏页的思路很简单,即在听书模式开启时,启动一个service,在service中监听系统SCREEN_OFF的广播。当屏幕熄灭时service监听到广播,开启一个锁屏页Activity在屏幕最上层显示,该Activity创建的同时会去掉系统的锁屏(如果有密码是禁不掉的)。示意图如下:


二、重要步骤

1、广播注册

LockScreenService是普通的Service,在应用启动听书模式时候startService(ReadBookActivity),与应用同一个进程。


此外,SCREEN_OFF广播监听必须是动态注册的,如果在AndroidManifest.xml中静态注册将无法接收到SCREEN_OFF广播。


标志位FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS,是为了避免在最近使用程序列表出现Service所启动的Activity。


启动Activity时Intent的Flag,如果不添加FLAG_ACTIVITY_NEW_TASK的标志位,会出现“Calling startActivity() from outside of an Activity”的运行时异常,因为我们是从Service启动的Activity。Activity要存在于activity的栈中,而Service在启动activity时必然不存在一个activity的栈,所以要新起一个栈,并装入启动的activity。使用该标志位时,也需要在AndroidManifest中声明taskAffinity,即新task的名称,否则锁屏Activity实质上还是在建立在原来App的task栈中。


2、Activity设置

锁屏的activity内部也要做相应的配置,让activity在锁屏时也能够显示,同时去掉系统锁屏。当然如果设置了系统锁屏密码,系统锁屏是没有办法去掉的,这里考虑没有设置密码的情况。我们在自定义锁屏Activity的onCreate()方法里设定以下标志位就能完全实现相同的功能:


FLAG_DISMISS_KEYGUARD用于去掉系统锁屏页,FLAG_SHOW_WHEN_LOCKED使Activity在锁屏时仍然能够显示。另外需要在Manifest中加入适当的权限:


3、按键的屏蔽

当自定义锁屏页最终出现在手机上时,我们希望它像系统锁屏页那样屹立不倒,所有的按键都不能触动它,只有通过划屏或者指纹才能解锁,因此有必要对按键进行一定程度上的屏蔽。针对只有虚拟按键的手机,我们可以通过隐藏虚拟按键的方式部分解决这个问题。但是当用户在锁屏页底部滑动,隐藏后的虚拟按键还是会滑出,而且如果用户是物理按键的话就必须进行屏蔽了。需要重写Activity的onBackPressed()方法即可。


Home键 与Recent键的点击事件是在framework层进行处理的,因此onKeyDown()与dispatchKeyEvent()都捕获不到点击事件。关于这两个按键的屏蔽方法,网上相关的资料有很多,有的用到了反射,有的通过改变Window的标志位和Type等,总的来说这些方法只对部分android版本有效,有的则完全无法编译通过。其实这么做的目的无非是为了实现一个纯粹的锁屏页,但是这种做法容易造成锁屏页的异常崩溃,我们要满足的是用户在锁屏页的快捷操作,Home键和Recent键无关痛痒,基本可以不管。

4、滑屏解锁

做完以上几步,当屏幕熄灭后,再打开屏幕就能够看到我们的自定义锁屏页了。接下来要实现划屏解锁。划瓶解锁的基本思路很简单,当手指在屏幕上滑动时,拦截并处理滑动事件,使锁屏页面随着手指运动,当运动到达一定的阈值时,用户手指松开手指,锁屏页自动滑动到屏幕边界消失,如果没有达到运动阀值,就会自动滑动到起始位置,重新覆盖屏幕。 为了将划屏逻辑与页面内容隔离开来,我们在锁屏页面布局中添加一个自定义的UnderView,这个UnderView填充整个屏幕,位于锁屏内容View(将其引用称之为mMoveView,并传入到UnderView中)的下方,所有划屏相关的事件都在这里拦截并处理。


mMoveView是锁屏页的显示内容,除了处理一些简单的点击事件,其他非点击事件序列都由底层的UnderView进行处理。只需要重写UnderView的onTouchEvent方法就能够实现


其中,mStartX记录滑动操作起始的x坐标,handleMoveView方法控制mMoveView随手指的移动,doTriggerEvent处理手指离开后mMoveView的移动动画。两个方法的定义如下:

在handleMoveView()中,首先计算当前触点x坐标与初始x坐标mStartX的差值movex,然后调用mMoveView的setTranslationX方法移动。此外,我们可以通过getBackground()获取UnderView的背景,并根据已划开屏幕占整个屏幕的百分比调用setAlpha方法改变背景的透明度,做出抽屉拉开时的光影变化效果。


当手指离开屏幕,doTraiggerEvent方法会对滑动的距离与阀值进行一个比较,此处的阀值为0.4*屏幕宽度,如果低于阀值,则通过ObjectAnimator在0.25s将mMoveView移动到初始位置,同时在ObjectAnimator的AnimatorUpdateListener的onAnimationUpdate方法中更新背景透明度;如果低于阀值,以同样的方式将mMoveView移出屏幕右边界,然后将Activity干掉,具体做法是为animator增加一个AnimatorListenerAdapter的监听器,在该监听器的onAnimationEnd方法中使用在Activity中定义的mHandler发送finish消息,完成解锁。

5、Event bus的使用

锁屏Activity中的Buttun,可以通过EventBus远程控制ReadBookActivity中的播放、暂停、下一首等操作。


二、出现的问题

1、小米和魅族等手机锁屏权限问题

例如小米手机(miui 6.8.18开始)有锁屏权限的问题,权限未开的情况下锁屏会在系统锁屏的下方。目前只能手动打开(个别应用在MIUI是默认打开)。

在设置中:


2、透明栏与沉浸模式

透明栏与沉浸模式总共用到了5个Flag,SYSTEM_UI_FLAG_LAYOUT_STABLE保持整个View稳定,使View不会因为SystemUI的变化而做layout。SYSTEM_UI_FLAG_IMMERSIVE_STIKY,能够在隐藏的bar被呼出时(比如从屏幕下边缘开始向上做滑动手势),使bar在无相关操作的情况下自动再次隐藏。对于SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,我们容易被其中的HIDE_NAVIGATION所迷惑,其实这个Flag没有隐藏导航栏的功能,只是控制导航栏浮在屏幕上层,不占据屏幕布局空间。SYSTEM_UI_FLAG_HIDE_NAVIGATION,才是能够隐藏导航栏的Flag。SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN也不能隐藏状态栏,只是使状态栏浮在屏幕上层。


需要注意的是,这段代码除了需要加在Activity的OnCreate()方法中,也要加在重写的onWindowFocusChanged()方法中,在窗口获取焦点时再将Flag设置一遍,否则可能导致无法达到预想的效果。

在Android 5.0之后状态栏和导航栏也有更多的特点。除了原有的“半透明”模式以外,还有“全透明”以及“变色”模式,一种会完全隐藏背景,另一种可以取色作为背景颜色等。对于Android 4.4以上5.0以下的版本,设置透明状态栏的方式如下:


对于Android 5.0及以上版本,设置透明状态栏的方法如下:


除了要清理掉4.4的FLAG_TRANSLUCENT_STATUS外,还要配合SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_STABLE,添加标志位FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,并调用setStatusBarColor设置状态栏的颜色为透明。

3、手机适配

由于Android手机屏幕高度差异比较大,所以有可能会存在要显示的控件高度比屏幕还高的问题。所以需要通过代码对布局中某些控件宽高进行等比例调整。


例如在本项目中通过固定音量键以上的高度和最下方滑动解锁的位置,来动态等比例动态调整中间的专辑封面图片。mMain.post(new Runnable()。

4、处理黑色闪屏

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


5、线控耳机

我们只要定义一个广播接收者来接收到这个广播。这个广播的意图是android.intent.action.MEDIA_BUTTON。注册普通的广播接收器有两个常见的办法,一种是在代码中动态注册,另一种是在项目Manifest里面注册。但是这个广播,要注册两遍、两遍、两遍,Manifest里一遍(常规办法),代码中一遍(借助多媒体服务注册),否则没有效果。


因为两种注册方式缺一不可,所以解除了一种,它的监听作用也就失效了。

6、Android上的「安全音量」

当Android设备插上耳机,为了避免音量过高伤害用户听力,会触发其“安全音量”(Safe Media Volume)机制,如果在未经用户确认允许使用大音量时,且这时设置音量newIndex超过其推荐阈值,则这段代码执行完你会发现毫无反应,播放的声音依然不会很大。

解决问题的关键在于被忽略的最后一个参数flags。只要在设置音量后,复查一次当前值是否相当,如果比较小,则交由系统来显示音量提示对话框。而此时因欲设定的值超过推荐值,一般会触发音量过高警告,提示用户用户确认后即可设置成功。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,568评论 25 707
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,201评论 0 17
  • Android Studio JNI流程首先在java代码声明本地方法 用到native关键字 本地方法不用去实现...
    MigrationUK阅读 11,765评论 7 123
  • 日月卧东方, 韬谋斩炽名。 仙幽实复幻, 俊逸雨修屏。 点黛楼轩改, 拨筝殿宇清。 剜心玉侣眷, 隐魄冻思凝。 声...
    云汐诗怡阅读 499评论 9 4
  • 培养情商的5个关键步骤 情商 情商,就是一种辨别、管理个人以及他人情绪的能力。很多学术研究都证实过,通过科学的情商...
    张耀磊阅读 227评论 0 0