Android修改原始碼控制永不鎖屏
Android系統的鎖屏時間存放在Setting資料庫中,欄位為Settings.System.SCREEN_OFF_TIMEOUT。檢視SettingsProvider原始碼,檢視如下檔案的原始碼:
frameworks/base/packages/SettingsProvider/src/com/Android/providers/settings/DatabaseHelper.java
檢視loadSystemSettings()函式的程式碼如下:
private void loadSystemSettings(SQLiteDatabase db) {
SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
+ " VALUES(?,?);");
Resources r = mContext.getResources();
loadBooleanSetting(stmt, Settings.System.DIM_SCREEN,
R.bool.def_dim_screen);
loadSetting(stmt, Settings.System.STAY_ON_WHILE_PLUGGED_IN,
"1".equals(SystemProperties.get("ro.kernel.qemu")) ? 1 : 0);
loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
R.integer.def_screen_off_timeout);
// Set default cdma emergency tone
loadSetting(stmt, Settings.System.EMERGENCY_TONE, 0);
// Set default cdma call auto retry
loadSetting(stmt, Settings.System.CALL_AUTO_RETRY, 0);
// Set default cdma DTMF type
loadSetting(stmt, Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, 0);
// Set default hearing aid
loadSetting(stmt, Settings.System.HEARING_AID, 0);
// Set default tty mode
loadSetting(stmt, Settings.System.TTY_MODE, 0);
loadBooleanSetting(stmt, Settings.System.AIRPLANE_MODE_ON,
R.bool.def_airplane_mode_on);
loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_RADIOS,
R.string.def_airplane_mode_radios);
loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
R.string.airplane_mode_toggleable_radios);
loadBooleanSetting(stmt, Settings.System.AUTO_TIME,
R.bool.def_auto_time); // Sync time to NITZ
loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS,
R.integer.def_screen_brightness);
loadBooleanSetting(stmt, Settings.System.SCREEN_BRIGHTNESS_MODE,
R.bool.def_screen_brightness_automatic_mode);
loadDefaultAnimationSettings(stmt);
loadBooleanSetting(stmt, Settings.System.ACCELEROMETER_ROTATION,
R.bool.def_accelerometer_rotation);
loadDefaultHapticSettings(stmt);
stmt.close();
}
從 程式碼中我們可以看出,假如 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的定義。
<integer name="def_screen_off_timeout">60000</integer>
發現預設值為60000ms,也就是60s。我們只需要把這個引數改為-1。然後重新編譯SettingsProvider模組,就OK了。
另外為了防止使用者進入系統後,修改鎖屏時間,在Setting模組中刪除對鎖屏時間的設定。這樣Android裝置就永不鎖屏了。
後來發現我的Android裝置燒錄好之後第一次啟動永遠不會鎖屏,但是裝置重啟之後開機就進入鎖屏狀態,解鎖之後就再也不會鎖屏了(因為永遠不超時)。看來“革命尚未成功,同志仍需努力”啊。
那麼為什麼啟動之後沒有進入鎖屏狀態呢?是不會系統有把超時鎖屏的值給修改了呢?我通過sqlite3去檢視settings.db的內容,發現超時鎖屏的值仍然是-1。說明啟動之後,系統並沒有去資料庫中檢視螢幕超時鎖屏的值,就直接鎖屏了。
但是怎樣才能開機之後不進入鎖屏狀態呢?這個是個非常費思量的問題。經過go,我知道鎖屏的程式碼在LockScreen.java中,然後順藤摸瓜,終於找到了可以設定鎖屏功能開關的位置。程式碼位於:
frameworks/policies/base/phone/com/Android/internal/policy/impl/KeyguardViewMediator.java
該檔案中有一個變數定義如下:
/**
* External apps (like the phone app) can tell us to disable the keygaurd.
*/
private boolean mExternallyEnabled = true;
mExternallyEnabled是用來管理是否開啟螢幕鎖的關鍵。預設值是開啟屏鎖,根據註釋可以知道他是希望應用程式來修改這個值。但是經過加列印資訊發現開機的時候沒有任何應用程式會修改它。修改這個值呼叫如下函式:
/**
* 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) {
// reenabled after previously hidden, reshow
if (DEBUG) Log.d(TAG, "previously hidden, reshowing, reenabling "
+ "status bar expansion");
mNeedToReshowWhenReenabled = false;
if (mExitSecureCallback != null) {
if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting");
mExitSecureCallback.onKeyguardExitResult(false);
mExitSecureCallback = null;
resetStateLocked();
} else {
showLocked();
// block until we know the keygaurd is done drawing (and post a message
// to unblock us after a timeout so we don't risk blocking too long
// and causing an ANR).
mWaitingUntilKeyguardVisible = true;
mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_DRAWING, KEYGUARD_DONE_DRAWING_TIMEOUT_MS);
if (DEBUG) Log.d(TAG, "waiting until mWaitingUntilKeyguardVisible is false");
while (mWaitingUntilKeyguardVisible) {
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
if (DEBUG) Log.d(TAG, "done waiting for mWaitingUntilKeyguardVisible");
}
}
}
}
經過上面的討論我們可以發現我們有兩個解決方法:
1、定義變數的時候,給其初始化為false。
2、在launcher模組啟動的時候,呼叫setKeyguardEnabled方法,關閉鎖屏功能。
我懶得修改Laucher模組,我的解決方法就是在定義mExternallyEnabled時修改其初始值為false。各位朋友可以根據自己的實際情況選擇解決方案。我的程式碼如下:
/**
* External apps (like the phone app) can tell us to disable the keygaurd.
*/
private boolean mExternallyEnabled = false;
這樣修改之後,Android裝置開機之後,預設不會進入鎖屏狀態,除非你在應用程式中呼叫setKeyguardEnabled方法顯示開啟這個功能。因為設定的超時時間為-1,則永遠也不會進入鎖屏介面。完全滿足了我的需求,終於大功告成了。開心啊~!!