Android 自己实现Keyguard的一些问题

1.原生Keyguard简单探究:

IKeyguardStateCallback.java文件是out底下生成的。因为在framework底下有IKeyguardStateCallback.aidl文件。所有编译之后就会由编译系统生成。
stub内部类有onTransact接口,底下还有个Proxy接口

public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub
即KeyguardStateMonitor这个类继承了系统生成的IKeyguardStateCallback类的子类Stub,获得了onTransact接口。KeyguardStateMonitor
是用来响应别人的transact的,是一个服务端。
比如onShowingStateChanged方法。客户端通过调用之后,Proxy会调用mRemote.transact(Stub.TRANSACTION_onShowingStateChanged).然后stub类呢就进行相应onTransact,调用this.onShowingStateChanged(_arg0)。而这个stub是个抽象类
要去寻找他的实现类,调用才能完成。

而前面我们已经找过了KeyguardStateMonitor就是子类。那很明显了
××××××××××××××××××××××××××××

那服务端找到了,我们要去找到客户端啊。肯定是在keyguard里啊,服务端在framework里,keyguard在SystemUI底下。
先说说KeyguarService吧,他是一个Service,后台不断运行的。
从Binder角度来说,他是一个服务端:

private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub()

private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
            //在这构造的
            mKeyguardService = new KeyguardServiceWrapper(mContext,
                    IKeyguardService.Stub.asInterface(service));
            if (mKeyguardState.systemIsReady) {
                // If the system is ready, it means keyguard crashed and restarted.
                mKeyguardService.onSystemReady();
                // This is used to hide the scrim once keyguard displays.
                mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(
                        mShowListenerWhenConnect));
                mShowListenerWhenConnect = null;
            }
            if (mKeyguardState.bootCompleted) {
                mKeyguardService.onBootCompleted();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
            mKeyguardService = null;
        }

    };

    public void bindService(Context context) {
        Intent intent = new Intent();
        intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
        //bindService的时候,传入的这个参数
        if (!context.bindServiceAsUser(intent, mKeyguardConnection,
                Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
            Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
            mKeyguardState.showing = false;
            mKeyguardState.showingAndNotOccluded = false;
            mKeyguardState.secure = false;
            mKeyguardState.deviceHasKeyguard = false;
            hideScrim();
        } else {
            if (DEBUG) Log.v(TAG, "*** Keyguard started");
        }
    }

public class KeyguardServiceWrapper implements IKeyguardService这又算个啥?
客户端的代理?包装?,总之,它和KeyguardService关联上了。要是没理解错的话,
KeyguardServiceWrapper.mService就是KeyguardService了

客户端(framwork这边)通过KeyguardServiceWrapper调用KeyguardService


PhoneWindowManager.java中

isKeyguardShowingAndNotOccluded()
mKeyguardDelegate.isShowing()
KeyguardServiceWrapper->isShowing()
mKeyguardStateMonitor.isShowing()

看实现

KeyguardStateMonitor
public boolean isShowing() {
        return mIsShowing;
    }

找赋值:

KeyguardStateMonitor: 
@Override // Binder interface
    public void onShowingStateChanged(boolean showing) {
        mIsShowing = showing;
    }

也就是说只有onShowingStateChanged被调用了,取isShowing的时候才能取到
那么谁会调用onShowingStateChanged呢?
这时候我们先回去说下KeyguardStateMonitor,还记得它是IKeyguardStateCallback服务端
看看他的构造函数:

public KeyguardStateMonitor(Context context, IKeyguardService service) {
        mLockPatternUtils = new LockPatternUtils(context);
        mLockPatternUtils.setCurrentUser(ActivityManager.getCurrentUser());
        try {
            service.addStateMonitorCallback(this);//注意这个函数
        } catch (RemoteException e) {
            Slog.w(TAG, "Remote Exception", e);
        }
    }
不用说,最终调用的就是keyguardService,参数callback就是KeyguardStateMonitor类
public void addStateMonitorCallback(IKeyguardStateCallback callback) {
        checkPermission();
        mKeyguardViewMediator.addStateMonitorCallback(callback);
    }
package com.android.systemui.keyguard;
KeyguardViewMediator类里:     
public void addStateMonitorCallback(IKeyguardStateCallback callback) {
        synchronized (this) {
            mKeyguardStateCallbacks.add(callback);//看看这个数组,有add,必有get
            try {
                callback.onSimSecureStateChanged(mUpdateMonitor.isSimPinSecure());
                callback.onShowingStateChanged(mShowing);
                ///M: added for ALPS01933830
                callback.onAntiTheftStateChanged(AntiTheftManager.isAntiTheftLocked()) ;
            } catch (RemoteException e) {
                Slog.w(TAG, "Failed to call onShowingStateChanged or onSimSecureStateChanged", e);
            }
        }
    }
KeyguardViewMediator.java:
    private void setShowingLocked(boolean showing) {
        Log.d(TAG, "setShowingLocked() - showing = " + showing + ", mShowing = " + mShowing) ;
        if (showing != mShowing) {            
            mShowing = showing;
            Log.d(TAG, "setShowingLocked() - set mShowing = " + mShowing) ;
            try {
                int size = mKeyguardStateCallbacks.size();
                for (int i = 0; i < size; i++) {
                    mKeyguardStateCallbacks.get(i).onShowingStateChanged(showing);//看着没?
                }
            } catch (RemoteException e) {
                Slog.w(TAG, "Failed to call onShowingStateChanged", e);
            }
            updateInputRestrictedLocked();
            mTrustManager.reportKeyguardShowingChanged();
        }
    }

我擦,终于明白了,也就是说KeyguardService调用setShowingLocked即可通知framework那边,我是isShowing否?

2.AIDL

自己实现的时候,aidl直接把SystemUI底下的aidl包括文件夹结构原封不动拷贝过来就行,因为最终的路径有区别,binder调用的时候根本找不到。binder调用的时候要求两端的类名包名完全一致,原因可以研究下out底下生成的对应java文件。
这边的aidl使用就是那种一个Service,客户端去binder…原生keyguard的研究,能学习到aidl,binder的使用。

3.如何屏蔽Home键的响应?

由于我们的硬件产品类似与小米那种,有实体按键,所以需要考虑这点。原生系统虚拟三键被keyguard完全遮盖了。

//frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
void launchHomeFromHotKey() {
        if (mKeyguardMediator != null && mKeyguardMediator.isShowingAndNotHidden()) {
            // don't launch home if keyguard showing
        } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) {
            // when in keyguard restricted mode, must first verify unlock
            // before launching home
            mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() {
                public void onKeyguardExitResult(boolean success) {
                    if (success) {
                        try {
                            ActivityManagerNative.getDefault().stopAppSwitches();
                        } catch (RemoteException e) {
                        }
                        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
                        startDockOrHome();
                    }
                }
            });
        } else {
            // no keyguard stuff to worry about, just launch home!
            try {
                ActivityManagerNative.getDefault().stopAppSwitches();
            } catch (RemoteException e) {
            }
            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
            startDockOrHome();
        }
    }

只要是第一个if条件那块满足,PhoneWindowsManager会做处理的。好吧。这可能不是大家想要的答案。因为很多人的需求是作为一个锁屏应用。而不是像这样有很高权限的系统应用,framework代码随便改的应用场景。

猜你喜欢

转载自blog.csdn.net/bberdong/article/details/69257758