Partial Fix for 2416967: Fix potential memory leak in PasswordUnlockScreen.
PasswordUnlockScreen was previously registering for multiple callbacks which *sometimes*
caused a memory leak because a reference stuck around in the callback list. I wasn't able to
track down the cause, but it looks like an interaction between switching between various lockscreen
modes and ordering of CONFIGURATION_CHANGED events.
I found one instance where the callback was being registered twice (fixed). However, I'm
still able to reproduce the bug but far less frequently.
As a workaround, I've added code to prevent adding additional callbacks and added logging to
detect when a callback is already registered.
Also fixed an instance where we'd recreate the password unlock screen in LockPatternKeyguardView.updateScreen()
so it should be quite a bit faster switching orientations now.
Renamed UnlockScreen.java to PatternUnlockScreen.java for consistency.
diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
index 3483405..9729eda 100644
--- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
+++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
@@ -492,7 +492,11 @@
* @param callback The callback.
*/
public void registerConfigurationChangeCallback(ConfigurationChangeCallback callback) {
- mConfigurationChangeCallbacks.add(callback);
+ if (!mConfigurationChangeCallbacks.contains(callback)) {
+ mConfigurationChangeCallbacks.add(callback);
+ } else {
+ Log.e(TAG, "Object tried to add another CONFIG callback", new Exception("Whoops"));
+ }
}
/**
@@ -501,7 +505,11 @@
* @param callback The callback.
*/
public void registerInfoCallback(InfoCallback callback) {
- mInfoCallbacks.add(callback);
+ if (!mInfoCallbacks.contains(callback)) {
+ mInfoCallbacks.add(callback);
+ } else {
+ Log.e(TAG, "Object tried to add another INFO callback", new Exception("Whoops"));
+ }
}
/**
@@ -509,7 +517,11 @@
* @param callback The callback.
*/
public void registerSimStateCallback(SimStateCallback callback) {
- mSimStateCallbacks.add(callback);
+ if (!mSimStateCallbacks.contains(callback)) {
+ mSimStateCallbacks.add(callback);
+ } else {
+ Log.e(TAG, "Object tried to add another SIM callback", new Exception("Whoops"));
+ }
}
public IccCard.State getSimState() {
diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java
index a7fc6b6..cdac278 100644
--- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -173,8 +173,8 @@
if (mUnlockScreen == null) {
Log.w(TAG, "no unlock screen when receiving AccountManager information");
- } else if (mUnlockScreen instanceof UnlockScreen) {
- ((UnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback);
+ } else if (mUnlockScreen instanceof PatternUnlockScreen) {
+ ((PatternUnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback);
}
}
@@ -411,7 +411,6 @@
}
}
-
private void recreateScreens() {
if (mLockScreen.getVisibility() == View.VISIBLE) {
((KeyguardScreen) mLockScreen).onPause();
@@ -504,8 +503,7 @@
mMode = mode;
final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen;
- final View visibleScreen = (mode == Mode.LockScreen)
- ? mLockScreen : getUnlockScreenForCurrentUnlockMode();
+ final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen;
// do this before changing visibility so focus isn't requested before the input
// flag is set
@@ -544,7 +542,7 @@
mIsPortrait = getResources().getBoolean(R.bool.lockscreen_isPortrait);
if (unlockMode == UnlockMode.Pattern) {
- UnlockScreen view = new UnlockScreen(
+ PatternUnlockScreen view = new PatternUnlockScreen(
mContext,
mLockPatternUtils,
mUpdateMonitor,
diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java
index 560a000..9094ed6 100644
--- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java
+++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java
@@ -53,6 +53,7 @@
private LockPatternUtils mLockPatternUtils;
private PasswordEntryKeyboardView mKeyboardView;
private PasswordEntryKeyboardHelper mKeyboardHelper;
+ private boolean mIsInPortrait;
// To avoid accidental lockout due to events while the device in in the pocket, ignore
// any passwords with length less than or equal to this length.
@@ -66,10 +67,10 @@
mCreatedWithKeyboardOpen = mUpdateMonitor.isKeyboardOpen();
LayoutInflater layoutInflater = LayoutInflater.from(context);
- if (mCreatedWithKeyboardOpen) {
- layoutInflater.inflate(R.layout.keyguard_screen_password_landscape, this, true);
- } else {
+ if (mUpdateMonitor.isInPortrait()) {
layoutInflater.inflate(R.layout.keyguard_screen_password_portrait, this, true);
+ } else {
+ layoutInflater.inflate(R.layout.keyguard_screen_password_landscape, this, true);
}
boolean isAlpha = lockPatternUtils.getPasswordMode() == LockPatternUtils.MODE_PASSWORD;
@@ -85,7 +86,7 @@
mKeyboardHelper.setKeyboardMode(isAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
: PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
- updateMonitor.registerConfigurationChangeCallback(this);
+ mKeyboardView.setVisibility(mCreatedWithKeyboardOpen ? View.INVISIBLE : View.VISIBLE);
mPasswordEntry.requestFocus();
}
@@ -144,13 +145,12 @@
}
public void onOrientationChange(boolean inPortrait) {
-
+ mCallback.recreateMe();
}
public void onKeyboardChange(boolean isKeyboardOpen) {
- if (isKeyboardOpen != mCreatedWithKeyboardOpen) {
- mCallback.recreateMe();
- }
+ // Don't show the soft keyboard when the real keyboard is open
+ mKeyboardView.setVisibility(isKeyboardOpen ? View.INVISIBLE : View.VISIBLE);
}
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/PatternUnlockScreen.java
similarity index 99%
rename from policy/com/android/internal/policy/impl/UnlockScreen.java
rename to policy/com/android/internal/policy/impl/PatternUnlockScreen.java
index f2a2c95..2e3aa84 100644
--- a/policy/com/android/internal/policy/impl/UnlockScreen.java
+++ b/policy/com/android/internal/policy/impl/PatternUnlockScreen.java
@@ -42,7 +42,7 @@
* This is the screen that shows the 9 circle unlock widget and instructs
* the user how to unlock their device, or make an emergency call.
*/
-class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
+class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient
implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback,
KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback {
@@ -160,7 +160,7 @@
* their pattern (e.g they have a google account so we can show them the account based
* backup option).
*/
- UnlockScreen(Context context,
+ PatternUnlockScreen(Context context,
LockPatternUtils lockPatternUtils,
KeyguardUpdateMonitor updateMonitor,
KeyguardScreenCallback callback,