Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5475906f authored by Jim Miller's avatar Jim Miller
Browse files

Fix 2428368: Fix most of the lockscreen orientation refresh bugs

This change removes the legacy notification of orientation and configuration changed events
from KeyguardUpdateMonitor and moves them into the individual activities.  This was necessary
to guarantee order of events.

In addition, to minimize discrepencies due to notification lag, Keyguard screens (LockScreen,
PatternUnlock, etc.) are now responsible for handling onConfigurationChanged() notification and
forwarding them to LockPatternKeyguardView by a call to recreateMe() with the new configuration.

This also removes the hack that used to prevent drawing while the configuration was in flux.

Change-Id: I6b72e8c06cebb2c5c83e2debeb478e89b6f6f386
parent 5f3063e3
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.accounts.AuthenticatorException;
import android.accounts.AccountManagerCallback;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.telephony.TelephonyManager;
import android.text.Editable;
@@ -79,10 +80,10 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree

    /**
     * AccountUnlockScreen constructor.
     * @param configuration
     */
    public AccountUnlockScreen(Context context,
                               KeyguardScreenCallback callback,
                               LockPatternUtils lockPatternUtils) {
    public AccountUnlockScreen(Context context,Configuration configuration,
            KeyguardScreenCallback callback, LockPatternUtils lockPatternUtils) {
        super(context);
        mCallback = callback;
        mLockPatternUtils = lockPatternUtils;
+3 −1
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.internal.policy.impl;

import android.content.res.Configuration;

/**
 * Within a keyguard, there may be several screens that need a callback
 * to the host keyguard view.
@@ -55,7 +57,7 @@ public interface KeyguardScreenCallback extends KeyguardViewCallback {
    /**
     * Stay on me, but recreate me (so I can use a different layout).
     */
    void recreateMe();
    void recreateMe(Configuration config);

    /**
     * Take action to send an emergency call.
+2 −86
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.provider.Settings;
import android.provider.Telephony;
import static android.provider.Telephony.Intents.EXTRA_PLMN;
@@ -66,8 +67,6 @@ public class KeyguardUpdateMonitor {
    private final Context mContext;

    private IccCard.State mSimState = IccCard.State.READY;
    private boolean mInPortrait;
    private boolean mKeyboardOpen;

    private boolean mKeyguardBypassEnabled;

@@ -84,15 +83,11 @@ public class KeyguardUpdateMonitor {

    private Handler mHandler;

    private ArrayList<ConfigurationChangeCallback> mConfigurationChangeCallbacks
            = Lists.newArrayList();
    private ArrayList<InfoCallback> mInfoCallbacks = Lists.newArrayList();
    private ArrayList<SimStateCallback> mSimStateCallbacks = Lists.newArrayList();
    private ContentObserver mContentObserver;


    // messages for the handler
    private static final int MSG_CONFIGURATION_CHANGED = 300;
    private static final int MSG_TIME_UPDATE = 301;
    private static final int MSG_BATTERY_UPDATE = 302;
    private static final int MSG_CARRIER_INFO_UPDATE = 303;
@@ -150,9 +145,6 @@ public class KeyguardUpdateMonitor {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MSG_CONFIGURATION_CHANGED:
                        handleConfigurationChange();
                        break;
                    case MSG_TIME_UPDATE:
                        handleTimeUpdate();
                        break;
@@ -209,9 +201,6 @@ public class KeyguardUpdateMonitor {
                Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
        }

        mInPortrait = queryInPortrait();
        mKeyboardOpen = queryKeyboardOpen();

        // take a guess to start
        mSimState = IccCard.State.READY;
        mDevicePluggedIn = true;
@@ -221,7 +210,6 @@ public class KeyguardUpdateMonitor {

        // setup receiver
        final IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
        filter.addAction(Intent.ACTION_TIME_TICK);
        filter.addAction(Intent.ACTION_TIME_CHANGED);
        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
@@ -236,9 +224,7 @@ public class KeyguardUpdateMonitor {
                final String action = intent.getAction();
                if (DEBUG) Log.d(TAG, "received broadcast " + action);

                if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
                    mHandler.sendMessage(mHandler.obtainMessage(MSG_CONFIGURATION_CHANGED));
                } else if (Intent.ACTION_TIME_TICK.equals(action)
                if (Intent.ACTION_TIME_TICK.equals(action)
                        || Intent.ACTION_TIME_CHANGED.equals(action)
                        || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
                    mHandler.sendMessage(mHandler.obtainMessage(MSG_TIME_UPDATE));
@@ -284,29 +270,6 @@ public class KeyguardUpdateMonitor {
        }
    }

    /**
     * Handle {@link #MSG_CONFIGURATION_CHANGED}
     */
    private void handleConfigurationChange() {
        if (DEBUG) Log.d(TAG, "handleConfigurationChange");

        final boolean inPortrait = queryInPortrait();
        if (mInPortrait != inPortrait) {
            mInPortrait = inPortrait;
            for (int i = 0; i < mConfigurationChangeCallbacks.size(); i++) {
                mConfigurationChangeCallbacks.get(i).onOrientationChange(inPortrait);
            }
        }

        final boolean keyboardOpen = queryKeyboardOpen();
        if (mKeyboardOpen != keyboardOpen) {
            mKeyboardOpen = keyboardOpen;
            for (int i = 0; i < mConfigurationChangeCallbacks.size(); i++) {
                mConfigurationChangeCallbacks.get(i).onKeyboardChange(keyboardOpen);
            }
        }
    }

    /**
     * Handle {@link #MSG_TIME_UPDATE}
     */
@@ -393,23 +356,6 @@ public class KeyguardUpdateMonitor {
        return false;
    }

    /**
     * What is the current orientation?
     */
    boolean queryInPortrait() {
        final Configuration configuration = mContext.getResources().getConfiguration();
        return configuration.orientation == Configuration.ORIENTATION_PORTRAIT;
    }

    /**
     * Is the (hard) keyboard currently open?
     */
    boolean queryKeyboardOpen() {
        final Configuration configuration = mContext.getResources().getConfiguration();

        return configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
    }

    /**
     * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION}
     * @return The string to use for the plmn, or null if it should not be shown.
@@ -455,20 +401,10 @@ public class KeyguardUpdateMonitor {
     *   {@link InfoCallback} or {@link SimStateCallback}
     */
    public void removeCallback(Object observer) {
        mConfigurationChangeCallbacks.remove(observer);
        mInfoCallbacks.remove(observer);
        mSimStateCallbacks.remove(observer);
    }

    /**
     * Callback for configuration changes.
     */
    interface ConfigurationChangeCallback {
        void onOrientationChange(boolean inPortrait);

        void onKeyboardChange(boolean isKeyboardOpen);
    }

    /**
     * Callback for general information relevant to lock screen.
     */
@@ -506,18 +442,6 @@ public class KeyguardUpdateMonitor {
        void onSimStateChanged(IccCard.State simState);
    }

    /**
     * Register to receive notifications about configuration changes.
     * @param callback The callback.
     */
    public void registerConfigurationChangeCallback(ConfigurationChangeCallback callback) {
        if (!mConfigurationChangeCallbacks.contains(callback)) {
            mConfigurationChangeCallbacks.add(callback);
        } else {
            Log.e(TAG, "Object tried to add another CONFIG callback", new Exception("Whoops"));
        }
    }

    /**
     * Register to receive notifications about general keyguard information
     * (see {@link InfoCallback}.
@@ -556,14 +480,6 @@ public class KeyguardUpdateMonitor {
        mSimState = IccCard.State.READY;
    }

    public boolean isInPortrait() {
        return mInPortrait;
    }

    public boolean isKeyboardOpen() {
        return mKeyboardOpen;
    }

    public boolean isKeyguardBypassEnabled() {
        return mKeyguardBypassEnabled;
    }
+15 −51
Original line number Diff line number Diff line
@@ -34,15 +34,14 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;

import java.io.IOException;
@@ -79,7 +78,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase
    private boolean mScreenOn = false;
    private boolean mEnableFallback = false; // assume no fallback UI until we know better


    /**
     * The current {@link KeyguardScreen} will use this to communicate back to us.
     */
@@ -156,10 +154,14 @@ public class LockPatternKeyguardView extends KeyguardViewBase
    private final LockPatternUtils mLockPatternUtils;

    private int mNumAccounts;
    private boolean mIsPortrait;

    private UnlockMode mCurrentUnlockMode = UnlockMode.Unknown;

    /**
     * The current configuration.
     */
    private Configuration mConfiguration;

    /**
     * @return Whether we are stuck on the lock screen because the sim is
     *   missing.
@@ -203,6 +205,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase
            KeyguardWindowController controller) {
        super(context);

        mConfiguration = context.getResources().getConfiguration();
        mEnableFallback = false;

        mRequiresSim =
@@ -257,7 +260,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase
                return mIsVerifyUnlockOnly;
            }

            public void recreateMe() {
            public void recreateMe(Configuration config) {
                mConfiguration = config;
                recreateScreens();
            }

@@ -370,23 +374,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase
    // be removed once the race condition is fixed. See bugs 2262578 and 2292713.
    @Override
    protected void dispatchDraw(Canvas canvas) {
        final int orientation = getResources().getConfiguration().orientation;
        if (mIsPortrait && Configuration.ORIENTATION_PORTRAIT != orientation
                || getResources().getBoolean(R.bool.lockscreen_isPortrait) != mIsPortrait) {
            // Make sure we redraw once things settle down.
            // Log.v(TAG, "dispatchDraw(): not drawing because state is inconsistent");
            postInvalidate();

            // In order to minimize flashing, draw the first child's background for now.
            ViewGroup view = (ViewGroup) (mMode == Mode.LockScreen ? mLockScreen : mUnlockScreen);
            if (view != null && view.getChildAt(0) != null) {
                Drawable background = view.getChildAt(0).getBackground();
                if (background != null) {
                    background.draw(canvas);
                }
            }
            return;
        }
        if (DEBUG) Log.v(TAG, "*** dispatchDraw() time: " + SystemClock.elapsedRealtime());
        super.dispatchDraw(canvas);
    }

@@ -550,19 +538,18 @@ public class LockPatternKeyguardView extends KeyguardViewBase
    View createLockScreen() {
        return new LockScreen(
                mContext,
                mConfiguration,
                mLockPatternUtils,
                mUpdateMonitor,
                mKeyguardScreenCallback);
    }

    View createUnlockScreenFor(UnlockMode unlockMode) {
        // Capture the orientation this layout was created in.
        mIsPortrait = getResources().getBoolean(R.bool.lockscreen_isPortrait);

        View unlockView = null;
        if (unlockMode == UnlockMode.Pattern) {
            PatternUnlockScreen view = new PatternUnlockScreen(
                    mContext,
                    mConfiguration,
                    mLockPatternUtils,
                    mUpdateMonitor,
                    mKeyguardScreenCallback,
@@ -574,6 +561,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase
        } else if (unlockMode == UnlockMode.SimPin) {
            unlockView = new SimUnlockScreen(
                    mContext,
                    mConfiguration,
                    mUpdateMonitor,
                    mKeyguardScreenCallback,
                    mLockPatternUtils);
@@ -581,6 +569,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase
            try {
                unlockView = new AccountUnlockScreen(
                        mContext,
                        mConfiguration,
                        mKeyguardScreenCallback,
                        mLockPatternUtils);
            } catch (IllegalStateException e) {
@@ -601,6 +590,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase
        } else if (unlockMode == UnlockMode.Password) {
            unlockView = new PasswordUnlockScreen(
                    mContext,
                    mConfiguration,
                    mLockPatternUtils,
                    mUpdateMonitor,
                    mKeyguardScreenCallback);
@@ -611,32 +601,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase
        return unlockView;
    }

    private View getUnlockScreenForCurrentUnlockMode() {
        final UnlockMode unlockMode = getUnlockMode();

        // if a screen exists for the correct mode, we're done
        if (unlockMode == mUnlockScreenMode) {
            return mUnlockScreen;
        }

        // remember the mode
        mUnlockScreenMode = unlockMode;

        // unlock mode has changed and we have an existing old unlock screen
        // to clean up
        if (mScreenOn && (mUnlockScreen.getVisibility() == View.VISIBLE)) {
            ((KeyguardScreen) mUnlockScreen).onPause();
        }
        ((KeyguardScreen) mUnlockScreen).cleanUp();
        removeViewInLayout(mUnlockScreen);

        // create the new one
        mUnlockScreen = createUnlockScreenFor(unlockMode);
        mUnlockScreen.setVisibility(View.INVISIBLE);
        addView(mUnlockScreen);
        return mUnlockScreen;
    }

    /**
     * Given the current state of things, what should be the initial mode of
     * the lock screen (lock or unlock).
+35 −32
Original line number Diff line number Diff line
@@ -18,15 +18,13 @@ package com.android.internal.policy.impl;

import com.android.internal.R;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.Phone.State;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.SlidingTab;

import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.ColorStateList;
import android.telephony.TelephonyManager;
import android.text.format.DateFormat;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -36,6 +34,7 @@ import android.widget.*;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.media.AudioManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;

@@ -48,8 +47,7 @@ import java.io.File;
 * past it, as applicable.
 */
class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateMonitor.InfoCallback,
        KeyguardUpdateMonitor.SimStateCallback, KeyguardUpdateMonitor.ConfigurationChangeCallback,
        SlidingTab.OnTriggerListener {
        KeyguardUpdateMonitor.SimStateCallback, SlidingTab.OnTriggerListener {

    private static final boolean DBG = false;
    private static final String TAG = "LockScreen";
@@ -70,6 +68,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM
    private TextView mScreenLocked;
    private Button mEmergencyCallButton;

    // current configuration state of keyboard and display
    private int mKeyboardHidden;
    private int mCreationOrientation;

    // are we showing battery information?
    private boolean mShowingBatteryInfo = false;

@@ -88,7 +90,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM
    private AudioManager mAudioManager;
    private String mDateFormatString;
    private java.text.DateFormat mTimeFormat;
    private boolean mCreatedInPortrait;
    private boolean mEnableMenuKeyInLockScreen;

    /**
@@ -159,12 +160,13 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM

    /**
     * @param context Used to setup the view.
     * @param configuration The current configuration. Used to use when selecting layout, etc.
     * @param lockPatternUtils Used to know the state of the lock pattern settings.
     * @param updateMonitor Used to register for updates on various keyguard related
     *    state, and query the initial state at setup.
     * @param callback Used to communicate back to the host keyguard view.
     */
    LockScreen(Context context, LockPatternUtils lockPatternUtils,
    LockScreen(Context context, Configuration configuration, LockPatternUtils lockPatternUtils,
            KeyguardUpdateMonitor updateMonitor,
            KeyguardScreenCallback callback) {
        super(context);
@@ -174,10 +176,13 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM

        mEnableMenuKeyInLockScreen = shouldEnableMenuKey();

        mCreatedInPortrait = updateMonitor.isInPortrait();
        mCreationOrientation = configuration.orientation;

        mKeyboardHidden = configuration.hardKeyboardHidden;

        final LayoutInflater inflater = LayoutInflater.from(context);
        if (mCreatedInPortrait) {
        if (DBG) Log.v(TAG, "Creation orientation = " + mCreationOrientation);
        if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) {
            inflater.inflate(R.layout.keyguard_screen_tab_unlock, this, true);
        } else {
            inflater.inflate(R.layout.keyguard_screen_tab_unlock_land, this, true);
@@ -211,7 +216,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM

        updateMonitor.registerInfoCallback(this);
        updateMonitor.registerSimStateCallback(this);
        updateMonitor.registerConfigurationChangeCallback(this);

        mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
        mSilentMode = isSilentMode();
@@ -368,7 +372,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM
    private Runnable mPendingR1;
    private Runnable mPendingR2;


    private void refreshAlarmDisplay() {
        mNextAlarm = mLockPatternUtils.getNextAlarm();
        if (mNextAlarm != null) {
@@ -457,13 +460,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM
        updateLayout(mStatus);
    }

    private void addRelativeLayoutRule(View view, int rule, int viewId) {
        final RelativeLayout.LayoutParams layoutParams =
                (RelativeLayout.LayoutParams) view.getLayoutParams();
        layoutParams.addRule(rule, viewId);
        view.setLayoutParams(layoutParams);
    }

    /**
     * Determine the current status of the lock screen given the sim state and other stuff.
     */
@@ -604,19 +600,26 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM
        updateStatusLines();
    }


    public void onOrientationChange(boolean inPortrait) {
        if (inPortrait != mCreatedInPortrait) {
            mCallback.recreateMe();
        }
    }

    public void onKeyboardChange(boolean isKeyboardOpen) {
    /** {@inheritDoc} */
    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (DBG) {
            Log.v(TAG, "onConfigurationChanged() time " + SystemClock.elapsedRealtime());
            if (getResources().getConfiguration().orientation != newConfig.orientation) {
                Log.e(TAG, "mismatchConfig: ", new Exception("stack trace:"));
            }
        }
        if (newConfig.orientation != mCreationOrientation) {
            mCallback.recreateMe(newConfig);
        } else if (newConfig.hardKeyboardHidden != mKeyboardHidden) {
            mKeyboardHidden = newConfig.hardKeyboardHidden;
            final boolean isKeyboardOpen = mKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
            if (mUpdateMonitor.isKeyguardBypassEnabled() && isKeyboardOpen) {
                mCallback.goToUnlockScreen();
            }
        }

    }

    /** {@inheritDoc} */
    public boolean needsInput() {
Loading