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:
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user