常常我们开 发程序的时候我们不需要系统唤醒系统锁屏功能,比如我们在做xxxNowTV或XXX播放器这样的程序,用户有时候在看电视或视频的时候不希望系统的锁屏 功能启动,既不想锁频,然而系统却在我们看电视或者视频的时候出来个锁屏的界面进行锁频拉,我们还要想继续看的话还要去解锁,这样好麻烦,不是我们想要 的,那我们该怎么做呢,其实很简单,我这里只讲其中的两种
一 :我们只要在程序中用代码实现。代码如下:
二:禁用系统的锁屏功能,这方法不建议使用,只有在设当的环境下适当使用既可,我们只要知道这样我们也可以达到这样的功能实现就OK。
我们知道Android系统的锁屏时间存放在Setting数据库中,字段为Settings.System.SCREEN_OFF_TIMEOUT。我们可以查看SettingsProvider源码,查看如下文件的源码如下:
~/frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java 查看loadSystemSettings()函数的代码如下
我们通过查看源码便知道, Settings.System.SCREEN_OFF_TIMEOUT没有初始化的话(系统首次启动,这个字段肯定是没 有初始化的),系统将会利用资源中的R.integer.def_screen_off_timeout来初始化。我们为了让系统永不锁屏,只需要把资源 R.integer.def_screen_off_timeout设为-1即可。查看文件在这里:
frameworks/base/packages/SettingsProvider/res/values/defaults.xml
可以找到R.integer.def_screen_off_timeout的定义
发现默认值为60000ms,也就是60s。我们只需要把这个参数改为-1。然后重新编译SettingsProvider模块,就OK了。
但有时候也会有这样的情况发生,用户进入系统后,修改锁屏时间,为了这样的情况发生我们得在Setting模块中删除对锁屏时间的设置。这样Android设备就不锁屏了。
我们这里还要处理一种情况,就是让系统一启动我们就禁用锁屏的功能,很简单,我们只要把系统锁 屏 功能的的初始默认开关给改以下就可以了,如下找到这个类:
frameworks/policies/base/phone/com/android/internal/policy/impl/KeyguardViewMediator.java 4.4 的在frameworks/base/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java 该文件中有一个变量定义如下:mExternallyEnabled是用来管理是否开启屏幕锁的关键。默认值是打开屏锁,根据注释可以知道他是希望应用程序来修改这个 值,我们可以把这个值改成false就可以了。 有时候我们不想修改这个初始值,那我们看看这个类有没有提供相应的方法来供外部修改这个值的,不出我们所料,看下面这段代码就是的了:
- /**
- * External apps (like the phone app) can tell us to disable the keygaurd.
- */
- private boolean mExternallyEnabled = true
转自:http://blog.csdn.net/chenyafei617/article/details/6575621
- /**
- * Same semantics as {@link WindowManagerPolicy#enableKeyguard}; provide
- * a way for external stuff to override normal keyguard behavior. For instance
- * the phone app disables the keyguard when it receives incoming calls.
- */
- public void setKeyguardEnabled(boolean enabled) {
- synchronized (this) {
- if (DEBUG) Log.d(TAG, "setKeyguardEnabled(" + enabled + ")");
- mExternallyEnabled = enabled;
- if (!enabled && mShowing) {
- if (mExitSecureCallback != null) {
- if (DEBUG) Log.d(TAG, "in process of verifyUnlock request, ignoring");
- // we're in the process of handling a request to verify the user
- // can get past the keyguard. ignore extraneous requests to disable / reenable
- return;
- }
- // hiding keyguard that is showing, remember to reshow later
- if (DEBUG) Log.d(TAG, "remembering to reshow, hiding keyguard, "
- + "disabling status bar expansion");
- mNeedToReshowWhenReenabled = true;
- hideLocked();
- } else if (enabled && mNeedToReshowWhenReenabled) {
- ...
- ...
- }
- }
刚毕业不久由于项目需要就接触到锁屏,从2.2到4.1都解过bug,也定制过一些功能。4.1之前的锁屏工作不难,但很费时间,因为它的逻辑,视图,资源分别分布在不同的路径下,就像散落在海边沙滩上的珠子,想串起来还是蛮费劲的。最开始时锁屏就是改个字段也要全编译生成img。后来新技能get,会针对修改的地方进行单编译,但每次编译jar,导入手机,重启看效果也是不方便的。
一年前把锁屏交出去就没有再看过了,前些日子自己的谷歌四太子升到4.4,发现锁屏有很大变化,可以左右滑页,添加删除widget,添加删除分页。简直就是一个简化版的launcher。很好奇google是怎么改变的,于是费了很大的劲拉了google的最新源码。在android 4.4中这个模块的改动简直是巨大,这里略作整理。
1.文件目录:
a,锁屏代理是在Frameworks/base/policy/src/com/android/internal/policy/impl/keyguard下:
![]()
b,整个工程应用在framework/package下,结构和功能现在都和 systemUI类似:
![]()
c,keyguard的对外接口Frameworks/base/core/java/android/app/keyguardManager.java:
android4.2前做一些第三方锁屏软件都会用到该服务接口来控制系统锁屏(比如禁止系统锁屏),现在该接口已经不建议使用了,有更好的做法:
- /**
- * @deprecated使用{@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
- * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
- * 来代替; 利用该方式可以使应用达到禁用锁屏的效果而不需要额外的权限申请。this allows you to
- * Enables you to lock or unlock thekeyboard. Get an instance of this class by
- * calling {@link android.content.Context#getSystemService(java.lang.String)Context.getSystemService()}.
- * This class is wrapped by {@link android.app.KeyguardManagerKeyguardManager}.
- * @param tag A tag that informallyidentifies who you are (for debugging who
- * is disabling he keyguard).
- *
- * @return A {@link KeyguardLock} handle to use todisable and reenable the
- * keyguard.
- */
- @Deprecated
- public KeyguardLock newKeyguardLock(Stringtag) {
- return new KeyguardLock(tag);
- }
Keyguard锁屏流程图
![]()
Keyguard锁屏view层次图:
Keyguard锁屏重要类分析:
1.PhoneWindowManager.java
这个类很厉害也很重要,它由WindowManagerService派生,处理了phone的顶层逻辑,主要有以下几块:
a) 横竖屏处理(屏幕旋转等)
- publicvoidsetCurrentOrientationLw(intnewOrientation){
- synchronized (mLock){
- if (newOrientation != mCurrentAppOrientation) {
- mCurrentAppOrientation = newOrientation;
- updateOrientationListenerLp();
- }
- }
- }
b) 是否显示状态条或者navigation_bar。
- privateintupdateSystemUiVisibilityLw() {
- // If there is no window focused,there will be nobody to handle the events
- // anyway, so just hang on inwhatever state we're in until things settle down.
- WindowState win = mFocusedWindow != null ? mFocusedWindow :mTopFullscreenOpaqueWindowState;
- if (win == null){
- return 0;
- }
- if (win.getAttrs().type == TYPE_KEYGUARD&&mHideLockScreen == true) {
- // We are updating at a pointwhere the keyguard has gotten
- // focus, but we were last in astate where the top window is
- // hiding it. This is probably because the keyguardas been
- // shown while the top window wasdisplayed, so we want to ignore
- // it here because this is just avery transient change and it
- // will quickly lose focus once itcorrectly gets hidden.
- return 0;
- }
- inttmpVisibility = win.getSystemUiVisibility()
- & ~mResettingSystemUiFlags
- & ~mForceClearedSystemUiFlags;
- if (mForcingShowNavBar&&win.getSurfaceLayer()
- tmpVisibility&= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
- }
- finalint visibility = updateSystemBarsLw(win,mLastSystemUiFlags,tmpVisibility);
- finalint diff = visibility ^ mLastSystemUiFlags;
- finalbooleanneedsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
- if (diff == 0 &&mLastFocusNeedsMenu == needsMenu
- &&mFocusedApp ==win.getAppToken()) {
- return 0;
- }
- mLastSystemUiFlags = visibility;
- mLastFocusNeedsMenu = needsMenu;
- mFocusedApp = win.getAppToken();
- mHandler.post(new Runnable() {
- @Override
- publicvoid run() {
- try {
- IStatusBarServicestatusbar = getStatusBarService();
- if (statusbar != null) {
- statusbar.setSystemUiVisibility(visibility,0xffffffff);
- statusbar.topAppWindowChanged(needsMenu);
- }
- } catch (RemoteException e) {
- // re-acquire status bar servicenext time it is needed.
- mStatusBarService = null;
- }
- }
- });
- return diff;
- }
c) 各种按键事件的拦截和分发(比如长按home键)
Home键的事件是在phonewindow这一层就拦截的,所以一般情况应用本身无法正常拦截该事件。
- privatevoidhandleLongPressOnHome() {
- if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
- mHomeConsumed = true;
- performHapticFeedbackLw(null,HapticFeedbackConstants.LONG_PRESS, false);
- if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
- toggleRecentApps();
- } elseif (mLongPressOnHomeBehavior == LONG_PRESS_HOME_ASSIST){
- launchAssistAction();
- }
- }
- }
d) 锁屏事件处理和响应
- publicvoidsystemReady() {
- if (!mHeadless){
- mKeyguardDelegate = newKeyguardServiceDelegate(mContext, null);
- mKeyguardDelegate.onSystemReady();
- }
- synchronized (mLock){
- updateOrientationListenerLp();
- mSystemReady = true;
- mHandler.post(new Runnable() {
- @Override
- publicvoid run() {
- updateSettings();
- }
- });
- }
- }
2.KeyguardServiceDelegate.java和KeyguardServiceWrapper.java
这两个类是android 4.4新增加的,分别对KeyguardService进行了代理和包装,代理类里面有一个Scrim视图在keyguard崩溃时显示。包装类就是对keyguardService的简单包装,最终把调度都会传给keyguardService。
3.keyguardService.java
上面一再说到该类,那么它有啥出众的地方呢,其实它就是keyguard的入口,锁屏所有的往生都因它而起,这个类很简单,实例化了一个IKeyguardService.Stub供其他类bindservice时调用,需要特别注意的是整个keyguard的核心实力派KeyguardViewMediator在这里诞生了。
4.KeyguardViewMediator.java
字面上的意思是keyguard视图调度者,功能上是负责处理keyguard视图的事件,比如完成锁屏和解锁这些动作的视图响应,它作为一个位高权重的调度使当然不会亲手去做这些,它有个得力干将KeyguardviewManager,所有的大小任务都会放权给它。
- /**
- *有关锁屏请求的调度者。包括锁屏状态的查询,power management事件影响锁屏是否应该被显示或者重置,特定的回调函数来
- *通知windowmanager锁屏是什么时候显示,以及接受view视图传过来的消息表明已经成功完成解锁。
- *请注意锁屏是在灭屏后立即被调用显示的。这样当你点亮屏幕,锁屏才能第一时间显示出来。
- *例如外部事件调度锁屏视图流程:
- *
- *-灭屏动作-》重置锁屏并显示它为下次点亮屏幕做好准备。
- *-锁屏很自然流畅的打开了-》如果他不是安全的,隐藏之。
- *
- *来自于锁屏视图的事件:
- *-用户成功完成解锁条件-》隐藏锁屏视图,不再对输入事件进行拦截。
- *请再注意:第三方应用通过条用power managment实例可以屏蔽系统的锁屏。
- *
- *线程和同步:
- *该类是由WindowManagerPolicy创建并运行在它的线程里,锁屏UI也是这个类的构造函数里面产生。这个apis也可以被其他线程所调用。
- *然而,这个类的方法手势同步的,同时任何一个锁屏视图都会发消息到handle来保证它是在锁屏UI线程里面执行的。
- */
- public class KeyguardViewMediatorimplements KeyguardViewCallback,
- KeyguardUpdateMonitor.InfoCallback,KeyguardUpdateMonitor.SimStateCallback {
- private static final intKEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
- /**
- * This handler will be associated with the policy thread, which willalso
- * be the UI thread of the keyguard. Since the apis of the policy, and therefore
- * this class, can be called by other threads, any action that directly
- * interacts with the keyguard ui should be posted to this handler,rather
- * than called directly.
- */
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case TIMEOUT:
- handleTimeout(msg.arg1);
- return ;
- case SHOW:
- handleShow();
- return ;
- case HIDE:
- handleHide();
- return ;
- case RESET:
- handleReset();
- return ;
- case VERIFY_UNLOCK:
- handleVerifyUnlock();
- return;
- case NOTIFY_SCREEN_OFF:
- handleNotifyScreenOff();
- return;
- case NOTIFY_SCREEN_ON:
- handleNotifyScreenOn((KeyguardViewManager.ShowListener)msg.obj);
- return;
- case WAKE_WHEN_READY:
- handleWakeWhenReady(msg.arg1);
- return;
- case KEYGUARD_DONE:
- handleKeyguardDone(msg.arg1!= 0);
- return;
- case KEYGUARD_DONE_DRAWING:
- handleKeyguardDoneDrawing();
- return;
- caseKEYGUARD_DONE_AUTHENTICATING:
- keyguardDone(true);
- return;
- case SET_HIDDEN:
- handleSetHidden(msg.arg1 !=0);
- break;
- case KEYGUARD_TIMEOUT:
- synchronized(KeyguardViewMediator.this) {
- doKeyguardLocked();
- }
- break;
- }
- }
- };
- private void adjustStatusBarLocked() {
- ......//控制是否能在锁屏界面下拉状态栏。
- }
- }
5.KeyguardViewManager.java
如果说mediator相当于总裁,那这个就是经理,而且是视图部门老大,它有一个类型为FrameLayout名叫ViewManager的内部类,用来作为keyguard的viewroot。在viewroot里添加了KeyguardHostView,我们叫它mKeyguardView。Keyguard里任何的view细节和问题都能通过它找到蛛丝马迹。
- /**
- * Manages creating, showing, hiding andresetting the keyguard. Callsback
- * via {@link KeyguardViewMediator.ViewMediatorCallback} to poke
- * the wake lock and report that the keyguardis done, which is in turn,
- * reported to this class by the current {@link KeyguardViewBase}.
- */
- public class KeyguardViewManager {
- private final static boolean DEBUG = KeyguardViewMediator.DEBUG;
- private static String TAG = "KeyguardViewManager";
- public static boolean USE_UPPER_CASE = true;
- public final static String IS_SWITCHING_USER = "is_switching_user";
- // Timeoutused for keypresses
- static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
- private final Context mContext;
- private final ViewManager mViewManager;
- private final KeyguardViewMediator.ViewMediatorCallbackmViewMediatorCallback;
- private WindowManager.LayoutParams mWindowLayoutParams;
- private boolean mNeedsInput = false;
- private ViewManagerHost mKeyguardHost;
- private KeyguardHostView mKeyguardView;
6.KeyguardHostVIew.java
这里完成keyguardView布局,实例化。分析一个自定义的viewgroup,重点需要分析的是它的构造方法和onFinishInflate()方法:
- public KeyguardHostView(Context context, AttributeSet attrs) {
- super(context, attrs);
- if (DEBUG) Log.e(TAG, "KeyguardHostView()");
- mLockPatternUtils = newLockPatternUtils(context);
- // Note: This depends on KeyguardHostView getting reconstructed every timethe
- // user switches, since mUserId will be used for the entire session.
- // Once created, keyguard should *never* re-use this instance withanother user.
- // In other words, mUserId should never change - hence it's marked final.
- mUserId = mLockPatternUtils.getCurrentUser();
- DevicePolicyManager dpm =
- (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
- if (dpm != null) {
- mDisabledFeatures =getDisabledFeatures(dpm);
- mCameraDisabled =dpm.getCameraDisabled(null);
- }
- mSafeModeEnabled= LockPatternUtils.isSafeModeEnabled();
- // These need to be created with the user context...
- Context userContext = null;
- try {
- final String packageName = "system";
- userContext = mContext.createPackageContextAsUser(packageName,0,
- new UserHandle(mUserId));
- } catch (NameNotFoundException e) {
- e.printStackTrace();
- // This should never happen, but it's better to have no widgets than tocrash.
- userContext = context;
- }
- mAppWidgetHost = new AppWidgetHost(userContext, APPWIDGET_HOST_ID, mOnClickHandler,
- Looper.myLooper());
- mAppWidgetManager =AppWidgetManager.getInstance(userContext);
- mSecurityModel = new KeyguardSecurityModel(context);
- mViewStateManager = newKeyguardViewStateManager(this);
- }
- @Override
- protected void onFinishInflate() {
- // Grab instances of and make any necessary changes to the main layouts.Create
- // view state manager and wire up necessary listeners / callbacks.
- View deleteDropTarget = findViewById(R.id.keyguard_widget_pager_delete_target);
- mAppWidgetContainer =(KeyguardWidgetPager) findViewById(R.id.app_widget_container);
- mAppWidgetContainer.setVisibility(VISIBLE);
- mAppWidgetContainer.setCallbacks(mWidgetCallbacks);
- mAppWidgetContainer.setDeleteDropTarget(deleteDropTarget);
- mAppWidgetContainer.setMinScale(0.5f);
- mSlidingChallengeLayout =(SlidingChallengeLayout) findViewById(R.id.sliding_layout);
- if (mSlidingChallengeLayout != null) {
- mSlidingChallengeLayout.setOnChallengeScrolledListener(mViewStateManager);
- }
- mAppWidgetContainer.setViewStateManager(mViewStateManager);
- mAppWidgetContainer.setLockPatternUtils(mLockPatternUtils);
- mMultiPaneChallengeLayout =
- (MultiPaneChallengeLayout)findViewById(R.id.multi_pane_challenge);
- ChallengeLayout challenge =mSlidingChallengeLayout != null ? mSlidingChallengeLayout :
- mMultiPaneChallengeLayout;
- challenge.setOnBouncerStateChangedListener(mViewStateManager);
- mAppWidgetContainer.setBouncerAnimationDuration(challenge.getBouncerAnimationDuration());
- mViewStateManager.setPagedView(mAppWidgetContainer);
- mViewStateManager.setChallengeLayout(challenge);
- mSecurityViewContainer = (KeyguardSecurityViewFlipper)findViewById(R.id.view_flipper);
- mKeyguardSelectorView =(KeyguardSelectorView) findViewById(R.id.keyguard_selector_view);
- mViewStateManager.setSecurityViewContainer(mSecurityViewContainer);
- setBackButtonEnabled(false);
- if (KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()){
- updateAndAddWidgets();
- } else {
- // We can't add widgets until after boot completes because AppWidgetHostmay try
- // to contact the providers. Do itlater.
- mPostBootCompletedRunnable = new Runnable() {
- @Override
- public void run() {
- updateAndAddWidgets();
- }
- };
- }
- showPrimarySecurityScreen(false);
- updateSecurityViews();
- enableUserSelectorIfNecessary();
- }
7.KeyguardUpdateMonitor.java
说明:监听系统状态值的改变如时间、SIM卡状态、电池电量等,状态值的改变会回调监听了该状态信息的对象实例。如果只是关注功能的话只需要看hadle里面的每个消息调用的方法即可。
- /**
- *Watches for updates that may be interesting to the keyguard, and provides
- *the up to date information as well as a registration for callbacks that care
- * tobe updated.
- *
- *Note: under time crunch, this has been extended to include some stuff that
- *doesn't really belong here. see {@link#handleBatteryUpdate} where it shutdowns
- *the device, and {@link #getFailedAttempts()}, {@link #reportFailedAttempt()}
- *and {@link #clearFailedAttempts()}. Maybe we should rename this 'KeyguardContext'...
- */
- public class KeyguardUpdateMonitor {
- private Handler mHandler;
- private ContentObserver mContentObserver;
- private int mRingMode;
- private int mPhoneState;
- ......
- /**
- * SIM卡状态改变捕获赋值。
- * the intent and provide a {@link SimCard.State} result.
- */
- private static class SimArgs {
- public final IccCard.State simState;
- private SimArgs(Intent intent) {
- if(!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
- throw newIllegalArgumentException("only handles intentACTION_SIM_STATE_CHANGED");
- }
- String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
- if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
- final String absentReason =intent
- .getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
- if(IccCard.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals(
- absentReason)) {
- this.simState =IccCard.State.PERM_DISABLED;
- } else {
- this.simState =IccCard.State.ABSENT;
- }
- } else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
- this.simState =IccCard.State.READY;
- } else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
- final String lockedReason =intent
- .getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
- if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)){
- this.simState =IccCard.State.PIN_REQUIRED;
- } else if(IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
- this.simState = IccCard.State.PUK_REQUIRED;
- } else {
- this.simState =IccCard.State.UNKNOWN;
- }
- } else if (IccCard.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) {
- this.simState =IccCard.State.NETWORK_LOCKED;
- } else {
- this.simState =IccCard.State.UNKNOWN;
- }
- }
- public String toString() {
- return simState.toString();
- }
- }
- public KeyguardUpdateMonitor(Context context) {
- mContext = context;
- mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_TIME_UPDATE:
- handleTimeUpdate();
- break;
- case MSG_BATTERY_UPDATE:
- handleBatteryUpdate(msg.arg1, msg.arg2);
- break;
- caseMSG_CARRIER_INFO_UPDATE:
- handleCarrierInfoUpdate();
- break;
- case MSG_SIM_STATE_CHANGE:
- handleSimStateChange((SimArgs) msg.obj);
- break;
- caseMSG_RINGER_MODE_CHANGED:
- handleRingerModeChange(msg.arg1);
- break;
- caseMSG_PHONE_STATE_CHANGED:
- handlePhoneStateChanged((String)msg.obj);
- break;
- caseMSG_CLOCK_VISIBILITY_CHANGED:
- handleClockVisibilityChanged();
- break;
- caseMSG_DEVICE_PROVISIONED:
- handleDeviceProvisioned();
- break;
- }
- }
- };