diff options
Diffstat (limited to 'policy')
10 files changed, 1043 insertions, 583 deletions
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java index ba1d7f5..70a4b20 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java @@ -113,7 +113,15 @@ public class KeyguardViewManager implements KeyguardWindowController { flags, PixelFormat.TRANSLUCENT); lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen; - lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; + + if (mContext.getResources().getBoolean(R.bool.config_enableLockScreenRotation)) { + Log.d(TAG, "Rotation sensor for lock screen On!"); + lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR; + } else { + Log.d(TAG, "Rotation sensor for lock screen Off!"); + lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; + } + lp.setTitle("Keyguard"); mWindowLayoutParams = lp; diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java index 88203c3..d19f318 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -16,6 +16,8 @@ package com.android.internal.policy.impl; +import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; + import com.android.internal.telephony.IccCard; import com.android.internal.widget.LockPatternUtils; @@ -41,6 +43,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; import android.telephony.TelephonyManager; import android.util.Config; import android.util.EventLog; @@ -93,6 +96,7 @@ import android.view.WindowManagerPolicy; */ public class KeyguardViewMediator implements KeyguardViewCallback, KeyguardUpdateMonitor.SimStateCallback { + private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000; private final static boolean DEBUG = false && Config.LOGD; private final static boolean DBG_WAKE = DEBUG || true; @@ -133,7 +137,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, * turning on the keyguard (i.e, the user has this much time to turn * the screen back on without having to face the keyguard). */ - private static final int KEYGUARD_DELAY_MS = 5000; + private static final int KEYGUARD_LOCK_AFTER_DELAY_DEFAULT = 5000; /** * How long we'll wait for the {@link KeyguardViewCallback#keyguardDoneDrawing()} @@ -244,6 +248,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, * the keyguard. */ private boolean mWaitingUntilKeyguardVisible = false; + private LockPatternUtils mLockPatternUtils; public KeyguardViewMediator(Context context, PhoneWindowManager callback, LocalPowerManager powerManager) { @@ -275,8 +280,9 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mUpdateMonitor.registerSimStateCallback(this); - mKeyguardViewProperties = new LockPatternKeyguardViewProperties( - new LockPatternUtils(mContext), mUpdateMonitor); + mLockPatternUtils = new LockPatternUtils(mContext); + mKeyguardViewProperties + = new LockPatternKeyguardViewProperties(mLockPatternUtils, mUpdateMonitor); mKeyguardViewManager = new KeyguardViewManager( context, WindowManagerImpl.getDefault(), this, @@ -326,15 +332,46 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // to enable it a little bit later (i.e, give the user a chance // to turn the screen back on within a certain window without // having to unlock the screen) - long when = SystemClock.elapsedRealtime() + KEYGUARD_DELAY_MS; - Intent intent = new Intent(DELAYED_KEYGUARD_ACTION); - intent.putExtra("seq", mDelayedShowingSequence); - PendingIntent sender = PendingIntent.getBroadcast(mContext, - 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, - sender); - if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = " - + mDelayedShowingSequence); + final ContentResolver cr = mContext.getContentResolver(); + + // From DisplaySettings + long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT, + KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT); + + // From SecuritySettings + final long lockAfterTimeout = Settings.Secure.getInt(cr, + Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, + KEYGUARD_LOCK_AFTER_DELAY_DEFAULT); + + // From DevicePolicyAdmin + final long policyTimeout = mLockPatternUtils.getDevicePolicyManager() + .getMaximumTimeToLock(null); + + long timeout; + if (policyTimeout > 0) { + // policy in effect. Make sure we don't go beyond policy limit. + displayTimeout = Math.max(displayTimeout, 0); // ignore negative values + timeout = Math.min(policyTimeout - displayTimeout, lockAfterTimeout); + } else { + timeout = lockAfterTimeout; + } + + if (timeout <= 0) { + // Lock now + mSuppressNextLockSound = true; + doKeyguard(); + } else { + // Lock in the future + long when = SystemClock.elapsedRealtime() + timeout; + Intent intent = new Intent(DELAYED_KEYGUARD_ACTION); + intent.putExtra("seq", mDelayedShowingSequence); + PendingIntent sender = PendingIntent.getBroadcast(mContext, + 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, + sender); + if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = " + + mDelayedShowingSequence); + } } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) { // Do not enable the keyguard if the prox sensor forced the screen off. } else { diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java index 27706ef..822be46 100644 --- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -645,7 +645,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase { // Show LockScreen first for any screen other than Pattern unlock. final boolean usingLockPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality() == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; - if (isSecure() && usingLockPattern) { + + boolean showSlidingTab = getResources().getBoolean(R.bool.config_enableSlidingTabFirst); + if (isSecure() && (usingLockPattern || !showSlidingTab)) { return Mode.UnlockScreen; } else { return Mode.LockScreen; @@ -667,6 +669,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: + case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: currentMode = UnlockMode.Password; break; case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: @@ -687,8 +690,17 @@ public class LockPatternKeyguardView extends KeyguardViewBase { private void showTimeoutDialog() { int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; + int messageId = R.string.lockscreen_too_many_failed_attempts_dialog_message; + if(getUnlockMode() == UnlockMode.Password) { + if(mLockPatternUtils.getKeyguardStoredPasswordQuality() == + DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) { + messageId = R.string.lockscreen_too_many_failed_pin_attempts_dialog_message; + } else { + messageId = R.string.lockscreen_too_many_failed_password_attempts_dialog_message; + } + } String message = mContext.getString( - R.string.lockscreen_too_many_failed_attempts_dialog_message, + messageId, mUpdateMonitor.getFailedAttempts(), timeoutInSeconds); final AlertDialog dialog = new AlertDialog.Builder(mContext) diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java index a5ef1fa..1383354 100644 --- a/policy/src/com/android/internal/policy/impl/LockScreen.java +++ b/policy/src/com/android/internal/policy/impl/LockScreen.java @@ -20,6 +20,8 @@ import com.android.internal.R; import com.android.internal.telephony.IccCard; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.SlidingTab; +import com.android.internal.widget.WaveView; +import com.android.internal.widget.WaveView.OnTriggerListener; import android.content.Context; import android.content.res.Configuration; @@ -46,8 +48,9 @@ import java.io.File; * information about the device depending on its state, and how to get * past it, as applicable. */ -class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateMonitor.InfoCallback, - KeyguardUpdateMonitor.SimStateCallback, SlidingTab.OnTriggerListener { +class LockScreen extends LinearLayout implements KeyguardScreen, + KeyguardUpdateMonitor.InfoCallback, + KeyguardUpdateMonitor.SimStateCallback { private static final boolean DBG = false; private static final String TAG = "LockScreen"; @@ -59,12 +62,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private final KeyguardUpdateMonitor mUpdateMonitor; private final KeyguardScreenCallback mCallback; - private TextView mCarrier; - private SlidingTab mSelector; - private TextView mTime; - private TextView mDate; - private TextView mStatus1; - private TextView mStatus2; + private SlidingTab mSlidingTab; private TextView mScreenLocked; private TextView mEmergencyCallText; private Button mEmergencyCallButton; @@ -93,6 +91,11 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private java.text.DateFormat mTimeFormat; private boolean mEnableMenuKeyInLockScreen; + private StatusView mStatusView; + private WaveView mEnergyWave; + private SlidingTabMethods mSlidingTabMethods; + private WaveViewMethods mWaveViewMethods; + /** * The status of this lock screen. */ @@ -144,6 +147,98 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } } + class SlidingTabMethods implements SlidingTab.OnTriggerListener { + + private void updateRightTabResources() { + boolean vibe = mSilentMode + && (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE); + + mSlidingTab.setRightTabResources( + mSilentMode ? ( vibe ? R.drawable.ic_jog_dial_vibrate_on + : R.drawable.ic_jog_dial_sound_off ) + : R.drawable.ic_jog_dial_sound_on, + mSilentMode ? R.drawable.jog_tab_target_yellow + : R.drawable.jog_tab_target_gray, + mSilentMode ? R.drawable.jog_tab_bar_right_sound_on + : R.drawable.jog_tab_bar_right_sound_off, + mSilentMode ? R.drawable.jog_tab_right_sound_on + : R.drawable.jog_tab_right_sound_off); + } + + /** {@inheritDoc} */ + public void onTrigger(View v, int whichHandle) { + if (whichHandle == SlidingTab.OnTriggerListener.LEFT_HANDLE) { + mCallback.goToUnlockScreen(); + } else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { + // toggle silent mode + mSilentMode = !mSilentMode; + if (mSilentMode) { + final boolean vibe = (Settings.System.getInt( + getContext().getContentResolver(), + Settings.System.VIBRATE_IN_SILENT, 1) == 1); + + mAudioManager.setRingerMode(vibe + ? AudioManager.RINGER_MODE_VIBRATE + : AudioManager.RINGER_MODE_SILENT); + } else { + mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); + } + + updateRightTabResources(); + + String message = mSilentMode ? + getContext().getString(R.string.global_action_silent_mode_on_status) : + getContext().getString(R.string.global_action_silent_mode_off_status); + + final int toastIcon = mSilentMode + ? R.drawable.ic_lock_ringer_off + : R.drawable.ic_lock_ringer_on; + + final int toastColor = mSilentMode + ? getContext().getResources().getColor(R.color.keyguard_text_color_soundoff) + : getContext().getResources().getColor(R.color.keyguard_text_color_soundon); + toastMessage(mScreenLocked, message, toastColor, toastIcon); + mCallback.pokeWakelock(); + } + } + + /** {@inheritDoc} */ + public void onGrabbedStateChange(View v, int grabbedState) { + if (grabbedState == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { + mSilentMode = isSilentMode(); + mSlidingTab.setRightHintText(mSilentMode ? R.string.lockscreen_sound_on_label + : R.string.lockscreen_sound_off_label); + } + mCallback.pokeWakelock(); + } + } + + class WaveViewMethods implements WaveView.OnTriggerListener { + private static final int WAIT_FOR_ANIMATION_TIMEOUT = 500; + private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000; + + /** {@inheritDoc} */ + public void onTrigger(View v, int whichHandle) { + if (whichHandle == WaveView.OnTriggerListener.CENTER_HANDLE) { + // Delay hiding lock screen long enough for animation to finish + postDelayed(new Runnable() { + public void run() { + mCallback.goToUnlockScreen(); + } + }, WAIT_FOR_ANIMATION_TIMEOUT); + } + } + + /** {@inheritDoc} */ + public void onGrabbedStateChange(View v, int grabbedState) { + if (grabbedState == WaveView.OnTriggerListener.CENTER_HANDLE) { + mCallback.pokeWakelock(STAY_ON_WHILE_GRABBED_TIMEOUT); + } else { + mCallback.pokeWakelock(); + } + } + } + /** * In general, we enable unlocking the insecure key guard with the menu key. However, there are * some cases where we wish to disable it, notably when the menu button placement or technology @@ -195,19 +290,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM inflater.inflate(R.layout.keyguard_screen_tab_unlock_land, this, true); } - mCarrier = (TextView) findViewById(R.id.carrier); - // Required for Marquee to work - mCarrier.setSelected(true); - mCarrier.setTextColor(0xffffffff); - - mDate = (TextView) findViewById(R.id.date); - mStatus1 = (TextView) findViewById(R.id.status1); - mStatus2 = (TextView) findViewById(R.id.status2); + mStatusView = new StatusView(this, mUpdateMonitor, mLockPatternUtils); mScreenLocked = (TextView) findViewById(R.id.screenLocked); - mSelector = (SlidingTab) findViewById(R.id.tab_selector); - mSelector.setHoldAfterTrigger(true, false); - mSelector.setLeftHintText(R.string.lockscreen_unlock_label); mEmergencyCallText = (TextView) findViewById(R.id.emergencyCallText); mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); @@ -220,7 +305,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } }); - setFocusable(true); setFocusableInTouchMode(true); setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); @@ -231,15 +315,25 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mSilentMode = isSilentMode(); - mSelector.setLeftTabResources( - R.drawable.ic_jog_dial_unlock, - R.drawable.jog_tab_target_green, - R.drawable.jog_tab_bar_left_unlock, - R.drawable.jog_tab_left_unlock); - - updateRightTabResources(); - - mSelector.setOnTriggerListener(this); + mSlidingTab = (SlidingTab) findViewById(R.id.tab_selector); + mEnergyWave = (WaveView) findViewById(R.id.wave_view); + if (mSlidingTab != null) { + mSlidingTab.setHoldAfterTrigger(true, false); + mSlidingTab.setLeftHintText(R.string.lockscreen_unlock_label); + mSlidingTab.setLeftTabResources( + R.drawable.ic_jog_dial_unlock, + R.drawable.jog_tab_target_green, + R.drawable.jog_tab_bar_left_unlock, + R.drawable.jog_tab_left_unlock); + mSlidingTabMethods = new SlidingTabMethods(); + mSlidingTab.setOnTriggerListener(mSlidingTabMethods); + mSlidingTabMethods.updateRightTabResources(); + } else if (mEnergyWave != null) { + mWaveViewMethods = new WaveViewMethods(); + mEnergyWave.setOnTriggerListener(mWaveViewMethods); + } else { + throw new IllegalStateException("Must have either SlidingTab or WaveView defined"); + } resetStatusInfo(updateMonitor); } @@ -248,22 +342,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM return mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; } - private void updateRightTabResources() { - boolean vibe = mSilentMode - && (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE); - - mSelector.setRightTabResources( - mSilentMode ? ( vibe ? R.drawable.ic_jog_dial_vibrate_on - : R.drawable.ic_jog_dial_sound_off ) - : R.drawable.ic_jog_dial_sound_on, - mSilentMode ? R.drawable.jog_tab_target_yellow - : R.drawable.jog_tab_target_gray, - mSilentMode ? R.drawable.jog_tab_bar_right_sound_on - : R.drawable.jog_tab_bar_right_sound_off, - mSilentMode ? R.drawable.jog_tab_right_sound_on - : R.drawable.jog_tab_right_sound_off); - } - private void resetStatusInfo(KeyguardUpdateMonitor updateMonitor) { mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo(); mPluggedIn = updateMonitor.isDevicePluggedIn(); @@ -289,53 +367,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM return false; } - /** {@inheritDoc} */ - public void onTrigger(View v, int whichHandle) { - if (whichHandle == SlidingTab.OnTriggerListener.LEFT_HANDLE) { - mCallback.goToUnlockScreen(); - } else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { - // toggle silent mode - mSilentMode = !mSilentMode; - if (mSilentMode) { - final boolean vibe = (Settings.System.getInt( - getContext().getContentResolver(), - Settings.System.VIBRATE_IN_SILENT, 1) == 1); - - mAudioManager.setRingerMode(vibe - ? AudioManager.RINGER_MODE_VIBRATE - : AudioManager.RINGER_MODE_SILENT); - } else { - mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); - } - - updateRightTabResources(); - - String message = mSilentMode ? - getContext().getString(R.string.global_action_silent_mode_on_status) : - getContext().getString(R.string.global_action_silent_mode_off_status); - - final int toastIcon = mSilentMode - ? R.drawable.ic_lock_ringer_off - : R.drawable.ic_lock_ringer_on; - - final int toastColor = mSilentMode - ? getContext().getResources().getColor(R.color.keyguard_text_color_soundoff) - : getContext().getResources().getColor(R.color.keyguard_text_color_soundon); - toastMessage(mScreenLocked, message, toastColor, toastIcon); - mCallback.pokeWakelock(); - } - } - - /** {@inheritDoc} */ - public void onGrabbedStateChange(View v, int grabbedState) { - if (grabbedState == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { - mSilentMode = isSilentMode(); - mSelector.setRightHintText(mSilentMode ? R.string.lockscreen_sound_on_label - : R.string.lockscreen_sound_off_label); - } - mCallback.pokeWakelock(); - } - /** * Displays a message in a text view and then restores the previous text. * @param textView The text view. @@ -428,38 +459,11 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } private void refreshTimeAndDateDisplay() { - mDate.setText(DateFormat.format(mDateFormatString, new Date())); + mStatusView.refreshTimeAndDateDisplay(); } private void updateStatusLines() { - if (!mStatus.showStatusLines() - || (mCharging == null && mNextAlarm == null)) { - mStatus1.setVisibility(View.INVISIBLE); - mStatus2.setVisibility(View.INVISIBLE); - } else if (mCharging != null && mNextAlarm == null) { - // charging only - mStatus1.setVisibility(View.VISIBLE); - mStatus2.setVisibility(View.INVISIBLE); - - mStatus1.setText(mCharging); - mStatus1.setCompoundDrawablesWithIntrinsicBounds(mChargingIcon, null, null, null); - } else if (mNextAlarm != null && mCharging == null) { - // next alarm only - mStatus1.setVisibility(View.VISIBLE); - mStatus2.setVisibility(View.INVISIBLE); - - mStatus1.setText(mNextAlarm); - mStatus1.setCompoundDrawablesWithIntrinsicBounds(mAlarmIcon, null, null, null); - } else if (mCharging != null && mNextAlarm != null) { - // both charging and next alarm - mStatus1.setVisibility(View.VISIBLE); - mStatus2.setVisibility(View.VISIBLE); - - mStatus1.setText(mCharging); - mStatus1.setCompoundDrawablesWithIntrinsicBounds(mChargingIcon, null, null, null); - mStatus2.setText(mNextAlarm); - mStatus2.setCompoundDrawablesWithIntrinsicBounds(mAlarmIcon, null, null, null); - } + mStatusView.updateStatusLines(mStatus.showStatusLines(), mCharging, mChargingIcon, mAlarmIcon); } /** {@inheritDoc} */ @@ -498,6 +502,22 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } /** + * Enables unlocking of this screen. Typically just shows the unlock widget. + */ + private void enableUnlock() { + if (mEnergyWave != null) mEnergyWave.setVisibility(View.VISIBLE); + if (mSlidingTab != null) mSlidingTab.setVisibility(View.VISIBLE); + } + + /** + * Disable unlocking of this screen. Typically just hides the unlock widget. + */ + private void disableUnlock() { + if (mEnergyWave != null) mEnergyWave.setVisibility(View.GONE); + if (mSlidingTab != null) mSlidingTab.setVisibility(View.GONE); + } + + /** * Update the layout to match the current status. */ private void updateLayout(Status status) { @@ -509,7 +529,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM switch (status) { case Normal: // text - mCarrier.setText( + mStatusView.setCarrierText( getCarrierString( mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn())); @@ -518,14 +538,15 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mScreenLocked.setText(""); // layout - mScreenLocked.setVisibility(View.VISIBLE); - mSelector.setVisibility(View.VISIBLE); + mScreenLocked.setVisibility(View.INVISIBLE); mEmergencyCallText.setVisibility(View.GONE); + enableUnlock(); break; + case NetworkLocked: // The carrier string shows both sim card status (i.e. No Sim Card) and // carrier's name and/or "Emergency Calls Only" status - mCarrier.setText( + mStatusView.setCarrierText( getCarrierString( mUpdateMonitor.getTelephonyPlmn(), getContext().getText(R.string.lockscreen_network_locked_message))); @@ -533,23 +554,24 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mSelector.setVisibility(View.VISIBLE); mEmergencyCallText.setVisibility(View.GONE); + enableUnlock(); break; + case SimMissing: // text - mCarrier.setText(R.string.lockscreen_missing_sim_message_short); + mStatusView.setCarrierText(R.string.lockscreen_missing_sim_message_short); mScreenLocked.setText(R.string.lockscreen_missing_sim_instructions); // layout mScreenLocked.setVisibility(View.VISIBLE); - mSelector.setVisibility(View.VISIBLE); mEmergencyCallText.setVisibility(View.VISIBLE); - // do not need to show the e-call button; user may unlock + enableUnlock(); // do not need to show the e-call button; user may unlock break; + case SimMissingLocked: // text - mCarrier.setText( + mStatusView.setCarrierText( getCarrierString( mUpdateMonitor.getTelephonyPlmn(), getContext().getText(R.string.lockscreen_missing_sim_message_short))); @@ -557,25 +579,27 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mSelector.setVisibility(View.GONE); // cannot unlock mEmergencyCallText.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.VISIBLE); + disableUnlock(); break; + case SimLocked: // text - mCarrier.setText( + mStatusView.setCarrierText( getCarrierString( mUpdateMonitor.getTelephonyPlmn(), getContext().getText(R.string.lockscreen_sim_locked_message))); // layout mScreenLocked.setVisibility(View.INVISIBLE); - mSelector.setVisibility(View.VISIBLE); mEmergencyCallText.setVisibility(View.GONE); + enableUnlock(); break; + case SimPukLocked: // text - mCarrier.setText( + mStatusView.setCarrierText( getCarrierString( mUpdateMonitor.getTelephonyPlmn(), getContext().getText(R.string.lockscreen_sim_puk_locked_message))); @@ -583,9 +607,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mSelector.setVisibility(View.GONE); // cannot unlock mEmergencyCallText.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.VISIBLE); + disableUnlock(); break; } } @@ -652,13 +676,14 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM /** {@inheritDoc} */ public void onPause() { - + if (mEnergyWave != null) { + mEnergyWave.reset(); + } } /** {@inheritDoc} */ public void onResume() { resetStatusInfo(mUpdateMonitor); - mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); } /** {@inheritDoc} */ @@ -671,11 +696,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM boolean silent = AudioManager.RINGER_MODE_NORMAL != state; if (silent != mSilentMode) { mSilentMode = silent; - updateRightTabResources(); + if (mSlidingTabMethods != null) mSlidingTabMethods.updateRightTabResources(); } } public void onPhoneStateChanged(String newState) { - mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); } } diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java index 39f2917..9db86aa 100644 --- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -30,6 +30,7 @@ import android.os.SystemClock; import android.telephony.TelephonyManager; import android.text.method.DigitsKeyListener; import android.text.method.TextKeyListener; +import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -50,19 +51,25 @@ import com.android.internal.widget.PasswordEntryKeyboardHelper; public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener, KeyguardUpdateMonitor.InfoCallback, OnEditorActionListener { + private static final String TAG = "PasswordUnlockScreen"; private final KeyguardUpdateMonitor mUpdateMonitor; private final KeyguardScreenCallback mCallback; + private boolean mIsAlpha; + private EditText mPasswordEntry; private Button mEmergencyCallButton; private LockPatternUtils mLockPatternUtils; private PasswordEntryKeyboardView mKeyboardView; + private PasswordEntryKeyboardView mKeyboardViewAlpha; private PasswordEntryKeyboardHelper mKeyboardHelper; + private PasswordEntryKeyboardHelper mKeyboardHelperAlpha; private int mCreationOrientation; private int mCreationHardKeyboardHidden; private CountDownTimer mCountdownTimer; - private TextView mTitle; + + private StatusView mStatusView; // 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. @@ -86,36 +93,65 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen layoutInflater.inflate(R.layout.keyguard_screen_password_landscape, this, true); } + mStatusView = new StatusView(this, mUpdateMonitor, mLockPatternUtils); + final int quality = lockPatternUtils.getKeyguardStoredPasswordQuality(); - final boolean isAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == quality - || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == quality; + mIsAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == quality + || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == quality + || DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == quality; mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard); + mKeyboardViewAlpha = (PasswordEntryKeyboardView) findViewById(R.id.keyboardAlpha); mPasswordEntry = (EditText) findViewById(R.id.passwordEntry); mPasswordEntry.setOnEditorActionListener(this); mEmergencyCallButton = (Button) findViewById(R.id.emergencyCall); mEmergencyCallButton.setOnClickListener(this); mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); - mTitle = (TextView) findViewById(R.id.enter_password_label); - mKeyboardHelper = new PasswordEntryKeyboardHelper(context, mKeyboardView, this); - mKeyboardHelper.setKeyboardMode(isAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA - : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC); + mKeyboardHelper = new PasswordEntryKeyboardHelper(context, mKeyboardView, this, false); + if (mKeyboardViewAlpha == null || !mIsAlpha) { + mKeyboardHelper.setKeyboardMode(mIsAlpha ? + PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA + : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC); + mKeyboardView.setVisibility( + mCreationHardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO + ? View.INVISIBLE : View.VISIBLE); + } else { + mKeyboardHelperAlpha = new PasswordEntryKeyboardHelper(context, mKeyboardViewAlpha, + this, false); + mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC); + mKeyboardHelperAlpha.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA); + mKeyboardView.setVisibility(View.GONE); + mKeyboardViewAlpha.setVisibility( + mCreationHardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO + ? View.INVISIBLE : View.VISIBLE); + mPasswordEntry.setWidth(mKeyboardViewAlpha.getLayoutParams().width); + } - mKeyboardView.setVisibility(mCreationHardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO - ? View.INVISIBLE : View.VISIBLE); + mPasswordEntry.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_lock, 0, + 0, 0); mPasswordEntry.requestFocus(); // This allows keyboards with overlapping qwerty/numeric keys to choose just the // numeric keys. - if (isAlpha) { + if (mIsAlpha) { mPasswordEntry.setKeyListener(TextKeyListener.getInstance()); } else { mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance()); + mStatusView.setInstructionText(R.string.keyguard_password_enter_pin_password_code); } mKeyboardHelper.setVibratePattern(mLockPatternUtils.isTactileFeedbackEnabled() ? com.android.internal.R.array.config_virtualKeyVibePattern : 0); + if (mKeyboardHelperAlpha != null) { + mKeyboardHelperAlpha.setVibratePattern(mLockPatternUtils.isTactileFeedbackEnabled() ? + com.android.internal.R.array.config_virtualKeyVibePattern : 0); + } + + // until we get an update... + mStatusView.setCarrierText(LockScreen.getCarrierString( + mUpdateMonitor.getTelephonyPlmn(), + mUpdateMonitor.getTelephonySpn())); } @Override @@ -136,8 +172,12 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen /** {@inheritDoc} */ public void onResume() { + // reset status + mStatusView.resetStatusInfo(mUpdateMonitor, mLockPatternUtils); + // start fresh mPasswordEntry.setText(""); + resetStatusInfo(); mPasswordEntry.requestFocus(); mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); @@ -174,6 +214,9 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); handleAttemptLockout(deadline); } + mStatusView.setInstructionText(R.string.lockscreen_password_wrong); + } else if (entry.length() > 0) { + mStatusView.setInstructionText(R.string.lockscreen_password_wrong); } mPasswordEntry.setText(""); } @@ -191,14 +234,14 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen String instructions = getContext().getString( R.string.lockscreen_too_many_failed_attempts_countdown, secondsRemaining); - mTitle.setText(instructions); + mStatusView.setInstructionText(instructions); } @Override public void onFinish() { mPasswordEntry.setEnabled(true); - mTitle.setText(R.string.keyguard_password_enter_password_code); mKeyboardView.setEnabled(true); + resetStatusInfo(); } }.start(); } @@ -244,24 +287,41 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen return false; } - public void onPhoneStateChanged(String newState) { - mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); - } + // ---------- InfoCallback + /** {@inheritDoc} */ public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + mStatusView.onRefreshBatteryInfo(showBatteryInfo, pluggedIn, batteryLevel); + } + /** {@inheritDoc} */ + public void onTimeChanged() { + mStatusView.onTimeChanged(); } + /** {@inheritDoc} */ public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { - + mStatusView.onRefreshCarrierInfo(plmn, spn); } + /** {@inheritDoc} */ public void onRingerModeChanged(int state) { - + // not currently used } - public void onTimeChanged() { + // ---------- SimStateCallback + /** {@inheritDoc} */ + public void onPhoneStateChanged(String newState) { + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); + } + + private void resetStatusInfo() { + if(mIsAlpha) { + mStatusView.setInstructionText(R.string.keyguard_password_enter_password_code); + } else { + mStatusView.setInstructionText(R.string.keyguard_password_enter_pin_password_code); + } } } diff --git a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java index 418e243..35fa3e5 100644 --- a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java +++ b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java @@ -25,9 +25,6 @@ import android.view.View; import android.view.ViewGroup; import android.view.MotionEvent; import android.widget.Button; -import android.widget.TextView; -import android.text.format.DateFormat; -import android.text.TextUtils; import android.util.Log; import com.android.internal.R; import com.android.internal.telephony.IccCard; @@ -37,7 +34,6 @@ import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockPatternView.Cell; import java.util.List; -import java.util.Date; /** * This is the screen that shows the 9 circle unlock widget and instructs @@ -75,27 +71,7 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient */ private boolean mEnableFallback; - private String mDateFormatString; - - private TextView mCarrier; - private TextView mDate; - - // are we showing battery information? - private boolean mShowingBatteryInfo = false; - - // last known plugged in state - private boolean mPluggedIn = false; - - // last known battery level - private int mBatteryLevel = 100; - - private String mNextAlarm = null; - - private String mInstructions = null; - private TextView mStatus1; - private TextView mStatusSep; - private TextView mStatus2; - + private StatusView mStatusView; private LockPatternView mLockPatternView; @@ -133,15 +109,18 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient private void updateFooter(FooterMode mode) { switch (mode) { case Normal: + Log.d(TAG, "mode normal"); mFooterNormal.setVisibility(View.VISIBLE); mFooterForgotPattern.setVisibility(View.GONE); break; case ForgotLockPattern: + Log.d(TAG, "mode ForgotLockPattern"); mFooterNormal.setVisibility(View.GONE); mFooterForgotPattern.setVisibility(View.VISIBLE); mForgotPatternButton.setVisibility(View.VISIBLE); break; case VerifyUnlocked: + Log.d(TAG, "mode VerifyUnlocked"); mFooterNormal.setVisibility(View.GONE); mFooterForgotPattern.setVisibility(View.GONE); } @@ -180,24 +159,16 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient mCreationOrientation = configuration.orientation; LayoutInflater inflater = LayoutInflater.from(context); + if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) { + Log.d(TAG, "portrait mode"); inflater.inflate(R.layout.keyguard_screen_unlock_portrait, this, true); } else { + Log.d(TAG, "landscape mode"); inflater.inflate(R.layout.keyguard_screen_unlock_landscape, this, true); } - mCarrier = (TextView) findViewById(R.id.carrier); - mDate = (TextView) findViewById(R.id.date); - - mDateFormatString = getContext().getString(R.string.full_wday_month_day_no_year); - refreshTimeAndDateDisplay(); - - mStatus1 = (TextView) findViewById(R.id.status1); - mStatusSep = (TextView) findViewById(R.id.statusSep); - mStatus2 = (TextView) findViewById(R.id.status2); - - resetStatusInfo(); - + mStatusView = new StatusView(this, mUpdateMonitor, mLockPatternUtils); mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern); @@ -249,15 +220,11 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient updateMonitor.registerSimStateCallback(this); setFocusableInTouchMode(true); - // Required to get Marquee to work. - mCarrier.setSelected(true); - mCarrier.setTextColor(0xffffffff); - // until we get an update... - mCarrier.setText( - LockScreen.getCarrierString( + mStatusView.setCarrierText(LockScreen.getCarrierString( mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn())); + } private void refreshEmergencyButtonText() { @@ -270,88 +237,6 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient mEnableFallback = state; } - private void resetStatusInfo() { - mInstructions = null; - mShowingBatteryInfo = mUpdateMonitor.shouldShowBatteryInfo(); - mPluggedIn = mUpdateMonitor.isDevicePluggedIn(); - mBatteryLevel = mUpdateMonitor.getBatteryLevel(); - mNextAlarm = mLockPatternUtils.getNextAlarm(); - updateStatusLines(); - } - - private void updateStatusLines() { - if (mInstructions != null) { - // instructions only - mStatus1.setText(mInstructions); - if (TextUtils.isEmpty(mInstructions)) { - mStatus1.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); - } else { - mStatus1.setCompoundDrawablesWithIntrinsicBounds( - R.drawable.ic_lock_idle_lock, 0, 0, 0); - } - - mStatus1.setVisibility(View.VISIBLE); - mStatusSep.setVisibility(View.GONE); - mStatus2.setVisibility(View.GONE); - } else if (mShowingBatteryInfo && mNextAlarm == null) { - // battery only - if (mPluggedIn) { - if (mBatteryLevel >= 100) { - mStatus1.setText(getContext().getString(R.string.lockscreen_charged)); - } else { - mStatus1.setText(getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel)); - } - } else { - mStatus1.setText(getContext().getString(R.string.lockscreen_low_battery)); - } - mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_charging, 0, 0, 0); - - mStatus1.setVisibility(View.VISIBLE); - mStatusSep.setVisibility(View.GONE); - mStatus2.setVisibility(View.GONE); - - } else if (mNextAlarm != null && !mShowingBatteryInfo) { - // alarm only - mStatus1.setText(mNextAlarm); - mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_alarm, 0, 0, 0); - - mStatus1.setVisibility(View.VISIBLE); - mStatusSep.setVisibility(View.GONE); - mStatus2.setVisibility(View.GONE); - } else if (mNextAlarm != null && mShowingBatteryInfo) { - // both battery and next alarm - mStatus1.setText(mNextAlarm); - mStatusSep.setText("|"); - mStatus2.setText(getContext().getString( - R.string.lockscreen_battery_short, - Math.min(100, mBatteryLevel))); - mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_alarm, 0, 0, 0); - if (mPluggedIn) { - mStatus2.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_charging, 0, 0, 0); - } else { - mStatus2.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); - } - - mStatus1.setVisibility(View.VISIBLE); - mStatusSep.setVisibility(View.VISIBLE); - mStatus2.setVisibility(View.VISIBLE); - } else { - // nothing specific to show; show general instructions - mStatus1.setText(R.string.lockscreen_pattern_instructions); - mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_lock, 0, 0, 0); - - mStatus1.setVisibility(View.VISIBLE); - mStatusSep.setVisibility(View.GONE); - mStatus2.setVisibility(View.GONE); - } - } - - - private void refreshTimeAndDateDisplay() { - mDate.setText(DateFormat.format(mDateFormatString, new Date())); - } - - @Override public boolean dispatchTouchEvent(MotionEvent ev) { // as long as the user is entering a pattern (i.e sending a touch @@ -366,25 +251,21 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient return result; } - // ---------- InfoCallback /** {@inheritDoc} */ public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { - mShowingBatteryInfo = showBatteryInfo; - mPluggedIn = pluggedIn; - mBatteryLevel = batteryLevel; - updateStatusLines(); + mStatusView.onRefreshBatteryInfo(showBatteryInfo, pluggedIn, batteryLevel); } /** {@inheritDoc} */ public void onTimeChanged() { - refreshTimeAndDateDisplay(); + mStatusView.onTimeChanged(); } /** {@inheritDoc} */ public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { - mCarrier.setText(LockScreen.getCarrierString(plmn, spn)); + mStatusView.onRefreshCarrierInfo(plmn, spn); } /** {@inheritDoc} */ @@ -444,8 +325,8 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient /** {@inheritDoc} */ public void onResume() { - // reset header - resetStatusInfo(); + // reset status + mStatusView.resetStatusInfo(mUpdateMonitor, mLockPatternUtils); // reset lock pattern mLockPatternView.enableInput(); @@ -514,8 +395,8 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient if (mLockPatternUtils.checkPattern(pattern)) { mLockPatternView .setDisplayMode(LockPatternView.DisplayMode.Correct); - mInstructions = ""; - updateStatusLines(); + mStatusView.setInstructions(""); + mStatusView.updateStatusLines(); mCallback.keyguardDone(true); mCallback.reportSuccessfulUnlockAttempt(); } else { @@ -533,8 +414,9 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient handleAttemptLockout(deadline); } else { // TODO mUnlockIcon.setVisibility(View.VISIBLE); - mInstructions = getContext().getString(R.string.lockscreen_pattern_wrong); - updateStatusLines(); + mStatusView.setInstructions( + getContext().getString(R.string.lockscreen_pattern_wrong)); + mStatusView.updateStatusLines(); mLockPatternView.postDelayed( mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS); @@ -552,17 +434,18 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient @Override public void onTick(long millisUntilFinished) { int secondsRemaining = (int) (millisUntilFinished / 1000); - mInstructions = getContext().getString( + mStatusView.setInstructions(getContext().getString( R.string.lockscreen_too_many_failed_attempts_countdown, - secondsRemaining); - updateStatusLines(); + secondsRemaining)); + mStatusView.updateStatusLines(); } @Override public void onFinish() { mLockPatternView.setEnabled(true); - mInstructions = getContext().getString(R.string.lockscreen_pattern_instructions); - updateStatusLines(); + mStatusView.setInstructions(getContext().getString( + R.string.lockscreen_pattern_instructions)); + mStatusView.updateStatusLines(); // TODO mUnlockIcon.setVisibility(View.VISIBLE); mFailedPatternAttemptsSinceLastTimeout = 0; if (mEnableFallback) { diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index dffccf8..db5f6c1 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -21,14 +21,19 @@ import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; +import static android.view.WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY; import com.android.internal.view.BaseSurfaceHolder; import com.android.internal.view.RootViewSurfaceTaker; +import com.android.internal.view.StandaloneActionMode; import com.android.internal.view.menu.ContextMenuBuilder; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuDialogHelper; +import com.android.internal.view.menu.MenuPopupHelper; import com.android.internal.view.menu.MenuView; import com.android.internal.view.menu.SubMenuBuilder; +import com.android.internal.widget.ActionBarContextView; +import com.android.internal.widget.ActionBarView; import android.app.KeyguardManager; import android.app.SearchManager; @@ -53,6 +58,7 @@ import android.util.Config; import android.util.EventLog; import android.util.Log; import android.util.SparseArray; +import android.view.ActionMode; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.InputQueue; @@ -66,6 +72,7 @@ import android.view.SurfaceHolder; import android.view.View; import android.view.ViewGroup; import android.view.ViewManager; +import android.view.ViewStub; import android.view.VolumePanel; import android.view.Window; import android.view.WindowManager; @@ -95,7 +102,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * Simple callback used by the context menu and its submenus. The options * menu submenus do not use this (their behavior is more complex). */ - ContextMenuCallback mContextMenuCallback = new ContextMenuCallback(FEATURE_CONTEXT_MENU); + DialogMenuCallback mContextMenuCallback = new DialogMenuCallback(FEATURE_CONTEXT_MENU); // This is the top-level view of the window, containing the window decor. private DecorView mDecor; @@ -114,6 +121,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private LayoutInflater mLayoutInflater; private TextView mTitleView; + + private ActionBarView mActionBar; private DrawableFeatureState[] mDrawables; @@ -191,8 +200,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { /* Custom title feature is enabled and the user is trying to enable another feature */ throw new AndroidRuntimeException("You cannot combine custom titles with other title features"); } - if (featureId == FEATURE_OPENGL) { - getAttributes().memoryType = WindowManager.LayoutParams.MEMORY_TYPE_GPU; + if ((features & (1 << FEATURE_NO_TITLE)) != 0 && featureId == FEATURE_ACTION_BAR) { + return false; // Ignore. No title dominates. + } + if ((features & (1 << FEATURE_ACTION_BAR)) != 0 && featureId == FEATURE_NO_TITLE) { + // Remove the action bar feature if we have no title. No title dominates. + removeFeature(FEATURE_ACTION_BAR); } return super.requestFeature(featureId); } @@ -276,6 +289,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public void setTitle(CharSequence title) { if (mTitleView != null) { mTitleView.setText(title); + } else if (mActionBar != null) { + mActionBar.setWindowTitle(title); } mTitle = title; } @@ -301,7 +316,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // Already prepared (isPrepared will be reset to false later) if (st.isPrepared) return true; - + if ((mPreparedPanel != null) && (mPreparedPanel != st)) { // Another Panel is prepared and possibly open, so close it closePanel(mPreparedPanel, false); @@ -315,9 +330,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (st.createdPanelView == null) { // Init the panel state's menu--return false if init failed - if (st.menu == null) { - if (!initializePanelMenu(st) || (st.menu == null)) { - return false; + if (st.menu == null || st.refreshMenuContent) { + if (st.menu == null) { + if (!initializePanelMenu(st) || (st.menu == null)) { + return false; + } } // Call callback, and return if it doesn't want to display menu if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) { @@ -326,6 +343,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return false; } + + st.refreshMenuContent = false; + + if (mActionBar != null) { + mActionBar.setMenu(st.menu); + } } // Callback and return if the callback does not want to show the menu @@ -349,36 +372,37 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public void onConfigurationChanged(Configuration newConfig) { - PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false); - if ((st != null) && (st.menu != null)) { - final MenuBuilder menuBuilder = (MenuBuilder) st.menu; + // Action bars handle their own menu state + if (mActionBar == null) { + PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false); + if ((st != null) && (st.menu != null)) { + final MenuBuilder menuBuilder = (MenuBuilder) st.menu; - if (st.isOpen) { - // Freeze state - final Bundle state = new Bundle(); - menuBuilder.saveHierarchyState(state); + if (st.isOpen) { + // Freeze state + final Bundle state = new Bundle(); + menuBuilder.saveHierarchyState(state); - // Remove the menu views since they need to be recreated - // according to the new configuration - clearMenuViews(st); + // Remove the menu views since they need to be recreated + // according to the new configuration + clearMenuViews(st); - // Re-open the same menu - reopenMenu(false); + // Re-open the same menu + reopenMenu(false); - // Restore state - menuBuilder.restoreHierarchyState(state); + // Restore state + menuBuilder.restoreHierarchyState(state); - } else { - // Clear menu views so on next menu opening, it will use - // the proper layout - clearMenuViews(st); + } else { + // Clear menu views so on next menu opening, it will use + // the proper layout + clearMenuViews(st); + } } } - } private static void clearMenuViews(PanelFeatureState st) { - // This can be called on config changes, so we should make sure // the views will be reconstructed based on the new orientation, etc. @@ -393,7 +417,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public final void openPanel(int featureId, KeyEvent event) { - openPanel(getPanelState(featureId, true), event); + if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null && + mActionBar.isOverflowReserved()) { + mActionBar.showOverflowMenu(); + } else { + openPanel(getPanelState(featureId, true), event); + } } private void openPanel(PanelFeatureState st, KeyEvent event) { @@ -484,7 +513,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public final void closePanel(int featureId) { - if (featureId == FEATURE_CONTEXT_MENU) { + if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null && + mActionBar.isOverflowReserved()) { + mActionBar.hideOverflowMenu(); + } else if (featureId == FEATURE_CONTEXT_MENU) { closeContextMenu(); } else { closePanel(getPanelState(featureId, true), true); @@ -545,6 +577,26 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } + @Override + public void invalidatePanelMenu(int featureId) { + PanelFeatureState st = getPanelState(featureId, true); + if (st.menu != null) { + st.menu.clear(); + } + st.refreshMenuContent = true; + st.refreshDecorView = true; + + // Prepare the options panel if we have an action bar + if ((featureId == FEATURE_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL) + && mActionBar != null) { + st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false); + if (st != null) { + st.isPrepared = false; + preparePanel(st, null); + } + } + } + /** * Called when the panel key is pushed down. * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}. @@ -558,7 +610,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // The panel key was pushed, so set the chording key mPanelChordingKey = keyCode; mPanelMayLongPress = false; - + PanelFeatureState st = getPanelState(featureId, true); if (!st.isOpen) { if (getContext().getResources().getConfiguration().keyboard @@ -567,7 +619,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } return preparePanel(st, event); } - } else if (mPanelMayLongPress && mPanelChordingKey == keyCode && (event.getFlags()&KeyEvent.FLAG_LONG_PRESS) != 0) { // We have had a long press while in a state where this @@ -602,25 +653,38 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } boolean playSoundEffect = false; - PanelFeatureState st = getPanelState(featureId, true); - if (st.isOpen || st.isHandled) { + final PanelFeatureState st = getPanelState(featureId, true); + if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null && + mActionBar.isOverflowReserved()) { + if (!mActionBar.isOverflowMenuShowing()) { + final Callback cb = getCallback(); + if (cb != null && + cb.onPreparePanel(featureId, st.createdPanelView, st.menu)) { + playSoundEffect = mActionBar.showOverflowMenu(); + } + } else { + playSoundEffect = mActionBar.hideOverflowMenu(); + } + } else { + if (st.isOpen || st.isHandled) { - // Play the sound effect if the user closed an open menu (and not if - // they just released a menu shortcut) - playSoundEffect = st.isOpen; + // Play the sound effect if the user closed an open menu (and not if + // they just released a menu shortcut) + playSoundEffect = st.isOpen; - // Close menu - closePanel(st, true); + // Close menu + closePanel(st, true); - } else if (st.isPrepared) { + } else if (st.isPrepared) { - // Write 'menu opened' to event log - EventLog.writeEvent(50001, 0); + // Write 'menu opened' to event log + EventLog.writeEvent(50001, 0); - // Show menu - openPanel(st, event); + // Show menu + openPanel(st, event); - playSoundEffect = true; + playSoundEffect = true; + } } if (playSoundEffect) { @@ -777,8 +841,20 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return true; } - // The window manager will give us a valid window token - new MenuDialogHelper(subMenu).show(null); + final Menu parentMenu = subMenu.getRootMenu(); + final PanelFeatureState panel = findMenuPanel(parentMenu); + + /* + * Use the panel open state to determine whether this is coming from an open panel + * or an action button. If it's an open panel we want to use MenuDialogHelper. + * If it's closed we want to grab the relevant view and create a popup anchored to it. + */ + if (panel.isOpen) { + // The window manager will give us a valid window token + new MenuDialogHelper(subMenu).show(null); + } else { + new MenuPopupHelper(getContext(), subMenu).show(); + } return true; } @@ -788,6 +864,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } private void reopenMenu(boolean toggleMenuMode) { + if (mActionBar != null) { + if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) { + final Callback cb = getCallback(); + if (cb != null) { + final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); + if (cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) { + mActionBar.showOverflowMenu(); + } + } + } else { + mActionBar.hideOverflowMenu(); + } + return; + } + PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); // Save the future expanded mode state since closePanel will reset it @@ -1414,7 +1505,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { sendCloseSystemWindows(); Intent intent = new Intent(Intent.ACTION_CALL_BUTTON); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getContext().startActivity(intent); + try { + getContext().startActivity(intent); + } catch (ActivityNotFoundException e) { + Log.w(TAG, "No activity found for android.intent.action.CALL_BUTTON."); + } } @Override @@ -1437,6 +1532,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { static private final String FOCUSED_ID_TAG = "android:focusedViewId"; static private final String VIEWS_TAG = "android:views"; static private final String PANELS_TAG = "android:Panels"; + static private final String ACTION_BAR_TAG = "android:ActionBar"; /** {@inheritDoc} */ @Override @@ -1470,6 +1566,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { outState.putSparseParcelableArray(PANELS_TAG, panelStates); } + if (mActionBar != null) { + outState.putBoolean(ACTION_BAR_TAG, mActionBar.isOverflowMenuShowing()); + } + return outState; } @@ -1504,6 +1604,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (panelStates != null) { restorePanelState(panelStates); } + + if (mActionBar != null && savedInstanceState.getBoolean(ACTION_BAR_TAG)) { + mActionBar.postShowOverflowMenu(); + } } /** @@ -1594,6 +1698,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private boolean mWatchingForMenu; private int mDownY; + private ActionMode mActionMode; + private ActionBarContextView mActionModeView; + public DecorView(Context context, int featureId) { super(context); mFeatureId = featureId; @@ -1602,7 +1709,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public boolean dispatchKeyEvent(KeyEvent event) { final int keyCode = event.getKeyCode(); - final boolean isDown = event.getAction() == KeyEvent.ACTION_DOWN; + final int action = event.getAction(); + final boolean isDown = action == KeyEvent.ACTION_DOWN; /* * If the user hits another key within the play sound delay, then @@ -1659,6 +1767,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } + // Back cancels action modes first. + if (mActionMode != null && keyCode == KeyEvent.KEYCODE_BACK) { + if (action == KeyEvent.ACTION_UP) { + mActionMode.finish(); + } + return true; + } + final Callback cb = getCallback(); final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event) : super.dispatchKeyEvent(event); @@ -1881,6 +1997,55 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return mContextMenuHelper != null; } + @Override + public ActionMode startActionModeForChild(View originalView, + ActionMode.Callback callback) { + // originalView can be used here to be sure that we don't obscure + // relevant content with the context mode UI. + return startActionMode(callback); + } + + @Override + public ActionMode startActionMode(ActionMode.Callback callback) { + if (mActionMode != null) { + mActionMode.finish(); + } + + final ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback); + ActionMode mode = getCallback().onStartActionMode(wrappedCallback); + if (mode != null) { + mActionMode = mode; + } else { + if (mActionModeView == null) { + if (hasFeature(FEATURE_ACTION_MODE_OVERLAY)) { + mActionModeView = new ActionBarContextView(mContext); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + MATCH_PARENT, WRAP_CONTENT); + addView(mActionModeView, params); + } else { + ViewStub stub = (ViewStub) findViewById( + com.android.internal.R.id.action_mode_bar_stub); + if (stub != null) { + mActionModeView = (ActionBarContextView) stub.inflate(); + } + } + } + + if (mActionModeView != null) { + mode = new StandaloneActionMode(getContext(), mActionModeView, wrappedCallback); + if (callback.onCreateActionMode(mode, mode.getMenu())) { + mode.invalidate(); + mActionModeView.initForMode(mode); + mActionModeView.setVisibility(View.VISIBLE); + mActionMode = mode; + } else { + mActionMode = null; + } + } + } + return mActionMode; + } + public void startChanging() { mChanging = true; } @@ -2060,6 +2225,37 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (keepOn) PhoneWindow.this.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); else PhoneWindow.this.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } + + /** + * Clears out internal reference when the action mode is destroyed. + */ + private class ActionModeCallbackWrapper implements ActionMode.Callback { + private ActionMode.Callback mWrapped; + + public ActionModeCallbackWrapper(ActionMode.Callback wrapped) { + mWrapped = wrapped; + } + + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + return mWrapped.onCreateActionMode(mode, menu); + } + + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return mWrapped.onPrepareActionMode(mode, menu); + } + + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + return mWrapped.onActionItemClicked(mode, item); + } + + public void onDestroyActionMode(ActionMode mode) { + mWrapped.onDestroyActionMode(mode); + if (mActionModeView != null) { + mActionModeView.removeAllViews(); + } + mActionMode = null; + } + } } protected DecorView generateDecor() { @@ -2108,6 +2304,17 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) { requestFeature(FEATURE_NO_TITLE); + } else if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBar, false)) { + // Don't allow an action bar if there is no title. + requestFeature(FEATURE_ACTION_BAR); + } + + if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBarOverlay, false)) { + requestFeature(FEATURE_ACTION_BAR_OVERLAY); + } + + if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionModeOverlay, false)) { + requestFeature(FEATURE_ACTION_MODE_OVERLAY); } if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) { @@ -2118,6 +2325,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags())); } + if (getContext().getApplicationInfo().targetSdkVersion + < android.os.Build.VERSION_CODES.HONEYCOMB) { + addFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY); + } + WindowManager.LayoutParams params = getAttributes(); if (!hasSoftInputMode()) { @@ -2172,11 +2384,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } else { layoutResource = com.android.internal.R.layout.screen_title_icons; } + // XXX Remove this once action bar supports these features. + removeFeature(FEATURE_ACTION_BAR); // System.out.println("Title Icons!"); } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) { // Special case for a window with only a progress bar (and title). // XXX Need to have a no-title version of embedded windows. layoutResource = com.android.internal.R.layout.screen_progress; + // XXX Remove this once action bar supports these features. + removeFeature(FEATURE_ACTION_BAR); // System.out.println("Progress!"); } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) { // Special case for a window with a custom title. @@ -2186,11 +2402,19 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } else { layoutResource = com.android.internal.R.layout.screen_custom_title; } + // XXX Remove this once action bar supports these features. + removeFeature(FEATURE_ACTION_BAR); } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) { // If no other features and not embedded, only need a title. // If the window is floating, we need a dialog layout if (mIsFloating) { layoutResource = com.android.internal.R.layout.dialog_title; + } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) { + if ((features & (1 << FEATURE_ACTION_BAR_OVERLAY)) != 0) { + layoutResource = com.android.internal.R.layout.screen_action_bar_overlay; + } else { + layoutResource = com.android.internal.R.layout.screen_action_bar; + } } else { layoutResource = com.android.internal.R.layout.screen_title; } @@ -2275,6 +2499,22 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } else { mTitleView.setText(mTitle); } + } else { + mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar); + if (mActionBar != null) { + if (mActionBar.getTitle() == null) { + mActionBar.setWindowTitle(mTitle); + } + // Post the panel invalidate for later; avoid application onCreateOptionsMenu + // being called in the middle of onCreate or similar. + mDecor.post(new Runnable() { + public void run() { + if (!isDestroyed()) { + invalidatePanelMenu(FEATURE_ACTION_BAR); + } + } + }); + } } } } @@ -2628,6 +2868,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { boolean refreshDecorView; + boolean refreshMenuContent; + boolean wasLastOpen; boolean wasLastExpanded; @@ -2750,11 +2992,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * <li> Calls back to the callback's onMenuItemSelected when an item is * selected. */ - private final class ContextMenuCallback implements MenuBuilder.Callback { + private final class DialogMenuCallback implements MenuBuilder.Callback { private int mFeatureId; private MenuDialogHelper mSubMenuHelper; - public ContextMenuCallback(int featureId) { + public DialogMenuCallback(int featureId) { mFeatureId = featureId; } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 3cf4360..c6898d4 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -46,6 +46,8 @@ import android.os.SystemProperties; import android.os.Vibrator; import android.provider.Settings; +import com.android.internal.R; +import com.android.internal.app.ShutdownThread; import com.android.internal.policy.PolicyManager; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.telephony.ITelephony; @@ -88,6 +90,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVE import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_DRAG; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_PHONE; @@ -126,6 +129,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final boolean DEBUG_LAYOUT = false; static final boolean SHOW_STARTING_ANIMATIONS = true; static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; + + static final int LONG_PRESS_POWER_NOTHING = 0; + static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1; + static final int LONG_PRESS_POWER_SHUT_OFF = 2; // wallpaper is at the bottom, though the window manager may move it. static final int WALLPAPER_LAYER = 2; @@ -151,8 +158,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { // responsible for power management when displayed. static final int KEYGUARD_LAYER = 14; static final int KEYGUARD_DIALOG_LAYER = 15; + // the drag layer: input for drag-and-drop is associated with this window, + // which sits above all other focusable windows + static final int DRAG_LAYER = 16; // things in here CAN NOT take focus, but are shown on top of everything else. - static final int SYSTEM_OVERLAY_LAYER = 16; + static final int SYSTEM_OVERLAY_LAYER = 17; static final int APPLICATION_MEDIA_SUBLAYER = -2; static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; @@ -176,6 +186,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Context mContext; IWindowManager mWindowManager; LocalPowerManager mPowerManager; + IStatusBarService mStatusBarService; Vibrator mVibrator; // Vibrator for giving feedback of orientation changes // Vibrator pattern for haptic feedback of a long press. @@ -198,6 +209,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mSafeMode; WindowState mStatusBar = null; + boolean mStatusBarCanHide; final ArrayList<WindowState> mStatusBarPanels = new ArrayList<WindowState>(); WindowState mKeyguard = null; KeyguardViewMediator mKeyguardMediator; @@ -217,6 +229,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mDeskDockEnablesAccelerometer; int mLidKeyboardAccessibility; int mLidNavigationAccessibility; + int mLongPressOnPowerBehavior = -1; boolean mScreenOn = false; boolean mOrientationSensorEnabled = false; int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -264,6 +277,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final Rect mTmpVisibleFrame = new Rect(); WindowState mTopFullscreenOpaqueWindowState; + boolean mTopIsFullscreen; boolean mForceStatusBar; boolean mHideLockScreen; boolean mDismissKeyguard; @@ -273,6 +287,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Intent mDeskDockIntent; boolean mSearchKeyPressed; boolean mConsumeSearchKeyUp; + boolean mShowMenuKey = false; // track FLAG_NEEDS_MENU_KEY on frontmost window // support for activating the lock screen while the screen is on boolean mAllowLockscreenWhenOn; @@ -293,6 +308,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Nothing to see here, move along... int mFancyRotationAnimation; + + // Enable 3D recents based on config settings. + private Boolean mUse3dRecents; ShortcutManager mShortcutManager; PowerManager.WakeLock mBroadcastWakeLock; @@ -456,10 +474,27 @@ public class PhoneWindowManager implements WindowManagerPolicy { Runnable mPowerLongPress = new Runnable() { public void run() { - mShouldTurnOffOnKeyUp = false; - performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); - showGlobalActionsDialog(); + // The context isn't read + if (mLongPressOnPowerBehavior < 0) { + mLongPressOnPowerBehavior = mContext.getResources().getInteger( + com.android.internal.R.integer.config_longPressOnPowerBehavior); + } + switch (mLongPressOnPowerBehavior) { + case LONG_PRESS_POWER_NOTHING: + break; + case LONG_PRESS_POWER_GLOBAL_ACTIONS: + mShouldTurnOffOnKeyUp = false; + performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); + showGlobalActionsDialog(); + break; + case LONG_PRESS_POWER_SHUT_OFF: + mShouldTurnOffOnKeyUp = false; + performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); + ShutdownThread.shutdown(mContext, true); + break; + } } }; @@ -501,6 +536,27 @@ public class PhoneWindowManager implements WindowManagerPolicy { * Create (if necessary) and launch the recent apps dialog */ void showRecentAppsDialog() { + // We can't initialize this in init() since the configuration hasn't been loaded yet. + if (mUse3dRecents == null) { + mUse3dRecents = mContext.getResources().getBoolean(R.bool.config_enableRecentApps3D); + } + + // Use 3d Recents dialog + if (mUse3dRecents) { + try { + Intent intent = new Intent(); + intent.setClassName("com.android.systemui", + "com.android.systemui.statusbar.RecentApplicationsActivity"); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + mContext.startActivity(intent); + return; + } catch (ActivityNotFoundException e) { + Log.e(TAG, "Failed to launch RecentAppsIntent", e); + } + } + + // Fallback to dialog if we fail to launch the above. if (mRecentAppsDialog == null) { mRecentAppsDialog = new RecentApplicationsDialog(mContext); } @@ -532,6 +588,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mDeskDockIntent.addCategory(Intent.CATEGORY_DESK_DOCK); mDeskDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PhoneWindowManager.mBroadcastWakeLock"); @@ -574,6 +631,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.array.config_safeModeDisabledVibePattern); mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_safeModeEnabledVibePattern); + + // Note: the Configuration is not stable here, so we cannot load mStatusBarCanHide from + // config_statusBarCanHide because the latter depends on the screen size } public void updateSettings() { @@ -810,6 +870,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return TOAST_LAYER; case TYPE_WALLPAPER: return WALLPAPER_LAYER; + case TYPE_DRAG: + return DRAG_LAYER; } Log.e(TAG, "Unknown window type: " + type); return APPLICATION_LAYER; @@ -986,6 +1048,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; } mStatusBar = win; + + // The Configuration will be stable by now, so we can load this + mStatusBarCanHide = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_statusBarCanHide); + break; case TYPE_STATUS_BAR_PANEL: mContext.enforceCallingOrSelfPermission( @@ -1244,7 +1311,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) { final int fl = attrs.flags; - if ((fl & + if (mStatusBarCanHide && (fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { contentInset.set(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom); @@ -1277,10 +1344,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mStatusBar.isVisibleLw()) { // If the status bar is hidden, we don't want to cause // windows behind it to scroll. - mDockTop = mContentTop = mCurTop = mStatusBar.getFrameLw().bottom; - if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mDockBottom=" - + mDockBottom + " mContentBottom=" - + mContentBottom + " mCurBottom=" + mCurBottom); + final Rect r = mStatusBar.getFrameLw(); + if (mDockTop == r.top) mDockTop = r.bottom; + else if (mDockBottom == r.bottom) mDockBottom = r.top; + mContentTop = mCurTop = mDockTop; + mContentBottom = mCurBottom = mDockBottom; + if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mDockTop=" + mDockTop + + " mContentTop=" + mContentTop + + " mCurTop=" + mCurTop + + " mDockBottom=" + mDockBottom + + " mContentBottom=" + mContentBottom + + " mCurBottom=" + mCurBottom); } } } @@ -1365,7 +1439,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { attrs.gravity = Gravity.BOTTOM; mDockLayer = win.getSurfaceLayer(); } else { - if ((fl & + if (mStatusBarCanHide && (fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { // This is the case for a normal activity window: we want it @@ -1397,7 +1471,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { vf.right = mCurRight; vf.bottom = mCurBottom; } - } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) { + } else if (mStatusBarCanHide && (fl & FLAG_LAYOUT_IN_SCREEN) != 0) { // A window that has requested to fill the entire screen just // gets everything, period. pf.left = df.left = cf.left = 0; @@ -1526,8 +1600,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public int finishAnimationLw() { int changes = 0; - - boolean hiding = false; + boolean topIsFullscreen = false; + + final WindowManager.LayoutParams lp = (mTopFullscreenOpaqueWindowState != null) + ? mTopFullscreenOpaqueWindowState.getAttrs() + : null; + if (mStatusBar != null) { if (localLOGV) Log.i(TAG, "force=" + mForceStatusBar + " top=" + mTopFullscreenOpaqueWindowState); @@ -1535,39 +1613,82 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; } else if (mTopFullscreenOpaqueWindowState != null) { - //Log.i(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw() - // + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw()); - //Log.i(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()); - WindowManager.LayoutParams lp = - mTopFullscreenOpaqueWindowState.getAttrs(); - boolean hideStatusBar = - (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; - if (hideStatusBar) { - if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar"); - if (mStatusBar.hideLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; - hiding = true; + if (localLOGV) { + Log.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw() + + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw()); + Log.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs() + + " lp.flags=0x" + Integer.toHexString(lp.flags)); + } + topIsFullscreen = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; + // The subtle difference between the window for mTopFullscreenOpaqueWindowState + // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window + // has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the + // case though. + if (topIsFullscreen) { + if (mStatusBarCanHide) { + if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar"); + if (mStatusBar.hideLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; + } else if (localLOGV) { + Log.v(TAG, "Preventing status bar from hiding by policy"); + } } else { if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; } } } - - if (changes != 0 && hiding) { - IStatusBarService sbs = IStatusBarService.Stub.asInterface(ServiceManager.getService("statusbar")); - if (sbs != null) { - try { - // Make sure the window shade is hidden. - sbs.collapse(); - } catch (RemoteException e) { - } - } + + boolean topNeedsMenu = mShowMenuKey; + if (lp != null) { + topNeedsMenu = (lp.flags & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0; + } + + if (DEBUG_LAYOUT) Log.v(TAG, "Top window " + + (topNeedsMenu ? "needs" : "does not need") + + " the MENU key"); + + final boolean changedFullscreen = (mTopIsFullscreen != topIsFullscreen); + final boolean changedMenu = (topNeedsMenu != mShowMenuKey); + + if (changedFullscreen || changedMenu) { + final boolean topIsFullscreenF = topIsFullscreen; + final boolean topNeedsMenuF = topNeedsMenu; + + mTopIsFullscreen = topIsFullscreen; + mShowMenuKey = topNeedsMenu; + + mHandler.post(new Runnable() { + public void run() { + if (mStatusBarService == null) { + // This is the one that can not go away, but it doesn't come up + // before the window manager does, so don't fail if it doesn't + // exist. This works as long as no fullscreen windows come up + // before the status bar service does. + mStatusBarService = IStatusBarService.Stub.asInterface( + ServiceManager.getService("statusbar")); + } + final IStatusBarService sbs = mStatusBarService; + if (mStatusBarService != null) { + try { + if (changedFullscreen) { + sbs.setActiveWindowIsFullscreen(topIsFullscreenF); + } + if (changedMenu) { + sbs.setMenuKeyVisible(topNeedsMenuF); + } + } catch (RemoteException e) { + // This should be impossible because we're in the same process. + mStatusBarService = null; + } + } + } + }); } // Hide the key guard if a visible window explicitly specifies that it wants to be displayed // when the screen is locked if (mKeyguard != null) { - if (localLOGV) Log.v(TAG, "finishLayoutLw::mHideKeyguard="+mHideLockScreen); + if (localLOGV) Log.v(TAG, "finishAnimationLw::mHideKeyguard="+mHideLockScreen); if (mDismissKeyguard && !mKeyguardMediator.isSecure()) { if (mKeyguard.hideLw(true)) { changes |= FINISH_LAYOUT_REDO_LAYOUT diff --git a/policy/src/com/android/internal/policy/impl/PowerDialog.java b/policy/src/com/android/internal/policy/impl/PowerDialog.java deleted file mode 100644 index de35bd7..0000000 --- a/policy/src/com/android/internal/policy/impl/PowerDialog.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.policy.impl; - -import com.android.internal.R; - -import android.app.Dialog; -import android.app.StatusBarManager; -import android.content.Context; -import android.os.Bundle; -import android.os.RemoteException; -import android.os.LocalPowerManager; -import android.os.ServiceManager; -import android.os.SystemClock; - -import com.android.internal.app.ShutdownThread; -import com.android.internal.telephony.ITelephony; -import android.view.KeyEvent; -import android.util.Log; -import android.view.View; -import android.view.WindowManager; -import android.view.View.OnClickListener; -import android.view.View.OnKeyListener; -import android.widget.Button; - -/** - * @deprecated use {@link GlobalActions} instead. - */ -public class PowerDialog extends Dialog implements OnClickListener, - OnKeyListener { - private static final String TAG = "PowerDialog"; - - static private StatusBarManager sStatusBar; - private Button mKeyguard; - private Button mPower; - private Button mRadioPower; - private Button mSilent; - - private LocalPowerManager mPowerManager; - - public PowerDialog(Context context, LocalPowerManager powerManager) { - super(context); - mPowerManager = powerManager; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Context context = getContext(); - - if (sStatusBar == null) { - sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE); - } - - setContentView(com.android.internal.R.layout.power_dialog); - - getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); - if (!getContext().getResources().getBoolean( - com.android.internal.R.bool.config_sf_slowBlur)) { - getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - } - getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, - WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - - setTitle(context.getText(R.string.power_dialog)); - - mKeyguard = (Button) findViewById(R.id.keyguard); - mPower = (Button) findViewById(R.id.off); - mRadioPower = (Button) findViewById(R.id.radio_power); - mSilent = (Button) findViewById(R.id.silent); - - if (mKeyguard != null) { - mKeyguard.setOnKeyListener(this); - mKeyguard.setOnClickListener(this); - } - if (mPower != null) { - mPower.setOnClickListener(this); - } - if (mRadioPower != null) { - mRadioPower.setOnClickListener(this); - } - if (mSilent != null) { - mSilent.setOnClickListener(this); - // XXX: HACK for now hide the silent until we get mute support - mSilent.setVisibility(View.GONE); - } - - CharSequence text; - - // set the keyguard button's text - text = context.getText(R.string.screen_lock); - mKeyguard.setText(text); - mKeyguard.requestFocus(); - - try { - ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); - if (phone != null) { - text = phone.isRadioOn() ? context - .getText(R.string.turn_off_radio) : context - .getText(R.string.turn_on_radio); - } - } catch (RemoteException ex) { - // ignore it - } - - mRadioPower.setText(text); - } - - public void onClick(View v) { - this.dismiss(); - if (v == mPower) { - // shutdown by making sure radio and power are handled accordingly. - ShutdownThread.shutdown(getContext(), true); - } else if (v == mRadioPower) { - try { - ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); - if (phone != null) { - phone.toggleRadioOnOff(); - } - } catch (RemoteException ex) { - // ignore it - } - } else if (v == mSilent) { - // do something - } else if (v == mKeyguard) { - if (v.isInTouchMode()) { - // only in touch mode for the reasons explained in onKey. - this.dismiss(); - mPowerManager.goToSleep(SystemClock.uptimeMillis() + 1); - } - } - } - - public boolean onKey(View v, int keyCode, KeyEvent event) { - // The activate keyguard button needs to put the device to sleep on the - // key up event. If we try to put it to sleep on the click or down - // action - // the the up action will cause the device to wake back up. - - // Log.i(TAG, "keyCode: " + keyCode + " action: " + event.getAction()); - if (keyCode != KeyEvent.KEYCODE_DPAD_CENTER - || event.getAction() != KeyEvent.ACTION_UP) { - // Log.i(TAG, "getting out of dodge..."); - return false; - } - - // Log.i(TAG, "Clicked mKeyguard! dimissing dialog"); - this.dismiss(); - // Log.i(TAG, "onKey: turning off the screen..."); - // XXX: This is a hack for now - mPowerManager.goToSleep(event.getEventTime() + 1); - return true; - } - - public void show() { - super.show(); - Log.d(TAG, "show... disabling expand"); - sStatusBar.disable(StatusBarManager.DISABLE_EXPAND); - } - - public void dismiss() { - super.dismiss(); - Log.d(TAG, "dismiss... reenabling expand"); - sStatusBar.disable(StatusBarManager.DISABLE_NONE); - } -} diff --git a/policy/src/com/android/internal/policy/impl/StatusView.java b/policy/src/com/android/internal/policy/impl/StatusView.java new file mode 100644 index 0000000..3f08cfd --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/StatusView.java @@ -0,0 +1,255 @@ +// Copyright 2010 Google Inc. All Rights Reserved. + +package com.android.internal.policy.impl; + +import com.android.internal.R; +import com.android.internal.widget.LockPatternUtils; + +import java.util.Date; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.text.format.DateFormat; +import android.util.Log; +import android.view.View; +import android.widget.TextView; + +class StatusView { + private String mDateFormatString; + + private TextView mCarrier; + private TextView mDate; + + // are we showing battery information? + private boolean mShowingBatteryInfo = false; + + // last known plugged in state + private boolean mPluggedIn = false; + + // last known battery level + private int mBatteryLevel = 100; + + private String mNextAlarm = null; + + private String mInstructions = null; + private TextView mStatus1; + private TextView mStatus2; + private TextView mPropertyOf; + + private boolean mHasStatus2; + private boolean mHasCarrier; + private boolean mHasDate; + private boolean mHasProperty; + + private View mView; + + private View findViewById(int id) { + return mView.findViewById(id); + } + + private Context getContext() { + return mView.getContext(); + } + + void setInstructions(String instructions) { + mInstructions = instructions; + } + + void setCarrierText(CharSequence carrierText) { + if (mCarrier != null) { + mCarrier.setText(carrierText); + } + } + + void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + mShowingBatteryInfo = showBatteryInfo; + mPluggedIn = pluggedIn; + mBatteryLevel = batteryLevel; + updateStatusLines(); + } + + void onTimeChanged() { + refreshTimeAndDateDisplay(); + } + + public void onRingerModeChanged(int state) { + } + + void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + setCarrierText(LockScreen.getCarrierString(plmn, spn)); + } + + public StatusView(View view, KeyguardUpdateMonitor updateMonitor, + LockPatternUtils lockPatternUtils) { + mView = view; + mCarrier = (TextView) findViewById(R.id.carrier); + mHasCarrier = (mCarrier != null); + mDate = (TextView) findViewById(R.id.date); + mHasDate = (mDate != null); + mDateFormatString = getContext().getString(R.string.full_wday_month_day_no_year); + + refreshTimeAndDateDisplay(); + + mStatus1 = (TextView) findViewById(R.id.status1); + mStatus2 = (TextView) findViewById(R.id.status2); + mHasStatus2 = (mStatus2 != null); + mPropertyOf = (TextView) findViewById(R.id.propertyOf); + mHasProperty = (mPropertyOf != null); + + resetStatusInfo(updateMonitor, lockPatternUtils); + + // Required to get Marquee to work. + if (mHasCarrier) { + mCarrier.setSelected(true); + mCarrier.setTextColor(0xffffffff); + } + + } + + void resetStatusInfo(KeyguardUpdateMonitor updateMonitor, LockPatternUtils lockPatternUtils) { + mInstructions = null; + mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo(); + mPluggedIn = updateMonitor.isDevicePluggedIn(); + mBatteryLevel = updateMonitor.getBatteryLevel(); + mNextAlarm = lockPatternUtils.getNextAlarm(); + updateStatusLines(); + } + + void setInstructionText(int stringId) { + mStatus1.setText(stringId); + mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_lock, 0, 0, 0); + mStatus1.setVisibility(View.VISIBLE); + } + + void setInstructionText(String string) { + mStatus1.setText(string); + mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_lock, 0, 0, 0); + mStatus1.setVisibility(View.VISIBLE); + } + + void setCarrierText(int stringId) { + mCarrier.setText(stringId); + } + void setCarrierText(String string) { + mCarrier.setText(string); + } + + /** Originated from PatternUnlockScreen **/ + void updateStatusLines() { + if (mHasProperty) { + // TODO Get actual name & email + String name = "John Smith"; + String email = "jsmith@gmail.com"; + mPropertyOf.setText("Property of:\n" + name + "\n" + email); + mPropertyOf.setVisibility(View.VISIBLE); + } + + if (!mHasStatus2) return; + + if (mInstructions != null) { + // instructions only + mStatus1.setText(mInstructions); + if (TextUtils.isEmpty(mInstructions)) { + mStatus1.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + } else { + mStatus1.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_lock_idle_lock, 0, 0, 0); + } + + mStatus1.setVisibility(View.VISIBLE); + mStatus2.setVisibility(View.INVISIBLE); + } else if (mShowingBatteryInfo && mNextAlarm == null) { + // battery only + if (mPluggedIn) { + if (mBatteryLevel >= 100) { + mStatus1.setText(getContext().getString(R.string.lockscreen_charged)); + } else { + mStatus1.setText(getContext().getString(R.string.lockscreen_plugged_in, + mBatteryLevel)); + } + } else { + mStatus1.setText(getContext().getString(R.string.lockscreen_low_battery)); + } + mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_charging, 0, + 0, 0); + + mStatus1.setVisibility(View.VISIBLE); + mStatus2.setVisibility(View.INVISIBLE); + + } else if (mNextAlarm != null && !mShowingBatteryInfo) { + // alarm only + mStatus1.setText(mNextAlarm); + mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_alarm, 0, + 0, 0); + + mStatus1.setVisibility(View.VISIBLE); + mStatus2.setVisibility(View.INVISIBLE); + } else if (mNextAlarm != null && mShowingBatteryInfo) { + // both battery and next alarm + mStatus1.setText(mNextAlarm); + mStatus2.setText(getContext().getString( + R.string.lockscreen_battery_short, + Math.min(100, mBatteryLevel))); + mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_alarm, 0, + 0, 0); + if (mPluggedIn) { + mStatus2.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_charging, + 0, 0, 0); + } else { + mStatus2.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + } + + mStatus1.setVisibility(View.VISIBLE); + mStatus2.setVisibility(View.VISIBLE); + } else { + // nothing specific to show; show general instructions + mStatus1.setText(R.string.lockscreen_pattern_instructions); + mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_lock, 0, + 0, 0); + + mStatus1.setVisibility(View.VISIBLE); + mStatus2.setVisibility(View.INVISIBLE); + } + } + + /** Originated from LockScreen **/ + // TODO Merge with function above + void updateStatusLines(boolean showStatusLines, String charging, Drawable chargingIcon, + Drawable alarmIcon) { + if (!showStatusLines || (charging == null && mNextAlarm == null)) { + mStatus1.setVisibility(View.INVISIBLE); + mStatus2.setVisibility(View.INVISIBLE); + } else if (charging != null && mNextAlarm == null) { + // charging only + mStatus1.setVisibility(View.VISIBLE); + mStatus2.setVisibility(View.INVISIBLE); + + mStatus1.setText(charging); + mStatus1.setCompoundDrawablesWithIntrinsicBounds(chargingIcon, null, null, null); + } else if (mNextAlarm != null && charging == null) { + // next alarm only + mStatus1.setVisibility(View.VISIBLE); + mStatus2.setVisibility(View.INVISIBLE); + + mStatus1.setText(mNextAlarm); + mStatus1.setCompoundDrawablesWithIntrinsicBounds(alarmIcon, null, null, null); + } else if (charging != null && mNextAlarm != null) { + // both charging and next alarm + mStatus1.setVisibility(View.VISIBLE); + mStatus2.setVisibility(View.VISIBLE); + + mStatus1.setText(charging); + mStatus1.setCompoundDrawablesWithIntrinsicBounds(chargingIcon, null, null, null); + mStatus2.setText(mNextAlarm); + mStatus2.setCompoundDrawablesWithIntrinsicBounds(alarmIcon, null, null, null); + } + } + + void refreshTimeAndDateDisplay() { + if (mHasDate) { + mDate.setText(DateFormat.format(mDateFormatString, new Date())); + } + } + +} |