Android5.0之前来电默认是全屏的,例如我正在火热的玩游戏,紧要关头结果一个来电.....所以这样的方式太粗暴了。然后产品经理同学们就想到了小窗来电,来电的时候弹出一个悬浮窗,不打断当前的任务,也可以接听或者拒绝来电。
Android5.0之后
Android5.0之后这个任务很简单了,因为Heads-up样式的通知就是这个效果。InCalUI中默认的通知实现就是这样的,见
packages/apps/InCallUI/src/com/android/incallui/StatusBarNotifier.java
private void configureFullScreenIntent(Notification.Builder builder, PendingIntent intent,
Call call) {
...
builder.setFullScreenIntent(intent, true);
...
}
在通知中调用setFullScreenIntent设置intent就可以使用Heads-up样式。
Android5.0之前
Android4.3和Android4.4代码中其实已经加入了Heads-up样式的通知(4.3是听人说过,4.4我看过代码绝对是有的),不过是测试原因还是没有正式开放,代码中把开关打开就和5.0一样使用,小米rom就自带这个开关。不过比较坑的是手机厂商升Android版本基本是拿旧的代码能编译过就直接用,所谓升级只是底层代码的升级,app层就是手机的出场版本。悬浮通知的实现代码在systemUI,所以想通过打开开关这种方式不大行的通。三星的通话apk本人就反编译过,4.x的版本代码还是2.x时候的......
那么更暴力的解决方案就是直接使用WindowManager添加一个view。
当然要在AndroidManifest中加权限:
WindowManager windowManager= (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
WindowParams = new LayoutParams();
WindowParams.x = 0;
WindowParams.y = marginTop //距离顶部距离
WindowParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE //弹出时不会抢占焦点
|WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN //位置参数是从全屏考虑的,不会从状态栏下开始算
|WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR //不会被状态栏覆盖
|WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; //能亮屏
//WindowParams.type = LayoutParams.TYPE_TOP_MOST; //mtk代码中加入的类型,是所有类型中最大的
WindowParams.type = LayoutParams.TYPE_SYSTEM_ERROR; //高通机器还是用这个吧
WindowParams.format = PixelFormat.RGBA_8888;
WindowParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; //顶部水平居中
WindowParams.width = w
WindowParams.height = h;
windowManager.addView(view, WindowParams);
移除代码如下:
windowManager.removeView(view);
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
除了权限外还有签名问题,不过手机厂商自己的apk可以直接用platform签名,我到是没试验过普通签名可不可以这样实现。
其它
WindowManager的实现方式自主性更强一些,因为画图的同学一般会对UI有要求的,使用通知的话改UI好麻烦。使用该种方式也好现实类似iphone通话切换到后台后的顶部绿色条。
这种方式有个问题,就是通过设置View的方法setY或者setTranslationY是可以设置view位置的,但是控件实际点击位置并无改变。
这个就是不按sdk开发,使用系统比较底层类的副作用,整个framework 显示、输入输出的框架就没有考虑周全用户直接使用WindowManager添加View的情况。
最后使用设置margin代替setTranslationY规避了此问题。