FUL now restarts when flipping tablet 180 (bug 7484464)

When a tablet rotates, FUL must be stopped and restarted in a new
position.  90 degree rotations cause a configuration change, causing
FUL to be automatically reconstructed in the new location.  However,
a 180 degree rotation is not a configuration change, so FUL was not
restarting.  A 180 degree rotation happens more often than one might
think.  If you set the tablet down and later picked it up in the
opposite orientation, FUL would not work prior to this fix.

This change adds a rotation watcher to KeyguardFaceUnlockView.  It
watches for 180 degree rotations and stops and restarts FUL
accordingly.

The rotation watcher callback must be unregistered when
KeyguardFaceUnlockView is recreated (as during 90 degree rotation
changes), otherwise the number of rotation watcher callbacks will keep
growing and they will never go away.  This is a problem not just
because there are many callbacks hanging around, but also because the
old callbacks end up trying to access biometric unlock views that no
longer exist, resulting in crashes.  So, a simple function was added
to the window manager to unregister a rotation watcher.

Change-Id: Ie1ef20a9a22b8f4e39918987dff2b8ad444fcfd1
This commit is contained in:
Brian Colonna
2013-03-29 11:52:42 -04:00
parent da160ec313
commit b1b9a8ac07
4 changed files with 88 additions and 3 deletions

View File

@ -174,6 +174,12 @@ interface IWindowManager
*/
int watchRotation(IRotationWatcher watcher);
/**
* Remove a rotation watcher set using watchRotation.
* @hide
*/
void removeRotationWatcher(IRotationWatcher watcher);
/**
* Determine the preferred edge of the screen to pin the compact options menu against.
* @return a Gravity value for the options menu panel

View File

@ -18,17 +18,22 @@ package com.android.internal.policy.impl.keyguard;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.TelephonyManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.IRotationWatcher;
import android.view.IWindowManager;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import com.android.internal.R;
import com.android.internal.widget.LockPatternUtils;
import java.lang.Math;
public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecurityView {
private static final String TAG = "FULKeyguardFaceUnlockView";
@ -45,6 +50,30 @@ public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecu
private boolean mIsShowing = false;
private final Object mIsShowingLock = new Object();
private int mLastRotation;
private boolean mWatchingRotation;
private final IWindowManager mWindowManager =
IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
private final IRotationWatcher mRotationWatcher = new IRotationWatcher.Stub() {
public void onRotationChanged(int rotation) {
if (DEBUG) Log.d(TAG, "onRotationChanged(): " + mLastRotation + "->" + rotation);
// If the difference between the new rotation value and the previous rotation value is
// equal to 2, the rotation change was 180 degrees. This stops the biometric unlock
// and starts it in the new position. This is not performed for 90 degree rotations
// since a 90 degree rotation is a configuration change, which takes care of this for
// us.
if (Math.abs(rotation - mLastRotation) == 2) {
if (mBiometricUnlock != null) {
mBiometricUnlock.stop();
maybeStartBiometricUnlock();
}
}
mLastRotation = rotation;
}
};
public KeyguardFaceUnlockView(Context context) {
this(context, null);
}
@ -91,6 +120,14 @@ public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecu
mBiometricUnlock.stop();
}
KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback);
if (mWatchingRotation) {
try {
mWindowManager.removeRotationWatcher(mRotationWatcher);
mWatchingRotation = false;
} catch (RemoteException e) {
Log.e(TAG, "Remote exception when removing rotation watcher");
}
}
}
@Override
@ -100,6 +137,14 @@ public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecu
mBiometricUnlock.stop();
}
KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback);
if (mWatchingRotation) {
try {
mWindowManager.removeRotationWatcher(mRotationWatcher);
mWatchingRotation = false;
} catch (RemoteException e) {
Log.e(TAG, "Remote exception when removing rotation watcher");
}
}
}
@Override
@ -108,6 +153,17 @@ public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecu
mIsShowing = KeyguardUpdateMonitor.getInstance(mContext).isKeyguardVisible();
maybeStartBiometricUnlock();
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
// Registers a callback which handles stopping the biometric unlock and restarting it in
// the new position for a 180 degree rotation change.
if (!mWatchingRotation) {
try {
mLastRotation = mWindowManager.watchRotation(mRotationWatcher);
mWatchingRotation = true;
} catch (RemoteException e) {
Log.e(TAG, "Remote exception when adding rotation watcher");
}
}
}
@Override
@ -172,9 +228,15 @@ public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecu
return;
}
// TODO: Some of these conditions are handled in KeyguardSecurityModel and may not be
// necessary here.
// Although these same conditions are handled in KeyguardSecurityModel, they are still
// necessary here. When a tablet is rotated 90 degrees, a configuration change is
// triggered and everything is torn down and reconstructed. That means
// KeyguardSecurityModel gets a chance to take care of the logic and doesn't even
// reconstruct KeyguardFaceUnlockView if the biometric unlock should be suppressed.
// However, for a 180 degree rotation, no configuration change is triggered, so only
// the logic here is capable of suppressing Face Unlock.
if (monitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
&& monitor.isAlternateUnlockEnabled()
&& !monitor.getMaxBiometricUnlockAttemptsReached()
&& !backupIsTimedOut) {
mBiometricUnlock.start();

View File

@ -5803,6 +5803,19 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
@Override
public void removeRotationWatcher(IRotationWatcher watcher) {
final IBinder watcherBinder = watcher.asBinder();
synchronized (mWindowMap) {
for (int i=0; i<mRotationWatchers.size(); i++) {
if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
mRotationWatchers.remove(i);
i--;
}
}
}
}
/**
* Apps that use the compact menu panel (as controlled by the panelMenuIsCompact
* theme attribute) on devices that feature a physical options menu key attempt to position

View File

@ -448,6 +448,10 @@ public class IWindowManagerImpl implements IWindowManager {
return 0;
}
@Override
public void removeRotationWatcher(IRotationWatcher arg0) throws RemoteException {
}
@Override
public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
return false;