From e5ed42d1bc9281d35d998d976835f93a6c8cffe6 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 21 Oct 2008 07:00:00 -0700 Subject: [PATCH 001/458] Initial Contribution --- policy/Android.mk | 12 + .../policy/impl/AccountUnlockScreen.java | 190 ++ .../internal/policy/impl/GlobalActions.java | 414 +++ .../internal/policy/impl/KeyguardScreen.java | 40 + .../policy/impl/KeyguardScreenCallback.java | 61 + .../policy/impl/KeyguardUpdateMonitor.java | 552 ++++ .../policy/impl/KeyguardViewBase.java | 175 ++ .../policy/impl/KeyguardViewCallback.java | 49 + .../policy/impl/KeyguardViewManager.java | 200 ++ .../policy/impl/KeyguardViewMediator.java | 902 ++++++ .../policy/impl/KeyguardViewProperties.java | 43 + .../policy/impl/LockPatternKeyguardView.java | 514 ++++ .../LockPatternKeyguardViewProperties.java | 65 + .../internal/policy/impl/LockScreen.java | 367 +++ .../policy/impl/PhoneLayoutInflater.java | 73 + .../internal/policy/impl/PhoneWindow.java | 2572 +++++++++++++++++ .../policy/impl/PhoneWindowManager.java | 1409 +++++++++ .../android/internal/policy/impl/Policy.java | 45 + .../internal/policy/impl/PowerDialog.java | 177 ++ .../policy/impl/RecentApplicationsDialog.java | 253 ++ .../internal/policy/impl/ShortcutManager.java | 120 + .../internal/policy/impl/ShutdownThread.java | 138 + .../internal/policy/impl/SimUnlockScreen.java | 351 +++ .../internal/policy/impl/UnlockScreen.java | 327 +++ .../android/internal/policy/impl/package.html | 5 + 25 files changed, 9054 insertions(+) create mode 100644 policy/Android.mk create mode 100644 policy/com/android/internal/policy/impl/AccountUnlockScreen.java create mode 100644 policy/com/android/internal/policy/impl/GlobalActions.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardScreen.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardScreenCallback.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardViewBase.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardViewCallback.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardViewManager.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardViewMediator.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardViewProperties.java create mode 100644 policy/com/android/internal/policy/impl/LockPatternKeyguardView.java create mode 100644 policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java create mode 100644 policy/com/android/internal/policy/impl/LockScreen.java create mode 100644 policy/com/android/internal/policy/impl/PhoneLayoutInflater.java create mode 100644 policy/com/android/internal/policy/impl/PhoneWindow.java create mode 100644 policy/com/android/internal/policy/impl/PhoneWindowManager.java create mode 100644 policy/com/android/internal/policy/impl/Policy.java create mode 100644 policy/com/android/internal/policy/impl/PowerDialog.java create mode 100644 policy/com/android/internal/policy/impl/RecentApplicationsDialog.java create mode 100644 policy/com/android/internal/policy/impl/ShortcutManager.java create mode 100644 policy/com/android/internal/policy/impl/ShutdownThread.java create mode 100644 policy/com/android/internal/policy/impl/SimUnlockScreen.java create mode 100644 policy/com/android/internal/policy/impl/UnlockScreen.java create mode 100644 policy/com/android/internal/policy/impl/package.html diff --git a/policy/Android.mk b/policy/Android.mk new file mode 100644 index 000000000000..462431f905fb --- /dev/null +++ b/policy/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) + +# the library +# ============================================================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + $(call all-subdir-java-files) + +LOCAL_MODULE:= android.policy + +include $(BUILD_JAVA_LIBRARY) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java new file mode 100644 index 000000000000..98cb548d8ff6 --- /dev/null +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2008 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 com.android.internal.widget.LockPatternUtils; + +import android.accounts.AccountsServiceConstants; +import android.accounts.IAccountsService; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.graphics.Rect; +import android.os.IBinder; +import android.os.RemoteException; +import android.text.InputFilter; +import android.text.LoginFilter; +import android.util.Log; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.RelativeLayout; +import android.widget.TextView; + +/** + * When the user forgets their password a bunch of times, we fall back on their + * account's login/password to unlock the phone (and reset their lock pattern). + * + *

This class is useful only on platforms that support the + * IAccountsService. + */ +public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen, + View.OnClickListener, ServiceConnection { + + + private static final String LOCK_PATTERN_PACKAGE = "com.android.settings"; + private static final String LOCK_PATTERN_CLASS = + "com.android.settings.ChooseLockPattern"; + + private final KeyguardScreenCallback mCallback; + private final LockPatternUtils mLockPatternUtils; + private IAccountsService mAccountsService; + + private TextView mTopHeader; + private TextView mInstructions; + private EditText mLogin; + private EditText mPassword; + private Button mOk; + private Button mEmergencyCall; + + /** + * AccountUnlockScreen constructor. + * + * @throws IllegalStateException if the IAccountsService is not + * available on the current platform. + */ + public AccountUnlockScreen(Context context, + KeyguardScreenCallback callback, + LockPatternUtils lockPatternUtils) { + super(context); + mCallback = callback; + mLockPatternUtils = lockPatternUtils; + + LayoutInflater.from(context).inflate( + R.layout.keyguard_screen_glogin_unlock, this, true); + + mTopHeader = (TextView) findViewById(R.id.topHeader); + + mInstructions = (TextView) findViewById(R.id.instructions); + + mLogin = (EditText) findViewById(R.id.login); + mLogin.setFilters(new InputFilter[] { new LoginFilter.UsernameFilterGeneric() } ); + + mPassword = (EditText) findViewById(R.id.password); + + mOk = (Button) findViewById(R.id.ok); + mOk.setOnClickListener(this); + + mEmergencyCall = (Button) findViewById(R.id.emergencyCall); + mEmergencyCall.setOnClickListener(this); + + Log.v("AccountUnlockScreen", "debug: Connecting to accounts service"); + final boolean connected = mContext.bindService(AccountsServiceConstants.SERVICE_INTENT, + this, Context.BIND_AUTO_CREATE); + if (!connected) { + Log.v("AccountUnlockScreen", "debug: Couldn't connect to accounts service"); + throw new IllegalStateException("couldn't bind to accounts service"); + } + } + + @Override + protected boolean onRequestFocusInDescendants(int direction, + Rect previouslyFocusedRect) { + // send focus to the login field + return mLogin.requestFocus(direction, previouslyFocusedRect); + } + + /** {@inheritDoc} */ + public void onPause() { + + } + + /** {@inheritDoc} */ + public void onResume() { + // start fresh + mLogin.setText(""); + mPassword.setText(""); + mLogin.requestFocus(); + } + + /** {@inheritDoc} */ + public void cleanUp() { + mContext.unbindService(this); + } + + /** {@inheritDoc} */ + public void onClick(View v) { + if (v == mOk) { + if (checkPassword()) { + // clear out forgotten password + mLockPatternUtils.setPermanentlyLocked(false); + + // launch the 'choose lock pattern' activity so + // the user can pick a new one if they want to + Intent intent = new Intent(); + intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + + // close the keyguard + mCallback.keyguardDone(true); + } else { + mInstructions.setText(R.string.lockscreen_glogin_invalid_input); + mPassword.setText(""); + } + } + + if (v == mEmergencyCall) { + mCallback.takeEmergencyCallAction(); + } + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_DOWN + && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { + mCallback.goToLockScreen(); + return true; + } + return super.dispatchKeyEvent(event); + } + + private boolean checkPassword() { + final String login = mLogin.getText().toString(); + final String password = mPassword.getText().toString(); + try { + return mAccountsService.shouldUnlock(login, password); + } catch (RemoteException e) { + return false; + } + } + + /** {@inheritDoc} */ + public void onServiceConnected(ComponentName name, IBinder service) { + Log.v("AccountUnlockScreen", "debug: About to grab as interface"); + mAccountsService = IAccountsService.Stub.asInterface(service); + } + + /** {@inheritDoc} */ + public void onServiceDisconnected(ComponentName name) { + mAccountsService = null; + } +} diff --git a/policy/com/android/internal/policy/impl/GlobalActions.java b/policy/com/android/internal/policy/impl/GlobalActions.java new file mode 100644 index 000000000000..7f8e57b13778 --- /dev/null +++ b/policy/com/android/internal/policy/impl/GlobalActions.java @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2008 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 com.google.android.collect.Lists; + +import android.app.AlertDialog; +import android.app.StatusBarManager; +import android.content.Context; +import android.content.BroadcastReceiver; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.DialogInterface; +import android.media.AudioManager; +import android.os.LocalPowerManager; +import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import java.util.ArrayList; + +/** + * Helper to show the global actions dialog. Each item is an {@link Action} that + * may show depending on whether the keyguard is showing, and whether the device + * is provisioned. + */ +class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener { + + private StatusBarManager mStatusBar; + + private final Context mContext; + private final LocalPowerManager mPowerManager; + private final AudioManager mAudioManager; + private ArrayList mItems; + private AlertDialog mDialog; + + private ToggleAction mSilentModeToggle; + + private MyAdapter mAdapter; + + private boolean mKeyguardShowing = false; + private boolean mDeviceProvisioned = false; + + /** + * @param context everything needs a context :) + * @param powerManager used to turn the screen off (the lock action). + */ + public GlobalActions(Context context, LocalPowerManager powerManager) { + mContext = context; + mPowerManager = powerManager; + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + + // receive broadcasts + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + context.registerReceiver(mBroadcastReceiver, filter); + } + + /** + * Show the global actions dialog (creating if necessary) + * @param keyguardShowing True if keyguard is showing + */ + public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) { + mKeyguardShowing = keyguardShowing; + mDeviceProvisioned = isDeviceProvisioned; + if (mDialog == null) { + mStatusBar = (StatusBarManager)mContext.getSystemService(Context.STATUS_BAR_SERVICE); + mDialog = createDialog(); + } + prepareDialog(); + + mStatusBar.disable(StatusBarManager.DISABLE_EXPAND); + mDialog.show(); + } + + /** + * Create the global actions dialog. + * @return A new dialog. + */ + private AlertDialog createDialog() { + + mSilentModeToggle = new ToggleAction( + R.drawable.ic_lock_silent_mode, + R.drawable.ic_lock_silent_mode_off, + R.string.global_action_toggle_silent_mode, + R.string.global_action_silent_mode_on_status, + R.string.global_action_silent_mode_off_status) { + + void onToggle(boolean on) { + mAudioManager.setRingerMode(on ? AudioManager.RINGER_MODE_SILENT + : AudioManager.RINGER_MODE_NORMAL); + } + + public boolean showDuringKeyguard() { + return true; + } + + public boolean showBeforeProvisioning() { + return false; + } + }; + + mItems = Lists.newArrayList( + /* Disabled pending bug 1304831 -- key or touch events wake up device before it + * can go to sleep. + // first: lock screen + new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock, R.string.global_action_lock) { + + public void onPress() { + mPowerManager.goToSleep(SystemClock.uptimeMillis() + 1); + } + + public boolean showDuringKeyguard() { + return false; + } + + public boolean showBeforeProvisioning() { + return false; + } + }, + */ + // next: silent mode + mSilentModeToggle, + // last: power off + new SinglePressAction(com.android.internal.R.drawable.ic_lock_power_off, R.string.global_action_power_off) { + + public void onPress() { + // shutdown by making sure radio and power are handled accordingly. + ShutdownThread.shutdownAfterDisablingRadio(mContext, true); + } + + public boolean showDuringKeyguard() { + return true; + } + + public boolean showBeforeProvisioning() { + return true; + } + }); + + mAdapter = new MyAdapter(); + + final AlertDialog.Builder ab = new AlertDialog.Builder(mContext); + + ab.setAdapter(mAdapter, this) + .setInverseBackgroundForced(true) + .setTitle(R.string.global_actions); + + final AlertDialog dialog = ab.create(); + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); + dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + + dialog.setOnDismissListener(this); + + return dialog; + } + + private void prepareDialog() { + // TODO: May need another 'Vibrate' toggle button, but for now treat them the same + final boolean silentModeOn = + mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; + mSilentModeToggle.updateState(silentModeOn); + mAdapter.notifyDataSetChanged(); + if (mKeyguardShowing) { + mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + } else { + mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); + } + } + + /** {@inheritDoc} */ + public void onDismiss(DialogInterface dialog) { + mStatusBar.disable(StatusBarManager.DISABLE_NONE); + } + + /** {@inheritDoc} */ + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + mAdapter.getItem(which).onPress(); + } + + + /** + * The adapter used for the list within the global actions dialog, taking + * into account whether the keyguard is showing via + * {@link GlobalActions#mKeyguardShowing} and whether the device is provisioned + * via {@link GlobalActions#mDeviceProvisioned}. + */ + private class MyAdapter extends BaseAdapter { + + public int getCount() { + int count = 0; + + for (int i = 0; i < mItems.size(); i++) { + final Action action = mItems.get(i); + + if (mKeyguardShowing && !action.showDuringKeyguard()) { + continue; + } + if (!mDeviceProvisioned && !action.showBeforeProvisioning()) { + continue; + } + count++; + } + return count; + } + + public Action getItem(int position) { + + int filteredPos = 0; + for (int i = 0; i < mItems.size(); i++) { + final Action action = mItems.get(i); + if (mKeyguardShowing && !action.showDuringKeyguard()) { + continue; + } + if (!mDeviceProvisioned && !action.showBeforeProvisioning()) { + continue; + } + if (filteredPos == position) { + return action; + } + filteredPos++; + } + + throw new IllegalArgumentException("position " + position + " out of " + + "range of showable actions, filtered count = " + + "= " + getCount() + ", keyguardshowing=" + mKeyguardShowing + + ", provisioned=" + mDeviceProvisioned); + } + + + public long getItemId(int position) { + return position; + } + + public View getView(int position, View convertView, ViewGroup parent) { + Action action = getItem(position); + return action.create(mContext, (LinearLayout) convertView, LayoutInflater.from(mContext)); + } + } + + // note: the scheme below made more sense when we were planning on having + // 8 different things in the global actions dialog. seems overkill with + // only 3 items now, but may as well keep this flexible approach so it will + // be easy should someone decide at the last minute to include something + // else, such as 'enable wifi', or 'enable bluetooth' + + /** + * What each item in the global actions dialog must be able to support. + */ + private interface Action { + LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater); + + void onPress(); + + /** + * @return whether this action should appear in the dialog when the keygaurd + * is showing. + */ + boolean showDuringKeyguard(); + + /** + * @return whether this action should appear in the dialog before the + * device is provisioned. + */ + boolean showBeforeProvisioning(); + } + + /** + * A single press action maintains no state, just responds to a press + * and takes an action. + */ + private static abstract class SinglePressAction implements Action { + private final int mIconResId; + private final int mMessageResId; + + protected SinglePressAction(int iconResId, int messageResId) { + mIconResId = iconResId; + mMessageResId = messageResId; + } + + abstract public void onPress(); + + public LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater) { + LinearLayout v = (LinearLayout) ((convertView != null) ? + convertView : + inflater.inflate(R.layout.global_actions_item, null)); + + ImageView icon = (ImageView) v.findViewById(R.id.icon); + TextView messageView = (TextView) v.findViewById(R.id.message); + + v.findViewById(R.id.status).setVisibility(View.GONE); + + icon.setImageDrawable(context.getResources().getDrawable(mIconResId)); + messageView.setText(mMessageResId); + + return v; + } + } + + /** + * A toggle action knows whether it is on or off, and displays an icon + * and status message accordingly. + */ + static abstract class ToggleAction implements Action { + + private boolean mOn = false; + + // prefs + private final int mEnabledIconResId; + private final int mDisabledIconResid; + private final int mMessageResId; + private final int mEnabledStatusMessageResId; + private final int mDisabledStatusMessageResId; + + /** + * @param enabledIconResId The icon for when this action is on. + * @param disabledIconResid The icon for when this action is off. + * @param essage The general information message, e.g 'Silent Mode' + * @param enabledStatusMessageResId The on status message, e.g 'sound disabled' + * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled' + */ + public ToggleAction(int enabledIconResId, + int disabledIconResid, + int essage, + int enabledStatusMessageResId, + int disabledStatusMessageResId) { + mEnabledIconResId = enabledIconResId; + mDisabledIconResid = disabledIconResid; + mMessageResId = essage; + mEnabledStatusMessageResId = enabledStatusMessageResId; + mDisabledStatusMessageResId = disabledStatusMessageResId; + } + + public LinearLayout create(Context context, LinearLayout convertView, + LayoutInflater inflater) { + LinearLayout v = (LinearLayout) ((convertView != null) ? + convertView : + inflater.inflate(R + .layout.global_actions_item, null)); + + ImageView icon = (ImageView) v.findViewById(R.id.icon); + TextView messageView = (TextView) v.findViewById(R.id.message); + TextView statusView = (TextView) v.findViewById(R.id.status); + + messageView.setText(mMessageResId); + + icon.setImageDrawable(context.getResources().getDrawable( + (mOn ? mEnabledIconResId : mDisabledIconResid))); + statusView.setText(mOn ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); + statusView.setVisibility(View.VISIBLE); + + return v; + } + + public void onPress() { + updateState(!mOn); + onToggle(mOn); + } + + abstract void onToggle(boolean on); + + public void updateState(boolean on) { + mOn = on; + } + } + + private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { + String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY); + if (! PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) { + mHandler.sendEmptyMessage(MESSAGE_DISMISS); + } + } + } + }; + + private static final int MESSAGE_DISMISS = 0; + private Handler mHandler = new Handler() { + public void handleMessage(Message msg) { + if (msg.what == MESSAGE_DISMISS) { + if (mDialog != null) { + mDialog.dismiss(); + } + } + } + }; +} diff --git a/policy/com/android/internal/policy/impl/KeyguardScreen.java b/policy/com/android/internal/policy/impl/KeyguardScreen.java new file mode 100644 index 000000000000..739664b30388 --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardScreen.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008 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; + +/** + * Common interface of each {@link android.view.View} that is a screen of + * {@link LockPatternKeyguardView}. + */ +public interface KeyguardScreen { + + /** + * This screen is no longer in front of the user. + */ + void onPause(); + + /** + * This screen is going to be in front of the user. + */ + void onResume(); + + /** + * This view is going away; a hook to do cleanup. + */ + void cleanUp(); + +} diff --git a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java new file mode 100644 index 000000000000..832288b1a04c --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2008 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; + +/** + * Within a keyguard, there may be several screens that need a callback + * to the host keyguard view. + */ +public interface KeyguardScreenCallback extends KeyguardViewCallback { + + /** + * Transition to the lock screen. + */ + void goToLockScreen(); + + /** + * Transitino to th unlock screen. + */ + void goToUnlockScreen(); + + /** + * @return Whether the keyguard requires some sort of PIN. + */ + boolean isSecure(); + + /** + * @return Whether we are in a mode where we only want to verify the + * user can get past the keyguard. + */ + boolean isVerifyUnlockOnly(); + + /** + * Stay on me, but recreate me (so I can use a different layout). + */ + void recreateMe(); + + /** + * Take action to send an emergency call. + */ + void takeEmergencyCallAction(); + + /** + * Report that the user had a failed attempt unlocking via the pattern. + */ + void reportFailedPatternAttempt(); + +} diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java new file mode 100644 index 000000000000..ab7c744c7363 --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -0,0 +1,552 @@ +/* + * Copyright (C) 2008 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 android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Configuration; +import android.database.ContentObserver; +import static android.os.BatteryManager.BATTERY_STATUS_CHARGING; +import static android.os.BatteryManager.BATTERY_STATUS_FULL; +import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; +import android.os.Handler; +import android.os.Message; +import android.provider.Settings; +import android.provider.Telephony; +import static android.provider.Telephony.Intents.EXTRA_PLMN; +import static android.provider.Telephony.Intents.EXTRA_SHOW_PLMN; +import static android.provider.Telephony.Intents.EXTRA_SHOW_SPN; +import static android.provider.Telephony.Intents.EXTRA_SPN; +import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION; +import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.TelephonyIntents; +import android.util.Log; +import com.android.internal.R; +import com.google.android.collect.Lists; + +import java.util.ArrayList; + +/** + * Watches for updates that may be interesting to the keyguard, and provides + * the up to date information as well as a registration for callbacks that care + * to be updated. + * + * Note: under time crunch, this has been extended to include some stuff that + * doesn't really belong here. see {@link #handleBatteryUpdate} where it shutdowns + * the device, and {@link #getFailedAttempts()}, {@link #reportFailedAttempt()} + * and {@link #clearFailedAttempts()}. Maybe we should rename this 'KeyguardContext'... + */ +public class KeyguardUpdateMonitor { + + static private final String TAG = "KeyguardUpdateMonitor"; + static private final boolean DEBUG = false; + + private static final int LOW_BATTERY_THRESHOLD = 20; + + private final Context mContext; + + private SimCard.State mSimState = SimCard.State.READY; + private boolean mInPortrait; + private boolean mKeyboardOpen; + + private boolean mDevicePluggedIn; + + private boolean mDeviceProvisioned; + + private int mBatteryLevel; + + private CharSequence mTelephonyPlmn; + private CharSequence mTelephonySpn; + + private int mFailedAttempts = 0; + + private Handler mHandler; + + private ArrayList mConfigurationChangeCallbacks + = Lists.newArrayList(); + private ArrayList mInfoCallbacks = Lists.newArrayList(); + private ArrayList mSimStateCallbacks = Lists.newArrayList(); + private ContentObserver mContentObserver; + + + // messages for the handler + private static final int MSG_CONFIGURATION_CHANGED = 300; + private static final int MSG_TIME_UPDATE = 301; + private static final int MSG_BATTERY_UPDATE = 302; + private static final int MSG_CARRIER_INFO_UPDATE = 303; + private static final int MSG_SIM_STATE_CHANGE = 304; + + + /** + * When we receive a {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, and + * then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange}, + * we need a single object to pass to the handler. This class helps decode + * the intent and provide a {@link SimCard.State} result. + */ + private static class SimArgs { + + public final SimCard.State simState; + + private SimArgs(Intent intent) { + if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) { + throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED"); + } + String stateExtra = intent.getStringExtra(SimCard.INTENT_KEY_SIM_STATE); + if (SimCard.INTENT_VALUE_SIM_ABSENT.equals(stateExtra)) { + this.simState = SimCard.State.ABSENT; + } else if (SimCard.INTENT_VALUE_SIM_READY.equals(stateExtra)) { + this.simState = SimCard.State.READY; + } else if (SimCard.INTENT_VALUE_SIM_LOCKED.equals(stateExtra)) { + final String lockedReason = intent + .getStringExtra(SimCard.INTENT_KEY_LOCKED_REASON); + if (SimCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { + this.simState = SimCard.State.PIN_REQUIRED; + } else if (SimCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { + this.simState = SimCard.State.PUK_REQUIRED; + } else { + this.simState = SimCard.State.UNKNOWN; + } + } else if (SimCard.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) { + this.simState = SimCard.State.NETWORK_LOCKED; + } else { + this.simState = SimCard.State.UNKNOWN; + } + } + + public String toString() { + return simState.toString(); + } + } + + public KeyguardUpdateMonitor(Context context) { + mContext = context; + + mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_CONFIGURATION_CHANGED: + handleConfigurationChange(); + break; + case MSG_TIME_UPDATE: + handleTimeUpdate(); + break; + case MSG_BATTERY_UPDATE: + handleBatteryUpdate(msg.arg1, msg.arg2); + break; + case MSG_CARRIER_INFO_UPDATE: + handleCarrierInfoUpdate(); + break; + case MSG_SIM_STATE_CHANGE: + handleSimStateChange((SimArgs) msg.obj); + break; + } + } + }; + + mDeviceProvisioned = Settings.System.getInt( + mContext.getContentResolver(), Settings.System.DEVICE_PROVISIONED, 0) != 0; + + // Since device can't be un-provisioned, we only need to register a content observer + // to update mDeviceProvisioned when we are... + if (!mDeviceProvisioned) { + mContentObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + mDeviceProvisioned = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.DEVICE_PROVISIONED, 0) != 0; + if (mDeviceProvisioned && mContentObserver != null) { + // We don't need the observer anymore... + mContext.getContentResolver().unregisterContentObserver(mContentObserver); + mContentObserver = null; + } + if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned); + } + }; + + mContext.getContentResolver().registerContentObserver( + Settings.System.getUriFor(Settings.System.DEVICE_PROVISIONED), + false, mContentObserver); + + // prevent a race condition between where we check the flag and where we register the + // observer by grabbing the value once again... + mDeviceProvisioned = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.DEVICE_PROVISIONED, 0) != 0; + } + + mInPortrait = queryInPortrait(); + mKeyboardOpen = queryKeyboardOpen(); + + // take a guess to start + mSimState = SimCard.State.READY; + mDevicePluggedIn = true; + mBatteryLevel = 100; + + mTelephonyPlmn = getDefaultPlmn(); + + // setup receiver + final IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + filter.addAction(Intent.ACTION_TIME_TICK); + filter.addAction(Intent.ACTION_TIME_CHANGED); + filter.addAction(Intent.ACTION_BATTERY_CHANGED); + filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); + filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + filter.addAction(SPN_STRINGS_UPDATED_ACTION); + context.registerReceiver(new BroadcastReceiver() { + + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (DEBUG) Log.d(TAG, "received broadcast " + action); + + if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_CONFIGURATION_CHANGED)); + } else if (Intent.ACTION_TIME_TICK.equals(action) + || Intent.ACTION_TIME_CHANGED.equals(action) + || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_TIME_UPDATE)); + } else if (SPN_STRINGS_UPDATED_ACTION.equals(action)) { + mTelephonyPlmn = getTelephonyPlmnFrom(intent); + mTelephonySpn = getTelephonySpnFrom(intent); + mHandler.sendMessage(mHandler.obtainMessage(MSG_CARRIER_INFO_UPDATE)); + } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { + final int pluggedInStatus = intent + .getIntExtra("status", BATTERY_STATUS_UNKNOWN); + int batteryLevel = intent.getIntExtra("level", 0); + final Message msg = mHandler.obtainMessage( + MSG_BATTERY_UPDATE, + pluggedInStatus, + batteryLevel); + mHandler.sendMessage(msg); + } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){ + mHandler.sendMessage(mHandler.obtainMessage( + MSG_SIM_STATE_CHANGE, + new SimArgs(intent))); + } + } + }, filter); + } + + /** + * Handle {@link #MSG_CONFIGURATION_CHANGED} + */ + private void handleConfigurationChange() { + if (DEBUG) Log.d(TAG, "handleConfigurationChange"); + + final boolean inPortrait = queryInPortrait(); + if (mInPortrait != inPortrait) { + mInPortrait = inPortrait; + for (int i = 0; i < mConfigurationChangeCallbacks.size(); i++) { + mConfigurationChangeCallbacks.get(i).onOrientationChange(inPortrait); + } + } + + final boolean keyboardOpen = queryKeyboardOpen(); + if (mKeyboardOpen != keyboardOpen) { + mKeyboardOpen = keyboardOpen; + for (int i = 0; i < mConfigurationChangeCallbacks.size(); i++) { + mConfigurationChangeCallbacks.get(i).onKeyboardChange(keyboardOpen); + } + } + } + + /** + * Handle {@link #MSG_TIME_UPDATE} + */ + private void handleTimeUpdate() { + if (DEBUG) Log.d(TAG, "handleTimeUpdate"); + for (int i = 0; i < mInfoCallbacks.size(); i++) { + mInfoCallbacks.get(i).onTimeChanged(); + } + } + + /** + * Handle {@link #MSG_BATTERY_UPDATE} + */ + private void handleBatteryUpdate(int pluggedInStatus, int batteryLevel) { + if (DEBUG) Log.d(TAG, "handleBatteryUpdate"); + final boolean pluggedIn = isPluggedIn(pluggedInStatus); + + if (isBatteryUpdateInteresting(pluggedIn, batteryLevel)) { + mBatteryLevel = batteryLevel; + mDevicePluggedIn = pluggedIn; + for (int i = 0; i < mInfoCallbacks.size(); i++) { + mInfoCallbacks.get(i).onRefreshBatteryInfo( + shouldShowBatteryInfo(), pluggedIn, batteryLevel); + } + } + + // shut down gracefully if our battery is critically low and we are not powered + if (batteryLevel == 0 && + pluggedInStatus != BATTERY_STATUS_CHARGING && + pluggedInStatus != BATTERY_STATUS_UNKNOWN) { + ShutdownThread.shutdownAfterDisablingRadio(mContext, false); + } + } + + /** + * Handle {@link #MSG_CARRIER_INFO_UPDATE} + */ + private void handleCarrierInfoUpdate() { + if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn + + ", spn = " + mTelephonySpn); + + for (int i = 0; i < mInfoCallbacks.size(); i++) { + mInfoCallbacks.get(i).onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn); + } + } + + /** + * Handle {@link #MSG_SIM_STATE_CHANGE} + */ + private void handleSimStateChange(SimArgs simArgs) { + final SimCard.State state = simArgs.simState; + + if (DEBUG) { + Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " " + + "state resolved to " + state.toString()); + } + + if (state != SimCard.State.UNKNOWN && state != mSimState) { + mSimState = state; + for (int i = 0; i < mSimStateCallbacks.size(); i++) { + mSimStateCallbacks.get(i).onSimStateChanged(state); + } + } + } + + /** + * @param status One of the statuses of {@link android.os.BatteryManager} + * @return Whether the status maps to a status for being plugged in. + */ + private boolean isPluggedIn(int status) { + return status == BATTERY_STATUS_CHARGING || status == BATTERY_STATUS_FULL; + } + + private boolean isBatteryUpdateInteresting(boolean pluggedIn, int batteryLevel) { + // change in plug is always interesting + if (mDevicePluggedIn != pluggedIn) { + return true; + } + + // change in battery level while plugged in + if (pluggedIn && mBatteryLevel != batteryLevel) { + return true; + } + + if (!pluggedIn) { + // not plugged in and going below threshold + if (batteryLevel < LOW_BATTERY_THRESHOLD + && mBatteryLevel >= LOW_BATTERY_THRESHOLD) { + return true; + } + // not plugged in and going above threshold (sounds impossible, but, meh...) + if (mBatteryLevel < LOW_BATTERY_THRESHOLD + && batteryLevel >= LOW_BATTERY_THRESHOLD) { + return true; + } + } + return false; + } + + /** + * What is the current orientation? + */ + boolean queryInPortrait() { + final Configuration configuration = mContext.getResources().getConfiguration(); + return configuration.orientation == Configuration.ORIENTATION_PORTRAIT; + } + + /** + * Is the keyboard currently open? + */ + boolean queryKeyboardOpen() { + final Configuration configuration = mContext.getResources().getConfiguration(); + + return configuration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO; + } + + /** + * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION} + * @return The string to use for the plmn, or null if it should not be shown. + */ + private CharSequence getTelephonyPlmnFrom(Intent intent) { + if (intent.getBooleanExtra(EXTRA_SHOW_PLMN, false)) { + final String plmn = intent.getStringExtra(EXTRA_PLMN); + if (plmn != null) { + return plmn; + } else { + return getDefaultPlmn(); + } + } + return null; + } + + /** + * @return The default plmn (no service) + */ + private CharSequence getDefaultPlmn() { + return mContext.getResources().getText( + R.string.lockscreen_carrier_default); + } + + /** + * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION} + * @return The string to use for the plmn, or null if it should not be shown. + */ + private CharSequence getTelephonySpnFrom(Intent intent) { + if (intent.getBooleanExtra(EXTRA_SHOW_SPN, false)) { + final String spn = intent.getStringExtra(EXTRA_SPN); + if (spn != null) { + return spn; + } + } + return null; + } + + /** + * Remove the given observer from being registered from any of the kinds + * of callbacks. + * @param observer The observer to remove (an instance of {@link ConfigurationChangeCallback}, + * {@link InfoCallback} or {@link SimStateCallback} + */ + public void removeCallback(Object observer) { + mConfigurationChangeCallbacks.remove(observer); + mInfoCallbacks.remove(observer); + mSimStateCallbacks.remove(observer); + } + + /** + * Callback for configuration changes. + */ + interface ConfigurationChangeCallback { + void onOrientationChange(boolean inPortrait); + + void onKeyboardChange(boolean isKeyboardOpen); + } + + /** + * Callback for general information releveant to lock screen. + */ + interface InfoCallback { + void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel); + void onTimeChanged(); + + /** + * @param plmn The operator name of the registered network. May be null if it shouldn't + * be displayed. + * @param spn The service provider name. May be null if it shouldn't be displayed. + */ + void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn); + } + + /** + * Callback to notify of sim state change. + */ + interface SimStateCallback { + void onSimStateChanged(SimCard.State simState); + } + + /** + * Register to receive notifications about configuration changes. + * @param callback The callback. + */ + public void registerConfigurationChangeCallback(ConfigurationChangeCallback callback) { + mConfigurationChangeCallbacks.add(callback); + } + + /** + * Register to receive notifications about general keyguard information + * (see {@link InfoCallback}. + * @param callback The callback. + */ + public void registerInfoCallback(InfoCallback callback) { + mInfoCallbacks.add(callback); + } + + /** + * Register to be notified of sim state changes. + * @param callback The callback. + */ + public void registerSimStateCallback(SimStateCallback callback) { + mSimStateCallbacks.add(callback); + } + + public SimCard.State getSimState() { + return mSimState; + } + + /** + * Report that the user succesfully entered the sim pin so we + * have the information earlier than waiting for the intent + * broadcast from the telephony code. + */ + public void reportSimPinUnlocked() { + mSimState = SimCard.State.READY; + } + + public boolean isInPortrait() { + return mInPortrait; + } + + public boolean isKeyboardOpen() { + return mKeyboardOpen; + } + + public boolean isDevicePluggedIn() { + return mDevicePluggedIn; + } + + public int getBatteryLevel() { + return mBatteryLevel; + } + + public boolean shouldShowBatteryInfo() { + return mDevicePluggedIn || mBatteryLevel < LOW_BATTERY_THRESHOLD; + } + + public CharSequence getTelephonyPlmn() { + return mTelephonyPlmn; + } + + public CharSequence getTelephonySpn() { + return mTelephonySpn; + } + + /** + * @return Whether the device is provisioned (whether they have gone through + * the setup wizard) + */ + public boolean isDeviceProvisioned() { + return mDeviceProvisioned; + } + + public int getFailedAttempts() { + return mFailedAttempts; + } + + public void clearFailedAttempts() { + mFailedAttempts = 0; + } + + public void reportFailedAttempt() { + mFailedAttempts++; + } +} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/com/android/internal/policy/impl/KeyguardViewBase.java new file mode 100644 index 000000000000..491300ea11e8 --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardViewBase.java @@ -0,0 +1,175 @@ +/* + * 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 android.content.Context; +import android.content.Intent; +import android.media.AudioManager; +import android.view.KeyEvent; +import android.view.View; +import android.widget.FrameLayout; + +/** + * Base class for keyguard views. {@link #reset} is where you should + * reset the state of your view. Use the {@link KeyguardViewCallback} via + * {@link #getCallback()} to send information back (such as poking the wake lock, + * or finishing the keyguard). + * + * Handles intercepting of media keys that still work when the keyguard is + * showing. + */ +public abstract class KeyguardViewBase extends FrameLayout { + + private KeyguardViewCallback mCallback; + private AudioManager mAudioManager; + + public KeyguardViewBase(Context context) { + super(context); + } + + // used to inject callback + void setCallback(KeyguardViewCallback callback) { + mCallback = callback; + } + + public KeyguardViewCallback getCallback() { + return mCallback; + } + + /** + * Called when you need to reset the state of your view. + */ + abstract public void reset(); + + /** + * Called when the screen turned off. + */ + abstract public void onScreenTurnedOff(); + + /** + * Called when the screen turned on. + */ + abstract public void onScreenTurnedOn(); + + /** + * Called when a key has woken the device to give us a chance to adjust our + * state according the the key. We are responsible for waking the device + * (by poking the wake lock) once we are ready. + * + * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}. + * Be sure not to take any action that takes a long time; any significant + * action should be posted to a handler. + * + * @param keyCode The wake key, which may be relevant for configuring the + * keyguard. + */ + abstract public void wakeWhenReadyTq(int keyCode); + + /** + * Verify that the user can get past the keyguard securely. This is called, + * for example, when the phone disables the keyguard but then wants to launch + * something else that requires secure access. + * + * The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)} + */ + abstract public void verifyUnlock(); + + /** + * Called before this view is being removed. + */ + abstract public void cleanUp(); + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (shouldEventKeepScreenOnWhileKeyguardShowing(event)) { + mCallback.pokeWakelock(); + } + + if (interceptMediaKey(event)) { + return true; + } + return super.dispatchKeyEvent(event); + } + + private boolean shouldEventKeepScreenOnWhileKeyguardShowing(KeyEvent event) { + if (event.getAction() != KeyEvent.ACTION_DOWN) { + return false; + } + switch (event.getKeyCode()) { + case KeyEvent.KEYCODE_DPAD_DOWN: + case KeyEvent.KEYCODE_DPAD_LEFT: + case KeyEvent.KEYCODE_DPAD_RIGHT: + case KeyEvent.KEYCODE_DPAD_UP: + return false; + default: + return true; + } + } + + /** + * Allows the media keys to work when the keygaurd is showing. + * The media keys should be of no interest to the actualy keygaurd view(s), + * so intercepting them here should not be of any harm. + * @param event The key event + * @return whether the event was consumed as a media key. + */ + private boolean interceptMediaKey(KeyEvent event) { + final int keyCode = event.getKeyCode(); + if (event.getAction() == KeyEvent.ACTION_DOWN) { + switch (keyCode) { + case KeyEvent.KEYCODE_HEADSETHOOK: { + Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, event); + getContext().sendOrderedBroadcast(intent, null); + return true; + } + + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: { + synchronized (this) { + if (mAudioManager == null) { + mAudioManager = (AudioManager) getContext().getSystemService( + Context.AUDIO_SERVICE); + } + } + // Volume buttons should only function for music. + if (mAudioManager.isMusicActive()) { + mAudioManager.adjustStreamVolume( + AudioManager.STREAM_MUSIC, + keyCode == KeyEvent.KEYCODE_VOLUME_UP + ? AudioManager.ADJUST_RAISE + : AudioManager.ADJUST_LOWER, + 0); + } + // Don't execute default volume behavior + return true; + } + } + } else if (event.getAction() == KeyEvent.ACTION_UP) { + switch (keyCode) { + case KeyEvent.KEYCODE_HEADSETHOOK: { + Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, event); + getContext().sendOrderedBroadcast(intent, null); + return true; + } + } + } + return false; + } + +} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewCallback.java b/policy/com/android/internal/policy/impl/KeyguardViewCallback.java new file mode 100644 index 000000000000..b376d657cc80 --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardViewCallback.java @@ -0,0 +1,49 @@ +/* + * 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; + +/** + * The callback used by the keyguard view to tell the {@link KeyguardViewMediator} + * various things. + */ +public interface KeyguardViewCallback { + + /** + * Request the wakelock to be poked for the default amount of time. + */ + void pokeWakelock(); + + /** + * Request the wakelock to be poked for a specific amount of time. + * @param millis The amount of time in millis. + */ + void pokeWakelock(int millis); + + /** + * Report that the keyguard is done. + * @param authenticated Whether the user securely got past the keyguard. + * the only reason for this to be false is if the keyguard was instructed + * to appear temporarily to verify the user is supposed to get past the + * keyguard, and the user fails to do so. + */ + void keyguardDone(boolean authenticated); + + /** + * Report that the keyguard is done drawing. + */ + void keyguardDoneDrawing(); +} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java new file mode 100644 index 000000000000..a48f4f9e3c58 --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -0,0 +1,200 @@ +/* + * 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.content.Context; +import android.graphics.PixelFormat; +import android.graphics.Canvas; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewManager; +import android.view.WindowManager; +import android.widget.FrameLayout; + +/** + * Manages creating, showing, hiding and resetting the keyguard. Calls back + * via {@link com.android.internal.policy.impl.KeyguardViewCallback} to poke + * the wake lock and report that the keyguard is done, which is in turn, + * reported to this class by the current {@link KeyguardViewBase}. + */ +public class KeyguardViewManager { + private final static boolean DEBUG = false; + private static String TAG = "KeyguardViewManager"; + + private final Context mContext; + private final ViewManager mViewManager; + private final KeyguardViewCallback mCallback; + private final KeyguardViewProperties mKeyguardViewProperties; + + private final KeyguardUpdateMonitor mUpdateMonitor; + + private FrameLayout mKeyguardHost; + private KeyguardViewBase mKeyguardView; + + private boolean mScreenOn = false; + + /** + * @param context Used to create views. + * @param viewManager Keyguard will be attached to this. + * @param callback Used to notify of changes. + */ + public KeyguardViewManager(Context context, ViewManager viewManager, + KeyguardViewCallback callback, KeyguardViewProperties keyguardViewProperties, KeyguardUpdateMonitor updateMonitor) { + mContext = context; + mViewManager = viewManager; + mCallback = callback; + mKeyguardViewProperties = keyguardViewProperties; + + mUpdateMonitor = updateMonitor; + } + + /** + * Helper class to host the keyguard view. + */ + private static class KeyguardViewHost extends FrameLayout { + private final KeyguardViewCallback mCallback; + + private KeyguardViewHost(Context context, KeyguardViewCallback callback) { + super(context); + mCallback = callback; + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + mCallback.keyguardDoneDrawing(); + } + } + + /** + * Show the keyguard. Will handle creating and attaching to the view manager + * lazily. + */ + public synchronized void show() { + if (DEBUG) Log.d(TAG, "show()"); + + if (mKeyguardHost == null) { + if (DEBUG) Log.d(TAG, "keyguard host is null, creating it..."); + + mKeyguardHost = new KeyguardViewHost(mContext, mCallback); + + final int stretch = ViewGroup.LayoutParams.FILL_PARENT; + int flags = WindowManager.LayoutParams.FLAG_DITHER + | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD, + flags, PixelFormat.OPAQUE); + lp.setTitle("Keyguard"); + + mViewManager.addView(mKeyguardHost, lp); + } + + if (mKeyguardView == null) { + if (DEBUG) Log.d(TAG, "keyguard view is null, creating it..."); + mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor); + mKeyguardView.setId(R.id.lock_screen); + mKeyguardView.setCallback(mCallback); + + final ViewGroup.LayoutParams lp = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.FILL_PARENT); + + mKeyguardHost.addView(mKeyguardView, lp); + + if (mScreenOn) { + mKeyguardView.onScreenTurnedOn(); + } + } + + mKeyguardHost.setVisibility(View.VISIBLE); + mKeyguardView.requestFocus(); + } + + /** + * Reset the state of the view. + */ + public synchronized void reset() { + if (DEBUG) Log.d(TAG, "reset()"); + if (mKeyguardView != null) { + mKeyguardView.reset(); + } + } + + public synchronized void onScreenTurnedOff() { + if (DEBUG) Log.d(TAG, "onScreenTurnedOff()"); + mScreenOn = false; + if (mKeyguardView != null) { + mKeyguardView.onScreenTurnedOff(); + } + } + + public synchronized void onScreenTurnedOn() { + if (DEBUG) Log.d(TAG, "onScreenTurnedOn()"); + mScreenOn = true; + if (mKeyguardView != null) { + mKeyguardView.onScreenTurnedOn(); + } + } + + public synchronized void verifyUnlock() { + if (DEBUG) Log.d(TAG, "verifyUnlock()"); + show(); + mKeyguardView.verifyUnlock(); + } + + /** + * A key has woken the device. We use this to potentially adjust the state + * of the lock screen based on the key. + * + * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}. + * Be sure not to take any action that takes a long time; any significant + * action should be posted to a handler. + * + * @param keyCode The wake key. + */ + public void wakeWhenReadyTq(int keyCode) { + if (DEBUG) Log.d(TAG, "wakeWhenReady(" + keyCode + ")"); + if (mKeyguardView != null) { + mKeyguardView.wakeWhenReadyTq(keyCode); + } + } + + /** + * Hides the keyguard view + */ + public synchronized void hide() { + if (DEBUG) Log.d(TAG, "hide()"); + if (mKeyguardHost != null) { + mKeyguardHost.setVisibility(View.INVISIBLE); + if (mKeyguardView != null) { + mKeyguardHost.removeView(mKeyguardView); + mKeyguardView.cleanUp(); + mKeyguardView = null; + } + } + } + + /** + * @return Whether the keyguard is showing + */ + public synchronized boolean isShowing() { + return (mKeyguardHost != null && mKeyguardHost.getVisibility() == View.VISIBLE); + } +} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java new file mode 100644 index 000000000000..ac816b0bd60e --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -0,0 +1,902 @@ +/* + * 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 android.app.AlarmManager; +import android.app.PendingIntent; +import android.app.StatusBarManager; +import static android.app.StatusBarManager.DISABLE_NONE; +import static android.app.StatusBarManager.DISABLE_EXPAND; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.os.LocalPowerManager; +import android.os.Message; +import android.os.PowerManager; +import android.os.SystemClock; +import android.util.Config; +import android.util.Log; +import android.util.EventLog; +import android.view.KeyEvent; +import android.view.WindowManagerImpl; +import android.view.WindowManagerPolicy; +import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.widget.LockPatternUtils; + +/** + * Mediates requests related to the keyguard. This includes queries about the + * state of the keyguard, power management events that effect whether the keyguard + * should be shown or reset, callbacks to the phone window manager to notify + * it of when the keyguard is showing, and events from the keyguard view itself + * stating that the keyguard was succesfully unlocked. + * + * Note that the keyguard view is shown when the screen is off (as appropriate) + * so that once the screen comes on, it will be ready immediately. + * + * Example queries about the keyguard: + * - is {movement, key} one that should wake the keygaurd? + * - is the keyguard showing? + * - are input events restricted due to the state of the keyguard? + * + * Callbacks to the phone window manager: + * - the keyguard is showing + * + * Example external events that translate to keyguard view changes: + * - screen turned off -> reset the keyguard, and show it so it will be ready + * next time the screen turns on + * - keyboard is slid open -> if the keyguard is not secure, hide it + * + * Events from the keyguard view: + * - user succesfully unlocked keyguard -> hide keyguard view, and no longer + * restrict input events. + * + * Note: in addition to normal power managment events that effect the state of + * whether the keyguard should be showing, external apps and services may request + * that the keyguard be disabled via {@link #setKeyguardEnabled(boolean)}. When + * false, this will override all other conditions for turning on the keyguard. + * + * Threading and synchronization: + * This class is created by the initialization routine of the {@link WindowManagerPolicy}, + * and runs on its thread. The keyguard UI is created from that thread in the + * constructor of this class. The apis may be called from other threads, including the + * {@link com.android.server.KeyInputQueue}'s and {@link android.view.WindowManager}'s. + * Therefore, methods on this class are synchronized, and any action that is pointed + * directly to the keyguard UI is posted to a {@link Handler} to ensure it is taken on the UI + * thread of the keyguard. + */ +public class KeyguardViewMediator implements KeyguardViewCallback, + KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.SimStateCallback { + private final static boolean DEBUG = false && Config.LOGD; + private final static boolean DBG_WAKE = DEBUG || true; + + private final static String TAG = "KeyguardViewMediator"; + + private static final String DELAYED_KEYGUARD_ACTION = "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD"; + + // used for handler messages + private static final int TIMEOUT = 1; + private static final int SHOW = 2; + private static final int HIDE = 3; + private static final int RESET = 4; + private static final int VERIFY_UNLOCK = 5; + private static final int NOTIFY_SCREEN_OFF = 6; + private static final int NOTIFY_SCREEN_ON = 7; + private static final int WAKE_WHEN_READY = 8; + private static final int KEYGUARD_DONE = 9; + private static final int KEYGUARD_DONE_DRAWING = 10; + + /** + * The default amount of time we stay awake (used for all key input) + */ + protected static final int AWAKE_INTERVAL_DEFAULT_MS = 5000; + + + /** + * The default amount of time we stay awake (used for all key input) when + * the keyboard is open + */ + protected static final int AWAKE_INTERVAL_DEFAULT_KEYBOARD_OPEN_MS = 10000; + + /** + * How long to wait after the screen turns off due to timeout before + * 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 = 0; + + /** + * How long we'll wait for the {@link KeyguardViewCallback#keyguardDoneDrawing()} + * callback before unblocking a call to {@link #setKeyguardEnabled(boolean)} + * that is reenabling the keyguard. + */ + private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000; + + private Context mContext; + private AlarmManager mAlarmManager; + + /** Low level access to the power manager for enableUserActivity. Having this + * requires that we run in the system process. */ + LocalPowerManager mRealPowerManager; + + /** High level access to the power manager for WakeLocks */ + private PowerManager mPM; + + /** + * Used to keep the device awake while the keyguard is showing, i.e for + * calls to {@link #pokeWakelock()} + */ + private PowerManager.WakeLock mWakeLock; + + /** + * Does not turn on screen, held while a call to {@link KeyguardViewManager#wakeWhenReadyTq(int)} + * is called to make sure the device doesn't sleep before it has a chance to poke + * the wake lock. + * @see #wakeWhenReadyLocked(int) + */ + private PowerManager.WakeLock mWakeAndHandOff; + + /** + * Used to disable / reenable status bar expansion. + */ + private StatusBarManager mStatusBarManager; + + private KeyguardViewManager mKeyguardViewManager; + + // these are protected by synchronized (this) + + /** + * External apps (like the phone app) can tell us to disable the keygaurd. + */ + private boolean mExternallyEnabled = true; + + /** + * Remember if an external call to {@link #setKeyguardEnabled} with value + * false caused us to hide the keyguard, so that we need to reshow it once + * the keygaurd is reenabled with another call with value true. + */ + private boolean mNeedToReshowWhenReenabled = false; + + // cached value of whether we are showing (need to know this to quickly + // answer whether the input should be restricted) + private boolean mShowing = false; + + /** + * Helps remember whether the screen has turned on since the last time + * it turned off due to timeout. see {@link #onScreenTurnedOff(int)} + */ + private int mDelayedShowingSequence; + + private int mWakelockSequence; + + private PhoneWindowManager mCallback; + + /** + * If the user has disabled the keyguard, then requests to exit, this is + * how we'll ultimately let them know whether it was successful. We use this + * var being non-null as an indicator that there is an in progress request. + */ + private WindowManagerPolicy.OnKeyguardExitResult mExitSecureCallback; + + // the properties of the keyguard + private KeyguardViewProperties mKeyguardViewProperties; + + private KeyguardUpdateMonitor mUpdateMonitor; + + private boolean mKeyboardOpen = false; + + /** + * {@link #setKeyguardEnabled} waits on this condition when it reenables + * the keyguard. + */ + private boolean mWaitingUntilKeyguardVisible = false; + + public KeyguardViewMediator(Context context, PhoneWindowManager callback, + LocalPowerManager powerManager) { + mContext = context; + + mRealPowerManager = powerManager; + mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + mWakeLock = mPM.newWakeLock( + PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, + "keyguard"); + mWakeLock.setReferenceCounted(false); + + mWakeAndHandOff = mPM.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, + "keyguardWakeAndHandOff"); + mWakeAndHandOff.setReferenceCounted(false); + + IntentFilter filter = new IntentFilter(); + filter.addAction(DELAYED_KEYGUARD_ACTION); + filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + context.registerReceiver(mBroadCastReceiver, filter); + mAlarmManager = (AlarmManager) context + .getSystemService(Context.ALARM_SERVICE); + mCallback = callback; + + mUpdateMonitor = new KeyguardUpdateMonitor(context); + + mUpdateMonitor.registerConfigurationChangeCallback(this); + mUpdateMonitor.registerSimStateCallback(this); + + mKeyguardViewProperties = + new LockPatternKeyguardViewProperties( + new LockPatternUtils(mContext.getContentResolver()), + mUpdateMonitor); + + mKeyguardViewManager = new KeyguardViewManager( + context, WindowManagerImpl.getDefault(), this, + mKeyguardViewProperties, mUpdateMonitor); + + } + + /** + * Let us know that the system is ready after startup. + */ + public void onSystemReady() { + synchronized (this) { + if (DEBUG) Log.d(TAG, "onSystemReady"); + doKeyguard(); + } + } + + /** + * Called to let us know the screen was turned off. + * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER} or + * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}. + */ + public void onScreenTurnedOff(int why) { + synchronized (this) { + if (DEBUG) Log.d(TAG, "onScreenTurnedOff(" + why + ")"); + + if (mExitSecureCallback != null) { + if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled"); + mExitSecureCallback.onKeyguardExitResult(false); + mExitSecureCallback = null; + if (!mExternallyEnabled) { + hideLocked(); + } + } else if (mShowing) { + notifyScreenOffLocked(); + resetStateLocked(); + } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT) { + // if the screen turned off because of timeout, set an alarm + // 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); + } else { + doKeyguard(); + } + } + } + + /** + * Let's us know the screen was turned on. + */ + public void onScreenTurnedOn() { + synchronized (this) { + mDelayedShowingSequence++; + if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence); + notifyScreenOnLocked(); + } + } + + /** + * Same semantics as {@link WindowManagerPolicy#enableKeyguard}; provide + * a way for external stuff to override normal keyguard behavior. For instance + * the phone app disables the keyguard when it receives incoming calls. + */ + public void setKeyguardEnabled(boolean enabled) { + synchronized (this) { + if (DEBUG) Log.d(TAG, "setKeyguardEnabled(" + enabled + ")"); + + + mExternallyEnabled = enabled; + + if (!enabled && mShowing) { + if (mExitSecureCallback != null) { + if (DEBUG) Log.d(TAG, "in process of verifyUnlock request, ignoring"); + // we're in the process of handling a request to verify the user + // can get past the keyguard. ignore extraneous requests to disable / reenable + return; + } + + // hiding keyguard that is showing, remember to reshow later + if (DEBUG) Log.d(TAG, "remembering to reshow, hiding keyguard, " + + "disabling status bar expansion"); + mNeedToReshowWhenReenabled = true; + setStatusBarExpandable(false); + hideLocked(); + } else if (enabled && mNeedToReshowWhenReenabled) { + // reenabled after previously hidden, reshow + if (DEBUG) Log.d(TAG, "previously hidden, reshowing, reenabling " + + "status bar expansion"); + mNeedToReshowWhenReenabled = false; + setStatusBarExpandable(true); + + if (mExitSecureCallback != null) { + if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting"); + mExitSecureCallback.onKeyguardExitResult(false); + mExitSecureCallback = null; + resetStateLocked(); + } else { + showLocked(); + + // block until we know the keygaurd is done drawing (and post a message + // to unblock us after a timeout so we don't risk blocking too long + // and causing an ANR). + mWaitingUntilKeyguardVisible = true; + mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_DRAWING, KEYGUARD_DONE_DRAWING_TIMEOUT_MS); + if (DEBUG) Log.d(TAG, "waiting until mWaitingUntilKeyguardVisible is false"); + while (mWaitingUntilKeyguardVisible) { + try { + wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + if (DEBUG) Log.d(TAG, "done waiting for mWaitingUntilKeyguardVisible"); + } + } + } + } + + /** + * @see android.app.KeyguardManager#exitKeyguardSecurely + */ + public void verifyUnlock(WindowManagerPolicy.OnKeyguardExitResult callback) { + synchronized (this) { + if (DEBUG) Log.d(TAG, "verifyUnlock"); + if (!mUpdateMonitor.isDeviceProvisioned()) { + // don't allow this api when the device isn't provisioned + if (DEBUG) Log.d(TAG, "ignoring because device isn't provisioned"); + callback.onKeyguardExitResult(false); + } else if (mExternallyEnabled) { + // this only applies when the user has externally disabled the + // keyguard. this is unexpected and means the user is not + // using the api properly. + Log.w(TAG, "verifyUnlock called when not externally disabled"); + callback.onKeyguardExitResult(false); + } else if (mExitSecureCallback != null) { + // already in progress with someone else + callback.onKeyguardExitResult(false); + } else { + mExitSecureCallback = callback; + verifyUnlockLocked(); + } + } + } + + + private void setStatusBarExpandable(boolean isExpandable) { + if (mStatusBarManager == null) { + mStatusBarManager = + (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); + } + mStatusBarManager.disable(isExpandable ? DISABLE_NONE : DISABLE_EXPAND); + } + + /** + * Is the keyguard currently showing? + */ + public boolean isShowing() { + return mShowing; + } + + /** + * Given the state of the keyguard, is the input restricted? + * Input is restricted when the keyguard is showing, or when the keyguard + * was suppressed by an app that disabled the keyguard or we haven't been provisioned yet. + */ + public boolean isInputRestricted() { + return mShowing || mNeedToReshowWhenReenabled || !mUpdateMonitor.isDeviceProvisioned(); + } + + + /** + * Enable the keyguard if the settings are appropriate. + */ + private void doKeyguard() { + synchronized (this) { + // if another app is disabling us, don't show + if (!mExternallyEnabled) { + if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled"); + return; + } + + // if the keyguard is already showing, don't bother + if (mKeyguardViewManager.isShowing()) { + if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing"); + return; + } + + // if the setup wizard hasn't run yet, don't show + final boolean provisioned = mUpdateMonitor.isDeviceProvisioned(); + final SimCard.State state = mUpdateMonitor.getSimState(); + final boolean lockedOrMissing = state.isPinLocked() || (state == SimCard.State.ABSENT); + if (!lockedOrMissing && !provisioned) { + if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned" + + " and the sim is not locked or missing"); + return; + } + + if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen"); + showLocked(); + } + } + + /** + * Send message to keyguard telling it to reset its state. + * @see #handleReset() + */ + private void resetStateLocked() { + if (DEBUG) Log.d(TAG, "resetStateLocked"); + Message msg = mHandler.obtainMessage(RESET); + mHandler.sendMessage(msg); + } + + /** + * Send message to keyguard telling it to verify unlock + * @see #handleVerifyUnlock() + */ + private void verifyUnlockLocked() { + if (DEBUG) Log.d(TAG, "verifyUnlockLocked"); + mHandler.sendEmptyMessage(VERIFY_UNLOCK); + } + + + /** + * Send a message to keyguard telling it the screen just turned on. + * @see #onScreenTurnedOff(int) + * @see #handleNotifyScreenOff + */ + private void notifyScreenOffLocked() { + if (DEBUG) Log.d(TAG, "notifyScreenOffLocked"); + mHandler.sendEmptyMessage(NOTIFY_SCREEN_OFF); + } + + /** + * Send a message to keyguard telling it the screen just turned on. + * @see #onScreenTurnedOn() + * @see #handleNotifyScreenOn + */ + private void notifyScreenOnLocked() { + if (DEBUG) Log.d(TAG, "notifyScreenOnLocked"); + mHandler.sendEmptyMessage(NOTIFY_SCREEN_ON); + } + + /** + * Send message to keyguard telling it about a wake key so it can adjust + * its state accordingly and then poke the wake lock when it is ready. + * @param keyCode The wake key. + * @see #handleWakeWhenReady + * @see #onWakeKeyWhenKeyguardShowingTq(int) + */ + private void wakeWhenReadyLocked(int keyCode) { + if (DBG_WAKE) Log.d(TAG, "wakeWhenReadyLocked(" + keyCode + ")"); + + /** + * acquire the handoff lock that will keep the cpu running. this will + * be released once the keyguard has set itself up and poked the other wakelock + * in {@link #handleWakeWhenReady(int)} + */ + mWakeAndHandOff.acquire(); + + Message msg = mHandler.obtainMessage(WAKE_WHEN_READY, keyCode, 0); + mHandler.sendMessage(msg); + } + + /** + * Send message to keyguard telling it to show itself + * @see #handleShow() + */ + private void showLocked() { + if (DEBUG) Log.d(TAG, "showLocked"); + Message msg = mHandler.obtainMessage(SHOW); + mHandler.sendMessage(msg); + } + + /** + * Send message to keyguard telling it to hide itself + * @see #handleHide() + */ + private void hideLocked() { + if (DEBUG) Log.d(TAG, "hideLocked"); + Message msg = mHandler.obtainMessage(HIDE); + mHandler.sendMessage(msg); + } + + /** + * {@link KeyguardUpdateMonitor} callbacks. + */ + + /** {@inheritDoc} */ + public void onOrientationChange(boolean inPortrait) { + + } + + /** {@inheritDoc} */ + public void onKeyboardChange(boolean isKeyboardOpen) { + mKeyboardOpen = isKeyboardOpen; + + if (mKeyboardOpen && !mKeyguardViewProperties.isSecure() + && mKeyguardViewManager.isShowing()) { + if (DEBUG) Log.d(TAG, "bypassing keyguard on sliding open of keyboard with non-secure keyguard"); + keyguardDone(true); + } + } + + /** {@inheritDoc} */ + public void onSimStateChanged(SimCard.State simState) { + if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState); + + switch (simState) { + case ABSENT: + // only force lock screen in case of missing sim if user hasn't + // gone through setup wizard + if (!mUpdateMonitor.isDeviceProvisioned()) { + if (!isShowing()) { + if (DEBUG) Log.d(TAG, "INTENT_VALUE_SIM_ABSENT and keygaurd isn't showing, we need " + + "to show the keyguard since the device isn't provisioned yet."); + doKeyguard(); + } else { + resetStateLocked(); + } + } + break; + case PIN_REQUIRED: + case PUK_REQUIRED: + if (!isShowing()) { + if (DEBUG) Log.d(TAG, "INTENT_VALUE_SIM_LOCKED and keygaurd isn't showing, we need " + + "to show the keyguard so the user can enter their sim pin"); + doKeyguard(); + } else { + resetStateLocked(); + } + + break; + case READY: + if (isShowing()) { + resetStateLocked(); + } + break; + } + } + + private BroadcastReceiver mBroadCastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(DELAYED_KEYGUARD_ACTION)) { + + int sequence = intent.getIntExtra("seq", 0); + + if (false) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = " + + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence); + + if (mDelayedShowingSequence == sequence) { + doKeyguard(); + } + } + } + }; + + + /** + * When a key is received when the screen is off and the keyguard is showing, + * we need to decide whether to actually turn on the screen, and if so, tell + * the keyguard to prepare itself and poke the wake lock when it is ready. + * + * The 'Tq' suffix is per the documentation in {@link WindowManagerPolicy}. + * Be sure not to take any action that takes a long time; any significant + * action should be posted to a handler. + * + * @param keyCode The keycode of the key that woke the device + * @return Whether we poked the wake lock (and turned the screen on) + */ + public boolean onWakeKeyWhenKeyguardShowingTq(int keyCode) { + if (DEBUG) Log.d(TAG, "onWakeKeyWhenKeyguardShowing(" + keyCode + ")"); + + if (isWakeKeyWhenKeyguardShowing(keyCode)) { + // give the keyguard view manager a chance to adjust the state of the + // keyguard based on the key that woke the device before poking + // the wake lock + wakeWhenReadyLocked(keyCode); + return true; + } else { + return false; + } + } + + private boolean isWakeKeyWhenKeyguardShowing(int keyCode) { + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_CAMERA: + return false; + } + return true; + } + + /** + * Callbacks from {@link KeyguardViewManager}. + */ + + /** {@inheritDoc} */ + public void pokeWakelock() { + pokeWakelock(mKeyboardOpen ? + AWAKE_INTERVAL_DEFAULT_KEYBOARD_OPEN_MS : AWAKE_INTERVAL_DEFAULT_MS); + } + + /** {@inheritDoc} */ + public void pokeWakelock(int holdMs) { + synchronized (this) { + if (DBG_WAKE) Log.d(TAG, "pokeWakelock(" + holdMs + ")"); + mWakeLock.acquire(); + mHandler.removeMessages(TIMEOUT); + mWakelockSequence++; + Message msg = mHandler.obtainMessage(TIMEOUT, mWakelockSequence, 0); + mHandler.sendMessageDelayed(msg, holdMs); + } + } + + /** + * {@inheritDoc} + * + * @see #handleKeyguardDone + */ + public void keyguardDone(boolean authenticated) { + synchronized (this) { + EventLog.writeEvent(70000, 2); + if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")"); + Message msg = mHandler.obtainMessage(KEYGUARD_DONE); + mHandler.sendMessage(msg); + + if (authenticated) { + mUpdateMonitor.clearFailedAttempts(); + } + + if (mExitSecureCallback != null) { + mExitSecureCallback.onKeyguardExitResult(authenticated); + mExitSecureCallback = null; + + if (authenticated) { + // after succesfully exiting securely, no need to reshow + // the keyguard when they've released the lock + mExternallyEnabled = true; + mNeedToReshowWhenReenabled = false; + setStatusBarExpandable(true); + } + } + } + } + + /** + * {@inheritDoc} + * + * @see #handleKeyguardDoneDrawing + */ + public void keyguardDoneDrawing() { + mHandler.sendEmptyMessage(KEYGUARD_DONE_DRAWING); + } + + /** + * This handler will be associated with the policy thread, which will also + * be the UI thread of the keyguard. Since the apis of the policy, and therefore + * this class, can be called by other threads, any action that directly + * interacts with the keyguard ui should be posted to this handler, rather + * than called directly. + */ + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) + { + switch (msg.what) + { + case TIMEOUT: + handleTimeout(msg.arg1); + return ; + case SHOW: + handleShow(); + return ; + case HIDE: + handleHide(); + return ; + case RESET: + handleReset(); + return ; + case VERIFY_UNLOCK: + handleVerifyUnlock(); + return; + case NOTIFY_SCREEN_OFF: + handleNotifyScreenOff(); + return; + case NOTIFY_SCREEN_ON: + handleNotifyScreenOn(); + return; + case WAKE_WHEN_READY: + handleWakeWhenReady(msg.arg1); + return; + case KEYGUARD_DONE: + handleKeyguardDone(); + return; + case KEYGUARD_DONE_DRAWING: + handleKeyguardDoneDrawing(); + } + } + }; + + /** + * @see #keyguardDone + * @see #KEYGUARD_DONE + */ + private void handleKeyguardDone() { + if (DEBUG) Log.d(TAG, "handleKeyguardDone"); + handleHide(); + mPM.userActivity(SystemClock.uptimeMillis(), true); + mWakeLock.release(); + } + + /** + * @see #keyguardDoneDrawing + * @see #KEYGUARD_DONE_DRAWING + */ + private void handleKeyguardDoneDrawing() { + synchronized(this) { + if (false) Log.d(TAG, "handleKeyguardDoneDrawing"); + if (mWaitingUntilKeyguardVisible) { + if (DEBUG) Log.d(TAG, "handleKeyguardDoneDrawing: notifying mWaitingUntilKeyguardVisible"); + mWaitingUntilKeyguardVisible = false; + notifyAll(); + + // there will usually be two of these sent, one as a timeout, and one + // as a result of the callback, so remove any remaining messages from + // the queue + mHandler.removeMessages(KEYGUARD_DONE_DRAWING); + } + } + } + + /** + * Handles the message sent by {@link #pokeWakelock} + * @param seq used to determine if anything has changed since the message + * was sent. + * @see #TIMEOUT + */ + private void handleTimeout(int seq) { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleTimeout"); + if (seq == mWakelockSequence) { + mWakeLock.release(); + } + } + } + + /** + * Handle message sent by {@link #showLocked}. + * @see #SHOW + */ + private void handleShow() { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleShow"); + // while we're showing, we control the wake state, so ask the power + // manager not to honor request for userActivity. + mRealPowerManager.enableUserActivity(false); + + mCallback.onKeyguardShow(); + mKeyguardViewManager.show(); + mShowing = true; + } + } + + /** + * Handle message sent by {@link #hideLocked()} + * @see #HIDE + */ + private void handleHide() { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleHide"); + // When we go away, tell the poewr manager to honor requests from userActivity. + mRealPowerManager.enableUserActivity(true); + + mKeyguardViewManager.hide(); + mShowing = false; + } + } + + /** + * Handle message sent by {@link #wakeWhenReadyLocked(int)} + * @param keyCode The key that woke the device. + * @see #WAKE_WHEN_READY + */ + private void handleWakeWhenReady(int keyCode) { + synchronized (KeyguardViewMediator.this) { + if (DBG_WAKE) Log.d(TAG, "handleWakeWhenReady(" + keyCode + ")"); + + // this should result in a call to 'poke wakelock' which will set a timeout + // on releasing the wakelock + mKeyguardViewManager.wakeWhenReadyTq(keyCode); + + /** + * Now that the keyguard is ready and has poked the wake lock, we can + * release the handoff wakelock + */ + mWakeAndHandOff.release(); + + if (!mWakeLock.isHeld()) { + Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock"); + } + } + } + + /** + * Handle message sent by {@link #resetStateLocked()} + * @see #RESET + */ + private void handleReset() { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleReset"); + mKeyguardViewManager.reset(); + } + } + + /** + * Handle message sent by {@link #verifyUnlock} + * @see #RESET + */ + private void handleVerifyUnlock() { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleVerifyUnlock"); + mKeyguardViewManager.verifyUnlock(); + } + } + + /** + * Handle message sent by {@link #notifyScreenOffLocked()} + * @see #NOTIFY_SCREEN_OFF + */ + private void handleNotifyScreenOff() { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleNotifyScreenOff"); + mKeyguardViewManager.onScreenTurnedOff(); + } + } + + /** + * Handle message sent by {@link #notifyScreenOnLocked()} + * @see #NOTIFY_SCREEN_ON + */ + private void handleNotifyScreenOn() { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleNotifyScreenOn"); + mKeyguardViewManager.onScreenTurnedOn(); + } + } +} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewProperties.java b/policy/com/android/internal/policy/impl/KeyguardViewProperties.java new file mode 100644 index 000000000000..a449653a2647 --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardViewProperties.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008 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 android.content.Context; + +/** + * Defines operations necessary for showing a keyguard, including how to create + * it, and various properties that are useful to be able to query independant + * of whether the keyguard instance is around or not. + */ +public interface KeyguardViewProperties { + + /** + * Create a keyguard view. + * @param context the context to use when creating the view. + * @param updateMonitor configuration may be based on this. + * @return the view. + */ + KeyguardViewBase createKeyguardView(Context context, KeyguardUpdateMonitor updateMonitor); + + /** + * Would the keyguard be secure right now? + * @return Whether the keyguard is currently secure, meaning it will block + * the user from getting past it until the user enters some sort of PIN. + */ + boolean isSecure(); + +} diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java new file mode 100644 index 000000000000..66a4c4e7813a --- /dev/null +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -0,0 +1,514 @@ +/* + * 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 android.app.AlertDialog; +import android.content.Context; +import android.content.Intent; +import android.os.SystemProperties; +import com.android.internal.telephony.SimCard; +import android.text.TextUtils; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.view.WindowManager; +import com.android.internal.R; +import com.android.internal.widget.LockPatternUtils; + +/** + * The host view for all of the screens of the pattern unlock screen. There are + * two {@link Mode}s of operation, lock and unlock. This will show the appropriate + * screen, and listen for callbacks via {@link com.android.internal.policy.impl.KeyguardScreenCallback + * from the current screen. + * + * This view, in turn, communicates back to {@link com.android.internal.policy.impl.KeyguardViewManager} + * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate. + */ +public class LockPatternKeyguardView extends KeyguardViewBase { + + // intent action for launching emergency dialer activity. + static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL"; + + private static final boolean DEBUG = false; + private static final String TAG = "LockPatternKeyguardView"; + + private final KeyguardUpdateMonitor mUpdateMonitor; + private View mLockScreen; + private View mUnlockScreen; + + private boolean mScreenOn = false; + + /** + * The current {@link KeyguardScreen} will use this to communicate back to us. + */ + KeyguardScreenCallback mKeyguardScreenCallback; + + + private boolean mRequiresSim; + + + /** + * Either a lock screen (an informational keyguard screen), or an unlock + * screen (a means for unlocking the device) is shown at any given time. + */ + enum Mode { + LockScreen, + UnlockScreen + } + + /** + * The different types screens available for {@link Mode#UnlockScreen}. + * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode() + */ + enum UnlockMode { + + /** + * Unlock by drawing a pattern. + */ + Pattern, + + /** + * Unlock by entering a sim pin. + */ + SimPin, + + /** + * Unlock by entering an account's login and password. + */ + Account + } + + /** + * The current mode. + */ + private Mode mMode = Mode.LockScreen; + + /** + * Keeps track of what mode the current unlock screen is + */ + private UnlockMode mUnlockScreenMode; + + /** + * If true, it means we are in the process of verifying that the user + * can get past the lock screen per {@link #verifyUnlock()} + */ + private boolean mIsVerifyUnlockOnly = false; + + + /** + * Used to lookup the state of the lock pattern + */ + private final LockPatternUtils mLockPatternUtils; + + + /** + * @return Whether we are stuck on the lock screen because the sim is + * missing. + */ + private boolean stuckOnLockScreenBecauseSimMissing() { + return mRequiresSim + && (!mUpdateMonitor.isDeviceProvisioned()) + && (mUpdateMonitor.getSimState() == SimCard.State.ABSENT); + } + + /** + * @param context Used to inflate, and create views. + * @param updateMonitor Knows the state of the world, and passed along to each + * screen so they can use the knowledge, and also register for callbacks + * on dynamic information. + * @param lockPatternUtils Used to look up state of lock pattern. + */ + public LockPatternKeyguardView( + Context context, + KeyguardUpdateMonitor updateMonitor, + LockPatternUtils lockPatternUtils) { + super(context); + + mRequiresSim = + TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); + + mUpdateMonitor = updateMonitor; + mLockPatternUtils = lockPatternUtils; + + mMode = getInitialMode(); + mKeyguardScreenCallback = new KeyguardScreenCallback() { + + public void goToLockScreen() { + if (mIsVerifyUnlockOnly) { + // navigating away from unlock screen during verify mode means + // we are done and the user failed to authenticate. + mIsVerifyUnlockOnly = false; + getCallback().keyguardDone(false); + } else { + updateScreen(Mode.LockScreen); + } + } + + public void goToUnlockScreen() { + final SimCard.State simState = mUpdateMonitor.getSimState(); + if (stuckOnLockScreenBecauseSimMissing() + || (simState == SimCard.State.PUK_REQUIRED)){ + // stuck on lock screen when sim missing or puk'd + return; + } + if (!isSecure()) { + getCallback().keyguardDone(true); + } else { + updateScreen(Mode.UnlockScreen); + } + } + + public boolean isSecure() { + return LockPatternKeyguardView.this.isSecure(); + } + + public boolean isVerifyUnlockOnly() { + return mIsVerifyUnlockOnly; + } + + public void recreateMe() { + recreateScreens(); + } + + public void takeEmergencyCallAction() { + Intent intent = new Intent(ACTION_EMERGENCY_DIAL); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + getContext().startActivity(intent); + } + + public void pokeWakelock() { + getCallback().pokeWakelock(); + } + + public void pokeWakelock(int millis) { + getCallback().pokeWakelock(millis); + } + + public void keyguardDone(boolean authenticated) { + getCallback().keyguardDone(authenticated); + } + + public void keyguardDoneDrawing() { + // irrelevant to keyguard screen, they shouldn't be calling this + } + + public void reportFailedPatternAttempt() { + mUpdateMonitor.reportFailedAttempt(); + final int failedAttempts = mUpdateMonitor.getFailedAttempts(); + if (failedAttempts == + (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { + showAlmostAtAccountLoginDialog(); + } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { + mLockPatternUtils.setPermanentlyLocked(true); + updateScreen(mMode); + } else if ((failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) + == 0) { + showTimeoutDialog(); + } + } + }; + + /** + * We'll get key events the current screen doesn't use. see + * {@link KeyguardViewBase#onKeyDown(int, android.view.KeyEvent)} + */ + setFocusableInTouchMode(true); + setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); + + // create both the lock and unlock screen so they are quickly available + // when the screen turns on + mLockScreen = createLockScreen(); + addView(mLockScreen); + final UnlockMode unlockMode = getUnlockMode(); + mUnlockScreen = createUnlockScreenFor(unlockMode); + mUnlockScreenMode = unlockMode; + addView(mUnlockScreen); + updateScreen(mMode); + } + + @Override + public void reset() { + mIsVerifyUnlockOnly = false; + updateScreen(getInitialMode()); + } + + @Override + public void onScreenTurnedOff() { + mScreenOn = false; + if (mMode == Mode.LockScreen) { + ((KeyguardScreen) mLockScreen).onPause(); + } else { + ((KeyguardScreen) mUnlockScreen).onPause(); + } + } + + @Override + public void onScreenTurnedOn() { + mScreenOn = true; + if (mMode == Mode.LockScreen) { + ((KeyguardScreen) mLockScreen).onResume(); + } else { + ((KeyguardScreen) mUnlockScreen).onResume(); + } + } + + + private void recreateScreens() { + if (mLockScreen.getVisibility() == View.VISIBLE) { + ((KeyguardScreen) mLockScreen).onPause(); + } + ((KeyguardScreen) mLockScreen).cleanUp(); + removeViewInLayout(mLockScreen); + + mLockScreen = createLockScreen(); + mLockScreen.setVisibility(View.INVISIBLE); + addView(mLockScreen); + + if (mUnlockScreen.getVisibility() == View.VISIBLE) { + ((KeyguardScreen) mUnlockScreen).onPause(); + } + ((KeyguardScreen) mUnlockScreen).cleanUp(); + removeViewInLayout(mUnlockScreen); + + final UnlockMode unlockMode = getUnlockMode(); + mUnlockScreen = createUnlockScreenFor(unlockMode); + mUnlockScreen.setVisibility(View.INVISIBLE); + mUnlockScreenMode = unlockMode; + addView(mUnlockScreen); + + updateScreen(mMode); + } + + + @Override + public void wakeWhenReadyTq(int keyCode) { + if (DEBUG) Log.d(TAG, "onWakeKey"); + if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen) + && (mUpdateMonitor.getSimState() != SimCard.State.PUK_REQUIRED)) { + if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); + updateScreen(Mode.UnlockScreen); + getCallback().pokeWakelock(); + } else { + if (DEBUG) Log.d(TAG, "poking wake lock immediately"); + getCallback().pokeWakelock(); + } + } + + @Override + public void verifyUnlock() { + if (!isSecure()) { + // non-secure keyguard screens are successfull by default + getCallback().keyguardDone(true); + } else if (mUnlockScreenMode != UnlockMode.Pattern) { + // can only verify unlock when in pattern mode + getCallback().keyguardDone(false); + } else { + // otherwise, go to the unlock screen, see if they can verify it + mIsVerifyUnlockOnly = true; + updateScreen(Mode.UnlockScreen); + } + } + + @Override + public void cleanUp() { + ((KeyguardScreen) mLockScreen).onPause(); + ((KeyguardScreen) mLockScreen).cleanUp(); + ((KeyguardScreen) mUnlockScreen).onPause(); + ((KeyguardScreen) mUnlockScreen).cleanUp(); + } + + private boolean isSecure() { + UnlockMode unlockMode = getUnlockMode(); + if (unlockMode == UnlockMode.Pattern) { + return mLockPatternUtils.isLockPatternEnabled(); + } else if (unlockMode == UnlockMode.SimPin) { + return mUpdateMonitor.getSimState() == SimCard.State.PIN_REQUIRED + || mUpdateMonitor.getSimState() == SimCard.State.PUK_REQUIRED; + } else if (unlockMode == UnlockMode.Account) { + return true; + } else { + throw new IllegalStateException("unknown unlock mode " + unlockMode); + } + } + + private void updateScreen(final Mode mode) { + + mMode = mode; + + final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen; + final View visibleScreen = (mode == Mode.LockScreen) + ? mLockScreen : getUnlockScreenForCurrentUnlockMode(); + + + if (mScreenOn) { + if (goneScreen.getVisibility() == View.VISIBLE) { + ((KeyguardScreen) goneScreen).onPause(); + } + if (visibleScreen.getVisibility() != View.VISIBLE) { + ((KeyguardScreen) visibleScreen).onResume(); + } + } + + goneScreen.setVisibility(View.GONE); + visibleScreen.setVisibility(View.VISIBLE); + + if (!visibleScreen.requestFocus()) { + throw new IllegalStateException("keyguard screen must be able to take " + + "focus when shown " + visibleScreen.getClass().getCanonicalName()); + } + } + + View createLockScreen() { + return new LockScreen( + mContext, + mLockPatternUtils, + mUpdateMonitor, + mKeyguardScreenCallback); + } + + View createUnlockScreenFor(UnlockMode unlockMode) { + if (unlockMode == UnlockMode.Pattern) { + return new UnlockScreen( + mContext, + mLockPatternUtils, + mUpdateMonitor, + mKeyguardScreenCallback, + mUpdateMonitor.getFailedAttempts()); + } else if (unlockMode == UnlockMode.SimPin) { + return new SimUnlockScreen( + mContext, + mUpdateMonitor, + mKeyguardScreenCallback); + } else if (unlockMode == UnlockMode.Account) { + try { + return new AccountUnlockScreen( + mContext, + mKeyguardScreenCallback, + mLockPatternUtils); + } catch (IllegalStateException e) { + Log.i(TAG, "Couldn't instantiate AccountUnlockScreen" + + " (IAccountsService isn't available)"); + // TODO: Need a more general way to provide a + // platform-specific fallback UI here. + // For now, if we can't display the account login + // unlock UI, just bring back the regular "Pattern" unlock mode. + + // (We do this by simply returning a regular UnlockScreen + // here. This means that the user will still see the + // regular pattern unlock UI, regardless of the value of + // mUnlockScreenMode or whether or not we're in the + // "permanently locked" state.) + return createUnlockScreenFor(UnlockMode.Pattern); + } + } else { + throw new IllegalArgumentException("unknown unlock mode " + unlockMode); + } + } + + private View getUnlockScreenForCurrentUnlockMode() { + final UnlockMode unlockMode = getUnlockMode(); + + // if a screen exists for the correct mode, we're done + if (unlockMode == mUnlockScreenMode) { + return mUnlockScreen; + } + + // remember the mode + mUnlockScreenMode = unlockMode; + + // unlock mode has changed and we have an existing old unlock screen + // to clean up + if (mScreenOn && (mUnlockScreen.getVisibility() == View.VISIBLE)) { + ((KeyguardScreen) mUnlockScreen).onPause(); + } + ((KeyguardScreen) mUnlockScreen).cleanUp(); + removeViewInLayout(mUnlockScreen); + + // create the new one + mUnlockScreen = createUnlockScreenFor(unlockMode); + mUnlockScreen.setVisibility(View.INVISIBLE); + addView(mUnlockScreen); + return mUnlockScreen; + } + + /** + * Given the current state of things, what should be the initial mode of + * the lock screen (lock or unlock). + */ + private Mode getInitialMode() { + final SimCard.State simState = mUpdateMonitor.getSimState(); + if (stuckOnLockScreenBecauseSimMissing() || (simState == SimCard.State.PUK_REQUIRED)) { + return Mode.LockScreen; + } else if (mUpdateMonitor.isKeyboardOpen() && isSecure()) { + return Mode.UnlockScreen; + } else { + return Mode.LockScreen; + } + } + + /** + * Given the current state of things, what should the unlock screen be? + */ + private UnlockMode getUnlockMode() { + final SimCard.State simState = mUpdateMonitor.getSimState(); + if (simState == SimCard.State.PIN_REQUIRED || simState == SimCard.State.PUK_REQUIRED) { + return UnlockMode.SimPin; + } else { + return mLockPatternUtils.isPermanentlyLocked() ? + UnlockMode.Account: + UnlockMode.Pattern; + } + } + + private void showTimeoutDialog() { + int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; + String message = mContext.getString( + R.string.lockscreen_too_many_failed_attempts_dialog_message, + mUpdateMonitor.getFailedAttempts(), + timeoutInSeconds); + final AlertDialog dialog = new AlertDialog.Builder(mContext) + .setTitle(null) + .setMessage(message) + .setNeutralButton(R.string.ok, null) + .create(); + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + dialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + dialog.show(); + } + + private void showAlmostAtAccountLoginDialog() { + int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; + String message = mContext.getString( + R.string.lockscreen_failed_attempts_almost_glogin, + LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, + LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, + timeoutInSeconds); + final AlertDialog dialog = new AlertDialog.Builder(mContext) + .setTitle(null) + .setMessage(message) + .setNeutralButton(R.string.ok, null) + .create(); + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + dialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + dialog.show(); + } +} diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java new file mode 100644 index 000000000000..697c0382884f --- /dev/null +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008 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.widget.LockPatternUtils; + +import android.content.Context; +import com.android.internal.telephony.SimCard; + +/** + * Knows how to create a lock pattern keyguard view, and answer questions about + * it (even if it hasn't been created, per the interface specs). + */ +public class LockPatternKeyguardViewProperties implements KeyguardViewProperties { + + private final LockPatternUtils mLockPatternUtils; + private final KeyguardUpdateMonitor mUpdateMonitor; + + /** + * @param lockPatternUtils Used to know whether the pattern enabled, and passed + * onto the keygaurd view when it is created. + * @param updateMonitor Used to know whether the sim pin is enabled, and passed + * onto the keyguard view when it is created. + */ + public LockPatternKeyguardViewProperties(LockPatternUtils lockPatternUtils, + KeyguardUpdateMonitor updateMonitor) { + mLockPatternUtils = lockPatternUtils; + mUpdateMonitor = updateMonitor; + } + + public KeyguardViewBase createKeyguardView(Context context, + KeyguardUpdateMonitor updateMonitor) { + return new LockPatternKeyguardView(context, updateMonitor, mLockPatternUtils); + } + + public boolean isSecure() { + return isLockPatternSecure() || isSimPinSecure(); + } + + private boolean isLockPatternSecure() { + return mLockPatternUtils.isLockPatternEnabled() && mLockPatternUtils + .savedPatternExists(); + } + + private boolean isSimPinSecure() { + final SimCard.State simState = mUpdateMonitor.getSimState(); + return (simState == SimCard.State.PIN_REQUIRED || simState == SimCard.State.PUK_REQUIRED + || simState == SimCard.State.ABSENT); + } + +} diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java new file mode 100644 index 000000000000..c717cc37ae15 --- /dev/null +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2008 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 com.android.internal.widget.LockPatternUtils; + +import android.content.Context; +import android.pim.DateFormat; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import com.android.internal.telephony.SimCard; + +import java.util.Date; + +/** + * The screen within {@link LockPatternKeyguardView} that shows general + * 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, KeyguardUpdateMonitor.ConfigurationChangeCallback { + private final LockPatternUtils mLockPatternUtils; + private final KeyguardUpdateMonitor mUpdateMonitor; + private final KeyguardScreenCallback mCallback; + + private TextView mHeaderSimOk1; + private TextView mHeaderSimOk2; + + private TextView mHeaderSimBad1; + private TextView mHeaderSimBad2; + + private TextView mTime; + private TextView mDate; + + private ViewGroup mBatteryInfoGroup; + private ImageView mBatteryInfoIcon; + private TextView mBatteryInfoText; + private View mBatteryInfoSpacer; + + private ViewGroup mNextAlarmGroup; + private TextView mAlarmText; + private View mAlarmSpacer; + + private ViewGroup mScreenLockedMessageGroup; + + private TextView mLockInstructions; + + private Button mEmergencyCallButton; + + /** + * false means sim is missing or PUK'd + */ + private boolean mSimOk = true; + + // 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 View[] mOnlyVisibleWhenSimOk; + + private View[] mOnlyVisibleWhenSimNotOk; + + /** + * @param context Used to setup the view. + * @param lockPatternUtils Used to know the state of the lock pattern settings. + * @param updateMonitor Used to register for updates on various keyguard related + * state, and query the initial state at setup. + * @param callback Used to communicate back to the host keyguard view. + */ + LockScreen(Context context, LockPatternUtils lockPatternUtils, + KeyguardUpdateMonitor updateMonitor, + KeyguardScreenCallback callback) { + super(context); + mLockPatternUtils = lockPatternUtils; + mUpdateMonitor = updateMonitor; + mCallback = callback; + + final LayoutInflater inflater = LayoutInflater.from(context); + inflater.inflate(R.layout.keyguard_screen_lock, this, true); + + mSimOk = isSimOk(updateMonitor.getSimState()); + mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo(); + mPluggedIn = updateMonitor.isDevicePluggedIn(); + mBatteryLevel = updateMonitor.getBatteryLevel(); + + mHeaderSimOk1 = (TextView) findViewById(R.id.headerSimOk1); + mHeaderSimOk2 = (TextView) findViewById(R.id.headerSimOk2); + + mHeaderSimBad1 = (TextView) findViewById(R.id.headerSimBad1); + mHeaderSimBad2 = (TextView) findViewById(R.id.headerSimBad2); + + mTime = (TextView) findViewById(R.id.time); + mDate = (TextView) findViewById(R.id.date); + + mBatteryInfoGroup = (ViewGroup) findViewById(R.id.batteryInfo); + mBatteryInfoIcon = (ImageView) findViewById(R.id.batteryInfoIcon); + mBatteryInfoText = (TextView) findViewById(R.id.batteryInfoText); + mBatteryInfoSpacer = findViewById(R.id.batteryInfoSpacer); + + mNextAlarmGroup = (ViewGroup) findViewById(R.id.nextAlarmInfo); + mAlarmText = (TextView) findViewById(R.id.nextAlarmText); + mAlarmSpacer = findViewById(R.id.nextAlarmSpacer); + + mScreenLockedMessageGroup = (ViewGroup) findViewById(R.id.screenLockedInfo); + + mLockInstructions = (TextView) findViewById(R.id.lockInstructions); + + mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); + + mEmergencyCallButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + mCallback.takeEmergencyCallAction(); + } + }); + + mOnlyVisibleWhenSimOk = new View[] { + mHeaderSimOk1, + mHeaderSimOk2, + mBatteryInfoGroup, + mBatteryInfoSpacer, + mNextAlarmGroup, + mAlarmSpacer, + mScreenLockedMessageGroup, + mLockInstructions + }; + + mOnlyVisibleWhenSimNotOk = new View[] { + mHeaderSimBad1, + mHeaderSimBad2, + mEmergencyCallButton + }; + + setFocusable(true); + setFocusableInTouchMode(true); + setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); + + refreshBatteryDisplay(); + refreshAlarmDisplay(); + refreshTimeAndDateDisplay(); + refreshUnlockIntructions(); + refreshViewsWRTSimOk(); + refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn()); + + updateMonitor.registerInfoCallback(this); + updateMonitor.registerSimStateCallback(this); + updateMonitor.registerConfigurationChangeCallback(this); + } + + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_MENU) { + mCallback.goToUnlockScreen(); + } + return false; + } + + private void refreshViewsWRTSimOk() { + if (mSimOk) { + for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) { + final View view = mOnlyVisibleWhenSimOk[i]; + if (view == null) throw new RuntimeException("index " + i + " null"); + view.setVisibility(View.VISIBLE); + } + for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) { + final View view = mOnlyVisibleWhenSimNotOk[i]; + view.setVisibility(View.GONE); + } + refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn()); + refreshAlarmDisplay(); + refreshBatteryDisplay(); + } else { + for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) { + final View view = mOnlyVisibleWhenSimOk[i]; + view.setVisibility(View.GONE); + } + for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) { + final View view = mOnlyVisibleWhenSimNotOk[i]; + view.setVisibility(View.VISIBLE); + } + refreshSimBadInfo(); + } + } + + private void refreshSimBadInfo() { + final SimCard.State simState = mUpdateMonitor.getSimState(); + if (simState == SimCard.State.PUK_REQUIRED) { + mHeaderSimBad1.setText(R.string.lockscreen_sim_puk_locked_message); + mHeaderSimBad2.setText(R.string.lockscreen_sim_puk_locked_instructions); + } else if (simState == SimCard.State.ABSENT) { + mHeaderSimBad1.setText(R.string.lockscreen_missing_sim_message); + mHeaderSimBad2.setVisibility(View.GONE); + //mHeaderSimBad2.setText(R.string.lockscreen_missing_sim_instructions); + } else { + mHeaderSimBad1.setVisibility(View.GONE); + mHeaderSimBad2.setVisibility(View.GONE); + } + } + + private void refreshUnlockIntructions() { + if (mLockPatternUtils.isLockPatternEnabled() + || mUpdateMonitor.getSimState() == SimCard.State.PIN_REQUIRED) { + mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_enabled); + } else { + mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_disabled); + } + } + + private void refreshAlarmDisplay() { + String nextAlarmText = mLockPatternUtils.getNextAlarm(); + if (nextAlarmText != null && mSimOk) { + setAlarmInfoVisible(true); + mAlarmText.setText(nextAlarmText); + } else { + setAlarmInfoVisible(false); + } + } + + private void setAlarmInfoVisible(boolean visible) { + final int visibilityFlag = visible ? View.VISIBLE : View.GONE; + mNextAlarmGroup.setVisibility(visibilityFlag); + mAlarmSpacer.setVisibility(visibilityFlag); + } + + + public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, + int batteryLevel) { + mShowingBatteryInfo = showBatteryInfo; + mPluggedIn = pluggedIn; + mBatteryLevel = batteryLevel; + + refreshBatteryDisplay(); + } + + private void refreshBatteryDisplay() { + if (!mShowingBatteryInfo || !mSimOk) { + mBatteryInfoGroup.setVisibility(View.GONE); + mBatteryInfoSpacer.setVisibility(View.GONE); + return; + } + mBatteryInfoGroup.setVisibility(View.VISIBLE); + mBatteryInfoSpacer.setVisibility(View.VISIBLE); + + if (mPluggedIn) { + mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_charging); + mBatteryInfoText.setText( + getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel)); + } else { + mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_low_battery); + mBatteryInfoText.setText(R.string.lockscreen_low_battery); + } + } + + public void onTimeChanged() { + refreshTimeAndDateDisplay(); + } + + private void refreshTimeAndDateDisplay() { + Date now = new Date(); + mTime.setText(DateFormat.getTimeFormat(getContext()).format(now)); + mDate.setText(DateFormat.getDateFormat(getContext()).format(now)); + } + + public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + refreshSimOkHeaders(plmn, spn); + } + + private void refreshSimOkHeaders(CharSequence plmn, CharSequence spn) { + final SimCard.State simState = mUpdateMonitor.getSimState(); + if (simState == SimCard.State.READY) { + if (plmn != null) { + mHeaderSimOk1.setVisibility(View.VISIBLE); + mHeaderSimOk1.setText(plmn); + } else { + mHeaderSimOk2.setVisibility(View.GONE); + } + + if (spn != null) { + mHeaderSimOk2.setVisibility(View.VISIBLE); + mHeaderSimOk2.setText(spn); + } else { + mHeaderSimOk2.setVisibility(View.GONE); + } + } else if (simState == SimCard.State.PIN_REQUIRED) { + mHeaderSimOk1.setVisibility(View.VISIBLE); + mHeaderSimOk1.setText(R.string.lockscreen_sim_locked_message); + mHeaderSimOk2.setVisibility(View.GONE); + } else if (simState == SimCard.State.ABSENT) { + mHeaderSimOk1.setVisibility(View.VISIBLE); + mHeaderSimOk1.setText(R.string.lockscreen_missing_sim_message_short); + mHeaderSimOk2.setVisibility(View.GONE); + } else if (simState == SimCard.State.NETWORK_LOCKED) { + mHeaderSimOk1.setVisibility(View.VISIBLE); + mHeaderSimOk1.setText(R.string.lockscreen_network_locked_message); + mHeaderSimOk2.setVisibility(View.GONE); + } + } + + public void onSimStateChanged(SimCard.State simState) { + mSimOk = isSimOk(simState); + refreshViewsWRTSimOk(); + } + + /** + * @return Whether the sim state is ok, meaning we don't need to show + * a special screen with the emergency call button and keep them from + * doing anything else. + */ + private boolean isSimOk(SimCard.State simState) { + boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned() + && simState == SimCard.State.ABSENT); + return !(missingAndNotProvisioned || simState == SimCard.State.PUK_REQUIRED); + } + + public void onOrientationChange(boolean inPortrait) { + mCallback.pokeWakelock(); + } + + public void onKeyboardChange(boolean isKeyboardOpen) { + if (isKeyboardOpen) { + mCallback.goToUnlockScreen(); + } + } + + + /** {@inheritDoc} */ + public void onPause() { + + } + + /** {@inheritDoc} */ + public void onResume() { + + } + + /** {@inheritDoc} */ + public void cleanUp() { + mUpdateMonitor.removeCallback(this); + } +} diff --git a/policy/com/android/internal/policy/impl/PhoneLayoutInflater.java b/policy/com/android/internal/policy/impl/PhoneLayoutInflater.java new file mode 100644 index 000000000000..6bf4beb0ea57 --- /dev/null +++ b/policy/com/android/internal/policy/impl/PhoneLayoutInflater.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2006 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 java.util.Map; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.LayoutInflater; + +public class PhoneLayoutInflater extends LayoutInflater { + private static final String[] sClassPrefixList = { + "android.widget.", + "android.webkit." + }; + + /** + * Instead of instantiating directly, you should retrieve an instance + * through {@link Context#getSystemService} + * + * @param context The Context in which in which to find resources and other + * application-specific things. + * + * @see Context#getSystemService + */ + public PhoneLayoutInflater(Context context) { + super(context); + } + + protected PhoneLayoutInflater(LayoutInflater original, Context newContext) { + super(original, newContext); + } + + /** Override onCreateView to instantiate names that correspond to the + widgets known to the Widget factory. If we don't find a match, + call through to our super class. + */ + @Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException { + for (String prefix : sClassPrefixList) { + try { + View view = createView(name, prefix, attrs); + if (view != null) { + return view; + } + } catch (ClassNotFoundException e) { + // In this case we want to let the base class take a crack + // at it. + } + } + + return super.onCreateView(name, attrs); + } + + public LayoutInflater cloneInContext(Context newContext) { + return new PhoneLayoutInflater(this, newContext); + } +} + diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java new file mode 100644 index 000000000000..2d5bd31aedd2 --- /dev/null +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -0,0 +1,2572 @@ +/* + * 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.view.menu.ContextMenuBuilder; +import com.android.internal.view.menu.MenuBuilder; +import com.android.internal.view.menu.MenuDialogHelper; +import com.android.internal.view.menu.MenuView; +import com.android.internal.view.menu.SubMenuBuilder; + +import android.app.KeyguardManager; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.media.AudioManager; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.SystemClock; +import android.provider.CallLog.Calls; +import android.util.AndroidRuntimeException; +import android.util.Config; +import android.util.EventLog; +import android.util.Log; +import android.util.SparseArray; +import android.view.Gravity; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import static android.view.ViewGroup.LayoutParams.FILL_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import android.view.ViewManager; +import android.view.VolumePanel; +import android.view.Window; +import android.view.WindowManager; +import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +/** + * Android-specific Window. + *

+ * todo: need to pull the generic functionality out into a base class + * in android.widget. + */ +public class PhoneWindow extends Window implements MenuBuilder.Callback { + private final static String TAG = "PhoneWindow"; + + private final static boolean SWEEP_OPEN_MENU = false; + + /** + * 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); + + // This is the top-level view of the window, containing the window decor. + private DecorView mDecor; + + // This is the view in which the window contents are placed. It is either + // mDecor itself, or a child of mDecor where the contents go. + private ViewGroup mContentParent; + + private boolean mIsFloating; + + private LayoutInflater mLayoutInflater; + + private TextView mTitleView; + + private DrawableFeatureState[] mDrawables; + + private PanelFeatureState[] mPanels; + + /** + * The panel that is prepared or opened (the most recent one if there are + * multiple panels). Shortcuts will go to this panel. It gets set in + * {@link #preparePanel} and cleared in {@link #closePanel}. + */ + private PanelFeatureState mPreparedPanel; + + /** + * The keycode that is currently held down (as a modifier) for chording. If + * this is 0, there is no key held down. + */ + private int mPanelChordingKey; + + private ImageView mLeftIconView; + + private ImageView mRightIconView; + + private ProgressBar mCircularProgressBar; + + private ProgressBar mHorizontalProgressBar; + + private int mBackgroundResource = 0; + + private Drawable mBackgroundDrawable; + + private int mFrameResource = 0; + + private int mTextColor = 0; + + private CharSequence mTitle = null; + + private int mTitleColor = 0; + + private ContextMenuBuilder mContextMenu; + private MenuDialogHelper mContextMenuHelper; + + private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; + private long mVolumeKeyUpTime; + + private KeyguardManager mKeyguardManager = null; + + private boolean mSearchKeyDownReceived; + + private final Handler mKeycodeCallTimeoutHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (!mKeycodeCallTimeoutActive) return; + mKeycodeCallTimeoutActive = false; + // launch the VoiceDialer + Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + getContext().startActivity(intent); + } catch (ActivityNotFoundException e) { + startCallActivity(); + } + } + }; + private boolean mKeycodeCallTimeoutActive = false; + + // Ideally the call and camera buttons would share a common base class, and each implement their + // own onShortPress() and onLongPress() methods, but to reduce the chance of regressions I'm + // keeping them separate for now. + private final Handler mKeycodeCameraTimeoutHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (!mKeycodeCameraTimeoutActive) return; + mKeycodeCameraTimeoutActive = false; + // Broadcast an intent that the Camera button was longpressed + Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj); + getContext().sendOrderedBroadcast(intent, null); + } + }; + private boolean mKeycodeCameraTimeoutActive = false; + + public PhoneWindow(Context context) { + super(context); + mLayoutInflater = LayoutInflater.from(context); + } + + @Override + public final void setContainer(Window container) { + super.setContainer(container); + } + + @Override + public boolean requestFeature(int featureId) { + if (mContentParent != null) { + throw new AndroidRuntimeException("requestFeature() must be called before adding content"); + } + final int features = getFeatures(); + if ((features != DEFAULT_FEATURES) && (featureId == FEATURE_CUSTOM_TITLE)) { + + /* Another feature is enabled and the user is trying to enable the custom title feature */ + throw new AndroidRuntimeException("You cannot combine custom titles with other title features"); + } + if (((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) && (featureId != FEATURE_CUSTOM_TITLE)) { + + /* 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"); + } + /* FEATURE_OPENGL disabled for 1.0 + if (featureId == FEATURE_OPENGL) { + getAttributes().memoryType = WindowManager.LayoutParams.MEMORY_TYPE_GPU; + } + */ + return super.requestFeature(featureId); + } + + @Override + public void setContentView(int layoutResID) { + if (mContentParent == null) { + installDecor(); + } else { + mContentParent.removeAllViews(); + } + mLayoutInflater.inflate(layoutResID, mContentParent); + final Callback cb = getCallback(); + if (cb != null) { + cb.onContentChanged(); + } + } + + @Override + public void setContentView(View view) { + setContentView(view, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT)); + } + + @Override + public void setContentView(View view, ViewGroup.LayoutParams params) { + if (mContentParent == null) { + installDecor(); + } else { + mContentParent.removeAllViews(); + } + mContentParent.addView(view, params); + final Callback cb = getCallback(); + if (cb != null) { + cb.onContentChanged(); + } + } + + @Override + public void addContentView(View view, ViewGroup.LayoutParams params) { + if (mContentParent == null) { + installDecor(); + } + mContentParent.addView(view, params); + final Callback cb = getCallback(); + if (cb != null) { + cb.onContentChanged(); + } + } + + @Override + public View getCurrentFocus() { + return mDecor != null ? mDecor.findFocus() : null; + } + + @Override + public boolean isFloating() { + return mIsFloating; + } + + /** + * Return a LayoutInflater instance that can be used to inflate XML view layout + * resources for use in this Window. + * + * @return LayoutInflater The shared LayoutInflater. + */ + @Override + public LayoutInflater getLayoutInflater() { + return mLayoutInflater; + } + + @Override + public void setTitle(CharSequence title) { + if (mTitleView != null) { + mTitleView.setText(title); + } + mTitle = title; + } + + @Override + public void setTitleColor(int textColor) { + if (mTitleView != null) { + mTitleView.setTextColor(textColor); + } + mTitleColor = textColor; + } + + /** + * Prepares the panel to either be opened or chorded. This creates the Menu + * instance for the panel and populates it via the Activity callbacks. + * + * @param st The panel state to prepare. + * @param event The event that triggered the preparing of the panel. + * @return Whether the panel was prepared. If the panel should not be shown, + * returns false. + */ + public final boolean preparePanel(PanelFeatureState st, KeyEvent event) { + // 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); + } + + final Callback cb = getCallback(); + + if (cb != null) { + st.createdPanelView = cb.onCreatePanelView(st.featureId); + } + + 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; + } + // Call callback, and return if it doesn't want to display menu + if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) { + // Ditch the menu created above + st.menu = null; + + return false; + } + } + + // Callback and return if the callback does not want to show the menu + if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) { + return false; + } + + // Set the proper keymap + KeyCharacterMap kmap = KeyCharacterMap.load(event != null ? event.getDeviceId() : 0); + st.qwertyMode = kmap.getKeyboardType() != KeyCharacterMap.NUMERIC; + st.menu.setQwertyMode(st.qwertyMode); + } + + // Set other state + st.isPrepared = true; + st.isHandled = false; + mPreparedPanel = st; + + return true; + } + + @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; + + 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); + + // Re-open the same menu + reopenMenu(false); + + // Restore state + menuBuilder.restoreHierarchyState(state); + + } 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. + + // Allow the callback to create a new panel view + st.createdPanelView = null; + + // Causes the decor view to be recreated + st.refreshDecorView = true; + + ((MenuBuilder) st.menu).clearMenuViews(); + } + + @Override + public final void openPanel(int featureId, KeyEvent event) { + openPanel(getPanelState(featureId, true), event); + } + + private void openPanel(PanelFeatureState st, KeyEvent event) { + // System.out.println("Open panel: isOpen=" + st.isOpen); + + // Already open, return + if (st.isOpen) { + return; + } + + Callback cb = getCallback(); + if ((cb != null) && (!cb.onMenuOpened(st.featureId, st.menu))) { + // Callback doesn't want the menu to open, reset any state + closePanel(st, true); + return; + } + + final WindowManager wm = getWindowManager(); + if (wm == null) { + return; + } + + // Prepare panel (should have been done before, but just in case) + if (!preparePanel(st, event)) { + return; + } + + if (st.decorView == null || st.refreshDecorView) { + if (st.decorView == null) { + // Initialize the panel decor, this will populate st.decorView + if (!initializePanelDecor(st) || (st.decorView == null)) + return; + } else if (st.refreshDecorView && (st.decorView.getChildCount() > 0)) { + // Decor needs refreshing, so remove its views + st.decorView.removeAllViews(); + } + + // This will populate st.shownPanelView + if (!initializePanelContent(st) || (st.shownPanelView == null)) { + return; + } + + ViewGroup.LayoutParams lp = st.shownPanelView.getLayoutParams(); + if (lp == null) { + lp = new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); + } + + int backgroundResId; + if (lp.width == ViewGroup.LayoutParams.FILL_PARENT) { + // If the contents is fill parent for the width, set the + // corresponding background + backgroundResId = st.fullBackground; + } else { + // Otherwise, set the normal panel background + backgroundResId = st.background; + } + st.decorView.setWindowBackground(getContext().getResources().getDrawable( + backgroundResId)); + + + st.decorView.addView(st.shownPanelView, lp); + + /* + * Give focus to the view, if it or one of its children does not + * already have it. + */ + if (!st.shownPanelView.hasFocus()) { + st.shownPanelView.requestFocus(); + } + } + + st.isOpen = true; + st.isHandled = false; + + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + WRAP_CONTENT, WRAP_CONTENT, + st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, + WindowManager.LayoutParams.FLAG_DITHER, + st.decorView.mDefaultOpacity); + + lp.gravity = st.gravity; + lp.windowAnimations = st.windowAnimations; + wm.addView(st.decorView, lp); + // Log.v(TAG, "Adding main menu to window manager."); + } + + @Override + public final void closePanel(int featureId) { + closePanel(getPanelState(featureId, true), true); + } + + /** + * Closes the given panel. + * + * @param st The panel to be closed. + * @param doCallback Whether to notify the callback that the panel was + * closed. If the panel is in the process of re-opening or + * opening another panel (e.g., menu opening a sub menu), the + * callback should not happen and this variable should be false. + * In addition, this method internally will only perform the + * callback if the panel is open. + */ + public final void closePanel(PanelFeatureState st, boolean doCallback) { + // System.out.println("Close panel: isOpen=" + st.isOpen); + final ViewManager wm = getWindowManager(); + if ((wm != null) && st.isOpen) { + if (st.decorView != null) { + wm.removeView(st.decorView); + // Log.v(TAG, "Removing main menu from window manager."); + } + + if (doCallback) { + callOnPanelClosed(st.featureId, st, null); + } + } + st.isPrepared = false; + st.isHandled = false; + st.isOpen = false; + + // This view is no longer shown, so null it out + st.shownPanelView = null; + + if (st.isInExpandedMode) { + // Next time the menu opens, it should not be in expanded mode, so + // force a refresh of the decor + st.refreshDecorView = true; + st.isInExpandedMode = false; + } + + if (mPreparedPanel == st) { + mPreparedPanel = null; + mPanelChordingKey = 0; + } + } + + @Override + public final void togglePanel(int featureId, KeyEvent event) { + PanelFeatureState st = getPanelState(featureId, true); + if (st.isOpen) { + closePanel(st, true); + } else { + openPanel(st, event); + } + } + + /** + * Called when the panel key is pushed down. + * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}. + * @param event The key event. + * @return Whether the key was handled. + */ + public final boolean onKeyDownPanel(int featureId, KeyEvent event) { + // The panel key was pushed, so set the chording key + mPanelChordingKey = event.getKeyCode(); + + PanelFeatureState st = getPanelState(featureId, true); + if (!st.isOpen) { + return preparePanel(st, event); + } + + return false; + } + + /** + * Called when the panel key is released. + * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}. + * @param event The key event. + */ + public final void onKeyUpPanel(int featureId, KeyEvent event) { + // The panel key was released, so clear the chording key + mPanelChordingKey = 0; + + boolean playSoundEffect = false; + PanelFeatureState st = getPanelState(featureId, true); + 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; + + // Close menu + closePanel(st, true); + + } else if (st.isPrepared) { + + // Write 'menu opened' to event log + EventLog.writeEvent(50001, 0); + + // Show menu + openPanel(st, event); + + playSoundEffect = true; + } + + if (playSoundEffect) { + AudioManager audioManager = (AudioManager) getContext().getSystemService( + Context.AUDIO_SERVICE); + if (audioManager != null) { + audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); + } else { + Log.w(TAG, "Couldn't get audio manager"); + } + } + } + + @Override + public final void closeAllPanels() { + final ViewManager wm = getWindowManager(); + if (wm == null) { + return; + } + + final PanelFeatureState[] panels = mPanels; + final int N = panels != null ? panels.length : 0; + for (int i = 0; i < N; i++) { + final PanelFeatureState panel = panels[i]; + if (panel != null) { + closePanel(panel, true); + } + } + + closeContextMenu(); + } + + private synchronized void closeContextMenu() { + mContextMenu = null; + + if (mContextMenuHelper != null) { + mContextMenuHelper.dismiss(); + mContextMenuHelper = null; + } + } + + @Override + public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) { + return performPanelShortcut(getPanelState(featureId, true), keyCode, event, flags); + } + + private boolean performPanelShortcut(PanelFeatureState st, int keyCode, KeyEvent event, + int flags) { + if (event.isSystem() || (st == null)) { + return false; + } + + boolean handled = false; + + // Only try to perform menu shortcuts if preparePanel returned true (possible false + // return value from application not wanting to show the menu). + if ((st.isPrepared || preparePanel(st, event)) && st.menu != null) { + // The menu is prepared now, perform the shortcut on it + handled = st.menu.performShortcut(keyCode, event, flags); + } + + if (handled) { + // Mark as handled + st.isHandled = true; + + if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0) { + closePanel(st, true); + } + } + + return handled; + } + + @Override + public boolean performPanelIdentifierAction(int featureId, int id, int flags) { + + PanelFeatureState st = getPanelState(featureId, true); + if (!preparePanel(st, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU))) { + return false; + } + if (st.menu == null) { + return false; + } + + boolean res = st.menu.performIdentifierAction(id, flags); + + closePanel(st, true); + + return res; + } + + public PanelFeatureState findMenuPanel(Menu menu) { + final PanelFeatureState[] panels = mPanels; + final int N = panels != null ? panels.length : 0; + for (int i = 0; i < N; i++) { + final PanelFeatureState panel = panels[i]; + if (panel != null && panel.menu == menu) { + return panel; + } + } + return null; + } + + public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { + final Callback cb = getCallback(); + if (cb != null) { + final PanelFeatureState panel = findMenuPanel(menu.getRootMenu()); + if (panel != null) { + return cb.onMenuItemSelected(panel.featureId, item); + } + } + return false; + } + + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + final PanelFeatureState panel = findMenuPanel(menu); + if (panel != null) { + // Close the panel and only do the callback if the menu is being + // closed + // completely, not if opening a sub menu + closePanel(panel, allMenusAreClosing); + } + } + + public void onCloseSubMenu(SubMenuBuilder subMenu) { + final Menu parentMenu = subMenu.getRootMenu(); + final PanelFeatureState panel = findMenuPanel(parentMenu); + + // Callback + if (panel != null) { + callOnPanelClosed(panel.featureId, panel, parentMenu); + closePanel(panel, true); + } + } + + public boolean onSubMenuSelected(final SubMenuBuilder subMenu) { + if (!subMenu.hasVisibleItems()) { + return true; + } + + // The window manager will give us a valid window token + new MenuDialogHelper(subMenu).show(null); + + return true; + } + + public void onMenuModeChange(MenuBuilder menu) { + reopenMenu(true); + } + + private void reopenMenu(boolean toggleMenuMode) { + PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); + + // Save the future expanded mode state since closePanel will reset it + boolean newExpandedMode = toggleMenuMode ? !st.isInExpandedMode : st.isInExpandedMode; + + st.refreshDecorView = true; + closePanel(st, false); + + // Set the expanded mode state + st.isInExpandedMode = newExpandedMode; + + openPanel(st, null); + } + + /** + * Initializes the menu associated with the given panel feature state. You + * must at the very least set PanelFeatureState.menu to the Menu to be + * associated with the given panel state. The default implementation creates + * a new menu for the panel state. + * + * @param st The panel whose menu is being initialized. + * @return Whether the initialization was successful. + */ + protected boolean initializePanelMenu(final PanelFeatureState st) { + final MenuBuilder menu = new MenuBuilder(getContext()); + + menu.setCallback(this); + st.setMenu(menu); + + return true; + } + + /** + * Perform initial setup of a panel. This should at the very least set the + * style information in the PanelFeatureState and must set + * PanelFeatureState.decor to the panel's window decor view. + * + * @param st The panel being initialized. + */ + protected boolean initializePanelDecor(PanelFeatureState st) { + st.decorView = new DecorView(getContext(), st.featureId); + st.gravity = Gravity.CENTER | Gravity.BOTTOM; + st.setStyle(getContext()); + + return true; + } + + /** + * Initializes the panel associated with the panel feature state. You must + * at the very least set PanelFeatureState.panel to the View implementing + * its contents. The default implementation gets the panel from the menu. + * + * @param st The panel state being initialized. + * @return Whether the initialization was successful. + */ + protected boolean initializePanelContent(PanelFeatureState st) { + + if (st.createdPanelView != null) { + st.shownPanelView = st.createdPanelView; + return true; + } + + final MenuBuilder menu = (MenuBuilder)st.menu; + if (menu == null) { + return false; + } + + st.shownPanelView = menu.getMenuView((st.isInExpandedMode) ? MenuBuilder.TYPE_EXPANDED + : MenuBuilder.TYPE_ICON, st.decorView); + + if (st.shownPanelView != null) { + // Use the menu View's default animations if it has any + final int defaultAnimations = ((MenuView) st.shownPanelView).getWindowAnimations(); + if (defaultAnimations != 0) { + st.windowAnimations = defaultAnimations; + } + return true; + } else { + return false; + } + } + + @Override + public boolean performContextMenuIdentifierAction(int id, int flags) { + return (mContextMenu != null) ? mContextMenu.performIdentifierAction(id, flags) : false; + } + + @Override + public final void setBackgroundDrawable(Drawable drawable) { + if (drawable != mBackgroundDrawable) { + mBackgroundResource = 0; + mBackgroundDrawable = drawable; + if (mDecor != null) { + mDecor.setWindowBackground(drawable); + } + } + } + + @Override + public final void setFeatureDrawableResource(int featureId, int resId) { + if (resId != 0) { + DrawableFeatureState st = getDrawableState(featureId, true); + if (st.resid != resId) { + st.resid = resId; + st.uri = null; + st.local = getContext().getResources().getDrawable(resId); + updateDrawable(featureId, st, false); + } + } else { + setFeatureDrawable(featureId, null); + } + } + + @Override + public final void setFeatureDrawableUri(int featureId, Uri uri) { + if (uri != null) { + DrawableFeatureState st = getDrawableState(featureId, true); + if (st.uri == null || !st.uri.equals(uri)) { + st.resid = 0; + st.uri = uri; + st.local = loadImageURI(uri); + updateDrawable(featureId, st, false); + } + } else { + setFeatureDrawable(featureId, null); + } + } + + @Override + public final void setFeatureDrawable(int featureId, Drawable drawable) { + DrawableFeatureState st = getDrawableState(featureId, true); + st.resid = 0; + st.uri = null; + if (st.local != drawable) { + st.local = drawable; + updateDrawable(featureId, st, false); + } + } + + @Override + public void setFeatureDrawableAlpha(int featureId, int alpha) { + DrawableFeatureState st = getDrawableState(featureId, true); + if (st.alpha != alpha) { + st.alpha = alpha; + updateDrawable(featureId, st, false); + } + } + + protected final void setFeatureDefaultDrawable(int featureId, Drawable drawable) { + DrawableFeatureState st = getDrawableState(featureId, true); + if (st.def != drawable) { + st.def = drawable; + updateDrawable(featureId, st, false); + } + } + + @Override + public final void setFeatureInt(int featureId, int value) { + // XXX Should do more management (as with drawable features) to + // deal with interactions between multiple window policies. + updateInt(featureId, value, false); + } + + /** + * Update the state of a drawable feature. This should be called, for every + * drawable feature supported, as part of onActive(), to make sure that the + * contents of a containing window is properly updated. + * + * @see #onActive + * @param featureId The desired drawable feature to change. + * @param fromActive Always true when called from onActive(). + */ + protected final void updateDrawable(int featureId, boolean fromActive) { + final DrawableFeatureState st = getDrawableState(featureId, false); + if (st != null) { + updateDrawable(featureId, st, fromActive); + } + } + + /** + * Called when a Drawable feature changes, for the window to update its + * graphics. + * + * @param featureId The feature being changed. + * @param drawable The new Drawable to show, or null if none. + * @param alpha The new alpha blending of the Drawable. + */ + protected void onDrawableChanged(int featureId, Drawable drawable, int alpha) { + ImageView view; + if (featureId == FEATURE_LEFT_ICON) { + view = getLeftIconView(); + } else if (featureId == FEATURE_RIGHT_ICON) { + view = getRightIconView(); + } else { + return; + } + + if (drawable != null) { + drawable.setAlpha(alpha); + view.setImageDrawable(drawable); + view.setVisibility(View.VISIBLE); + } else { + view.setVisibility(View.GONE); + } + } + + /** + * Called when an int feature changes, for the window to update its + * graphics. + * + * @param featureId The feature being changed. + * @param value The new integer value. + */ + protected void onIntChanged(int featureId, int value) { + if (featureId == FEATURE_PROGRESS || featureId == FEATURE_INDETERMINATE_PROGRESS) { + updateProgressBars(value); + } else if (featureId == FEATURE_CUSTOM_TITLE) { + FrameLayout titleContainer = (FrameLayout) findViewById(com.android.internal.R.id.title_container); + if (titleContainer != null) { + mLayoutInflater.inflate(value, titleContainer); + } + } + } + + /** + * Updates the progress bars that are shown in the title bar. + * + * @param value Can be one of {@link Window#PROGRESS_VISIBILITY_ON}, + * {@link Window#PROGRESS_VISIBILITY_OFF}, + * {@link Window#PROGRESS_INDETERMINATE_ON}, + * {@link Window#PROGRESS_INDETERMINATE_OFF}, or a value + * starting at {@link Window#PROGRESS_START} through + * {@link Window#PROGRESS_END} for setting the default + * progress (if {@link Window#PROGRESS_END} is given, + * the progress bar widgets in the title will be hidden after an + * animation), a value between + * {@link Window#PROGRESS_SECONDARY_START} - + * {@link Window#PROGRESS_SECONDARY_END} for the + * secondary progress (if + * {@link Window#PROGRESS_SECONDARY_END} is given, the + * progress bar widgets will still be shown with the secondary + * progress bar will be completely filled in.) + */ + private void updateProgressBars(int value) { + ProgressBar circularProgressBar = getCircularProgressBar(true); + ProgressBar horizontalProgressBar = getHorizontalProgressBar(true); + + final int features = getLocalFeatures(); + if (value == PROGRESS_VISIBILITY_ON) { + if ((features & (1 << FEATURE_PROGRESS)) != 0) { + int level = horizontalProgressBar.getProgress(); + int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ? + View.VISIBLE : View.INVISIBLE; + horizontalProgressBar.setVisibility(visibility); + } + if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { + circularProgressBar.setVisibility(View.VISIBLE); + } + } else if (value == PROGRESS_VISIBILITY_OFF) { + if ((features & (1 << FEATURE_PROGRESS)) != 0) { + horizontalProgressBar.setVisibility(View.GONE); + } + if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { + circularProgressBar.setVisibility(View.GONE); + } + } else if (value == PROGRESS_INDETERMINATE_ON) { + horizontalProgressBar.setIndeterminate(true); + } else if (value == PROGRESS_INDETERMINATE_OFF) { + horizontalProgressBar.setIndeterminate(false); + } else if (PROGRESS_START <= value && value <= PROGRESS_END) { + // We want to set the progress value before testing for visibility + // so that when the progress bar becomes visible again, it has the + // correct level. + horizontalProgressBar.setProgress(value - PROGRESS_START); + + if (value < PROGRESS_END) { + showProgressBars(horizontalProgressBar, circularProgressBar); + } else { + hideProgressBars(horizontalProgressBar, circularProgressBar); + } + } else if (PROGRESS_SECONDARY_START <= value && value <= PROGRESS_SECONDARY_END) { + horizontalProgressBar.setSecondaryProgress(value - PROGRESS_SECONDARY_START); + + showProgressBars(horizontalProgressBar, circularProgressBar); + } + + } + + private void showProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) { + final int features = getLocalFeatures(); + if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 && + spinnyProgressBar.getVisibility() == View.INVISIBLE) { + spinnyProgressBar.setVisibility(View.VISIBLE); + } + // Only show the progress bars if the primary progress is not complete + if ((features & (1 << FEATURE_PROGRESS)) != 0 && + horizontalProgressBar.getProgress() < 10000) { + horizontalProgressBar.setVisibility(View.VISIBLE); + } + } + + private void hideProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) { + final int features = getLocalFeatures(); + Animation anim = AnimationUtils.loadAnimation(getContext(), com.android.internal.R.anim.fade_out); + anim.setDuration(1000); + if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 && + spinnyProgressBar.getVisibility() == View.VISIBLE) { + spinnyProgressBar.startAnimation(anim); + spinnyProgressBar.setVisibility(View.INVISIBLE); + } + if ((features & (1 << FEATURE_PROGRESS)) != 0 && + horizontalProgressBar.getVisibility() == View.VISIBLE) { + horizontalProgressBar.startAnimation(anim); + horizontalProgressBar.setVisibility(View.INVISIBLE); + } + } + + /** + * Request that key events come to this activity. Use this if your activity + * has no views with focus, but the activity still wants a chance to process + * key events. + */ + @Override + public void takeKeyEvents(boolean get) { + mDecor.setFocusable(get); + } + + @Override + public boolean superDispatchKeyEvent(KeyEvent event) { + return mDecor.superDispatchKeyEvent(event); + } + + @Override + public boolean superDispatchTouchEvent(MotionEvent event) { + return mDecor.superDispatchTouchEvent(event); + } + + @Override + public boolean superDispatchTrackballEvent(MotionEvent event) { + return mDecor.superDispatchTrackballEvent(event); + } + + /** + * A key was pressed down and not handled by anything else in the window. + * + * @see #onKeyUp + * @see android.view.KeyEvent + */ + protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) { + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: { + AudioManager audioManager = (AudioManager) getContext().getSystemService( + Context.AUDIO_SERVICE); + if (audioManager != null) { + /* + * Adjust the volume in on key down since it is more + * responsive to the user. + */ + audioManager.adjustSuggestedStreamVolume( + keyCode == KeyEvent.KEYCODE_VOLUME_UP + ? AudioManager.ADJUST_RAISE + : AudioManager.ADJUST_LOWER, + mVolumeControlStreamType, + AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE); + } + return true; + } + + case KeyEvent.KEYCODE_HEADSETHOOK: { + Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, event); + getContext().sendOrderedBroadcast(intent, null); + return true; + } + + case KeyEvent.KEYCODE_CAMERA: { + if (getKeyguardManager().inKeyguardRestrictedInputMode()) { + break; + } + if (event.getRepeatCount() > 0) break; + mKeycodeCameraTimeoutActive = true; + mKeycodeCameraTimeoutHandler.removeMessages(0); + Message message = mKeycodeCameraTimeoutHandler.obtainMessage(0); + message.obj = event; + mKeycodeCameraTimeoutHandler.sendMessageDelayed(message, + ViewConfiguration.getLongPressTimeout()); + return true; + } + + case KeyEvent.KEYCODE_MENU: { + if (event.getRepeatCount() > 0) break; + onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event); + return true; + } + + case KeyEvent.KEYCODE_BACK: { + if (event.getRepeatCount() > 0) break; + if (featureId < 0) break; + if (featureId == FEATURE_OPTIONS_PANEL) { + PanelFeatureState st = getPanelState(featureId, false); + if (st != null && st.isInExpandedMode) { + // If the user is in an expanded menu and hits back, it + // should go back to the icon menu + reopenMenu(true); + return true; + } + } + closePanel(featureId); + return true; + } + + case KeyEvent.KEYCODE_CALL: { + if (getKeyguardManager().inKeyguardRestrictedInputMode()) { + break; + } + if (event.getRepeatCount() > 0) break; + mKeycodeCallTimeoutActive = true; + mKeycodeCallTimeoutHandler.removeMessages(0); + mKeycodeCallTimeoutHandler.sendMessageDelayed( + mKeycodeCallTimeoutHandler.obtainMessage(0), + ViewConfiguration.getLongPressTimeout()); + return true; + } + + case KeyEvent.KEYCODE_SEARCH: { + if (event.getRepeatCount() == 0) { + mSearchKeyDownReceived = true; + } + break; + } + } + + return false; + } + + /** + * @return A handle to the keyguard manager. + */ + private KeyguardManager getKeyguardManager() { + if (mKeyguardManager == null) { + mKeyguardManager = (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE); + } + return mKeyguardManager; + } + + /** + * A key was released and not handled by anything else in the window. + * + * @see #onKeyDown + * @see android.view.KeyEvent + */ + protected boolean onKeyUp(int featureId, int keyCode, KeyEvent event) { + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: { + AudioManager audioManager = (AudioManager) getContext().getSystemService( + Context.AUDIO_SERVICE); + if (audioManager != null) { + /* + * Play a sound. This is done on key up since we don't want the + * sound to play when a user holds down volume down to mute. + */ + audioManager.adjustSuggestedStreamVolume( + AudioManager.ADJUST_SAME, + mVolumeControlStreamType, + AudioManager.FLAG_PLAY_SOUND); + mVolumeKeyUpTime = SystemClock.uptimeMillis(); + } + return true; + } + + case KeyEvent.KEYCODE_MENU: { + onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId, + event); + return true; + } + + case KeyEvent.KEYCODE_HEADSETHOOK: { + Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, event); + getContext().sendOrderedBroadcast(intent, null); + return true; + } + + case KeyEvent.KEYCODE_CAMERA: { + if (getKeyguardManager().inKeyguardRestrictedInputMode()) { + break; + } + if (event.getRepeatCount() > 0) break; // Can a key up event repeat? + mKeycodeCameraTimeoutHandler.removeMessages(0); + if (!mKeycodeCameraTimeoutActive) break; + mKeycodeCameraTimeoutActive = false; + // Add short press behavior here if desired + return true; + } + + case KeyEvent.KEYCODE_CALL: { + if (getKeyguardManager().inKeyguardRestrictedInputMode()) { + break; + } + if (event.getRepeatCount() > 0) break; + mKeycodeCallTimeoutHandler.removeMessages(0); + if (!mKeycodeCallTimeoutActive) break; + mKeycodeCallTimeoutActive = false; + startCallActivity(); + return true; + } + + case KeyEvent.KEYCODE_SEARCH: { + /* + * Do this in onKeyUp since the Search key is also used for + * chording quick launch shortcuts. + */ + if (getKeyguardManager().inKeyguardRestrictedInputMode() || + !mSearchKeyDownReceived) { + break; + } + mSearchKeyDownReceived = false; + launchDefaultSearch(); + return true; + } + } + + return false; + } + + private void startCallActivity() { + Intent intent = new Intent(Intent.ACTION_CALL_BUTTON); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + getContext().startActivity(intent); + } + + @Override + protected void onActive() { + } + + @Override + public final View getDecorView() { + if (mDecor == null) { + installDecor(); + } + return mDecor; + } + + @Override + public final View peekDecorView() { + return mDecor; + } + + 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"; + + /** {@inheritDoc} */ + @Override + public Bundle saveHierarchyState() { + Bundle outState = new Bundle(); + if (mContentParent == null) { + return outState; + } + + SparseArray states = new SparseArray(); + mContentParent.saveHierarchyState(states); + outState.putSparseParcelableArray(VIEWS_TAG, states); + + // save the focused view id + View focusedView = mContentParent.findFocus(); + if (focusedView != null) { + if (focusedView.getId() != View.NO_ID) { + outState.putInt(FOCUSED_ID_TAG, focusedView.getId()); + } else { + if (Config.LOGD) { + Log.d(TAG, "couldn't save which view has focus because the focused view " + + focusedView + " has no id."); + } + } + } + + // save the panels + SparseArray panelStates = new SparseArray(); + savePanelState(panelStates); + if (panelStates.size() > 0) { + outState.putSparseParcelableArray(PANELS_TAG, panelStates); + } + + return outState; + } + + /** {@inheritDoc} */ + @Override + public void restoreHierarchyState(Bundle savedInstanceState) { + if (mContentParent == null) { + return; + } + + SparseArray savedStates + = savedInstanceState.getSparseParcelableArray(VIEWS_TAG); + if (savedStates != null) { + mContentParent.restoreHierarchyState(savedStates); + } + + // restore the focused view + int focusedViewId = savedInstanceState.getInt(FOCUSED_ID_TAG, View.NO_ID); + if (focusedViewId != View.NO_ID) { + View needsFocus = mContentParent.findViewById(focusedViewId); + if (needsFocus != null) { + needsFocus.requestFocus(); + } else { + Log.w(TAG, + "Previously focused view reported id " + focusedViewId + + " during save, but can't be found during restore."); + } + } + + // restore the panels + SparseArray panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG); + if (panelStates != null) { + restorePanelState(panelStates); + } + } + + /** + * Invoked when the panels should freeze their state. + * + * @param icicles Save state into this. This is usually indexed by the + * featureId. This will be given to {@link #restorePanelState} in the + * future. + */ + private void savePanelState(SparseArray icicles) { + PanelFeatureState[] panels = mPanels; + if (panels == null) { + return; + } + + for (int curFeatureId = panels.length - 1; curFeatureId >= 0; curFeatureId--) { + if (panels[curFeatureId] != null) { + icicles.put(curFeatureId, panels[curFeatureId].onSaveInstanceState()); + } + } + } + + /** + * Invoked when the panels should thaw their state from a previously frozen state. + * + * @param icicles The state saved by {@link #savePanelState} that needs to be thawed. + */ + private void restorePanelState(SparseArray icicles) { + PanelFeatureState st; + for (int curFeatureId = icicles.size() - 1; curFeatureId >= 0; curFeatureId--) { + st = getPanelState(curFeatureId, false /* required */); + if (st == null) { + // The panel must not have been required, and is currently not around, skip it + continue; + } + + st.onRestoreInstanceState(icicles.get(curFeatureId)); + } + + /* + * Implementation note: call openPanelsAfterRestore later to actually open the + * restored panels. + */ + } + + /** + * Opens the panels that have had their state restored. This should be + * called sometime after {@link #restorePanelState} when it is safe to add + * to the window manager. + */ + private void openPanelsAfterRestore() { + PanelFeatureState[] panels = mPanels; + + if (panels == null) { + return; + } + + PanelFeatureState st; + for (int i = panels.length - 1; i >= 0; i--) { + st = panels[i]; + if ((st != null) && st.isOpen) { + // Clear st.isOpen (openPanel will not open if it's already open) + st.isOpen = false; + openPanel(st, null); + } + } + } + + private final class DecorView extends FrameLayout { + /* package */int mDefaultOpacity = PixelFormat.OPAQUE; + + /** The feature ID of the panel, or -1 if this is the application's DecorView */ + private final int mFeatureId; + + private final Rect mDrawingBounds = new Rect(); + + private final Rect mBackgroundPadding = new Rect(); + + private final Rect mFramePadding = new Rect(); + + private final Rect mFrameOffsets = new Rect(); + + private final Paint mBlackPaint = new Paint(); + + private boolean mChanging; + + private Drawable mMenuBackground; + private boolean mWatchingForMenu; + private int mDownY; + + public DecorView(Context context, int featureId) { + super(context); + mFeatureId = featureId; + mBlackPaint.setColor(0xFF000000); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + final int keyCode = event.getKeyCode(); + final boolean isDown = event.getAction() == KeyEvent.ACTION_DOWN; + + /* + * If the user hits another key within the play sound delay, then + * cancel the sound + */ + if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP + && mVolumeKeyUpTime + VolumePanel.PLAY_SOUND_DELAY + > SystemClock.uptimeMillis()) { + /* + * The user has hit another key during the delay (e.g., 300ms) + * since the last volume key up, so cancel any sounds. + */ + AudioManager audioManager = (AudioManager) getContext().getSystemService( + Context.AUDIO_SERVICE); + if (audioManager != null) { + audioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_SAME, + mVolumeControlStreamType, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); + } + } + + if (isDown && (event.getRepeatCount() == 0)) { + // First handle chording of panel key: if a panel key is held + // but not released, try to execute a shortcut in it. + if ((mPanelChordingKey > 0) && (mPanelChordingKey != keyCode)) { + // Perform the shortcut (mPreparedPanel can be null since + // global shortcuts (such as search) don't rely on a + // prepared panel or menu). + boolean handled = performPanelShortcut(mPreparedPanel, keyCode, event, + Menu.FLAG_PERFORM_NO_CLOSE); + + if (!handled) { + /* + * If not handled, then pass it to the view hierarchy + * and anyone else that may be interested. + */ + handled = dispatchKeyShortcut(event); + + if (handled && mPreparedPanel != null) { + mPreparedPanel.isHandled = true; + } + } + + if (handled) { + return true; + } + } + + // If a panel is open, perform a shortcut on it without the + // chorded panel key + if ((mPreparedPanel != null) && mPreparedPanel.isOpen) { + if (performPanelShortcut(mPreparedPanel, keyCode, event, 0)) { + return true; + } + } + } + + final Callback cb = getCallback(); + final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event) + : super.dispatchKeyEvent(event); + if (handled) { + return true; + } + return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event) + : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event); + } + + private boolean dispatchKeyShortcut(KeyEvent event) { + View focusedView = findFocus(); + return focusedView == null ? false : focusedView.dispatchKeyShortcutEvent(event); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + final Callback cb = getCallback(); + return cb != null && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super + .dispatchTouchEvent(ev); + } + + @Override + public boolean dispatchTrackballEvent(MotionEvent ev) { + final Callback cb = getCallback(); + return cb != null && mFeatureId < 0 ? cb.dispatchTrackballEvent(ev) : super + .dispatchTrackballEvent(ev); + } + + public boolean superDispatchKeyEvent(KeyEvent event) { + return super.dispatchKeyEvent(event); + } + + public boolean superDispatchTouchEvent(MotionEvent event) { + return super.dispatchTouchEvent(event); + } + + public boolean superDispatchTrackballEvent(MotionEvent event) { + return super.dispatchTrackballEvent(event); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return onInterceptTouchEvent(event); + } + + private boolean isOutOfBounds(int x, int y) { + return x < -5 || y < -5 || x > (getWidth() + 5) + || y > (getHeight() + 5); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + int action = event.getAction(); + if (mFeatureId >= 0) { + if (action == MotionEvent.ACTION_DOWN) { + int x = (int)event.getX(); + int y = (int)event.getY(); + if (isOutOfBounds(x, y)) { + closePanel(mFeatureId); + return true; + } + } + } + + if (!SWEEP_OPEN_MENU) { + return false; + } + + if (mFeatureId >= 0) { + if (action == MotionEvent.ACTION_DOWN) { + Log.i(TAG, "Watchiing!"); + mWatchingForMenu = true; + mDownY = (int) event.getY(); + return false; + } + + if (!mWatchingForMenu) { + return false; + } + + int y = (int)event.getY(); + if (action == MotionEvent.ACTION_MOVE) { + if (y > (mDownY+30)) { + Log.i(TAG, "Closing!"); + closePanel(mFeatureId); + mWatchingForMenu = false; + return true; + } + } else if (action == MotionEvent.ACTION_UP) { + mWatchingForMenu = false; + } + + return false; + } + + //Log.i(TAG, "Intercept: action=" + action + " y=" + event.getY() + // + " (in " + getHeight() + ")"); + + if (action == MotionEvent.ACTION_DOWN) { + int y = (int)event.getY(); + if (y >= (getHeight()-5) && !hasChildren()) { + Log.i(TAG, "Watchiing!"); + mWatchingForMenu = true; + } + return false; + } + + if (!mWatchingForMenu) { + return false; + } + + int y = (int)event.getY(); + if (action == MotionEvent.ACTION_MOVE) { + if (y < (getHeight()-30)) { + Log.i(TAG, "Opening!"); + openPanel(FEATURE_OPTIONS_PANEL, new KeyEvent( + KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU)); + mWatchingForMenu = false; + return true; + } + } else if (action == MotionEvent.ACTION_UP) { + mWatchingForMenu = false; + } + + return false; + } + + @Override + protected boolean setFrame(int l, int t, int r, int b) { + boolean changed = super.setFrame(l, t, r, b); + if (changed) { + final Rect drawingBounds = mDrawingBounds; + getDrawingRect(drawingBounds); + + Drawable fg = getForeground(); + if (fg != null) { + final Rect frameOffsets = mFrameOffsets; + drawingBounds.left += frameOffsets.left; + drawingBounds.top += frameOffsets.top; + drawingBounds.right -= frameOffsets.right; + drawingBounds.bottom -= frameOffsets.bottom; + fg.setBounds(drawingBounds); + final Rect framePadding = mFramePadding; + drawingBounds.left += framePadding.left - frameOffsets.left; + drawingBounds.top += framePadding.top - frameOffsets.top; + drawingBounds.right -= framePadding.right - frameOffsets.right; + drawingBounds.bottom -= framePadding.bottom - frameOffsets.bottom; + } + + Drawable bg = getBackground(); + if (bg != null) { + bg.setBounds(drawingBounds); + } + + if (SWEEP_OPEN_MENU) { + if (mMenuBackground == null && mFeatureId < 0 + && getAttributes().height + == WindowManager.LayoutParams.FILL_PARENT) { + mMenuBackground = getContext().getResources().getDrawable( + com.android.internal.R.drawable.menu_background); + } + if (mMenuBackground != null) { + mMenuBackground.setBounds(drawingBounds.left, + drawingBounds.bottom-6, drawingBounds.right, + drawingBounds.bottom+20); + } + } + } + return changed; + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + + if (mMenuBackground != null) { + mMenuBackground.draw(canvas); + } + } + + + @Override + public boolean showContextMenuForChild(View originalView) { + // Reuse the context menu builder + if (mContextMenu == null) { + mContextMenu = new ContextMenuBuilder(getContext()); + mContextMenu.setCallback(mContextMenuCallback); + } else { + mContextMenu.clearAll(); + } + + mContextMenuHelper = mContextMenu.show(originalView, originalView.getWindowToken()); + return mContextMenuHelper != null; + } + + public void startChanging() { + mChanging = true; + } + + public void finishChanging() { + mChanging = false; + drawableChanged(); + } + + public void setWindowBackground(Drawable drawable) { + if (getBackground() != drawable) { + setBackgroundDrawable(drawable); + if (drawable != null) { + drawable.getPadding(mBackgroundPadding); + } else { + mBackgroundPadding.setEmpty(); + } + drawableChanged(); + } + } + + public void setWindowFrame(Drawable drawable) { + if (getForeground() != drawable) { + setForeground(drawable); + if (drawable != null) { + drawable.getPadding(mFramePadding); + } else { + mFramePadding.setEmpty(); + } + drawableChanged(); + } + } + + @Override + protected boolean fitSystemWindows(Rect insets) { + mFrameOffsets.set(insets); + if (getForeground() != null) { + drawableChanged(); + } + return super.fitSystemWindows(insets); + } + + private void drawableChanged() { + if (mChanging) { + return; + } + + setPadding(mFramePadding.left + mBackgroundPadding.left, mFramePadding.top + + mBackgroundPadding.top, mFramePadding.right + mBackgroundPadding.right, + mFramePadding.bottom + mBackgroundPadding.bottom); + requestLayout(); + invalidate(); + + int opacity = PixelFormat.OPAQUE; + + // Note: if there is no background, we will assume opaque. The + // common case seems to be that an application sets there to be + // no background so it can draw everything itself. For that, + // we would like to assume OPAQUE and let the app force it to + // the slower TRANSLUCENT mode if that is really what it wants. + Drawable bg = getBackground(); + Drawable fg = getForeground(); + if (bg != null) { + if (fg == null) { + opacity = bg.getOpacity(); + } else if (mFramePadding.left <= 0 && mFramePadding.top <= 0 + && mFramePadding.right <= 0 && mFramePadding.bottom <= 0) { + // If the frame padding is zero, then we can be opaque + // if either the frame -or- the background is opaque. + int fop = fg.getOpacity(); + int bop = bg.getOpacity(); + if (Config.LOGV) + Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop); + if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) { + opacity = PixelFormat.OPAQUE; + } else if (fop == PixelFormat.UNKNOWN) { + opacity = bop; + } else if (bop == PixelFormat.UNKNOWN) { + opacity = fop; + } else { + opacity = Drawable.resolveOpacity(fop, bop); + } + } else { + // For now we have to assume translucent if there is a + // frame with padding... there is no way to tell if the + // frame and background together will draw all pixels. + if (Config.LOGV) + Log.v(TAG, "Padding: " + mFramePadding); + opacity = PixelFormat.TRANSLUCENT; + } + } + + if (Config.LOGV) + Log.v(TAG, "Background: " + bg + ", Frame: " + fg); + if (Config.LOGV) + Log.v(TAG, "Selected default opacity: " + opacity); + + mDefaultOpacity = opacity; + if (mFeatureId < 0) { + setDefaultWindowFormat(opacity); + } + } + + @Override + public void onWindowFocusChanged(boolean hasWindowFocus) { + super.onWindowFocusChanged(hasWindowFocus); + + // no KEYCODE_CALL events active across focus changes + mKeycodeCallTimeoutHandler.removeMessages(0); + mKeycodeCallTimeoutActive = false; + mKeycodeCameraTimeoutHandler.removeMessages(0); + mKeycodeCameraTimeoutActive = false; + + // If the user is chording a menu shortcut, release the chord since + // this window lost focus + if (!hasWindowFocus && mPanelChordingKey > 0) { + closePanel(FEATURE_OPTIONS_PANEL); + } + + final Callback cb = getCallback(); + if (cb != null && mFeatureId < 0) { + cb.onWindowFocusChanged(hasWindowFocus); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + if (mFeatureId == -1) { + /* + * The main window has been attached, try to restore any panels + * that may have been open before. This is called in cases where + * an activity is being killed for configuration change and the + * menu was open. When the activity is recreated, the menu + * should be shown again. + */ + openPanelsAfterRestore(); + } + } + } + + protected DecorView generateDecor() { + return new DecorView(getContext(), -1); + } + + protected void setFeatureFromAttrs(int featureId, TypedArray attrs, + int drawableAttr, int alphaAttr) { + Drawable d = attrs.getDrawable(drawableAttr); + if (d != null) { + requestFeature(featureId); + setFeatureDefaultDrawable(featureId, d); + } + if ((getFeatures() & (1 << featureId)) != 0) { + int alpha = attrs.getInt(alphaAttr, -1); + if (alpha >= 0) { + setFeatureDrawableAlpha(featureId, alpha); + } + } + } + + protected ViewGroup generateLayout(DecorView decor) { + // Apply data from current theme. + + final Context c = getContext(); + TypedArray a = getWindowStyle(); + + if (false) { + System.out.println("From style:"); + String s = "Attrs:"; + for (int i = 0; i < com.android.internal.R.styleable.Window.length; i++) { + s = s + " " + Integer.toHexString(com.android.internal.R.styleable.Window[i]) + "=" + + a.getString(i); + } + System.out.println(s); + } + + mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false); + int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR) + & (~getForcedWindowFlags()); + if (mIsFloating) { + setLayout(WRAP_CONTENT, WRAP_CONTENT); + setFlags(0, flagsToUpdate); + + /* All dialogs should have the window dimmed */ + WindowManager.LayoutParams params = getAttributes(); + TypedArray attrs = c.obtainStyledAttributes( + com.android.internal.R.styleable.Theme); + params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; + params.dimAmount = attrs.getFloat( + android.R.styleable.Theme_backgroundDimAmount, 0.5f); + attrs.recycle(); + } else { + setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate); + } + + if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) { + requestFeature(FEATURE_NO_TITLE); + } + + if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) { + setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags())); + } + + // The rest are only done if this window is not embedded; otherwise, + // the values are inherited from our container. + if (getContainer() == null) { + if (mBackgroundDrawable == null) { + if (mBackgroundResource == 0) { + mBackgroundResource = a.getResourceId( + com.android.internal.R.styleable.Window_windowBackground, 0); + } + if (mFrameResource == 0) { + mFrameResource = a.getResourceId(com.android.internal.R.styleable.Window_windowFrame, 0); + } + if (false) { + System.out.println("Background: " + + Integer.toHexString(mBackgroundResource) + " Frame: " + + Integer.toHexString(mFrameResource)); + } + } + mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000); + } + + // Inflate the window decor. + + int layoutResource; + int features = getLocalFeatures(); + // System.out.println("Features: 0x" + Integer.toHexString(features)); + if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) { + if (mIsFloating) { + layoutResource = com.android.internal.R.layout.dialog_title_icons; + } else { + layoutResource = com.android.internal.R.layout.screen_title_icons; + } + // 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; + // System.out.println("Progress!"); + } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) { + // Special case for a window with a custom title. + // If the window is floating, we need a dialog layout + if (mIsFloating) { + layoutResource = com.android.internal.R.layout.dialog_custom_title; + } else { + layoutResource = com.android.internal.R.layout.screen_custom_title; + } + } 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 { + layoutResource = com.android.internal.R.layout.screen_title; + } + // System.out.println("Title!"); + } else { + // Embedded, so no decoration is needed. + layoutResource = com.android.internal.R.layout.screen_simple; + // System.out.println("Simple!"); + } + + mDecor.startChanging(); + + View in = mLayoutInflater.inflate(layoutResource, null); + decor.addView(in, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT)); + + ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); + if (contentParent == null) { + throw new RuntimeException("Window couldn't find content container view"); + } + + if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { + ProgressBar progress = getCircularProgressBar(false); + if (progress != null) { + progress.setIndeterminate(true); + } + } + + // Remaining setup -- of background and title -- that only applies + // to top-level windows. + if (getContainer() == null) { + Drawable drawable = mBackgroundDrawable; + if (mBackgroundResource != 0) { + drawable = getContext().getResources().getDrawable(mBackgroundResource); + } + mDecor.setWindowBackground(drawable); + drawable = null; + if (mFrameResource != 0) { + drawable = getContext().getResources().getDrawable(mFrameResource); + } + mDecor.setWindowFrame(drawable); + + // System.out.println("Text=" + Integer.toHexString(mTextColor) + + // " Sel=" + Integer.toHexString(mTextSelectedColor) + + // " Title=" + Integer.toHexString(mTitleColor)); + + if (mTitleColor == 0) { + mTitleColor = mTextColor; + } + + if (mTitle != null) { + setTitle(mTitle); + } + setTitleColor(mTitleColor); + } + + mDecor.finishChanging(); + + return contentParent; + } + + private void installDecor() { + if (mDecor == null) { + mDecor = generateDecor(); + mDecor.setIsRootNamespace(true); + } + if (mContentParent == null) { + mContentParent = generateLayout(mDecor); + + mTitleView = (TextView)findViewById(com.android.internal.R.id.title); + if (mTitleView != null) { + if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) { + View titleContainer = findViewById(com.android.internal.R.id.title_container); + if (titleContainer != null) { + titleContainer.setVisibility(View.GONE); + } else { + mTitleView.setVisibility(View.GONE); + } + if (mContentParent instanceof FrameLayout) { + ((FrameLayout)mContentParent).setForeground(null); + } + } else { + mTitleView.setText(mTitle); + } + } + } + } + + private Drawable loadImageURI(Uri uri) { + try { + return Drawable.createFromStream( + getContext().getContentResolver().openInputStream(uri), null); + } catch (Exception e) { + Log.w(TAG, "Unable to open content: " + uri); + } + return null; + } + + private DrawableFeatureState getDrawableState(int featureId, boolean required) { + if ((getFeatures() & (1 << featureId)) == 0) { + if (!required) { + return null; + } + throw new RuntimeException("The feature has not been requested"); + } + + DrawableFeatureState[] ar; + if ((ar = mDrawables) == null || ar.length <= featureId) { + DrawableFeatureState[] nar = new DrawableFeatureState[featureId + 1]; + if (ar != null) { + System.arraycopy(ar, 0, nar, 0, ar.length); + } + mDrawables = ar = nar; + } + + DrawableFeatureState st = ar[featureId]; + if (st == null) { + ar[featureId] = st = new DrawableFeatureState(featureId); + } + return st; + } + + /** + * Gets a panel's state based on its feature ID. + * + * @param featureId The feature ID of the panel. + * @param required Whether the panel is required (if it is required and it + * isn't in our features, this throws an exception). + * @return The panel state. + */ + private PanelFeatureState getPanelState(int featureId, boolean required) { + return getPanelState(featureId, required, null); + } + + /** + * Gets a panel's state based on its feature ID. + * + * @param featureId The feature ID of the panel. + * @param required Whether the panel is required (if it is required and it + * isn't in our features, this throws an exception). + * @param convertPanelState Optional: If the panel state does not exist, use + * this as the panel state. + * @return The panel state. + */ + private PanelFeatureState getPanelState(int featureId, boolean required, + PanelFeatureState convertPanelState) { + if ((getFeatures() & (1 << featureId)) == 0) { + if (!required) { + return null; + } + throw new RuntimeException("The feature has not been requested"); + } + + PanelFeatureState[] ar; + if ((ar = mPanels) == null || ar.length <= featureId) { + PanelFeatureState[] nar = new PanelFeatureState[featureId + 1]; + if (ar != null) { + System.arraycopy(ar, 0, nar, 0, ar.length); + } + mPanels = ar = nar; + } + + PanelFeatureState st = ar[featureId]; + if (st == null) { + ar[featureId] = st = (convertPanelState != null) + ? convertPanelState + : new PanelFeatureState(featureId); + } + return st; + } + + @Override + public final void setChildDrawable(int featureId, Drawable drawable) { + DrawableFeatureState st = getDrawableState(featureId, true); + st.child = drawable; + updateDrawable(featureId, st, false); + } + + @Override + public final void setChildInt(int featureId, int value) { + updateInt(featureId, value, false); + } + + @Override + public boolean isShortcutKey(int keyCode, KeyEvent event) { + PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); + return st.menu != null && st.menu.isShortcutKey(keyCode, event); + } + + private void updateDrawable(int featureId, DrawableFeatureState st, boolean fromResume) { + // Do nothing if the decor is not yet installed... an update will + // need to be forced when we eventually become active. + if (mContentParent == null) { + return; + } + + final int featureMask = 1 << featureId; + + if ((getFeatures() & featureMask) == 0 && !fromResume) { + return; + } + + Drawable drawable = null; + if (st != null) { + drawable = st.child; + if (drawable == null) + drawable = st.local; + if (drawable == null) + drawable = st.def; + } + if ((getLocalFeatures() & featureMask) == 0) { + if (getContainer() != null) { + if (isActive() || fromResume) { + getContainer().setChildDrawable(featureId, drawable); + } + } + } else if (st != null && (st.cur != drawable || st.curAlpha != st.alpha)) { + // System.out.println("Drawable changed: old=" + st.cur + // + ", new=" + drawable); + st.cur = drawable; + st.curAlpha = st.alpha; + onDrawableChanged(featureId, drawable, st.alpha); + } + } + + private void updateInt(int featureId, int value, boolean fromResume) { + + // Do nothing if the decor is not yet installed... an update will + // need to be forced when we eventually become active. + if (mContentParent == null) { + return; + } + + final int featureMask = 1 << featureId; + + if ((getFeatures() & featureMask) == 0 && !fromResume) { + return; + } + + if ((getLocalFeatures() & featureMask) == 0) { + if (getContainer() != null) { + getContainer().setChildInt(featureId, value); + } + } else { + onIntChanged(featureId, value); + } + } + + private ImageView getLeftIconView() { + if (mLeftIconView != null) { + return mLeftIconView; + } + if (mContentParent == null) { + installDecor(); + } + return (mLeftIconView = (ImageView)findViewById(com.android.internal.R.id.left_icon)); + } + + private ProgressBar getCircularProgressBar(boolean shouldInstallDecor) { + if (mCircularProgressBar != null) { + return mCircularProgressBar; + } + if (mContentParent == null && shouldInstallDecor) { + installDecor(); + } + mCircularProgressBar = (ProgressBar)findViewById(com.android.internal.R.id.progress_circular); + mCircularProgressBar.setVisibility(View.INVISIBLE); + return mCircularProgressBar; + } + + private ProgressBar getHorizontalProgressBar(boolean shouldInstallDecor) { + if (mHorizontalProgressBar != null) { + return mHorizontalProgressBar; + } + if (mContentParent == null && shouldInstallDecor) { + installDecor(); + } + mHorizontalProgressBar = (ProgressBar)findViewById(com.android.internal.R.id.progress_horizontal); + mHorizontalProgressBar.setVisibility(View.INVISIBLE); + return mHorizontalProgressBar; + } + + private ImageView getRightIconView() { + if (mRightIconView != null) { + return mRightIconView; + } + if (mContentParent == null) { + installDecor(); + } + return (mRightIconView = (ImageView)findViewById(com.android.internal.R.id.right_icon)); + } + + /** + * Helper method for calling the {@link Callback#onPanelClosed(int, Menu)} + * callback. This method will grab whatever extra state is needed for the + * callback that isn't given in the parameters. If the panel is not open, + * this will not perform the callback. + * + * @param featureId Feature ID of the panel that was closed. Must be given. + * @param panel Panel that was closed. Optional but useful if there is no + * menu given. + * @param menu The menu that was closed. Optional, but give if you have. + */ + private void callOnPanelClosed(int featureId, PanelFeatureState panel, Menu menu) { + final Callback cb = getCallback(); + if (cb == null) + return; + + // Try to get a menu + if (menu == null) { + // Need a panel to grab the menu, so try to get that + if (panel == null) { + if ((featureId >= 0) && (featureId < mPanels.length)) { + panel = mPanels[featureId]; + } + } + + if (panel != null) { + // menu still may be null, which is okay--we tried our best + menu = panel.menu; + } + } + + // If the panel is not open, do not callback + if ((panel != null) && (!panel.isOpen)) + return; + + cb.onPanelClosed(featureId, menu); + } + + /** + * Helper method for adding launch-search to most applications. Opens the + * search window using default settings. + * + * @return true if search window opened + */ + private boolean launchDefaultSearch() { + final Callback cb = getCallback(); + if (cb == null) { + return false; + } else { + return cb.onSearchRequested(); + } + } + + @Override + public void setVolumeControlStream(int streamType) { + mVolumeControlStreamType = streamType; + } + + @Override + public int getVolumeControlStream() { + return mVolumeControlStreamType; + } + + private static final class DrawableFeatureState { + DrawableFeatureState(int _featureId) { + featureId = _featureId; + } + + final int featureId; + + int resid; + + Uri uri; + + Drawable local; + + Drawable child; + + Drawable def; + + Drawable cur; + + int alpha = 255; + + int curAlpha = 255; + } + + private static final class PanelFeatureState { + + /** Feature ID for this panel. */ + int featureId; + + // Information pulled from the style for this panel. + + int background; + + /** The background when the panel spans the entire available width. */ + int fullBackground; + + int gravity; + + int x; + + int y; + + int windowAnimations; + + /** Dynamic state of the panel. */ + DecorView decorView; + + /** The panel that was returned by onCreatePanelView(). */ + View createdPanelView; + + /** The panel that we are actually showing. */ + View shownPanelView; + + /** Use {@link #setMenu} to set this. */ + Menu menu; + + /** + * Whether the panel has been prepared (see + * {@link PhoneWindow#preparePanel}). + */ + boolean isPrepared; + + /** + * Whether an item's action has been performed. This happens in obvious + * scenarios (user clicks on menu item), but can also happen with + * chording menu+(shortcut key). + */ + boolean isHandled; + + boolean isOpen; + + /** + * True if the menu is in expanded mode, false if the menu is in icon + * mode + */ + boolean isInExpandedMode; + + public boolean qwertyMode; + + boolean refreshDecorView; + + /** + * Contains the state of the menu when told to freeze. + */ + Bundle frozenMenuState; + + PanelFeatureState(int featureId) { + this.featureId = featureId; + + refreshDecorView = false; + } + + void setStyle(Context context) { + TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme); + background = a.getResourceId( + com.android.internal.R.styleable.Theme_panelBackground, 0); + fullBackground = a.getResourceId( + com.android.internal.R.styleable.Theme_panelFullBackground, 0); + windowAnimations = a.getResourceId( + com.android.internal.R.styleable.Theme_windowAnimationStyle, 0); + a.recycle(); + } + + void setMenu(Menu menu) { + this.menu = menu; + + if (frozenMenuState != null) { + ((MenuBuilder) menu).restoreHierarchyState(frozenMenuState); + frozenMenuState = null; + } + } + + Parcelable onSaveInstanceState() { + SavedState savedState = new SavedState(); + savedState.featureId = featureId; + savedState.isOpen = isOpen; + savedState.isInExpandedMode = isInExpandedMode; + + if (menu != null) { + savedState.menuState = new Bundle(); + ((MenuBuilder) menu).saveHierarchyState(savedState.menuState); + } + + return savedState; + } + + void onRestoreInstanceState(Parcelable state) { + SavedState savedState = (SavedState) state; + featureId = savedState.featureId; + isOpen = savedState.isOpen; + isInExpandedMode = savedState.isInExpandedMode; + frozenMenuState = savedState.menuState; + + /* + * A LocalActivityManager keeps the same instance of this class around. + * The first time the menu is being shown after restoring, the + * Activity.onCreateOptionsMenu should be called. But, if it is the + * same instance then menu != null and we won't call that method. + * So, clear this. Also clear any cached views. + */ + menu = null; + createdPanelView = null; + shownPanelView = null; + decorView = null; + } + + private static class SavedState implements Parcelable { + int featureId; + boolean isOpen; + boolean isInExpandedMode; + Bundle menuState; + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(featureId); + dest.writeInt(isOpen ? 1 : 0); + dest.writeInt(isInExpandedMode ? 1 : 0); + + if (isOpen) { + dest.writeBundle(menuState); + } + } + + private static SavedState readFromParcel(Parcel source) { + SavedState savedState = new SavedState(); + savedState.featureId = source.readInt(); + savedState.isOpen = source.readInt() == 1; + savedState.isInExpandedMode = source.readInt() == 1; + + if (savedState.isOpen) { + savedState.menuState = source.readBundle(); + } + + return savedState; + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public SavedState createFromParcel(Parcel in) { + return readFromParcel(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + } + + /** + * Simple implementation of MenuBuilder.Callback that: + *

  • Opens a submenu when selected. + *
  • Calls back to the callback's onMenuItemSelected when an item is + * selected. + */ + private final class ContextMenuCallback implements MenuBuilder.Callback { + private int mFeatureId; + + public ContextMenuCallback(int featureId) { + mFeatureId = featureId; + } + + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + if (allMenusAreClosing) { + Callback callback = getCallback(); + if (callback != null) callback.onPanelClosed(mFeatureId, menu); + + if (menu == mContextMenu) { + closeContextMenu(); + } + } + } + + public void onCloseSubMenu(SubMenuBuilder menu) { + Callback callback = getCallback(); + if (callback != null) callback.onPanelClosed(mFeatureId, menu.getRootMenu()); + } + + public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { + Callback callback = getCallback(); + return (callback != null) && callback.onMenuItemSelected(mFeatureId, item); + + } + + public void onMenuModeChange(MenuBuilder menu) { + } + + public boolean onSubMenuSelected(SubMenuBuilder subMenu) { + // Set a simple callback for the submenu + subMenu.setCallback(this); + + // The window manager will give us a valid window token + new MenuDialogHelper(subMenu).show(null); + + return true; + } + } +} diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java new file mode 100644 index 000000000000..250d2d40e531 --- /dev/null +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -0,0 +1,1409 @@ +/* + * Copyright (C) 2006 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 android.app.Activity; +import android.app.ActivityManagerNative; +import android.app.IActivityManager; +import android.app.IStatusBar; +import android.content.BroadcastReceiver; +import android.content.ContentQueryMap; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.database.Cursor; +import android.graphics.Rect; +import android.os.Handler; +import android.os.IBinder; +import android.os.LocalPowerManager; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.provider.Settings; +import static android.provider.Settings.System.END_BUTTON_BEHAVIOR; + +import com.android.internal.policy.PolicyManager; +import com.android.internal.telephony.ITelephony; +import android.util.Config; +import android.util.EventLog; +import android.util.Log; +import android.view.IWindowManager; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.OrientationListener; +import android.view.RawInputEvent; +import android.view.Surface; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.Window; +import android.view.WindowManager; +import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; +import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; +import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; +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_KEYGUARD; +import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_PHONE; +import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE; +import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_TOAST; +import android.view.WindowManagerImpl; +import android.view.WindowManagerPolicy; +import android.media.IAudioService; +import android.media.AudioManager; + +import java.util.Observable; +import java.util.Observer; + +/** + * WindowManagerPolicy implementation for the Android phone UI. + */ +public class PhoneWindowManager implements WindowManagerPolicy { + private static final String TAG = "WindowManager"; + private static final boolean DEBUG = false; + private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; + private static final boolean SHOW_STARTING_ANIMATIONS = true; + private static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; + + private static final int APPLICATION_LAYER = 1; + private static final int PHONE_LAYER = 2; + private static final int SEARCH_BAR_LAYER = 3; + private static final int STATUS_BAR_PANEL_LAYER = 4; + // toasts and the plugged-in battery thing + private static final int TOAST_LAYER = 5; + private static final int STATUS_BAR_LAYER = 6; + // SIM errors and unlock. Not sure if this really should be in a high layer. + private static final int PRIORITY_PHONE_LAYER = 7; + // like the ANR / app crashed dialogs + private static final int SYSTEM_ALERT_LAYER = 8; + // system-level error dialogs + private static final int SYSTEM_ERROR_LAYER = 9; + // the keyguard; nothing on top of these can take focus, since they are + // responsible for power management when displayed. + private static final int KEYGUARD_LAYER = 10; + private static final int KEYGUARD_DIALOG_LAYER = 11; + // things in here CAN NOT take focus, but are shown on top of everything else. + private static final int SYSTEM_OVERLAY_LAYER = 12; + + private static final int APPLICATION_PANEL_SUBLAYER = 1; + private static final int APPLICATION_MEDIA_SUBLAYER = -1; + private static final int APPLICATION_SUB_PANEL_SUBLAYER = 2; + + private static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f; + + static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; + static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; + static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; + + private Context mContext; + private IWindowManager mWindowManager; + private LocalPowerManager mPowerManager; + + /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ + private boolean mEnableShiftMenuBugReports = false; + + private WindowState mStatusBar = null; + private WindowState mSearchBar = null; + private WindowState mKeyguard = null; + private KeyguardViewMediator mKeyguardMediator; + private GlobalActions mGlobalActions; + private boolean mShouldTurnOffOnKeyUp; + private RecentApplicationsDialog mRecentAppsDialog; + private Handler mHandler; + + private boolean mLidOpen; + private int mSensorOrientation = OrientationListener.ORIENTATION_UNKNOWN; + private int mSensorRotation = -1; + private boolean mScreenOn = false; + private boolean mOrientationSensorEnabled = false; + private int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + + private int mW, mH; + private int mCurLeft, mCurTop, mCurRight, mCurBottom; + private WindowState mTopFullscreenOpaqueWindowState; + private boolean mForceStatusBar; + private boolean mHomePressed; + private Intent mHomeIntent; + private boolean mSearchKeyPressed; + private boolean mConsumeSearchKeyUp; + + private static final int ENDCALL_HOME = 0x1; + private static final int ENDCALL_SLEEPS = 0x2; + private static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; + private int mEndcallBehavior; + + private ShortcutManager mShortcutManager; + private PowerManager.WakeLock mBroadcastWakeLock; + + private class SettingsObserver implements Observer { + private ContentQueryMap mSettings; + + void observe() { + ContentResolver resolver = mContext.getContentResolver(); + Cursor settingsCursor = resolver.query(Settings.System.CONTENT_URI, null, + Settings.System.NAME + "=?", + new String[] { END_BUTTON_BEHAVIOR}, + null); + mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mHandler); + mSettings.addObserver(this); + + // pretend that the settings changed so we will get their initial state + update(mSettings, null); + } + + private int getInt(String name, int def) { + ContentValues row = mSettings.getValues(name); + if (row != null) { + Integer ret = row.getAsInteger(Settings.System.VALUE); + if(ret == null) { + return def; + } + return ret; + } else { + return def; + } + } + + public void update(Observable o, Object arg) { + mEndcallBehavior = getInt(END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); + } + } + + private class MyOrientationListener extends OrientationListener { + + MyOrientationListener(Context context) { + super(context); + } + + @Override + public void onOrientationChanged(int orientation) { + // ignore orientation changes unless the value is in a range that + // matches portrait or landscape + // portrait range is 270+45 to 359 and 0 to 45 + // landscape range is 270-45 to 270+45 + if ((orientation >= 0 && orientation <= 45) || (orientation >= 270 - 45)) { + mSensorOrientation = orientation; + int rotation = (orientation >= 270 - 45 + && orientation <= 270 + 45) + ? Surface.ROTATION_90 : Surface.ROTATION_0; + if (rotation != mSensorRotation) { + if(localLOGV) Log.i(TAG, "onOrientationChanged, rotation changed from "+rotation+" to "+mSensorRotation); + // Update window manager. The lid rotation hasn't changed, + // but we want it to re-evaluate the final rotation in case + // it needs to call back and get the sensor orientation. + mSensorRotation = rotation; + try { + mWindowManager.setRotation(USE_LAST_ROTATION, false); + } catch (RemoteException e) { + // Ignore + } + } + } + } + } + private MyOrientationListener mOrientationListener; + + /* + * Various use cases for invoking this function + * screen turning off, should always disable listeners if already enabled + * screen turned on and current app has sensor based orientation, enable listeners + * if not already enabled + * screen turned on and current app does not have sensor orientation, disable listeners if + * already enabled + * screen turning on and current app has sensor based orientation, enable listeners if needed + * screen turning on and current app has nosensor based orientation, do nothing + */ + private void updateOrientationListener() { + //Could have been invoked due to screen turning on or off or + //change of the currently visible window's orientation + if(localLOGV) Log.i(TAG, "Screen status="+mScreenOn+ + ", current orientation="+mCurrentAppOrientation+ + ", SensorEnabled="+mOrientationSensorEnabled); + boolean disable = true; + if(mScreenOn) { + if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { + disable = false; + //enable listener if not already enabled + if(!mOrientationSensorEnabled) { + mOrientationListener.enable(); + if(localLOGV) Log.i(TAG, "Enabling listeners"); + mOrientationSensorEnabled = true; + } + } + } + //check if sensors need to be disabled + if(disable && mOrientationSensorEnabled) { + mOrientationListener.disable(); + if(localLOGV) Log.i(TAG, "Disabling listeners"); + mOrientationSensorEnabled = false; + } + } + + private Runnable mEndCallLongPress = new Runnable() { + public void run() { + mShouldTurnOffOnKeyUp = false; + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); + showGlobalActionsDialog(); + } + }; + + private void showGlobalActionsDialog() { + if (mGlobalActions == null) { + mGlobalActions = new GlobalActions(mContext, mPowerManager); + } + final boolean keyguardShowing = mKeyguardMediator.isShowing(); + mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); + if (keyguardShowing) { + // since it took two seconds of long press to bring this up, + // poke the wake lock so they have some time to see the dialog. + mKeyguardMediator.pokeWakelock(); + } + } + + private boolean isDeviceProvisioned() { + return Settings.System.getInt( + mContext.getContentResolver(), Settings.System.DEVICE_PROVISIONED, 0) != 0; + } + + /** + * When a home-key longpress expires, close other system windows and launch the recent apps + */ + private Runnable mHomeLongPress = new Runnable() { + public void run() { + /* + * Eat the longpress so it won't dismiss the recent apps dialog when + * the user lets go of the home key + */ + mHomePressed = false; + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS); + showRecentAppsDialog(); + } + }; + + /** + * Create (if necessary) and launch the recent apps dialog + */ + private void showRecentAppsDialog() { + if (mRecentAppsDialog == null) { + mRecentAppsDialog = new RecentApplicationsDialog(mContext); + } + mRecentAppsDialog.show(); + } + + /** {@inheritDoc} */ + public void init(Context context, IWindowManager windowManager, + LocalPowerManager powerManager) { + mContext = context; + mWindowManager = windowManager; + mPowerManager = powerManager; + mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager); + mHandler = new Handler(); + mOrientationListener = new MyOrientationListener(mContext); + SettingsObserver settingsObserver = new SettingsObserver(); + settingsObserver.observe(); + mShortcutManager = new ShortcutManager(context, mHandler); + mShortcutManager.observe(); + mHomeIntent = new Intent(Intent.ACTION_MAIN, null); + mHomeIntent.addCategory(Intent.CATEGORY_HOME); + mHomeIntent.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"); + mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); + } + + /** {@inheritDoc} */ + public int checkAddPermission(WindowManager.LayoutParams attrs) { + int type = attrs.type; + if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW + || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { + return WindowManagerImpl.ADD_OKAY; + } + String permission = null; + switch (type) { + case TYPE_TOAST: + // XXX right now the app process has complete control over + // this... should introduce a token to let the system + // monitor/control what they are doing. + break; + case TYPE_PHONE: + case TYPE_PRIORITY_PHONE: + case TYPE_SYSTEM_ALERT: + case TYPE_SYSTEM_ERROR: + case TYPE_SYSTEM_OVERLAY: + permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW; + break; + default: + permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; + } + if (permission != null) { + if (mContext.checkCallingOrSelfPermission(permission) + != PackageManager.PERMISSION_GRANTED) { + return WindowManagerImpl.ADD_PERMISSION_DENIED; + } + } + return WindowManagerImpl.ADD_OKAY; + } + + public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) { + switch (attrs.type) { + case TYPE_SYSTEM_OVERLAY: + case TYPE_TOAST: + // These types of windows can't receive input events. + attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + break; + } + } + + private void readLidState() { + try { + int sw = mWindowManager.getSwitchState(0); + if (sw >= 0) { + mLidOpen = sw == 0; + } + } catch (RemoteException e) { + // Ignore + } + } + + /** {@inheritDoc} */ + public void adjustConfigurationLw(Configuration config) { + readLidState(); + mPowerManager.setKeyboardVisibility(mLidOpen); + config.keyboardHidden = mLidOpen + ? Configuration.KEYBOARDHIDDEN_NO + : Configuration.KEYBOARDHIDDEN_YES; + if (keyguardIsShowingTq()) { + if (mLidOpen) { + // only do this if it's opening -- closing the device shouldn't turn it + // off, but it also shouldn't turn it on. + mKeyguardMediator.pokeWakelock(); + } + } else { + mPowerManager.userActivity(SystemClock.uptimeMillis(), false, + LocalPowerManager.OTHER_EVENT); + } + } + + public boolean isCheekPressedAgainstScreen(MotionEvent ev) { + if(ev.getSize() > SLIDE_TOUCH_EVENT_SIZE_LIMIT) { + return true; + } + int size = ev.getHistorySize(); + for(int i = 0; i < size; i++) { + if(ev.getHistoricalSize(i) > SLIDE_TOUCH_EVENT_SIZE_LIMIT) { + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public int windowTypeToLayerLw(int type) { + if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) { + return APPLICATION_LAYER; + } + switch (type) { + case TYPE_APPLICATION_PANEL: + return APPLICATION_LAYER; + case TYPE_APPLICATION_SUB_PANEL: + return APPLICATION_LAYER; + case TYPE_STATUS_BAR: + return STATUS_BAR_LAYER; + case TYPE_STATUS_BAR_PANEL: + return STATUS_BAR_PANEL_LAYER; + case TYPE_SEARCH_BAR: + return SEARCH_BAR_LAYER; + case TYPE_PHONE: + return PHONE_LAYER; + case TYPE_KEYGUARD: + return KEYGUARD_LAYER; + case TYPE_KEYGUARD_DIALOG: + return KEYGUARD_DIALOG_LAYER; + case TYPE_SYSTEM_ALERT: + return SYSTEM_ALERT_LAYER; + case TYPE_SYSTEM_ERROR: + return SYSTEM_ERROR_LAYER; + case TYPE_SYSTEM_OVERLAY: + return SYSTEM_OVERLAY_LAYER; + case TYPE_PRIORITY_PHONE: + return PRIORITY_PHONE_LAYER; + case TYPE_TOAST: + return TOAST_LAYER; + } + Log.e(TAG, "Unknown window type: " + type); + return APPLICATION_LAYER; + } + + /** {@inheritDoc} */ + public int subWindowTypeToLayerLw(int type) { + switch (type) { + case TYPE_APPLICATION_PANEL: + return APPLICATION_PANEL_SUBLAYER; + case TYPE_APPLICATION_MEDIA: + return APPLICATION_MEDIA_SUBLAYER; + case TYPE_APPLICATION_SUB_PANEL: + return APPLICATION_SUB_PANEL_SUBLAYER; + } + Log.e(TAG, "Unknown sub-window type: " + type); + return 0; + } + + /** {@inheritDoc} */ + public View addStartingWindow(IBinder appToken, String packageName, + int theme, CharSequence nonLocalizedLabel, + int labelRes, int icon) { + if (!SHOW_STARTING_ANIMATIONS) { + return null; + } + if (packageName == null) { + return null; + } + + Context context = mContext; + boolean setTheme = false; + //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel=" + // + nonLocalizedLabel + " theme=" + Integer.toHexString(theme)); + if (theme != 0 || labelRes != 0) { + try { + context = context.createPackageContext(packageName, 0); + if (theme != 0) { + context.setTheme(theme); + setTheme = true; + } + } catch (PackageManager.NameNotFoundException e) { + // Ignore + } + } + if (!setTheme) { + context.setTheme(com.android.internal.R.style.Theme); + } + + Window win = PolicyManager.makeNewWindow(context); + Resources r = context.getResources(); + win.setTitle(r.getText(labelRes, nonLocalizedLabel)); + + win.setType( + WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); + win.setFlags( + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); + + win.setLayout(WindowManager.LayoutParams.FILL_PARENT, + WindowManager.LayoutParams.FILL_PARENT); + + final WindowManager.LayoutParams params = win.getAttributes(); + params.token = appToken; + params.packageName = packageName; + params.windowAnimations = win.getWindowStyle().getResourceId( + com.android.internal.R.styleable.Window_windowAnimationStyle, 0); + params.setTitle("Starting " + packageName); + + try { + WindowManagerImpl wm = (WindowManagerImpl) + context.getSystemService(Context.WINDOW_SERVICE); + View view = win.getDecorView(); + + if (win.isFloating()) { + // Whoops, there is no way to display an animation/preview + // of such a thing! After all that work... let's skip it. + // (Note that we must do this here because it is in + // getDecorView() where the theme is evaluated... maybe + // we should peek the floating attribute from the theme + // earlier.) + return null; + } + + if (localLOGV) Log.v( + TAG, "Adding starting window for " + packageName + + " / " + appToken + ": " + + (view.getParent() != null ? view : null)); + + wm.addView(view, params); + + // Only return the view if it was successfully added to the + // window manager... which we can tell by it having a parent. + return view.getParent() != null ? view : null; + } catch (WindowManagerImpl.BadTokenException e) { + // ignore + Log.w(TAG, appToken + " already running, starting window not displayed"); + } + + return null; + } + + /** {@inheritDoc} */ + public void removeStartingWindow(IBinder appToken, View window) { + // RuntimeException e = new RuntimeException(); + // Log.i(TAG, "remove " + appToken + " " + window, e); + + if (localLOGV) Log.v( + TAG, "Removing starting window for " + appToken + ": " + window); + + if (window != null) { + WindowManagerImpl wm = (WindowManagerImpl) mContext.getSystemService(Context.WINDOW_SERVICE); + wm.removeView(window); + } + } + + /** + * Preflight adding a window to the system. + * + * Currently enforces that three window types are singletons: + * + * + * @param win The window to be added + * @param attrs Information about the window to be added + * + * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, WindowManagerImpl.ADD_MULTIPLE_SINGLETON + */ + public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) { + switch (attrs.type) { + case TYPE_STATUS_BAR: + if (mStatusBar != null) { + return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; + } + mStatusBar = win; + break; + case TYPE_SEARCH_BAR: + if (mSearchBar != null) { + return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; + } + mSearchBar = win; + break; + case TYPE_KEYGUARD: + if (mKeyguard != null) { + return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; + } + mKeyguard = win; + break; + } + return WindowManagerImpl.ADD_OKAY; + } + + /** {@inheritDoc} */ + public void removeWindowLw(WindowState win) { + if (mStatusBar == win) { + mStatusBar = null; + } + else if (mSearchBar == win) { + mSearchBar = null; + } + else if (mKeyguard == win) { + mKeyguard = null; + } + } + + private static final boolean PRINT_ANIM = false; + + /** {@inheritDoc} */ + public int selectAnimationLw(WindowState win, int transit) { + if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win + + ": transit=" + transit); + if (transit == TRANSIT_PREVIEW_DONE) { + if (win.hasAppShownWindows()) { + if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT"); + return com.android.internal.R.anim.app_starting_exit; + } + } + + return 0; + } + + private static ITelephony getPhoneInterface() { + return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE)); + } + + private static IAudioService getAudioInterface() { + return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE)); + } + + private boolean keyguardOn() { + return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode(); + } + + /** {@inheritDoc} */ + public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, + int repeatCount) { + boolean keyguardOn = keyguardOn(); + + if (false) { + Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount=" + + repeatCount + " keyguardOn=" + keyguardOn); + } + + // Clear a pending HOME longpress if the user releases Home + // TODO: This could probably be inside the next bit of logic, but that code + // turned out to be a bit fragile so I'm doing it here explicitly, for now. + if ((code == KeyEvent.KEYCODE_HOME) && !down) { + mHandler.removeCallbacks(mHomeLongPress); + } + + // If the HOME button is currently being held, then we do special + // chording with it. + if (mHomePressed) { + + // If we have released the home key, and didn't do anything else + // while it was pressed, then it is time to go home! + if (code == KeyEvent.KEYCODE_HOME) { + if (!down) { + mHomePressed = false; + + // If an incoming call is ringing, HOME is totally disabled. + // (The user is already on the InCallScreen at this point, + // and his ONLY options are to answer or reject the call.) + boolean incomingRinging = false; + try { + ITelephony phoneServ = getPhoneInterface(); + if (phoneServ != null) { + incomingRinging = phoneServ.isRinging(); + } else { + Log.w(TAG, "Unable to find ITelephony interface"); + } + } catch (RemoteException ex) { + Log.w(TAG, "RemoteException from getPhoneInterface()", ex); + } + + if (incomingRinging) { + Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); + } else { + launchHomeFromHotKey(); + } + } + } + + return true; + } + + // First we always handle the home key here, so applications + // can never break it, although if keyguard is on, we do let + // it handle it, because that gives us the correct 5 second + // timeout. + if (code == KeyEvent.KEYCODE_HOME) { + + // If a system window has focus, then it doesn't make sense + // right now to interact with applications. + WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null; + if (attrs != null) { + int type = attrs.type; + if (type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW + && type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { + // Only do this once, so home-key-longpress doesn't close itself + if (repeatCount == 0 && down) { + sendCloseSystemWindows(); + } + return false; + } + } + + if (down && repeatCount == 0) { + if (!keyguardOn) { + mHandler.postDelayed(mHomeLongPress, ViewConfiguration.getGlobalActionKeyTimeout()); + } + mHomePressed = true; + } + return true; + } else if (code == KeyEvent.KEYCODE_MENU) { + // Hijack modified menu keys for debugging features + final int chordBug = KeyEvent.META_SHIFT_ON; + + if (down && repeatCount == 0) { + if (mEnableShiftMenuBugReports && (metaKeys & chordBug) == chordBug) { + Intent intent = new Intent(Intent.ACTION_BUG_REPORT); + mContext.sendOrderedBroadcast(intent, null); + return true; + } else if (SHOW_PROCESSES_ON_ALT_MENU && + (metaKeys & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) { + Intent service = new Intent(); + service.setClassName(mContext, "com.android.server.LoadAverageService"); + ContentResolver res = mContext.getContentResolver(); + boolean shown = Settings.System.getInt( + res, Settings.System.SHOW_PROCESSES, 0) != 0; + if (!shown) { + mContext.startService(service); + } else { + mContext.stopService(service); + } + Settings.System.putInt( + res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1); + return true; + } + } + } else if (code == KeyEvent.KEYCODE_NOTIFICATION) { + if (down) { + // this key doesn't exist on current hardware, but if a device + // didn't have a touchscreen, it would want one of these to open + // the status bar. + IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar")); + if (sbs != null) { + try { + sbs.toggle(); + } catch (RemoteException e) { + // we're screwed anyway, since it's in this process + throw new RuntimeException(e); + } + } + } + return true; + } else if (code == KeyEvent.KEYCODE_SEARCH) { + if (down) { + if (repeatCount == 0) { + mSearchKeyPressed = true; + } + } else { + mSearchKeyPressed = false; + + if (mConsumeSearchKeyUp) { + // Consume the up-event + mConsumeSearchKeyUp = false; + return true; + } + } + } + + // Shortcuts are invoked through Search+key, so intercept those here + if (mSearchKeyPressed) { + if (down && repeatCount == 0 && !keyguardOn) { + Intent shortcutIntent = mShortcutManager.getIntent(code, metaKeys); + if (shortcutIntent != null) { + shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(shortcutIntent); + + /* + * We launched an app, so the up-event of the search key + * should be consumed + */ + mConsumeSearchKeyUp = true; + return true; + } + } + } + + return false; + } + + /** + * A home key -> launch home action was detected. Take the appropriate action + * given the situation with the keyguard. + */ + private void launchHomeFromHotKey() { + if (mKeyguardMediator.isShowing()) { + // don't launch home if keyguard showing + } else if (mKeyguardMediator.isInputRestricted()) { + // when in keyguard restricted mode, must first verify unlock + // before launching home + mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() { + public void onKeyguardExitResult(boolean success) { + if (success) { + mContext.startActivity(mHomeIntent); + sendCloseSystemWindows(); + } + } + }); + } else { + // no keyguard stuff to worry about, just launch home! + mContext.startActivity(mHomeIntent); + sendCloseSystemWindows(); + } + } + + public void getCoveredInsetHintLw(WindowManager.LayoutParams attrs, Rect coveredInset) { + final int fl = attrs.flags; + + if ((fl & + (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) + == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { + coveredInset.set(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom); + } else { + coveredInset.setEmpty(); + } + } + + /** {@inheritDoc} */ + public void beginLayoutLw(int displayWidth, int displayHeight) { + mW = displayWidth; + mH = displayHeight; + mCurLeft = 0; + mCurTop = 0; + mCurRight = displayWidth; + mCurBottom = displayHeight; + + // decide where the status bar goes ahead of time + if (mStatusBar != null) { + mStatusBar.computeFrameLw(0, 0, displayWidth, displayHeight, + 0, 0, displayWidth, displayHeight); + mCurTop = mStatusBar.getFrameLw().bottom; + } + } + + /** {@inheritDoc} */ + public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached) { + // we've already done the status bar + if (win == mStatusBar) { + return; + } + + final int fl = attrs.flags; + + int dl, dt, dr, db; + if ((fl & FLAG_LAYOUT_IN_SCREEN) == 0) { + // Make sure this window doesn't intrude into the status bar. + dl = mCurLeft; + dt = mCurTop; + dr = mCurRight; + db = mCurBottom; + } else { + dl = 0; + dt = 0; + dr = mW; + db = mH; + } + + if ((fl & + (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) + == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { + win.setCoveredInsetsLw(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom); + } else { + win.setCoveredInsetsLw(0, 0, 0, 0); + } + + int pl, pt, pr, pb; + if (attached != null && (fl & (FLAG_LAYOUT_IN_SCREEN)) == 0) { + final Rect r = attached.getFrameLw(); + pl = r.left; + pt = r.top; + pr = r.right; + pb = r.bottom; + } else { + pl = dl; + pt = dt; + pr = dr; + pb = db; + } + + if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) { + dl = -100000; + dt = -100000; + dr = 100000; + db = 100000; + } + + win.computeFrameLw(pl, pt, pr, pb, dl, dt, dr, db); + } + + /** {@inheritDoc} */ + public void finishLayoutLw() { + } + + /** {@inheritDoc} */ + public void beginAnimationLw(int displayWidth, int displayHeight) { + mTopFullscreenOpaqueWindowState = null; + mForceStatusBar = false; + } + + /** {@inheritDoc} */ + public void animatingWindowLw(WindowState win, + WindowManager.LayoutParams attrs) { + if (mTopFullscreenOpaqueWindowState == null + && attrs.type >= FIRST_APPLICATION_WINDOW + && attrs.type <= LAST_APPLICATION_WINDOW + && win.fillsScreenLw(mW, mH, true) + && win.isDisplayedLw()) { + mTopFullscreenOpaqueWindowState = win; + } else if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { + mForceStatusBar = true; + } + } + + /** {@inheritDoc} */ + public boolean finishAnimationLw() { + if (mStatusBar != null) { + if (mForceStatusBar) { + mStatusBar.showLw(); + } else if (mTopFullscreenOpaqueWindowState != null) { + WindowManager.LayoutParams lp = + mTopFullscreenOpaqueWindowState.getAttrs(); + boolean hideStatusBar = + (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; + if (hideStatusBar) { + mStatusBar.hideLw(); + } else { + mStatusBar.showLw(); + } + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean preprocessInputEventTq(RawInputEvent event) { + switch (event.type) { + case RawInputEvent.EV_SW: + if (event.keycode == 0) { + // lid changed state + mLidOpen = event.value == 0; + updateRotation(); + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean isAppSwitchKeyTqTiLwLi(int keycode) { + return keycode == KeyEvent.KEYCODE_HOME + || keycode == KeyEvent.KEYCODE_ENDCALL; + } + + /** {@inheritDoc} */ + public boolean isMovementKeyTi(int keycode) { + switch (keycode) { + case KeyEvent.KEYCODE_DPAD_UP: + case KeyEvent.KEYCODE_DPAD_DOWN: + case KeyEvent.KEYCODE_DPAD_LEFT: + case KeyEvent.KEYCODE_DPAD_RIGHT: + return true; + } + return false; + } + + + /** + * @return Whether a telephone call is in progress right now. + */ + private boolean isInCall() { + final ITelephony phone = getPhoneInterface(); + if (phone == null) { + Log.w(TAG, "couldn't get ITelephony reference"); + return false; + } + try { + return phone.isOffhook(); + } catch (RemoteException e) { + Log.w(TAG, "ITelephony.isOffhhook threw RemoteException " + e); + return false; + } + } + + /** + * @return Whether music is being played right now. + */ + private boolean isMusicActive() { + final IAudioService audio = getAudioInterface(); + if (audio == null) { + Log.w(TAG, "isMusicActive: couldn't get IAudioService reference"); + return false; + } + try { + return audio.isMusicActive(); + } catch (RemoteException e) { + Log.w(TAG, "IAudioService.isMusicActive() threw RemoteException " + e); + return false; + } + } + + /** + * Tell the audio service to adjust the volume appropriate to the event. + * @param keycode + */ + private void sendVolToMusic(int keycode) { + final IAudioService audio = getAudioInterface(); + if (audio == null) { + Log.w(TAG, "sendVolToMusic: couldn't get IAudioService reference"); + return; + } + try { + // since audio is playing, we shouldn't have to hold a wake lock + // during the call, but we do it as a precaution for the rare possibility + // that the music stops right before we call this + mBroadcastWakeLock.acquire(); + audio.adjustStreamVolume( + AudioManager.STREAM_MUSIC, + keycode == KeyEvent.KEYCODE_VOLUME_UP + ? AudioManager.ADJUST_RAISE + : AudioManager.ADJUST_LOWER, + 0); + } catch (RemoteException e) { + Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e); + } finally { + mBroadcastWakeLock.release(); + } + } + + /** {@inheritDoc} */ + public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) { + int result = ACTION_PASS_TO_USER; + final boolean isWakeKey = isWakeKeyTq(event); + final boolean keyguardShowing = keyguardIsShowingTq(); + + if (keyguardShowing) { + if (screenIsOn) { + // when the screen is on, always give the event to the keyguard + result |= ACTION_PASS_TO_USER; + } else { + // otherwise, don't pass it to the user + result &= ~ACTION_PASS_TO_USER; + + final boolean isKeyDown = + (event.type == RawInputEvent.EV_KEY) && (event.value != 0); + if (isWakeKey && isKeyDown) { + + // tell the mediator about a wake key, it may decide to + // turn on the screen depending on whether the key is + // appropriate. + if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode) + && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN + || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) { + if (isInCall()) { + // if the keyguard didn't wake the device, we are in call, and + // it is a volume key, turn on the screen so that the user + // can more easily adjust the in call volume. + mKeyguardMediator.pokeWakelock(); + } else if (isMusicActive()) { + // when keyguard is showing and screen off, we need + // to handle the volume key for music here + sendVolToMusic(event.keycode); + } + } + } + } + } else if (!screenIsOn) { + if (isWakeKey) { + // a wake key has a sole purpose of waking the device; don't pass + // it to the user + result |= ACTION_POKE_USER_ACTIVITY; + result &= ~ACTION_PASS_TO_USER; + } + } + + int type = event.type; + int code = event.keycode; + boolean down = event.value != 0; + + if (type == RawInputEvent.EV_KEY) { + if (code == KeyEvent.KEYCODE_ENDCALL) { + if (down) { + boolean hungUp = false; + // key repeats are generated by the window manager, and we don't see them + // here, so unless the driver is doing something it shouldn't be, we know + // this is the real press event. + try { + ITelephony phoneServ = getPhoneInterface(); + if (phoneServ != null) { + hungUp = phoneServ.endCall(); + } else { + Log.w(TAG, "!!! Unable to find ITelephony interface !!!"); + } + } catch (RemoteException ex) { + Log.w(TAG, "ITelephony.endCall() threw RemoteException" + ex); + } + if (hungUp || !screenIsOn) { + mShouldTurnOffOnKeyUp = false; + } else { + // only try to turn off the screen if we didn't already hang up + mShouldTurnOffOnKeyUp = true; + mHandler.postDelayed(mEndCallLongPress, + ViewConfiguration.getGlobalActionKeyTimeout()); + result &= ~ACTION_PASS_TO_USER; + } + } else { + mHandler.removeCallbacks(mEndCallLongPress); + if (mShouldTurnOffOnKeyUp) { + mShouldTurnOffOnKeyUp = false; + boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0; + boolean sleeps = (mEndcallBehavior & ENDCALL_SLEEPS) != 0; + if (keyguardShowing + || (sleeps && !gohome) + || (gohome && !goHome() && sleeps)) { + // they must already be on the keyguad or home screen, + // go to sleep instead + Log.d(TAG, "I'm tired mEndcallBehavior=0x" + + Integer.toHexString(mEndcallBehavior)); + result &= ~ACTION_POKE_USER_ACTIVITY; + result |= ACTION_GO_TO_SLEEP; + } + result &= ~ACTION_PASS_TO_USER; + } + } + } else if (code == KeyEvent.KEYCODE_HEADSETHOOK) { + // This key needs to be handled even if the screen is off. + // If others need to be handled while it's off, this is a reasonable + // pattern to follow. + if ((result & ACTION_PASS_TO_USER) == 0) { + // Only do this if we would otherwise not pass it to the user. In that + // case, the PhoneWindow class will do the same thing, except it will + // only do it if the showing app doesn't process the key on its own. + KeyEvent keyEvent = new KeyEvent(event.when, event.when, + down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP, + KeyEvent.KEYCODE_HEADSETHOOK, 0); + mBroadcastWakeLock.acquire(); + mHandler.post(new PassHeadsetKey(keyEvent)); + } + } + } + + return result; + } + + class PassHeadsetKey implements Runnable { + KeyEvent mKeyEvent; + + PassHeadsetKey(KeyEvent keyEvent) { + mKeyEvent = keyEvent; + } + + public void run() { + Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent); + mContext.sendOrderedBroadcast(intent, null, mBroadcastDone, + mHandler, Activity.RESULT_OK, null, null); + } + } + + private BroadcastReceiver mBroadcastDone = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + mBroadcastWakeLock.release(); + } + }; + + /** {@inheritDoc} */ + public boolean isWakeRelMovementTq(int device, int classes, + RawInputEvent event) { + // if it's tagged with one of the wake bits, it wakes up the device + return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0); + } + + /** {@inheritDoc} */ + public boolean isWakeAbsMovementTq(int device, int classes, + RawInputEvent event) { + // if it's tagged with one of the wake bits, it wakes up the device + return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0); + } + + /** + * Given the current state of the world, should this key wake up the device? + */ + protected boolean isWakeKeyTq(RawInputEvent event) { + // There are not key maps for trackball devices, but we'd still + // like to have pressing it wake the device up, so force it here. + int keycode = event.keycode; + int flags = event.flags; + if (keycode == RawInputEvent.BTN_MOUSE) { + flags |= WindowManagerPolicy.FLAG_WAKE; + } + return (flags + & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; + } + + /** {@inheritDoc} */ + public void screenTurnedOff(int why) { + EventLog.writeEvent(70000, 0); + mKeyguardMediator.onScreenTurnedOff(why); + mScreenOn = false; + updateOrientationListener(); + } + + /** {@inheritDoc} */ + public void screenTurnedOn() { + EventLog.writeEvent(70000, 1); + mKeyguardMediator.onScreenTurnedOn(); + mScreenOn = true; + updateOrientationListener(); + } + + /** {@inheritDoc} */ + public void enableKeyguard(boolean enabled) { + mKeyguardMediator.setKeyguardEnabled(enabled); + } + + /** {@inheritDoc} */ + public void exitKeyguardSecurely(OnKeyguardExitResult callback) { + mKeyguardMediator.verifyUnlock(callback); + } + + /** {@inheritDoc} */ + public boolean keyguardIsShowingTq() { + return mKeyguardMediator.isShowing(); + } + + /** {@inheritDoc} */ + public boolean inKeyguardRestrictedKeyInputMode() { + return mKeyguardMediator.isInputRestricted(); + } + + /** + * Callback from {@link KeyguardViewMediator} + */ + public void onKeyguardShow() { + sendCloseSystemWindows(); + } + + private void sendCloseSystemWindows() { + sendCloseSystemWindows(null); + } + + private void sendCloseSystemWindows(String reason) { + Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + if (reason != null) { + intent.putExtra(SYSTEM_DIALOG_REASON_KEY, reason); + } + mContext.sendBroadcast(intent); + } + + public int rotationForOrientation(int orientation) { + switch (orientation) { + case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: + //always return landscape if orientation set to landscape + return Surface.ROTATION_90; + case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: + //always return portrait if orientation set to portrait + return Surface.ROTATION_0; + case ActivityInfo.SCREEN_ORIENTATION_SENSOR: + if(mOrientationSensorEnabled) { + //consider only sensor based orientation keyboard slide ignored + return mSensorRotation >= 0 ? mSensorRotation : Surface.ROTATION_0; + } + //if orientation sensor is disabled fall back to default behaviour + //based on lid + } + // case for nosensor meaning ignore sensor and consider only lid + // or orientation sensor disabled + //or case.unspecified + if(mLidOpen) { + return Surface.ROTATION_90; + } else { + return Surface.ROTATION_0; + } + } + + /** {@inheritDoc} */ + public void systemReady() { + try { + int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU); + Log.i(TAG, "Menu key state: " + menuState); + if (menuState > 0) { + // If the user is holding the menu key code, then we are + // going to boot into safe mode. + ActivityManagerNative.getDefault().enterSafeMode(); + } else { + // tell the keyguard + mKeyguardMediator.onSystemReady(); + android.os.SystemProperties.set("dev.bootcomplete", "1"); + } + } catch (RemoteException e) { + // Ignore + } + } + + /** {@inheritDoc} */ + public void enableScreenAfterBoot() { + readLidState(); + updateRotation(); + } + + private void updateRotation() { + mPowerManager.setKeyboardVisibility(mLidOpen); + int rotation= Surface.ROTATION_0; + if (mLidOpen) { + // always use landscape if lid is open + rotation = Surface.ROTATION_90; + } + //if lid is closed orientation will be portrait + try { + //set orientation on WindowManager + mWindowManager.setRotation(rotation, true); + } catch (RemoteException e) { + // Ignore + } + if (keyguardIsShowingTq()) { + if (mLidOpen) { + // only do this if it's opening -- closing the device shouldn't turn it + // off, but it also shouldn't turn it on. + mKeyguardMediator.pokeWakelock(); + } + } else { + // Light up the keyboard if we are sliding up. + if (mLidOpen) { + mPowerManager.userActivity(SystemClock.uptimeMillis(), false, + LocalPowerManager.BUTTON_EVENT); + } else { + mPowerManager.userActivity(SystemClock.uptimeMillis(), false, + LocalPowerManager.OTHER_EVENT); + } + } + } + + /** + * goes to the home screen + * @return whether it did anything + */ + boolean goHome() { + if (false) { + // This code always brings home to the front. + mContext.startActivity(mHomeIntent); + } else { + // This code brings home to the front or, if it is already + // at the front, puts the device to sleep. + try { + int result = ActivityManagerNative.getDefault() + .startActivity(null, mHomeIntent, + mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()), + null, 0, null, null, 0, true /* onlyIfNeeded*/, false); + if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) { + return false; + } + } catch (RemoteException ex) { + // bummer, the activity manager, which is in this process, is dead + } + } + sendCloseSystemWindows(); + return true; + } + + public void setCurrentOrientation(int newOrientation) { + if(newOrientation != mCurrentAppOrientation) { + mCurrentAppOrientation = newOrientation; + updateOrientationListener(); + } + } +} diff --git a/policy/com/android/internal/policy/impl/Policy.java b/policy/com/android/internal/policy/impl/Policy.java new file mode 100644 index 000000000000..f537186766cd --- /dev/null +++ b/policy/com/android/internal/policy/impl/Policy.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008 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 android.content.Context; + +import com.android.internal.policy.IPolicy; +import com.android.internal.policy.impl.PhoneLayoutInflater; +import com.android.internal.policy.impl.PhoneWindow; +import com.android.internal.policy.impl.PhoneWindowManager; + +/** + * {@hide} + */ + +// Simple implementation of the policy interface that spawns the right +// set of objects +public class Policy implements IPolicy { + + public PhoneWindow makeNewWindow(Context context) { + return new PhoneWindow(context); + } + + public PhoneLayoutInflater makeNewLayoutInflater(Context context) { + return new PhoneLayoutInflater(context); + } + + public PhoneWindowManager makeNewWindowManager() { + return new PhoneWindowManager(); + } +} diff --git a/policy/com/android/internal/policy/impl/PowerDialog.java b/policy/com/android/internal/policy/impl/PowerDialog.java new file mode 100644 index 000000000000..ce9363e93fdb --- /dev/null +++ b/policy/com/android/internal/policy/impl/PowerDialog.java @@ -0,0 +1,177 @@ +/* + * 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.IServiceManager; +import android.os.LocalPowerManager; +import android.os.ServiceManager; +import android.os.ServiceManagerNative; +import android.os.SystemClock; +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); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + + 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.shutdownAfterDisablingRadio(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/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java new file mode 100644 index 000000000000..0c4a7dce17e9 --- /dev/null +++ b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2008 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 android.app.ActivityManager; +import android.app.Dialog; +import android.app.StatusBarManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.view.View.OnClickListener; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.List; + +public class RecentApplicationsDialog extends Dialog implements OnClickListener { + // Elements for debugging support +// private static final String LOG_TAG = "RecentApplicationsDialog"; + private static final boolean DBG_FORCE_EMPTY_LIST = false; + + static private StatusBarManager sStatusBar; + + private static final int NUM_BUTTONS = 6; + private static final int MAX_RECENT_TASKS = NUM_BUTTONS * 2; // allow for some discards + + final View[] mButtons = new View[NUM_BUTTONS]; + View mNoAppsText; + IntentFilter mBroadcastIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + + public RecentApplicationsDialog(Context context) { + super(context); + } + + /** + * We create the recent applications dialog just once, and it stays around (hidden) + * until activated by the user. + * + * @see PhoneWindowManager#showRecentAppsDialog + */ + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Context context = getContext(); + + if (sStatusBar == null) { + sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE); + } + + Window theWindow = getWindow(); + theWindow.requestFeature(Window.FEATURE_NO_TITLE); + theWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); + theWindow.setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + + setContentView(com.android.internal.R.layout.recent_apps_dialog); + + mButtons[0] = findViewById(com.android.internal.R.id.button1); + mButtons[1] = findViewById(com.android.internal.R.id.button2); + mButtons[2] = findViewById(com.android.internal.R.id.button3); + mButtons[3] = findViewById(com.android.internal.R.id.button4); + mButtons[4] = findViewById(com.android.internal.R.id.button5); + mButtons[5] = findViewById(com.android.internal.R.id.button6); + mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message); + + for (View b : mButtons) { + b.setOnClickListener(this); + } + } + + /** + * Handler for user clicks. If a button was clicked, launch the corresponding activity. + */ + public void onClick(View v) { + + for (View b : mButtons) { + if (b == v) { + // prepare a launch intent and send it + Intent intent = (Intent)b.getTag(); + intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); + getContext().startActivity(intent); + } + } + dismiss(); + } + + /** + * Set up and show the recent activities dialog. + */ + @Override + public void onStart() { + super.onStart(); + reloadButtons(); + if (sStatusBar != null) { + sStatusBar.disable(StatusBarManager.DISABLE_EXPAND); + } + + // receive broadcasts + getContext().registerReceiver(mBroadcastReceiver, mBroadcastIntentFilter); + } + + /** + * Dismiss the recent activities dialog. + */ + @Override + public void onStop() { + super.onStop(); + + // dump extra memory we're hanging on to + for (View b : mButtons) { + setButtonAppearance(b, null, null); + b.setTag(null); + } + + if (sStatusBar != null) { + sStatusBar.disable(StatusBarManager.DISABLE_NONE); + } + + // stop receiving broadcasts + getContext().unregisterReceiver(mBroadcastReceiver); + } + + /** + * Reload the 6 buttons with recent activities + */ + private void reloadButtons() { + + final Context context = getContext(); + final PackageManager pm = context.getPackageManager(); + final ActivityManager am = (ActivityManager) + context.getSystemService(Context.ACTIVITY_SERVICE); + final List recentTasks = + am.getRecentTasks(MAX_RECENT_TASKS, 0); + + ResolveInfo homeInfo = pm.resolveActivity( + new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME), + 0); + + // Performance note: Our android performance guide says to prefer Iterator when + // using a List class, but because we know that getRecentTasks() always returns + // an ArrayList<>, we'll use a simple index instead. + int button = 0; + int numTasks = recentTasks.size(); + for (int i = 0; i < numTasks && (button < NUM_BUTTONS); ++i) { + final ActivityManager.RecentTaskInfo info = recentTasks.get(i); + + // for debug purposes only, disallow first result to create empty lists + if (DBG_FORCE_EMPTY_LIST && (i == 0)) continue; + + Intent intent = new Intent(info.baseIntent); + if (info.origActivity != null) { + intent.setComponent(info.origActivity); + } + + // Skip the current home activity. + if (homeInfo != null) { + if (homeInfo.activityInfo.packageName.equals( + intent.getComponent().getPackageName()) + && homeInfo.activityInfo.name.equals( + intent.getComponent().getClassName())) { + continue; + } + } + + intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) + | Intent.FLAG_ACTIVITY_NEW_TASK); + final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0); + if (resolveInfo != null) { + final ActivityInfo activityInfo = resolveInfo.activityInfo; + final String title = activityInfo.loadLabel(pm).toString(); + final Drawable icon = activityInfo.loadIcon(pm); + + if (title != null && title.length() > 0 && icon != null) { + final View b = mButtons[button]; + setButtonAppearance(b, title, icon); + b.setTag(intent); + b.setVisibility(View.VISIBLE); + b.setPressed(false); + b.clearFocus(); + ++button; + } + } + } + + // handle the case of "no icons to show" + mNoAppsText.setVisibility((button == 0) ? View.VISIBLE : View.GONE); + + // hide the rest + for ( ; button < NUM_BUTTONS; ++button) { + mButtons[button].setVisibility(View.GONE); + } + } + + /** + * Adjust appearance of each icon-button + */ + private void setButtonAppearance(View theButton, final String theTitle, final Drawable icon) { + TextView tv = (TextView) theButton.findViewById(com.android.internal.R.id.label); + tv.setText(theTitle); + ImageView iv = (ImageView) theButton.findViewById(com.android.internal.R.id.icon); + iv.setImageDrawable(icon); + } + + /** + * This is the listener for the ACTION_CLOSE_SYSTEM_DIALOGS intent. It's an indication that + * we should close ourselves immediately, in order to allow a higher-priority UI to take over + * (e.g. phone call received). + * + * TODO: This is a really heavyweight solution for something that should be so simple. + * For example, we already have a handler, in our superclass, why aren't we sharing that? + * I think we need to investigate simplifying this entire methodology, or perhaps boosting + * it up into the Dialog class. + */ + private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { + String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY); + if (! PhoneWindowManager.SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) { + dismiss(); + } + } + } + }; +} diff --git a/policy/com/android/internal/policy/impl/ShortcutManager.java b/policy/com/android/internal/policy/impl/ShortcutManager.java new file mode 100644 index 000000000000..d86ac44cf87f --- /dev/null +++ b/policy/com/android/internal/policy/impl/ShortcutManager.java @@ -0,0 +1,120 @@ +/* + * 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 android.content.Context; +import android.content.Intent; +import android.database.ContentObserver; +import android.database.Cursor; +import android.os.Handler; +import android.provider.Settings; +import android.util.Log; +import android.util.SparseArray; +import android.view.KeyCharacterMap; + +import java.net.URISyntaxException; + +/** + * Manages quick launch shortcuts by: + *
  • Keeping the local copy in sync with the database (this is an observer) + *
  • Returning a shortcut-matching intent to clients + */ +class ShortcutManager extends ContentObserver { + + private static final String TAG = "ShortcutManager"; + + private static final int COLUMN_SHORTCUT = 0; + private static final int COLUMN_INTENT = 1; + private static final String[] sProjection = new String[] { + Settings.Bookmarks.SHORTCUT, Settings.Bookmarks.INTENT + }; + + private Context mContext; + private Cursor mCursor; + /** Map of a shortcut to its intent. */ + private SparseArray mShortcutIntents; + + public ShortcutManager(Context context, Handler handler) { + super(handler); + + mContext = context; + mShortcutIntents = new SparseArray(); + } + + /** Observes the provider of shortcut+intents */ + public void observe() { + mCursor = mContext.getContentResolver().query( + Settings.Bookmarks.CONTENT_URI, sProjection, null, null, null); + mCursor.registerContentObserver(this); + updateShortcuts(); + } + + @Override + public void onChange(boolean selfChange) { + updateShortcuts(); + } + + private void updateShortcuts() { + Cursor c = mCursor; + if (!c.requery()) { + Log.e(TAG, "ShortcutObserver could not re-query shortcuts."); + return; + } + + mShortcutIntents.clear(); + while (c.moveToNext()) { + int shortcut = c.getInt(COLUMN_SHORTCUT); + if (shortcut == 0) continue; + String intentURI = c.getString(COLUMN_INTENT); + Intent intent = null; + try { + intent = Intent.getIntent(intentURI); + } catch (URISyntaxException e) { + Log.w(TAG, "Intent URI for shortcut invalid.", e); + } + if (intent == null) continue; + mShortcutIntents.put(shortcut, intent); + } + } + + /** + * Gets the shortcut intent for a given keycode+modifier. Make sure you + * strip whatever modifier is used for invoking shortcuts (for example, + * if 'Sym+A' should invoke a shortcut on 'A', you should strip the + * 'Sym' bit from the modifiers before calling this method. + *

    + * This will first try an exact match (with modifiers), and then try a + * match without modifiers (primary character on a key). + * + * @param keyCode The keycode of the key pushed. + * @param modifiers The modifiers without any that are used for chording + * to invoke a shortcut. + * @return The intent that matches the shortcut, or null if not found. + */ + public Intent getIntent(int keyCode, int modifiers) { + KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD); + // First try the exact keycode (with modifiers) + int shortcut = kcm.get(keyCode, modifiers); + Intent intent = shortcut != 0 ? mShortcutIntents.get(shortcut) : null; + if (intent != null) return intent; + + // Next try the keycode without modifiers (the primary character on that key) + shortcut = Character.toLowerCase(kcm.get(keyCode, 0)); + return shortcut != 0 ? mShortcutIntents.get(shortcut) : null; + } + +} diff --git a/policy/com/android/internal/policy/impl/ShutdownThread.java b/policy/com/android/internal/policy/impl/ShutdownThread.java new file mode 100644 index 000000000000..994b1d50bdf9 --- /dev/null +++ b/policy/com/android/internal/policy/impl/ShutdownThread.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2008 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 android.app.ProgressDialog; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.RemoteException; +import android.os.Power; +import android.os.ServiceManager; +import android.os.SystemClock; +import com.android.internal.telephony.ITelephony; +import android.util.Log; +import android.view.WindowManager; + + +final class ShutdownThread extends Thread { + // constants + private static final String TAG = "ShutdownThread"; + private static final int MAX_NUM_PHONE_STATE_READS = 16; + private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500; + private static final ITelephony sPhone = + ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); + + // state tracking + private static Object sIsStartedGuard = new Object(); + private static boolean sIsStarted = false; + + // static instance of this thread + private static final ShutdownThread sInstance = new ShutdownThread(); + + private ShutdownThread() { + } + + /** + * request a shutdown. + * + * @param context Context used to display the shutdown progress dialog. + */ + public static void shutdownAfterDisablingRadio(final Context context, boolean confirm){ + // ensure that only one thread is trying to power down. + // any additional calls are just returned + synchronized (sIsStartedGuard){ + if (sIsStarted) { + Log.d(TAG, "Request to shutdown already running, returning."); + return; + } + } + + Log.d(TAG, "Notifying thread to start radio shutdown"); + + if (confirm) { + final AlertDialog dialog = new AlertDialog.Builder(context) + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(com.android.internal.R.string.power_off) + .setMessage(com.android.internal.R.string.shutdown_confirm) + .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + beginShutdownSequence(context); + } + }) + .setNegativeButton(com.android.internal.R.string.no, null) + .create(); + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + dialog.show(); + } else { + beginShutdownSequence(context); + } + } + + private static void beginShutdownSequence(Context context) { + synchronized (sIsStartedGuard) { + sIsStarted = true; + } + + // throw up an indeterminate system dialog to indicate radio is + // shutting down. + ProgressDialog pd = new ProgressDialog(context); + pd.setTitle(context.getText(com.android.internal.R.string.power_off)); + pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress)); + pd.setIndeterminate(true); + pd.setCancelable(false); + pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + + pd.show(); + + // start the thread that initiates shutdown + sInstance.start(); + } + + /** + * Makes sure we handle the shutdown gracefully. + * Shuts off power regardless of radio state if the alloted time has passed. + */ + public void run() { + //shutdown the phone radio if possible. + if (sPhone != null) { + try { + //shutdown radio + sPhone.setRadio(false); + + for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++){ + // poll radio up to 64 times, with a 0.5 sec delay between each call, + // totaling 32 sec. + if (!sPhone.isRadioOn()) { + Log.d(TAG, "Radio shutdown complete."); + break; + } + SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC); + } + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException caught from failed radio shutdown.", ex); + } + } + + //shutdown power + Log.d(TAG, "Shutting down power."); + Power.shutdown(); + } +} diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java new file mode 100644 index 000000000000..4c713925d174 --- /dev/null +++ b/policy/com/android/internal/policy/impl/SimUnlockScreen.java @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2008 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 android.app.Dialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.os.RemoteException; +import android.os.ServiceManager; +import com.android.internal.telephony.ITelephony; +import android.text.Editable; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; +import com.android.internal.R; + +/** + * Displays a dialer like interface to unlock the SIM PIN. + */ +public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener, + KeyguardUpdateMonitor.ConfigurationChangeCallback { + + private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; + + private final KeyguardUpdateMonitor mUpdateMonitor; + private final KeyguardScreenCallback mCallback; + + private final boolean mCreatedWithKeyboardOpen; + + private TextView mHeaderText; + private EditText mPinText; + + private TextView mOkButton; + private TextView mEmergencyCallButton; + + private View mBackSpaceButton; + + private final int[] mEnteredPin = {0, 0, 0, 0, 0, 0, 0, 0}; + private int mEnteredDigits = 0; + + private ProgressDialog mSimUnlockProgressDialog = null; + + private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + + public SimUnlockScreen(Context context, KeyguardUpdateMonitor updateMonitor, + KeyguardScreenCallback callback) { + super(context); + mUpdateMonitor = updateMonitor; + mCallback = callback; + mCreatedWithKeyboardOpen = mUpdateMonitor.isKeyboardOpen(); + + if (mCreatedWithKeyboardOpen) { + LayoutInflater.from(context).inflate(R.layout.keyguard_screen_sim_pin_landscape, this, true); + } else { + LayoutInflater.from(context).inflate(R.layout.keyguard_screen_sim_pin_portrait, this, true); + new TouchInput(); + } + + mHeaderText = (TextView) findViewById(R.id.headerText); + mPinText = (EditText) findViewById(R.id.pinDisplay); + mBackSpaceButton = findViewById(R.id.backspace); + mBackSpaceButton.setOnClickListener(this); + + mEmergencyCallButton = (TextView) findViewById(R.id.emergencyCall); + mOkButton = (TextView) findViewById(R.id.ok); + + mHeaderText.setText(R.string.keyguard_password_enter_pin_code); + mPinText.setFocusable(false); + + mEmergencyCallButton.setOnClickListener(this); + mOkButton.setOnClickListener(this); + + mUpdateMonitor.registerConfigurationChangeCallback(this); + setFocusableInTouchMode(true); + } + + /** {@inheritDoc} */ + public void onPause() { + + } + + /** {@inheritDoc} */ + public void onResume() { + // start fresh + mHeaderText.setText(R.string.keyguard_password_enter_pin_code); + mPinText.setText(""); + } + + /** {@inheritDoc} */ + public void cleanUp() { + mUpdateMonitor.removeCallback(this); + } + + + /** + * Since the IPC can block, we want to run the request in a separate thread + * with a callback. + */ + private abstract class CheckSimPin extends Thread { + + private final String mPin; + + protected CheckSimPin(String pin) { + mPin = pin; + } + + abstract void onSimLockChangedResponse(boolean success); + + @Override + public void run() { + try { + final boolean result = ITelephony.Stub.asInterface(ServiceManager + .checkService("phone")).supplyPin(mPin); + post(new Runnable() { + public void run() { + onSimLockChangedResponse(result); + } + }); + } catch (RemoteException e) { + post(new Runnable() { + public void run() { + onSimLockChangedResponse(false); + } + }); + } + } + } + + public void onClick(View v) { + if (v == mBackSpaceButton) { + final Editable digits = mPinText.getText(); + final int len = digits.length(); + if (len > 0) { + digits.delete(len-1, len); + mEnteredDigits--; + } + mCallback.pokeWakelock(); + } else if (v == mEmergencyCallButton) { + mCallback.takeEmergencyCallAction(); + } else if (v == mOkButton) { + checkPin(); + } + } + + private Dialog getSimUnlockProgressDialog() { + if (mSimUnlockProgressDialog == null) { + mSimUnlockProgressDialog = new ProgressDialog(mContext); + mSimUnlockProgressDialog.setMessage( + mContext.getString(R.string.lockscreen_sim_unlock_progress_dialog_message)); + mSimUnlockProgressDialog.setIndeterminate(true); + mSimUnlockProgressDialog.setCancelable(false); + mSimUnlockProgressDialog.getWindow().setType( + WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + mSimUnlockProgressDialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + } + return mSimUnlockProgressDialog; + } + + private void checkPin() { + + // make sure that the pin is at least 4 digits long. + if (mEnteredDigits < 4) { + // otherwise, display a message to the user, and don't submit. + mHeaderText.setText(R.string.invalidPin); + mPinText.setText(""); + mEnteredDigits = 0; + mCallback.pokeWakelock(); + return; + } + getSimUnlockProgressDialog().show(); + + new CheckSimPin(mPinText.getText().toString()) { + void onSimLockChangedResponse(boolean success) { + getSimUnlockProgressDialog().hide(); + if (success) { + // before closing the keyguard, report back that + // the sim is unlocked so it knows right away + mUpdateMonitor.reportSimPinUnlocked(); + mCallback.goToUnlockScreen(); + } else { + mHeaderText.setText(R.string.keyguard_password_wrong_pin_code); + mPinText.setText(""); + mEnteredDigits = 0; + mCallback.pokeWakelock(); + } + } + }.start(); + } + + + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + mCallback.goToLockScreen(); + return true; + } + + final char match = event.getMatch(DIGITS); + if (match != 0) { + reportDigit(match - '0'); + return true; + } + if (keyCode == KeyEvent.KEYCODE_DEL) { + if (mEnteredDigits > 0) { + mPinText.onKeyDown(keyCode, event); + mEnteredDigits--; + } + return true; + } + + if (keyCode == KeyEvent.KEYCODE_ENTER) { + checkPin(); + return true; + } + + return false; + } + + private void reportDigit(int digit) { + if (mEnteredDigits == 0) { + mPinText.setText(""); + } + if (mEnteredDigits == 8) { + return; + } + mPinText.append(Integer.toString(digit)); + mEnteredPin[mEnteredDigits++] = digit; + } + + public void onOrientationChange(boolean inPortrait) {} + + public void onKeyboardChange(boolean isKeyboardOpen) { + if (isKeyboardOpen != mCreatedWithKeyboardOpen) { + mCallback.recreateMe(); + } + } + + /** + * Helper class to handle input from touch dialer. Only relevant when + * the keyboard is shut. + */ + private class TouchInput implements View.OnClickListener { + private TextView mZero; + private TextView mOne; + private TextView mTwo; + private TextView mThree; + private TextView mFour; + private TextView mFive; + private TextView mSix; + private TextView mSeven; + private TextView mEight; + private TextView mNine; + private TextView mCancelButton; + + private TouchInput() { + mZero = (TextView) findViewById(R.id.zero); + mOne = (TextView) findViewById(R.id.one); + mTwo = (TextView) findViewById(R.id.two); + mThree = (TextView) findViewById(R.id.three); + mFour = (TextView) findViewById(R.id.four); + mFive = (TextView) findViewById(R.id.five); + mSix = (TextView) findViewById(R.id.six); + mSeven = (TextView) findViewById(R.id.seven); + mEight = (TextView) findViewById(R.id.eight); + mNine = (TextView) findViewById(R.id.nine); + mCancelButton = (TextView) findViewById(R.id.cancel); + + mZero.setText("0"); + mOne.setText("1"); + mTwo.setText("2"); + mThree.setText("3"); + mFour.setText("4"); + mFive.setText("5"); + mSix.setText("6"); + mSeven.setText("7"); + mEight.setText("8"); + mNine.setText("9"); + + mZero.setOnClickListener(this); + mOne.setOnClickListener(this); + mTwo.setOnClickListener(this); + mThree.setOnClickListener(this); + mFour.setOnClickListener(this); + mFive.setOnClickListener(this); + mSix.setOnClickListener(this); + mSeven.setOnClickListener(this); + mEight.setOnClickListener(this); + mNine.setOnClickListener(this); + mCancelButton.setOnClickListener(this); + } + + + public void onClick(View v) { + if (v == mCancelButton) { + mCallback.goToLockScreen(); + return; + } + + final int digit = checkDigit(v); + if (digit >= 0) { + mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS); + reportDigit(digit); + } + } + + private int checkDigit(View v) { + int digit = -1; + if (v == mZero) { + digit = 0; + } else if (v == mOne) { + digit = 1; + } else if (v == mTwo) { + digit = 2; + } else if (v == mThree) { + digit = 3; + } else if (v == mFour) { + digit = 4; + } else if (v == mFive) { + digit = 5; + } else if (v == mSix) { + digit = 6; + } else if (v == mSeven) { + digit = 7; + } else if (v == mEight) { + digit = 8; + } else if (v == mNine) { + digit = 9; + } + return digit; + } + } +} diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java new file mode 100644 index 000000000000..bd0b6d521e50 --- /dev/null +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2008 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 android.content.Context; +import android.os.CountDownTimer; +import android.os.SystemClock; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.MotionEvent; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import com.android.internal.R; +import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient; +import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockPatternView; + +import java.util.List; + +/** + * This is the screen that shows the 9 circle unlock widget and instructs + * the user how to unlock their device, or make an emergency call. + */ +class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient + implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback { + + private static final String TAG = "UnlockScreen"; + + // how long before we clear the wrong pattern + private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000; + + // how long we stay awake once the user is ready to enter a pattern + private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000; + + private int mFailedPatternAttemptsSinceLastTimeout = 0; + private int mTotalFailedPatternAttempts = 0; + private CountDownTimer mCountdownTimer = null; + + private final LockPatternUtils mLockPatternUtils; + private final KeyguardUpdateMonitor mUpdateMonitor; + private final KeyguardScreenCallback mCallback; + + private boolean mCreatedInPortrait; + + private ImageView mUnlockIcon; + private TextView mUnlockHeader; + private LockPatternView mLockPatternView; + + private ViewGroup mFooterNormal; + private ViewGroup mFooterForgotPattern; + + /** + * Keeps track of the last time we poked the wake lock during dispatching + * of the touch event, initalized to something gauranteed to make us + * poke it when the user starts drawing the pattern. + * @see #dispatchTouchEvent(android.view.MotionEvent) + */ + private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS; + + /** + * Useful for clearing out the wrong pattern after a delay + */ + private Runnable mCancelPatternRunnable = new Runnable() { + public void run() { + mLockPatternView.clearPattern(); + } + }; + + private Button mForgotPatternButton; + + + enum FooterMode { + Normal, + ForgotLockPattern, + VerifyUnlocked + } + + private void updateFooter(FooterMode mode) { + switch (mode) { + case Normal: + mFooterNormal.setVisibility(View.VISIBLE); + mFooterForgotPattern.setVisibility(View.GONE); + break; + case ForgotLockPattern: + mFooterNormal.setVisibility(View.GONE); + mFooterForgotPattern.setVisibility(View.VISIBLE); + break; + case VerifyUnlocked: + mFooterNormal.setVisibility(View.GONE); + mFooterForgotPattern.setVisibility(View.GONE); + } + } + + /** + * @param context The context. + * @param lockPatternUtils Used to lookup lock pattern settings. + * @param updateMonitor Used to lookup state affecting keyguard. + * @param callback Used to notify the manager when we're done, etc. + * @param totalFailedAttempts The current number of failed attempts. + */ + UnlockScreen(Context context, + LockPatternUtils lockPatternUtils, + KeyguardUpdateMonitor updateMonitor, + KeyguardScreenCallback callback, + int totalFailedAttempts) { + super(context); + mLockPatternUtils = lockPatternUtils; + mUpdateMonitor = updateMonitor; + mCallback = callback; + mTotalFailedPatternAttempts = totalFailedAttempts; + mFailedPatternAttemptsSinceLastTimeout = totalFailedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; + + if (mUpdateMonitor.isInPortrait()) { + LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_portrait, this, true); + } else { + LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_landscape, this, true); + } + + mUnlockIcon = (ImageView) findViewById(R.id.unlockLockIcon); + + mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern); + mUnlockHeader = (TextView) findViewById(R.id.headerText); + + mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); + + mFooterNormal = (ViewGroup) findViewById(R.id.footerNormal); + mFooterForgotPattern = (ViewGroup) findViewById(R.id.footerForgotPattern); + + // emergency call buttons + final OnClickListener emergencyClick = new OnClickListener() { + public void onClick(View v) { + mCallback.takeEmergencyCallAction(); + } + }; + Button emergencyAlone = (Button) findViewById(R.id.emergencyCallAlone); + emergencyAlone.setFocusable(false); // touch only! + emergencyAlone.setOnClickListener(emergencyClick); + Button emergencyTogether = (Button) findViewById(R.id.emergencyCallTogether); + emergencyTogether.setFocusable(false); + emergencyTogether.setOnClickListener(emergencyClick); + + mForgotPatternButton = (Button) findViewById(R.id.forgotPattern); + mForgotPatternButton.setText(R.string.lockscreen_forgot_pattern_button_text); + mForgotPatternButton.setOnClickListener(new OnClickListener() { + + public void onClick(View v) { + mLockPatternUtils.setPermanentlyLocked(true); + mCallback.goToUnlockScreen(); + } + }); + + // make it so unhandled touch events within the unlock screen go to the + // lock pattern view. + setDefaultTouchRecepient(mLockPatternView); + + mLockPatternView.setSaveEnabled(false); + mLockPatternView.setFocusable(false); + mLockPatternView.setOnPatternListener(new UnlockPatternListener()); + + // stealth mode will be the same for the life of this screen + mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled()); + + // assume normal footer mode for now + updateFooter(FooterMode.Normal); + + mCreatedInPortrait = updateMonitor.isInPortrait(); + updateMonitor.registerConfigurationChangeCallback(this); + setFocusableInTouchMode(true); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + mCallback.goToLockScreen(); + return true; + } + return false; + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + // as long as the user is entering a pattern (i.e sending a touch + // event that was handled by this screen), keep poking the + // wake lock so that the screen will stay on. + final boolean result = super.dispatchTouchEvent(ev); + if (result && + ((SystemClock.elapsedRealtime() - mLastPokeTime) + > (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) { + mLastPokeTime = SystemClock.elapsedRealtime(); + mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); + } + return result; + } + + /** {@inheritDoc} */ + public void onOrientationChange(boolean inPortrait) { + if (inPortrait != mCreatedInPortrait) { + mCallback.recreateMe(); + } + } + + /** {@inheritDoc} */ + public void onKeyboardChange(boolean isKeyboardOpen) {} + + /** {@inheritDoc} */ + public void onPause() { + if (mCountdownTimer != null) { + mCountdownTimer.cancel(); + mCountdownTimer = null; + } + } + + /** {@inheritDoc} */ + public void onResume() { + // reset header + mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); + mUnlockIcon.setVisibility(View.VISIBLE); + + // reset lock pattern + mLockPatternView.enableInput(); + mLockPatternView.setEnabled(true); + mLockPatternView.clearPattern(); + + // if the user is currently locked out, enforce it. + long deadline = mLockPatternUtils.getLockoutAttemptDeadline(); + if (deadline != 0) { + handleAttemptLockout(deadline); + } + + // the footer depends on how many total attempts the user has failed + if (mCallback.isVerifyUnlockOnly()) { + updateFooter(FooterMode.VerifyUnlocked); + } else if (mTotalFailedPatternAttempts < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { + updateFooter(FooterMode.Normal); + } else { + updateFooter(FooterMode.ForgotLockPattern); + } + } + + /** {@inheritDoc} */ + public void cleanUp() { + mUpdateMonitor.removeCallback(this); + } + + private class UnlockPatternListener + implements LockPatternView.OnPatternListener { + + public void onPatternStart() { + mLockPatternView.removeCallbacks(mCancelPatternRunnable); + } + + public void onPatternCleared() { + } + + public void onPatternDetected(List pattern) { + if (mLockPatternUtils.checkPattern(pattern)) { + mLockPatternView + .setDisplayMode(LockPatternView.DisplayMode.Correct); + mUnlockIcon.setVisibility(View.GONE); + mUnlockHeader.setText(R.string.lockscreen_pattern_correct); + mCallback.keyguardDone(true); + } else { + mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); + mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong); + if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { + mTotalFailedPatternAttempts++; + mFailedPatternAttemptsSinceLastTimeout++; + mCallback.reportFailedPatternAttempt(); + } + if (mFailedPatternAttemptsSinceLastTimeout >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { + long deadline = SystemClock.elapsedRealtime() + LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS; + mLockPatternUtils.setLockoutAttemptDeadline(deadline); + handleAttemptLockout(deadline); + return; + } + mUnlockIcon.setVisibility(View.VISIBLE); + mUnlockHeader.setText(R.string.lockscreen_pattern_wrong); + mLockPatternView.postDelayed( + mCancelPatternRunnable, + PATTERN_CLEAR_TIMEOUT_MS); + } + } + } + + private void handleAttemptLockout(long elapsedRealtimeDeadline) { + mLockPatternView.clearPattern(); + mLockPatternView.setEnabled(false); + long elapsedRealtime = SystemClock.elapsedRealtime(); + mCountdownTimer = new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) { + + @Override + public void onTick(long millisUntilFinished) { + int secondsRemaining = (int) (millisUntilFinished / 1000); + mUnlockHeader.setText(getContext().getString( + R.string.lockscreen_too_many_failed_attempts_countdown, + secondsRemaining)); + } + + @Override + public void onFinish() { + mLockPatternView.setEnabled(true); + mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); + mUnlockIcon.setVisibility(View.VISIBLE); + mFailedPatternAttemptsSinceLastTimeout = 0; + updateFooter(FooterMode.ForgotLockPattern); + } + }.start(); + } + +} diff --git a/policy/com/android/internal/policy/impl/package.html b/policy/com/android/internal/policy/impl/package.html new file mode 100644 index 000000000000..c9f96a66ab3b --- /dev/null +++ b/policy/com/android/internal/policy/impl/package.html @@ -0,0 +1,5 @@ + + +{@hide} + + -- GitLab From aba08754228eeb07efcefdee47a9905706e4201b Mon Sep 17 00:00:00 2001 From: Rich Cannings Date: Tue, 11 Nov 2008 15:12:25 +0900 Subject: [PATCH 002/458] Fix the lock screen bypass issue reported in http://forum.xda-developers.com/showthread.php?t=436767. --- .../android/internal/policy/impl/PhoneWindowManager.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 250d2d40e531..17312062960e 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1325,11 +1325,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // If the user is holding the menu key code, then we are // going to boot into safe mode. ActivityManagerNative.getDefault().enterSafeMode(); - } else { - // tell the keyguard - mKeyguardMediator.onSystemReady(); - android.os.SystemProperties.set("dev.bootcomplete", "1"); } + // tell the keyguard + mKeyguardMediator.onSystemReady(); + android.os.SystemProperties.set("dev.bootcomplete", "1"); } catch (RemoteException e) { // Ignore } -- GitLab From 646860b2e8b57977fb2425075d88ad608ff2ffaf Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Wed, 17 Dec 2008 18:05:50 -0800 Subject: [PATCH 003/458] Code drop from //branches/cupcake/...@124589 --- policy/Android.mk | 3 +- .../policy/impl/KeyguardScreenCallback.java | 5 + .../policy/impl/KeyguardUpdateMonitor.java | 14 +- .../policy/impl/KeyguardViewBase.java | 16 +- .../policy/impl/KeyguardViewMediator.java | 14 +- .../policy/impl/LockPatternKeyguardView.java | 58 +- .../internal/policy/impl/LockScreen.java | 4 +- .../internal/policy/impl/PhoneWindow.java | 100 ++- .../policy/impl/PhoneWindowManager.java | 568 ++++++++++++------ .../android/internal/policy/impl/Policy.java | 24 + .../internal/policy/impl/SimUnlockScreen.java | 14 +- .../internal/policy/impl/UnlockScreen.java | 14 + 12 files changed, 613 insertions(+), 221 deletions(-) diff --git a/policy/Android.mk b/policy/Android.mk index 462431f905fb..29f62b872306 100644 --- a/policy/Android.mk +++ b/policy/Android.mk @@ -7,6 +7,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ $(call all-subdir-java-files) -LOCAL_MODULE:= android.policy +LOCAL_MODULE := android.policy_phone +LOCAL_UNINSTALLABLE_MODULE := true include $(BUILD_JAVA_LIBRARY) diff --git a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java index 832288b1a04c..b46b37d04db0 100644 --- a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java +++ b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java @@ -58,4 +58,9 @@ public interface KeyguardScreenCallback extends KeyguardViewCallback { */ void reportFailedPatternAttempt(); + /** + * Report whether we there's another way to unlock the device. + * @return true + */ + boolean doesFallbackUnlockScreenExist(); } diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index ab7c744c7363..4671957592cc 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -160,8 +160,8 @@ public class KeyguardUpdateMonitor { } }; - mDeviceProvisioned = Settings.System.getInt( - mContext.getContentResolver(), Settings.System.DEVICE_PROVISIONED, 0) != 0; + mDeviceProvisioned = Settings.Secure.getInt( + mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; // Since device can't be un-provisioned, we only need to register a content observer // to update mDeviceProvisioned when we are... @@ -170,8 +170,8 @@ public class KeyguardUpdateMonitor { @Override public void onChange(boolean selfChange) { super.onChange(selfChange); - mDeviceProvisioned = Settings.System.getInt(mContext.getContentResolver(), - Settings.System.DEVICE_PROVISIONED, 0) != 0; + mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.DEVICE_PROVISIONED, 0) != 0; if (mDeviceProvisioned && mContentObserver != null) { // We don't need the observer anymore... mContext.getContentResolver().unregisterContentObserver(mContentObserver); @@ -182,13 +182,13 @@ public class KeyguardUpdateMonitor { }; mContext.getContentResolver().registerContentObserver( - Settings.System.getUriFor(Settings.System.DEVICE_PROVISIONED), + Settings.Secure.getUriFor(Settings.Secure.DEVICE_PROVISIONED), false, mContentObserver); // prevent a race condition between where we check the flag and where we register the // observer by grabbing the value once again... - mDeviceProvisioned = Settings.System.getInt(mContext.getContentResolver(), - Settings.System.DEVICE_PROVISIONED, 0) != 0; + mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.DEVICE_PROVISIONED, 0) != 0; } mInPortrait = queryInPortrait(); diff --git a/policy/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/com/android/internal/policy/impl/KeyguardViewBase.java index 491300ea11e8..5a3ebdee1be4 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewBase.java @@ -131,7 +131,13 @@ public abstract class KeyguardViewBase extends FrameLayout { final int keyCode = event.getKeyCode(); if (event.getAction() == KeyEvent.ACTION_DOWN) { switch (keyCode) { - case KeyEvent.KEYCODE_HEADSETHOOK: { + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); @@ -161,7 +167,13 @@ public abstract class KeyguardViewBase extends FrameLayout { } } else if (event.getAction() == KeyEvent.ACTION_UP) { switch (keyCode) { - case KeyEvent.KEYCODE_HEADSETHOOK: { + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index ac816b0bd60e..2431ffe8075d 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -131,6 +131,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private Context mContext; private AlarmManager mAlarmManager; + private boolean mSystemReady; + /** Low level access to the power manager for enableUserActivity. Having this * requires that we run in the system process. */ LocalPowerManager mRealPowerManager; @@ -254,6 +256,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, public void onSystemReady() { synchronized (this) { if (DEBUG) Log.d(TAG, "onSystemReady"); + mSystemReady = true; doKeyguard(); } } @@ -638,7 +641,13 @@ public class KeyguardViewMediator implements KeyguardViewCallback, switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: - case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: case KeyEvent.KEYCODE_CAMERA: return false; } @@ -806,6 +815,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private void handleShow() { synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleShow"); + if (!mSystemReady) return; + // while we're showing, we control the wake state, so ask the power // manager not to honor request for userActivity. mRealPowerManager.enableUserActivity(false); @@ -875,6 +886,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleVerifyUnlock"); mKeyguardViewManager.verifyUnlock(); + mShowing = true; } } diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 66a4c4e7813a..4ff87e3a196c 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -16,9 +16,15 @@ package com.android.internal.policy.impl; +import android.accounts.AccountsServiceConstants; +import android.accounts.IAccountsService; import android.app.AlertDialog; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.RemoteException; import android.os.SystemProperties; import com.android.internal.telephony.SimCard; import android.text.TextUtils; @@ -51,6 +57,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { private View mUnlockScreen; private boolean mScreenOn = false; + private boolean mHasAccount = false; // assume they don't have an account until we know better + /** * The current {@link KeyguardScreen} will use this to communicate back to us. @@ -114,6 +122,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase { */ private final LockPatternUtils mLockPatternUtils; + /** + * Used to fetch accounts from GLS. + */ + private ServiceConnection mServiceConnection; /** * @return Whether we are stuck on the lock screen because the sim is @@ -137,7 +149,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase { KeyguardUpdateMonitor updateMonitor, LockPatternUtils lockPatternUtils) { super(context); - + + asyncCheckForAccount(); + mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); @@ -145,6 +159,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { mLockPatternUtils = lockPatternUtils; mMode = getInitialMode(); + mKeyguardScreenCallback = new KeyguardScreenCallback() { public void goToLockScreen() { @@ -210,10 +225,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase { public void reportFailedPatternAttempt() { mUpdateMonitor.reportFailedAttempt(); final int failedAttempts = mUpdateMonitor.getFailedAttempts(); - if (failedAttempts == - (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { + if (mHasAccount && failedAttempts == + (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET + - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { showAlmostAtAccountLoginDialog(); - } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { + } else if (mHasAccount && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { mLockPatternUtils.setPermanentlyLocked(true); updateScreen(mMode); } else if ((failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) @@ -221,6 +237,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase { showTimeoutDialog(); } } + + public boolean doesFallbackUnlockScreenExist() { + return mHasAccount; + } }; /** @@ -241,6 +261,36 @@ public class LockPatternKeyguardView extends KeyguardViewBase { updateScreen(mMode); } + /** + * Asynchronously checks for at least one account. This will set mHasAccount + * to true if an account is found. + */ + private void asyncCheckForAccount() { + + mServiceConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + try { + IAccountsService accountsService = IAccountsService.Stub.asInterface(service); + String accounts[] = accountsService.getAccounts(); + mHasAccount = (accounts.length > 0); + } catch (RemoteException e) { + // Not much we can do here... + Log.e(TAG, "Gls died while attempting to get accounts: " + e); + } finally { + getContext().unbindService(mServiceConnection); + mServiceConnection = null; + } + } + + public void onServiceDisconnected(ComponentName className) { + // nothing to do here + } + }; + boolean status = getContext().bindService(AccountsServiceConstants.SERVICE_INTENT, + mServiceConnection, Context.BIND_AUTO_CREATE); + if (!status) Log.e(TAG, "Failed to bind to GLS while checking for account"); + } + @Override public void reset() { mIsVerifyUnlockOnly = false; diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index c717cc37ae15..0825c3bde2ee 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -20,7 +20,7 @@ import com.android.internal.R; import com.android.internal.widget.LockPatternUtils; import android.content.Context; -import android.pim.DateFormat; +import android.text.format.DateFormat; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -299,7 +299,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mHeaderSimOk1.setVisibility(View.VISIBLE); mHeaderSimOk1.setText(plmn); } else { - mHeaderSimOk2.setVisibility(View.GONE); + mHeaderSimOk1.setVisibility(View.GONE); } if (spn != null) { diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 2d5bd31aedd2..dfc4b6c940be 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -41,7 +41,6 @@ import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; -import android.provider.CallLog.Calls; import android.util.AndroidRuntimeException; import android.util.Config; import android.util.EventLog; @@ -66,6 +65,7 @@ import android.view.WindowManager; import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; +import static android.view.WindowManager.LayoutParams.FLAG_RESTORED_STATE; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.FrameLayout; @@ -482,7 +482,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { WindowManager.LayoutParams lp = new WindowManager.LayoutParams( WRAP_CONTENT, WRAP_CONTENT, st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, - WindowManager.LayoutParams.FLAG_DITHER, + WindowManager.LayoutParams.FLAG_DITHER + | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, st.decorView.mDefaultOpacity); lp.gravity = st.gravity; @@ -493,7 +494,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public final void closePanel(int featureId) { - closePanel(getPanelState(featureId, true), true); + if (featureId == FEATURE_CONTEXT_MENU) { + closeContextMenu(); + } else { + closePanel(getPanelState(featureId, true), true); + } } /** @@ -628,8 +633,23 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { closeContextMenu(); } - + + /** + * Closes the context menu. This notifies the menu logic of the close, along + * with dismissing it from the UI. + */ private synchronized void closeContextMenu() { + if (mContextMenu != null) { + mContextMenu.close(); + dismissContextMenu(); + } + } + + /** + * Dismisses just the context menu UI. To close the context menu, use + * {@link #closeContextMenu()}. + */ + private synchronized void dismissContextMenu() { mContextMenu = null; if (mContextMenuHelper != null) { @@ -1117,7 +1137,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return true; } - case KeyEvent.KEYCODE_HEADSETHOOK: { + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); @@ -1226,7 +1252,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return true; } - case KeyEvent.KEYCODE_HEADSETHOOK: { + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); @@ -1344,6 +1376,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return; } + setFlags(FLAG_RESTORED_STATE, FLAG_RESTORED_STATE); + SparseArray savedStates = savedInstanceState.getSparseParcelableArray(VIEWS_TAG); if (savedStates != null) { @@ -1503,7 +1537,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * If not handled, then pass it to the view hierarchy * and anyone else that may be interested. */ - handled = dispatchKeyShortcut(event); + handled = dispatchKeyShortcutEvent(event); if (handled && mPreparedPanel != null) { mPreparedPanel.isHandled = true; @@ -1534,11 +1568,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event); } - private boolean dispatchKeyShortcut(KeyEvent event) { - View focusedView = findFocus(); - return focusedView == null ? false : focusedView.dispatchKeyShortcutEvent(event); - } - @Override public boolean dispatchTouchEvent(MotionEvent ev) { final Callback cb = getCallback(); @@ -1884,7 +1913,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { protected ViewGroup generateLayout(DecorView decor) { // Apply data from current theme. - final Context c = getContext(); TypedArray a = getWindowStyle(); if (false) { @@ -1903,19 +1931,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mIsFloating) { setLayout(WRAP_CONTENT, WRAP_CONTENT); setFlags(0, flagsToUpdate); - - /* All dialogs should have the window dimmed */ - WindowManager.LayoutParams params = getAttributes(); - TypedArray attrs = c.obtainStyledAttributes( - com.android.internal.R.styleable.Theme); - params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; - params.dimAmount = attrs.getFloat( - android.R.styleable.Theme_backgroundDimAmount, 0.5f); - attrs.recycle(); } else { setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate); } - + if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) { requestFeature(FEATURE_NO_TITLE); } @@ -1924,6 +1943,28 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags())); } + WindowManager.LayoutParams params = getAttributes(); + + if (!hasSoftInputMode()) { + params.softInputMode = (byte)a.getInt( + com.android.internal.R.styleable.Window_windowSoftInputMode, + params.softInputMode); + } + + if (a.getBoolean(com.android.internal.R.styleable.Window_backgroundDimEnabled, + mIsFloating)) { + /* All dialogs should have the window dimmed */ + if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) { + params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; + } + params.dimAmount = a.getFloat( + android.R.styleable.Window_backgroundDimAmount, 0.5f); + } + + params.windowAnimations = a.getResourceId( + com.android.internal.R.styleable.Window_windowAnimationStyle, + params.windowAnimations); + // The rest are only done if this window is not embedded; otherwise, // the values are inherited from our container. if (getContainer() == null) { @@ -2529,6 +2570,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { */ private final class ContextMenuCallback implements MenuBuilder.Callback { private int mFeatureId; + private MenuDialogHelper mSubMenuHelper; public ContextMenuCallback(int featureId) { mFeatureId = featureId; @@ -2540,7 +2582,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (callback != null) callback.onPanelClosed(mFeatureId, menu); if (menu == mContextMenu) { - closeContextMenu(); + dismissContextMenu(); + } + + // Dismiss the submenu, if it is showing + if (mSubMenuHelper != null) { + mSubMenuHelper.dismiss(); + mSubMenuHelper = null; } } } @@ -2553,7 +2601,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { Callback callback = getCallback(); return (callback != null) && callback.onMenuItemSelected(mFeatureId, item); - } public void onMenuModeChange(MenuBuilder menu) { @@ -2564,7 +2611,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { subMenu.setCallback(this); // The window manager will give us a valid window token - new MenuDialogHelper(subMenu).show(null); + mSubMenuHelper = new MenuDialogHelper(subMenu); + mSubMenuHelper.show(null); return true; } diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 250d2d40e531..603b2216e418 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -23,14 +23,13 @@ import android.app.IStatusBar; import android.content.BroadcastReceiver; import android.content.ContentQueryMap; import android.content.ContentResolver; -import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; -import android.database.Cursor; +import android.database.ContentObserver; import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; @@ -41,13 +40,13 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; -import static android.provider.Settings.System.END_BUTTON_BEHAVIOR; import com.android.internal.policy.PolicyManager; import com.android.internal.telephony.ITelephony; import android.util.Config; import android.util.EventLog; import android.util.Log; +import android.view.Gravity; import android.view.IWindowManager; import android.view.KeyEvent; import android.view.MotionEvent; @@ -64,10 +63,13 @@ import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; 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_KEYGUARD; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_PHONE; @@ -77,6 +79,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import android.view.WindowManagerImpl; @@ -91,117 +95,159 @@ import java.util.Observer; * WindowManagerPolicy implementation for the Android phone UI. */ public class PhoneWindowManager implements WindowManagerPolicy { - private static final String TAG = "WindowManager"; - private static final boolean DEBUG = false; - private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; - private static final boolean SHOW_STARTING_ANIMATIONS = true; - private static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; + static final String TAG = "WindowManager"; + static final boolean DEBUG = false; + static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; + static final boolean SHOW_STARTING_ANIMATIONS = true; + static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; - private static final int APPLICATION_LAYER = 1; - private static final int PHONE_LAYER = 2; - private static final int SEARCH_BAR_LAYER = 3; - private static final int STATUS_BAR_PANEL_LAYER = 4; + static final int APPLICATION_LAYER = 1; + static final int PHONE_LAYER = 2; + static final int SEARCH_BAR_LAYER = 3; + static final int STATUS_BAR_PANEL_LAYER = 4; // toasts and the plugged-in battery thing - private static final int TOAST_LAYER = 5; - private static final int STATUS_BAR_LAYER = 6; + static final int TOAST_LAYER = 5; + static final int STATUS_BAR_LAYER = 6; // SIM errors and unlock. Not sure if this really should be in a high layer. - private static final int PRIORITY_PHONE_LAYER = 7; + static final int PRIORITY_PHONE_LAYER = 7; // like the ANR / app crashed dialogs - private static final int SYSTEM_ALERT_LAYER = 8; + static final int SYSTEM_ALERT_LAYER = 8; // system-level error dialogs - private static final int SYSTEM_ERROR_LAYER = 9; + static final int SYSTEM_ERROR_LAYER = 9; + // on-screen keyboards and other such input method user interfaces go here. + static final int INPUT_METHOD_LAYER = 10; + // on-screen keyboards and other such input method user interfaces go here. + static final int INPUT_METHOD_DIALOG_LAYER = 11; // the keyguard; nothing on top of these can take focus, since they are // responsible for power management when displayed. - private static final int KEYGUARD_LAYER = 10; - private static final int KEYGUARD_DIALOG_LAYER = 11; + static final int KEYGUARD_LAYER = 12; + static final int KEYGUARD_DIALOG_LAYER = 13; // things in here CAN NOT take focus, but are shown on top of everything else. - private static final int SYSTEM_OVERLAY_LAYER = 12; + static final int SYSTEM_OVERLAY_LAYER = 14; - private static final int APPLICATION_PANEL_SUBLAYER = 1; - private static final int APPLICATION_MEDIA_SUBLAYER = -1; - private static final int APPLICATION_SUB_PANEL_SUBLAYER = 2; + static final int APPLICATION_PANEL_SUBLAYER = 1; + static final int APPLICATION_MEDIA_SUBLAYER = -1; + static final int APPLICATION_SUB_PANEL_SUBLAYER = 2; - private static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f; + static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f; + + // Debugging: set this to have the system act like there is no hard keyboard. + static final boolean KEYBOARD_ALWAYS_HIDDEN = false; static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; - private Context mContext; - private IWindowManager mWindowManager; - private LocalPowerManager mPowerManager; + Context mContext; + IWindowManager mWindowManager; + LocalPowerManager mPowerManager; /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ - private boolean mEnableShiftMenuBugReports = false; + boolean mEnableShiftMenuBugReports = false; + + WindowState mStatusBar = null; + WindowState mSearchBar = null; + WindowState mKeyguard = null; + KeyguardViewMediator mKeyguardMediator; + GlobalActions mGlobalActions; + boolean mShouldTurnOffOnKeyUp; + RecentApplicationsDialog mRecentAppsDialog; + Handler mHandler; + + boolean mLidOpen; + int mSensorRotation = -1; + boolean mScreenOn = false; + boolean mOrientationSensorEnabled = false; + int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + static final int DEFAULT_ACCELEROMETER_ROTATION = 0; + int mAccelerometerDefault = DEFAULT_ACCELEROMETER_ROTATION; + boolean mHasSoftInput = false; + + // The current size of the screen. + int mW, mH; + // During layout, the current screen borders with all outer decoration + // (status bar, input method dock) accounted for. + int mCurLeft, mCurTop, mCurRight, mCurBottom; + // During layout, the frame in which content should be displayed + // to the user, accounting for all screen decoration except for any + // space they deem as available for other content. This is usually + // the same as mCur*, but may be larger if the screen decor has supplied + // content insets. + int mContentLeft, mContentTop, mContentRight, mContentBottom; + // During layout, the current screen borders along with input method + // windows are placed. + int mDockLeft, mDockTop, mDockRight, mDockBottom; + // During layout, the layer at which the doc window is placed. + int mDockLayer; - private WindowState mStatusBar = null; - private WindowState mSearchBar = null; - private WindowState mKeyguard = null; - private KeyguardViewMediator mKeyguardMediator; - private GlobalActions mGlobalActions; - private boolean mShouldTurnOffOnKeyUp; - private RecentApplicationsDialog mRecentAppsDialog; - private Handler mHandler; - - private boolean mLidOpen; - private int mSensorOrientation = OrientationListener.ORIENTATION_UNKNOWN; - private int mSensorRotation = -1; - private boolean mScreenOn = false; - private boolean mOrientationSensorEnabled = false; - private int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + static final Rect mTmpParentFrame = new Rect(); + static final Rect mTmpDisplayFrame = new Rect(); + static final Rect mTmpContentFrame = new Rect(); + static final Rect mTmpVisibleFrame = new Rect(); - private int mW, mH; - private int mCurLeft, mCurTop, mCurRight, mCurBottom; - private WindowState mTopFullscreenOpaqueWindowState; - private boolean mForceStatusBar; - private boolean mHomePressed; - private Intent mHomeIntent; - private boolean mSearchKeyPressed; - private boolean mConsumeSearchKeyUp; - - private static final int ENDCALL_HOME = 0x1; - private static final int ENDCALL_SLEEPS = 0x2; - private static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; - private int mEndcallBehavior; - - private ShortcutManager mShortcutManager; - private PowerManager.WakeLock mBroadcastWakeLock; - - private class SettingsObserver implements Observer { + WindowState mTopFullscreenOpaqueWindowState; + boolean mForceStatusBar; + boolean mHomePressed; + Intent mHomeIntent; + boolean mSearchKeyPressed; + boolean mConsumeSearchKeyUp; + + static final int ENDCALL_HOME = 0x1; + static final int ENDCALL_SLEEPS = 0x2; + static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; + int mEndcallBehavior; + + ShortcutManager mShortcutManager; + PowerManager.WakeLock mBroadcastWakeLock; + + class SettingsObserver extends ContentObserver { private ContentQueryMap mSettings; + SettingsObserver(Handler handler) { + super(handler); + } + void observe() { ContentResolver resolver = mContext.getContentResolver(); - Cursor settingsCursor = resolver.query(Settings.System.CONTENT_URI, null, - Settings.System.NAME + "=?", - new String[] { END_BUTTON_BEHAVIOR}, - null); - mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mHandler); - mSettings.addObserver(this); - - // pretend that the settings changed so we will get their initial state - update(mSettings, null); - } - - private int getInt(String name, int def) { - ContentValues row = mSettings.getValues(name); - if (row != null) { - Integer ret = row.getAsInteger(Settings.System.VALUE); - if(ret == null) { - return def; - } - return ret; - } else { - return def; + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.END_BUTTON_BEHAVIOR), false, this); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.ACCELEROMETER_ROTATION), false, this); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.DEFAULT_INPUT_METHOD), false, this); + update(); + } + + @Override public void onChange(boolean selfChange) { + update(); + try { + mWindowManager.setRotation(USE_LAST_ROTATION, false); + } catch (RemoteException e) { + // Ignore } } - - public void update(Observable o, Object arg) { - mEndcallBehavior = getInt(END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); + + public void update() { + ContentResolver resolver = mContext.getContentResolver(); + mEndcallBehavior = Settings.System.getInt(resolver, + Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); + int accelerometerDefault = Settings.System.getInt(resolver, + Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); + if (mAccelerometerDefault != accelerometerDefault) { + mAccelerometerDefault = accelerometerDefault; + updateOrientationListener(); + } + String imId = Settings.Secure.getString(resolver, + Settings.Secure.DEFAULT_INPUT_METHOD); + boolean hasSoftInput = imId != null && imId.length() > 0; + if (mHasSoftInput != hasSoftInput) { + mHasSoftInput = hasSoftInput; + updateRotation(); + } } } - private class MyOrientationListener extends OrientationListener { + class MyOrientationListener extends OrientationListener { MyOrientationListener(Context context) { super(context); @@ -214,7 +260,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { // portrait range is 270+45 to 359 and 0 to 45 // landscape range is 270-45 to 270+45 if ((orientation >= 0 && orientation <= 45) || (orientation >= 270 - 45)) { - mSensorOrientation = orientation; int rotation = (orientation >= 270 - 45 && orientation <= 270 + 45) ? Surface.ROTATION_90 : Surface.ROTATION_0; @@ -233,8 +278,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } - private MyOrientationListener mOrientationListener; + MyOrientationListener mOrientationListener; + boolean useSensorForOrientation() { + if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { + return true; + } + if (mAccelerometerDefault != 0 && ( + mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || + mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { + return true; + } + return false; + } + /* * Various use cases for invoking this function * screen turning off, should always disable listeners if already enabled @@ -245,7 +302,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * screen turning on and current app has sensor based orientation, enable listeners if needed * screen turning on and current app has nosensor based orientation, do nothing */ - private void updateOrientationListener() { + void updateOrientationListener() { //Could have been invoked due to screen turning on or off or //change of the currently visible window's orientation if(localLOGV) Log.i(TAG, "Screen status="+mScreenOn+ @@ -253,7 +310,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { ", SensorEnabled="+mOrientationSensorEnabled); boolean disable = true; if(mScreenOn) { - if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { + if(useSensorForOrientation()) { disable = false; //enable listener if not already enabled if(!mOrientationSensorEnabled) { @@ -271,7 +328,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private Runnable mEndCallLongPress = new Runnable() { + Runnable mEndCallLongPress = new Runnable() { public void run() { mShouldTurnOffOnKeyUp = false; sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); @@ -279,7 +336,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; - private void showGlobalActionsDialog() { + void showGlobalActionsDialog() { if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext, mPowerManager); } @@ -292,15 +349,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private boolean isDeviceProvisioned() { - return Settings.System.getInt( - mContext.getContentResolver(), Settings.System.DEVICE_PROVISIONED, 0) != 0; + boolean isDeviceProvisioned() { + return Settings.Secure.getInt( + mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; } /** * When a home-key longpress expires, close other system windows and launch the recent apps */ - private Runnable mHomeLongPress = new Runnable() { + Runnable mHomeLongPress = new Runnable() { public void run() { /* * Eat the longpress so it won't dismiss the recent apps dialog when @@ -315,7 +372,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** * Create (if necessary) and launch the recent apps dialog */ - private void showRecentAppsDialog() { + void showRecentAppsDialog() { if (mRecentAppsDialog == null) { mRecentAppsDialog = new RecentApplicationsDialog(mContext); } @@ -331,7 +388,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager); mHandler = new Handler(); mOrientationListener = new MyOrientationListener(mContext); - SettingsObserver settingsObserver = new SettingsObserver(); + SettingsObserver settingsObserver = new SettingsObserver(mHandler); settingsObserver.observe(); mShortcutManager = new ShortcutManager(context, mHandler); mShortcutManager.observe(); @@ -359,6 +416,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // this... should introduce a token to let the system // monitor/control what they are doing. break; + case TYPE_INPUT_METHOD: + // The window manager will check this. + break; case TYPE_PHONE: case TYPE_PRIORITY_PHONE: case TYPE_SYSTEM_ALERT: @@ -389,7 +449,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private void readLidState() { + void readLidState() { try { int sw = mWindowManager.getSwitchState(0); if (sw >= 0) { @@ -403,8 +463,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void adjustConfigurationLw(Configuration config) { readLidState(); - mPowerManager.setKeyboardVisibility(mLidOpen); - config.keyboardHidden = mLidOpen + final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen; + mPowerManager.setKeyboardVisibility(lidOpen); + config.keyboardHidden = (lidOpen || mHasSoftInput) + ? Configuration.KEYBOARDHIDDEN_NO + : Configuration.KEYBOARDHIDDEN_YES; + config.hardKeyboardHidden = lidOpen ? Configuration.KEYBOARDHIDDEN_NO : Configuration.KEYBOARDHIDDEN_YES; if (keyguardIsShowingTq()) { @@ -438,10 +502,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { return APPLICATION_LAYER; } switch (type) { - case TYPE_APPLICATION_PANEL: - return APPLICATION_LAYER; - case TYPE_APPLICATION_SUB_PANEL: - return APPLICATION_LAYER; case TYPE_STATUS_BAR: return STATUS_BAR_LAYER; case TYPE_STATUS_BAR_PANEL: @@ -458,6 +518,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { return SYSTEM_ALERT_LAYER; case TYPE_SYSTEM_ERROR: return SYSTEM_ERROR_LAYER; + case TYPE_INPUT_METHOD: + return INPUT_METHOD_LAYER; + case TYPE_INPUT_METHOD_DIALOG: + return INPUT_METHOD_DIALOG_LAYER; case TYPE_SYSTEM_OVERLAY: return SYSTEM_OVERLAY_LAYER; case TYPE_PRIORITY_PHONE: @@ -473,6 +537,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public int subWindowTypeToLayerLw(int type) { switch (type) { case TYPE_APPLICATION_PANEL: + case TYPE_APPLICATION_ATTACHED_DIALOG: return APPLICATION_PANEL_SUBLAYER; case TYPE_APPLICATION_MEDIA: return APPLICATION_MEDIA_SUBLAYER; @@ -514,6 +579,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } Window win = PolicyManager.makeNewWindow(context); + if (win.getWindowStyle().getBoolean( + com.android.internal.R.styleable.Window_windowDisablePreview, false)) { + return null; + } + Resources r = context.getResources(); win.setTitle(r.getText(labelRes, nonLocalizedLabel)); @@ -634,7 +704,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private static final boolean PRINT_ANIM = false; + static final boolean PRINT_ANIM = false; /** {@inheritDoc} */ public int selectAnimationLw(WindowState win, int transit) { @@ -650,15 +720,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } - private static ITelephony getPhoneInterface() { + static ITelephony getPhoneInterface() { return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE)); } - private static IAudioService getAudioInterface() { + static IAudioService getAudioInterface() { return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE)); } - private boolean keyguardOn() { + boolean keyguardOn() { return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode(); } @@ -826,7 +896,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * A home key -> launch home action was detected. Take the appropriate action * given the situation with the keyguard. */ - private void launchHomeFromHotKey() { + void launchHomeFromHotKey() { if (mKeyguardMediator.isShowing()) { // don't launch home if keyguard showing } else if (mKeyguardMediator.isInputRestricted()) { @@ -847,15 +917,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - public void getCoveredInsetHintLw(WindowManager.LayoutParams attrs, Rect coveredInset) { + public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) { final int fl = attrs.flags; if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { - coveredInset.set(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom); + contentInset.set(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom); } else { - coveredInset.setEmpty(); + contentInset.setEmpty(); } } @@ -863,19 +933,75 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void beginLayoutLw(int displayWidth, int displayHeight) { mW = displayWidth; mH = displayHeight; - mCurLeft = 0; - mCurTop = 0; - mCurRight = displayWidth; - mCurBottom = displayHeight; + mDockLeft = mContentLeft = mCurLeft = 0; + mDockTop = mContentTop = mCurTop = 0; + mDockRight = mContentRight = mCurRight = displayWidth; + mDockBottom = mContentBottom = mCurBottom = displayHeight; + mDockLayer = 0x10000000; // decide where the status bar goes ahead of time if (mStatusBar != null) { - mStatusBar.computeFrameLw(0, 0, displayWidth, displayHeight, - 0, 0, displayWidth, displayHeight); - mCurTop = mStatusBar.getFrameLw().bottom; + final Rect pf = mTmpParentFrame; + final Rect df = mTmpDisplayFrame; + final Rect vf = mTmpVisibleFrame; + pf.left = df.left = vf.left = 0; + pf.top = df.top = vf.top = 0; + pf.right = df.right = vf.right = displayWidth; + pf.bottom = df.bottom = vf.bottom = displayHeight; + + mStatusBar.computeFrameLw(pf, df, vf, vf); + mDockTop = mContentTop = mCurTop = mStatusBar.getFrameLw().bottom; } } + void setAttachedWindowFrames(WindowState win, int fl, int sim, + WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) { + if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) { + // Here's a special case: if this attached window is a panel that is + // above the dock window, and the window it is attached to is below + // the dock window, then the frames we computed for the window it is + // attached to can not be used because the dock is effectively part + // of the underlying window and the attached window is floating on top + // of the whole thing. So, we ignore the attached window and explicitly + // compute the frames that would be appropriate without the dock. + df.left = cf.left = vf.left = mDockLeft; + df.top = cf.top = vf.top = mDockTop; + df.right = cf.right = vf.right = mDockRight; + df.bottom = cf.bottom = vf.bottom = mDockBottom; + } else { + // The effective display frame of the attached window depends on + // whether it is taking care of insetting its content. If not, + // we need to use the parent's content frame so that the entire + // window is positioned within that content. Otherwise we can use + // the display frame and let the attached window take care of + // positioning its content appropriately. + if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { + cf.set(attached.getDisplayFrameLw()); + } else { + // If the window is resizing, then we want to base the content + // frame on our attached content frame to resize... however, + // things can be tricky if the attached window is NOT in resize + // mode, in which case its content frame will be larger. + // Ungh. So to deal with that, make sure the content frame + // we end up using is not covering the IM dock. + cf.set(attached.getContentFrameLw()); + if (attached.getSurfaceLayer() < mDockLayer) { + if (cf.left < mContentLeft) cf.left = mContentLeft; + if (cf.top < mContentTop) cf.top = mContentTop; + if (cf.right > mContentRight) cf.right = mContentRight; + if (cf.bottom > mContentBottom) cf.bottom = mContentBottom; + } + } + df.set(insetDecors ? attached.getDisplayFrameLw() : cf); + vf.set(attached.getVisibleFrameLw()); + } + // The LAYOUT_IN_SCREEN flag is used to determine whether the attached + // window should be positioned relative to its parent or the entire + // screen. + pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 + ? attached.getFrameLw() : df); + } + /** {@inheritDoc} */ public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached) { // we've already done the status bar @@ -883,52 +1009,132 @@ public class PhoneWindowManager implements WindowManagerPolicy { return; } + if (false) { + if ("com.google.android.youtube".equals(attrs.packageName) + && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { + Log.i(TAG, "GOTCHA!"); + } + } + final int fl = attrs.flags; + final int sim = attrs.softInputMode; + + final Rect pf = mTmpParentFrame; + final Rect df = mTmpDisplayFrame; + final Rect cf = mTmpContentFrame; + final Rect vf = mTmpVisibleFrame; - int dl, dt, dr, db; - if ((fl & FLAG_LAYOUT_IN_SCREEN) == 0) { - // Make sure this window doesn't intrude into the status bar. - dl = mCurLeft; - dt = mCurTop; - dr = mCurRight; - db = mCurBottom; + if (attrs.type == TYPE_INPUT_METHOD) { + pf.left = df.left = cf.left = vf.left = mDockLeft; + pf.top = df.top = cf.top = vf.top = mDockTop; + pf.right = df.right = cf.right = vf.right = mDockRight; + pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom; + // IM dock windows always go to the bottom of the screen. + attrs.gravity = Gravity.BOTTOM; + mDockLayer = win.getSurfaceLayer(); } else { - dl = 0; - dt = 0; - dr = mW; - db = mH; + if ((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 + // to cover all of the screen space, and it can take care of + // moving its contents to account for screen decorations that + // intrude into that space. + if (attached != null) { + // If this window is attached to another, our display + // frame is the same as the one we are attached to. + setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf); + } else { + pf.left = df.left = 0; + pf.top = df.top = 0; + pf.right = df.right = mW; + pf.bottom = df.bottom = mH; + if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { + cf.left = mDockLeft; + cf.top = mDockTop; + cf.right = mDockRight; + cf.bottom = mDockBottom; + } else { + cf.left = mContentLeft; + cf.top = mContentTop; + cf.right = mContentRight; + cf.bottom = mContentBottom; + } + vf.left = mCurLeft; + vf.top = mCurTop; + vf.right = mCurRight; + vf.bottom = mCurBottom; + } + } else if ((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; + pf.top = df.top = cf.top = 0; + pf.right = df.right = cf.right = mW; + pf.bottom = df.bottom = cf.bottom = mH; + vf.left = mCurLeft; + vf.top = mCurTop; + vf.right = mCurRight; + vf.bottom = mCurBottom; + } else if (attached != null) { + // A child window should be placed inside of the same visible + // frame that its parent had. + setAttachedWindowFrames(win, fl, sim, attached, false, pf, df, cf, vf); + } else { + // Otherwise, a normal window must be placed inside the content + // of all screen decorations. + pf.left = mContentLeft; + pf.top = mContentTop; + pf.right = mContentRight; + pf.bottom = mContentBottom; + if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { + df.left = cf.left = mDockLeft; + df.top = cf.top = mDockTop; + df.right = cf.right = mDockRight; + df.bottom = cf.bottom = mDockBottom; + } else { + df.left = cf.left = mContentLeft; + df.top = cf.top = mContentTop; + df.right = cf.right = mContentRight; + df.bottom = cf.bottom = mContentBottom; + } + vf.left = mCurLeft; + vf.top = mCurTop; + vf.right = mCurRight; + vf.bottom = mCurBottom; + } } - if ((fl & - (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) - == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { - win.setCoveredInsetsLw(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom); - } else { - win.setCoveredInsetsLw(0, 0, 0, 0); + if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) { + df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000; + df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000; } - int pl, pt, pr, pb; - if (attached != null && (fl & (FLAG_LAYOUT_IN_SCREEN)) == 0) { - final Rect r = attached.getFrameLw(); - pl = r.left; - pt = r.top; - pr = r.right; - pb = r.bottom; - } else { - pl = dl; - pt = dt; - pr = dr; - pb = db; + if (false) { + if ("com.google.android.youtube".equals(attrs.packageName) + && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { + if (true || localLOGV) Log.v(TAG, "Computing frame of " + win + + ": pf=" + pf.toShortString() + " df=" + df.toShortString() + + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()); + } } - if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) { - dl = -100000; - dt = -100000; - dr = 100000; - db = 100000; + win.computeFrameLw(pf, df, cf, vf); + + // Dock windows carve out the bottom of the screen, so normal windows + // can't appear underneath them. + if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) { + int top = win.getContentFrameLw().top; + top += win.getGivenContentInsetsLw().top; + if (mContentBottom > top) { + mContentBottom = top; + } + top = win.getVisibleFrameLw().top; + top += win.getGivenVisibleInsetsLw().top; + if (mCurBottom > top) { + mCurBottom = top; + } } - - win.computeFrameLw(pl, pt, pr, pb, dl, dt, dr, db); } /** {@inheritDoc} */ @@ -1011,7 +1217,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** * @return Whether a telephone call is in progress right now. */ - private boolean isInCall() { + boolean isInCall() { final ITelephony phone = getPhoneInterface(); if (phone == null) { Log.w(TAG, "couldn't get ITelephony reference"); @@ -1028,7 +1234,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** * @return Whether music is being played right now. */ - private boolean isMusicActive() { + boolean isMusicActive() { final IAudioService audio = getAudioInterface(); if (audio == null) { Log.w(TAG, "isMusicActive: couldn't get IAudioService reference"); @@ -1046,7 +1252,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * Tell the audio service to adjust the volume appropriate to the event. * @param keycode */ - private void sendVolToMusic(int keycode) { + void sendVolToMusic(int keycode) { final IAudioService audio = getAudioInterface(); if (audio == null) { Log.w(TAG, "sendVolToMusic: couldn't get IAudioService reference"); @@ -1069,7 +1275,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { mBroadcastWakeLock.release(); } } - + + static boolean isMediaKey(int code) { + if (code == KeyEvent.KEYCODE_HEADSETHOOK || + code == KeyEvent.KEYCODE_PLAYPAUSE || + code == KeyEvent.KEYCODE_STOP || + code == KeyEvent.KEYCODE_NEXTSONG || + code == KeyEvent.KEYCODE_PREVIOUSSONG || + code == KeyEvent.KEYCODE_PREVIOUSSONG || + code == KeyEvent.KEYCODE_FORWARD) { + return true; + } + return false; + } + /** {@inheritDoc} */ public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) { int result = ACTION_PASS_TO_USER; @@ -1165,7 +1384,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { result &= ~ACTION_PASS_TO_USER; } } - } else if (code == KeyEvent.KEYCODE_HEADSETHOOK) { + } else if (isMediaKey(code)) { // This key needs to be handled even if the screen is off. // If others need to be handled while it's off, this is a reasonable // pattern to follow. @@ -1175,7 +1394,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // only do it if the showing app doesn't process the key on its own. KeyEvent keyEvent = new KeyEvent(event.when, event.when, down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP, - KeyEvent.KEYCODE_HEADSETHOOK, 0); + code, 0); mBroadcastWakeLock.acquire(); mHandler.post(new PassHeadsetKey(keyEvent)); } @@ -1200,7 +1419,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private BroadcastReceiver mBroadcastDone = new BroadcastReceiver() { + BroadcastReceiver mBroadcastDone = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { mBroadcastWakeLock.release(); } @@ -1298,20 +1517,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: //always return portrait if orientation set to portrait return Surface.ROTATION_0; - case ActivityInfo.SCREEN_ORIENTATION_SENSOR: - if(mOrientationSensorEnabled) { - //consider only sensor based orientation keyboard slide ignored - return mSensorRotation >= 0 ? mSensorRotation : Surface.ROTATION_0; - } - //if orientation sensor is disabled fall back to default behaviour - //based on lid } // case for nosensor meaning ignore sensor and consider only lid // or orientation sensor disabled //or case.unspecified - if(mLidOpen) { + if (mLidOpen) { return Surface.ROTATION_90; } else { + if (useSensorForOrientation()) { + // If the user has enabled auto rotation by default, do it. + return mSensorRotation >= 0 ? mSensorRotation : Surface.ROTATION_0; + } return Surface.ROTATION_0; } } @@ -1325,11 +1541,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { // If the user is holding the menu key code, then we are // going to boot into safe mode. ActivityManagerNative.getDefault().enterSafeMode(); - } else { - // tell the keyguard - mKeyguardMediator.onSystemReady(); - android.os.SystemProperties.set("dev.bootcomplete", "1"); } + // tell the keyguard + mKeyguardMediator.onSystemReady(); + android.os.SystemProperties.set("dev.bootcomplete", "1"); + updateOrientationListener(); } catch (RemoteException e) { // Ignore } @@ -1341,7 +1557,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateRotation(); } - private void updateRotation() { + void updateRotation() { mPowerManager.setKeyboardVisibility(mLidOpen); int rotation= Surface.ROTATION_0; if (mLidOpen) { diff --git a/policy/com/android/internal/policy/impl/Policy.java b/policy/com/android/internal/policy/impl/Policy.java index f537186766cd..17f3e9129666 100644 --- a/policy/com/android/internal/policy/impl/Policy.java +++ b/policy/com/android/internal/policy/impl/Policy.java @@ -17,6 +17,7 @@ package com.android.internal.policy.impl; import android.content.Context; +import android.util.Log; import com.android.internal.policy.IPolicy; import com.android.internal.policy.impl.PhoneLayoutInflater; @@ -30,6 +31,29 @@ import com.android.internal.policy.impl.PhoneWindowManager; // Simple implementation of the policy interface that spawns the right // set of objects public class Policy implements IPolicy { + private static final String TAG = "PhonePolicy"; + + private static final String[] preload_classes = { + "com.android.internal.policy.impl.PhoneLayoutInflater", + "com.android.internal.policy.impl.PhoneWindow", + "com.android.internal.policy.impl.PhoneWindow$1", + "com.android.internal.policy.impl.PhoneWindow$ContextMenuCallback", + "com.android.internal.policy.impl.PhoneWindow$DecorView", + "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState", + "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState", + }; + + static { + // For performance reasons, preload some policy specific classes when + // the policy gets loaded. + for (String s : preload_classes) { + try { + Class.forName(s); + } catch (ClassNotFoundException ex) { + Log.e(TAG, "Could not preload class for phone policy: " + s); + } + } + } public PhoneWindow makeNewWindow(Context context) { return new PhoneWindow(context); diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java index 4c713925d174..fceec5fb997e 100644 --- a/policy/com/android/internal/policy/impl/SimUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/SimUnlockScreen.java @@ -101,11 +101,19 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie public void onResume() { // start fresh mHeaderText.setText(R.string.keyguard_password_enter_pin_code); + + // make sure that the number of entered digits is consistent when we + // erase the SIM unlock code, including orientation changes. mPinText.setText(""); + mEnteredDigits = 0; } /** {@inheritDoc} */ public void cleanUp() { + // hide the dialog. + if (mSimUnlockProgressDialog != null) { + mSimUnlockProgressDialog.hide(); + } mUpdateMonitor.removeCallback(this); } @@ -143,7 +151,7 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie } } } - + public void onClick(View v) { if (v == mBackSpaceButton) { final Editable digits = mPinText.getText(); @@ -191,7 +199,9 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie new CheckSimPin(mPinText.getText().toString()) { void onSimLockChangedResponse(boolean success) { - getSimUnlockProgressDialog().hide(); + if (mSimUnlockProgressDialog != null) { + mSimUnlockProgressDialog.hide(); + } if (success) { // before closing the keyguard, report back that // the sim is unlocked so it knows right away diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index bd0b6d521e50..65ab439c336f 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -16,9 +16,14 @@ package com.android.internal.policy.impl; +import android.content.ComponentName; import android.content.Context; +import android.content.ServiceConnection; import android.os.CountDownTimer; +import android.os.IBinder; +import android.os.RemoteException; import android.os.SystemClock; +import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -85,6 +90,8 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient private Button mForgotPatternButton; + private ServiceConnection mServiceConnection; + enum FooterMode { Normal, @@ -177,6 +184,9 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient // stealth mode will be the same for the life of this screen mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled()); + // vibrate mode will be the same for the life of this screen + mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled()); + // assume normal footer mode for now updateFooter(FooterMode.Normal); @@ -237,6 +247,10 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mLockPatternView.enableInput(); mLockPatternView.setEnabled(true); mLockPatternView.clearPattern(); + + // show "forgot pattern?" button if we have an alternate authentication method + mForgotPatternButton.setVisibility(mCallback.doesFallbackUnlockScreenExist() + ? View.VISIBLE : View.INVISIBLE); // if the user is currently locked out, enforce it. long deadline = mLockPatternUtils.getLockoutAttemptDeadline(); -- GitLab From 871f4ce2eef7443237aa321d60a52cc011caeacf Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Thu, 15 Jan 2009 14:33:27 -0800 Subject: [PATCH 004/458] Optional provisioning This introduces an ro.requires_provisioning property, which defaults to false, such that by default the platform doesn't require any setup application to set a run-time "provisioned" bit and allows all behaviors right away (home key, lock screen, etc...). --- .../internal/policy/impl/KeyguardUpdateMonitor.java | 9 +++++++-- .../android/internal/policy/impl/PhoneWindowManager.java | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 4671957592cc..a9f93566c600 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -27,6 +27,7 @@ import static android.os.BatteryManager.BATTERY_STATUS_FULL; import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; import android.os.Handler; import android.os.Message; +import android.os.SystemProperties; import android.provider.Settings; import android.provider.Telephony; import static android.provider.Telephony.Intents.EXTRA_PLMN; @@ -160,8 +161,12 @@ public class KeyguardUpdateMonitor { } }; - mDeviceProvisioned = Settings.Secure.getInt( - mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; + if (!SystemProperties.getBoolean("ro.requires_provisioning", false)) { + mDeviceProvisioned = true; + } else { + mDeviceProvisioned = Settings.Secure.getInt( + mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; + } // Since device can't be un-provisioned, we only need to register a content observer // to update mDeviceProvisioned when we are... diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 603b2216e418..2dcf81df7aa3 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -350,6 +350,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } boolean isDeviceProvisioned() { + if (!SystemProperties.getBoolean("ro.requires_provisioning", false)) { + return true; + } return Settings.Secure.getInt( mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; } -- GitLab From 348bd8257e3a173e1668b95056fd02e191a07c9a Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Thu, 15 Jan 2009 16:12:12 -0800 Subject: [PATCH 005/458] auto import from //branches/cupcake/...@126645 --- .../android/internal/policy/impl/KeyguardViewManager.java | 3 ++- policy/com/android/internal/policy/impl/PhoneWindow.java | 5 +---- policy/com/android/internal/policy/impl/PowerDialog.java | 2 ++ .../internal/policy/impl/RecentApplicationsDialog.java | 4 +++- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index a48f4f9e3c58..f5dd3e5f88c5 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -97,7 +97,8 @@ public class KeyguardViewManager { final int stretch = ViewGroup.LayoutParams.FILL_PARENT; int flags = WindowManager.LayoutParams.FLAG_DITHER - | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; + | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN + | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; WindowManager.LayoutParams lp = new WindowManager.LayoutParams( stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD, flags, PixelFormat.OPAQUE); diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index dfc4b6c940be..80a212097eb6 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -65,7 +65,6 @@ import android.view.WindowManager; import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; -import static android.view.WindowManager.LayoutParams.FLAG_RESTORED_STATE; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.FrameLayout; @@ -1376,8 +1375,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return; } - setFlags(FLAG_RESTORED_STATE, FLAG_RESTORED_STATE); - SparseArray savedStates = savedInstanceState.getSparseParcelableArray(VIEWS_TAG); if (savedStates != null) { @@ -1946,7 +1943,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { WindowManager.LayoutParams params = getAttributes(); if (!hasSoftInputMode()) { - params.softInputMode = (byte)a.getInt( + params.softInputMode = a.getInt( com.android.internal.R.styleable.Window_windowSoftInputMode, params.softInputMode); } diff --git a/policy/com/android/internal/policy/impl/PowerDialog.java b/policy/com/android/internal/policy/impl/PowerDialog.java index ce9363e93fdb..77c42abcd402 100644 --- a/policy/com/android/internal/policy/impl/PowerDialog.java +++ b/policy/com/android/internal/policy/impl/PowerDialog.java @@ -72,6 +72,8 @@ public class PowerDialog extends Dialog implements OnClickListener, getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); 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)); diff --git a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java index 0c4a7dce17e9..5442dd4e4bde 100644 --- a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java +++ b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java @@ -78,7 +78,9 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener theWindow.requestFeature(Window.FEATURE_NO_TITLE); theWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); theWindow.setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + theWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, + WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); setContentView(com.android.internal.R.layout.recent_apps_dialog); -- GitLab From 572612e1c05f7640657083743f1e3ed39319d4de Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Wed, 21 Jan 2009 14:53:23 -0800 Subject: [PATCH 006/458] Revert "Optional provisioning" This reverts commit a9f4ccea6d0463345206a4306fdae9376932eb79. --- .../internal/policy/impl/KeyguardUpdateMonitor.java | 9 ++------- .../android/internal/policy/impl/PhoneWindowManager.java | 3 --- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index a9f93566c600..4671957592cc 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -27,7 +27,6 @@ import static android.os.BatteryManager.BATTERY_STATUS_FULL; import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; import android.os.Handler; import android.os.Message; -import android.os.SystemProperties; import android.provider.Settings; import android.provider.Telephony; import static android.provider.Telephony.Intents.EXTRA_PLMN; @@ -161,12 +160,8 @@ public class KeyguardUpdateMonitor { } }; - if (!SystemProperties.getBoolean("ro.requires_provisioning", false)) { - mDeviceProvisioned = true; - } else { - mDeviceProvisioned = Settings.Secure.getInt( - mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; - } + mDeviceProvisioned = Settings.Secure.getInt( + mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; // Since device can't be un-provisioned, we only need to register a content observer // to update mDeviceProvisioned when we are... diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 2dcf81df7aa3..603b2216e418 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -350,9 +350,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } boolean isDeviceProvisioned() { - if (!SystemProperties.getBoolean("ro.requires_provisioning", false)) { - return true; - } return Settings.Secure.getInt( mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; } -- GitLab From f7bff5129402e15e9cd596a72034c0546d0626d6 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Thu, 22 Jan 2009 00:13:43 -0800 Subject: [PATCH 007/458] auto import from //branches/cupcake/...@127436 --- .../internal/policy/impl/PhoneWindowManager.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 603b2216e418..346470f7c568 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -950,7 +950,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { pf.bottom = df.bottom = vf.bottom = displayHeight; mStatusBar.computeFrameLw(pf, df, vf, vf); - mDockTop = mContentTop = mCurTop = mStatusBar.getFrameLw().bottom; + if (mStatusBar.isDisplayedLw()) { + // If the status bar is hidden, we don't want to cause + // windows behind it to scroll. + mDockTop = mContentTop = mCurTop = mStatusBar.getFrameLw().bottom; + } } } @@ -1154,7 +1158,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { && attrs.type >= FIRST_APPLICATION_WINDOW && attrs.type <= LAST_APPLICATION_WINDOW && win.fillsScreenLw(mW, mH, true) - && win.isDisplayedLw()) { + && win.isVisibleLw()) { mTopFullscreenOpaqueWindowState = win; } else if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { mForceStatusBar = true; @@ -1165,16 +1169,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { public boolean finishAnimationLw() { if (mStatusBar != null) { if (mForceStatusBar) { - mStatusBar.showLw(); + mStatusBar.showLw(true); } else if (mTopFullscreenOpaqueWindowState != null) { WindowManager.LayoutParams lp = mTopFullscreenOpaqueWindowState.getAttrs(); boolean hideStatusBar = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; if (hideStatusBar) { - mStatusBar.hideLw(); + mStatusBar.hideLw(true); } else { - mStatusBar.showLw(); + mStatusBar.showLw(true); } } } -- GitLab From 6782641672b29ea4175e1d4cb0526af5dca775a1 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 10 Feb 2009 15:44:04 -0800 Subject: [PATCH 008/458] auto import from //branches/cupcake/...@130745 --- .../policy/impl/AccountUnlockScreen.java | 22 ++- .../internal/policy/impl/KeyguardScreen.java | 7 +- .../policy/impl/KeyguardUpdateMonitor.java | 4 +- .../policy/impl/KeyguardViewManager.java | 36 +++- .../policy/impl/KeyguardViewProperties.java | 5 +- .../policy/impl/KeyguardWindowController.java | 29 +++ .../policy/impl/LockPatternKeyguardView.java | 8 +- .../LockPatternKeyguardViewProperties.java | 6 +- .../internal/policy/impl/LockScreen.java | 5 + .../internal/policy/impl/PhoneWindow.java | 178 +++++++++++------- .../policy/impl/PhoneWindowManager.java | 102 +++++++--- .../internal/policy/impl/SimUnlockScreen.java | 5 + .../internal/policy/impl/UnlockScreen.java | 5 + 13 files changed, 297 insertions(+), 115 deletions(-) create mode 100644 policy/com/android/internal/policy/impl/KeyguardWindowController.java diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index 98cb548d8ff6..573622f32ee9 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -28,8 +28,10 @@ import android.content.ServiceConnection; import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; +import android.text.Editable; import android.text.InputFilter; import android.text.LoginFilter; +import android.text.TextWatcher; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -47,7 +49,7 @@ import android.widget.TextView; * IAccountsService. */ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen, - View.OnClickListener, ServiceConnection { + View.OnClickListener, ServiceConnection, TextWatcher { private static final String LOCK_PATTERN_PACKAGE = "com.android.settings"; @@ -87,8 +89,10 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree mLogin = (EditText) findViewById(R.id.login); mLogin.setFilters(new InputFilter[] { new LoginFilter.UsernameFilterGeneric() } ); + mLogin.addTextChangedListener(this); mPassword = (EditText) findViewById(R.id.password); + mPassword.addTextChangedListener(this); mOk = (Button) findViewById(R.id.ok); mOk.setOnClickListener(this); @@ -105,6 +109,16 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree } } + public void afterTextChanged(Editable s) { + } + + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + public void onTextChanged(CharSequence s, int start, int before, int count) { + mCallback.pokeWakelock(); + } + @Override protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { @@ -112,6 +126,11 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree return mLogin.requestFocus(direction, previouslyFocusedRect); } + /** {@inheritDoc} */ + public boolean needsInput() { + return true; + } + /** {@inheritDoc} */ public void onPause() { @@ -132,6 +151,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree /** {@inheritDoc} */ public void onClick(View v) { + mCallback.pokeWakelock(); if (v == mOk) { if (checkPassword()) { // clear out forgotten password diff --git a/policy/com/android/internal/policy/impl/KeyguardScreen.java b/policy/com/android/internal/policy/impl/KeyguardScreen.java index 739664b30388..bbb687554e73 100644 --- a/policy/com/android/internal/policy/impl/KeyguardScreen.java +++ b/policy/com/android/internal/policy/impl/KeyguardScreen.java @@ -22,6 +22,12 @@ package com.android.internal.policy.impl; */ public interface KeyguardScreen { + /** + * Return true if your view needs input, so should allow the soft + * keyboard to be displayed. + */ + boolean needsInput(); + /** * This screen is no longer in front of the user. */ @@ -36,5 +42,4 @@ public interface KeyguardScreen { * This view is going away; a hook to do cleanup. */ void cleanUp(); - } diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 4671957592cc..3a25d38d9ef6 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -375,12 +375,12 @@ public class KeyguardUpdateMonitor { } /** - * Is the keyboard currently open? + * Is the (hard) keyboard currently open? */ boolean queryKeyboardOpen() { final Configuration configuration = mContext.getResources().getConfiguration(); - return configuration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO; + return configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO; } /** diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index f5dd3e5f88c5..567c9122e380 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -19,6 +19,7 @@ package com.android.internal.policy.impl; import com.android.internal.R; import android.content.Context; +import android.content.pm.ActivityInfo; import android.graphics.PixelFormat; import android.graphics.Canvas; import android.util.Log; @@ -34,7 +35,7 @@ import android.widget.FrameLayout; * the wake lock and report that the keyguard is done, which is in turn, * reported to this class by the current {@link KeyguardViewBase}. */ -public class KeyguardViewManager { +public class KeyguardViewManager implements KeyguardWindowController { private final static boolean DEBUG = false; private static String TAG = "KeyguardViewManager"; @@ -45,6 +46,9 @@ public class KeyguardViewManager { private final KeyguardUpdateMonitor mUpdateMonitor; + private WindowManager.LayoutParams mWindowLayoutParams; + private boolean mNeedsInput = false; + private FrameLayout mKeyguardHost; private KeyguardViewBase mKeyguardView; @@ -97,19 +101,27 @@ public class KeyguardViewManager { final int stretch = ViewGroup.LayoutParams.FILL_PARENT; int flags = WindowManager.LayoutParams.FLAG_DITHER - | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN - | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ + | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; + if (!mNeedsInput) { + flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + } WindowManager.LayoutParams lp = new WindowManager.LayoutParams( stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD, flags, PixelFormat.OPAQUE); + lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; + lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen; + lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; lp.setTitle("Keyguard"); + mWindowLayoutParams = lp; mViewManager.addView(mKeyguardHost, lp); } if (mKeyguardView == null) { if (DEBUG) Log.d(TAG, "keyguard view is null, creating it..."); - mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor); + mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor, this); mKeyguardView.setId(R.id.lock_screen); mKeyguardView.setCallback(mCallback); @@ -128,6 +140,20 @@ public class KeyguardViewManager { mKeyguardView.requestFocus(); } + public void setNeedsInput(boolean needsInput) { + mNeedsInput = needsInput; + if (mWindowLayoutParams != null) { + if (needsInput) { + mWindowLayoutParams.flags &= + ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + } else { + mWindowLayoutParams.flags |= + WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + } + mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); + } + } + /** * Reset the state of the view. */ @@ -183,7 +209,7 @@ public class KeyguardViewManager { public synchronized void hide() { if (DEBUG) Log.d(TAG, "hide()"); if (mKeyguardHost != null) { - mKeyguardHost.setVisibility(View.INVISIBLE); + mKeyguardHost.setVisibility(View.GONE); if (mKeyguardView != null) { mKeyguardHost.removeView(mKeyguardView); mKeyguardView.cleanUp(); diff --git a/policy/com/android/internal/policy/impl/KeyguardViewProperties.java b/policy/com/android/internal/policy/impl/KeyguardViewProperties.java index a449653a2647..bda08eb4252e 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewProperties.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewProperties.java @@ -29,9 +29,12 @@ public interface KeyguardViewProperties { * Create a keyguard view. * @param context the context to use when creating the view. * @param updateMonitor configuration may be based on this. + * @param controller for talking back with the containing window. * @return the view. */ - KeyguardViewBase createKeyguardView(Context context, KeyguardUpdateMonitor updateMonitor); + KeyguardViewBase createKeyguardView(Context context, + KeyguardUpdateMonitor updateMonitor, + KeyguardWindowController controller); /** * Would the keyguard be secure right now? diff --git a/policy/com/android/internal/policy/impl/KeyguardWindowController.java b/policy/com/android/internal/policy/impl/KeyguardWindowController.java new file mode 100644 index 000000000000..4ad48fb8e007 --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardWindowController.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2009 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; + +/** + * Interface passed to the keyguard view, for it to call up to control + * its containing window. + */ +public interface KeyguardWindowController { + /** + * Control whether the window needs input -- that is if it has + * text fields and thus should allow input method interaction. + */ + void setNeedsInput(boolean needsInput); +} diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 4ff87e3a196c..1ec7e1507556 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -53,6 +53,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { private static final String TAG = "LockPatternKeyguardView"; private final KeyguardUpdateMonitor mUpdateMonitor; + private final KeyguardWindowController mWindowController; + private View mLockScreen; private View mUnlockScreen; @@ -147,7 +149,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { public LockPatternKeyguardView( Context context, KeyguardUpdateMonitor updateMonitor, - LockPatternUtils lockPatternUtils) { + LockPatternUtils lockPatternUtils, + KeyguardWindowController controller) { super(context); asyncCheckForAccount(); @@ -157,6 +160,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { mUpdateMonitor = updateMonitor; mLockPatternUtils = lockPatternUtils; + mWindowController = controller; mMode = getInitialMode(); @@ -417,6 +421,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { goneScreen.setVisibility(View.GONE); visibleScreen.setVisibility(View.VISIBLE); + mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); + if (!visibleScreen.requestFocus()) { throw new IllegalStateException("keyguard screen must be able to take " + "focus when shown " + visibleScreen.getClass().getCanonicalName()); diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java index 697c0382884f..4e0cf09c2ad0 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java @@ -43,8 +43,10 @@ public class LockPatternKeyguardViewProperties implements KeyguardViewProperties } public KeyguardViewBase createKeyguardView(Context context, - KeyguardUpdateMonitor updateMonitor) { - return new LockPatternKeyguardView(context, updateMonitor, mLockPatternUtils); + KeyguardUpdateMonitor updateMonitor, + KeyguardWindowController controller) { + return new LockPatternKeyguardView(context, updateMonitor, + mLockPatternUtils, controller); } public boolean isSecure() { diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 0825c3bde2ee..700c9eba9468 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -350,6 +350,11 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } + /** {@inheritDoc} */ + public boolean needsInput() { + return false; + } + /** {@inheritDoc} */ public void onPause() { diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 80a212097eb6..6afe528c5539 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -1,5 +1,4 @@ /* - * 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. @@ -67,6 +66,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import android.view.animation.Animation; import android.view.animation.AnimationUtils; +import android.view.inputmethod.InputMethodManager; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ProgressBar; @@ -149,39 +149,52 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private boolean mSearchKeyDownReceived; - private final Handler mKeycodeCallTimeoutHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - if (!mKeycodeCallTimeoutActive) return; - mKeycodeCallTimeoutActive = false; - // launch the VoiceDialer - Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - getContext().startActivity(intent); - } catch (ActivityNotFoundException e) { - startCallActivity(); - } - } - }; private boolean mKeycodeCallTimeoutActive = false; - // Ideally the call and camera buttons would share a common base class, and each implement their - // own onShortPress() and onLongPress() methods, but to reduce the chance of regressions I'm - // keeping them separate for now. - private final Handler mKeycodeCameraTimeoutHandler = new Handler() { + private boolean mKeycodeCameraTimeoutActive = false; + + static final int MSG_MENU_LONG_PRESS = 1; + static final int MSG_CALL_LONG_PRESS = 2; + static final int MSG_CAMERA_LONG_PRESS = 3; + + private final Handler mKeycodeMenuTimeoutHandler = new Handler() { @Override public void handleMessage(Message msg) { - if (!mKeycodeCameraTimeoutActive) return; - mKeycodeCameraTimeoutActive = false; - // Broadcast an intent that the Camera button was longpressed - Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); - intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj); - getContext().sendOrderedBroadcast(intent, null); + switch (msg.what) { + case MSG_MENU_LONG_PRESS: { + if (mPanelChordingKey == 0) return; + mPanelChordingKey = 0; + InputMethodManager imm = (InputMethodManager) + getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + imm.showSoftInputUnchecked(InputMethodManager.SHOW_FORCED); + } + } break; + case MSG_CALL_LONG_PRESS: { + if (!mKeycodeCallTimeoutActive) return; + mKeycodeCallTimeoutActive = false; + // launch the VoiceDialer + Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + sendCloseSystemWindows(); + getContext().startActivity(intent); + } catch (ActivityNotFoundException e) { + startCallActivity(); + } + } break; + case MSG_CAMERA_LONG_PRESS: { + if (!mKeycodeCameraTimeoutActive) return; + mKeycodeCameraTimeoutActive = false; + // Broadcast an intent that the Camera button was longpressed + Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj); + getContext().sendOrderedBroadcast(intent, null); + } break; + } } }; - private boolean mKeycodeCameraTimeoutActive = false; - + public PhoneWindow(Context context) { super(context); mLayoutInflater = LayoutInflater.from(context); @@ -566,6 +579,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { PanelFeatureState st = getPanelState(featureId, true); if (!st.isOpen) { + if (getContext().getResources().getConfiguration().keyboard + == Configuration.KEYBOARD_NOKEYS) { + mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); + mKeycodeMenuTimeoutHandler.sendMessageDelayed( + mKeycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS), + ViewConfiguration.getLongPressTimeout()); + } return preparePanel(st, event); } @@ -579,37 +599,40 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { */ public final void onKeyUpPanel(int featureId, KeyEvent event) { // The panel key was released, so clear the chording key - mPanelChordingKey = 0; - - boolean playSoundEffect = false; - PanelFeatureState st = getPanelState(featureId, true); - 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; - - // Close menu - closePanel(st, true); - - } else if (st.isPrepared) { - - // Write 'menu opened' to event log - EventLog.writeEvent(50001, 0); - - // Show menu - openPanel(st, event); - - playSoundEffect = true; - } - - if (playSoundEffect) { - AudioManager audioManager = (AudioManager) getContext().getSystemService( - Context.AUDIO_SERVICE); - if (audioManager != null) { - audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); - } else { - Log.w(TAG, "Couldn't get audio manager"); + if (mPanelChordingKey != 0) { + mPanelChordingKey = 0; + mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); + + boolean playSoundEffect = false; + PanelFeatureState st = getPanelState(featureId, true); + 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; + + // Close menu + closePanel(st, true); + + } else if (st.isPrepared) { + + // Write 'menu opened' to event log + EventLog.writeEvent(50001, 0); + + // Show menu + openPanel(st, event); + + playSoundEffect = true; + } + + if (playSoundEffect) { + AudioManager audioManager = (AudioManager) getContext().getSystemService( + Context.AUDIO_SERVICE); + if (audioManager != null) { + audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); + } else { + Log.w(TAG, "Couldn't get audio manager"); + } } } } @@ -1155,10 +1178,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } if (event.getRepeatCount() > 0) break; mKeycodeCameraTimeoutActive = true; - mKeycodeCameraTimeoutHandler.removeMessages(0); - Message message = mKeycodeCameraTimeoutHandler.obtainMessage(0); + mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); + Message message = mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CAMERA_LONG_PRESS); message.obj = event; - mKeycodeCameraTimeoutHandler.sendMessageDelayed(message, + mKeycodeMenuTimeoutHandler.sendMessageDelayed(message, ViewConfiguration.getLongPressTimeout()); return true; } @@ -1191,9 +1214,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } if (event.getRepeatCount() > 0) break; mKeycodeCallTimeoutActive = true; - mKeycodeCallTimeoutHandler.removeMessages(0); - mKeycodeCallTimeoutHandler.sendMessageDelayed( - mKeycodeCallTimeoutHandler.obtainMessage(0), + mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); + mKeycodeMenuTimeoutHandler.sendMessageDelayed( + mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CALL_LONG_PRESS), ViewConfiguration.getLongPressTimeout()); return true; } @@ -1269,7 +1292,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { break; } if (event.getRepeatCount() > 0) break; // Can a key up event repeat? - mKeycodeCameraTimeoutHandler.removeMessages(0); + mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); if (!mKeycodeCameraTimeoutActive) break; mKeycodeCameraTimeoutActive = false; // Add short press behavior here if desired @@ -1281,7 +1304,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { break; } if (event.getRepeatCount() > 0) break; - mKeycodeCallTimeoutHandler.removeMessages(0); + mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); if (!mKeycodeCallTimeoutActive) break; mKeycodeCallTimeoutActive = false; startCallActivity(); @@ -1307,6 +1330,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } private void startCallActivity() { + sendCloseSystemWindows(); Intent intent = new Intent(Intent.ACTION_CALL_BUTTON); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getContext().startActivity(intent); @@ -1854,9 +1878,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { super.onWindowFocusChanged(hasWindowFocus); // no KEYCODE_CALL events active across focus changes - mKeycodeCallTimeoutHandler.removeMessages(0); + mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); + mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); + mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); mKeycodeCallTimeoutActive = false; - mKeycodeCameraTimeoutHandler.removeMessages(0); mKeycodeCameraTimeoutActive = false; // If the user is chording a menu shortcut, release the chord since @@ -1958,9 +1983,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { android.R.styleable.Window_backgroundDimAmount, 0.5f); } - params.windowAnimations = a.getResourceId( - com.android.internal.R.styleable.Window_windowAnimationStyle, - params.windowAnimations); + if (params.windowAnimations == 0) { + params.windowAnimations = a.getResourceId( + com.android.internal.R.styleable.Window_windowAnimationStyle, 0); + } // The rest are only done if this window is not embedded; otherwise, // the values are inherited from our container. @@ -2614,4 +2640,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return true; } } + + void sendCloseSystemWindows() { + PhoneWindowManager.sendCloseSystemWindows(getContext(), null); + } + + void sendCloseSystemWindows(String reason) { + PhoneWindowManager.sendCloseSystemWindows(getContext(), reason); + } } diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 346470f7c568..172ab353e15e 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -39,6 +39,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.Vibrator; import android.provider.Settings; import com.android.internal.policy.PolicyManager; @@ -138,13 +139,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; + // Vibrator pattern for indicating when the orientation has changed + private static final long[] VIBE_PATTERN = {0, 1, 40, 41}; + Context mContext; IWindowManager mWindowManager; LocalPowerManager mPowerManager; + Vibrator mVibrator; // Vibrator for giving feedback of orientation changes /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ boolean mEnableShiftMenuBugReports = false; + boolean mSafeMode; WindowState mStatusBar = null; WindowState mSearchBar = null; WindowState mKeyguard = null; @@ -732,6 +738,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode(); } + private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = { + WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, + WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, + }; + /** {@inheritDoc} */ public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, int repeatCount) { @@ -739,7 +750,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (false) { Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount=" - + repeatCount + " keyguardOn=" + keyguardOn); + + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed); } // Clear a pending HOME longpress if the user releases Home @@ -795,15 +806,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { // right now to interact with applications. WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null; if (attrs != null) { - int type = attrs.type; - if (type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW - && type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { - // Only do this once, so home-key-longpress doesn't close itself - if (repeatCount == 0 && down) { - sendCloseSystemWindows(); - } + final int type = attrs.type; + if (type == WindowManager.LayoutParams.TYPE_KEYGUARD + || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) { + // the "app" is keyguard, so give it the key return false; } + final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length; + for (int i=0; i= 0 ? mSensorRotation : Surface.ROTATION_0; + int rotation = mSensorRotation >= 0 ? mSensorRotation : Surface.ROTATION_0; + if (displayEnabled && rotation != lastRotation) { + mVibrator.vibrate(VIBE_PATTERN, -1); + } + return rotation; } return Surface.ROTATION_0; } } + + public boolean detectSafeMode() { + try { + int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU); + mSafeMode = menuState > 0; + Log.i(TAG, "Menu key state: " + menuState + " safeMode=" + mSafeMode); + return mSafeMode; + } catch (RemoteException e) { + // Doom! (it's also local) + throw new RuntimeException("window manager dead"); + } + } /** {@inheritDoc} */ public void systemReady() { try { - int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU); - Log.i(TAG, "Menu key state: " + menuState); - if (menuState > 0) { + if (mSafeMode) { // If the user is holding the menu key code, then we are // going to boot into safe mode. ActivityManagerNative.getDefault().enterSafeMode(); @@ -1550,11 +1590,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardMediator.onSystemReady(); android.os.SystemProperties.set("dev.bootcomplete", "1"); updateOrientationListener(); + mVibrator = new Vibrator(); } catch (RemoteException e) { // Ignore } } - + + /** {@inheritDoc} */ public void enableScreenAfterBoot() { readLidState(); diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java index fceec5fb997e..9453212d4ad1 100644 --- a/policy/com/android/internal/policy/impl/SimUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/SimUnlockScreen.java @@ -92,6 +92,11 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie setFocusableInTouchMode(true); } + /** {@inheritDoc} */ + public boolean needsInput() { + return true; + } + /** {@inheritDoc} */ public void onPause() { diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index 65ab439c336f..16208d9c4d27 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -229,6 +229,11 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient /** {@inheritDoc} */ public void onKeyboardChange(boolean isKeyboardOpen) {} + /** {@inheritDoc} */ + public boolean needsInput() { + return false; + } + /** {@inheritDoc} */ public void onPause() { if (mCountdownTimer != null) { -- GitLab From 5a9453de15cee598a2d9fee2550899a7fa03a85c Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Fri, 13 Feb 2009 12:57:52 -0800 Subject: [PATCH 009/458] auto import from //branches/cupcake/...@131421 --- .../internal/policy/impl/LockScreen.java | 1 - .../internal/policy/impl/PhoneWindow.java | 4 + .../policy/impl/PhoneWindowManager.java | 123 ++++++++++++------ 3 files changed, 86 insertions(+), 42 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 700c9eba9468..82a52f9ed993 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -340,7 +340,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } public void onOrientationChange(boolean inPortrait) { - mCallback.pokeWakelock(); } public void onKeyboardChange(boolean isKeyboardOpen) { diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 6afe528c5539..4ae74004cac0 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -46,6 +46,7 @@ import android.util.EventLog; import android.util.Log; import android.util.SparseArray; import android.view.Gravity; +import android.view.HapticFeedbackConstants; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -164,6 +165,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { case MSG_MENU_LONG_PRESS: { if (mPanelChordingKey == 0) return; mPanelChordingKey = 0; + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); if (imm != null) { @@ -173,6 +175,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { case MSG_CALL_LONG_PRESS: { if (!mKeycodeCallTimeoutActive) return; mKeycodeCallTimeoutActive = false; + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); // launch the VoiceDialer Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); @@ -186,6 +189,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { case MSG_CAMERA_LONG_PRESS: { if (!mKeycodeCameraTimeoutActive) return; mKeycodeCameraTimeoutActive = false; + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); // Broadcast an intent that the Camera button was longpressed Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj); diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 172ab353e15e..e76ce548113f 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -48,6 +48,7 @@ import android.util.Config; import android.util.EventLog; import android.util.Log; import android.view.Gravity; +import android.view.HapticFeedbackConstants; import android.view.IWindowManager; import android.view.KeyEvent; import android.view.MotionEvent; @@ -86,12 +87,10 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; +import android.view.WindowManagerPolicy.WindowState; import android.media.IAudioService; import android.media.AudioManager; -import java.util.Observable; -import java.util.Observer; - /** * WindowManagerPolicy implementation for the Android phone UI. */ @@ -139,8 +138,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; - // Vibrator pattern for indicating when the orientation has changed - private static final long[] VIBE_PATTERN = {0, 1, 40, 41}; + // Vibrator pattern for haptic feedback of a long press. + private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 40, 41}; + // Vibrator pattern for haptic feedback of a zoom ring tick + private static final long[] ZOOM_RING_TICK_VIBE_PATTERN = {0, 1, 40, 41}; Context mContext; IWindowManager mWindowManager; @@ -276,7 +277,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // it needs to call back and get the sensor orientation. mSensorRotation = rotation; try { - mWindowManager.setRotation(USE_LAST_ROTATION, false); + mWindowManager.setRotation(rotation, false); } catch (RemoteException e) { // Ignore } @@ -298,6 +299,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } + boolean needSensorRunning() { + if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { + // If the application has explicitly requested to follow the + // orientation, then we need to turn the sensor or. + return true; + } + if (mAccelerometerDefault != 0) { + // If the setting for using the sensor by default is enabled, then + // we will always leave it on. Note that the user could go to + // a window that forces an orientation that does not use the + // sensor and in theory we could turn it off... however, when next + // turning it on we won't have a good value for the current + // orientation for a little bit, which can cause orientation + // changes to lag, so we'd like to keep it always on. (It will + // still be turned off when the screen is off.) + return true; + } + return false; + } + /* * Various use cases for invoking this function * screen turning off, should always disable listeners if already enabled @@ -316,12 +337,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { ", SensorEnabled="+mOrientationSensorEnabled); boolean disable = true; if(mScreenOn) { - if(useSensorForOrientation()) { + if(needSensorRunning()) { disable = false; //enable listener if not already enabled if(!mOrientationSensorEnabled) { mOrientationListener.enable(); if(localLOGV) Log.i(TAG, "Enabling listeners"); + // We haven't had the sensor on, so don't yet know + // the rotation. + mSensorRotation = -1; mOrientationSensorEnabled = true; } } @@ -330,6 +354,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if(disable && mOrientationSensorEnabled) { mOrientationListener.disable(); if(localLOGV) Log.i(TAG, "Disabling listeners"); + mSensorRotation = -1; mOrientationSensorEnabled = false; } } @@ -337,6 +362,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Runnable mEndCallLongPress = new Runnable() { public void run() { mShouldTurnOffOnKeyUp = false; + performHapticFeedback(null, HapticFeedbackConstants.LONG_PRESS, false); sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); showGlobalActionsDialog(); } @@ -370,6 +396,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * the user lets go of the home key */ mHomePressed = false; + performHapticFeedback(null, HapticFeedbackConstants.LONG_PRESS, false); sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS); showRecentAppsDialog(); } @@ -477,16 +504,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { config.hardKeyboardHidden = lidOpen ? Configuration.KEYBOARDHIDDEN_NO : Configuration.KEYBOARDHIDDEN_YES; - if (keyguardIsShowingTq()) { - if (mLidOpen) { - // only do this if it's opening -- closing the device shouldn't turn it - // off, but it also shouldn't turn it on. - mKeyguardMediator.pokeWakelock(); - } - } else { - mPowerManager.userActivity(SystemClock.uptimeMillis(), false, - LocalPowerManager.OTHER_EVENT); - } } public boolean isCheekPressedAgainstScreen(MotionEvent ev) { @@ -595,11 +612,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { win.setType( WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); + // Force the window flags: this is a fake window, so it is not really + // touchable or focusable by the user. We also add in the ALT_FOCUSABLE_IM + // flag because we do know that the next window will take input + // focus, so we want to get the IME window up on top of us right away. win.setFlags( WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| + WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| + WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); win.setLayout(WindowManager.LayoutParams.FILL_PARENT, WindowManager.LayoutParams.FILL_PARENT); @@ -965,7 +988,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { pf.bottom = df.bottom = vf.bottom = displayHeight; mStatusBar.computeFrameLw(pf, df, vf, vf); - if (mStatusBar.isDisplayedLw()) { + 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; @@ -1210,6 +1233,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { // lid changed state mLidOpen = event.value == 0; updateRotation(); + if (keyguardIsShowingTq()) { + if (mLidOpen) { + // only do this if it's opening -- closing the device shouldn't turn it + // off, but it also shouldn't turn it on. + mKeyguardMediator.pokeWakelock(); + } + } else { + // Light up the keyboard if we are sliding up. + if (mLidOpen) { + mPowerManager.userActivity(SystemClock.uptimeMillis(), false, + LocalPowerManager.BUTTON_EVENT); + } else { + mPowerManager.userActivity(SystemClock.uptimeMillis(), false, + LocalPowerManager.OTHER_EVENT); + } + } } } return false; @@ -1556,11 +1595,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else { if (useSensorForOrientation()) { // If the user has enabled auto rotation by default, do it. - int rotation = mSensorRotation >= 0 ? mSensorRotation : Surface.ROTATION_0; - if (displayEnabled && rotation != lastRotation) { - mVibrator.vibrate(VIBE_PATTERN, -1); - } - return rotation; + return mSensorRotation >= 0 ? mSensorRotation : lastRotation; } return Surface.ROTATION_0; } @@ -1617,22 +1652,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } catch (RemoteException e) { // Ignore } - if (keyguardIsShowingTq()) { - if (mLidOpen) { - // only do this if it's opening -- closing the device shouldn't turn it - // off, but it also shouldn't turn it on. - mKeyguardMediator.pokeWakelock(); - } - } else { - // Light up the keyboard if we are sliding up. - if (mLidOpen) { - mPowerManager.userActivity(SystemClock.uptimeMillis(), false, - LocalPowerManager.BUTTON_EVENT); - } else { - mPowerManager.userActivity(SystemClock.uptimeMillis(), false, - LocalPowerManager.OTHER_EVENT); - } - } } /** @@ -1668,4 +1687,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateOrientationListener(); } } + + public boolean performHapticFeedback(WindowState win, int effectId, boolean always) { + if (!always && Settings.System.getInt(mContext.getContentResolver(), + Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) { + return false; + } + switch (effectId) { + case HapticFeedbackConstants.LONG_PRESS: + mVibrator.vibrate(LONG_PRESS_VIBE_PATTERN, -1); + return true; + case HapticFeedbackConstants.ZOOM_RING_TICK: + mVibrator.vibrate(ZOOM_RING_TICK_VIBE_PATTERN, -1); + } + return false; + } + + public void screenOnStopped() { + if (!mKeyguardMediator.isShowing()) { + long curTime = SystemClock.uptimeMillis(); + mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); + } + } } -- GitLab From ffe2ab43f8ba77418bc3f5facbce6411de3208f9 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Thu, 19 Feb 2009 10:57:35 -0800 Subject: [PATCH 010/458] auto import from //branches/cupcake/...@132276 --- .../policy/impl/AccountUnlockScreen.java | 7 +- .../policy/impl/PhoneWindowManager.java | 122 ++++++++++++++---- .../internal/policy/impl/UnlockScreen.java | 7 +- 3 files changed, 107 insertions(+), 29 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index 573622f32ee9..b5a144ec604d 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -56,6 +56,11 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree private static final String LOCK_PATTERN_CLASS = "com.android.settings.ChooseLockPattern"; + /** + * The amount of millis to stay awake once this screen detects activity + */ + private static final int AWAKE_POKE_MILLIS = 30000; + private final KeyguardScreenCallback mCallback; private final LockPatternUtils mLockPatternUtils; private IAccountsService mAccountsService; @@ -116,7 +121,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree } public void onTextChanged(CharSequence s, int start, int before, int count) { - mCallback.pokeWakelock(); + mCallback.pokeWakelock(AWAKE_POKE_MILLIS); } @Override diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index e76ce548113f..7b1819df3d73 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -52,7 +52,7 @@ import android.view.HapticFeedbackConstants; import android.view.IWindowManager; import android.view.KeyEvent; import android.view.MotionEvent; -import android.view.OrientationListener; +import android.view.WindowOrientationListener; import android.view.RawInputEvent; import android.view.Surface; import android.view.View; @@ -141,7 +141,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Vibrator pattern for haptic feedback of a long press. private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 40, 41}; // Vibrator pattern for haptic feedback of a zoom ring tick - private static final long[] ZOOM_RING_TICK_VIBE_PATTERN = {0, 1, 40, 41}; + private static final long[] ZOOM_RING_TICK_VIBE_PATTERN = {0, 10}; Context mContext; IWindowManager mWindowManager; @@ -254,33 +254,47 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - class MyOrientationListener extends OrientationListener { - + class MyOrientationListener extends WindowOrientationListener { + private static final int _LOWER_THRESHOLD = 30; + private static final int _UPPER_THRESHOLD = 60; + MyOrientationListener(Context context) { super(context); } @Override public void onOrientationChanged(int orientation) { - // ignore orientation changes unless the value is in a range that - // matches portrait or landscape - // portrait range is 270+45 to 359 and 0 to 45 - // landscape range is 270-45 to 270+45 - if ((orientation >= 0 && orientation <= 45) || (orientation >= 270 - 45)) { - int rotation = (orientation >= 270 - 45 - && orientation <= 270 + 45) + // ignore orientation changes unless the value is in a range + // When switching from portrait to landscape try to use a lower threshold limit + // Use upper threshold limit when switching from landscape to portrait + // this is to delay the switch as much as we can + int rotation; + int threshold = (mSensorRotation == Surface.ROTATION_90) ? _UPPER_THRESHOLD : + _LOWER_THRESHOLD; + + if ((orientation >= 0 && orientation <= _UPPER_THRESHOLD) || + (orientation >= 270 - _LOWER_THRESHOLD)) { + rotation = (orientation >= 270 - _LOWER_THRESHOLD + && orientation <= 270 + threshold) ? Surface.ROTATION_90 : Surface.ROTATION_0; - if (rotation != mSensorRotation) { - if(localLOGV) Log.i(TAG, "onOrientationChanged, rotation changed from "+rotation+" to "+mSensorRotation); - // Update window manager. The lid rotation hasn't changed, - // but we want it to re-evaluate the final rotation in case - // it needs to call back and get the sensor orientation. - mSensorRotation = rotation; - try { - mWindowManager.setRotation(rotation, false); - } catch (RemoteException e) { - // Ignore - } + } else if (orientation == WindowOrientationListener.ORIENTATION_FLAT) { + // return portrait + rotation = Surface.ROTATION_0; + } else { + // ignore orientation value + return; + } + // Send updates based on orientation value + if (rotation != mSensorRotation) { + if(localLOGV) Log.i(TAG, "onOrientationChanged, rotation changed from "+rotation+" to "+mSensorRotation); + // Update window manager. The lid rotation hasn't changed, + // but we want it to re-evaluate the final rotation in case + // it needs to call back and get the sensor orientation. + mSensorRotation = rotation; + try { + mWindowManager.setRotation(rotation, false); + } catch (RemoteException e) { + // Ignore } } } @@ -1355,6 +1369,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { final boolean isWakeKey = isWakeKeyTq(event); final boolean keyguardShowing = keyguardIsShowingTq(); + if (false) { + Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode + + " screenIsOn=" + screenIsOn + " keyguardShowing=" + keyguardShowing); + } + if (keyguardShowing) { if (screenIsOn) { // when the screen is on, always give the event to the keyguard @@ -1458,6 +1477,65 @@ public class PhoneWindowManager implements WindowManagerPolicy { mBroadcastWakeLock.acquire(); mHandler.post(new PassHeadsetKey(keyEvent)); } + } else if (code == KeyEvent.KEYCODE_CALL) { + // If an incoming call is ringing, answer it! + // (We handle this key here, rather than in the InCallScreen, to make + // sure we'll respond to the key even if the InCallScreen hasn't come to + // the foreground yet.) + + // We answer the call on the DOWN event, to agree with + // the "fallback" behavior in the InCallScreen. + if (down) { + try { + ITelephony phoneServ = getPhoneInterface(); + if (phoneServ != null) { + if (phoneServ.isRinging()) { + Log.i(TAG, "interceptKeyTq:" + + " CALL key-down while ringing: Answer the call!"); + phoneServ.answerRingingCall(); + + // And *don't* pass this key thru to the current activity + // (which is presumably the InCallScreen.) + result &= ~ACTION_PASS_TO_USER; + } + } else { + Log.w(TAG, "CALL button: Unable to find ITelephony interface"); + } + } catch (RemoteException ex) { + Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex); + } + } + } else if ((code == KeyEvent.KEYCODE_VOLUME_UP) + || (code == KeyEvent.KEYCODE_VOLUME_DOWN)) { + // If an incoming call is ringing, either VOLUME key means + // "silence ringer". We handle these keys here, rather than + // in the InCallScreen, to make sure we'll respond to them + // even if the InCallScreen hasn't come to the foreground yet. + + // Look for the DOWN event here, to agree with the "fallback" + // behavior in the InCallScreen. + if (down) { + try { + ITelephony phoneServ = getPhoneInterface(); + if (phoneServ != null) { + if (phoneServ.isRinging()) { + Log.i(TAG, "interceptKeyTq:" + + " VOLUME key-down while ringing: Silence ringer!"); + // Silence the ringer. (It's safe to call this + // even if the ringer has already been silenced.) + phoneServ.silenceRinger(); + + // And *don't* pass this key thru to the current activity + // (which is probably the InCallScreen.) + result &= ~ACTION_PASS_TO_USER; + } + } else { + Log.w(TAG, "VOLUME button: Unable to find ITelephony interface"); + } + } catch (RemoteException ex) { + Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex); + } + } } } diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index 16208d9c4d27..51e3621f368a 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -16,14 +16,10 @@ package com.android.internal.policy.impl; -import android.content.ComponentName; import android.content.Context; import android.content.ServiceConnection; import android.os.CountDownTimer; -import android.os.IBinder; -import android.os.RemoteException; import android.os.SystemClock; -import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -304,8 +300,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mCallback.reportFailedPatternAttempt(); } if (mFailedPatternAttemptsSinceLastTimeout >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { - long deadline = SystemClock.elapsedRealtime() + LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS; - mLockPatternUtils.setLockoutAttemptDeadline(deadline); + long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); handleAttemptLockout(deadline); return; } -- GitLab From e1e5e408a44f3dd7783f4795acdfb20646e8e605 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Fri, 20 Feb 2009 07:38:32 -0800 Subject: [PATCH 011/458] auto import from //branches/cupcake/...@132569 --- .../policy/impl/KeyguardViewBase.java | 1 + .../policy/impl/KeyguardViewManager.java | 5 +- .../policy/impl/KeyguardViewMediator.java | 1 + .../internal/policy/impl/PhoneWindow.java | 13 ++--- .../policy/impl/PhoneWindowManager.java | 52 +++++++++++-------- 5 files changed, 42 insertions(+), 30 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/com/android/internal/policy/impl/KeyguardViewBase.java index 5a3ebdee1be4..a565808e76c9 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewBase.java @@ -167,6 +167,7 @@ public abstract class KeyguardViewBase extends FrameLayout { } } else if (event.getAction() == KeyEvent.ACTION_UP) { switch (keyCode) { + case KeyEvent.KEYCODE_MUTE: case KeyEvent.KEYCODE_HEADSETHOOK: case KeyEvent.KEYCODE_PLAYPAUSE: case KeyEvent.KEYCODE_STOP: diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index 567c9122e380..297d62f4a4bf 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -100,10 +100,9 @@ public class KeyguardViewManager implements KeyguardWindowController { mKeyguardHost = new KeyguardViewHost(mContext, mCallback); final int stretch = ViewGroup.LayoutParams.FILL_PARENT; - int flags = WindowManager.LayoutParams.FLAG_DITHER + int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ - | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; + | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ; if (!mNeedsInput) { flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; } diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 2431ffe8075d..e7366c2a72d6 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -641,6 +641,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: + case KeyEvent.KEYCODE_MUTE: case KeyEvent.KEYCODE_HEADSETHOOK: case KeyEvent.KEYCODE_PLAYPAUSE: case KeyEvent.KEYCODE_STOP: diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 4ae74004cac0..9fa59e48f9a9 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -1163,12 +1163,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return true; } - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_MUTE: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: case KeyEvent.KEYCODE_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 7b1819df3d73..0fa8ff57f9d3 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -344,6 +344,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { * screen turning on and current app has nosensor based orientation, do nothing */ void updateOrientationListener() { + if (!mOrientationListener.canDetectOrientation()) { + // If sensor is turned off or nonexistent for some reason + return; + } //Could have been invoked due to screen turning on or off or //change of the currently visible window's orientation if(localLOGV) Log.i(TAG, "Screen status="+mScreenOn+ @@ -1206,15 +1210,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void animatingWindowLw(WindowState win, WindowManager.LayoutParams attrs) { - if (mTopFullscreenOpaqueWindowState == null - && attrs.type >= FIRST_APPLICATION_WINDOW - && attrs.type <= LAST_APPLICATION_WINDOW - && win.fillsScreenLw(mW, mH, true) - && win.isVisibleLw()) { - mTopFullscreenOpaqueWindowState = win; - } else if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0 - && win.isVisibleLw()) { - mForceStatusBar = true; + if (win.isVisibleLw()) { + if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { + mForceStatusBar = true; + } else if (mTopFullscreenOpaqueWindowState == null + && attrs.type >= FIRST_APPLICATION_WINDOW + && attrs.type <= LAST_APPLICATION_WINDOW + && win.fillsScreenLw(mW, mH, true, false) + && win.isVisibleLw()) { + mTopFullscreenOpaqueWindowState = win; + } } } @@ -1222,21 +1227,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { public boolean finishAnimationLw() { boolean changed = false; if (mStatusBar != null) { + //Log.i(TAG, "force=" + mForceStatusBar + // + " top=" + mTopFullscreenOpaqueWindowState); if (mForceStatusBar) { changed |= mStatusBar.showLw(true); } else if (mTopFullscreenOpaqueWindowState != null) { - WindowManager.LayoutParams lp = - mTopFullscreenOpaqueWindowState.getAttrs(); - boolean hideStatusBar = - (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; - if (hideStatusBar) { - changed |= mStatusBar.hideLw(true); - } else { - changed |= mStatusBar.showLw(true); - } - } - } - return changed; + //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) { + changed |= mStatusBar.hideLw(true); + } else { + changed |= mStatusBar.showLw(true); + } + } + } + return changed; } /** {@inheritDoc} */ -- GitLab From e10e0bc28891c4a8b63ebf5be526454148d25f91 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Mon, 2 Mar 2009 22:54:37 -0800 Subject: [PATCH 012/458] auto import from //depot/cupcake/@137055 --- .../policy/impl/AccountUnlockScreen.java | 71 ++++++- .../internal/policy/impl/GlobalActions.java | 200 +++++++++++++----- .../policy/impl/LockPatternKeyguardView.java | 75 ++++++- .../internal/policy/impl/PhoneWindow.java | 40 +++- .../policy/impl/PhoneWindowManager.java | 4 +- .../internal/policy/impl/UnlockScreen.java | 2 +- 6 files changed, 328 insertions(+), 64 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index b5a144ec604d..65102c67fc8b 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -32,6 +32,7 @@ import android.text.Editable; import android.text.InputFilter; import android.text.LoginFilter; import android.text.TextWatcher; +import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -50,8 +51,6 @@ import android.widget.TextView; */ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen, View.OnClickListener, ServiceConnection, TextWatcher { - - private static final String LOCK_PATTERN_PACKAGE = "com.android.settings"; private static final String LOCK_PATTERN_CLASS = "com.android.settings.ChooseLockPattern"; @@ -135,7 +134,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree public boolean needsInput() { return true; } - + /** {@inheritDoc} */ public void onPause() { @@ -192,11 +191,75 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree return super.dispatchKeyEvent(event); } + /** + * Given the string the user entered in the 'username' field, find + * the stored account that they probably intended. Prefer, in order: + * + * - an exact match for what was typed, or + * - a case-insensitive match for what was typed, or + * - if they didn't include a domain, an exact match of the username, or + * - if they didn't include a domain, a case-insensitive + * match of the username. + * + * If there is a tie for the best match, choose neither -- + * the user needs to be more specific. + * + * @return an account name from the database, or null if we can't + * find a single best match. + */ + private String findIntendedAccount(String username) { + String[] accounts = null; + try { + accounts = mAccountsService.getAccounts(); + } catch (RemoteException e) { + return null; + } + if (accounts == null) { + return null; + } + + // Try to figure out which account they meant if they + // typed only the username (and not the domain), or got + // the case wrong. + + String bestAccount = null; + int bestScore = 0; + for (String a: accounts) { + int score = 0; + if (username.equals(a)) { + score = 4; + } else if (username.equalsIgnoreCase(a)) { + score = 3; + } else if (username.indexOf('@') < 0) { + int i = a.indexOf('@'); + if (i >= 0) { + String aUsername = a.substring(0, i); + if (username.equals(aUsername)) { + score = 2; + } else if (username.equalsIgnoreCase(aUsername)) { + score = 1; + } + } + } + if (score > bestScore) { + bestAccount = a; + bestScore = score; + } else if (score == bestScore) { + bestAccount = null; + } + } + return bestAccount; + } + private boolean checkPassword() { final String login = mLogin.getText().toString(); final String password = mPassword.getText().toString(); try { - return mAccountsService.shouldUnlock(login, password); + String account = findIntendedAccount(login); + if (account == null) { + return false; + } + return mAccountsService.shouldUnlock(account, password); } catch (RemoteException e) { return false; } diff --git a/policy/com/android/internal/policy/impl/GlobalActions.java b/policy/com/android/internal/policy/impl/GlobalActions.java index 7f8e57b13778..eeb875a2f4be 100644 --- a/policy/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/com/android/internal/policy/impl/GlobalActions.java @@ -16,29 +16,30 @@ package com.android.internal.policy.impl; -import com.android.internal.R; -import com.google.android.collect.Lists; - import android.app.AlertDialog; import android.app.StatusBarManager; -import android.content.Context; import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; -import android.content.DialogInterface; import android.media.AudioManager; -import android.os.LocalPowerManager; import android.os.Handler; import android.os.Message; -import android.os.SystemClock; +import android.provider.Settings; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.BaseAdapter; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.TextView; +import com.android.internal.R; +import com.google.android.collect.Lists; import java.util.ArrayList; @@ -49,34 +50,41 @@ import java.util.ArrayList; */ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener { + private static final String TAG = "GlobalActions"; + private StatusBarManager mStatusBar; private final Context mContext; - private final LocalPowerManager mPowerManager; private final AudioManager mAudioManager; + private ArrayList mItems; private AlertDialog mDialog; private ToggleAction mSilentModeToggle; + private ToggleAction mAirplaneModeOn; private MyAdapter mAdapter; private boolean mKeyguardShowing = false; private boolean mDeviceProvisioned = false; + private ToggleAction.State mAirplaneState = ToggleAction.State.Off; /** - * @param context everything needs a context :) - * @param powerManager used to turn the screen off (the lock action). + * @param context everything needs a context :( */ - public GlobalActions(Context context, LocalPowerManager powerManager) { + public GlobalActions(Context context) { mContext = context; - mPowerManager = powerManager; mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); // receive broadcasts IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); context.registerReceiver(mBroadcastReceiver, filter); + + // get notified of phone state changes + TelephonyManager telephonyManager = + (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE); } /** @@ -123,29 +131,48 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } }; - mItems = Lists.newArrayList( - /* Disabled pending bug 1304831 -- key or touch events wake up device before it - * can go to sleep. - // first: lock screen - new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock, R.string.global_action_lock) { + mAirplaneModeOn = new ToggleAction( + R.drawable.ic_lock_airplane_mode, + R.drawable.ic_lock_airplane_mode_off, + R.string.global_actions_toggle_airplane_mode, + R.string.global_actions_airplane_mode_on_status, + R.string.global_actions_airplane_mode_off_status) { - public void onPress() { - mPowerManager.goToSleep(SystemClock.uptimeMillis() + 1); - } + void onToggle(boolean on) { + // Change the system setting + Settings.System.putInt( + mContext.getContentResolver(), + Settings.System.AIRPLANE_MODE_ON, + on ? 1 : 0); + Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.putExtra("state", on); + mContext.sendBroadcast(intent); + } - public boolean showDuringKeyguard() { - return false; - } + @Override + protected void changeStateFromPress(boolean buttonOn) { + mState = buttonOn ? State.TurningOn : State.TurningOff; + mAirplaneState = mState; + } - public boolean showBeforeProvisioning() { - return false; - } - }, - */ - // next: silent mode + public boolean showDuringKeyguard() { + return true; + } + + public boolean showBeforeProvisioning() { + return false; + } + }; + + mItems = Lists.newArrayList( + // silent mode mSilentModeToggle, + // next: airplane mode + mAirplaneModeOn, // last: power off - new SinglePressAction(com.android.internal.R.drawable.ic_lock_power_off, R.string.global_action_power_off) { + new SinglePressAction( + com.android.internal.R.drawable.ic_lock_power_off, + R.string.global_action_power_off) { public void onPress() { // shutdown by making sure radio and power are handled accordingly. @@ -180,10 +207,11 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } private void prepareDialog() { - // TODO: May need another 'Vibrate' toggle button, but for now treat them the same final boolean silentModeOn = mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; - mSilentModeToggle.updateState(silentModeOn); + mSilentModeToggle.updateState( + silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off); + mAirplaneModeOn.updateState(mAirplaneState); mAdapter.notifyDataSetChanged(); if (mKeyguardShowing) { mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); @@ -192,6 +220,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } } + /** {@inheritDoc} */ public void onDismiss(DialogInterface dialog) { mStatusBar.disable(StatusBarManager.DISABLE_NONE); @@ -229,6 +258,16 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac return count; } + @Override + public boolean isEnabled(int position) { + return getItem(position).isEnabled(); + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + public Action getItem(int position) { int filteredPos = 0; @@ -259,7 +298,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac public View getView(int position, View convertView, ViewGroup parent) { Action action = getItem(position); - return action.create(mContext, (LinearLayout) convertView, LayoutInflater.from(mContext)); + return action.create(mContext, convertView, parent, LayoutInflater.from(mContext)); } } @@ -273,7 +312,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac * What each item in the global actions dialog must be able to support. */ private interface Action { - LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater); + View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater); void onPress(); @@ -288,6 +327,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac * device is provisioned. */ boolean showBeforeProvisioning(); + + boolean isEnabled(); } /** @@ -303,12 +344,17 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mMessageResId = messageResId; } + public boolean isEnabled() { + return true; + } + abstract public void onPress(); - public LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater) { - LinearLayout v = (LinearLayout) ((convertView != null) ? + public View create( + Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { + View v = (convertView != null) ? convertView : - inflater.inflate(R.layout.global_actions_item, null)); + inflater.inflate(R.layout.global_actions_item, parent, false); ImageView icon = (ImageView) v.findViewById(R.id.icon); TextView messageView = (TextView) v.findViewById(R.id.message); @@ -326,9 +372,26 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac * A toggle action knows whether it is on or off, and displays an icon * and status message accordingly. */ - static abstract class ToggleAction implements Action { + private static abstract class ToggleAction implements Action { - private boolean mOn = false; + enum State { + Off(false), + TurningOn(true), + TurningOff(true), + On(false); + + private final boolean inTransition; + + State(boolean intermediate) { + inTransition = intermediate; + } + + public boolean inTransition() { + return inTransition; + } + } + + protected State mState = State.Off; // prefs private final int mEnabledIconResId; @@ -356,12 +419,12 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mDisabledStatusMessageResId = disabledStatusMessageResId; } - public LinearLayout create(Context context, LinearLayout convertView, + public View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { - LinearLayout v = (LinearLayout) ((convertView != null) ? + View v = (convertView != null) ? convertView : inflater.inflate(R - .layout.global_actions_item, null)); + .layout.global_actions_item, parent, false); ImageView icon = (ImageView) v.findViewById(R.id.icon); TextView messageView = (TextView) v.findViewById(R.id.message); @@ -369,23 +432,50 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac messageView.setText(mMessageResId); + boolean on = ((mState == State.On) || (mState == State.TurningOn)); icon.setImageDrawable(context.getResources().getDrawable( - (mOn ? mEnabledIconResId : mDisabledIconResid))); - statusView.setText(mOn ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); + (on ? mEnabledIconResId : mDisabledIconResid))); + statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); statusView.setVisibility(View.VISIBLE); + final boolean enabled = isEnabled(); + messageView.setEnabled(enabled); + statusView.setEnabled(enabled); + icon.setEnabled(enabled); + v.setEnabled(enabled); + return v; } - public void onPress() { - updateState(!mOn); - onToggle(mOn); + public final void onPress() { + if (mState.inTransition()) { + Log.w(TAG, "shouldn't be able to toggle when in transition"); + return; + } + + final boolean nowOn = !(mState == State.On); + onToggle(nowOn); + changeStateFromPress(nowOn); + } + + public boolean isEnabled() { + return !mState.inTransition(); + } + + /** + * Implementations may override this if their state can be in on of the intermediate + * states until some notification is received (e.g airplane mode is 'turning off' until + * we know the wireless connections are back online + * @param buttonOn Whether the button was turned on or off + */ + protected void changeStateFromPress(boolean buttonOn) { + mState = buttonOn ? State.On : State.Off; } abstract void onToggle(boolean on); - public void updateState(boolean on) { - mOn = on; + public void updateState(State state) { + mState = state; } } @@ -401,6 +491,16 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } }; + PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + @Override + public void onServiceStateChanged(ServiceState serviceState) { + final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF; + mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off; + mAirplaneModeOn.updateState(mAirplaneState); + mAdapter.notifyDataSetChanged(); + } + }; + private static final int MESSAGE_DISMISS = 0; private Handler mHandler = new Handler() { public void handleMessage(Message msg) { diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 1ec7e1507556..cb3131d0e8b4 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -32,6 +32,12 @@ import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.WindowManager; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.PixelFormat; +import android.graphics.ColorFilter; import com.android.internal.R; import com.android.internal.widget.LockPatternUtils; @@ -233,7 +239,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { showAlmostAtAccountLoginDialog(); - } else if (mHasAccount && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { + } else if (mHasAccount + && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { mLockPatternUtils.setPermanentlyLocked(true); updateScreen(mMode); } else if ((failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) @@ -254,6 +261,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase { setFocusableInTouchMode(true); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); + // wall paper background + final BitmapDrawable drawable = (BitmapDrawable) context.getWallpaper(); + setBackgroundDrawable( + new FastBitmapDrawable(drawable.getBitmap())); + // create both the lock and unlock screen so they are quickly available // when the screen turns on mLockScreen = createLockScreen(); @@ -408,6 +420,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase { final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : getUnlockScreenForCurrentUnlockMode(); + // do this before changing visibility so focus isn't requested before the input + // flag is set + mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); + if (mScreenOn) { if (goneScreen.getVisibility() == View.VISIBLE) { @@ -421,8 +437,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { goneScreen.setVisibility(View.GONE); visibleScreen.setVisibility(View.VISIBLE); - mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); - + if (!visibleScreen.requestFocus()) { throw new IllegalStateException("keyguard screen must be able to take " + "focus when shown " + visibleScreen.getClass().getCanonicalName()); @@ -567,4 +582,58 @@ public class LockPatternKeyguardView extends KeyguardViewBase { WindowManager.LayoutParams.FLAG_BLUR_BEHIND); dialog.show(); } + + /** + * Used to put wallpaper on the background of the lock screen. Centers it Horizontally and + * vertically. + */ + static private class FastBitmapDrawable extends Drawable { + private Bitmap mBitmap; + + private FastBitmapDrawable(Bitmap bitmap) { + mBitmap = bitmap; + } + + @Override + public void draw(Canvas canvas) { + canvas.drawBitmap( + mBitmap, + (getBounds().width() - mBitmap.getWidth()) / 2, + (getBounds().height() - mBitmap.getHeight()) / 2, + null); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public void setAlpha(int alpha) { + } + + @Override + public void setColorFilter(ColorFilter cf) { + } + + @Override + public int getIntrinsicWidth() { + return mBitmap.getWidth(); + } + + @Override + public int getIntrinsicHeight() { + return mBitmap.getHeight(); + } + + @Override + public int getMinimumWidth() { + return mBitmap.getWidth(); + } + + @Override + public int getMinimumHeight() { + return mBitmap.getHeight(); + } + } } diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 9fa59e48f9a9..0d26bfbbfac3 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -155,14 +155,45 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private boolean mKeycodeCameraTimeoutActive = false; static final int MSG_MENU_LONG_PRESS = 1; - static final int MSG_CALL_LONG_PRESS = 2; - static final int MSG_CAMERA_LONG_PRESS = 3; + static final int MSG_MENU_LONG_PRESS_COMPLETE = 2; + static final int MSG_CALL_LONG_PRESS = 3; + static final int MSG_CALL_LONG_PRESS_COMPLETE = 4; + static final int MSG_CAMERA_LONG_PRESS = 5; + static final int MSG_CAMERA_LONG_PRESS_COMPLETE = 6; private final Handler mKeycodeMenuTimeoutHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_MENU_LONG_PRESS: { + if (mPanelChordingKey == 0) return; + // Before actually doing the long press, enqueue another + // message and do the processing there. This helps if + // the app isn't being responsive, and finally woke up -- + // if the window manager wasn't told about it processing + // the down key for too long, it would enqueue the key up + // at a time after the timeout of this message. So we go + // through another message, to make sure we process an up + // before continuing. + mKeycodeMenuTimeoutHandler.sendEmptyMessage( + MSG_MENU_LONG_PRESS_COMPLETE); + break; + } + case MSG_CALL_LONG_PRESS: { + if (!mKeycodeCallTimeoutActive) return; + // See above. + mKeycodeMenuTimeoutHandler.sendEmptyMessage( + MSG_CALL_LONG_PRESS_COMPLETE); + break; + } + case MSG_CAMERA_LONG_PRESS: { + if (!mKeycodeCameraTimeoutActive) return; + // See above. + mKeycodeMenuTimeoutHandler.sendEmptyMessage( + MSG_CAMERA_LONG_PRESS_COMPLETE); + break; + } + case MSG_MENU_LONG_PRESS_COMPLETE: { if (mPanelChordingKey == 0) return; mPanelChordingKey = 0; mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); @@ -172,7 +203,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { imm.showSoftInputUnchecked(InputMethodManager.SHOW_FORCED); } } break; - case MSG_CALL_LONG_PRESS: { + case MSG_CALL_LONG_PRESS_COMPLETE: { if (!mKeycodeCallTimeoutActive) return; mKeycodeCallTimeoutActive = false; mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); @@ -186,7 +217,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { startCallActivity(); } } break; - case MSG_CAMERA_LONG_PRESS: { + case MSG_CAMERA_LONG_PRESS_COMPLETE: { if (!mKeycodeCameraTimeoutActive) return; mKeycodeCameraTimeoutActive = false; mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); @@ -194,6 +225,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj); getContext().sendOrderedBroadcast(intent, null); + sendCloseSystemWindows(); } break; } } diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 0fa8ff57f9d3..d1b757604465 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -139,7 +139,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; // Vibrator pattern for haptic feedback of a long press. - private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 40, 41}; + private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21}; // Vibrator pattern for haptic feedback of a zoom ring tick private static final long[] ZOOM_RING_TICK_VIBE_PATTERN = {0, 10}; @@ -388,7 +388,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { void showGlobalActionsDialog() { if (mGlobalActions == null) { - mGlobalActions = new GlobalActions(mContext, mPowerManager); + mGlobalActions = new GlobalActions(mContext); } final boolean keyguardShowing = mKeyguardMediator.isShowing(); mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index 51e3621f368a..9aedf901d232 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -289,7 +289,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mLockPatternView .setDisplayMode(LockPatternView.DisplayMode.Correct); mUnlockIcon.setVisibility(View.GONE); - mUnlockHeader.setText(R.string.lockscreen_pattern_correct); + mUnlockHeader.setText(""); mCallback.keyguardDone(true); } else { mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); -- GitLab From fee49fc0d29f6864e8f91fcf29cc1a19c4d91ff7 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 14:04:28 -0800 Subject: [PATCH 013/458] auto import from //depot/cupcake/@132589 --- .../policy/impl/AccountUnlockScreen.java | 71 +------ .../internal/policy/impl/GlobalActions.java | 200 +++++------------- .../policy/impl/LockPatternKeyguardView.java | 75 +------ .../internal/policy/impl/PhoneWindow.java | 40 +--- .../policy/impl/PhoneWindowManager.java | 4 +- .../internal/policy/impl/UnlockScreen.java | 2 +- 6 files changed, 64 insertions(+), 328 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index 65102c67fc8b..b5a144ec604d 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -32,7 +32,6 @@ import android.text.Editable; import android.text.InputFilter; import android.text.LoginFilter; import android.text.TextWatcher; -import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -51,6 +50,8 @@ import android.widget.TextView; */ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen, View.OnClickListener, ServiceConnection, TextWatcher { + + private static final String LOCK_PATTERN_PACKAGE = "com.android.settings"; private static final String LOCK_PATTERN_CLASS = "com.android.settings.ChooseLockPattern"; @@ -134,7 +135,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree public boolean needsInput() { return true; } - + /** {@inheritDoc} */ public void onPause() { @@ -191,75 +192,11 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree return super.dispatchKeyEvent(event); } - /** - * Given the string the user entered in the 'username' field, find - * the stored account that they probably intended. Prefer, in order: - * - * - an exact match for what was typed, or - * - a case-insensitive match for what was typed, or - * - if they didn't include a domain, an exact match of the username, or - * - if they didn't include a domain, a case-insensitive - * match of the username. - * - * If there is a tie for the best match, choose neither -- - * the user needs to be more specific. - * - * @return an account name from the database, or null if we can't - * find a single best match. - */ - private String findIntendedAccount(String username) { - String[] accounts = null; - try { - accounts = mAccountsService.getAccounts(); - } catch (RemoteException e) { - return null; - } - if (accounts == null) { - return null; - } - - // Try to figure out which account they meant if they - // typed only the username (and not the domain), or got - // the case wrong. - - String bestAccount = null; - int bestScore = 0; - for (String a: accounts) { - int score = 0; - if (username.equals(a)) { - score = 4; - } else if (username.equalsIgnoreCase(a)) { - score = 3; - } else if (username.indexOf('@') < 0) { - int i = a.indexOf('@'); - if (i >= 0) { - String aUsername = a.substring(0, i); - if (username.equals(aUsername)) { - score = 2; - } else if (username.equalsIgnoreCase(aUsername)) { - score = 1; - } - } - } - if (score > bestScore) { - bestAccount = a; - bestScore = score; - } else if (score == bestScore) { - bestAccount = null; - } - } - return bestAccount; - } - private boolean checkPassword() { final String login = mLogin.getText().toString(); final String password = mPassword.getText().toString(); try { - String account = findIntendedAccount(login); - if (account == null) { - return false; - } - return mAccountsService.shouldUnlock(account, password); + return mAccountsService.shouldUnlock(login, password); } catch (RemoteException e) { return false; } diff --git a/policy/com/android/internal/policy/impl/GlobalActions.java b/policy/com/android/internal/policy/impl/GlobalActions.java index eeb875a2f4be..7f8e57b13778 100644 --- a/policy/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/com/android/internal/policy/impl/GlobalActions.java @@ -16,30 +16,29 @@ package com.android.internal.policy.impl; +import com.android.internal.R; +import com.google.android.collect.Lists; + import android.app.AlertDialog; import android.app.StatusBarManager; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.DialogInterface; +import android.content.BroadcastReceiver; import android.content.Intent; import android.content.IntentFilter; +import android.content.DialogInterface; import android.media.AudioManager; +import android.os.LocalPowerManager; import android.os.Handler; import android.os.Message; -import android.provider.Settings; -import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; -import android.telephony.TelephonyManager; -import android.util.Log; +import android.os.SystemClock; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.BaseAdapter; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; -import com.android.internal.R; -import com.google.android.collect.Lists; import java.util.ArrayList; @@ -50,41 +49,34 @@ import java.util.ArrayList; */ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener { - private static final String TAG = "GlobalActions"; - private StatusBarManager mStatusBar; private final Context mContext; + private final LocalPowerManager mPowerManager; private final AudioManager mAudioManager; - private ArrayList mItems; private AlertDialog mDialog; private ToggleAction mSilentModeToggle; - private ToggleAction mAirplaneModeOn; private MyAdapter mAdapter; private boolean mKeyguardShowing = false; private boolean mDeviceProvisioned = false; - private ToggleAction.State mAirplaneState = ToggleAction.State.Off; /** - * @param context everything needs a context :( + * @param context everything needs a context :) + * @param powerManager used to turn the screen off (the lock action). */ - public GlobalActions(Context context) { + public GlobalActions(Context context, LocalPowerManager powerManager) { mContext = context; + mPowerManager = powerManager; mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); // receive broadcasts IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); context.registerReceiver(mBroadcastReceiver, filter); - - // get notified of phone state changes - TelephonyManager telephonyManager = - (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE); } /** @@ -131,48 +123,29 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } }; - mAirplaneModeOn = new ToggleAction( - R.drawable.ic_lock_airplane_mode, - R.drawable.ic_lock_airplane_mode_off, - R.string.global_actions_toggle_airplane_mode, - R.string.global_actions_airplane_mode_on_status, - R.string.global_actions_airplane_mode_off_status) { - - void onToggle(boolean on) { - // Change the system setting - Settings.System.putInt( - mContext.getContentResolver(), - Settings.System.AIRPLANE_MODE_ON, - on ? 1 : 0); - Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - intent.putExtra("state", on); - mContext.sendBroadcast(intent); - } - - @Override - protected void changeStateFromPress(boolean buttonOn) { - mState = buttonOn ? State.TurningOn : State.TurningOff; - mAirplaneState = mState; - } + mItems = Lists.newArrayList( + /* Disabled pending bug 1304831 -- key or touch events wake up device before it + * can go to sleep. + // first: lock screen + new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock, R.string.global_action_lock) { - public boolean showDuringKeyguard() { - return true; - } + public void onPress() { + mPowerManager.goToSleep(SystemClock.uptimeMillis() + 1); + } - public boolean showBeforeProvisioning() { - return false; - } - }; + public boolean showDuringKeyguard() { + return false; + } - mItems = Lists.newArrayList( - // silent mode + public boolean showBeforeProvisioning() { + return false; + } + }, + */ + // next: silent mode mSilentModeToggle, - // next: airplane mode - mAirplaneModeOn, // last: power off - new SinglePressAction( - com.android.internal.R.drawable.ic_lock_power_off, - R.string.global_action_power_off) { + new SinglePressAction(com.android.internal.R.drawable.ic_lock_power_off, R.string.global_action_power_off) { public void onPress() { // shutdown by making sure radio and power are handled accordingly. @@ -207,11 +180,10 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } private void prepareDialog() { + // TODO: May need another 'Vibrate' toggle button, but for now treat them the same final boolean silentModeOn = mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; - mSilentModeToggle.updateState( - silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off); - mAirplaneModeOn.updateState(mAirplaneState); + mSilentModeToggle.updateState(silentModeOn); mAdapter.notifyDataSetChanged(); if (mKeyguardShowing) { mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); @@ -220,7 +192,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } } - /** {@inheritDoc} */ public void onDismiss(DialogInterface dialog) { mStatusBar.disable(StatusBarManager.DISABLE_NONE); @@ -258,16 +229,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac return count; } - @Override - public boolean isEnabled(int position) { - return getItem(position).isEnabled(); - } - - @Override - public boolean areAllItemsEnabled() { - return false; - } - public Action getItem(int position) { int filteredPos = 0; @@ -298,7 +259,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac public View getView(int position, View convertView, ViewGroup parent) { Action action = getItem(position); - return action.create(mContext, convertView, parent, LayoutInflater.from(mContext)); + return action.create(mContext, (LinearLayout) convertView, LayoutInflater.from(mContext)); } } @@ -312,7 +273,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac * What each item in the global actions dialog must be able to support. */ private interface Action { - View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater); + LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater); void onPress(); @@ -327,8 +288,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac * device is provisioned. */ boolean showBeforeProvisioning(); - - boolean isEnabled(); } /** @@ -344,17 +303,12 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mMessageResId = messageResId; } - public boolean isEnabled() { - return true; - } - abstract public void onPress(); - public View create( - Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { - View v = (convertView != null) ? + public LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater) { + LinearLayout v = (LinearLayout) ((convertView != null) ? convertView : - inflater.inflate(R.layout.global_actions_item, parent, false); + inflater.inflate(R.layout.global_actions_item, null)); ImageView icon = (ImageView) v.findViewById(R.id.icon); TextView messageView = (TextView) v.findViewById(R.id.message); @@ -372,26 +326,9 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac * A toggle action knows whether it is on or off, and displays an icon * and status message accordingly. */ - private static abstract class ToggleAction implements Action { + static abstract class ToggleAction implements Action { - enum State { - Off(false), - TurningOn(true), - TurningOff(true), - On(false); - - private final boolean inTransition; - - State(boolean intermediate) { - inTransition = intermediate; - } - - public boolean inTransition() { - return inTransition; - } - } - - protected State mState = State.Off; + private boolean mOn = false; // prefs private final int mEnabledIconResId; @@ -419,12 +356,12 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mDisabledStatusMessageResId = disabledStatusMessageResId; } - public View create(Context context, View convertView, ViewGroup parent, + public LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater) { - View v = (convertView != null) ? + LinearLayout v = (LinearLayout) ((convertView != null) ? convertView : inflater.inflate(R - .layout.global_actions_item, parent, false); + .layout.global_actions_item, null)); ImageView icon = (ImageView) v.findViewById(R.id.icon); TextView messageView = (TextView) v.findViewById(R.id.message); @@ -432,50 +369,23 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac messageView.setText(mMessageResId); - boolean on = ((mState == State.On) || (mState == State.TurningOn)); icon.setImageDrawable(context.getResources().getDrawable( - (on ? mEnabledIconResId : mDisabledIconResid))); - statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); + (mOn ? mEnabledIconResId : mDisabledIconResid))); + statusView.setText(mOn ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); statusView.setVisibility(View.VISIBLE); - final boolean enabled = isEnabled(); - messageView.setEnabled(enabled); - statusView.setEnabled(enabled); - icon.setEnabled(enabled); - v.setEnabled(enabled); - return v; } - public final void onPress() { - if (mState.inTransition()) { - Log.w(TAG, "shouldn't be able to toggle when in transition"); - return; - } - - final boolean nowOn = !(mState == State.On); - onToggle(nowOn); - changeStateFromPress(nowOn); - } - - public boolean isEnabled() { - return !mState.inTransition(); - } - - /** - * Implementations may override this if their state can be in on of the intermediate - * states until some notification is received (e.g airplane mode is 'turning off' until - * we know the wireless connections are back online - * @param buttonOn Whether the button was turned on or off - */ - protected void changeStateFromPress(boolean buttonOn) { - mState = buttonOn ? State.On : State.Off; + public void onPress() { + updateState(!mOn); + onToggle(mOn); } abstract void onToggle(boolean on); - public void updateState(State state) { - mState = state; + public void updateState(boolean on) { + mOn = on; } } @@ -491,16 +401,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } }; - PhoneStateListener mPhoneStateListener = new PhoneStateListener() { - @Override - public void onServiceStateChanged(ServiceState serviceState) { - final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF; - mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off; - mAirplaneModeOn.updateState(mAirplaneState); - mAdapter.notifyDataSetChanged(); - } - }; - private static final int MESSAGE_DISMISS = 0; private Handler mHandler = new Handler() { public void handleMessage(Message msg) { diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index cb3131d0e8b4..1ec7e1507556 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -32,12 +32,6 @@ import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.WindowManager; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.PixelFormat; -import android.graphics.ColorFilter; import com.android.internal.R; import com.android.internal.widget.LockPatternUtils; @@ -239,8 +233,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { showAlmostAtAccountLoginDialog(); - } else if (mHasAccount - && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { + } else if (mHasAccount && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { mLockPatternUtils.setPermanentlyLocked(true); updateScreen(mMode); } else if ((failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) @@ -261,11 +254,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase { setFocusableInTouchMode(true); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); - // wall paper background - final BitmapDrawable drawable = (BitmapDrawable) context.getWallpaper(); - setBackgroundDrawable( - new FastBitmapDrawable(drawable.getBitmap())); - // create both the lock and unlock screen so they are quickly available // when the screen turns on mLockScreen = createLockScreen(); @@ -420,10 +408,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase { final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : getUnlockScreenForCurrentUnlockMode(); - // do this before changing visibility so focus isn't requested before the input - // flag is set - mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); - if (mScreenOn) { if (goneScreen.getVisibility() == View.VISIBLE) { @@ -437,7 +421,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { goneScreen.setVisibility(View.GONE); visibleScreen.setVisibility(View.VISIBLE); - + mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); + if (!visibleScreen.requestFocus()) { throw new IllegalStateException("keyguard screen must be able to take " + "focus when shown " + visibleScreen.getClass().getCanonicalName()); @@ -582,58 +567,4 @@ public class LockPatternKeyguardView extends KeyguardViewBase { WindowManager.LayoutParams.FLAG_BLUR_BEHIND); dialog.show(); } - - /** - * Used to put wallpaper on the background of the lock screen. Centers it Horizontally and - * vertically. - */ - static private class FastBitmapDrawable extends Drawable { - private Bitmap mBitmap; - - private FastBitmapDrawable(Bitmap bitmap) { - mBitmap = bitmap; - } - - @Override - public void draw(Canvas canvas) { - canvas.drawBitmap( - mBitmap, - (getBounds().width() - mBitmap.getWidth()) / 2, - (getBounds().height() - mBitmap.getHeight()) / 2, - null); - } - - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } - - @Override - public void setAlpha(int alpha) { - } - - @Override - public void setColorFilter(ColorFilter cf) { - } - - @Override - public int getIntrinsicWidth() { - return mBitmap.getWidth(); - } - - @Override - public int getIntrinsicHeight() { - return mBitmap.getHeight(); - } - - @Override - public int getMinimumWidth() { - return mBitmap.getWidth(); - } - - @Override - public int getMinimumHeight() { - return mBitmap.getHeight(); - } - } } diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 0d26bfbbfac3..9fa59e48f9a9 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -155,45 +155,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private boolean mKeycodeCameraTimeoutActive = false; static final int MSG_MENU_LONG_PRESS = 1; - static final int MSG_MENU_LONG_PRESS_COMPLETE = 2; - static final int MSG_CALL_LONG_PRESS = 3; - static final int MSG_CALL_LONG_PRESS_COMPLETE = 4; - static final int MSG_CAMERA_LONG_PRESS = 5; - static final int MSG_CAMERA_LONG_PRESS_COMPLETE = 6; + static final int MSG_CALL_LONG_PRESS = 2; + static final int MSG_CAMERA_LONG_PRESS = 3; private final Handler mKeycodeMenuTimeoutHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_MENU_LONG_PRESS: { - if (mPanelChordingKey == 0) return; - // Before actually doing the long press, enqueue another - // message and do the processing there. This helps if - // the app isn't being responsive, and finally woke up -- - // if the window manager wasn't told about it processing - // the down key for too long, it would enqueue the key up - // at a time after the timeout of this message. So we go - // through another message, to make sure we process an up - // before continuing. - mKeycodeMenuTimeoutHandler.sendEmptyMessage( - MSG_MENU_LONG_PRESS_COMPLETE); - break; - } - case MSG_CALL_LONG_PRESS: { - if (!mKeycodeCallTimeoutActive) return; - // See above. - mKeycodeMenuTimeoutHandler.sendEmptyMessage( - MSG_CALL_LONG_PRESS_COMPLETE); - break; - } - case MSG_CAMERA_LONG_PRESS: { - if (!mKeycodeCameraTimeoutActive) return; - // See above. - mKeycodeMenuTimeoutHandler.sendEmptyMessage( - MSG_CAMERA_LONG_PRESS_COMPLETE); - break; - } - case MSG_MENU_LONG_PRESS_COMPLETE: { if (mPanelChordingKey == 0) return; mPanelChordingKey = 0; mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); @@ -203,7 +172,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { imm.showSoftInputUnchecked(InputMethodManager.SHOW_FORCED); } } break; - case MSG_CALL_LONG_PRESS_COMPLETE: { + case MSG_CALL_LONG_PRESS: { if (!mKeycodeCallTimeoutActive) return; mKeycodeCallTimeoutActive = false; mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); @@ -217,7 +186,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { startCallActivity(); } } break; - case MSG_CAMERA_LONG_PRESS_COMPLETE: { + case MSG_CAMERA_LONG_PRESS: { if (!mKeycodeCameraTimeoutActive) return; mKeycodeCameraTimeoutActive = false; mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); @@ -225,7 +194,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj); getContext().sendOrderedBroadcast(intent, null); - sendCloseSystemWindows(); } break; } } diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index d1b757604465..0fa8ff57f9d3 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -139,7 +139,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; // Vibrator pattern for haptic feedback of a long press. - private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21}; + private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 40, 41}; // Vibrator pattern for haptic feedback of a zoom ring tick private static final long[] ZOOM_RING_TICK_VIBE_PATTERN = {0, 10}; @@ -388,7 +388,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { void showGlobalActionsDialog() { if (mGlobalActions == null) { - mGlobalActions = new GlobalActions(mContext); + mGlobalActions = new GlobalActions(mContext, mPowerManager); } final boolean keyguardShowing = mKeyguardMediator.isShowing(); mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index 9aedf901d232..51e3621f368a 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -289,7 +289,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mLockPatternView .setDisplayMode(LockPatternView.DisplayMode.Correct); mUnlockIcon.setVisibility(View.GONE); - mUnlockHeader.setText(""); + mUnlockHeader.setText(R.string.lockscreen_pattern_correct); mCallback.keyguardDone(true); } else { mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); -- GitLab From 10bf778e493ae9ed7b0a9317bf35f00142e11cb4 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 18:28:48 -0800 Subject: [PATCH 014/458] auto import from //depot/cupcake/@135843 --- policy/Android.mk | 13 - .../policy/impl/AccountUnlockScreen.java | 215 -- .../internal/policy/impl/GlobalActions.java | 414 --- .../internal/policy/impl/KeyguardScreen.java | 45 - .../policy/impl/KeyguardScreenCallback.java | 66 - .../policy/impl/KeyguardUpdateMonitor.java | 552 ---- .../policy/impl/KeyguardViewBase.java | 188 -- .../policy/impl/KeyguardViewCallback.java | 49 - .../policy/impl/KeyguardViewManager.java | 226 -- .../policy/impl/KeyguardViewMediator.java | 915 ------ .../policy/impl/KeyguardViewProperties.java | 46 - .../policy/impl/KeyguardWindowController.java | 29 - .../policy/impl/LockPatternKeyguardView.java | 570 ---- .../LockPatternKeyguardViewProperties.java | 67 - .../internal/policy/impl/LockScreen.java | 371 --- .../policy/impl/PhoneLayoutInflater.java | 73 - .../internal/policy/impl/PhoneWindow.java | 2656 ----------------- .../policy/impl/PhoneWindowManager.java | 1800 ----------- .../android/internal/policy/impl/Policy.java | 69 - .../internal/policy/impl/PowerDialog.java | 179 -- .../policy/impl/RecentApplicationsDialog.java | 255 -- .../internal/policy/impl/ShortcutManager.java | 120 - .../internal/policy/impl/ShutdownThread.java | 138 - .../internal/policy/impl/SimUnlockScreen.java | 366 --- .../internal/policy/impl/UnlockScreen.java | 341 --- .../android/internal/policy/impl/package.html | 5 - 26 files changed, 9768 deletions(-) delete mode 100644 policy/Android.mk delete mode 100644 policy/com/android/internal/policy/impl/AccountUnlockScreen.java delete mode 100644 policy/com/android/internal/policy/impl/GlobalActions.java delete mode 100644 policy/com/android/internal/policy/impl/KeyguardScreen.java delete mode 100644 policy/com/android/internal/policy/impl/KeyguardScreenCallback.java delete mode 100644 policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java delete mode 100644 policy/com/android/internal/policy/impl/KeyguardViewBase.java delete mode 100644 policy/com/android/internal/policy/impl/KeyguardViewCallback.java delete mode 100644 policy/com/android/internal/policy/impl/KeyguardViewManager.java delete mode 100644 policy/com/android/internal/policy/impl/KeyguardViewMediator.java delete mode 100644 policy/com/android/internal/policy/impl/KeyguardViewProperties.java delete mode 100644 policy/com/android/internal/policy/impl/KeyguardWindowController.java delete mode 100644 policy/com/android/internal/policy/impl/LockPatternKeyguardView.java delete mode 100644 policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java delete mode 100644 policy/com/android/internal/policy/impl/LockScreen.java delete mode 100644 policy/com/android/internal/policy/impl/PhoneLayoutInflater.java delete mode 100644 policy/com/android/internal/policy/impl/PhoneWindow.java delete mode 100644 policy/com/android/internal/policy/impl/PhoneWindowManager.java delete mode 100644 policy/com/android/internal/policy/impl/Policy.java delete mode 100644 policy/com/android/internal/policy/impl/PowerDialog.java delete mode 100644 policy/com/android/internal/policy/impl/RecentApplicationsDialog.java delete mode 100644 policy/com/android/internal/policy/impl/ShortcutManager.java delete mode 100644 policy/com/android/internal/policy/impl/ShutdownThread.java delete mode 100644 policy/com/android/internal/policy/impl/SimUnlockScreen.java delete mode 100644 policy/com/android/internal/policy/impl/UnlockScreen.java delete mode 100644 policy/com/android/internal/policy/impl/package.html diff --git a/policy/Android.mk b/policy/Android.mk deleted file mode 100644 index 29f62b872306..000000000000 --- a/policy/Android.mk +++ /dev/null @@ -1,13 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -# the library -# ============================================================ -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - $(call all-subdir-java-files) - -LOCAL_MODULE := android.policy_phone -LOCAL_UNINSTALLABLE_MODULE := true - -include $(BUILD_JAVA_LIBRARY) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java deleted file mode 100644 index b5a144ec604d..000000000000 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2008 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 com.android.internal.widget.LockPatternUtils; - -import android.accounts.AccountsServiceConstants; -import android.accounts.IAccountsService; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.graphics.Rect; -import android.os.IBinder; -import android.os.RemoteException; -import android.text.Editable; -import android.text.InputFilter; -import android.text.LoginFilter; -import android.text.TextWatcher; -import android.util.Log; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; -import android.widget.RelativeLayout; -import android.widget.TextView; - -/** - * When the user forgets their password a bunch of times, we fall back on their - * account's login/password to unlock the phone (and reset their lock pattern). - * - *

    This class is useful only on platforms that support the - * IAccountsService. - */ -public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen, - View.OnClickListener, ServiceConnection, TextWatcher { - - - private static final String LOCK_PATTERN_PACKAGE = "com.android.settings"; - private static final String LOCK_PATTERN_CLASS = - "com.android.settings.ChooseLockPattern"; - - /** - * The amount of millis to stay awake once this screen detects activity - */ - private static final int AWAKE_POKE_MILLIS = 30000; - - private final KeyguardScreenCallback mCallback; - private final LockPatternUtils mLockPatternUtils; - private IAccountsService mAccountsService; - - private TextView mTopHeader; - private TextView mInstructions; - private EditText mLogin; - private EditText mPassword; - private Button mOk; - private Button mEmergencyCall; - - /** - * AccountUnlockScreen constructor. - * - * @throws IllegalStateException if the IAccountsService is not - * available on the current platform. - */ - public AccountUnlockScreen(Context context, - KeyguardScreenCallback callback, - LockPatternUtils lockPatternUtils) { - super(context); - mCallback = callback; - mLockPatternUtils = lockPatternUtils; - - LayoutInflater.from(context).inflate( - R.layout.keyguard_screen_glogin_unlock, this, true); - - mTopHeader = (TextView) findViewById(R.id.topHeader); - - mInstructions = (TextView) findViewById(R.id.instructions); - - mLogin = (EditText) findViewById(R.id.login); - mLogin.setFilters(new InputFilter[] { new LoginFilter.UsernameFilterGeneric() } ); - mLogin.addTextChangedListener(this); - - mPassword = (EditText) findViewById(R.id.password); - mPassword.addTextChangedListener(this); - - mOk = (Button) findViewById(R.id.ok); - mOk.setOnClickListener(this); - - mEmergencyCall = (Button) findViewById(R.id.emergencyCall); - mEmergencyCall.setOnClickListener(this); - - Log.v("AccountUnlockScreen", "debug: Connecting to accounts service"); - final boolean connected = mContext.bindService(AccountsServiceConstants.SERVICE_INTENT, - this, Context.BIND_AUTO_CREATE); - if (!connected) { - Log.v("AccountUnlockScreen", "debug: Couldn't connect to accounts service"); - throw new IllegalStateException("couldn't bind to accounts service"); - } - } - - public void afterTextChanged(Editable s) { - } - - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - public void onTextChanged(CharSequence s, int start, int before, int count) { - mCallback.pokeWakelock(AWAKE_POKE_MILLIS); - } - - @Override - protected boolean onRequestFocusInDescendants(int direction, - Rect previouslyFocusedRect) { - // send focus to the login field - return mLogin.requestFocus(direction, previouslyFocusedRect); - } - - /** {@inheritDoc} */ - public boolean needsInput() { - return true; - } - - /** {@inheritDoc} */ - public void onPause() { - - } - - /** {@inheritDoc} */ - public void onResume() { - // start fresh - mLogin.setText(""); - mPassword.setText(""); - mLogin.requestFocus(); - } - - /** {@inheritDoc} */ - public void cleanUp() { - mContext.unbindService(this); - } - - /** {@inheritDoc} */ - public void onClick(View v) { - mCallback.pokeWakelock(); - if (v == mOk) { - if (checkPassword()) { - // clear out forgotten password - mLockPatternUtils.setPermanentlyLocked(false); - - // launch the 'choose lock pattern' activity so - // the user can pick a new one if they want to - Intent intent = new Intent(); - intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(intent); - - // close the keyguard - mCallback.keyguardDone(true); - } else { - mInstructions.setText(R.string.lockscreen_glogin_invalid_input); - mPassword.setText(""); - } - } - - if (v == mEmergencyCall) { - mCallback.takeEmergencyCallAction(); - } - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - if (event.getAction() == KeyEvent.ACTION_DOWN - && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { - mCallback.goToLockScreen(); - return true; - } - return super.dispatchKeyEvent(event); - } - - private boolean checkPassword() { - final String login = mLogin.getText().toString(); - final String password = mPassword.getText().toString(); - try { - return mAccountsService.shouldUnlock(login, password); - } catch (RemoteException e) { - return false; - } - } - - /** {@inheritDoc} */ - public void onServiceConnected(ComponentName name, IBinder service) { - Log.v("AccountUnlockScreen", "debug: About to grab as interface"); - mAccountsService = IAccountsService.Stub.asInterface(service); - } - - /** {@inheritDoc} */ - public void onServiceDisconnected(ComponentName name) { - mAccountsService = null; - } -} diff --git a/policy/com/android/internal/policy/impl/GlobalActions.java b/policy/com/android/internal/policy/impl/GlobalActions.java deleted file mode 100644 index 7f8e57b13778..000000000000 --- a/policy/com/android/internal/policy/impl/GlobalActions.java +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Copyright (C) 2008 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 com.google.android.collect.Lists; - -import android.app.AlertDialog; -import android.app.StatusBarManager; -import android.content.Context; -import android.content.BroadcastReceiver; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.DialogInterface; -import android.media.AudioManager; -import android.os.LocalPowerManager; -import android.os.Handler; -import android.os.Message; -import android.os.SystemClock; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.BaseAdapter; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import java.util.ArrayList; - -/** - * Helper to show the global actions dialog. Each item is an {@link Action} that - * may show depending on whether the keyguard is showing, and whether the device - * is provisioned. - */ -class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener { - - private StatusBarManager mStatusBar; - - private final Context mContext; - private final LocalPowerManager mPowerManager; - private final AudioManager mAudioManager; - private ArrayList mItems; - private AlertDialog mDialog; - - private ToggleAction mSilentModeToggle; - - private MyAdapter mAdapter; - - private boolean mKeyguardShowing = false; - private boolean mDeviceProvisioned = false; - - /** - * @param context everything needs a context :) - * @param powerManager used to turn the screen off (the lock action). - */ - public GlobalActions(Context context, LocalPowerManager powerManager) { - mContext = context; - mPowerManager = powerManager; - mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - - // receive broadcasts - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - context.registerReceiver(mBroadcastReceiver, filter); - } - - /** - * Show the global actions dialog (creating if necessary) - * @param keyguardShowing True if keyguard is showing - */ - public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) { - mKeyguardShowing = keyguardShowing; - mDeviceProvisioned = isDeviceProvisioned; - if (mDialog == null) { - mStatusBar = (StatusBarManager)mContext.getSystemService(Context.STATUS_BAR_SERVICE); - mDialog = createDialog(); - } - prepareDialog(); - - mStatusBar.disable(StatusBarManager.DISABLE_EXPAND); - mDialog.show(); - } - - /** - * Create the global actions dialog. - * @return A new dialog. - */ - private AlertDialog createDialog() { - - mSilentModeToggle = new ToggleAction( - R.drawable.ic_lock_silent_mode, - R.drawable.ic_lock_silent_mode_off, - R.string.global_action_toggle_silent_mode, - R.string.global_action_silent_mode_on_status, - R.string.global_action_silent_mode_off_status) { - - void onToggle(boolean on) { - mAudioManager.setRingerMode(on ? AudioManager.RINGER_MODE_SILENT - : AudioManager.RINGER_MODE_NORMAL); - } - - public boolean showDuringKeyguard() { - return true; - } - - public boolean showBeforeProvisioning() { - return false; - } - }; - - mItems = Lists.newArrayList( - /* Disabled pending bug 1304831 -- key or touch events wake up device before it - * can go to sleep. - // first: lock screen - new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock, R.string.global_action_lock) { - - public void onPress() { - mPowerManager.goToSleep(SystemClock.uptimeMillis() + 1); - } - - public boolean showDuringKeyguard() { - return false; - } - - public boolean showBeforeProvisioning() { - return false; - } - }, - */ - // next: silent mode - mSilentModeToggle, - // last: power off - new SinglePressAction(com.android.internal.R.drawable.ic_lock_power_off, R.string.global_action_power_off) { - - public void onPress() { - // shutdown by making sure radio and power are handled accordingly. - ShutdownThread.shutdownAfterDisablingRadio(mContext, true); - } - - public boolean showDuringKeyguard() { - return true; - } - - public boolean showBeforeProvisioning() { - return true; - } - }); - - mAdapter = new MyAdapter(); - - final AlertDialog.Builder ab = new AlertDialog.Builder(mContext); - - ab.setAdapter(mAdapter, this) - .setInverseBackgroundForced(true) - .setTitle(R.string.global_actions); - - final AlertDialog dialog = ab.create(); - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); - dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - - dialog.setOnDismissListener(this); - - return dialog; - } - - private void prepareDialog() { - // TODO: May need another 'Vibrate' toggle button, but for now treat them the same - final boolean silentModeOn = - mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; - mSilentModeToggle.updateState(silentModeOn); - mAdapter.notifyDataSetChanged(); - if (mKeyguardShowing) { - mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - } else { - mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); - } - } - - /** {@inheritDoc} */ - public void onDismiss(DialogInterface dialog) { - mStatusBar.disable(StatusBarManager.DISABLE_NONE); - } - - /** {@inheritDoc} */ - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - mAdapter.getItem(which).onPress(); - } - - - /** - * The adapter used for the list within the global actions dialog, taking - * into account whether the keyguard is showing via - * {@link GlobalActions#mKeyguardShowing} and whether the device is provisioned - * via {@link GlobalActions#mDeviceProvisioned}. - */ - private class MyAdapter extends BaseAdapter { - - public int getCount() { - int count = 0; - - for (int i = 0; i < mItems.size(); i++) { - final Action action = mItems.get(i); - - if (mKeyguardShowing && !action.showDuringKeyguard()) { - continue; - } - if (!mDeviceProvisioned && !action.showBeforeProvisioning()) { - continue; - } - count++; - } - return count; - } - - public Action getItem(int position) { - - int filteredPos = 0; - for (int i = 0; i < mItems.size(); i++) { - final Action action = mItems.get(i); - if (mKeyguardShowing && !action.showDuringKeyguard()) { - continue; - } - if (!mDeviceProvisioned && !action.showBeforeProvisioning()) { - continue; - } - if (filteredPos == position) { - return action; - } - filteredPos++; - } - - throw new IllegalArgumentException("position " + position + " out of " - + "range of showable actions, filtered count = " - + "= " + getCount() + ", keyguardshowing=" + mKeyguardShowing - + ", provisioned=" + mDeviceProvisioned); - } - - - public long getItemId(int position) { - return position; - } - - public View getView(int position, View convertView, ViewGroup parent) { - Action action = getItem(position); - return action.create(mContext, (LinearLayout) convertView, LayoutInflater.from(mContext)); - } - } - - // note: the scheme below made more sense when we were planning on having - // 8 different things in the global actions dialog. seems overkill with - // only 3 items now, but may as well keep this flexible approach so it will - // be easy should someone decide at the last minute to include something - // else, such as 'enable wifi', or 'enable bluetooth' - - /** - * What each item in the global actions dialog must be able to support. - */ - private interface Action { - LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater); - - void onPress(); - - /** - * @return whether this action should appear in the dialog when the keygaurd - * is showing. - */ - boolean showDuringKeyguard(); - - /** - * @return whether this action should appear in the dialog before the - * device is provisioned. - */ - boolean showBeforeProvisioning(); - } - - /** - * A single press action maintains no state, just responds to a press - * and takes an action. - */ - private static abstract class SinglePressAction implements Action { - private final int mIconResId; - private final int mMessageResId; - - protected SinglePressAction(int iconResId, int messageResId) { - mIconResId = iconResId; - mMessageResId = messageResId; - } - - abstract public void onPress(); - - public LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater) { - LinearLayout v = (LinearLayout) ((convertView != null) ? - convertView : - inflater.inflate(R.layout.global_actions_item, null)); - - ImageView icon = (ImageView) v.findViewById(R.id.icon); - TextView messageView = (TextView) v.findViewById(R.id.message); - - v.findViewById(R.id.status).setVisibility(View.GONE); - - icon.setImageDrawable(context.getResources().getDrawable(mIconResId)); - messageView.setText(mMessageResId); - - return v; - } - } - - /** - * A toggle action knows whether it is on or off, and displays an icon - * and status message accordingly. - */ - static abstract class ToggleAction implements Action { - - private boolean mOn = false; - - // prefs - private final int mEnabledIconResId; - private final int mDisabledIconResid; - private final int mMessageResId; - private final int mEnabledStatusMessageResId; - private final int mDisabledStatusMessageResId; - - /** - * @param enabledIconResId The icon for when this action is on. - * @param disabledIconResid The icon for when this action is off. - * @param essage The general information message, e.g 'Silent Mode' - * @param enabledStatusMessageResId The on status message, e.g 'sound disabled' - * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled' - */ - public ToggleAction(int enabledIconResId, - int disabledIconResid, - int essage, - int enabledStatusMessageResId, - int disabledStatusMessageResId) { - mEnabledIconResId = enabledIconResId; - mDisabledIconResid = disabledIconResid; - mMessageResId = essage; - mEnabledStatusMessageResId = enabledStatusMessageResId; - mDisabledStatusMessageResId = disabledStatusMessageResId; - } - - public LinearLayout create(Context context, LinearLayout convertView, - LayoutInflater inflater) { - LinearLayout v = (LinearLayout) ((convertView != null) ? - convertView : - inflater.inflate(R - .layout.global_actions_item, null)); - - ImageView icon = (ImageView) v.findViewById(R.id.icon); - TextView messageView = (TextView) v.findViewById(R.id.message); - TextView statusView = (TextView) v.findViewById(R.id.status); - - messageView.setText(mMessageResId); - - icon.setImageDrawable(context.getResources().getDrawable( - (mOn ? mEnabledIconResId : mDisabledIconResid))); - statusView.setText(mOn ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); - statusView.setVisibility(View.VISIBLE); - - return v; - } - - public void onPress() { - updateState(!mOn); - onToggle(mOn); - } - - abstract void onToggle(boolean on); - - public void updateState(boolean on) { - mOn = on; - } - } - - private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { - String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY); - if (! PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) { - mHandler.sendEmptyMessage(MESSAGE_DISMISS); - } - } - } - }; - - private static final int MESSAGE_DISMISS = 0; - private Handler mHandler = new Handler() { - public void handleMessage(Message msg) { - if (msg.what == MESSAGE_DISMISS) { - if (mDialog != null) { - mDialog.dismiss(); - } - } - } - }; -} diff --git a/policy/com/android/internal/policy/impl/KeyguardScreen.java b/policy/com/android/internal/policy/impl/KeyguardScreen.java deleted file mode 100644 index bbb687554e73..000000000000 --- a/policy/com/android/internal/policy/impl/KeyguardScreen.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2008 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; - -/** - * Common interface of each {@link android.view.View} that is a screen of - * {@link LockPatternKeyguardView}. - */ -public interface KeyguardScreen { - - /** - * Return true if your view needs input, so should allow the soft - * keyboard to be displayed. - */ - boolean needsInput(); - - /** - * This screen is no longer in front of the user. - */ - void onPause(); - - /** - * This screen is going to be in front of the user. - */ - void onResume(); - - /** - * This view is going away; a hook to do cleanup. - */ - void cleanUp(); -} diff --git a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java deleted file mode 100644 index b46b37d04db0..000000000000 --- a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2008 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; - -/** - * Within a keyguard, there may be several screens that need a callback - * to the host keyguard view. - */ -public interface KeyguardScreenCallback extends KeyguardViewCallback { - - /** - * Transition to the lock screen. - */ - void goToLockScreen(); - - /** - * Transitino to th unlock screen. - */ - void goToUnlockScreen(); - - /** - * @return Whether the keyguard requires some sort of PIN. - */ - boolean isSecure(); - - /** - * @return Whether we are in a mode where we only want to verify the - * user can get past the keyguard. - */ - boolean isVerifyUnlockOnly(); - - /** - * Stay on me, but recreate me (so I can use a different layout). - */ - void recreateMe(); - - /** - * Take action to send an emergency call. - */ - void takeEmergencyCallAction(); - - /** - * Report that the user had a failed attempt unlocking via the pattern. - */ - void reportFailedPatternAttempt(); - - /** - * Report whether we there's another way to unlock the device. - * @return true - */ - boolean doesFallbackUnlockScreenExist(); -} diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java deleted file mode 100644 index 3a25d38d9ef6..000000000000 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ /dev/null @@ -1,552 +0,0 @@ -/* - * Copyright (C) 2008 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 android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Configuration; -import android.database.ContentObserver; -import static android.os.BatteryManager.BATTERY_STATUS_CHARGING; -import static android.os.BatteryManager.BATTERY_STATUS_FULL; -import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; -import android.os.Handler; -import android.os.Message; -import android.provider.Settings; -import android.provider.Telephony; -import static android.provider.Telephony.Intents.EXTRA_PLMN; -import static android.provider.Telephony.Intents.EXTRA_SHOW_PLMN; -import static android.provider.Telephony.Intents.EXTRA_SHOW_SPN; -import static android.provider.Telephony.Intents.EXTRA_SPN; -import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION; -import com.android.internal.telephony.SimCard; -import com.android.internal.telephony.TelephonyIntents; -import android.util.Log; -import com.android.internal.R; -import com.google.android.collect.Lists; - -import java.util.ArrayList; - -/** - * Watches for updates that may be interesting to the keyguard, and provides - * the up to date information as well as a registration for callbacks that care - * to be updated. - * - * Note: under time crunch, this has been extended to include some stuff that - * doesn't really belong here. see {@link #handleBatteryUpdate} where it shutdowns - * the device, and {@link #getFailedAttempts()}, {@link #reportFailedAttempt()} - * and {@link #clearFailedAttempts()}. Maybe we should rename this 'KeyguardContext'... - */ -public class KeyguardUpdateMonitor { - - static private final String TAG = "KeyguardUpdateMonitor"; - static private final boolean DEBUG = false; - - private static final int LOW_BATTERY_THRESHOLD = 20; - - private final Context mContext; - - private SimCard.State mSimState = SimCard.State.READY; - private boolean mInPortrait; - private boolean mKeyboardOpen; - - private boolean mDevicePluggedIn; - - private boolean mDeviceProvisioned; - - private int mBatteryLevel; - - private CharSequence mTelephonyPlmn; - private CharSequence mTelephonySpn; - - private int mFailedAttempts = 0; - - private Handler mHandler; - - private ArrayList mConfigurationChangeCallbacks - = Lists.newArrayList(); - private ArrayList mInfoCallbacks = Lists.newArrayList(); - private ArrayList mSimStateCallbacks = Lists.newArrayList(); - private ContentObserver mContentObserver; - - - // messages for the handler - private static final int MSG_CONFIGURATION_CHANGED = 300; - private static final int MSG_TIME_UPDATE = 301; - private static final int MSG_BATTERY_UPDATE = 302; - private static final int MSG_CARRIER_INFO_UPDATE = 303; - private static final int MSG_SIM_STATE_CHANGE = 304; - - - /** - * When we receive a {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, and - * then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange}, - * we need a single object to pass to the handler. This class helps decode - * the intent and provide a {@link SimCard.State} result. - */ - private static class SimArgs { - - public final SimCard.State simState; - - private SimArgs(Intent intent) { - if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) { - throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED"); - } - String stateExtra = intent.getStringExtra(SimCard.INTENT_KEY_SIM_STATE); - if (SimCard.INTENT_VALUE_SIM_ABSENT.equals(stateExtra)) { - this.simState = SimCard.State.ABSENT; - } else if (SimCard.INTENT_VALUE_SIM_READY.equals(stateExtra)) { - this.simState = SimCard.State.READY; - } else if (SimCard.INTENT_VALUE_SIM_LOCKED.equals(stateExtra)) { - final String lockedReason = intent - .getStringExtra(SimCard.INTENT_KEY_LOCKED_REASON); - if (SimCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { - this.simState = SimCard.State.PIN_REQUIRED; - } else if (SimCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { - this.simState = SimCard.State.PUK_REQUIRED; - } else { - this.simState = SimCard.State.UNKNOWN; - } - } else if (SimCard.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) { - this.simState = SimCard.State.NETWORK_LOCKED; - } else { - this.simState = SimCard.State.UNKNOWN; - } - } - - public String toString() { - return simState.toString(); - } - } - - public KeyguardUpdateMonitor(Context context) { - mContext = context; - - mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_CONFIGURATION_CHANGED: - handleConfigurationChange(); - break; - case MSG_TIME_UPDATE: - handleTimeUpdate(); - break; - case MSG_BATTERY_UPDATE: - handleBatteryUpdate(msg.arg1, msg.arg2); - break; - case MSG_CARRIER_INFO_UPDATE: - handleCarrierInfoUpdate(); - break; - case MSG_SIM_STATE_CHANGE: - handleSimStateChange((SimArgs) msg.obj); - break; - } - } - }; - - mDeviceProvisioned = Settings.Secure.getInt( - mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; - - // Since device can't be un-provisioned, we only need to register a content observer - // to update mDeviceProvisioned when we are... - if (!mDeviceProvisioned) { - mContentObserver = new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.DEVICE_PROVISIONED, 0) != 0; - if (mDeviceProvisioned && mContentObserver != null) { - // We don't need the observer anymore... - mContext.getContentResolver().unregisterContentObserver(mContentObserver); - mContentObserver = null; - } - if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned); - } - }; - - mContext.getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.DEVICE_PROVISIONED), - false, mContentObserver); - - // prevent a race condition between where we check the flag and where we register the - // observer by grabbing the value once again... - mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.DEVICE_PROVISIONED, 0) != 0; - } - - mInPortrait = queryInPortrait(); - mKeyboardOpen = queryKeyboardOpen(); - - // take a guess to start - mSimState = SimCard.State.READY; - mDevicePluggedIn = true; - mBatteryLevel = 100; - - mTelephonyPlmn = getDefaultPlmn(); - - // setup receiver - final IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); - filter.addAction(Intent.ACTION_TIME_TICK); - filter.addAction(Intent.ACTION_TIME_CHANGED); - filter.addAction(Intent.ACTION_BATTERY_CHANGED); - filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); - filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); - filter.addAction(SPN_STRINGS_UPDATED_ACTION); - context.registerReceiver(new BroadcastReceiver() { - - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (DEBUG) Log.d(TAG, "received broadcast " + action); - - if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_CONFIGURATION_CHANGED)); - } else if (Intent.ACTION_TIME_TICK.equals(action) - || Intent.ACTION_TIME_CHANGED.equals(action) - || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_TIME_UPDATE)); - } else if (SPN_STRINGS_UPDATED_ACTION.equals(action)) { - mTelephonyPlmn = getTelephonyPlmnFrom(intent); - mTelephonySpn = getTelephonySpnFrom(intent); - mHandler.sendMessage(mHandler.obtainMessage(MSG_CARRIER_INFO_UPDATE)); - } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { - final int pluggedInStatus = intent - .getIntExtra("status", BATTERY_STATUS_UNKNOWN); - int batteryLevel = intent.getIntExtra("level", 0); - final Message msg = mHandler.obtainMessage( - MSG_BATTERY_UPDATE, - pluggedInStatus, - batteryLevel); - mHandler.sendMessage(msg); - } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){ - mHandler.sendMessage(mHandler.obtainMessage( - MSG_SIM_STATE_CHANGE, - new SimArgs(intent))); - } - } - }, filter); - } - - /** - * Handle {@link #MSG_CONFIGURATION_CHANGED} - */ - private void handleConfigurationChange() { - if (DEBUG) Log.d(TAG, "handleConfigurationChange"); - - final boolean inPortrait = queryInPortrait(); - if (mInPortrait != inPortrait) { - mInPortrait = inPortrait; - for (int i = 0; i < mConfigurationChangeCallbacks.size(); i++) { - mConfigurationChangeCallbacks.get(i).onOrientationChange(inPortrait); - } - } - - final boolean keyboardOpen = queryKeyboardOpen(); - if (mKeyboardOpen != keyboardOpen) { - mKeyboardOpen = keyboardOpen; - for (int i = 0; i < mConfigurationChangeCallbacks.size(); i++) { - mConfigurationChangeCallbacks.get(i).onKeyboardChange(keyboardOpen); - } - } - } - - /** - * Handle {@link #MSG_TIME_UPDATE} - */ - private void handleTimeUpdate() { - if (DEBUG) Log.d(TAG, "handleTimeUpdate"); - for (int i = 0; i < mInfoCallbacks.size(); i++) { - mInfoCallbacks.get(i).onTimeChanged(); - } - } - - /** - * Handle {@link #MSG_BATTERY_UPDATE} - */ - private void handleBatteryUpdate(int pluggedInStatus, int batteryLevel) { - if (DEBUG) Log.d(TAG, "handleBatteryUpdate"); - final boolean pluggedIn = isPluggedIn(pluggedInStatus); - - if (isBatteryUpdateInteresting(pluggedIn, batteryLevel)) { - mBatteryLevel = batteryLevel; - mDevicePluggedIn = pluggedIn; - for (int i = 0; i < mInfoCallbacks.size(); i++) { - mInfoCallbacks.get(i).onRefreshBatteryInfo( - shouldShowBatteryInfo(), pluggedIn, batteryLevel); - } - } - - // shut down gracefully if our battery is critically low and we are not powered - if (batteryLevel == 0 && - pluggedInStatus != BATTERY_STATUS_CHARGING && - pluggedInStatus != BATTERY_STATUS_UNKNOWN) { - ShutdownThread.shutdownAfterDisablingRadio(mContext, false); - } - } - - /** - * Handle {@link #MSG_CARRIER_INFO_UPDATE} - */ - private void handleCarrierInfoUpdate() { - if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn - + ", spn = " + mTelephonySpn); - - for (int i = 0; i < mInfoCallbacks.size(); i++) { - mInfoCallbacks.get(i).onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn); - } - } - - /** - * Handle {@link #MSG_SIM_STATE_CHANGE} - */ - private void handleSimStateChange(SimArgs simArgs) { - final SimCard.State state = simArgs.simState; - - if (DEBUG) { - Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " " - + "state resolved to " + state.toString()); - } - - if (state != SimCard.State.UNKNOWN && state != mSimState) { - mSimState = state; - for (int i = 0; i < mSimStateCallbacks.size(); i++) { - mSimStateCallbacks.get(i).onSimStateChanged(state); - } - } - } - - /** - * @param status One of the statuses of {@link android.os.BatteryManager} - * @return Whether the status maps to a status for being plugged in. - */ - private boolean isPluggedIn(int status) { - return status == BATTERY_STATUS_CHARGING || status == BATTERY_STATUS_FULL; - } - - private boolean isBatteryUpdateInteresting(boolean pluggedIn, int batteryLevel) { - // change in plug is always interesting - if (mDevicePluggedIn != pluggedIn) { - return true; - } - - // change in battery level while plugged in - if (pluggedIn && mBatteryLevel != batteryLevel) { - return true; - } - - if (!pluggedIn) { - // not plugged in and going below threshold - if (batteryLevel < LOW_BATTERY_THRESHOLD - && mBatteryLevel >= LOW_BATTERY_THRESHOLD) { - return true; - } - // not plugged in and going above threshold (sounds impossible, but, meh...) - if (mBatteryLevel < LOW_BATTERY_THRESHOLD - && batteryLevel >= LOW_BATTERY_THRESHOLD) { - return true; - } - } - return false; - } - - /** - * What is the current orientation? - */ - boolean queryInPortrait() { - final Configuration configuration = mContext.getResources().getConfiguration(); - return configuration.orientation == Configuration.ORIENTATION_PORTRAIT; - } - - /** - * Is the (hard) keyboard currently open? - */ - boolean queryKeyboardOpen() { - final Configuration configuration = mContext.getResources().getConfiguration(); - - return configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO; - } - - /** - * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION} - * @return The string to use for the plmn, or null if it should not be shown. - */ - private CharSequence getTelephonyPlmnFrom(Intent intent) { - if (intent.getBooleanExtra(EXTRA_SHOW_PLMN, false)) { - final String plmn = intent.getStringExtra(EXTRA_PLMN); - if (plmn != null) { - return plmn; - } else { - return getDefaultPlmn(); - } - } - return null; - } - - /** - * @return The default plmn (no service) - */ - private CharSequence getDefaultPlmn() { - return mContext.getResources().getText( - R.string.lockscreen_carrier_default); - } - - /** - * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION} - * @return The string to use for the plmn, or null if it should not be shown. - */ - private CharSequence getTelephonySpnFrom(Intent intent) { - if (intent.getBooleanExtra(EXTRA_SHOW_SPN, false)) { - final String spn = intent.getStringExtra(EXTRA_SPN); - if (spn != null) { - return spn; - } - } - return null; - } - - /** - * Remove the given observer from being registered from any of the kinds - * of callbacks. - * @param observer The observer to remove (an instance of {@link ConfigurationChangeCallback}, - * {@link InfoCallback} or {@link SimStateCallback} - */ - public void removeCallback(Object observer) { - mConfigurationChangeCallbacks.remove(observer); - mInfoCallbacks.remove(observer); - mSimStateCallbacks.remove(observer); - } - - /** - * Callback for configuration changes. - */ - interface ConfigurationChangeCallback { - void onOrientationChange(boolean inPortrait); - - void onKeyboardChange(boolean isKeyboardOpen); - } - - /** - * Callback for general information releveant to lock screen. - */ - interface InfoCallback { - void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel); - void onTimeChanged(); - - /** - * @param plmn The operator name of the registered network. May be null if it shouldn't - * be displayed. - * @param spn The service provider name. May be null if it shouldn't be displayed. - */ - void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn); - } - - /** - * Callback to notify of sim state change. - */ - interface SimStateCallback { - void onSimStateChanged(SimCard.State simState); - } - - /** - * Register to receive notifications about configuration changes. - * @param callback The callback. - */ - public void registerConfigurationChangeCallback(ConfigurationChangeCallback callback) { - mConfigurationChangeCallbacks.add(callback); - } - - /** - * Register to receive notifications about general keyguard information - * (see {@link InfoCallback}. - * @param callback The callback. - */ - public void registerInfoCallback(InfoCallback callback) { - mInfoCallbacks.add(callback); - } - - /** - * Register to be notified of sim state changes. - * @param callback The callback. - */ - public void registerSimStateCallback(SimStateCallback callback) { - mSimStateCallbacks.add(callback); - } - - public SimCard.State getSimState() { - return mSimState; - } - - /** - * Report that the user succesfully entered the sim pin so we - * have the information earlier than waiting for the intent - * broadcast from the telephony code. - */ - public void reportSimPinUnlocked() { - mSimState = SimCard.State.READY; - } - - public boolean isInPortrait() { - return mInPortrait; - } - - public boolean isKeyboardOpen() { - return mKeyboardOpen; - } - - public boolean isDevicePluggedIn() { - return mDevicePluggedIn; - } - - public int getBatteryLevel() { - return mBatteryLevel; - } - - public boolean shouldShowBatteryInfo() { - return mDevicePluggedIn || mBatteryLevel < LOW_BATTERY_THRESHOLD; - } - - public CharSequence getTelephonyPlmn() { - return mTelephonyPlmn; - } - - public CharSequence getTelephonySpn() { - return mTelephonySpn; - } - - /** - * @return Whether the device is provisioned (whether they have gone through - * the setup wizard) - */ - public boolean isDeviceProvisioned() { - return mDeviceProvisioned; - } - - public int getFailedAttempts() { - return mFailedAttempts; - } - - public void clearFailedAttempts() { - mFailedAttempts = 0; - } - - public void reportFailedAttempt() { - mFailedAttempts++; - } -} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/com/android/internal/policy/impl/KeyguardViewBase.java deleted file mode 100644 index a565808e76c9..000000000000 --- a/policy/com/android/internal/policy/impl/KeyguardViewBase.java +++ /dev/null @@ -1,188 +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 android.content.Context; -import android.content.Intent; -import android.media.AudioManager; -import android.view.KeyEvent; -import android.view.View; -import android.widget.FrameLayout; - -/** - * Base class for keyguard views. {@link #reset} is where you should - * reset the state of your view. Use the {@link KeyguardViewCallback} via - * {@link #getCallback()} to send information back (such as poking the wake lock, - * or finishing the keyguard). - * - * Handles intercepting of media keys that still work when the keyguard is - * showing. - */ -public abstract class KeyguardViewBase extends FrameLayout { - - private KeyguardViewCallback mCallback; - private AudioManager mAudioManager; - - public KeyguardViewBase(Context context) { - super(context); - } - - // used to inject callback - void setCallback(KeyguardViewCallback callback) { - mCallback = callback; - } - - public KeyguardViewCallback getCallback() { - return mCallback; - } - - /** - * Called when you need to reset the state of your view. - */ - abstract public void reset(); - - /** - * Called when the screen turned off. - */ - abstract public void onScreenTurnedOff(); - - /** - * Called when the screen turned on. - */ - abstract public void onScreenTurnedOn(); - - /** - * Called when a key has woken the device to give us a chance to adjust our - * state according the the key. We are responsible for waking the device - * (by poking the wake lock) once we are ready. - * - * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}. - * Be sure not to take any action that takes a long time; any significant - * action should be posted to a handler. - * - * @param keyCode The wake key, which may be relevant for configuring the - * keyguard. - */ - abstract public void wakeWhenReadyTq(int keyCode); - - /** - * Verify that the user can get past the keyguard securely. This is called, - * for example, when the phone disables the keyguard but then wants to launch - * something else that requires secure access. - * - * The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)} - */ - abstract public void verifyUnlock(); - - /** - * Called before this view is being removed. - */ - abstract public void cleanUp(); - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - if (shouldEventKeepScreenOnWhileKeyguardShowing(event)) { - mCallback.pokeWakelock(); - } - - if (interceptMediaKey(event)) { - return true; - } - return super.dispatchKeyEvent(event); - } - - private boolean shouldEventKeepScreenOnWhileKeyguardShowing(KeyEvent event) { - if (event.getAction() != KeyEvent.ACTION_DOWN) { - return false; - } - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_DPAD_DOWN: - case KeyEvent.KEYCODE_DPAD_LEFT: - case KeyEvent.KEYCODE_DPAD_RIGHT: - case KeyEvent.KEYCODE_DPAD_UP: - return false; - default: - return true; - } - } - - /** - * Allows the media keys to work when the keygaurd is showing. - * The media keys should be of no interest to the actualy keygaurd view(s), - * so intercepting them here should not be of any harm. - * @param event The key event - * @return whether the event was consumed as a media key. - */ - private boolean interceptMediaKey(KeyEvent event) { - final int keyCode = event.getKeyCode(); - if (event.getAction() == KeyEvent.ACTION_DOWN) { - switch (keyCode) { - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { - Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); - intent.putExtra(Intent.EXTRA_KEY_EVENT, event); - getContext().sendOrderedBroadcast(intent, null); - return true; - } - - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: { - synchronized (this) { - if (mAudioManager == null) { - mAudioManager = (AudioManager) getContext().getSystemService( - Context.AUDIO_SERVICE); - } - } - // Volume buttons should only function for music. - if (mAudioManager.isMusicActive()) { - mAudioManager.adjustStreamVolume( - AudioManager.STREAM_MUSIC, - keyCode == KeyEvent.KEYCODE_VOLUME_UP - ? AudioManager.ADJUST_RAISE - : AudioManager.ADJUST_LOWER, - 0); - } - // Don't execute default volume behavior - return true; - } - } - } else if (event.getAction() == KeyEvent.ACTION_UP) { - switch (keyCode) { - case KeyEvent.KEYCODE_MUTE: - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { - Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); - intent.putExtra(Intent.EXTRA_KEY_EVENT, event); - getContext().sendOrderedBroadcast(intent, null); - return true; - } - } - } - return false; - } - -} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewCallback.java b/policy/com/android/internal/policy/impl/KeyguardViewCallback.java deleted file mode 100644 index b376d657cc80..000000000000 --- a/policy/com/android/internal/policy/impl/KeyguardViewCallback.java +++ /dev/null @@ -1,49 +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; - -/** - * The callback used by the keyguard view to tell the {@link KeyguardViewMediator} - * various things. - */ -public interface KeyguardViewCallback { - - /** - * Request the wakelock to be poked for the default amount of time. - */ - void pokeWakelock(); - - /** - * Request the wakelock to be poked for a specific amount of time. - * @param millis The amount of time in millis. - */ - void pokeWakelock(int millis); - - /** - * Report that the keyguard is done. - * @param authenticated Whether the user securely got past the keyguard. - * the only reason for this to be false is if the keyguard was instructed - * to appear temporarily to verify the user is supposed to get past the - * keyguard, and the user fails to do so. - */ - void keyguardDone(boolean authenticated); - - /** - * Report that the keyguard is done drawing. - */ - void keyguardDoneDrawing(); -} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java deleted file mode 100644 index 297d62f4a4bf..000000000000 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ /dev/null @@ -1,226 +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.content.Context; -import android.content.pm.ActivityInfo; -import android.graphics.PixelFormat; -import android.graphics.Canvas; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewManager; -import android.view.WindowManager; -import android.widget.FrameLayout; - -/** - * Manages creating, showing, hiding and resetting the keyguard. Calls back - * via {@link com.android.internal.policy.impl.KeyguardViewCallback} to poke - * the wake lock and report that the keyguard is done, which is in turn, - * reported to this class by the current {@link KeyguardViewBase}. - */ -public class KeyguardViewManager implements KeyguardWindowController { - private final static boolean DEBUG = false; - private static String TAG = "KeyguardViewManager"; - - private final Context mContext; - private final ViewManager mViewManager; - private final KeyguardViewCallback mCallback; - private final KeyguardViewProperties mKeyguardViewProperties; - - private final KeyguardUpdateMonitor mUpdateMonitor; - - private WindowManager.LayoutParams mWindowLayoutParams; - private boolean mNeedsInput = false; - - private FrameLayout mKeyguardHost; - private KeyguardViewBase mKeyguardView; - - private boolean mScreenOn = false; - - /** - * @param context Used to create views. - * @param viewManager Keyguard will be attached to this. - * @param callback Used to notify of changes. - */ - public KeyguardViewManager(Context context, ViewManager viewManager, - KeyguardViewCallback callback, KeyguardViewProperties keyguardViewProperties, KeyguardUpdateMonitor updateMonitor) { - mContext = context; - mViewManager = viewManager; - mCallback = callback; - mKeyguardViewProperties = keyguardViewProperties; - - mUpdateMonitor = updateMonitor; - } - - /** - * Helper class to host the keyguard view. - */ - private static class KeyguardViewHost extends FrameLayout { - private final KeyguardViewCallback mCallback; - - private KeyguardViewHost(Context context, KeyguardViewCallback callback) { - super(context); - mCallback = callback; - } - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - mCallback.keyguardDoneDrawing(); - } - } - - /** - * Show the keyguard. Will handle creating and attaching to the view manager - * lazily. - */ - public synchronized void show() { - if (DEBUG) Log.d(TAG, "show()"); - - if (mKeyguardHost == null) { - if (DEBUG) Log.d(TAG, "keyguard host is null, creating it..."); - - mKeyguardHost = new KeyguardViewHost(mContext, mCallback); - - final int stretch = ViewGroup.LayoutParams.FILL_PARENT; - int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN - /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ; - if (!mNeedsInput) { - flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; - } - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD, - flags, PixelFormat.OPAQUE); - lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; - lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen; - lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; - lp.setTitle("Keyguard"); - mWindowLayoutParams = lp; - - mViewManager.addView(mKeyguardHost, lp); - } - - if (mKeyguardView == null) { - if (DEBUG) Log.d(TAG, "keyguard view is null, creating it..."); - mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor, this); - mKeyguardView.setId(R.id.lock_screen); - mKeyguardView.setCallback(mCallback); - - final ViewGroup.LayoutParams lp = new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.FILL_PARENT); - - mKeyguardHost.addView(mKeyguardView, lp); - - if (mScreenOn) { - mKeyguardView.onScreenTurnedOn(); - } - } - - mKeyguardHost.setVisibility(View.VISIBLE); - mKeyguardView.requestFocus(); - } - - public void setNeedsInput(boolean needsInput) { - mNeedsInput = needsInput; - if (mWindowLayoutParams != null) { - if (needsInput) { - mWindowLayoutParams.flags &= - ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; - } else { - mWindowLayoutParams.flags |= - WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; - } - mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); - } - } - - /** - * Reset the state of the view. - */ - public synchronized void reset() { - if (DEBUG) Log.d(TAG, "reset()"); - if (mKeyguardView != null) { - mKeyguardView.reset(); - } - } - - public synchronized void onScreenTurnedOff() { - if (DEBUG) Log.d(TAG, "onScreenTurnedOff()"); - mScreenOn = false; - if (mKeyguardView != null) { - mKeyguardView.onScreenTurnedOff(); - } - } - - public synchronized void onScreenTurnedOn() { - if (DEBUG) Log.d(TAG, "onScreenTurnedOn()"); - mScreenOn = true; - if (mKeyguardView != null) { - mKeyguardView.onScreenTurnedOn(); - } - } - - public synchronized void verifyUnlock() { - if (DEBUG) Log.d(TAG, "verifyUnlock()"); - show(); - mKeyguardView.verifyUnlock(); - } - - /** - * A key has woken the device. We use this to potentially adjust the state - * of the lock screen based on the key. - * - * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}. - * Be sure not to take any action that takes a long time; any significant - * action should be posted to a handler. - * - * @param keyCode The wake key. - */ - public void wakeWhenReadyTq(int keyCode) { - if (DEBUG) Log.d(TAG, "wakeWhenReady(" + keyCode + ")"); - if (mKeyguardView != null) { - mKeyguardView.wakeWhenReadyTq(keyCode); - } - } - - /** - * Hides the keyguard view - */ - public synchronized void hide() { - if (DEBUG) Log.d(TAG, "hide()"); - if (mKeyguardHost != null) { - mKeyguardHost.setVisibility(View.GONE); - if (mKeyguardView != null) { - mKeyguardHost.removeView(mKeyguardView); - mKeyguardView.cleanUp(); - mKeyguardView = null; - } - } - } - - /** - * @return Whether the keyguard is showing - */ - public synchronized boolean isShowing() { - return (mKeyguardHost != null && mKeyguardHost.getVisibility() == View.VISIBLE); - } -} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java deleted file mode 100644 index e7366c2a72d6..000000000000 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ /dev/null @@ -1,915 +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 android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.StatusBarManager; -import static android.app.StatusBarManager.DISABLE_NONE; -import static android.app.StatusBarManager.DISABLE_EXPAND; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Handler; -import android.os.LocalPowerManager; -import android.os.Message; -import android.os.PowerManager; -import android.os.SystemClock; -import android.util.Config; -import android.util.Log; -import android.util.EventLog; -import android.view.KeyEvent; -import android.view.WindowManagerImpl; -import android.view.WindowManagerPolicy; -import com.android.internal.telephony.SimCard; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.widget.LockPatternUtils; - -/** - * Mediates requests related to the keyguard. This includes queries about the - * state of the keyguard, power management events that effect whether the keyguard - * should be shown or reset, callbacks to the phone window manager to notify - * it of when the keyguard is showing, and events from the keyguard view itself - * stating that the keyguard was succesfully unlocked. - * - * Note that the keyguard view is shown when the screen is off (as appropriate) - * so that once the screen comes on, it will be ready immediately. - * - * Example queries about the keyguard: - * - is {movement, key} one that should wake the keygaurd? - * - is the keyguard showing? - * - are input events restricted due to the state of the keyguard? - * - * Callbacks to the phone window manager: - * - the keyguard is showing - * - * Example external events that translate to keyguard view changes: - * - screen turned off -> reset the keyguard, and show it so it will be ready - * next time the screen turns on - * - keyboard is slid open -> if the keyguard is not secure, hide it - * - * Events from the keyguard view: - * - user succesfully unlocked keyguard -> hide keyguard view, and no longer - * restrict input events. - * - * Note: in addition to normal power managment events that effect the state of - * whether the keyguard should be showing, external apps and services may request - * that the keyguard be disabled via {@link #setKeyguardEnabled(boolean)}. When - * false, this will override all other conditions for turning on the keyguard. - * - * Threading and synchronization: - * This class is created by the initialization routine of the {@link WindowManagerPolicy}, - * and runs on its thread. The keyguard UI is created from that thread in the - * constructor of this class. The apis may be called from other threads, including the - * {@link com.android.server.KeyInputQueue}'s and {@link android.view.WindowManager}'s. - * Therefore, methods on this class are synchronized, and any action that is pointed - * directly to the keyguard UI is posted to a {@link Handler} to ensure it is taken on the UI - * thread of the keyguard. - */ -public class KeyguardViewMediator implements KeyguardViewCallback, - KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.SimStateCallback { - private final static boolean DEBUG = false && Config.LOGD; - private final static boolean DBG_WAKE = DEBUG || true; - - private final static String TAG = "KeyguardViewMediator"; - - private static final String DELAYED_KEYGUARD_ACTION = "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD"; - - // used for handler messages - private static final int TIMEOUT = 1; - private static final int SHOW = 2; - private static final int HIDE = 3; - private static final int RESET = 4; - private static final int VERIFY_UNLOCK = 5; - private static final int NOTIFY_SCREEN_OFF = 6; - private static final int NOTIFY_SCREEN_ON = 7; - private static final int WAKE_WHEN_READY = 8; - private static final int KEYGUARD_DONE = 9; - private static final int KEYGUARD_DONE_DRAWING = 10; - - /** - * The default amount of time we stay awake (used for all key input) - */ - protected static final int AWAKE_INTERVAL_DEFAULT_MS = 5000; - - - /** - * The default amount of time we stay awake (used for all key input) when - * the keyboard is open - */ - protected static final int AWAKE_INTERVAL_DEFAULT_KEYBOARD_OPEN_MS = 10000; - - /** - * How long to wait after the screen turns off due to timeout before - * 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 = 0; - - /** - * How long we'll wait for the {@link KeyguardViewCallback#keyguardDoneDrawing()} - * callback before unblocking a call to {@link #setKeyguardEnabled(boolean)} - * that is reenabling the keyguard. - */ - private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000; - - private Context mContext; - private AlarmManager mAlarmManager; - - private boolean mSystemReady; - - /** Low level access to the power manager for enableUserActivity. Having this - * requires that we run in the system process. */ - LocalPowerManager mRealPowerManager; - - /** High level access to the power manager for WakeLocks */ - private PowerManager mPM; - - /** - * Used to keep the device awake while the keyguard is showing, i.e for - * calls to {@link #pokeWakelock()} - */ - private PowerManager.WakeLock mWakeLock; - - /** - * Does not turn on screen, held while a call to {@link KeyguardViewManager#wakeWhenReadyTq(int)} - * is called to make sure the device doesn't sleep before it has a chance to poke - * the wake lock. - * @see #wakeWhenReadyLocked(int) - */ - private PowerManager.WakeLock mWakeAndHandOff; - - /** - * Used to disable / reenable status bar expansion. - */ - private StatusBarManager mStatusBarManager; - - private KeyguardViewManager mKeyguardViewManager; - - // these are protected by synchronized (this) - - /** - * External apps (like the phone app) can tell us to disable the keygaurd. - */ - private boolean mExternallyEnabled = true; - - /** - * Remember if an external call to {@link #setKeyguardEnabled} with value - * false caused us to hide the keyguard, so that we need to reshow it once - * the keygaurd is reenabled with another call with value true. - */ - private boolean mNeedToReshowWhenReenabled = false; - - // cached value of whether we are showing (need to know this to quickly - // answer whether the input should be restricted) - private boolean mShowing = false; - - /** - * Helps remember whether the screen has turned on since the last time - * it turned off due to timeout. see {@link #onScreenTurnedOff(int)} - */ - private int mDelayedShowingSequence; - - private int mWakelockSequence; - - private PhoneWindowManager mCallback; - - /** - * If the user has disabled the keyguard, then requests to exit, this is - * how we'll ultimately let them know whether it was successful. We use this - * var being non-null as an indicator that there is an in progress request. - */ - private WindowManagerPolicy.OnKeyguardExitResult mExitSecureCallback; - - // the properties of the keyguard - private KeyguardViewProperties mKeyguardViewProperties; - - private KeyguardUpdateMonitor mUpdateMonitor; - - private boolean mKeyboardOpen = false; - - /** - * {@link #setKeyguardEnabled} waits on this condition when it reenables - * the keyguard. - */ - private boolean mWaitingUntilKeyguardVisible = false; - - public KeyguardViewMediator(Context context, PhoneWindowManager callback, - LocalPowerManager powerManager) { - mContext = context; - - mRealPowerManager = powerManager; - mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - mWakeLock = mPM.newWakeLock( - PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, - "keyguard"); - mWakeLock.setReferenceCounted(false); - - mWakeAndHandOff = mPM.newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, - "keyguardWakeAndHandOff"); - mWakeAndHandOff.setReferenceCounted(false); - - IntentFilter filter = new IntentFilter(); - filter.addAction(DELAYED_KEYGUARD_ACTION); - filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); - filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); - context.registerReceiver(mBroadCastReceiver, filter); - mAlarmManager = (AlarmManager) context - .getSystemService(Context.ALARM_SERVICE); - mCallback = callback; - - mUpdateMonitor = new KeyguardUpdateMonitor(context); - - mUpdateMonitor.registerConfigurationChangeCallback(this); - mUpdateMonitor.registerSimStateCallback(this); - - mKeyguardViewProperties = - new LockPatternKeyguardViewProperties( - new LockPatternUtils(mContext.getContentResolver()), - mUpdateMonitor); - - mKeyguardViewManager = new KeyguardViewManager( - context, WindowManagerImpl.getDefault(), this, - mKeyguardViewProperties, mUpdateMonitor); - - } - - /** - * Let us know that the system is ready after startup. - */ - public void onSystemReady() { - synchronized (this) { - if (DEBUG) Log.d(TAG, "onSystemReady"); - mSystemReady = true; - doKeyguard(); - } - } - - /** - * Called to let us know the screen was turned off. - * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER} or - * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}. - */ - public void onScreenTurnedOff(int why) { - synchronized (this) { - if (DEBUG) Log.d(TAG, "onScreenTurnedOff(" + why + ")"); - - if (mExitSecureCallback != null) { - if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled"); - mExitSecureCallback.onKeyguardExitResult(false); - mExitSecureCallback = null; - if (!mExternallyEnabled) { - hideLocked(); - } - } else if (mShowing) { - notifyScreenOffLocked(); - resetStateLocked(); - } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT) { - // if the screen turned off because of timeout, set an alarm - // 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); - } else { - doKeyguard(); - } - } - } - - /** - * Let's us know the screen was turned on. - */ - public void onScreenTurnedOn() { - synchronized (this) { - mDelayedShowingSequence++; - if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence); - notifyScreenOnLocked(); - } - } - - /** - * Same semantics as {@link WindowManagerPolicy#enableKeyguard}; provide - * a way for external stuff to override normal keyguard behavior. For instance - * the phone app disables the keyguard when it receives incoming calls. - */ - public void setKeyguardEnabled(boolean enabled) { - synchronized (this) { - if (DEBUG) Log.d(TAG, "setKeyguardEnabled(" + enabled + ")"); - - - mExternallyEnabled = enabled; - - if (!enabled && mShowing) { - if (mExitSecureCallback != null) { - if (DEBUG) Log.d(TAG, "in process of verifyUnlock request, ignoring"); - // we're in the process of handling a request to verify the user - // can get past the keyguard. ignore extraneous requests to disable / reenable - return; - } - - // hiding keyguard that is showing, remember to reshow later - if (DEBUG) Log.d(TAG, "remembering to reshow, hiding keyguard, " - + "disabling status bar expansion"); - mNeedToReshowWhenReenabled = true; - setStatusBarExpandable(false); - hideLocked(); - } else if (enabled && mNeedToReshowWhenReenabled) { - // reenabled after previously hidden, reshow - if (DEBUG) Log.d(TAG, "previously hidden, reshowing, reenabling " - + "status bar expansion"); - mNeedToReshowWhenReenabled = false; - setStatusBarExpandable(true); - - if (mExitSecureCallback != null) { - if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting"); - mExitSecureCallback.onKeyguardExitResult(false); - mExitSecureCallback = null; - resetStateLocked(); - } else { - showLocked(); - - // block until we know the keygaurd is done drawing (and post a message - // to unblock us after a timeout so we don't risk blocking too long - // and causing an ANR). - mWaitingUntilKeyguardVisible = true; - mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_DRAWING, KEYGUARD_DONE_DRAWING_TIMEOUT_MS); - if (DEBUG) Log.d(TAG, "waiting until mWaitingUntilKeyguardVisible is false"); - while (mWaitingUntilKeyguardVisible) { - try { - wait(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - if (DEBUG) Log.d(TAG, "done waiting for mWaitingUntilKeyguardVisible"); - } - } - } - } - - /** - * @see android.app.KeyguardManager#exitKeyguardSecurely - */ - public void verifyUnlock(WindowManagerPolicy.OnKeyguardExitResult callback) { - synchronized (this) { - if (DEBUG) Log.d(TAG, "verifyUnlock"); - if (!mUpdateMonitor.isDeviceProvisioned()) { - // don't allow this api when the device isn't provisioned - if (DEBUG) Log.d(TAG, "ignoring because device isn't provisioned"); - callback.onKeyguardExitResult(false); - } else if (mExternallyEnabled) { - // this only applies when the user has externally disabled the - // keyguard. this is unexpected and means the user is not - // using the api properly. - Log.w(TAG, "verifyUnlock called when not externally disabled"); - callback.onKeyguardExitResult(false); - } else if (mExitSecureCallback != null) { - // already in progress with someone else - callback.onKeyguardExitResult(false); - } else { - mExitSecureCallback = callback; - verifyUnlockLocked(); - } - } - } - - - private void setStatusBarExpandable(boolean isExpandable) { - if (mStatusBarManager == null) { - mStatusBarManager = - (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); - } - mStatusBarManager.disable(isExpandable ? DISABLE_NONE : DISABLE_EXPAND); - } - - /** - * Is the keyguard currently showing? - */ - public boolean isShowing() { - return mShowing; - } - - /** - * Given the state of the keyguard, is the input restricted? - * Input is restricted when the keyguard is showing, or when the keyguard - * was suppressed by an app that disabled the keyguard or we haven't been provisioned yet. - */ - public boolean isInputRestricted() { - return mShowing || mNeedToReshowWhenReenabled || !mUpdateMonitor.isDeviceProvisioned(); - } - - - /** - * Enable the keyguard if the settings are appropriate. - */ - private void doKeyguard() { - synchronized (this) { - // if another app is disabling us, don't show - if (!mExternallyEnabled) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled"); - return; - } - - // if the keyguard is already showing, don't bother - if (mKeyguardViewManager.isShowing()) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing"); - return; - } - - // if the setup wizard hasn't run yet, don't show - final boolean provisioned = mUpdateMonitor.isDeviceProvisioned(); - final SimCard.State state = mUpdateMonitor.getSimState(); - final boolean lockedOrMissing = state.isPinLocked() || (state == SimCard.State.ABSENT); - if (!lockedOrMissing && !provisioned) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned" - + " and the sim is not locked or missing"); - return; - } - - if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen"); - showLocked(); - } - } - - /** - * Send message to keyguard telling it to reset its state. - * @see #handleReset() - */ - private void resetStateLocked() { - if (DEBUG) Log.d(TAG, "resetStateLocked"); - Message msg = mHandler.obtainMessage(RESET); - mHandler.sendMessage(msg); - } - - /** - * Send message to keyguard telling it to verify unlock - * @see #handleVerifyUnlock() - */ - private void verifyUnlockLocked() { - if (DEBUG) Log.d(TAG, "verifyUnlockLocked"); - mHandler.sendEmptyMessage(VERIFY_UNLOCK); - } - - - /** - * Send a message to keyguard telling it the screen just turned on. - * @see #onScreenTurnedOff(int) - * @see #handleNotifyScreenOff - */ - private void notifyScreenOffLocked() { - if (DEBUG) Log.d(TAG, "notifyScreenOffLocked"); - mHandler.sendEmptyMessage(NOTIFY_SCREEN_OFF); - } - - /** - * Send a message to keyguard telling it the screen just turned on. - * @see #onScreenTurnedOn() - * @see #handleNotifyScreenOn - */ - private void notifyScreenOnLocked() { - if (DEBUG) Log.d(TAG, "notifyScreenOnLocked"); - mHandler.sendEmptyMessage(NOTIFY_SCREEN_ON); - } - - /** - * Send message to keyguard telling it about a wake key so it can adjust - * its state accordingly and then poke the wake lock when it is ready. - * @param keyCode The wake key. - * @see #handleWakeWhenReady - * @see #onWakeKeyWhenKeyguardShowingTq(int) - */ - private void wakeWhenReadyLocked(int keyCode) { - if (DBG_WAKE) Log.d(TAG, "wakeWhenReadyLocked(" + keyCode + ")"); - - /** - * acquire the handoff lock that will keep the cpu running. this will - * be released once the keyguard has set itself up and poked the other wakelock - * in {@link #handleWakeWhenReady(int)} - */ - mWakeAndHandOff.acquire(); - - Message msg = mHandler.obtainMessage(WAKE_WHEN_READY, keyCode, 0); - mHandler.sendMessage(msg); - } - - /** - * Send message to keyguard telling it to show itself - * @see #handleShow() - */ - private void showLocked() { - if (DEBUG) Log.d(TAG, "showLocked"); - Message msg = mHandler.obtainMessage(SHOW); - mHandler.sendMessage(msg); - } - - /** - * Send message to keyguard telling it to hide itself - * @see #handleHide() - */ - private void hideLocked() { - if (DEBUG) Log.d(TAG, "hideLocked"); - Message msg = mHandler.obtainMessage(HIDE); - mHandler.sendMessage(msg); - } - - /** - * {@link KeyguardUpdateMonitor} callbacks. - */ - - /** {@inheritDoc} */ - public void onOrientationChange(boolean inPortrait) { - - } - - /** {@inheritDoc} */ - public void onKeyboardChange(boolean isKeyboardOpen) { - mKeyboardOpen = isKeyboardOpen; - - if (mKeyboardOpen && !mKeyguardViewProperties.isSecure() - && mKeyguardViewManager.isShowing()) { - if (DEBUG) Log.d(TAG, "bypassing keyguard on sliding open of keyboard with non-secure keyguard"); - keyguardDone(true); - } - } - - /** {@inheritDoc} */ - public void onSimStateChanged(SimCard.State simState) { - if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState); - - switch (simState) { - case ABSENT: - // only force lock screen in case of missing sim if user hasn't - // gone through setup wizard - if (!mUpdateMonitor.isDeviceProvisioned()) { - if (!isShowing()) { - if (DEBUG) Log.d(TAG, "INTENT_VALUE_SIM_ABSENT and keygaurd isn't showing, we need " - + "to show the keyguard since the device isn't provisioned yet."); - doKeyguard(); - } else { - resetStateLocked(); - } - } - break; - case PIN_REQUIRED: - case PUK_REQUIRED: - if (!isShowing()) { - if (DEBUG) Log.d(TAG, "INTENT_VALUE_SIM_LOCKED and keygaurd isn't showing, we need " - + "to show the keyguard so the user can enter their sim pin"); - doKeyguard(); - } else { - resetStateLocked(); - } - - break; - case READY: - if (isShowing()) { - resetStateLocked(); - } - break; - } - } - - private BroadcastReceiver mBroadCastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(DELAYED_KEYGUARD_ACTION)) { - - int sequence = intent.getIntExtra("seq", 0); - - if (false) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = " - + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence); - - if (mDelayedShowingSequence == sequence) { - doKeyguard(); - } - } - } - }; - - - /** - * When a key is received when the screen is off and the keyguard is showing, - * we need to decide whether to actually turn on the screen, and if so, tell - * the keyguard to prepare itself and poke the wake lock when it is ready. - * - * The 'Tq' suffix is per the documentation in {@link WindowManagerPolicy}. - * Be sure not to take any action that takes a long time; any significant - * action should be posted to a handler. - * - * @param keyCode The keycode of the key that woke the device - * @return Whether we poked the wake lock (and turned the screen on) - */ - public boolean onWakeKeyWhenKeyguardShowingTq(int keyCode) { - if (DEBUG) Log.d(TAG, "onWakeKeyWhenKeyguardShowing(" + keyCode + ")"); - - if (isWakeKeyWhenKeyguardShowing(keyCode)) { - // give the keyguard view manager a chance to adjust the state of the - // keyguard based on the key that woke the device before poking - // the wake lock - wakeWhenReadyLocked(keyCode); - return true; - } else { - return false; - } - } - - private boolean isWakeKeyWhenKeyguardShowing(int keyCode) { - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: - case KeyEvent.KEYCODE_MUTE: - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: - case KeyEvent.KEYCODE_CAMERA: - return false; - } - return true; - } - - /** - * Callbacks from {@link KeyguardViewManager}. - */ - - /** {@inheritDoc} */ - public void pokeWakelock() { - pokeWakelock(mKeyboardOpen ? - AWAKE_INTERVAL_DEFAULT_KEYBOARD_OPEN_MS : AWAKE_INTERVAL_DEFAULT_MS); - } - - /** {@inheritDoc} */ - public void pokeWakelock(int holdMs) { - synchronized (this) { - if (DBG_WAKE) Log.d(TAG, "pokeWakelock(" + holdMs + ")"); - mWakeLock.acquire(); - mHandler.removeMessages(TIMEOUT); - mWakelockSequence++; - Message msg = mHandler.obtainMessage(TIMEOUT, mWakelockSequence, 0); - mHandler.sendMessageDelayed(msg, holdMs); - } - } - - /** - * {@inheritDoc} - * - * @see #handleKeyguardDone - */ - public void keyguardDone(boolean authenticated) { - synchronized (this) { - EventLog.writeEvent(70000, 2); - if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")"); - Message msg = mHandler.obtainMessage(KEYGUARD_DONE); - mHandler.sendMessage(msg); - - if (authenticated) { - mUpdateMonitor.clearFailedAttempts(); - } - - if (mExitSecureCallback != null) { - mExitSecureCallback.onKeyguardExitResult(authenticated); - mExitSecureCallback = null; - - if (authenticated) { - // after succesfully exiting securely, no need to reshow - // the keyguard when they've released the lock - mExternallyEnabled = true; - mNeedToReshowWhenReenabled = false; - setStatusBarExpandable(true); - } - } - } - } - - /** - * {@inheritDoc} - * - * @see #handleKeyguardDoneDrawing - */ - public void keyguardDoneDrawing() { - mHandler.sendEmptyMessage(KEYGUARD_DONE_DRAWING); - } - - /** - * This handler will be associated with the policy thread, which will also - * be the UI thread of the keyguard. Since the apis of the policy, and therefore - * this class, can be called by other threads, any action that directly - * interacts with the keyguard ui should be posted to this handler, rather - * than called directly. - */ - private Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) - { - switch (msg.what) - { - case TIMEOUT: - handleTimeout(msg.arg1); - return ; - case SHOW: - handleShow(); - return ; - case HIDE: - handleHide(); - return ; - case RESET: - handleReset(); - return ; - case VERIFY_UNLOCK: - handleVerifyUnlock(); - return; - case NOTIFY_SCREEN_OFF: - handleNotifyScreenOff(); - return; - case NOTIFY_SCREEN_ON: - handleNotifyScreenOn(); - return; - case WAKE_WHEN_READY: - handleWakeWhenReady(msg.arg1); - return; - case KEYGUARD_DONE: - handleKeyguardDone(); - return; - case KEYGUARD_DONE_DRAWING: - handleKeyguardDoneDrawing(); - } - } - }; - - /** - * @see #keyguardDone - * @see #KEYGUARD_DONE - */ - private void handleKeyguardDone() { - if (DEBUG) Log.d(TAG, "handleKeyguardDone"); - handleHide(); - mPM.userActivity(SystemClock.uptimeMillis(), true); - mWakeLock.release(); - } - - /** - * @see #keyguardDoneDrawing - * @see #KEYGUARD_DONE_DRAWING - */ - private void handleKeyguardDoneDrawing() { - synchronized(this) { - if (false) Log.d(TAG, "handleKeyguardDoneDrawing"); - if (mWaitingUntilKeyguardVisible) { - if (DEBUG) Log.d(TAG, "handleKeyguardDoneDrawing: notifying mWaitingUntilKeyguardVisible"); - mWaitingUntilKeyguardVisible = false; - notifyAll(); - - // there will usually be two of these sent, one as a timeout, and one - // as a result of the callback, so remove any remaining messages from - // the queue - mHandler.removeMessages(KEYGUARD_DONE_DRAWING); - } - } - } - - /** - * Handles the message sent by {@link #pokeWakelock} - * @param seq used to determine if anything has changed since the message - * was sent. - * @see #TIMEOUT - */ - private void handleTimeout(int seq) { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleTimeout"); - if (seq == mWakelockSequence) { - mWakeLock.release(); - } - } - } - - /** - * Handle message sent by {@link #showLocked}. - * @see #SHOW - */ - private void handleShow() { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleShow"); - if (!mSystemReady) return; - - // while we're showing, we control the wake state, so ask the power - // manager not to honor request for userActivity. - mRealPowerManager.enableUserActivity(false); - - mCallback.onKeyguardShow(); - mKeyguardViewManager.show(); - mShowing = true; - } - } - - /** - * Handle message sent by {@link #hideLocked()} - * @see #HIDE - */ - private void handleHide() { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleHide"); - // When we go away, tell the poewr manager to honor requests from userActivity. - mRealPowerManager.enableUserActivity(true); - - mKeyguardViewManager.hide(); - mShowing = false; - } - } - - /** - * Handle message sent by {@link #wakeWhenReadyLocked(int)} - * @param keyCode The key that woke the device. - * @see #WAKE_WHEN_READY - */ - private void handleWakeWhenReady(int keyCode) { - synchronized (KeyguardViewMediator.this) { - if (DBG_WAKE) Log.d(TAG, "handleWakeWhenReady(" + keyCode + ")"); - - // this should result in a call to 'poke wakelock' which will set a timeout - // on releasing the wakelock - mKeyguardViewManager.wakeWhenReadyTq(keyCode); - - /** - * Now that the keyguard is ready and has poked the wake lock, we can - * release the handoff wakelock - */ - mWakeAndHandOff.release(); - - if (!mWakeLock.isHeld()) { - Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock"); - } - } - } - - /** - * Handle message sent by {@link #resetStateLocked()} - * @see #RESET - */ - private void handleReset() { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleReset"); - mKeyguardViewManager.reset(); - } - } - - /** - * Handle message sent by {@link #verifyUnlock} - * @see #RESET - */ - private void handleVerifyUnlock() { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleVerifyUnlock"); - mKeyguardViewManager.verifyUnlock(); - mShowing = true; - } - } - - /** - * Handle message sent by {@link #notifyScreenOffLocked()} - * @see #NOTIFY_SCREEN_OFF - */ - private void handleNotifyScreenOff() { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleNotifyScreenOff"); - mKeyguardViewManager.onScreenTurnedOff(); - } - } - - /** - * Handle message sent by {@link #notifyScreenOnLocked()} - * @see #NOTIFY_SCREEN_ON - */ - private void handleNotifyScreenOn() { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleNotifyScreenOn"); - mKeyguardViewManager.onScreenTurnedOn(); - } - } -} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewProperties.java b/policy/com/android/internal/policy/impl/KeyguardViewProperties.java deleted file mode 100644 index bda08eb4252e..000000000000 --- a/policy/com/android/internal/policy/impl/KeyguardViewProperties.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2008 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 android.content.Context; - -/** - * Defines operations necessary for showing a keyguard, including how to create - * it, and various properties that are useful to be able to query independant - * of whether the keyguard instance is around or not. - */ -public interface KeyguardViewProperties { - - /** - * Create a keyguard view. - * @param context the context to use when creating the view. - * @param updateMonitor configuration may be based on this. - * @param controller for talking back with the containing window. - * @return the view. - */ - KeyguardViewBase createKeyguardView(Context context, - KeyguardUpdateMonitor updateMonitor, - KeyguardWindowController controller); - - /** - * Would the keyguard be secure right now? - * @return Whether the keyguard is currently secure, meaning it will block - * the user from getting past it until the user enters some sort of PIN. - */ - boolean isSecure(); - -} diff --git a/policy/com/android/internal/policy/impl/KeyguardWindowController.java b/policy/com/android/internal/policy/impl/KeyguardWindowController.java deleted file mode 100644 index 4ad48fb8e007..000000000000 --- a/policy/com/android/internal/policy/impl/KeyguardWindowController.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2009 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; - -/** - * Interface passed to the keyguard view, for it to call up to control - * its containing window. - */ -public interface KeyguardWindowController { - /** - * Control whether the window needs input -- that is if it has - * text fields and thus should allow input method interaction. - */ - void setNeedsInput(boolean needsInput); -} diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java deleted file mode 100644 index 1ec7e1507556..000000000000 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ /dev/null @@ -1,570 +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 android.accounts.AccountsServiceConstants; -import android.accounts.IAccountsService; -import android.app.AlertDialog; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.SystemProperties; -import com.android.internal.telephony.SimCard; -import android.text.TextUtils; -import android.util.Log; -import android.view.KeyEvent; -import android.view.View; -import android.view.WindowManager; -import com.android.internal.R; -import com.android.internal.widget.LockPatternUtils; - -/** - * The host view for all of the screens of the pattern unlock screen. There are - * two {@link Mode}s of operation, lock and unlock. This will show the appropriate - * screen, and listen for callbacks via {@link com.android.internal.policy.impl.KeyguardScreenCallback - * from the current screen. - * - * This view, in turn, communicates back to {@link com.android.internal.policy.impl.KeyguardViewManager} - * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate. - */ -public class LockPatternKeyguardView extends KeyguardViewBase { - - // intent action for launching emergency dialer activity. - static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL"; - - private static final boolean DEBUG = false; - private static final String TAG = "LockPatternKeyguardView"; - - private final KeyguardUpdateMonitor mUpdateMonitor; - private final KeyguardWindowController mWindowController; - - private View mLockScreen; - private View mUnlockScreen; - - private boolean mScreenOn = false; - private boolean mHasAccount = false; // assume they don't have an account until we know better - - - /** - * The current {@link KeyguardScreen} will use this to communicate back to us. - */ - KeyguardScreenCallback mKeyguardScreenCallback; - - - private boolean mRequiresSim; - - - /** - * Either a lock screen (an informational keyguard screen), or an unlock - * screen (a means for unlocking the device) is shown at any given time. - */ - enum Mode { - LockScreen, - UnlockScreen - } - - /** - * The different types screens available for {@link Mode#UnlockScreen}. - * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode() - */ - enum UnlockMode { - - /** - * Unlock by drawing a pattern. - */ - Pattern, - - /** - * Unlock by entering a sim pin. - */ - SimPin, - - /** - * Unlock by entering an account's login and password. - */ - Account - } - - /** - * The current mode. - */ - private Mode mMode = Mode.LockScreen; - - /** - * Keeps track of what mode the current unlock screen is - */ - private UnlockMode mUnlockScreenMode; - - /** - * If true, it means we are in the process of verifying that the user - * can get past the lock screen per {@link #verifyUnlock()} - */ - private boolean mIsVerifyUnlockOnly = false; - - - /** - * Used to lookup the state of the lock pattern - */ - private final LockPatternUtils mLockPatternUtils; - - /** - * Used to fetch accounts from GLS. - */ - private ServiceConnection mServiceConnection; - - /** - * @return Whether we are stuck on the lock screen because the sim is - * missing. - */ - private boolean stuckOnLockScreenBecauseSimMissing() { - return mRequiresSim - && (!mUpdateMonitor.isDeviceProvisioned()) - && (mUpdateMonitor.getSimState() == SimCard.State.ABSENT); - } - - /** - * @param context Used to inflate, and create views. - * @param updateMonitor Knows the state of the world, and passed along to each - * screen so they can use the knowledge, and also register for callbacks - * on dynamic information. - * @param lockPatternUtils Used to look up state of lock pattern. - */ - public LockPatternKeyguardView( - Context context, - KeyguardUpdateMonitor updateMonitor, - LockPatternUtils lockPatternUtils, - KeyguardWindowController controller) { - super(context); - - asyncCheckForAccount(); - - mRequiresSim = - TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); - - mUpdateMonitor = updateMonitor; - mLockPatternUtils = lockPatternUtils; - mWindowController = controller; - - mMode = getInitialMode(); - - mKeyguardScreenCallback = new KeyguardScreenCallback() { - - public void goToLockScreen() { - if (mIsVerifyUnlockOnly) { - // navigating away from unlock screen during verify mode means - // we are done and the user failed to authenticate. - mIsVerifyUnlockOnly = false; - getCallback().keyguardDone(false); - } else { - updateScreen(Mode.LockScreen); - } - } - - public void goToUnlockScreen() { - final SimCard.State simState = mUpdateMonitor.getSimState(); - if (stuckOnLockScreenBecauseSimMissing() - || (simState == SimCard.State.PUK_REQUIRED)){ - // stuck on lock screen when sim missing or puk'd - return; - } - if (!isSecure()) { - getCallback().keyguardDone(true); - } else { - updateScreen(Mode.UnlockScreen); - } - } - - public boolean isSecure() { - return LockPatternKeyguardView.this.isSecure(); - } - - public boolean isVerifyUnlockOnly() { - return mIsVerifyUnlockOnly; - } - - public void recreateMe() { - recreateScreens(); - } - - public void takeEmergencyCallAction() { - Intent intent = new Intent(ACTION_EMERGENCY_DIAL); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - getContext().startActivity(intent); - } - - public void pokeWakelock() { - getCallback().pokeWakelock(); - } - - public void pokeWakelock(int millis) { - getCallback().pokeWakelock(millis); - } - - public void keyguardDone(boolean authenticated) { - getCallback().keyguardDone(authenticated); - } - - public void keyguardDoneDrawing() { - // irrelevant to keyguard screen, they shouldn't be calling this - } - - public void reportFailedPatternAttempt() { - mUpdateMonitor.reportFailedAttempt(); - final int failedAttempts = mUpdateMonitor.getFailedAttempts(); - if (mHasAccount && failedAttempts == - (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { - showAlmostAtAccountLoginDialog(); - } else if (mHasAccount && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { - mLockPatternUtils.setPermanentlyLocked(true); - updateScreen(mMode); - } else if ((failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) - == 0) { - showTimeoutDialog(); - } - } - - public boolean doesFallbackUnlockScreenExist() { - return mHasAccount; - } - }; - - /** - * We'll get key events the current screen doesn't use. see - * {@link KeyguardViewBase#onKeyDown(int, android.view.KeyEvent)} - */ - setFocusableInTouchMode(true); - setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); - - // create both the lock and unlock screen so they are quickly available - // when the screen turns on - mLockScreen = createLockScreen(); - addView(mLockScreen); - final UnlockMode unlockMode = getUnlockMode(); - mUnlockScreen = createUnlockScreenFor(unlockMode); - mUnlockScreenMode = unlockMode; - addView(mUnlockScreen); - updateScreen(mMode); - } - - /** - * Asynchronously checks for at least one account. This will set mHasAccount - * to true if an account is found. - */ - private void asyncCheckForAccount() { - - mServiceConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - try { - IAccountsService accountsService = IAccountsService.Stub.asInterface(service); - String accounts[] = accountsService.getAccounts(); - mHasAccount = (accounts.length > 0); - } catch (RemoteException e) { - // Not much we can do here... - Log.e(TAG, "Gls died while attempting to get accounts: " + e); - } finally { - getContext().unbindService(mServiceConnection); - mServiceConnection = null; - } - } - - public void onServiceDisconnected(ComponentName className) { - // nothing to do here - } - }; - boolean status = getContext().bindService(AccountsServiceConstants.SERVICE_INTENT, - mServiceConnection, Context.BIND_AUTO_CREATE); - if (!status) Log.e(TAG, "Failed to bind to GLS while checking for account"); - } - - @Override - public void reset() { - mIsVerifyUnlockOnly = false; - updateScreen(getInitialMode()); - } - - @Override - public void onScreenTurnedOff() { - mScreenOn = false; - if (mMode == Mode.LockScreen) { - ((KeyguardScreen) mLockScreen).onPause(); - } else { - ((KeyguardScreen) mUnlockScreen).onPause(); - } - } - - @Override - public void onScreenTurnedOn() { - mScreenOn = true; - if (mMode == Mode.LockScreen) { - ((KeyguardScreen) mLockScreen).onResume(); - } else { - ((KeyguardScreen) mUnlockScreen).onResume(); - } - } - - - private void recreateScreens() { - if (mLockScreen.getVisibility() == View.VISIBLE) { - ((KeyguardScreen) mLockScreen).onPause(); - } - ((KeyguardScreen) mLockScreen).cleanUp(); - removeViewInLayout(mLockScreen); - - mLockScreen = createLockScreen(); - mLockScreen.setVisibility(View.INVISIBLE); - addView(mLockScreen); - - if (mUnlockScreen.getVisibility() == View.VISIBLE) { - ((KeyguardScreen) mUnlockScreen).onPause(); - } - ((KeyguardScreen) mUnlockScreen).cleanUp(); - removeViewInLayout(mUnlockScreen); - - final UnlockMode unlockMode = getUnlockMode(); - mUnlockScreen = createUnlockScreenFor(unlockMode); - mUnlockScreen.setVisibility(View.INVISIBLE); - mUnlockScreenMode = unlockMode; - addView(mUnlockScreen); - - updateScreen(mMode); - } - - - @Override - public void wakeWhenReadyTq(int keyCode) { - if (DEBUG) Log.d(TAG, "onWakeKey"); - if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen) - && (mUpdateMonitor.getSimState() != SimCard.State.PUK_REQUIRED)) { - if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); - updateScreen(Mode.UnlockScreen); - getCallback().pokeWakelock(); - } else { - if (DEBUG) Log.d(TAG, "poking wake lock immediately"); - getCallback().pokeWakelock(); - } - } - - @Override - public void verifyUnlock() { - if (!isSecure()) { - // non-secure keyguard screens are successfull by default - getCallback().keyguardDone(true); - } else if (mUnlockScreenMode != UnlockMode.Pattern) { - // can only verify unlock when in pattern mode - getCallback().keyguardDone(false); - } else { - // otherwise, go to the unlock screen, see if they can verify it - mIsVerifyUnlockOnly = true; - updateScreen(Mode.UnlockScreen); - } - } - - @Override - public void cleanUp() { - ((KeyguardScreen) mLockScreen).onPause(); - ((KeyguardScreen) mLockScreen).cleanUp(); - ((KeyguardScreen) mUnlockScreen).onPause(); - ((KeyguardScreen) mUnlockScreen).cleanUp(); - } - - private boolean isSecure() { - UnlockMode unlockMode = getUnlockMode(); - if (unlockMode == UnlockMode.Pattern) { - return mLockPatternUtils.isLockPatternEnabled(); - } else if (unlockMode == UnlockMode.SimPin) { - return mUpdateMonitor.getSimState() == SimCard.State.PIN_REQUIRED - || mUpdateMonitor.getSimState() == SimCard.State.PUK_REQUIRED; - } else if (unlockMode == UnlockMode.Account) { - return true; - } else { - throw new IllegalStateException("unknown unlock mode " + unlockMode); - } - } - - private void updateScreen(final Mode mode) { - - mMode = mode; - - final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen; - final View visibleScreen = (mode == Mode.LockScreen) - ? mLockScreen : getUnlockScreenForCurrentUnlockMode(); - - - if (mScreenOn) { - if (goneScreen.getVisibility() == View.VISIBLE) { - ((KeyguardScreen) goneScreen).onPause(); - } - if (visibleScreen.getVisibility() != View.VISIBLE) { - ((KeyguardScreen) visibleScreen).onResume(); - } - } - - goneScreen.setVisibility(View.GONE); - visibleScreen.setVisibility(View.VISIBLE); - - mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); - - if (!visibleScreen.requestFocus()) { - throw new IllegalStateException("keyguard screen must be able to take " - + "focus when shown " + visibleScreen.getClass().getCanonicalName()); - } - } - - View createLockScreen() { - return new LockScreen( - mContext, - mLockPatternUtils, - mUpdateMonitor, - mKeyguardScreenCallback); - } - - View createUnlockScreenFor(UnlockMode unlockMode) { - if (unlockMode == UnlockMode.Pattern) { - return new UnlockScreen( - mContext, - mLockPatternUtils, - mUpdateMonitor, - mKeyguardScreenCallback, - mUpdateMonitor.getFailedAttempts()); - } else if (unlockMode == UnlockMode.SimPin) { - return new SimUnlockScreen( - mContext, - mUpdateMonitor, - mKeyguardScreenCallback); - } else if (unlockMode == UnlockMode.Account) { - try { - return new AccountUnlockScreen( - mContext, - mKeyguardScreenCallback, - mLockPatternUtils); - } catch (IllegalStateException e) { - Log.i(TAG, "Couldn't instantiate AccountUnlockScreen" - + " (IAccountsService isn't available)"); - // TODO: Need a more general way to provide a - // platform-specific fallback UI here. - // For now, if we can't display the account login - // unlock UI, just bring back the regular "Pattern" unlock mode. - - // (We do this by simply returning a regular UnlockScreen - // here. This means that the user will still see the - // regular pattern unlock UI, regardless of the value of - // mUnlockScreenMode or whether or not we're in the - // "permanently locked" state.) - return createUnlockScreenFor(UnlockMode.Pattern); - } - } else { - throw new IllegalArgumentException("unknown unlock mode " + unlockMode); - } - } - - private View getUnlockScreenForCurrentUnlockMode() { - final UnlockMode unlockMode = getUnlockMode(); - - // if a screen exists for the correct mode, we're done - if (unlockMode == mUnlockScreenMode) { - return mUnlockScreen; - } - - // remember the mode - mUnlockScreenMode = unlockMode; - - // unlock mode has changed and we have an existing old unlock screen - // to clean up - if (mScreenOn && (mUnlockScreen.getVisibility() == View.VISIBLE)) { - ((KeyguardScreen) mUnlockScreen).onPause(); - } - ((KeyguardScreen) mUnlockScreen).cleanUp(); - removeViewInLayout(mUnlockScreen); - - // create the new one - mUnlockScreen = createUnlockScreenFor(unlockMode); - mUnlockScreen.setVisibility(View.INVISIBLE); - addView(mUnlockScreen); - return mUnlockScreen; - } - - /** - * Given the current state of things, what should be the initial mode of - * the lock screen (lock or unlock). - */ - private Mode getInitialMode() { - final SimCard.State simState = mUpdateMonitor.getSimState(); - if (stuckOnLockScreenBecauseSimMissing() || (simState == SimCard.State.PUK_REQUIRED)) { - return Mode.LockScreen; - } else if (mUpdateMonitor.isKeyboardOpen() && isSecure()) { - return Mode.UnlockScreen; - } else { - return Mode.LockScreen; - } - } - - /** - * Given the current state of things, what should the unlock screen be? - */ - private UnlockMode getUnlockMode() { - final SimCard.State simState = mUpdateMonitor.getSimState(); - if (simState == SimCard.State.PIN_REQUIRED || simState == SimCard.State.PUK_REQUIRED) { - return UnlockMode.SimPin; - } else { - return mLockPatternUtils.isPermanentlyLocked() ? - UnlockMode.Account: - UnlockMode.Pattern; - } - } - - private void showTimeoutDialog() { - int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; - String message = mContext.getString( - R.string.lockscreen_too_many_failed_attempts_dialog_message, - mUpdateMonitor.getFailedAttempts(), - timeoutInSeconds); - final AlertDialog dialog = new AlertDialog.Builder(mContext) - .setTitle(null) - .setMessage(message) - .setNeutralButton(R.string.ok, null) - .create(); - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - dialog.getWindow().setFlags( - WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - dialog.show(); - } - - private void showAlmostAtAccountLoginDialog() { - int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; - String message = mContext.getString( - R.string.lockscreen_failed_attempts_almost_glogin, - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, - timeoutInSeconds); - final AlertDialog dialog = new AlertDialog.Builder(mContext) - .setTitle(null) - .setMessage(message) - .setNeutralButton(R.string.ok, null) - .create(); - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - dialog.getWindow().setFlags( - WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - dialog.show(); - } -} diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java deleted file mode 100644 index 4e0cf09c2ad0..000000000000 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2008 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.widget.LockPatternUtils; - -import android.content.Context; -import com.android.internal.telephony.SimCard; - -/** - * Knows how to create a lock pattern keyguard view, and answer questions about - * it (even if it hasn't been created, per the interface specs). - */ -public class LockPatternKeyguardViewProperties implements KeyguardViewProperties { - - private final LockPatternUtils mLockPatternUtils; - private final KeyguardUpdateMonitor mUpdateMonitor; - - /** - * @param lockPatternUtils Used to know whether the pattern enabled, and passed - * onto the keygaurd view when it is created. - * @param updateMonitor Used to know whether the sim pin is enabled, and passed - * onto the keyguard view when it is created. - */ - public LockPatternKeyguardViewProperties(LockPatternUtils lockPatternUtils, - KeyguardUpdateMonitor updateMonitor) { - mLockPatternUtils = lockPatternUtils; - mUpdateMonitor = updateMonitor; - } - - public KeyguardViewBase createKeyguardView(Context context, - KeyguardUpdateMonitor updateMonitor, - KeyguardWindowController controller) { - return new LockPatternKeyguardView(context, updateMonitor, - mLockPatternUtils, controller); - } - - public boolean isSecure() { - return isLockPatternSecure() || isSimPinSecure(); - } - - private boolean isLockPatternSecure() { - return mLockPatternUtils.isLockPatternEnabled() && mLockPatternUtils - .savedPatternExists(); - } - - private boolean isSimPinSecure() { - final SimCard.State simState = mUpdateMonitor.getSimState(); - return (simState == SimCard.State.PIN_REQUIRED || simState == SimCard.State.PUK_REQUIRED - || simState == SimCard.State.ABSENT); - } - -} diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java deleted file mode 100644 index 82a52f9ed993..000000000000 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (C) 2008 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 com.android.internal.widget.LockPatternUtils; - -import android.content.Context; -import android.text.format.DateFormat; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import com.android.internal.telephony.SimCard; - -import java.util.Date; - -/** - * The screen within {@link LockPatternKeyguardView} that shows general - * 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, KeyguardUpdateMonitor.ConfigurationChangeCallback { - private final LockPatternUtils mLockPatternUtils; - private final KeyguardUpdateMonitor mUpdateMonitor; - private final KeyguardScreenCallback mCallback; - - private TextView mHeaderSimOk1; - private TextView mHeaderSimOk2; - - private TextView mHeaderSimBad1; - private TextView mHeaderSimBad2; - - private TextView mTime; - private TextView mDate; - - private ViewGroup mBatteryInfoGroup; - private ImageView mBatteryInfoIcon; - private TextView mBatteryInfoText; - private View mBatteryInfoSpacer; - - private ViewGroup mNextAlarmGroup; - private TextView mAlarmText; - private View mAlarmSpacer; - - private ViewGroup mScreenLockedMessageGroup; - - private TextView mLockInstructions; - - private Button mEmergencyCallButton; - - /** - * false means sim is missing or PUK'd - */ - private boolean mSimOk = true; - - // 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 View[] mOnlyVisibleWhenSimOk; - - private View[] mOnlyVisibleWhenSimNotOk; - - /** - * @param context Used to setup the view. - * @param lockPatternUtils Used to know the state of the lock pattern settings. - * @param updateMonitor Used to register for updates on various keyguard related - * state, and query the initial state at setup. - * @param callback Used to communicate back to the host keyguard view. - */ - LockScreen(Context context, LockPatternUtils lockPatternUtils, - KeyguardUpdateMonitor updateMonitor, - KeyguardScreenCallback callback) { - super(context); - mLockPatternUtils = lockPatternUtils; - mUpdateMonitor = updateMonitor; - mCallback = callback; - - final LayoutInflater inflater = LayoutInflater.from(context); - inflater.inflate(R.layout.keyguard_screen_lock, this, true); - - mSimOk = isSimOk(updateMonitor.getSimState()); - mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo(); - mPluggedIn = updateMonitor.isDevicePluggedIn(); - mBatteryLevel = updateMonitor.getBatteryLevel(); - - mHeaderSimOk1 = (TextView) findViewById(R.id.headerSimOk1); - mHeaderSimOk2 = (TextView) findViewById(R.id.headerSimOk2); - - mHeaderSimBad1 = (TextView) findViewById(R.id.headerSimBad1); - mHeaderSimBad2 = (TextView) findViewById(R.id.headerSimBad2); - - mTime = (TextView) findViewById(R.id.time); - mDate = (TextView) findViewById(R.id.date); - - mBatteryInfoGroup = (ViewGroup) findViewById(R.id.batteryInfo); - mBatteryInfoIcon = (ImageView) findViewById(R.id.batteryInfoIcon); - mBatteryInfoText = (TextView) findViewById(R.id.batteryInfoText); - mBatteryInfoSpacer = findViewById(R.id.batteryInfoSpacer); - - mNextAlarmGroup = (ViewGroup) findViewById(R.id.nextAlarmInfo); - mAlarmText = (TextView) findViewById(R.id.nextAlarmText); - mAlarmSpacer = findViewById(R.id.nextAlarmSpacer); - - mScreenLockedMessageGroup = (ViewGroup) findViewById(R.id.screenLockedInfo); - - mLockInstructions = (TextView) findViewById(R.id.lockInstructions); - - mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); - - mEmergencyCallButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - mCallback.takeEmergencyCallAction(); - } - }); - - mOnlyVisibleWhenSimOk = new View[] { - mHeaderSimOk1, - mHeaderSimOk2, - mBatteryInfoGroup, - mBatteryInfoSpacer, - mNextAlarmGroup, - mAlarmSpacer, - mScreenLockedMessageGroup, - mLockInstructions - }; - - mOnlyVisibleWhenSimNotOk = new View[] { - mHeaderSimBad1, - mHeaderSimBad2, - mEmergencyCallButton - }; - - setFocusable(true); - setFocusableInTouchMode(true); - setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); - - refreshBatteryDisplay(); - refreshAlarmDisplay(); - refreshTimeAndDateDisplay(); - refreshUnlockIntructions(); - refreshViewsWRTSimOk(); - refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn()); - - updateMonitor.registerInfoCallback(this); - updateMonitor.registerSimStateCallback(this); - updateMonitor.registerConfigurationChangeCallback(this); - } - - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU) { - mCallback.goToUnlockScreen(); - } - return false; - } - - private void refreshViewsWRTSimOk() { - if (mSimOk) { - for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) { - final View view = mOnlyVisibleWhenSimOk[i]; - if (view == null) throw new RuntimeException("index " + i + " null"); - view.setVisibility(View.VISIBLE); - } - for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) { - final View view = mOnlyVisibleWhenSimNotOk[i]; - view.setVisibility(View.GONE); - } - refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn()); - refreshAlarmDisplay(); - refreshBatteryDisplay(); - } else { - for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) { - final View view = mOnlyVisibleWhenSimOk[i]; - view.setVisibility(View.GONE); - } - for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) { - final View view = mOnlyVisibleWhenSimNotOk[i]; - view.setVisibility(View.VISIBLE); - } - refreshSimBadInfo(); - } - } - - private void refreshSimBadInfo() { - final SimCard.State simState = mUpdateMonitor.getSimState(); - if (simState == SimCard.State.PUK_REQUIRED) { - mHeaderSimBad1.setText(R.string.lockscreen_sim_puk_locked_message); - mHeaderSimBad2.setText(R.string.lockscreen_sim_puk_locked_instructions); - } else if (simState == SimCard.State.ABSENT) { - mHeaderSimBad1.setText(R.string.lockscreen_missing_sim_message); - mHeaderSimBad2.setVisibility(View.GONE); - //mHeaderSimBad2.setText(R.string.lockscreen_missing_sim_instructions); - } else { - mHeaderSimBad1.setVisibility(View.GONE); - mHeaderSimBad2.setVisibility(View.GONE); - } - } - - private void refreshUnlockIntructions() { - if (mLockPatternUtils.isLockPatternEnabled() - || mUpdateMonitor.getSimState() == SimCard.State.PIN_REQUIRED) { - mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_enabled); - } else { - mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_disabled); - } - } - - private void refreshAlarmDisplay() { - String nextAlarmText = mLockPatternUtils.getNextAlarm(); - if (nextAlarmText != null && mSimOk) { - setAlarmInfoVisible(true); - mAlarmText.setText(nextAlarmText); - } else { - setAlarmInfoVisible(false); - } - } - - private void setAlarmInfoVisible(boolean visible) { - final int visibilityFlag = visible ? View.VISIBLE : View.GONE; - mNextAlarmGroup.setVisibility(visibilityFlag); - mAlarmSpacer.setVisibility(visibilityFlag); - } - - - public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, - int batteryLevel) { - mShowingBatteryInfo = showBatteryInfo; - mPluggedIn = pluggedIn; - mBatteryLevel = batteryLevel; - - refreshBatteryDisplay(); - } - - private void refreshBatteryDisplay() { - if (!mShowingBatteryInfo || !mSimOk) { - mBatteryInfoGroup.setVisibility(View.GONE); - mBatteryInfoSpacer.setVisibility(View.GONE); - return; - } - mBatteryInfoGroup.setVisibility(View.VISIBLE); - mBatteryInfoSpacer.setVisibility(View.VISIBLE); - - if (mPluggedIn) { - mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_charging); - mBatteryInfoText.setText( - getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel)); - } else { - mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_low_battery); - mBatteryInfoText.setText(R.string.lockscreen_low_battery); - } - } - - public void onTimeChanged() { - refreshTimeAndDateDisplay(); - } - - private void refreshTimeAndDateDisplay() { - Date now = new Date(); - mTime.setText(DateFormat.getTimeFormat(getContext()).format(now)); - mDate.setText(DateFormat.getDateFormat(getContext()).format(now)); - } - - public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { - refreshSimOkHeaders(plmn, spn); - } - - private void refreshSimOkHeaders(CharSequence plmn, CharSequence spn) { - final SimCard.State simState = mUpdateMonitor.getSimState(); - if (simState == SimCard.State.READY) { - if (plmn != null) { - mHeaderSimOk1.setVisibility(View.VISIBLE); - mHeaderSimOk1.setText(plmn); - } else { - mHeaderSimOk1.setVisibility(View.GONE); - } - - if (spn != null) { - mHeaderSimOk2.setVisibility(View.VISIBLE); - mHeaderSimOk2.setText(spn); - } else { - mHeaderSimOk2.setVisibility(View.GONE); - } - } else if (simState == SimCard.State.PIN_REQUIRED) { - mHeaderSimOk1.setVisibility(View.VISIBLE); - mHeaderSimOk1.setText(R.string.lockscreen_sim_locked_message); - mHeaderSimOk2.setVisibility(View.GONE); - } else if (simState == SimCard.State.ABSENT) { - mHeaderSimOk1.setVisibility(View.VISIBLE); - mHeaderSimOk1.setText(R.string.lockscreen_missing_sim_message_short); - mHeaderSimOk2.setVisibility(View.GONE); - } else if (simState == SimCard.State.NETWORK_LOCKED) { - mHeaderSimOk1.setVisibility(View.VISIBLE); - mHeaderSimOk1.setText(R.string.lockscreen_network_locked_message); - mHeaderSimOk2.setVisibility(View.GONE); - } - } - - public void onSimStateChanged(SimCard.State simState) { - mSimOk = isSimOk(simState); - refreshViewsWRTSimOk(); - } - - /** - * @return Whether the sim state is ok, meaning we don't need to show - * a special screen with the emergency call button and keep them from - * doing anything else. - */ - private boolean isSimOk(SimCard.State simState) { - boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned() - && simState == SimCard.State.ABSENT); - return !(missingAndNotProvisioned || simState == SimCard.State.PUK_REQUIRED); - } - - public void onOrientationChange(boolean inPortrait) { - } - - public void onKeyboardChange(boolean isKeyboardOpen) { - if (isKeyboardOpen) { - mCallback.goToUnlockScreen(); - } - } - - - /** {@inheritDoc} */ - public boolean needsInput() { - return false; - } - - /** {@inheritDoc} */ - public void onPause() { - - } - - /** {@inheritDoc} */ - public void onResume() { - - } - - /** {@inheritDoc} */ - public void cleanUp() { - mUpdateMonitor.removeCallback(this); - } -} diff --git a/policy/com/android/internal/policy/impl/PhoneLayoutInflater.java b/policy/com/android/internal/policy/impl/PhoneLayoutInflater.java deleted file mode 100644 index 6bf4beb0ea57..000000000000 --- a/policy/com/android/internal/policy/impl/PhoneLayoutInflater.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2006 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 java.util.Map; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.view.LayoutInflater; - -public class PhoneLayoutInflater extends LayoutInflater { - private static final String[] sClassPrefixList = { - "android.widget.", - "android.webkit." - }; - - /** - * Instead of instantiating directly, you should retrieve an instance - * through {@link Context#getSystemService} - * - * @param context The Context in which in which to find resources and other - * application-specific things. - * - * @see Context#getSystemService - */ - public PhoneLayoutInflater(Context context) { - super(context); - } - - protected PhoneLayoutInflater(LayoutInflater original, Context newContext) { - super(original, newContext); - } - - /** Override onCreateView to instantiate names that correspond to the - widgets known to the Widget factory. If we don't find a match, - call through to our super class. - */ - @Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException { - for (String prefix : sClassPrefixList) { - try { - View view = createView(name, prefix, attrs); - if (view != null) { - return view; - } - } catch (ClassNotFoundException e) { - // In this case we want to let the base class take a crack - // at it. - } - } - - return super.onCreateView(name, attrs); - } - - public LayoutInflater cloneInContext(Context newContext) { - return new PhoneLayoutInflater(this, newContext); - } -} - diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java deleted file mode 100644 index 9fa59e48f9a9..000000000000 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ /dev/null @@ -1,2656 +0,0 @@ -/* - * - * 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.view.menu.ContextMenuBuilder; -import com.android.internal.view.menu.MenuBuilder; -import com.android.internal.view.menu.MenuDialogHelper; -import com.android.internal.view.menu.MenuView; -import com.android.internal.view.menu.SubMenuBuilder; - -import android.app.KeyguardManager; -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.media.AudioManager; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.SystemClock; -import android.util.AndroidRuntimeException; -import android.util.Config; -import android.util.EventLog; -import android.util.Log; -import android.util.SparseArray; -import android.view.Gravity; -import android.view.HapticFeedbackConstants; -import android.view.KeyCharacterMap; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import static android.view.ViewGroup.LayoutParams.FILL_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; -import android.view.ViewManager; -import android.view.VolumePanel; -import android.view.Window; -import android.view.WindowManager; -import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.view.inputmethod.InputMethodManager; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; - -/** - * Android-specific Window. - *

    - * todo: need to pull the generic functionality out into a base class - * in android.widget. - */ -public class PhoneWindow extends Window implements MenuBuilder.Callback { - private final static String TAG = "PhoneWindow"; - - private final static boolean SWEEP_OPEN_MENU = false; - - /** - * 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); - - // This is the top-level view of the window, containing the window decor. - private DecorView mDecor; - - // This is the view in which the window contents are placed. It is either - // mDecor itself, or a child of mDecor where the contents go. - private ViewGroup mContentParent; - - private boolean mIsFloating; - - private LayoutInflater mLayoutInflater; - - private TextView mTitleView; - - private DrawableFeatureState[] mDrawables; - - private PanelFeatureState[] mPanels; - - /** - * The panel that is prepared or opened (the most recent one if there are - * multiple panels). Shortcuts will go to this panel. It gets set in - * {@link #preparePanel} and cleared in {@link #closePanel}. - */ - private PanelFeatureState mPreparedPanel; - - /** - * The keycode that is currently held down (as a modifier) for chording. If - * this is 0, there is no key held down. - */ - private int mPanelChordingKey; - - private ImageView mLeftIconView; - - private ImageView mRightIconView; - - private ProgressBar mCircularProgressBar; - - private ProgressBar mHorizontalProgressBar; - - private int mBackgroundResource = 0; - - private Drawable mBackgroundDrawable; - - private int mFrameResource = 0; - - private int mTextColor = 0; - - private CharSequence mTitle = null; - - private int mTitleColor = 0; - - private ContextMenuBuilder mContextMenu; - private MenuDialogHelper mContextMenuHelper; - - private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; - private long mVolumeKeyUpTime; - - private KeyguardManager mKeyguardManager = null; - - private boolean mSearchKeyDownReceived; - - private boolean mKeycodeCallTimeoutActive = false; - - private boolean mKeycodeCameraTimeoutActive = false; - - static final int MSG_MENU_LONG_PRESS = 1; - static final int MSG_CALL_LONG_PRESS = 2; - static final int MSG_CAMERA_LONG_PRESS = 3; - - private final Handler mKeycodeMenuTimeoutHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_MENU_LONG_PRESS: { - if (mPanelChordingKey == 0) return; - mPanelChordingKey = 0; - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - InputMethodManager imm = (InputMethodManager) - getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - if (imm != null) { - imm.showSoftInputUnchecked(InputMethodManager.SHOW_FORCED); - } - } break; - case MSG_CALL_LONG_PRESS: { - if (!mKeycodeCallTimeoutActive) return; - mKeycodeCallTimeoutActive = false; - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - // launch the VoiceDialer - Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - sendCloseSystemWindows(); - getContext().startActivity(intent); - } catch (ActivityNotFoundException e) { - startCallActivity(); - } - } break; - case MSG_CAMERA_LONG_PRESS: { - if (!mKeycodeCameraTimeoutActive) return; - mKeycodeCameraTimeoutActive = false; - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - // Broadcast an intent that the Camera button was longpressed - Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); - intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj); - getContext().sendOrderedBroadcast(intent, null); - } break; - } - } - }; - - public PhoneWindow(Context context) { - super(context); - mLayoutInflater = LayoutInflater.from(context); - } - - @Override - public final void setContainer(Window container) { - super.setContainer(container); - } - - @Override - public boolean requestFeature(int featureId) { - if (mContentParent != null) { - throw new AndroidRuntimeException("requestFeature() must be called before adding content"); - } - final int features = getFeatures(); - if ((features != DEFAULT_FEATURES) && (featureId == FEATURE_CUSTOM_TITLE)) { - - /* Another feature is enabled and the user is trying to enable the custom title feature */ - throw new AndroidRuntimeException("You cannot combine custom titles with other title features"); - } - if (((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) && (featureId != FEATURE_CUSTOM_TITLE)) { - - /* 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"); - } - /* FEATURE_OPENGL disabled for 1.0 - if (featureId == FEATURE_OPENGL) { - getAttributes().memoryType = WindowManager.LayoutParams.MEMORY_TYPE_GPU; - } - */ - return super.requestFeature(featureId); - } - - @Override - public void setContentView(int layoutResID) { - if (mContentParent == null) { - installDecor(); - } else { - mContentParent.removeAllViews(); - } - mLayoutInflater.inflate(layoutResID, mContentParent); - final Callback cb = getCallback(); - if (cb != null) { - cb.onContentChanged(); - } - } - - @Override - public void setContentView(View view) { - setContentView(view, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT)); - } - - @Override - public void setContentView(View view, ViewGroup.LayoutParams params) { - if (mContentParent == null) { - installDecor(); - } else { - mContentParent.removeAllViews(); - } - mContentParent.addView(view, params); - final Callback cb = getCallback(); - if (cb != null) { - cb.onContentChanged(); - } - } - - @Override - public void addContentView(View view, ViewGroup.LayoutParams params) { - if (mContentParent == null) { - installDecor(); - } - mContentParent.addView(view, params); - final Callback cb = getCallback(); - if (cb != null) { - cb.onContentChanged(); - } - } - - @Override - public View getCurrentFocus() { - return mDecor != null ? mDecor.findFocus() : null; - } - - @Override - public boolean isFloating() { - return mIsFloating; - } - - /** - * Return a LayoutInflater instance that can be used to inflate XML view layout - * resources for use in this Window. - * - * @return LayoutInflater The shared LayoutInflater. - */ - @Override - public LayoutInflater getLayoutInflater() { - return mLayoutInflater; - } - - @Override - public void setTitle(CharSequence title) { - if (mTitleView != null) { - mTitleView.setText(title); - } - mTitle = title; - } - - @Override - public void setTitleColor(int textColor) { - if (mTitleView != null) { - mTitleView.setTextColor(textColor); - } - mTitleColor = textColor; - } - - /** - * Prepares the panel to either be opened or chorded. This creates the Menu - * instance for the panel and populates it via the Activity callbacks. - * - * @param st The panel state to prepare. - * @param event The event that triggered the preparing of the panel. - * @return Whether the panel was prepared. If the panel should not be shown, - * returns false. - */ - public final boolean preparePanel(PanelFeatureState st, KeyEvent event) { - // 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); - } - - final Callback cb = getCallback(); - - if (cb != null) { - st.createdPanelView = cb.onCreatePanelView(st.featureId); - } - - 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; - } - // Call callback, and return if it doesn't want to display menu - if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) { - // Ditch the menu created above - st.menu = null; - - return false; - } - } - - // Callback and return if the callback does not want to show the menu - if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) { - return false; - } - - // Set the proper keymap - KeyCharacterMap kmap = KeyCharacterMap.load(event != null ? event.getDeviceId() : 0); - st.qwertyMode = kmap.getKeyboardType() != KeyCharacterMap.NUMERIC; - st.menu.setQwertyMode(st.qwertyMode); - } - - // Set other state - st.isPrepared = true; - st.isHandled = false; - mPreparedPanel = st; - - return true; - } - - @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; - - 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); - - // Re-open the same menu - reopenMenu(false); - - // Restore state - menuBuilder.restoreHierarchyState(state); - - } 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. - - // Allow the callback to create a new panel view - st.createdPanelView = null; - - // Causes the decor view to be recreated - st.refreshDecorView = true; - - ((MenuBuilder) st.menu).clearMenuViews(); - } - - @Override - public final void openPanel(int featureId, KeyEvent event) { - openPanel(getPanelState(featureId, true), event); - } - - private void openPanel(PanelFeatureState st, KeyEvent event) { - // System.out.println("Open panel: isOpen=" + st.isOpen); - - // Already open, return - if (st.isOpen) { - return; - } - - Callback cb = getCallback(); - if ((cb != null) && (!cb.onMenuOpened(st.featureId, st.menu))) { - // Callback doesn't want the menu to open, reset any state - closePanel(st, true); - return; - } - - final WindowManager wm = getWindowManager(); - if (wm == null) { - return; - } - - // Prepare panel (should have been done before, but just in case) - if (!preparePanel(st, event)) { - return; - } - - if (st.decorView == null || st.refreshDecorView) { - if (st.decorView == null) { - // Initialize the panel decor, this will populate st.decorView - if (!initializePanelDecor(st) || (st.decorView == null)) - return; - } else if (st.refreshDecorView && (st.decorView.getChildCount() > 0)) { - // Decor needs refreshing, so remove its views - st.decorView.removeAllViews(); - } - - // This will populate st.shownPanelView - if (!initializePanelContent(st) || (st.shownPanelView == null)) { - return; - } - - ViewGroup.LayoutParams lp = st.shownPanelView.getLayoutParams(); - if (lp == null) { - lp = new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); - } - - int backgroundResId; - if (lp.width == ViewGroup.LayoutParams.FILL_PARENT) { - // If the contents is fill parent for the width, set the - // corresponding background - backgroundResId = st.fullBackground; - } else { - // Otherwise, set the normal panel background - backgroundResId = st.background; - } - st.decorView.setWindowBackground(getContext().getResources().getDrawable( - backgroundResId)); - - - st.decorView.addView(st.shownPanelView, lp); - - /* - * Give focus to the view, if it or one of its children does not - * already have it. - */ - if (!st.shownPanelView.hasFocus()) { - st.shownPanelView.requestFocus(); - } - } - - st.isOpen = true; - st.isHandled = false; - - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - WRAP_CONTENT, WRAP_CONTENT, - st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, - WindowManager.LayoutParams.FLAG_DITHER - | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, - st.decorView.mDefaultOpacity); - - lp.gravity = st.gravity; - lp.windowAnimations = st.windowAnimations; - wm.addView(st.decorView, lp); - // Log.v(TAG, "Adding main menu to window manager."); - } - - @Override - public final void closePanel(int featureId) { - if (featureId == FEATURE_CONTEXT_MENU) { - closeContextMenu(); - } else { - closePanel(getPanelState(featureId, true), true); - } - } - - /** - * Closes the given panel. - * - * @param st The panel to be closed. - * @param doCallback Whether to notify the callback that the panel was - * closed. If the panel is in the process of re-opening or - * opening another panel (e.g., menu opening a sub menu), the - * callback should not happen and this variable should be false. - * In addition, this method internally will only perform the - * callback if the panel is open. - */ - public final void closePanel(PanelFeatureState st, boolean doCallback) { - // System.out.println("Close panel: isOpen=" + st.isOpen); - final ViewManager wm = getWindowManager(); - if ((wm != null) && st.isOpen) { - if (st.decorView != null) { - wm.removeView(st.decorView); - // Log.v(TAG, "Removing main menu from window manager."); - } - - if (doCallback) { - callOnPanelClosed(st.featureId, st, null); - } - } - st.isPrepared = false; - st.isHandled = false; - st.isOpen = false; - - // This view is no longer shown, so null it out - st.shownPanelView = null; - - if (st.isInExpandedMode) { - // Next time the menu opens, it should not be in expanded mode, so - // force a refresh of the decor - st.refreshDecorView = true; - st.isInExpandedMode = false; - } - - if (mPreparedPanel == st) { - mPreparedPanel = null; - mPanelChordingKey = 0; - } - } - - @Override - public final void togglePanel(int featureId, KeyEvent event) { - PanelFeatureState st = getPanelState(featureId, true); - if (st.isOpen) { - closePanel(st, true); - } else { - openPanel(st, event); - } - } - - /** - * Called when the panel key is pushed down. - * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}. - * @param event The key event. - * @return Whether the key was handled. - */ - public final boolean onKeyDownPanel(int featureId, KeyEvent event) { - // The panel key was pushed, so set the chording key - mPanelChordingKey = event.getKeyCode(); - - PanelFeatureState st = getPanelState(featureId, true); - if (!st.isOpen) { - if (getContext().getResources().getConfiguration().keyboard - == Configuration.KEYBOARD_NOKEYS) { - mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); - mKeycodeMenuTimeoutHandler.sendMessageDelayed( - mKeycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS), - ViewConfiguration.getLongPressTimeout()); - } - return preparePanel(st, event); - } - - return false; - } - - /** - * Called when the panel key is released. - * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}. - * @param event The key event. - */ - public final void onKeyUpPanel(int featureId, KeyEvent event) { - // The panel key was released, so clear the chording key - if (mPanelChordingKey != 0) { - mPanelChordingKey = 0; - mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); - - boolean playSoundEffect = false; - PanelFeatureState st = getPanelState(featureId, true); - 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; - - // Close menu - closePanel(st, true); - - } else if (st.isPrepared) { - - // Write 'menu opened' to event log - EventLog.writeEvent(50001, 0); - - // Show menu - openPanel(st, event); - - playSoundEffect = true; - } - - if (playSoundEffect) { - AudioManager audioManager = (AudioManager) getContext().getSystemService( - Context.AUDIO_SERVICE); - if (audioManager != null) { - audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); - } else { - Log.w(TAG, "Couldn't get audio manager"); - } - } - } - } - - @Override - public final void closeAllPanels() { - final ViewManager wm = getWindowManager(); - if (wm == null) { - return; - } - - final PanelFeatureState[] panels = mPanels; - final int N = panels != null ? panels.length : 0; - for (int i = 0; i < N; i++) { - final PanelFeatureState panel = panels[i]; - if (panel != null) { - closePanel(panel, true); - } - } - - closeContextMenu(); - } - - /** - * Closes the context menu. This notifies the menu logic of the close, along - * with dismissing it from the UI. - */ - private synchronized void closeContextMenu() { - if (mContextMenu != null) { - mContextMenu.close(); - dismissContextMenu(); - } - } - - /** - * Dismisses just the context menu UI. To close the context menu, use - * {@link #closeContextMenu()}. - */ - private synchronized void dismissContextMenu() { - mContextMenu = null; - - if (mContextMenuHelper != null) { - mContextMenuHelper.dismiss(); - mContextMenuHelper = null; - } - } - - @Override - public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) { - return performPanelShortcut(getPanelState(featureId, true), keyCode, event, flags); - } - - private boolean performPanelShortcut(PanelFeatureState st, int keyCode, KeyEvent event, - int flags) { - if (event.isSystem() || (st == null)) { - return false; - } - - boolean handled = false; - - // Only try to perform menu shortcuts if preparePanel returned true (possible false - // return value from application not wanting to show the menu). - if ((st.isPrepared || preparePanel(st, event)) && st.menu != null) { - // The menu is prepared now, perform the shortcut on it - handled = st.menu.performShortcut(keyCode, event, flags); - } - - if (handled) { - // Mark as handled - st.isHandled = true; - - if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0) { - closePanel(st, true); - } - } - - return handled; - } - - @Override - public boolean performPanelIdentifierAction(int featureId, int id, int flags) { - - PanelFeatureState st = getPanelState(featureId, true); - if (!preparePanel(st, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU))) { - return false; - } - if (st.menu == null) { - return false; - } - - boolean res = st.menu.performIdentifierAction(id, flags); - - closePanel(st, true); - - return res; - } - - public PanelFeatureState findMenuPanel(Menu menu) { - final PanelFeatureState[] panels = mPanels; - final int N = panels != null ? panels.length : 0; - for (int i = 0; i < N; i++) { - final PanelFeatureState panel = panels[i]; - if (panel != null && panel.menu == menu) { - return panel; - } - } - return null; - } - - public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { - final Callback cb = getCallback(); - if (cb != null) { - final PanelFeatureState panel = findMenuPanel(menu.getRootMenu()); - if (panel != null) { - return cb.onMenuItemSelected(panel.featureId, item); - } - } - return false; - } - - public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { - final PanelFeatureState panel = findMenuPanel(menu); - if (panel != null) { - // Close the panel and only do the callback if the menu is being - // closed - // completely, not if opening a sub menu - closePanel(panel, allMenusAreClosing); - } - } - - public void onCloseSubMenu(SubMenuBuilder subMenu) { - final Menu parentMenu = subMenu.getRootMenu(); - final PanelFeatureState panel = findMenuPanel(parentMenu); - - // Callback - if (panel != null) { - callOnPanelClosed(panel.featureId, panel, parentMenu); - closePanel(panel, true); - } - } - - public boolean onSubMenuSelected(final SubMenuBuilder subMenu) { - if (!subMenu.hasVisibleItems()) { - return true; - } - - // The window manager will give us a valid window token - new MenuDialogHelper(subMenu).show(null); - - return true; - } - - public void onMenuModeChange(MenuBuilder menu) { - reopenMenu(true); - } - - private void reopenMenu(boolean toggleMenuMode) { - PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); - - // Save the future expanded mode state since closePanel will reset it - boolean newExpandedMode = toggleMenuMode ? !st.isInExpandedMode : st.isInExpandedMode; - - st.refreshDecorView = true; - closePanel(st, false); - - // Set the expanded mode state - st.isInExpandedMode = newExpandedMode; - - openPanel(st, null); - } - - /** - * Initializes the menu associated with the given panel feature state. You - * must at the very least set PanelFeatureState.menu to the Menu to be - * associated with the given panel state. The default implementation creates - * a new menu for the panel state. - * - * @param st The panel whose menu is being initialized. - * @return Whether the initialization was successful. - */ - protected boolean initializePanelMenu(final PanelFeatureState st) { - final MenuBuilder menu = new MenuBuilder(getContext()); - - menu.setCallback(this); - st.setMenu(menu); - - return true; - } - - /** - * Perform initial setup of a panel. This should at the very least set the - * style information in the PanelFeatureState and must set - * PanelFeatureState.decor to the panel's window decor view. - * - * @param st The panel being initialized. - */ - protected boolean initializePanelDecor(PanelFeatureState st) { - st.decorView = new DecorView(getContext(), st.featureId); - st.gravity = Gravity.CENTER | Gravity.BOTTOM; - st.setStyle(getContext()); - - return true; - } - - /** - * Initializes the panel associated with the panel feature state. You must - * at the very least set PanelFeatureState.panel to the View implementing - * its contents. The default implementation gets the panel from the menu. - * - * @param st The panel state being initialized. - * @return Whether the initialization was successful. - */ - protected boolean initializePanelContent(PanelFeatureState st) { - - if (st.createdPanelView != null) { - st.shownPanelView = st.createdPanelView; - return true; - } - - final MenuBuilder menu = (MenuBuilder)st.menu; - if (menu == null) { - return false; - } - - st.shownPanelView = menu.getMenuView((st.isInExpandedMode) ? MenuBuilder.TYPE_EXPANDED - : MenuBuilder.TYPE_ICON, st.decorView); - - if (st.shownPanelView != null) { - // Use the menu View's default animations if it has any - final int defaultAnimations = ((MenuView) st.shownPanelView).getWindowAnimations(); - if (defaultAnimations != 0) { - st.windowAnimations = defaultAnimations; - } - return true; - } else { - return false; - } - } - - @Override - public boolean performContextMenuIdentifierAction(int id, int flags) { - return (mContextMenu != null) ? mContextMenu.performIdentifierAction(id, flags) : false; - } - - @Override - public final void setBackgroundDrawable(Drawable drawable) { - if (drawable != mBackgroundDrawable) { - mBackgroundResource = 0; - mBackgroundDrawable = drawable; - if (mDecor != null) { - mDecor.setWindowBackground(drawable); - } - } - } - - @Override - public final void setFeatureDrawableResource(int featureId, int resId) { - if (resId != 0) { - DrawableFeatureState st = getDrawableState(featureId, true); - if (st.resid != resId) { - st.resid = resId; - st.uri = null; - st.local = getContext().getResources().getDrawable(resId); - updateDrawable(featureId, st, false); - } - } else { - setFeatureDrawable(featureId, null); - } - } - - @Override - public final void setFeatureDrawableUri(int featureId, Uri uri) { - if (uri != null) { - DrawableFeatureState st = getDrawableState(featureId, true); - if (st.uri == null || !st.uri.equals(uri)) { - st.resid = 0; - st.uri = uri; - st.local = loadImageURI(uri); - updateDrawable(featureId, st, false); - } - } else { - setFeatureDrawable(featureId, null); - } - } - - @Override - public final void setFeatureDrawable(int featureId, Drawable drawable) { - DrawableFeatureState st = getDrawableState(featureId, true); - st.resid = 0; - st.uri = null; - if (st.local != drawable) { - st.local = drawable; - updateDrawable(featureId, st, false); - } - } - - @Override - public void setFeatureDrawableAlpha(int featureId, int alpha) { - DrawableFeatureState st = getDrawableState(featureId, true); - if (st.alpha != alpha) { - st.alpha = alpha; - updateDrawable(featureId, st, false); - } - } - - protected final void setFeatureDefaultDrawable(int featureId, Drawable drawable) { - DrawableFeatureState st = getDrawableState(featureId, true); - if (st.def != drawable) { - st.def = drawable; - updateDrawable(featureId, st, false); - } - } - - @Override - public final void setFeatureInt(int featureId, int value) { - // XXX Should do more management (as with drawable features) to - // deal with interactions between multiple window policies. - updateInt(featureId, value, false); - } - - /** - * Update the state of a drawable feature. This should be called, for every - * drawable feature supported, as part of onActive(), to make sure that the - * contents of a containing window is properly updated. - * - * @see #onActive - * @param featureId The desired drawable feature to change. - * @param fromActive Always true when called from onActive(). - */ - protected final void updateDrawable(int featureId, boolean fromActive) { - final DrawableFeatureState st = getDrawableState(featureId, false); - if (st != null) { - updateDrawable(featureId, st, fromActive); - } - } - - /** - * Called when a Drawable feature changes, for the window to update its - * graphics. - * - * @param featureId The feature being changed. - * @param drawable The new Drawable to show, or null if none. - * @param alpha The new alpha blending of the Drawable. - */ - protected void onDrawableChanged(int featureId, Drawable drawable, int alpha) { - ImageView view; - if (featureId == FEATURE_LEFT_ICON) { - view = getLeftIconView(); - } else if (featureId == FEATURE_RIGHT_ICON) { - view = getRightIconView(); - } else { - return; - } - - if (drawable != null) { - drawable.setAlpha(alpha); - view.setImageDrawable(drawable); - view.setVisibility(View.VISIBLE); - } else { - view.setVisibility(View.GONE); - } - } - - /** - * Called when an int feature changes, for the window to update its - * graphics. - * - * @param featureId The feature being changed. - * @param value The new integer value. - */ - protected void onIntChanged(int featureId, int value) { - if (featureId == FEATURE_PROGRESS || featureId == FEATURE_INDETERMINATE_PROGRESS) { - updateProgressBars(value); - } else if (featureId == FEATURE_CUSTOM_TITLE) { - FrameLayout titleContainer = (FrameLayout) findViewById(com.android.internal.R.id.title_container); - if (titleContainer != null) { - mLayoutInflater.inflate(value, titleContainer); - } - } - } - - /** - * Updates the progress bars that are shown in the title bar. - * - * @param value Can be one of {@link Window#PROGRESS_VISIBILITY_ON}, - * {@link Window#PROGRESS_VISIBILITY_OFF}, - * {@link Window#PROGRESS_INDETERMINATE_ON}, - * {@link Window#PROGRESS_INDETERMINATE_OFF}, or a value - * starting at {@link Window#PROGRESS_START} through - * {@link Window#PROGRESS_END} for setting the default - * progress (if {@link Window#PROGRESS_END} is given, - * the progress bar widgets in the title will be hidden after an - * animation), a value between - * {@link Window#PROGRESS_SECONDARY_START} - - * {@link Window#PROGRESS_SECONDARY_END} for the - * secondary progress (if - * {@link Window#PROGRESS_SECONDARY_END} is given, the - * progress bar widgets will still be shown with the secondary - * progress bar will be completely filled in.) - */ - private void updateProgressBars(int value) { - ProgressBar circularProgressBar = getCircularProgressBar(true); - ProgressBar horizontalProgressBar = getHorizontalProgressBar(true); - - final int features = getLocalFeatures(); - if (value == PROGRESS_VISIBILITY_ON) { - if ((features & (1 << FEATURE_PROGRESS)) != 0) { - int level = horizontalProgressBar.getProgress(); - int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ? - View.VISIBLE : View.INVISIBLE; - horizontalProgressBar.setVisibility(visibility); - } - if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { - circularProgressBar.setVisibility(View.VISIBLE); - } - } else if (value == PROGRESS_VISIBILITY_OFF) { - if ((features & (1 << FEATURE_PROGRESS)) != 0) { - horizontalProgressBar.setVisibility(View.GONE); - } - if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { - circularProgressBar.setVisibility(View.GONE); - } - } else if (value == PROGRESS_INDETERMINATE_ON) { - horizontalProgressBar.setIndeterminate(true); - } else if (value == PROGRESS_INDETERMINATE_OFF) { - horizontalProgressBar.setIndeterminate(false); - } else if (PROGRESS_START <= value && value <= PROGRESS_END) { - // We want to set the progress value before testing for visibility - // so that when the progress bar becomes visible again, it has the - // correct level. - horizontalProgressBar.setProgress(value - PROGRESS_START); - - if (value < PROGRESS_END) { - showProgressBars(horizontalProgressBar, circularProgressBar); - } else { - hideProgressBars(horizontalProgressBar, circularProgressBar); - } - } else if (PROGRESS_SECONDARY_START <= value && value <= PROGRESS_SECONDARY_END) { - horizontalProgressBar.setSecondaryProgress(value - PROGRESS_SECONDARY_START); - - showProgressBars(horizontalProgressBar, circularProgressBar); - } - - } - - private void showProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) { - final int features = getLocalFeatures(); - if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 && - spinnyProgressBar.getVisibility() == View.INVISIBLE) { - spinnyProgressBar.setVisibility(View.VISIBLE); - } - // Only show the progress bars if the primary progress is not complete - if ((features & (1 << FEATURE_PROGRESS)) != 0 && - horizontalProgressBar.getProgress() < 10000) { - horizontalProgressBar.setVisibility(View.VISIBLE); - } - } - - private void hideProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) { - final int features = getLocalFeatures(); - Animation anim = AnimationUtils.loadAnimation(getContext(), com.android.internal.R.anim.fade_out); - anim.setDuration(1000); - if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 && - spinnyProgressBar.getVisibility() == View.VISIBLE) { - spinnyProgressBar.startAnimation(anim); - spinnyProgressBar.setVisibility(View.INVISIBLE); - } - if ((features & (1 << FEATURE_PROGRESS)) != 0 && - horizontalProgressBar.getVisibility() == View.VISIBLE) { - horizontalProgressBar.startAnimation(anim); - horizontalProgressBar.setVisibility(View.INVISIBLE); - } - } - - /** - * Request that key events come to this activity. Use this if your activity - * has no views with focus, but the activity still wants a chance to process - * key events. - */ - @Override - public void takeKeyEvents(boolean get) { - mDecor.setFocusable(get); - } - - @Override - public boolean superDispatchKeyEvent(KeyEvent event) { - return mDecor.superDispatchKeyEvent(event); - } - - @Override - public boolean superDispatchTouchEvent(MotionEvent event) { - return mDecor.superDispatchTouchEvent(event); - } - - @Override - public boolean superDispatchTrackballEvent(MotionEvent event) { - return mDecor.superDispatchTrackballEvent(event); - } - - /** - * A key was pressed down and not handled by anything else in the window. - * - * @see #onKeyUp - * @see android.view.KeyEvent - */ - protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: { - AudioManager audioManager = (AudioManager) getContext().getSystemService( - Context.AUDIO_SERVICE); - if (audioManager != null) { - /* - * Adjust the volume in on key down since it is more - * responsive to the user. - */ - audioManager.adjustSuggestedStreamVolume( - keyCode == KeyEvent.KEYCODE_VOLUME_UP - ? AudioManager.ADJUST_RAISE - : AudioManager.ADJUST_LOWER, - mVolumeControlStreamType, - AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE); - } - return true; - } - - case KeyEvent.KEYCODE_MUTE: - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { - Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); - intent.putExtra(Intent.EXTRA_KEY_EVENT, event); - getContext().sendOrderedBroadcast(intent, null); - return true; - } - - case KeyEvent.KEYCODE_CAMERA: { - if (getKeyguardManager().inKeyguardRestrictedInputMode()) { - break; - } - if (event.getRepeatCount() > 0) break; - mKeycodeCameraTimeoutActive = true; - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); - Message message = mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CAMERA_LONG_PRESS); - message.obj = event; - mKeycodeMenuTimeoutHandler.sendMessageDelayed(message, - ViewConfiguration.getLongPressTimeout()); - return true; - } - - case KeyEvent.KEYCODE_MENU: { - if (event.getRepeatCount() > 0) break; - onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event); - return true; - } - - case KeyEvent.KEYCODE_BACK: { - if (event.getRepeatCount() > 0) break; - if (featureId < 0) break; - if (featureId == FEATURE_OPTIONS_PANEL) { - PanelFeatureState st = getPanelState(featureId, false); - if (st != null && st.isInExpandedMode) { - // If the user is in an expanded menu and hits back, it - // should go back to the icon menu - reopenMenu(true); - return true; - } - } - closePanel(featureId); - return true; - } - - case KeyEvent.KEYCODE_CALL: { - if (getKeyguardManager().inKeyguardRestrictedInputMode()) { - break; - } - if (event.getRepeatCount() > 0) break; - mKeycodeCallTimeoutActive = true; - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); - mKeycodeMenuTimeoutHandler.sendMessageDelayed( - mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CALL_LONG_PRESS), - ViewConfiguration.getLongPressTimeout()); - return true; - } - - case KeyEvent.KEYCODE_SEARCH: { - if (event.getRepeatCount() == 0) { - mSearchKeyDownReceived = true; - } - break; - } - } - - return false; - } - - /** - * @return A handle to the keyguard manager. - */ - private KeyguardManager getKeyguardManager() { - if (mKeyguardManager == null) { - mKeyguardManager = (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE); - } - return mKeyguardManager; - } - - /** - * A key was released and not handled by anything else in the window. - * - * @see #onKeyDown - * @see android.view.KeyEvent - */ - protected boolean onKeyUp(int featureId, int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: { - AudioManager audioManager = (AudioManager) getContext().getSystemService( - Context.AUDIO_SERVICE); - if (audioManager != null) { - /* - * Play a sound. This is done on key up since we don't want the - * sound to play when a user holds down volume down to mute. - */ - audioManager.adjustSuggestedStreamVolume( - AudioManager.ADJUST_SAME, - mVolumeControlStreamType, - AudioManager.FLAG_PLAY_SOUND); - mVolumeKeyUpTime = SystemClock.uptimeMillis(); - } - return true; - } - - case KeyEvent.KEYCODE_MENU: { - onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId, - event); - return true; - } - - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { - Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); - intent.putExtra(Intent.EXTRA_KEY_EVENT, event); - getContext().sendOrderedBroadcast(intent, null); - return true; - } - - case KeyEvent.KEYCODE_CAMERA: { - if (getKeyguardManager().inKeyguardRestrictedInputMode()) { - break; - } - if (event.getRepeatCount() > 0) break; // Can a key up event repeat? - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); - if (!mKeycodeCameraTimeoutActive) break; - mKeycodeCameraTimeoutActive = false; - // Add short press behavior here if desired - return true; - } - - case KeyEvent.KEYCODE_CALL: { - if (getKeyguardManager().inKeyguardRestrictedInputMode()) { - break; - } - if (event.getRepeatCount() > 0) break; - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); - if (!mKeycodeCallTimeoutActive) break; - mKeycodeCallTimeoutActive = false; - startCallActivity(); - return true; - } - - case KeyEvent.KEYCODE_SEARCH: { - /* - * Do this in onKeyUp since the Search key is also used for - * chording quick launch shortcuts. - */ - if (getKeyguardManager().inKeyguardRestrictedInputMode() || - !mSearchKeyDownReceived) { - break; - } - mSearchKeyDownReceived = false; - launchDefaultSearch(); - return true; - } - } - - return false; - } - - private void startCallActivity() { - sendCloseSystemWindows(); - Intent intent = new Intent(Intent.ACTION_CALL_BUTTON); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getContext().startActivity(intent); - } - - @Override - protected void onActive() { - } - - @Override - public final View getDecorView() { - if (mDecor == null) { - installDecor(); - } - return mDecor; - } - - @Override - public final View peekDecorView() { - return mDecor; - } - - 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"; - - /** {@inheritDoc} */ - @Override - public Bundle saveHierarchyState() { - Bundle outState = new Bundle(); - if (mContentParent == null) { - return outState; - } - - SparseArray states = new SparseArray(); - mContentParent.saveHierarchyState(states); - outState.putSparseParcelableArray(VIEWS_TAG, states); - - // save the focused view id - View focusedView = mContentParent.findFocus(); - if (focusedView != null) { - if (focusedView.getId() != View.NO_ID) { - outState.putInt(FOCUSED_ID_TAG, focusedView.getId()); - } else { - if (Config.LOGD) { - Log.d(TAG, "couldn't save which view has focus because the focused view " - + focusedView + " has no id."); - } - } - } - - // save the panels - SparseArray panelStates = new SparseArray(); - savePanelState(panelStates); - if (panelStates.size() > 0) { - outState.putSparseParcelableArray(PANELS_TAG, panelStates); - } - - return outState; - } - - /** {@inheritDoc} */ - @Override - public void restoreHierarchyState(Bundle savedInstanceState) { - if (mContentParent == null) { - return; - } - - SparseArray savedStates - = savedInstanceState.getSparseParcelableArray(VIEWS_TAG); - if (savedStates != null) { - mContentParent.restoreHierarchyState(savedStates); - } - - // restore the focused view - int focusedViewId = savedInstanceState.getInt(FOCUSED_ID_TAG, View.NO_ID); - if (focusedViewId != View.NO_ID) { - View needsFocus = mContentParent.findViewById(focusedViewId); - if (needsFocus != null) { - needsFocus.requestFocus(); - } else { - Log.w(TAG, - "Previously focused view reported id " + focusedViewId - + " during save, but can't be found during restore."); - } - } - - // restore the panels - SparseArray panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG); - if (panelStates != null) { - restorePanelState(panelStates); - } - } - - /** - * Invoked when the panels should freeze their state. - * - * @param icicles Save state into this. This is usually indexed by the - * featureId. This will be given to {@link #restorePanelState} in the - * future. - */ - private void savePanelState(SparseArray icicles) { - PanelFeatureState[] panels = mPanels; - if (panels == null) { - return; - } - - for (int curFeatureId = panels.length - 1; curFeatureId >= 0; curFeatureId--) { - if (panels[curFeatureId] != null) { - icicles.put(curFeatureId, panels[curFeatureId].onSaveInstanceState()); - } - } - } - - /** - * Invoked when the panels should thaw their state from a previously frozen state. - * - * @param icicles The state saved by {@link #savePanelState} that needs to be thawed. - */ - private void restorePanelState(SparseArray icicles) { - PanelFeatureState st; - for (int curFeatureId = icicles.size() - 1; curFeatureId >= 0; curFeatureId--) { - st = getPanelState(curFeatureId, false /* required */); - if (st == null) { - // The panel must not have been required, and is currently not around, skip it - continue; - } - - st.onRestoreInstanceState(icicles.get(curFeatureId)); - } - - /* - * Implementation note: call openPanelsAfterRestore later to actually open the - * restored panels. - */ - } - - /** - * Opens the panels that have had their state restored. This should be - * called sometime after {@link #restorePanelState} when it is safe to add - * to the window manager. - */ - private void openPanelsAfterRestore() { - PanelFeatureState[] panels = mPanels; - - if (panels == null) { - return; - } - - PanelFeatureState st; - for (int i = panels.length - 1; i >= 0; i--) { - st = panels[i]; - if ((st != null) && st.isOpen) { - // Clear st.isOpen (openPanel will not open if it's already open) - st.isOpen = false; - openPanel(st, null); - } - } - } - - private final class DecorView extends FrameLayout { - /* package */int mDefaultOpacity = PixelFormat.OPAQUE; - - /** The feature ID of the panel, or -1 if this is the application's DecorView */ - private final int mFeatureId; - - private final Rect mDrawingBounds = new Rect(); - - private final Rect mBackgroundPadding = new Rect(); - - private final Rect mFramePadding = new Rect(); - - private final Rect mFrameOffsets = new Rect(); - - private final Paint mBlackPaint = new Paint(); - - private boolean mChanging; - - private Drawable mMenuBackground; - private boolean mWatchingForMenu; - private int mDownY; - - public DecorView(Context context, int featureId) { - super(context); - mFeatureId = featureId; - mBlackPaint.setColor(0xFF000000); - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - final int keyCode = event.getKeyCode(); - final boolean isDown = event.getAction() == KeyEvent.ACTION_DOWN; - - /* - * If the user hits another key within the play sound delay, then - * cancel the sound - */ - if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP - && mVolumeKeyUpTime + VolumePanel.PLAY_SOUND_DELAY - > SystemClock.uptimeMillis()) { - /* - * The user has hit another key during the delay (e.g., 300ms) - * since the last volume key up, so cancel any sounds. - */ - AudioManager audioManager = (AudioManager) getContext().getSystemService( - Context.AUDIO_SERVICE); - if (audioManager != null) { - audioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_SAME, - mVolumeControlStreamType, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); - } - } - - if (isDown && (event.getRepeatCount() == 0)) { - // First handle chording of panel key: if a panel key is held - // but not released, try to execute a shortcut in it. - if ((mPanelChordingKey > 0) && (mPanelChordingKey != keyCode)) { - // Perform the shortcut (mPreparedPanel can be null since - // global shortcuts (such as search) don't rely on a - // prepared panel or menu). - boolean handled = performPanelShortcut(mPreparedPanel, keyCode, event, - Menu.FLAG_PERFORM_NO_CLOSE); - - if (!handled) { - /* - * If not handled, then pass it to the view hierarchy - * and anyone else that may be interested. - */ - handled = dispatchKeyShortcutEvent(event); - - if (handled && mPreparedPanel != null) { - mPreparedPanel.isHandled = true; - } - } - - if (handled) { - return true; - } - } - - // If a panel is open, perform a shortcut on it without the - // chorded panel key - if ((mPreparedPanel != null) && mPreparedPanel.isOpen) { - if (performPanelShortcut(mPreparedPanel, keyCode, event, 0)) { - return true; - } - } - } - - final Callback cb = getCallback(); - final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event) - : super.dispatchKeyEvent(event); - if (handled) { - return true; - } - return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event) - : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event); - } - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - final Callback cb = getCallback(); - return cb != null && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super - .dispatchTouchEvent(ev); - } - - @Override - public boolean dispatchTrackballEvent(MotionEvent ev) { - final Callback cb = getCallback(); - return cb != null && mFeatureId < 0 ? cb.dispatchTrackballEvent(ev) : super - .dispatchTrackballEvent(ev); - } - - public boolean superDispatchKeyEvent(KeyEvent event) { - return super.dispatchKeyEvent(event); - } - - public boolean superDispatchTouchEvent(MotionEvent event) { - return super.dispatchTouchEvent(event); - } - - public boolean superDispatchTrackballEvent(MotionEvent event) { - return super.dispatchTrackballEvent(event); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - return onInterceptTouchEvent(event); - } - - private boolean isOutOfBounds(int x, int y) { - return x < -5 || y < -5 || x > (getWidth() + 5) - || y > (getHeight() + 5); - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent event) { - int action = event.getAction(); - if (mFeatureId >= 0) { - if (action == MotionEvent.ACTION_DOWN) { - int x = (int)event.getX(); - int y = (int)event.getY(); - if (isOutOfBounds(x, y)) { - closePanel(mFeatureId); - return true; - } - } - } - - if (!SWEEP_OPEN_MENU) { - return false; - } - - if (mFeatureId >= 0) { - if (action == MotionEvent.ACTION_DOWN) { - Log.i(TAG, "Watchiing!"); - mWatchingForMenu = true; - mDownY = (int) event.getY(); - return false; - } - - if (!mWatchingForMenu) { - return false; - } - - int y = (int)event.getY(); - if (action == MotionEvent.ACTION_MOVE) { - if (y > (mDownY+30)) { - Log.i(TAG, "Closing!"); - closePanel(mFeatureId); - mWatchingForMenu = false; - return true; - } - } else if (action == MotionEvent.ACTION_UP) { - mWatchingForMenu = false; - } - - return false; - } - - //Log.i(TAG, "Intercept: action=" + action + " y=" + event.getY() - // + " (in " + getHeight() + ")"); - - if (action == MotionEvent.ACTION_DOWN) { - int y = (int)event.getY(); - if (y >= (getHeight()-5) && !hasChildren()) { - Log.i(TAG, "Watchiing!"); - mWatchingForMenu = true; - } - return false; - } - - if (!mWatchingForMenu) { - return false; - } - - int y = (int)event.getY(); - if (action == MotionEvent.ACTION_MOVE) { - if (y < (getHeight()-30)) { - Log.i(TAG, "Opening!"); - openPanel(FEATURE_OPTIONS_PANEL, new KeyEvent( - KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU)); - mWatchingForMenu = false; - return true; - } - } else if (action == MotionEvent.ACTION_UP) { - mWatchingForMenu = false; - } - - return false; - } - - @Override - protected boolean setFrame(int l, int t, int r, int b) { - boolean changed = super.setFrame(l, t, r, b); - if (changed) { - final Rect drawingBounds = mDrawingBounds; - getDrawingRect(drawingBounds); - - Drawable fg = getForeground(); - if (fg != null) { - final Rect frameOffsets = mFrameOffsets; - drawingBounds.left += frameOffsets.left; - drawingBounds.top += frameOffsets.top; - drawingBounds.right -= frameOffsets.right; - drawingBounds.bottom -= frameOffsets.bottom; - fg.setBounds(drawingBounds); - final Rect framePadding = mFramePadding; - drawingBounds.left += framePadding.left - frameOffsets.left; - drawingBounds.top += framePadding.top - frameOffsets.top; - drawingBounds.right -= framePadding.right - frameOffsets.right; - drawingBounds.bottom -= framePadding.bottom - frameOffsets.bottom; - } - - Drawable bg = getBackground(); - if (bg != null) { - bg.setBounds(drawingBounds); - } - - if (SWEEP_OPEN_MENU) { - if (mMenuBackground == null && mFeatureId < 0 - && getAttributes().height - == WindowManager.LayoutParams.FILL_PARENT) { - mMenuBackground = getContext().getResources().getDrawable( - com.android.internal.R.drawable.menu_background); - } - if (mMenuBackground != null) { - mMenuBackground.setBounds(drawingBounds.left, - drawingBounds.bottom-6, drawingBounds.right, - drawingBounds.bottom+20); - } - } - } - return changed; - } - - @Override - public void draw(Canvas canvas) { - super.draw(canvas); - - if (mMenuBackground != null) { - mMenuBackground.draw(canvas); - } - } - - - @Override - public boolean showContextMenuForChild(View originalView) { - // Reuse the context menu builder - if (mContextMenu == null) { - mContextMenu = new ContextMenuBuilder(getContext()); - mContextMenu.setCallback(mContextMenuCallback); - } else { - mContextMenu.clearAll(); - } - - mContextMenuHelper = mContextMenu.show(originalView, originalView.getWindowToken()); - return mContextMenuHelper != null; - } - - public void startChanging() { - mChanging = true; - } - - public void finishChanging() { - mChanging = false; - drawableChanged(); - } - - public void setWindowBackground(Drawable drawable) { - if (getBackground() != drawable) { - setBackgroundDrawable(drawable); - if (drawable != null) { - drawable.getPadding(mBackgroundPadding); - } else { - mBackgroundPadding.setEmpty(); - } - drawableChanged(); - } - } - - public void setWindowFrame(Drawable drawable) { - if (getForeground() != drawable) { - setForeground(drawable); - if (drawable != null) { - drawable.getPadding(mFramePadding); - } else { - mFramePadding.setEmpty(); - } - drawableChanged(); - } - } - - @Override - protected boolean fitSystemWindows(Rect insets) { - mFrameOffsets.set(insets); - if (getForeground() != null) { - drawableChanged(); - } - return super.fitSystemWindows(insets); - } - - private void drawableChanged() { - if (mChanging) { - return; - } - - setPadding(mFramePadding.left + mBackgroundPadding.left, mFramePadding.top - + mBackgroundPadding.top, mFramePadding.right + mBackgroundPadding.right, - mFramePadding.bottom + mBackgroundPadding.bottom); - requestLayout(); - invalidate(); - - int opacity = PixelFormat.OPAQUE; - - // Note: if there is no background, we will assume opaque. The - // common case seems to be that an application sets there to be - // no background so it can draw everything itself. For that, - // we would like to assume OPAQUE and let the app force it to - // the slower TRANSLUCENT mode if that is really what it wants. - Drawable bg = getBackground(); - Drawable fg = getForeground(); - if (bg != null) { - if (fg == null) { - opacity = bg.getOpacity(); - } else if (mFramePadding.left <= 0 && mFramePadding.top <= 0 - && mFramePadding.right <= 0 && mFramePadding.bottom <= 0) { - // If the frame padding is zero, then we can be opaque - // if either the frame -or- the background is opaque. - int fop = fg.getOpacity(); - int bop = bg.getOpacity(); - if (Config.LOGV) - Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop); - if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) { - opacity = PixelFormat.OPAQUE; - } else if (fop == PixelFormat.UNKNOWN) { - opacity = bop; - } else if (bop == PixelFormat.UNKNOWN) { - opacity = fop; - } else { - opacity = Drawable.resolveOpacity(fop, bop); - } - } else { - // For now we have to assume translucent if there is a - // frame with padding... there is no way to tell if the - // frame and background together will draw all pixels. - if (Config.LOGV) - Log.v(TAG, "Padding: " + mFramePadding); - opacity = PixelFormat.TRANSLUCENT; - } - } - - if (Config.LOGV) - Log.v(TAG, "Background: " + bg + ", Frame: " + fg); - if (Config.LOGV) - Log.v(TAG, "Selected default opacity: " + opacity); - - mDefaultOpacity = opacity; - if (mFeatureId < 0) { - setDefaultWindowFormat(opacity); - } - } - - @Override - public void onWindowFocusChanged(boolean hasWindowFocus) { - super.onWindowFocusChanged(hasWindowFocus); - - // no KEYCODE_CALL events active across focus changes - mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); - mKeycodeCallTimeoutActive = false; - mKeycodeCameraTimeoutActive = false; - - // If the user is chording a menu shortcut, release the chord since - // this window lost focus - if (!hasWindowFocus && mPanelChordingKey > 0) { - closePanel(FEATURE_OPTIONS_PANEL); - } - - final Callback cb = getCallback(); - if (cb != null && mFeatureId < 0) { - cb.onWindowFocusChanged(hasWindowFocus); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - - if (mFeatureId == -1) { - /* - * The main window has been attached, try to restore any panels - * that may have been open before. This is called in cases where - * an activity is being killed for configuration change and the - * menu was open. When the activity is recreated, the menu - * should be shown again. - */ - openPanelsAfterRestore(); - } - } - } - - protected DecorView generateDecor() { - return new DecorView(getContext(), -1); - } - - protected void setFeatureFromAttrs(int featureId, TypedArray attrs, - int drawableAttr, int alphaAttr) { - Drawable d = attrs.getDrawable(drawableAttr); - if (d != null) { - requestFeature(featureId); - setFeatureDefaultDrawable(featureId, d); - } - if ((getFeatures() & (1 << featureId)) != 0) { - int alpha = attrs.getInt(alphaAttr, -1); - if (alpha >= 0) { - setFeatureDrawableAlpha(featureId, alpha); - } - } - } - - protected ViewGroup generateLayout(DecorView decor) { - // Apply data from current theme. - - TypedArray a = getWindowStyle(); - - if (false) { - System.out.println("From style:"); - String s = "Attrs:"; - for (int i = 0; i < com.android.internal.R.styleable.Window.length; i++) { - s = s + " " + Integer.toHexString(com.android.internal.R.styleable.Window[i]) + "=" - + a.getString(i); - } - System.out.println(s); - } - - mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false); - int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR) - & (~getForcedWindowFlags()); - if (mIsFloating) { - setLayout(WRAP_CONTENT, WRAP_CONTENT); - setFlags(0, flagsToUpdate); - } else { - setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate); - } - - if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) { - requestFeature(FEATURE_NO_TITLE); - } - - if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) { - setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags())); - } - - WindowManager.LayoutParams params = getAttributes(); - - if (!hasSoftInputMode()) { - params.softInputMode = a.getInt( - com.android.internal.R.styleable.Window_windowSoftInputMode, - params.softInputMode); - } - - if (a.getBoolean(com.android.internal.R.styleable.Window_backgroundDimEnabled, - mIsFloating)) { - /* All dialogs should have the window dimmed */ - if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) { - params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; - } - params.dimAmount = a.getFloat( - android.R.styleable.Window_backgroundDimAmount, 0.5f); - } - - if (params.windowAnimations == 0) { - params.windowAnimations = a.getResourceId( - com.android.internal.R.styleable.Window_windowAnimationStyle, 0); - } - - // The rest are only done if this window is not embedded; otherwise, - // the values are inherited from our container. - if (getContainer() == null) { - if (mBackgroundDrawable == null) { - if (mBackgroundResource == 0) { - mBackgroundResource = a.getResourceId( - com.android.internal.R.styleable.Window_windowBackground, 0); - } - if (mFrameResource == 0) { - mFrameResource = a.getResourceId(com.android.internal.R.styleable.Window_windowFrame, 0); - } - if (false) { - System.out.println("Background: " - + Integer.toHexString(mBackgroundResource) + " Frame: " - + Integer.toHexString(mFrameResource)); - } - } - mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000); - } - - // Inflate the window decor. - - int layoutResource; - int features = getLocalFeatures(); - // System.out.println("Features: 0x" + Integer.toHexString(features)); - if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) { - if (mIsFloating) { - layoutResource = com.android.internal.R.layout.dialog_title_icons; - } else { - layoutResource = com.android.internal.R.layout.screen_title_icons; - } - // 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; - // System.out.println("Progress!"); - } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) { - // Special case for a window with a custom title. - // If the window is floating, we need a dialog layout - if (mIsFloating) { - layoutResource = com.android.internal.R.layout.dialog_custom_title; - } else { - layoutResource = com.android.internal.R.layout.screen_custom_title; - } - } 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 { - layoutResource = com.android.internal.R.layout.screen_title; - } - // System.out.println("Title!"); - } else { - // Embedded, so no decoration is needed. - layoutResource = com.android.internal.R.layout.screen_simple; - // System.out.println("Simple!"); - } - - mDecor.startChanging(); - - View in = mLayoutInflater.inflate(layoutResource, null); - decor.addView(in, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT)); - - ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); - if (contentParent == null) { - throw new RuntimeException("Window couldn't find content container view"); - } - - if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { - ProgressBar progress = getCircularProgressBar(false); - if (progress != null) { - progress.setIndeterminate(true); - } - } - - // Remaining setup -- of background and title -- that only applies - // to top-level windows. - if (getContainer() == null) { - Drawable drawable = mBackgroundDrawable; - if (mBackgroundResource != 0) { - drawable = getContext().getResources().getDrawable(mBackgroundResource); - } - mDecor.setWindowBackground(drawable); - drawable = null; - if (mFrameResource != 0) { - drawable = getContext().getResources().getDrawable(mFrameResource); - } - mDecor.setWindowFrame(drawable); - - // System.out.println("Text=" + Integer.toHexString(mTextColor) + - // " Sel=" + Integer.toHexString(mTextSelectedColor) + - // " Title=" + Integer.toHexString(mTitleColor)); - - if (mTitleColor == 0) { - mTitleColor = mTextColor; - } - - if (mTitle != null) { - setTitle(mTitle); - } - setTitleColor(mTitleColor); - } - - mDecor.finishChanging(); - - return contentParent; - } - - private void installDecor() { - if (mDecor == null) { - mDecor = generateDecor(); - mDecor.setIsRootNamespace(true); - } - if (mContentParent == null) { - mContentParent = generateLayout(mDecor); - - mTitleView = (TextView)findViewById(com.android.internal.R.id.title); - if (mTitleView != null) { - if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) { - View titleContainer = findViewById(com.android.internal.R.id.title_container); - if (titleContainer != null) { - titleContainer.setVisibility(View.GONE); - } else { - mTitleView.setVisibility(View.GONE); - } - if (mContentParent instanceof FrameLayout) { - ((FrameLayout)mContentParent).setForeground(null); - } - } else { - mTitleView.setText(mTitle); - } - } - } - } - - private Drawable loadImageURI(Uri uri) { - try { - return Drawable.createFromStream( - getContext().getContentResolver().openInputStream(uri), null); - } catch (Exception e) { - Log.w(TAG, "Unable to open content: " + uri); - } - return null; - } - - private DrawableFeatureState getDrawableState(int featureId, boolean required) { - if ((getFeatures() & (1 << featureId)) == 0) { - if (!required) { - return null; - } - throw new RuntimeException("The feature has not been requested"); - } - - DrawableFeatureState[] ar; - if ((ar = mDrawables) == null || ar.length <= featureId) { - DrawableFeatureState[] nar = new DrawableFeatureState[featureId + 1]; - if (ar != null) { - System.arraycopy(ar, 0, nar, 0, ar.length); - } - mDrawables = ar = nar; - } - - DrawableFeatureState st = ar[featureId]; - if (st == null) { - ar[featureId] = st = new DrawableFeatureState(featureId); - } - return st; - } - - /** - * Gets a panel's state based on its feature ID. - * - * @param featureId The feature ID of the panel. - * @param required Whether the panel is required (if it is required and it - * isn't in our features, this throws an exception). - * @return The panel state. - */ - private PanelFeatureState getPanelState(int featureId, boolean required) { - return getPanelState(featureId, required, null); - } - - /** - * Gets a panel's state based on its feature ID. - * - * @param featureId The feature ID of the panel. - * @param required Whether the panel is required (if it is required and it - * isn't in our features, this throws an exception). - * @param convertPanelState Optional: If the panel state does not exist, use - * this as the panel state. - * @return The panel state. - */ - private PanelFeatureState getPanelState(int featureId, boolean required, - PanelFeatureState convertPanelState) { - if ((getFeatures() & (1 << featureId)) == 0) { - if (!required) { - return null; - } - throw new RuntimeException("The feature has not been requested"); - } - - PanelFeatureState[] ar; - if ((ar = mPanels) == null || ar.length <= featureId) { - PanelFeatureState[] nar = new PanelFeatureState[featureId + 1]; - if (ar != null) { - System.arraycopy(ar, 0, nar, 0, ar.length); - } - mPanels = ar = nar; - } - - PanelFeatureState st = ar[featureId]; - if (st == null) { - ar[featureId] = st = (convertPanelState != null) - ? convertPanelState - : new PanelFeatureState(featureId); - } - return st; - } - - @Override - public final void setChildDrawable(int featureId, Drawable drawable) { - DrawableFeatureState st = getDrawableState(featureId, true); - st.child = drawable; - updateDrawable(featureId, st, false); - } - - @Override - public final void setChildInt(int featureId, int value) { - updateInt(featureId, value, false); - } - - @Override - public boolean isShortcutKey(int keyCode, KeyEvent event) { - PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); - return st.menu != null && st.menu.isShortcutKey(keyCode, event); - } - - private void updateDrawable(int featureId, DrawableFeatureState st, boolean fromResume) { - // Do nothing if the decor is not yet installed... an update will - // need to be forced when we eventually become active. - if (mContentParent == null) { - return; - } - - final int featureMask = 1 << featureId; - - if ((getFeatures() & featureMask) == 0 && !fromResume) { - return; - } - - Drawable drawable = null; - if (st != null) { - drawable = st.child; - if (drawable == null) - drawable = st.local; - if (drawable == null) - drawable = st.def; - } - if ((getLocalFeatures() & featureMask) == 0) { - if (getContainer() != null) { - if (isActive() || fromResume) { - getContainer().setChildDrawable(featureId, drawable); - } - } - } else if (st != null && (st.cur != drawable || st.curAlpha != st.alpha)) { - // System.out.println("Drawable changed: old=" + st.cur - // + ", new=" + drawable); - st.cur = drawable; - st.curAlpha = st.alpha; - onDrawableChanged(featureId, drawable, st.alpha); - } - } - - private void updateInt(int featureId, int value, boolean fromResume) { - - // Do nothing if the decor is not yet installed... an update will - // need to be forced when we eventually become active. - if (mContentParent == null) { - return; - } - - final int featureMask = 1 << featureId; - - if ((getFeatures() & featureMask) == 0 && !fromResume) { - return; - } - - if ((getLocalFeatures() & featureMask) == 0) { - if (getContainer() != null) { - getContainer().setChildInt(featureId, value); - } - } else { - onIntChanged(featureId, value); - } - } - - private ImageView getLeftIconView() { - if (mLeftIconView != null) { - return mLeftIconView; - } - if (mContentParent == null) { - installDecor(); - } - return (mLeftIconView = (ImageView)findViewById(com.android.internal.R.id.left_icon)); - } - - private ProgressBar getCircularProgressBar(boolean shouldInstallDecor) { - if (mCircularProgressBar != null) { - return mCircularProgressBar; - } - if (mContentParent == null && shouldInstallDecor) { - installDecor(); - } - mCircularProgressBar = (ProgressBar)findViewById(com.android.internal.R.id.progress_circular); - mCircularProgressBar.setVisibility(View.INVISIBLE); - return mCircularProgressBar; - } - - private ProgressBar getHorizontalProgressBar(boolean shouldInstallDecor) { - if (mHorizontalProgressBar != null) { - return mHorizontalProgressBar; - } - if (mContentParent == null && shouldInstallDecor) { - installDecor(); - } - mHorizontalProgressBar = (ProgressBar)findViewById(com.android.internal.R.id.progress_horizontal); - mHorizontalProgressBar.setVisibility(View.INVISIBLE); - return mHorizontalProgressBar; - } - - private ImageView getRightIconView() { - if (mRightIconView != null) { - return mRightIconView; - } - if (mContentParent == null) { - installDecor(); - } - return (mRightIconView = (ImageView)findViewById(com.android.internal.R.id.right_icon)); - } - - /** - * Helper method for calling the {@link Callback#onPanelClosed(int, Menu)} - * callback. This method will grab whatever extra state is needed for the - * callback that isn't given in the parameters. If the panel is not open, - * this will not perform the callback. - * - * @param featureId Feature ID of the panel that was closed. Must be given. - * @param panel Panel that was closed. Optional but useful if there is no - * menu given. - * @param menu The menu that was closed. Optional, but give if you have. - */ - private void callOnPanelClosed(int featureId, PanelFeatureState panel, Menu menu) { - final Callback cb = getCallback(); - if (cb == null) - return; - - // Try to get a menu - if (menu == null) { - // Need a panel to grab the menu, so try to get that - if (panel == null) { - if ((featureId >= 0) && (featureId < mPanels.length)) { - panel = mPanels[featureId]; - } - } - - if (panel != null) { - // menu still may be null, which is okay--we tried our best - menu = panel.menu; - } - } - - // If the panel is not open, do not callback - if ((panel != null) && (!panel.isOpen)) - return; - - cb.onPanelClosed(featureId, menu); - } - - /** - * Helper method for adding launch-search to most applications. Opens the - * search window using default settings. - * - * @return true if search window opened - */ - private boolean launchDefaultSearch() { - final Callback cb = getCallback(); - if (cb == null) { - return false; - } else { - return cb.onSearchRequested(); - } - } - - @Override - public void setVolumeControlStream(int streamType) { - mVolumeControlStreamType = streamType; - } - - @Override - public int getVolumeControlStream() { - return mVolumeControlStreamType; - } - - private static final class DrawableFeatureState { - DrawableFeatureState(int _featureId) { - featureId = _featureId; - } - - final int featureId; - - int resid; - - Uri uri; - - Drawable local; - - Drawable child; - - Drawable def; - - Drawable cur; - - int alpha = 255; - - int curAlpha = 255; - } - - private static final class PanelFeatureState { - - /** Feature ID for this panel. */ - int featureId; - - // Information pulled from the style for this panel. - - int background; - - /** The background when the panel spans the entire available width. */ - int fullBackground; - - int gravity; - - int x; - - int y; - - int windowAnimations; - - /** Dynamic state of the panel. */ - DecorView decorView; - - /** The panel that was returned by onCreatePanelView(). */ - View createdPanelView; - - /** The panel that we are actually showing. */ - View shownPanelView; - - /** Use {@link #setMenu} to set this. */ - Menu menu; - - /** - * Whether the panel has been prepared (see - * {@link PhoneWindow#preparePanel}). - */ - boolean isPrepared; - - /** - * Whether an item's action has been performed. This happens in obvious - * scenarios (user clicks on menu item), but can also happen with - * chording menu+(shortcut key). - */ - boolean isHandled; - - boolean isOpen; - - /** - * True if the menu is in expanded mode, false if the menu is in icon - * mode - */ - boolean isInExpandedMode; - - public boolean qwertyMode; - - boolean refreshDecorView; - - /** - * Contains the state of the menu when told to freeze. - */ - Bundle frozenMenuState; - - PanelFeatureState(int featureId) { - this.featureId = featureId; - - refreshDecorView = false; - } - - void setStyle(Context context) { - TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme); - background = a.getResourceId( - com.android.internal.R.styleable.Theme_panelBackground, 0); - fullBackground = a.getResourceId( - com.android.internal.R.styleable.Theme_panelFullBackground, 0); - windowAnimations = a.getResourceId( - com.android.internal.R.styleable.Theme_windowAnimationStyle, 0); - a.recycle(); - } - - void setMenu(Menu menu) { - this.menu = menu; - - if (frozenMenuState != null) { - ((MenuBuilder) menu).restoreHierarchyState(frozenMenuState); - frozenMenuState = null; - } - } - - Parcelable onSaveInstanceState() { - SavedState savedState = new SavedState(); - savedState.featureId = featureId; - savedState.isOpen = isOpen; - savedState.isInExpandedMode = isInExpandedMode; - - if (menu != null) { - savedState.menuState = new Bundle(); - ((MenuBuilder) menu).saveHierarchyState(savedState.menuState); - } - - return savedState; - } - - void onRestoreInstanceState(Parcelable state) { - SavedState savedState = (SavedState) state; - featureId = savedState.featureId; - isOpen = savedState.isOpen; - isInExpandedMode = savedState.isInExpandedMode; - frozenMenuState = savedState.menuState; - - /* - * A LocalActivityManager keeps the same instance of this class around. - * The first time the menu is being shown after restoring, the - * Activity.onCreateOptionsMenu should be called. But, if it is the - * same instance then menu != null and we won't call that method. - * So, clear this. Also clear any cached views. - */ - menu = null; - createdPanelView = null; - shownPanelView = null; - decorView = null; - } - - private static class SavedState implements Parcelable { - int featureId; - boolean isOpen; - boolean isInExpandedMode; - Bundle menuState; - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(featureId); - dest.writeInt(isOpen ? 1 : 0); - dest.writeInt(isInExpandedMode ? 1 : 0); - - if (isOpen) { - dest.writeBundle(menuState); - } - } - - private static SavedState readFromParcel(Parcel source) { - SavedState savedState = new SavedState(); - savedState.featureId = source.readInt(); - savedState.isOpen = source.readInt() == 1; - savedState.isInExpandedMode = source.readInt() == 1; - - if (savedState.isOpen) { - savedState.menuState = source.readBundle(); - } - - return savedState; - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public SavedState createFromParcel(Parcel in) { - return readFromParcel(in); - } - - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }; - } - - } - - /** - * Simple implementation of MenuBuilder.Callback that: - *

  • Opens a submenu when selected. - *
  • Calls back to the callback's onMenuItemSelected when an item is - * selected. - */ - private final class ContextMenuCallback implements MenuBuilder.Callback { - private int mFeatureId; - private MenuDialogHelper mSubMenuHelper; - - public ContextMenuCallback(int featureId) { - mFeatureId = featureId; - } - - public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { - if (allMenusAreClosing) { - Callback callback = getCallback(); - if (callback != null) callback.onPanelClosed(mFeatureId, menu); - - if (menu == mContextMenu) { - dismissContextMenu(); - } - - // Dismiss the submenu, if it is showing - if (mSubMenuHelper != null) { - mSubMenuHelper.dismiss(); - mSubMenuHelper = null; - } - } - } - - public void onCloseSubMenu(SubMenuBuilder menu) { - Callback callback = getCallback(); - if (callback != null) callback.onPanelClosed(mFeatureId, menu.getRootMenu()); - } - - public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { - Callback callback = getCallback(); - return (callback != null) && callback.onMenuItemSelected(mFeatureId, item); - } - - public void onMenuModeChange(MenuBuilder menu) { - } - - public boolean onSubMenuSelected(SubMenuBuilder subMenu) { - // Set a simple callback for the submenu - subMenu.setCallback(this); - - // The window manager will give us a valid window token - mSubMenuHelper = new MenuDialogHelper(subMenu); - mSubMenuHelper.show(null); - - return true; - } - } - - void sendCloseSystemWindows() { - PhoneWindowManager.sendCloseSystemWindows(getContext(), null); - } - - void sendCloseSystemWindows(String reason) { - PhoneWindowManager.sendCloseSystemWindows(getContext(), reason); - } -} diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java deleted file mode 100644 index 0fa8ff57f9d3..000000000000 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ /dev/null @@ -1,1800 +0,0 @@ -/* - * Copyright (C) 2006 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 android.app.Activity; -import android.app.ActivityManagerNative; -import android.app.IActivityManager; -import android.app.IStatusBar; -import android.content.BroadcastReceiver; -import android.content.ContentQueryMap; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.database.ContentObserver; -import android.graphics.Rect; -import android.os.Handler; -import android.os.IBinder; -import android.os.LocalPowerManager; -import android.os.PowerManager; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.Vibrator; -import android.provider.Settings; - -import com.android.internal.policy.PolicyManager; -import com.android.internal.telephony.ITelephony; -import android.util.Config; -import android.util.EventLog; -import android.util.Log; -import android.view.Gravity; -import android.view.HapticFeedbackConstants; -import android.view.IWindowManager; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.WindowOrientationListener; -import android.view.RawInputEvent; -import android.view.Surface; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.Window; -import android.view.WindowManager; -import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; -import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; -import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; -import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; -import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; -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_KEYGUARD; -import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; -import static android.view.WindowManager.LayoutParams.TYPE_PHONE; -import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE; -import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR; -import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; -import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; -import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; -import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; -import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; -import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; -import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; -import static android.view.WindowManager.LayoutParams.TYPE_TOAST; -import android.view.WindowManagerImpl; -import android.view.WindowManagerPolicy; -import android.view.WindowManagerPolicy.WindowState; -import android.media.IAudioService; -import android.media.AudioManager; - -/** - * WindowManagerPolicy implementation for the Android phone UI. - */ -public class PhoneWindowManager implements WindowManagerPolicy { - static final String TAG = "WindowManager"; - static final boolean DEBUG = false; - static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; - static final boolean SHOW_STARTING_ANIMATIONS = true; - static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; - - static final int APPLICATION_LAYER = 1; - static final int PHONE_LAYER = 2; - static final int SEARCH_BAR_LAYER = 3; - static final int STATUS_BAR_PANEL_LAYER = 4; - // toasts and the plugged-in battery thing - static final int TOAST_LAYER = 5; - static final int STATUS_BAR_LAYER = 6; - // SIM errors and unlock. Not sure if this really should be in a high layer. - static final int PRIORITY_PHONE_LAYER = 7; - // like the ANR / app crashed dialogs - static final int SYSTEM_ALERT_LAYER = 8; - // system-level error dialogs - static final int SYSTEM_ERROR_LAYER = 9; - // on-screen keyboards and other such input method user interfaces go here. - static final int INPUT_METHOD_LAYER = 10; - // on-screen keyboards and other such input method user interfaces go here. - static final int INPUT_METHOD_DIALOG_LAYER = 11; - // the keyguard; nothing on top of these can take focus, since they are - // responsible for power management when displayed. - static final int KEYGUARD_LAYER = 12; - static final int KEYGUARD_DIALOG_LAYER = 13; - // things in here CAN NOT take focus, but are shown on top of everything else. - static final int SYSTEM_OVERLAY_LAYER = 14; - - static final int APPLICATION_PANEL_SUBLAYER = 1; - static final int APPLICATION_MEDIA_SUBLAYER = -1; - static final int APPLICATION_SUB_PANEL_SUBLAYER = 2; - - static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f; - - // Debugging: set this to have the system act like there is no hard keyboard. - static final boolean KEYBOARD_ALWAYS_HIDDEN = false; - - static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; - static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; - static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; - - // Vibrator pattern for haptic feedback of a long press. - private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 40, 41}; - // Vibrator pattern for haptic feedback of a zoom ring tick - private static final long[] ZOOM_RING_TICK_VIBE_PATTERN = {0, 10}; - - Context mContext; - IWindowManager mWindowManager; - LocalPowerManager mPowerManager; - Vibrator mVibrator; // Vibrator for giving feedback of orientation changes - - /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ - boolean mEnableShiftMenuBugReports = false; - - boolean mSafeMode; - WindowState mStatusBar = null; - WindowState mSearchBar = null; - WindowState mKeyguard = null; - KeyguardViewMediator mKeyguardMediator; - GlobalActions mGlobalActions; - boolean mShouldTurnOffOnKeyUp; - RecentApplicationsDialog mRecentAppsDialog; - Handler mHandler; - - boolean mLidOpen; - int mSensorRotation = -1; - boolean mScreenOn = false; - boolean mOrientationSensorEnabled = false; - int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - static final int DEFAULT_ACCELEROMETER_ROTATION = 0; - int mAccelerometerDefault = DEFAULT_ACCELEROMETER_ROTATION; - boolean mHasSoftInput = false; - - // The current size of the screen. - int mW, mH; - // During layout, the current screen borders with all outer decoration - // (status bar, input method dock) accounted for. - int mCurLeft, mCurTop, mCurRight, mCurBottom; - // During layout, the frame in which content should be displayed - // to the user, accounting for all screen decoration except for any - // space they deem as available for other content. This is usually - // the same as mCur*, but may be larger if the screen decor has supplied - // content insets. - int mContentLeft, mContentTop, mContentRight, mContentBottom; - // During layout, the current screen borders along with input method - // windows are placed. - int mDockLeft, mDockTop, mDockRight, mDockBottom; - // During layout, the layer at which the doc window is placed. - int mDockLayer; - - static final Rect mTmpParentFrame = new Rect(); - static final Rect mTmpDisplayFrame = new Rect(); - static final Rect mTmpContentFrame = new Rect(); - static final Rect mTmpVisibleFrame = new Rect(); - - WindowState mTopFullscreenOpaqueWindowState; - boolean mForceStatusBar; - boolean mHomePressed; - Intent mHomeIntent; - boolean mSearchKeyPressed; - boolean mConsumeSearchKeyUp; - - static final int ENDCALL_HOME = 0x1; - static final int ENDCALL_SLEEPS = 0x2; - static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; - int mEndcallBehavior; - - ShortcutManager mShortcutManager; - PowerManager.WakeLock mBroadcastWakeLock; - - class SettingsObserver extends ContentObserver { - private ContentQueryMap mSettings; - - SettingsObserver(Handler handler) { - super(handler); - } - - void observe() { - ContentResolver resolver = mContext.getContentResolver(); - resolver.registerContentObserver(Settings.System.getUriFor( - Settings.System.END_BUTTON_BEHAVIOR), false, this); - resolver.registerContentObserver(Settings.System.getUriFor( - Settings.System.ACCELEROMETER_ROTATION), false, this); - resolver.registerContentObserver(Settings.Secure.getUriFor( - Settings.Secure.DEFAULT_INPUT_METHOD), false, this); - update(); - } - - @Override public void onChange(boolean selfChange) { - update(); - try { - mWindowManager.setRotation(USE_LAST_ROTATION, false); - } catch (RemoteException e) { - // Ignore - } - } - - public void update() { - ContentResolver resolver = mContext.getContentResolver(); - mEndcallBehavior = Settings.System.getInt(resolver, - Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); - int accelerometerDefault = Settings.System.getInt(resolver, - Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); - if (mAccelerometerDefault != accelerometerDefault) { - mAccelerometerDefault = accelerometerDefault; - updateOrientationListener(); - } - String imId = Settings.Secure.getString(resolver, - Settings.Secure.DEFAULT_INPUT_METHOD); - boolean hasSoftInput = imId != null && imId.length() > 0; - if (mHasSoftInput != hasSoftInput) { - mHasSoftInput = hasSoftInput; - updateRotation(); - } - } - } - - class MyOrientationListener extends WindowOrientationListener { - private static final int _LOWER_THRESHOLD = 30; - private static final int _UPPER_THRESHOLD = 60; - - MyOrientationListener(Context context) { - super(context); - } - - @Override - public void onOrientationChanged(int orientation) { - // ignore orientation changes unless the value is in a range - // When switching from portrait to landscape try to use a lower threshold limit - // Use upper threshold limit when switching from landscape to portrait - // this is to delay the switch as much as we can - int rotation; - int threshold = (mSensorRotation == Surface.ROTATION_90) ? _UPPER_THRESHOLD : - _LOWER_THRESHOLD; - - if ((orientation >= 0 && orientation <= _UPPER_THRESHOLD) || - (orientation >= 270 - _LOWER_THRESHOLD)) { - rotation = (orientation >= 270 - _LOWER_THRESHOLD - && orientation <= 270 + threshold) - ? Surface.ROTATION_90 : Surface.ROTATION_0; - } else if (orientation == WindowOrientationListener.ORIENTATION_FLAT) { - // return portrait - rotation = Surface.ROTATION_0; - } else { - // ignore orientation value - return; - } - // Send updates based on orientation value - if (rotation != mSensorRotation) { - if(localLOGV) Log.i(TAG, "onOrientationChanged, rotation changed from "+rotation+" to "+mSensorRotation); - // Update window manager. The lid rotation hasn't changed, - // but we want it to re-evaluate the final rotation in case - // it needs to call back and get the sensor orientation. - mSensorRotation = rotation; - try { - mWindowManager.setRotation(rotation, false); - } catch (RemoteException e) { - // Ignore - } - } - } - } - MyOrientationListener mOrientationListener; - - boolean useSensorForOrientation() { - if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { - return true; - } - if (mAccelerometerDefault != 0 && ( - mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || - mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { - return true; - } - return false; - } - - boolean needSensorRunning() { - if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { - // If the application has explicitly requested to follow the - // orientation, then we need to turn the sensor or. - return true; - } - if (mAccelerometerDefault != 0) { - // If the setting for using the sensor by default is enabled, then - // we will always leave it on. Note that the user could go to - // a window that forces an orientation that does not use the - // sensor and in theory we could turn it off... however, when next - // turning it on we won't have a good value for the current - // orientation for a little bit, which can cause orientation - // changes to lag, so we'd like to keep it always on. (It will - // still be turned off when the screen is off.) - return true; - } - return false; - } - - /* - * Various use cases for invoking this function - * screen turning off, should always disable listeners if already enabled - * screen turned on and current app has sensor based orientation, enable listeners - * if not already enabled - * screen turned on and current app does not have sensor orientation, disable listeners if - * already enabled - * screen turning on and current app has sensor based orientation, enable listeners if needed - * screen turning on and current app has nosensor based orientation, do nothing - */ - void updateOrientationListener() { - if (!mOrientationListener.canDetectOrientation()) { - // If sensor is turned off or nonexistent for some reason - return; - } - //Could have been invoked due to screen turning on or off or - //change of the currently visible window's orientation - if(localLOGV) Log.i(TAG, "Screen status="+mScreenOn+ - ", current orientation="+mCurrentAppOrientation+ - ", SensorEnabled="+mOrientationSensorEnabled); - boolean disable = true; - if(mScreenOn) { - if(needSensorRunning()) { - disable = false; - //enable listener if not already enabled - if(!mOrientationSensorEnabled) { - mOrientationListener.enable(); - if(localLOGV) Log.i(TAG, "Enabling listeners"); - // We haven't had the sensor on, so don't yet know - // the rotation. - mSensorRotation = -1; - mOrientationSensorEnabled = true; - } - } - } - //check if sensors need to be disabled - if(disable && mOrientationSensorEnabled) { - mOrientationListener.disable(); - if(localLOGV) Log.i(TAG, "Disabling listeners"); - mSensorRotation = -1; - mOrientationSensorEnabled = false; - } - } - - Runnable mEndCallLongPress = new Runnable() { - public void run() { - mShouldTurnOffOnKeyUp = false; - performHapticFeedback(null, HapticFeedbackConstants.LONG_PRESS, false); - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); - showGlobalActionsDialog(); - } - }; - - void showGlobalActionsDialog() { - if (mGlobalActions == null) { - mGlobalActions = new GlobalActions(mContext, mPowerManager); - } - final boolean keyguardShowing = mKeyguardMediator.isShowing(); - mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); - if (keyguardShowing) { - // since it took two seconds of long press to bring this up, - // poke the wake lock so they have some time to see the dialog. - mKeyguardMediator.pokeWakelock(); - } - } - - boolean isDeviceProvisioned() { - return Settings.Secure.getInt( - mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; - } - - /** - * When a home-key longpress expires, close other system windows and launch the recent apps - */ - Runnable mHomeLongPress = new Runnable() { - public void run() { - /* - * Eat the longpress so it won't dismiss the recent apps dialog when - * the user lets go of the home key - */ - mHomePressed = false; - performHapticFeedback(null, HapticFeedbackConstants.LONG_PRESS, false); - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS); - showRecentAppsDialog(); - } - }; - - /** - * Create (if necessary) and launch the recent apps dialog - */ - void showRecentAppsDialog() { - if (mRecentAppsDialog == null) { - mRecentAppsDialog = new RecentApplicationsDialog(mContext); - } - mRecentAppsDialog.show(); - } - - /** {@inheritDoc} */ - public void init(Context context, IWindowManager windowManager, - LocalPowerManager powerManager) { - mContext = context; - mWindowManager = windowManager; - mPowerManager = powerManager; - mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager); - mHandler = new Handler(); - mOrientationListener = new MyOrientationListener(mContext); - SettingsObserver settingsObserver = new SettingsObserver(mHandler); - settingsObserver.observe(); - mShortcutManager = new ShortcutManager(context, mHandler); - mShortcutManager.observe(); - mHomeIntent = new Intent(Intent.ACTION_MAIN, null); - mHomeIntent.addCategory(Intent.CATEGORY_HOME); - mHomeIntent.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"); - mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); - } - - /** {@inheritDoc} */ - public int checkAddPermission(WindowManager.LayoutParams attrs) { - int type = attrs.type; - if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW - || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { - return WindowManagerImpl.ADD_OKAY; - } - String permission = null; - switch (type) { - case TYPE_TOAST: - // XXX right now the app process has complete control over - // this... should introduce a token to let the system - // monitor/control what they are doing. - break; - case TYPE_INPUT_METHOD: - // The window manager will check this. - break; - case TYPE_PHONE: - case TYPE_PRIORITY_PHONE: - case TYPE_SYSTEM_ALERT: - case TYPE_SYSTEM_ERROR: - case TYPE_SYSTEM_OVERLAY: - permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW; - break; - default: - permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; - } - if (permission != null) { - if (mContext.checkCallingOrSelfPermission(permission) - != PackageManager.PERMISSION_GRANTED) { - return WindowManagerImpl.ADD_PERMISSION_DENIED; - } - } - return WindowManagerImpl.ADD_OKAY; - } - - public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) { - switch (attrs.type) { - case TYPE_SYSTEM_OVERLAY: - case TYPE_TOAST: - // These types of windows can't receive input events. - attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; - break; - } - } - - void readLidState() { - try { - int sw = mWindowManager.getSwitchState(0); - if (sw >= 0) { - mLidOpen = sw == 0; - } - } catch (RemoteException e) { - // Ignore - } - } - - /** {@inheritDoc} */ - public void adjustConfigurationLw(Configuration config) { - readLidState(); - final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen; - mPowerManager.setKeyboardVisibility(lidOpen); - config.keyboardHidden = (lidOpen || mHasSoftInput) - ? Configuration.KEYBOARDHIDDEN_NO - : Configuration.KEYBOARDHIDDEN_YES; - config.hardKeyboardHidden = lidOpen - ? Configuration.KEYBOARDHIDDEN_NO - : Configuration.KEYBOARDHIDDEN_YES; - } - - public boolean isCheekPressedAgainstScreen(MotionEvent ev) { - if(ev.getSize() > SLIDE_TOUCH_EVENT_SIZE_LIMIT) { - return true; - } - int size = ev.getHistorySize(); - for(int i = 0; i < size; i++) { - if(ev.getHistoricalSize(i) > SLIDE_TOUCH_EVENT_SIZE_LIMIT) { - return true; - } - } - return false; - } - - /** {@inheritDoc} */ - public int windowTypeToLayerLw(int type) { - if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) { - return APPLICATION_LAYER; - } - switch (type) { - case TYPE_STATUS_BAR: - return STATUS_BAR_LAYER; - case TYPE_STATUS_BAR_PANEL: - return STATUS_BAR_PANEL_LAYER; - case TYPE_SEARCH_BAR: - return SEARCH_BAR_LAYER; - case TYPE_PHONE: - return PHONE_LAYER; - case TYPE_KEYGUARD: - return KEYGUARD_LAYER; - case TYPE_KEYGUARD_DIALOG: - return KEYGUARD_DIALOG_LAYER; - case TYPE_SYSTEM_ALERT: - return SYSTEM_ALERT_LAYER; - case TYPE_SYSTEM_ERROR: - return SYSTEM_ERROR_LAYER; - case TYPE_INPUT_METHOD: - return INPUT_METHOD_LAYER; - case TYPE_INPUT_METHOD_DIALOG: - return INPUT_METHOD_DIALOG_LAYER; - case TYPE_SYSTEM_OVERLAY: - return SYSTEM_OVERLAY_LAYER; - case TYPE_PRIORITY_PHONE: - return PRIORITY_PHONE_LAYER; - case TYPE_TOAST: - return TOAST_LAYER; - } - Log.e(TAG, "Unknown window type: " + type); - return APPLICATION_LAYER; - } - - /** {@inheritDoc} */ - public int subWindowTypeToLayerLw(int type) { - switch (type) { - case TYPE_APPLICATION_PANEL: - case TYPE_APPLICATION_ATTACHED_DIALOG: - return APPLICATION_PANEL_SUBLAYER; - case TYPE_APPLICATION_MEDIA: - return APPLICATION_MEDIA_SUBLAYER; - case TYPE_APPLICATION_SUB_PANEL: - return APPLICATION_SUB_PANEL_SUBLAYER; - } - Log.e(TAG, "Unknown sub-window type: " + type); - return 0; - } - - /** {@inheritDoc} */ - public View addStartingWindow(IBinder appToken, String packageName, - int theme, CharSequence nonLocalizedLabel, - int labelRes, int icon) { - if (!SHOW_STARTING_ANIMATIONS) { - return null; - } - if (packageName == null) { - return null; - } - - Context context = mContext; - boolean setTheme = false; - //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel=" - // + nonLocalizedLabel + " theme=" + Integer.toHexString(theme)); - if (theme != 0 || labelRes != 0) { - try { - context = context.createPackageContext(packageName, 0); - if (theme != 0) { - context.setTheme(theme); - setTheme = true; - } - } catch (PackageManager.NameNotFoundException e) { - // Ignore - } - } - if (!setTheme) { - context.setTheme(com.android.internal.R.style.Theme); - } - - Window win = PolicyManager.makeNewWindow(context); - if (win.getWindowStyle().getBoolean( - com.android.internal.R.styleable.Window_windowDisablePreview, false)) { - return null; - } - - Resources r = context.getResources(); - win.setTitle(r.getText(labelRes, nonLocalizedLabel)); - - win.setType( - WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); - // Force the window flags: this is a fake window, so it is not really - // touchable or focusable by the user. We also add in the ALT_FOCUSABLE_IM - // flag because we do know that the next window will take input - // focus, so we want to get the IME window up on top of us right away. - win.setFlags( - WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| - WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, - WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| - WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - - win.setLayout(WindowManager.LayoutParams.FILL_PARENT, - WindowManager.LayoutParams.FILL_PARENT); - - final WindowManager.LayoutParams params = win.getAttributes(); - params.token = appToken; - params.packageName = packageName; - params.windowAnimations = win.getWindowStyle().getResourceId( - com.android.internal.R.styleable.Window_windowAnimationStyle, 0); - params.setTitle("Starting " + packageName); - - try { - WindowManagerImpl wm = (WindowManagerImpl) - context.getSystemService(Context.WINDOW_SERVICE); - View view = win.getDecorView(); - - if (win.isFloating()) { - // Whoops, there is no way to display an animation/preview - // of such a thing! After all that work... let's skip it. - // (Note that we must do this here because it is in - // getDecorView() where the theme is evaluated... maybe - // we should peek the floating attribute from the theme - // earlier.) - return null; - } - - if (localLOGV) Log.v( - TAG, "Adding starting window for " + packageName - + " / " + appToken + ": " - + (view.getParent() != null ? view : null)); - - wm.addView(view, params); - - // Only return the view if it was successfully added to the - // window manager... which we can tell by it having a parent. - return view.getParent() != null ? view : null; - } catch (WindowManagerImpl.BadTokenException e) { - // ignore - Log.w(TAG, appToken + " already running, starting window not displayed"); - } - - return null; - } - - /** {@inheritDoc} */ - public void removeStartingWindow(IBinder appToken, View window) { - // RuntimeException e = new RuntimeException(); - // Log.i(TAG, "remove " + appToken + " " + window, e); - - if (localLOGV) Log.v( - TAG, "Removing starting window for " + appToken + ": " + window); - - if (window != null) { - WindowManagerImpl wm = (WindowManagerImpl) mContext.getSystemService(Context.WINDOW_SERVICE); - wm.removeView(window); - } - } - - /** - * Preflight adding a window to the system. - * - * Currently enforces that three window types are singletons: - * - * - * @param win The window to be added - * @param attrs Information about the window to be added - * - * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, WindowManagerImpl.ADD_MULTIPLE_SINGLETON - */ - public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) { - switch (attrs.type) { - case TYPE_STATUS_BAR: - if (mStatusBar != null) { - return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; - } - mStatusBar = win; - break; - case TYPE_SEARCH_BAR: - if (mSearchBar != null) { - return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; - } - mSearchBar = win; - break; - case TYPE_KEYGUARD: - if (mKeyguard != null) { - return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; - } - mKeyguard = win; - break; - } - return WindowManagerImpl.ADD_OKAY; - } - - /** {@inheritDoc} */ - public void removeWindowLw(WindowState win) { - if (mStatusBar == win) { - mStatusBar = null; - } - else if (mSearchBar == win) { - mSearchBar = null; - } - else if (mKeyguard == win) { - mKeyguard = null; - } - } - - static final boolean PRINT_ANIM = false; - - /** {@inheritDoc} */ - public int selectAnimationLw(WindowState win, int transit) { - if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win - + ": transit=" + transit); - if (transit == TRANSIT_PREVIEW_DONE) { - if (win.hasAppShownWindows()) { - if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT"); - return com.android.internal.R.anim.app_starting_exit; - } - } - - return 0; - } - - static ITelephony getPhoneInterface() { - return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE)); - } - - static IAudioService getAudioInterface() { - return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE)); - } - - boolean keyguardOn() { - return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode(); - } - - private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = { - WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, - WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, - }; - - /** {@inheritDoc} */ - public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, - int repeatCount) { - boolean keyguardOn = keyguardOn(); - - if (false) { - Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount=" - + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed); - } - - // Clear a pending HOME longpress if the user releases Home - // TODO: This could probably be inside the next bit of logic, but that code - // turned out to be a bit fragile so I'm doing it here explicitly, for now. - if ((code == KeyEvent.KEYCODE_HOME) && !down) { - mHandler.removeCallbacks(mHomeLongPress); - } - - // If the HOME button is currently being held, then we do special - // chording with it. - if (mHomePressed) { - - // If we have released the home key, and didn't do anything else - // while it was pressed, then it is time to go home! - if (code == KeyEvent.KEYCODE_HOME) { - if (!down) { - mHomePressed = false; - - // If an incoming call is ringing, HOME is totally disabled. - // (The user is already on the InCallScreen at this point, - // and his ONLY options are to answer or reject the call.) - boolean incomingRinging = false; - try { - ITelephony phoneServ = getPhoneInterface(); - if (phoneServ != null) { - incomingRinging = phoneServ.isRinging(); - } else { - Log.w(TAG, "Unable to find ITelephony interface"); - } - } catch (RemoteException ex) { - Log.w(TAG, "RemoteException from getPhoneInterface()", ex); - } - - if (incomingRinging) { - Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); - } else { - launchHomeFromHotKey(); - } - } - } - - return true; - } - - // First we always handle the home key here, so applications - // can never break it, although if keyguard is on, we do let - // it handle it, because that gives us the correct 5 second - // timeout. - if (code == KeyEvent.KEYCODE_HOME) { - - // If a system window has focus, then it doesn't make sense - // right now to interact with applications. - WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null; - if (attrs != null) { - final int type = attrs.type; - if (type == WindowManager.LayoutParams.TYPE_KEYGUARD - || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) { - // the "app" is keyguard, so give it the key - return false; - } - final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length; - for (int i=0; i launch home action was detected. Take the appropriate action - * given the situation with the keyguard. - */ - void launchHomeFromHotKey() { - if (mKeyguardMediator.isShowing()) { - // don't launch home if keyguard showing - } else if (mKeyguardMediator.isInputRestricted()) { - // when in keyguard restricted mode, must first verify unlock - // before launching home - mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() { - public void onKeyguardExitResult(boolean success) { - if (success) { - mContext.startActivity(mHomeIntent); - sendCloseSystemWindows(); - } - } - }); - } else { - // no keyguard stuff to worry about, just launch home! - mContext.startActivity(mHomeIntent); - sendCloseSystemWindows(); - } - } - - public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) { - final int fl = attrs.flags; - - if ((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); - } else { - contentInset.setEmpty(); - } - } - - /** {@inheritDoc} */ - public void beginLayoutLw(int displayWidth, int displayHeight) { - mW = displayWidth; - mH = displayHeight; - mDockLeft = mContentLeft = mCurLeft = 0; - mDockTop = mContentTop = mCurTop = 0; - mDockRight = mContentRight = mCurRight = displayWidth; - mDockBottom = mContentBottom = mCurBottom = displayHeight; - mDockLayer = 0x10000000; - - // decide where the status bar goes ahead of time - if (mStatusBar != null) { - final Rect pf = mTmpParentFrame; - final Rect df = mTmpDisplayFrame; - final Rect vf = mTmpVisibleFrame; - pf.left = df.left = vf.left = 0; - pf.top = df.top = vf.top = 0; - pf.right = df.right = vf.right = displayWidth; - pf.bottom = df.bottom = vf.bottom = displayHeight; - - mStatusBar.computeFrameLw(pf, df, vf, vf); - 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; - } - } - } - - void setAttachedWindowFrames(WindowState win, int fl, int sim, - WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) { - if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) { - // Here's a special case: if this attached window is a panel that is - // above the dock window, and the window it is attached to is below - // the dock window, then the frames we computed for the window it is - // attached to can not be used because the dock is effectively part - // of the underlying window and the attached window is floating on top - // of the whole thing. So, we ignore the attached window and explicitly - // compute the frames that would be appropriate without the dock. - df.left = cf.left = vf.left = mDockLeft; - df.top = cf.top = vf.top = mDockTop; - df.right = cf.right = vf.right = mDockRight; - df.bottom = cf.bottom = vf.bottom = mDockBottom; - } else { - // The effective display frame of the attached window depends on - // whether it is taking care of insetting its content. If not, - // we need to use the parent's content frame so that the entire - // window is positioned within that content. Otherwise we can use - // the display frame and let the attached window take care of - // positioning its content appropriately. - if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { - cf.set(attached.getDisplayFrameLw()); - } else { - // If the window is resizing, then we want to base the content - // frame on our attached content frame to resize... however, - // things can be tricky if the attached window is NOT in resize - // mode, in which case its content frame will be larger. - // Ungh. So to deal with that, make sure the content frame - // we end up using is not covering the IM dock. - cf.set(attached.getContentFrameLw()); - if (attached.getSurfaceLayer() < mDockLayer) { - if (cf.left < mContentLeft) cf.left = mContentLeft; - if (cf.top < mContentTop) cf.top = mContentTop; - if (cf.right > mContentRight) cf.right = mContentRight; - if (cf.bottom > mContentBottom) cf.bottom = mContentBottom; - } - } - df.set(insetDecors ? attached.getDisplayFrameLw() : cf); - vf.set(attached.getVisibleFrameLw()); - } - // The LAYOUT_IN_SCREEN flag is used to determine whether the attached - // window should be positioned relative to its parent or the entire - // screen. - pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 - ? attached.getFrameLw() : df); - } - - /** {@inheritDoc} */ - public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached) { - // we've already done the status bar - if (win == mStatusBar) { - return; - } - - if (false) { - if ("com.google.android.youtube".equals(attrs.packageName) - && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { - Log.i(TAG, "GOTCHA!"); - } - } - - final int fl = attrs.flags; - final int sim = attrs.softInputMode; - - final Rect pf = mTmpParentFrame; - final Rect df = mTmpDisplayFrame; - final Rect cf = mTmpContentFrame; - final Rect vf = mTmpVisibleFrame; - - if (attrs.type == TYPE_INPUT_METHOD) { - pf.left = df.left = cf.left = vf.left = mDockLeft; - pf.top = df.top = cf.top = vf.top = mDockTop; - pf.right = df.right = cf.right = vf.right = mDockRight; - pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom; - // IM dock windows always go to the bottom of the screen. - attrs.gravity = Gravity.BOTTOM; - mDockLayer = win.getSurfaceLayer(); - } else { - if ((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 - // to cover all of the screen space, and it can take care of - // moving its contents to account for screen decorations that - // intrude into that space. - if (attached != null) { - // If this window is attached to another, our display - // frame is the same as the one we are attached to. - setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf); - } else { - pf.left = df.left = 0; - pf.top = df.top = 0; - pf.right = df.right = mW; - pf.bottom = df.bottom = mH; - if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { - cf.left = mDockLeft; - cf.top = mDockTop; - cf.right = mDockRight; - cf.bottom = mDockBottom; - } else { - cf.left = mContentLeft; - cf.top = mContentTop; - cf.right = mContentRight; - cf.bottom = mContentBottom; - } - vf.left = mCurLeft; - vf.top = mCurTop; - vf.right = mCurRight; - vf.bottom = mCurBottom; - } - } else if ((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; - pf.top = df.top = cf.top = 0; - pf.right = df.right = cf.right = mW; - pf.bottom = df.bottom = cf.bottom = mH; - vf.left = mCurLeft; - vf.top = mCurTop; - vf.right = mCurRight; - vf.bottom = mCurBottom; - } else if (attached != null) { - // A child window should be placed inside of the same visible - // frame that its parent had. - setAttachedWindowFrames(win, fl, sim, attached, false, pf, df, cf, vf); - } else { - // Otherwise, a normal window must be placed inside the content - // of all screen decorations. - pf.left = mContentLeft; - pf.top = mContentTop; - pf.right = mContentRight; - pf.bottom = mContentBottom; - if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { - df.left = cf.left = mDockLeft; - df.top = cf.top = mDockTop; - df.right = cf.right = mDockRight; - df.bottom = cf.bottom = mDockBottom; - } else { - df.left = cf.left = mContentLeft; - df.top = cf.top = mContentTop; - df.right = cf.right = mContentRight; - df.bottom = cf.bottom = mContentBottom; - } - vf.left = mCurLeft; - vf.top = mCurTop; - vf.right = mCurRight; - vf.bottom = mCurBottom; - } - } - - if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) { - df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000; - df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000; - } - - if (false) { - if ("com.google.android.youtube".equals(attrs.packageName) - && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { - if (true || localLOGV) Log.v(TAG, "Computing frame of " + win + - ": pf=" + pf.toShortString() + " df=" + df.toShortString() - + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()); - } - } - - win.computeFrameLw(pf, df, cf, vf); - - // Dock windows carve out the bottom of the screen, so normal windows - // can't appear underneath them. - if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) { - int top = win.getContentFrameLw().top; - top += win.getGivenContentInsetsLw().top; - if (mContentBottom > top) { - mContentBottom = top; - } - top = win.getVisibleFrameLw().top; - top += win.getGivenVisibleInsetsLw().top; - if (mCurBottom > top) { - mCurBottom = top; - } - } - } - - /** {@inheritDoc} */ - public void finishLayoutLw() { - } - - /** {@inheritDoc} */ - public void beginAnimationLw(int displayWidth, int displayHeight) { - mTopFullscreenOpaqueWindowState = null; - mForceStatusBar = false; - } - - /** {@inheritDoc} */ - public void animatingWindowLw(WindowState win, - WindowManager.LayoutParams attrs) { - if (win.isVisibleLw()) { - if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { - mForceStatusBar = true; - } else if (mTopFullscreenOpaqueWindowState == null - && attrs.type >= FIRST_APPLICATION_WINDOW - && attrs.type <= LAST_APPLICATION_WINDOW - && win.fillsScreenLw(mW, mH, true, false) - && win.isVisibleLw()) { - mTopFullscreenOpaqueWindowState = win; - } - } - } - - /** {@inheritDoc} */ - public boolean finishAnimationLw() { - boolean changed = false; - if (mStatusBar != null) { - //Log.i(TAG, "force=" + mForceStatusBar - // + " top=" + mTopFullscreenOpaqueWindowState); - if (mForceStatusBar) { - changed |= mStatusBar.showLw(true); - } 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) { - changed |= mStatusBar.hideLw(true); - } else { - changed |= mStatusBar.showLw(true); - } - } - } - return changed; - } - - /** {@inheritDoc} */ - public boolean preprocessInputEventTq(RawInputEvent event) { - switch (event.type) { - case RawInputEvent.EV_SW: - if (event.keycode == 0) { - // lid changed state - mLidOpen = event.value == 0; - updateRotation(); - if (keyguardIsShowingTq()) { - if (mLidOpen) { - // only do this if it's opening -- closing the device shouldn't turn it - // off, but it also shouldn't turn it on. - mKeyguardMediator.pokeWakelock(); - } - } else { - // Light up the keyboard if we are sliding up. - if (mLidOpen) { - mPowerManager.userActivity(SystemClock.uptimeMillis(), false, - LocalPowerManager.BUTTON_EVENT); - } else { - mPowerManager.userActivity(SystemClock.uptimeMillis(), false, - LocalPowerManager.OTHER_EVENT); - } - } - } - } - return false; - } - - - /** {@inheritDoc} */ - public boolean isAppSwitchKeyTqTiLwLi(int keycode) { - return keycode == KeyEvent.KEYCODE_HOME - || keycode == KeyEvent.KEYCODE_ENDCALL; - } - - /** {@inheritDoc} */ - public boolean isMovementKeyTi(int keycode) { - switch (keycode) { - case KeyEvent.KEYCODE_DPAD_UP: - case KeyEvent.KEYCODE_DPAD_DOWN: - case KeyEvent.KEYCODE_DPAD_LEFT: - case KeyEvent.KEYCODE_DPAD_RIGHT: - return true; - } - return false; - } - - - /** - * @return Whether a telephone call is in progress right now. - */ - boolean isInCall() { - final ITelephony phone = getPhoneInterface(); - if (phone == null) { - Log.w(TAG, "couldn't get ITelephony reference"); - return false; - } - try { - return phone.isOffhook(); - } catch (RemoteException e) { - Log.w(TAG, "ITelephony.isOffhhook threw RemoteException " + e); - return false; - } - } - - /** - * @return Whether music is being played right now. - */ - boolean isMusicActive() { - final IAudioService audio = getAudioInterface(); - if (audio == null) { - Log.w(TAG, "isMusicActive: couldn't get IAudioService reference"); - return false; - } - try { - return audio.isMusicActive(); - } catch (RemoteException e) { - Log.w(TAG, "IAudioService.isMusicActive() threw RemoteException " + e); - return false; - } - } - - /** - * Tell the audio service to adjust the volume appropriate to the event. - * @param keycode - */ - void sendVolToMusic(int keycode) { - final IAudioService audio = getAudioInterface(); - if (audio == null) { - Log.w(TAG, "sendVolToMusic: couldn't get IAudioService reference"); - return; - } - try { - // since audio is playing, we shouldn't have to hold a wake lock - // during the call, but we do it as a precaution for the rare possibility - // that the music stops right before we call this - mBroadcastWakeLock.acquire(); - audio.adjustStreamVolume( - AudioManager.STREAM_MUSIC, - keycode == KeyEvent.KEYCODE_VOLUME_UP - ? AudioManager.ADJUST_RAISE - : AudioManager.ADJUST_LOWER, - 0); - } catch (RemoteException e) { - Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e); - } finally { - mBroadcastWakeLock.release(); - } - } - - static boolean isMediaKey(int code) { - if (code == KeyEvent.KEYCODE_HEADSETHOOK || - code == KeyEvent.KEYCODE_PLAYPAUSE || - code == KeyEvent.KEYCODE_STOP || - code == KeyEvent.KEYCODE_NEXTSONG || - code == KeyEvent.KEYCODE_PREVIOUSSONG || - code == KeyEvent.KEYCODE_PREVIOUSSONG || - code == KeyEvent.KEYCODE_FORWARD) { - return true; - } - return false; - } - - /** {@inheritDoc} */ - public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) { - int result = ACTION_PASS_TO_USER; - final boolean isWakeKey = isWakeKeyTq(event); - final boolean keyguardShowing = keyguardIsShowingTq(); - - if (false) { - Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode - + " screenIsOn=" + screenIsOn + " keyguardShowing=" + keyguardShowing); - } - - if (keyguardShowing) { - if (screenIsOn) { - // when the screen is on, always give the event to the keyguard - result |= ACTION_PASS_TO_USER; - } else { - // otherwise, don't pass it to the user - result &= ~ACTION_PASS_TO_USER; - - final boolean isKeyDown = - (event.type == RawInputEvent.EV_KEY) && (event.value != 0); - if (isWakeKey && isKeyDown) { - - // tell the mediator about a wake key, it may decide to - // turn on the screen depending on whether the key is - // appropriate. - if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode) - && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN - || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) { - if (isInCall()) { - // if the keyguard didn't wake the device, we are in call, and - // it is a volume key, turn on the screen so that the user - // can more easily adjust the in call volume. - mKeyguardMediator.pokeWakelock(); - } else if (isMusicActive()) { - // when keyguard is showing and screen off, we need - // to handle the volume key for music here - sendVolToMusic(event.keycode); - } - } - } - } - } else if (!screenIsOn) { - if (isWakeKey) { - // a wake key has a sole purpose of waking the device; don't pass - // it to the user - result |= ACTION_POKE_USER_ACTIVITY; - result &= ~ACTION_PASS_TO_USER; - } - } - - int type = event.type; - int code = event.keycode; - boolean down = event.value != 0; - - if (type == RawInputEvent.EV_KEY) { - if (code == KeyEvent.KEYCODE_ENDCALL) { - if (down) { - boolean hungUp = false; - // key repeats are generated by the window manager, and we don't see them - // here, so unless the driver is doing something it shouldn't be, we know - // this is the real press event. - try { - ITelephony phoneServ = getPhoneInterface(); - if (phoneServ != null) { - hungUp = phoneServ.endCall(); - } else { - Log.w(TAG, "!!! Unable to find ITelephony interface !!!"); - } - } catch (RemoteException ex) { - Log.w(TAG, "ITelephony.endCall() threw RemoteException" + ex); - } - if (hungUp || !screenIsOn) { - mShouldTurnOffOnKeyUp = false; - } else { - // only try to turn off the screen if we didn't already hang up - mShouldTurnOffOnKeyUp = true; - mHandler.postDelayed(mEndCallLongPress, - ViewConfiguration.getGlobalActionKeyTimeout()); - result &= ~ACTION_PASS_TO_USER; - } - } else { - mHandler.removeCallbacks(mEndCallLongPress); - if (mShouldTurnOffOnKeyUp) { - mShouldTurnOffOnKeyUp = false; - boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0; - boolean sleeps = (mEndcallBehavior & ENDCALL_SLEEPS) != 0; - if (keyguardShowing - || (sleeps && !gohome) - || (gohome && !goHome() && sleeps)) { - // they must already be on the keyguad or home screen, - // go to sleep instead - Log.d(TAG, "I'm tired mEndcallBehavior=0x" - + Integer.toHexString(mEndcallBehavior)); - result &= ~ACTION_POKE_USER_ACTIVITY; - result |= ACTION_GO_TO_SLEEP; - } - result &= ~ACTION_PASS_TO_USER; - } - } - } else if (isMediaKey(code)) { - // This key needs to be handled even if the screen is off. - // If others need to be handled while it's off, this is a reasonable - // pattern to follow. - if ((result & ACTION_PASS_TO_USER) == 0) { - // Only do this if we would otherwise not pass it to the user. In that - // case, the PhoneWindow class will do the same thing, except it will - // only do it if the showing app doesn't process the key on its own. - KeyEvent keyEvent = new KeyEvent(event.when, event.when, - down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP, - code, 0); - mBroadcastWakeLock.acquire(); - mHandler.post(new PassHeadsetKey(keyEvent)); - } - } else if (code == KeyEvent.KEYCODE_CALL) { - // If an incoming call is ringing, answer it! - // (We handle this key here, rather than in the InCallScreen, to make - // sure we'll respond to the key even if the InCallScreen hasn't come to - // the foreground yet.) - - // We answer the call on the DOWN event, to agree with - // the "fallback" behavior in the InCallScreen. - if (down) { - try { - ITelephony phoneServ = getPhoneInterface(); - if (phoneServ != null) { - if (phoneServ.isRinging()) { - Log.i(TAG, "interceptKeyTq:" - + " CALL key-down while ringing: Answer the call!"); - phoneServ.answerRingingCall(); - - // And *don't* pass this key thru to the current activity - // (which is presumably the InCallScreen.) - result &= ~ACTION_PASS_TO_USER; - } - } else { - Log.w(TAG, "CALL button: Unable to find ITelephony interface"); - } - } catch (RemoteException ex) { - Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex); - } - } - } else if ((code == KeyEvent.KEYCODE_VOLUME_UP) - || (code == KeyEvent.KEYCODE_VOLUME_DOWN)) { - // If an incoming call is ringing, either VOLUME key means - // "silence ringer". We handle these keys here, rather than - // in the InCallScreen, to make sure we'll respond to them - // even if the InCallScreen hasn't come to the foreground yet. - - // Look for the DOWN event here, to agree with the "fallback" - // behavior in the InCallScreen. - if (down) { - try { - ITelephony phoneServ = getPhoneInterface(); - if (phoneServ != null) { - if (phoneServ.isRinging()) { - Log.i(TAG, "interceptKeyTq:" - + " VOLUME key-down while ringing: Silence ringer!"); - // Silence the ringer. (It's safe to call this - // even if the ringer has already been silenced.) - phoneServ.silenceRinger(); - - // And *don't* pass this key thru to the current activity - // (which is probably the InCallScreen.) - result &= ~ACTION_PASS_TO_USER; - } - } else { - Log.w(TAG, "VOLUME button: Unable to find ITelephony interface"); - } - } catch (RemoteException ex) { - Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex); - } - } - } - } - - return result; - } - - class PassHeadsetKey implements Runnable { - KeyEvent mKeyEvent; - - PassHeadsetKey(KeyEvent keyEvent) { - mKeyEvent = keyEvent; - } - - public void run() { - if (ActivityManagerNative.isSystemReady()) { - Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); - intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent); - mContext.sendOrderedBroadcast(intent, null, mBroadcastDone, - mHandler, Activity.RESULT_OK, null, null); - } - } - } - - BroadcastReceiver mBroadcastDone = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - mBroadcastWakeLock.release(); - } - }; - - /** {@inheritDoc} */ - public boolean isWakeRelMovementTq(int device, int classes, - RawInputEvent event) { - // if it's tagged with one of the wake bits, it wakes up the device - return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0); - } - - /** {@inheritDoc} */ - public boolean isWakeAbsMovementTq(int device, int classes, - RawInputEvent event) { - // if it's tagged with one of the wake bits, it wakes up the device - return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0); - } - - /** - * Given the current state of the world, should this key wake up the device? - */ - protected boolean isWakeKeyTq(RawInputEvent event) { - // There are not key maps for trackball devices, but we'd still - // like to have pressing it wake the device up, so force it here. - int keycode = event.keycode; - int flags = event.flags; - if (keycode == RawInputEvent.BTN_MOUSE) { - flags |= WindowManagerPolicy.FLAG_WAKE; - } - return (flags - & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; - } - - /** {@inheritDoc} */ - public void screenTurnedOff(int why) { - EventLog.writeEvent(70000, 0); - mKeyguardMediator.onScreenTurnedOff(why); - mScreenOn = false; - updateOrientationListener(); - } - - /** {@inheritDoc} */ - public void screenTurnedOn() { - EventLog.writeEvent(70000, 1); - mKeyguardMediator.onScreenTurnedOn(); - mScreenOn = true; - updateOrientationListener(); - } - - /** {@inheritDoc} */ - public void enableKeyguard(boolean enabled) { - mKeyguardMediator.setKeyguardEnabled(enabled); - } - - /** {@inheritDoc} */ - public void exitKeyguardSecurely(OnKeyguardExitResult callback) { - mKeyguardMediator.verifyUnlock(callback); - } - - /** {@inheritDoc} */ - public boolean keyguardIsShowingTq() { - return mKeyguardMediator.isShowing(); - } - - /** {@inheritDoc} */ - public boolean inKeyguardRestrictedKeyInputMode() { - return mKeyguardMediator.isInputRestricted(); - } - - /** - * Callback from {@link KeyguardViewMediator} - */ - public void onKeyguardShow() { - sendCloseSystemWindows(); - } - - void sendCloseSystemWindows() { - sendCloseSystemWindows(mContext, null); - } - - void sendCloseSystemWindows(String reason) { - sendCloseSystemWindows(mContext, reason); - } - - static void sendCloseSystemWindows(Context context, String reason) { - if (ActivityManagerNative.isSystemReady()) { - Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - if (reason != null) { - intent.putExtra(SYSTEM_DIALOG_REASON_KEY, reason); - } - context.sendBroadcast(intent); - } - } - - public int rotationForOrientation(int orientation, int lastRotation, - boolean displayEnabled) { - switch (orientation) { - case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: - //always return landscape if orientation set to landscape - return Surface.ROTATION_90; - case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: - //always return portrait if orientation set to portrait - return Surface.ROTATION_0; - } - // case for nosensor meaning ignore sensor and consider only lid - // or orientation sensor disabled - //or case.unspecified - if (mLidOpen) { - return Surface.ROTATION_90; - } else { - if (useSensorForOrientation()) { - // If the user has enabled auto rotation by default, do it. - return mSensorRotation >= 0 ? mSensorRotation : lastRotation; - } - return Surface.ROTATION_0; - } - } - - public boolean detectSafeMode() { - try { - int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU); - mSafeMode = menuState > 0; - Log.i(TAG, "Menu key state: " + menuState + " safeMode=" + mSafeMode); - return mSafeMode; - } catch (RemoteException e) { - // Doom! (it's also local) - throw new RuntimeException("window manager dead"); - } - } - - /** {@inheritDoc} */ - public void systemReady() { - try { - if (mSafeMode) { - // If the user is holding the menu key code, then we are - // going to boot into safe mode. - ActivityManagerNative.getDefault().enterSafeMode(); - } - // tell the keyguard - mKeyguardMediator.onSystemReady(); - android.os.SystemProperties.set("dev.bootcomplete", "1"); - updateOrientationListener(); - mVibrator = new Vibrator(); - } catch (RemoteException e) { - // Ignore - } - } - - - /** {@inheritDoc} */ - public void enableScreenAfterBoot() { - readLidState(); - updateRotation(); - } - - void updateRotation() { - mPowerManager.setKeyboardVisibility(mLidOpen); - int rotation= Surface.ROTATION_0; - if (mLidOpen) { - // always use landscape if lid is open - rotation = Surface.ROTATION_90; - } - //if lid is closed orientation will be portrait - try { - //set orientation on WindowManager - mWindowManager.setRotation(rotation, true); - } catch (RemoteException e) { - // Ignore - } - } - - /** - * goes to the home screen - * @return whether it did anything - */ - boolean goHome() { - if (false) { - // This code always brings home to the front. - mContext.startActivity(mHomeIntent); - } else { - // This code brings home to the front or, if it is already - // at the front, puts the device to sleep. - try { - int result = ActivityManagerNative.getDefault() - .startActivity(null, mHomeIntent, - mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()), - null, 0, null, null, 0, true /* onlyIfNeeded*/, false); - if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) { - return false; - } - } catch (RemoteException ex) { - // bummer, the activity manager, which is in this process, is dead - } - } - sendCloseSystemWindows(); - return true; - } - - public void setCurrentOrientation(int newOrientation) { - if(newOrientation != mCurrentAppOrientation) { - mCurrentAppOrientation = newOrientation; - updateOrientationListener(); - } - } - - public boolean performHapticFeedback(WindowState win, int effectId, boolean always) { - if (!always && Settings.System.getInt(mContext.getContentResolver(), - Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) { - return false; - } - switch (effectId) { - case HapticFeedbackConstants.LONG_PRESS: - mVibrator.vibrate(LONG_PRESS_VIBE_PATTERN, -1); - return true; - case HapticFeedbackConstants.ZOOM_RING_TICK: - mVibrator.vibrate(ZOOM_RING_TICK_VIBE_PATTERN, -1); - } - return false; - } - - public void screenOnStopped() { - if (!mKeyguardMediator.isShowing()) { - long curTime = SystemClock.uptimeMillis(); - mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); - } - } -} diff --git a/policy/com/android/internal/policy/impl/Policy.java b/policy/com/android/internal/policy/impl/Policy.java deleted file mode 100644 index 17f3e9129666..000000000000 --- a/policy/com/android/internal/policy/impl/Policy.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2008 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 android.content.Context; -import android.util.Log; - -import com.android.internal.policy.IPolicy; -import com.android.internal.policy.impl.PhoneLayoutInflater; -import com.android.internal.policy.impl.PhoneWindow; -import com.android.internal.policy.impl.PhoneWindowManager; - -/** - * {@hide} - */ - -// Simple implementation of the policy interface that spawns the right -// set of objects -public class Policy implements IPolicy { - private static final String TAG = "PhonePolicy"; - - private static final String[] preload_classes = { - "com.android.internal.policy.impl.PhoneLayoutInflater", - "com.android.internal.policy.impl.PhoneWindow", - "com.android.internal.policy.impl.PhoneWindow$1", - "com.android.internal.policy.impl.PhoneWindow$ContextMenuCallback", - "com.android.internal.policy.impl.PhoneWindow$DecorView", - "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState", - "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState", - }; - - static { - // For performance reasons, preload some policy specific classes when - // the policy gets loaded. - for (String s : preload_classes) { - try { - Class.forName(s); - } catch (ClassNotFoundException ex) { - Log.e(TAG, "Could not preload class for phone policy: " + s); - } - } - } - - public PhoneWindow makeNewWindow(Context context) { - return new PhoneWindow(context); - } - - public PhoneLayoutInflater makeNewLayoutInflater(Context context) { - return new PhoneLayoutInflater(context); - } - - public PhoneWindowManager makeNewWindowManager() { - return new PhoneWindowManager(); - } -} diff --git a/policy/com/android/internal/policy/impl/PowerDialog.java b/policy/com/android/internal/policy/impl/PowerDialog.java deleted file mode 100644 index 77c42abcd402..000000000000 --- a/policy/com/android/internal/policy/impl/PowerDialog.java +++ /dev/null @@ -1,179 +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.IServiceManager; -import android.os.LocalPowerManager; -import android.os.ServiceManager; -import android.os.ServiceManagerNative; -import android.os.SystemClock; -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); - 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.shutdownAfterDisablingRadio(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/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java deleted file mode 100644 index 5442dd4e4bde..000000000000 --- a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (C) 2008 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 android.app.ActivityManager; -import android.app.Dialog; -import android.app.StatusBarManager; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.view.View.OnClickListener; -import android.widget.ImageView; -import android.widget.TextView; - -import java.util.List; - -public class RecentApplicationsDialog extends Dialog implements OnClickListener { - // Elements for debugging support -// private static final String LOG_TAG = "RecentApplicationsDialog"; - private static final boolean DBG_FORCE_EMPTY_LIST = false; - - static private StatusBarManager sStatusBar; - - private static final int NUM_BUTTONS = 6; - private static final int MAX_RECENT_TASKS = NUM_BUTTONS * 2; // allow for some discards - - final View[] mButtons = new View[NUM_BUTTONS]; - View mNoAppsText; - IntentFilter mBroadcastIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - - public RecentApplicationsDialog(Context context) { - super(context); - } - - /** - * We create the recent applications dialog just once, and it stays around (hidden) - * until activated by the user. - * - * @see PhoneWindowManager#showRecentAppsDialog - */ - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Context context = getContext(); - - if (sStatusBar == null) { - sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE); - } - - Window theWindow = getWindow(); - theWindow.requestFeature(Window.FEATURE_NO_TITLE); - theWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); - theWindow.setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - theWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, - WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - - setContentView(com.android.internal.R.layout.recent_apps_dialog); - - mButtons[0] = findViewById(com.android.internal.R.id.button1); - mButtons[1] = findViewById(com.android.internal.R.id.button2); - mButtons[2] = findViewById(com.android.internal.R.id.button3); - mButtons[3] = findViewById(com.android.internal.R.id.button4); - mButtons[4] = findViewById(com.android.internal.R.id.button5); - mButtons[5] = findViewById(com.android.internal.R.id.button6); - mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message); - - for (View b : mButtons) { - b.setOnClickListener(this); - } - } - - /** - * Handler for user clicks. If a button was clicked, launch the corresponding activity. - */ - public void onClick(View v) { - - for (View b : mButtons) { - if (b == v) { - // prepare a launch intent and send it - Intent intent = (Intent)b.getTag(); - intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); - getContext().startActivity(intent); - } - } - dismiss(); - } - - /** - * Set up and show the recent activities dialog. - */ - @Override - public void onStart() { - super.onStart(); - reloadButtons(); - if (sStatusBar != null) { - sStatusBar.disable(StatusBarManager.DISABLE_EXPAND); - } - - // receive broadcasts - getContext().registerReceiver(mBroadcastReceiver, mBroadcastIntentFilter); - } - - /** - * Dismiss the recent activities dialog. - */ - @Override - public void onStop() { - super.onStop(); - - // dump extra memory we're hanging on to - for (View b : mButtons) { - setButtonAppearance(b, null, null); - b.setTag(null); - } - - if (sStatusBar != null) { - sStatusBar.disable(StatusBarManager.DISABLE_NONE); - } - - // stop receiving broadcasts - getContext().unregisterReceiver(mBroadcastReceiver); - } - - /** - * Reload the 6 buttons with recent activities - */ - private void reloadButtons() { - - final Context context = getContext(); - final PackageManager pm = context.getPackageManager(); - final ActivityManager am = (ActivityManager) - context.getSystemService(Context.ACTIVITY_SERVICE); - final List recentTasks = - am.getRecentTasks(MAX_RECENT_TASKS, 0); - - ResolveInfo homeInfo = pm.resolveActivity( - new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME), - 0); - - // Performance note: Our android performance guide says to prefer Iterator when - // using a List class, but because we know that getRecentTasks() always returns - // an ArrayList<>, we'll use a simple index instead. - int button = 0; - int numTasks = recentTasks.size(); - for (int i = 0; i < numTasks && (button < NUM_BUTTONS); ++i) { - final ActivityManager.RecentTaskInfo info = recentTasks.get(i); - - // for debug purposes only, disallow first result to create empty lists - if (DBG_FORCE_EMPTY_LIST && (i == 0)) continue; - - Intent intent = new Intent(info.baseIntent); - if (info.origActivity != null) { - intent.setComponent(info.origActivity); - } - - // Skip the current home activity. - if (homeInfo != null) { - if (homeInfo.activityInfo.packageName.equals( - intent.getComponent().getPackageName()) - && homeInfo.activityInfo.name.equals( - intent.getComponent().getClassName())) { - continue; - } - } - - intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) - | Intent.FLAG_ACTIVITY_NEW_TASK); - final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0); - if (resolveInfo != null) { - final ActivityInfo activityInfo = resolveInfo.activityInfo; - final String title = activityInfo.loadLabel(pm).toString(); - final Drawable icon = activityInfo.loadIcon(pm); - - if (title != null && title.length() > 0 && icon != null) { - final View b = mButtons[button]; - setButtonAppearance(b, title, icon); - b.setTag(intent); - b.setVisibility(View.VISIBLE); - b.setPressed(false); - b.clearFocus(); - ++button; - } - } - } - - // handle the case of "no icons to show" - mNoAppsText.setVisibility((button == 0) ? View.VISIBLE : View.GONE); - - // hide the rest - for ( ; button < NUM_BUTTONS; ++button) { - mButtons[button].setVisibility(View.GONE); - } - } - - /** - * Adjust appearance of each icon-button - */ - private void setButtonAppearance(View theButton, final String theTitle, final Drawable icon) { - TextView tv = (TextView) theButton.findViewById(com.android.internal.R.id.label); - tv.setText(theTitle); - ImageView iv = (ImageView) theButton.findViewById(com.android.internal.R.id.icon); - iv.setImageDrawable(icon); - } - - /** - * This is the listener for the ACTION_CLOSE_SYSTEM_DIALOGS intent. It's an indication that - * we should close ourselves immediately, in order to allow a higher-priority UI to take over - * (e.g. phone call received). - * - * TODO: This is a really heavyweight solution for something that should be so simple. - * For example, we already have a handler, in our superclass, why aren't we sharing that? - * I think we need to investigate simplifying this entire methodology, or perhaps boosting - * it up into the Dialog class. - */ - private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { - String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY); - if (! PhoneWindowManager.SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) { - dismiss(); - } - } - } - }; -} diff --git a/policy/com/android/internal/policy/impl/ShortcutManager.java b/policy/com/android/internal/policy/impl/ShortcutManager.java deleted file mode 100644 index d86ac44cf87f..000000000000 --- a/policy/com/android/internal/policy/impl/ShortcutManager.java +++ /dev/null @@ -1,120 +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 android.content.Context; -import android.content.Intent; -import android.database.ContentObserver; -import android.database.Cursor; -import android.os.Handler; -import android.provider.Settings; -import android.util.Log; -import android.util.SparseArray; -import android.view.KeyCharacterMap; - -import java.net.URISyntaxException; - -/** - * Manages quick launch shortcuts by: - *
  • Keeping the local copy in sync with the database (this is an observer) - *
  • Returning a shortcut-matching intent to clients - */ -class ShortcutManager extends ContentObserver { - - private static final String TAG = "ShortcutManager"; - - private static final int COLUMN_SHORTCUT = 0; - private static final int COLUMN_INTENT = 1; - private static final String[] sProjection = new String[] { - Settings.Bookmarks.SHORTCUT, Settings.Bookmarks.INTENT - }; - - private Context mContext; - private Cursor mCursor; - /** Map of a shortcut to its intent. */ - private SparseArray mShortcutIntents; - - public ShortcutManager(Context context, Handler handler) { - super(handler); - - mContext = context; - mShortcutIntents = new SparseArray(); - } - - /** Observes the provider of shortcut+intents */ - public void observe() { - mCursor = mContext.getContentResolver().query( - Settings.Bookmarks.CONTENT_URI, sProjection, null, null, null); - mCursor.registerContentObserver(this); - updateShortcuts(); - } - - @Override - public void onChange(boolean selfChange) { - updateShortcuts(); - } - - private void updateShortcuts() { - Cursor c = mCursor; - if (!c.requery()) { - Log.e(TAG, "ShortcutObserver could not re-query shortcuts."); - return; - } - - mShortcutIntents.clear(); - while (c.moveToNext()) { - int shortcut = c.getInt(COLUMN_SHORTCUT); - if (shortcut == 0) continue; - String intentURI = c.getString(COLUMN_INTENT); - Intent intent = null; - try { - intent = Intent.getIntent(intentURI); - } catch (URISyntaxException e) { - Log.w(TAG, "Intent URI for shortcut invalid.", e); - } - if (intent == null) continue; - mShortcutIntents.put(shortcut, intent); - } - } - - /** - * Gets the shortcut intent for a given keycode+modifier. Make sure you - * strip whatever modifier is used for invoking shortcuts (for example, - * if 'Sym+A' should invoke a shortcut on 'A', you should strip the - * 'Sym' bit from the modifiers before calling this method. - *

    - * This will first try an exact match (with modifiers), and then try a - * match without modifiers (primary character on a key). - * - * @param keyCode The keycode of the key pushed. - * @param modifiers The modifiers without any that are used for chording - * to invoke a shortcut. - * @return The intent that matches the shortcut, or null if not found. - */ - public Intent getIntent(int keyCode, int modifiers) { - KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD); - // First try the exact keycode (with modifiers) - int shortcut = kcm.get(keyCode, modifiers); - Intent intent = shortcut != 0 ? mShortcutIntents.get(shortcut) : null; - if (intent != null) return intent; - - // Next try the keycode without modifiers (the primary character on that key) - shortcut = Character.toLowerCase(kcm.get(keyCode, 0)); - return shortcut != 0 ? mShortcutIntents.get(shortcut) : null; - } - -} diff --git a/policy/com/android/internal/policy/impl/ShutdownThread.java b/policy/com/android/internal/policy/impl/ShutdownThread.java deleted file mode 100644 index 994b1d50bdf9..000000000000 --- a/policy/com/android/internal/policy/impl/ShutdownThread.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2008 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 android.app.ProgressDialog; -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.RemoteException; -import android.os.Power; -import android.os.ServiceManager; -import android.os.SystemClock; -import com.android.internal.telephony.ITelephony; -import android.util.Log; -import android.view.WindowManager; - - -final class ShutdownThread extends Thread { - // constants - private static final String TAG = "ShutdownThread"; - private static final int MAX_NUM_PHONE_STATE_READS = 16; - private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500; - private static final ITelephony sPhone = - ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); - - // state tracking - private static Object sIsStartedGuard = new Object(); - private static boolean sIsStarted = false; - - // static instance of this thread - private static final ShutdownThread sInstance = new ShutdownThread(); - - private ShutdownThread() { - } - - /** - * request a shutdown. - * - * @param context Context used to display the shutdown progress dialog. - */ - public static void shutdownAfterDisablingRadio(final Context context, boolean confirm){ - // ensure that only one thread is trying to power down. - // any additional calls are just returned - synchronized (sIsStartedGuard){ - if (sIsStarted) { - Log.d(TAG, "Request to shutdown already running, returning."); - return; - } - } - - Log.d(TAG, "Notifying thread to start radio shutdown"); - - if (confirm) { - final AlertDialog dialog = new AlertDialog.Builder(context) - .setIcon(android.R.drawable.ic_dialog_alert) - .setTitle(com.android.internal.R.string.power_off) - .setMessage(com.android.internal.R.string.shutdown_confirm) - .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - beginShutdownSequence(context); - } - }) - .setNegativeButton(com.android.internal.R.string.no, null) - .create(); - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - dialog.show(); - } else { - beginShutdownSequence(context); - } - } - - private static void beginShutdownSequence(Context context) { - synchronized (sIsStartedGuard) { - sIsStarted = true; - } - - // throw up an indeterminate system dialog to indicate radio is - // shutting down. - ProgressDialog pd = new ProgressDialog(context); - pd.setTitle(context.getText(com.android.internal.R.string.power_off)); - pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress)); - pd.setIndeterminate(true); - pd.setCancelable(false); - pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - - pd.show(); - - // start the thread that initiates shutdown - sInstance.start(); - } - - /** - * Makes sure we handle the shutdown gracefully. - * Shuts off power regardless of radio state if the alloted time has passed. - */ - public void run() { - //shutdown the phone radio if possible. - if (sPhone != null) { - try { - //shutdown radio - sPhone.setRadio(false); - - for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++){ - // poll radio up to 64 times, with a 0.5 sec delay between each call, - // totaling 32 sec. - if (!sPhone.isRadioOn()) { - Log.d(TAG, "Radio shutdown complete."); - break; - } - SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC); - } - } catch (RemoteException ex) { - Log.e(TAG, "RemoteException caught from failed radio shutdown.", ex); - } - } - - //shutdown power - Log.d(TAG, "Shutting down power."); - Power.shutdown(); - } -} diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java deleted file mode 100644 index 9453212d4ad1..000000000000 --- a/policy/com/android/internal/policy/impl/SimUnlockScreen.java +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (C) 2008 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 android.app.Dialog; -import android.app.ProgressDialog; -import android.content.Context; -import android.os.RemoteException; -import android.os.ServiceManager; -import com.android.internal.telephony.ITelephony; -import android.text.Editable; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.WindowManager; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.TextView; -import com.android.internal.R; - -/** - * Displays a dialer like interface to unlock the SIM PIN. - */ -public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener, - KeyguardUpdateMonitor.ConfigurationChangeCallback { - - private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; - - private final KeyguardUpdateMonitor mUpdateMonitor; - private final KeyguardScreenCallback mCallback; - - private final boolean mCreatedWithKeyboardOpen; - - private TextView mHeaderText; - private EditText mPinText; - - private TextView mOkButton; - private TextView mEmergencyCallButton; - - private View mBackSpaceButton; - - private final int[] mEnteredPin = {0, 0, 0, 0, 0, 0, 0, 0}; - private int mEnteredDigits = 0; - - private ProgressDialog mSimUnlockProgressDialog = null; - - private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; - - public SimUnlockScreen(Context context, KeyguardUpdateMonitor updateMonitor, - KeyguardScreenCallback callback) { - super(context); - mUpdateMonitor = updateMonitor; - mCallback = callback; - mCreatedWithKeyboardOpen = mUpdateMonitor.isKeyboardOpen(); - - if (mCreatedWithKeyboardOpen) { - LayoutInflater.from(context).inflate(R.layout.keyguard_screen_sim_pin_landscape, this, true); - } else { - LayoutInflater.from(context).inflate(R.layout.keyguard_screen_sim_pin_portrait, this, true); - new TouchInput(); - } - - mHeaderText = (TextView) findViewById(R.id.headerText); - mPinText = (EditText) findViewById(R.id.pinDisplay); - mBackSpaceButton = findViewById(R.id.backspace); - mBackSpaceButton.setOnClickListener(this); - - mEmergencyCallButton = (TextView) findViewById(R.id.emergencyCall); - mOkButton = (TextView) findViewById(R.id.ok); - - mHeaderText.setText(R.string.keyguard_password_enter_pin_code); - mPinText.setFocusable(false); - - mEmergencyCallButton.setOnClickListener(this); - mOkButton.setOnClickListener(this); - - mUpdateMonitor.registerConfigurationChangeCallback(this); - setFocusableInTouchMode(true); - } - - /** {@inheritDoc} */ - public boolean needsInput() { - return true; - } - - /** {@inheritDoc} */ - public void onPause() { - - } - - /** {@inheritDoc} */ - public void onResume() { - // start fresh - mHeaderText.setText(R.string.keyguard_password_enter_pin_code); - - // make sure that the number of entered digits is consistent when we - // erase the SIM unlock code, including orientation changes. - mPinText.setText(""); - mEnteredDigits = 0; - } - - /** {@inheritDoc} */ - public void cleanUp() { - // hide the dialog. - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.hide(); - } - mUpdateMonitor.removeCallback(this); - } - - - /** - * Since the IPC can block, we want to run the request in a separate thread - * with a callback. - */ - private abstract class CheckSimPin extends Thread { - - private final String mPin; - - protected CheckSimPin(String pin) { - mPin = pin; - } - - abstract void onSimLockChangedResponse(boolean success); - - @Override - public void run() { - try { - final boolean result = ITelephony.Stub.asInterface(ServiceManager - .checkService("phone")).supplyPin(mPin); - post(new Runnable() { - public void run() { - onSimLockChangedResponse(result); - } - }); - } catch (RemoteException e) { - post(new Runnable() { - public void run() { - onSimLockChangedResponse(false); - } - }); - } - } - } - - public void onClick(View v) { - if (v == mBackSpaceButton) { - final Editable digits = mPinText.getText(); - final int len = digits.length(); - if (len > 0) { - digits.delete(len-1, len); - mEnteredDigits--; - } - mCallback.pokeWakelock(); - } else if (v == mEmergencyCallButton) { - mCallback.takeEmergencyCallAction(); - } else if (v == mOkButton) { - checkPin(); - } - } - - private Dialog getSimUnlockProgressDialog() { - if (mSimUnlockProgressDialog == null) { - mSimUnlockProgressDialog = new ProgressDialog(mContext); - mSimUnlockProgressDialog.setMessage( - mContext.getString(R.string.lockscreen_sim_unlock_progress_dialog_message)); - mSimUnlockProgressDialog.setIndeterminate(true); - mSimUnlockProgressDialog.setCancelable(false); - mSimUnlockProgressDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - mSimUnlockProgressDialog.getWindow().setFlags( - WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - } - return mSimUnlockProgressDialog; - } - - private void checkPin() { - - // make sure that the pin is at least 4 digits long. - if (mEnteredDigits < 4) { - // otherwise, display a message to the user, and don't submit. - mHeaderText.setText(R.string.invalidPin); - mPinText.setText(""); - mEnteredDigits = 0; - mCallback.pokeWakelock(); - return; - } - getSimUnlockProgressDialog().show(); - - new CheckSimPin(mPinText.getText().toString()) { - void onSimLockChangedResponse(boolean success) { - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.hide(); - } - if (success) { - // before closing the keyguard, report back that - // the sim is unlocked so it knows right away - mUpdateMonitor.reportSimPinUnlocked(); - mCallback.goToUnlockScreen(); - } else { - mHeaderText.setText(R.string.keyguard_password_wrong_pin_code); - mPinText.setText(""); - mEnteredDigits = 0; - mCallback.pokeWakelock(); - } - } - }.start(); - } - - - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - mCallback.goToLockScreen(); - return true; - } - - final char match = event.getMatch(DIGITS); - if (match != 0) { - reportDigit(match - '0'); - return true; - } - if (keyCode == KeyEvent.KEYCODE_DEL) { - if (mEnteredDigits > 0) { - mPinText.onKeyDown(keyCode, event); - mEnteredDigits--; - } - return true; - } - - if (keyCode == KeyEvent.KEYCODE_ENTER) { - checkPin(); - return true; - } - - return false; - } - - private void reportDigit(int digit) { - if (mEnteredDigits == 0) { - mPinText.setText(""); - } - if (mEnteredDigits == 8) { - return; - } - mPinText.append(Integer.toString(digit)); - mEnteredPin[mEnteredDigits++] = digit; - } - - public void onOrientationChange(boolean inPortrait) {} - - public void onKeyboardChange(boolean isKeyboardOpen) { - if (isKeyboardOpen != mCreatedWithKeyboardOpen) { - mCallback.recreateMe(); - } - } - - /** - * Helper class to handle input from touch dialer. Only relevant when - * the keyboard is shut. - */ - private class TouchInput implements View.OnClickListener { - private TextView mZero; - private TextView mOne; - private TextView mTwo; - private TextView mThree; - private TextView mFour; - private TextView mFive; - private TextView mSix; - private TextView mSeven; - private TextView mEight; - private TextView mNine; - private TextView mCancelButton; - - private TouchInput() { - mZero = (TextView) findViewById(R.id.zero); - mOne = (TextView) findViewById(R.id.one); - mTwo = (TextView) findViewById(R.id.two); - mThree = (TextView) findViewById(R.id.three); - mFour = (TextView) findViewById(R.id.four); - mFive = (TextView) findViewById(R.id.five); - mSix = (TextView) findViewById(R.id.six); - mSeven = (TextView) findViewById(R.id.seven); - mEight = (TextView) findViewById(R.id.eight); - mNine = (TextView) findViewById(R.id.nine); - mCancelButton = (TextView) findViewById(R.id.cancel); - - mZero.setText("0"); - mOne.setText("1"); - mTwo.setText("2"); - mThree.setText("3"); - mFour.setText("4"); - mFive.setText("5"); - mSix.setText("6"); - mSeven.setText("7"); - mEight.setText("8"); - mNine.setText("9"); - - mZero.setOnClickListener(this); - mOne.setOnClickListener(this); - mTwo.setOnClickListener(this); - mThree.setOnClickListener(this); - mFour.setOnClickListener(this); - mFive.setOnClickListener(this); - mSix.setOnClickListener(this); - mSeven.setOnClickListener(this); - mEight.setOnClickListener(this); - mNine.setOnClickListener(this); - mCancelButton.setOnClickListener(this); - } - - - public void onClick(View v) { - if (v == mCancelButton) { - mCallback.goToLockScreen(); - return; - } - - final int digit = checkDigit(v); - if (digit >= 0) { - mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS); - reportDigit(digit); - } - } - - private int checkDigit(View v) { - int digit = -1; - if (v == mZero) { - digit = 0; - } else if (v == mOne) { - digit = 1; - } else if (v == mTwo) { - digit = 2; - } else if (v == mThree) { - digit = 3; - } else if (v == mFour) { - digit = 4; - } else if (v == mFive) { - digit = 5; - } else if (v == mSix) { - digit = 6; - } else if (v == mSeven) { - digit = 7; - } else if (v == mEight) { - digit = 8; - } else if (v == mNine) { - digit = 9; - } - return digit; - } - } -} diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java deleted file mode 100644 index 51e3621f368a..000000000000 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (C) 2008 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 android.content.Context; -import android.content.ServiceConnection; -import android.os.CountDownTimer; -import android.os.SystemClock; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.MotionEvent; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.TextView; -import com.android.internal.R; -import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient; -import com.android.internal.widget.LockPatternUtils; -import com.android.internal.widget.LockPatternView; - -import java.util.List; - -/** - * This is the screen that shows the 9 circle unlock widget and instructs - * the user how to unlock their device, or make an emergency call. - */ -class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient - implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback { - - private static final String TAG = "UnlockScreen"; - - // how long before we clear the wrong pattern - private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000; - - // how long we stay awake once the user is ready to enter a pattern - private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000; - - private int mFailedPatternAttemptsSinceLastTimeout = 0; - private int mTotalFailedPatternAttempts = 0; - private CountDownTimer mCountdownTimer = null; - - private final LockPatternUtils mLockPatternUtils; - private final KeyguardUpdateMonitor mUpdateMonitor; - private final KeyguardScreenCallback mCallback; - - private boolean mCreatedInPortrait; - - private ImageView mUnlockIcon; - private TextView mUnlockHeader; - private LockPatternView mLockPatternView; - - private ViewGroup mFooterNormal; - private ViewGroup mFooterForgotPattern; - - /** - * Keeps track of the last time we poked the wake lock during dispatching - * of the touch event, initalized to something gauranteed to make us - * poke it when the user starts drawing the pattern. - * @see #dispatchTouchEvent(android.view.MotionEvent) - */ - private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS; - - /** - * Useful for clearing out the wrong pattern after a delay - */ - private Runnable mCancelPatternRunnable = new Runnable() { - public void run() { - mLockPatternView.clearPattern(); - } - }; - - private Button mForgotPatternButton; - - private ServiceConnection mServiceConnection; - - - enum FooterMode { - Normal, - ForgotLockPattern, - VerifyUnlocked - } - - private void updateFooter(FooterMode mode) { - switch (mode) { - case Normal: - mFooterNormal.setVisibility(View.VISIBLE); - mFooterForgotPattern.setVisibility(View.GONE); - break; - case ForgotLockPattern: - mFooterNormal.setVisibility(View.GONE); - mFooterForgotPattern.setVisibility(View.VISIBLE); - break; - case VerifyUnlocked: - mFooterNormal.setVisibility(View.GONE); - mFooterForgotPattern.setVisibility(View.GONE); - } - } - - /** - * @param context The context. - * @param lockPatternUtils Used to lookup lock pattern settings. - * @param updateMonitor Used to lookup state affecting keyguard. - * @param callback Used to notify the manager when we're done, etc. - * @param totalFailedAttempts The current number of failed attempts. - */ - UnlockScreen(Context context, - LockPatternUtils lockPatternUtils, - KeyguardUpdateMonitor updateMonitor, - KeyguardScreenCallback callback, - int totalFailedAttempts) { - super(context); - mLockPatternUtils = lockPatternUtils; - mUpdateMonitor = updateMonitor; - mCallback = callback; - mTotalFailedPatternAttempts = totalFailedAttempts; - mFailedPatternAttemptsSinceLastTimeout = totalFailedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; - - if (mUpdateMonitor.isInPortrait()) { - LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_portrait, this, true); - } else { - LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_landscape, this, true); - } - - mUnlockIcon = (ImageView) findViewById(R.id.unlockLockIcon); - - mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern); - mUnlockHeader = (TextView) findViewById(R.id.headerText); - - mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); - - mFooterNormal = (ViewGroup) findViewById(R.id.footerNormal); - mFooterForgotPattern = (ViewGroup) findViewById(R.id.footerForgotPattern); - - // emergency call buttons - final OnClickListener emergencyClick = new OnClickListener() { - public void onClick(View v) { - mCallback.takeEmergencyCallAction(); - } - }; - Button emergencyAlone = (Button) findViewById(R.id.emergencyCallAlone); - emergencyAlone.setFocusable(false); // touch only! - emergencyAlone.setOnClickListener(emergencyClick); - Button emergencyTogether = (Button) findViewById(R.id.emergencyCallTogether); - emergencyTogether.setFocusable(false); - emergencyTogether.setOnClickListener(emergencyClick); - - mForgotPatternButton = (Button) findViewById(R.id.forgotPattern); - mForgotPatternButton.setText(R.string.lockscreen_forgot_pattern_button_text); - mForgotPatternButton.setOnClickListener(new OnClickListener() { - - public void onClick(View v) { - mLockPatternUtils.setPermanentlyLocked(true); - mCallback.goToUnlockScreen(); - } - }); - - // make it so unhandled touch events within the unlock screen go to the - // lock pattern view. - setDefaultTouchRecepient(mLockPatternView); - - mLockPatternView.setSaveEnabled(false); - mLockPatternView.setFocusable(false); - mLockPatternView.setOnPatternListener(new UnlockPatternListener()); - - // stealth mode will be the same for the life of this screen - mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled()); - - // vibrate mode will be the same for the life of this screen - mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled()); - - // assume normal footer mode for now - updateFooter(FooterMode.Normal); - - mCreatedInPortrait = updateMonitor.isInPortrait(); - updateMonitor.registerConfigurationChangeCallback(this); - setFocusableInTouchMode(true); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - mCallback.goToLockScreen(); - return true; - } - return false; - } - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - // as long as the user is entering a pattern (i.e sending a touch - // event that was handled by this screen), keep poking the - // wake lock so that the screen will stay on. - final boolean result = super.dispatchTouchEvent(ev); - if (result && - ((SystemClock.elapsedRealtime() - mLastPokeTime) - > (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) { - mLastPokeTime = SystemClock.elapsedRealtime(); - mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); - } - return result; - } - - /** {@inheritDoc} */ - public void onOrientationChange(boolean inPortrait) { - if (inPortrait != mCreatedInPortrait) { - mCallback.recreateMe(); - } - } - - /** {@inheritDoc} */ - public void onKeyboardChange(boolean isKeyboardOpen) {} - - /** {@inheritDoc} */ - public boolean needsInput() { - return false; - } - - /** {@inheritDoc} */ - public void onPause() { - if (mCountdownTimer != null) { - mCountdownTimer.cancel(); - mCountdownTimer = null; - } - } - - /** {@inheritDoc} */ - public void onResume() { - // reset header - mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); - mUnlockIcon.setVisibility(View.VISIBLE); - - // reset lock pattern - mLockPatternView.enableInput(); - mLockPatternView.setEnabled(true); - mLockPatternView.clearPattern(); - - // show "forgot pattern?" button if we have an alternate authentication method - mForgotPatternButton.setVisibility(mCallback.doesFallbackUnlockScreenExist() - ? View.VISIBLE : View.INVISIBLE); - - // if the user is currently locked out, enforce it. - long deadline = mLockPatternUtils.getLockoutAttemptDeadline(); - if (deadline != 0) { - handleAttemptLockout(deadline); - } - - // the footer depends on how many total attempts the user has failed - if (mCallback.isVerifyUnlockOnly()) { - updateFooter(FooterMode.VerifyUnlocked); - } else if (mTotalFailedPatternAttempts < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { - updateFooter(FooterMode.Normal); - } else { - updateFooter(FooterMode.ForgotLockPattern); - } - } - - /** {@inheritDoc} */ - public void cleanUp() { - mUpdateMonitor.removeCallback(this); - } - - private class UnlockPatternListener - implements LockPatternView.OnPatternListener { - - public void onPatternStart() { - mLockPatternView.removeCallbacks(mCancelPatternRunnable); - } - - public void onPatternCleared() { - } - - public void onPatternDetected(List pattern) { - if (mLockPatternUtils.checkPattern(pattern)) { - mLockPatternView - .setDisplayMode(LockPatternView.DisplayMode.Correct); - mUnlockIcon.setVisibility(View.GONE); - mUnlockHeader.setText(R.string.lockscreen_pattern_correct); - mCallback.keyguardDone(true); - } else { - mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); - mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong); - if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { - mTotalFailedPatternAttempts++; - mFailedPatternAttemptsSinceLastTimeout++; - mCallback.reportFailedPatternAttempt(); - } - if (mFailedPatternAttemptsSinceLastTimeout >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { - long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); - handleAttemptLockout(deadline); - return; - } - mUnlockIcon.setVisibility(View.VISIBLE); - mUnlockHeader.setText(R.string.lockscreen_pattern_wrong); - mLockPatternView.postDelayed( - mCancelPatternRunnable, - PATTERN_CLEAR_TIMEOUT_MS); - } - } - } - - private void handleAttemptLockout(long elapsedRealtimeDeadline) { - mLockPatternView.clearPattern(); - mLockPatternView.setEnabled(false); - long elapsedRealtime = SystemClock.elapsedRealtime(); - mCountdownTimer = new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) { - - @Override - public void onTick(long millisUntilFinished) { - int secondsRemaining = (int) (millisUntilFinished / 1000); - mUnlockHeader.setText(getContext().getString( - R.string.lockscreen_too_many_failed_attempts_countdown, - secondsRemaining)); - } - - @Override - public void onFinish() { - mLockPatternView.setEnabled(true); - mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); - mUnlockIcon.setVisibility(View.VISIBLE); - mFailedPatternAttemptsSinceLastTimeout = 0; - updateFooter(FooterMode.ForgotLockPattern); - } - }.start(); - } - -} diff --git a/policy/com/android/internal/policy/impl/package.html b/policy/com/android/internal/policy/impl/package.html deleted file mode 100644 index c9f96a66ab3b..000000000000 --- a/policy/com/android/internal/policy/impl/package.html +++ /dev/null @@ -1,5 +0,0 @@ - - -{@hide} - - -- GitLab From 1f838aaece3cd61d07ab9e41c5c6af761d643324 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 19:32:13 -0800 Subject: [PATCH 015/458] auto import from //depot/cupcake/@135843 --- policy/Android.mk | 13 + .../policy/impl/AccountUnlockScreen.java | 278 ++ .../internal/policy/impl/GlobalActions.java | 514 ++++ .../internal/policy/impl/KeyguardScreen.java | 45 + .../policy/impl/KeyguardScreenCallback.java | 66 + .../policy/impl/KeyguardUpdateMonitor.java | 552 ++++ .../policy/impl/KeyguardViewBase.java | 188 ++ .../policy/impl/KeyguardViewCallback.java | 49 + .../policy/impl/KeyguardViewManager.java | 226 ++ .../policy/impl/KeyguardViewMediator.java | 915 ++++++ .../policy/impl/KeyguardViewProperties.java | 46 + .../policy/impl/KeyguardWindowController.java | 29 + .../policy/impl/LockPatternKeyguardView.java | 639 ++++ .../LockPatternKeyguardViewProperties.java | 67 + .../internal/policy/impl/LockScreen.java | 371 +++ .../policy/impl/PhoneLayoutInflater.java | 73 + .../internal/policy/impl/PhoneWindow.java | 2688 +++++++++++++++++ .../policy/impl/PhoneWindowManager.java | 1800 +++++++++++ .../android/internal/policy/impl/Policy.java | 69 + .../internal/policy/impl/PowerDialog.java | 179 ++ .../policy/impl/RecentApplicationsDialog.java | 255 ++ .../internal/policy/impl/ShortcutManager.java | 120 + .../internal/policy/impl/ShutdownThread.java | 138 + .../internal/policy/impl/SimUnlockScreen.java | 366 +++ .../internal/policy/impl/UnlockScreen.java | 341 +++ .../android/internal/policy/impl/package.html | 5 + 26 files changed, 10032 insertions(+) create mode 100644 policy/Android.mk create mode 100644 policy/com/android/internal/policy/impl/AccountUnlockScreen.java create mode 100644 policy/com/android/internal/policy/impl/GlobalActions.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardScreen.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardScreenCallback.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardViewBase.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardViewCallback.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardViewManager.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardViewMediator.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardViewProperties.java create mode 100644 policy/com/android/internal/policy/impl/KeyguardWindowController.java create mode 100644 policy/com/android/internal/policy/impl/LockPatternKeyguardView.java create mode 100644 policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java create mode 100644 policy/com/android/internal/policy/impl/LockScreen.java create mode 100644 policy/com/android/internal/policy/impl/PhoneLayoutInflater.java create mode 100644 policy/com/android/internal/policy/impl/PhoneWindow.java create mode 100644 policy/com/android/internal/policy/impl/PhoneWindowManager.java create mode 100644 policy/com/android/internal/policy/impl/Policy.java create mode 100644 policy/com/android/internal/policy/impl/PowerDialog.java create mode 100644 policy/com/android/internal/policy/impl/RecentApplicationsDialog.java create mode 100644 policy/com/android/internal/policy/impl/ShortcutManager.java create mode 100644 policy/com/android/internal/policy/impl/ShutdownThread.java create mode 100644 policy/com/android/internal/policy/impl/SimUnlockScreen.java create mode 100644 policy/com/android/internal/policy/impl/UnlockScreen.java create mode 100644 policy/com/android/internal/policy/impl/package.html diff --git a/policy/Android.mk b/policy/Android.mk new file mode 100644 index 000000000000..29f62b872306 --- /dev/null +++ b/policy/Android.mk @@ -0,0 +1,13 @@ +LOCAL_PATH:= $(call my-dir) + +# the library +# ============================================================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + $(call all-subdir-java-files) + +LOCAL_MODULE := android.policy_phone +LOCAL_UNINSTALLABLE_MODULE := true + +include $(BUILD_JAVA_LIBRARY) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java new file mode 100644 index 000000000000..65102c67fc8b --- /dev/null +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2008 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 com.android.internal.widget.LockPatternUtils; + +import android.accounts.AccountsServiceConstants; +import android.accounts.IAccountsService; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.graphics.Rect; +import android.os.IBinder; +import android.os.RemoteException; +import android.text.Editable; +import android.text.InputFilter; +import android.text.LoginFilter; +import android.text.TextWatcher; +import android.text.TextUtils; +import android.util.Log; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.RelativeLayout; +import android.widget.TextView; + +/** + * When the user forgets their password a bunch of times, we fall back on their + * account's login/password to unlock the phone (and reset their lock pattern). + * + *

    This class is useful only on platforms that support the + * IAccountsService. + */ +public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen, + View.OnClickListener, ServiceConnection, TextWatcher { + private static final String LOCK_PATTERN_PACKAGE = "com.android.settings"; + private static final String LOCK_PATTERN_CLASS = + "com.android.settings.ChooseLockPattern"; + + /** + * The amount of millis to stay awake once this screen detects activity + */ + private static final int AWAKE_POKE_MILLIS = 30000; + + private final KeyguardScreenCallback mCallback; + private final LockPatternUtils mLockPatternUtils; + private IAccountsService mAccountsService; + + private TextView mTopHeader; + private TextView mInstructions; + private EditText mLogin; + private EditText mPassword; + private Button mOk; + private Button mEmergencyCall; + + /** + * AccountUnlockScreen constructor. + * + * @throws IllegalStateException if the IAccountsService is not + * available on the current platform. + */ + public AccountUnlockScreen(Context context, + KeyguardScreenCallback callback, + LockPatternUtils lockPatternUtils) { + super(context); + mCallback = callback; + mLockPatternUtils = lockPatternUtils; + + LayoutInflater.from(context).inflate( + R.layout.keyguard_screen_glogin_unlock, this, true); + + mTopHeader = (TextView) findViewById(R.id.topHeader); + + mInstructions = (TextView) findViewById(R.id.instructions); + + mLogin = (EditText) findViewById(R.id.login); + mLogin.setFilters(new InputFilter[] { new LoginFilter.UsernameFilterGeneric() } ); + mLogin.addTextChangedListener(this); + + mPassword = (EditText) findViewById(R.id.password); + mPassword.addTextChangedListener(this); + + mOk = (Button) findViewById(R.id.ok); + mOk.setOnClickListener(this); + + mEmergencyCall = (Button) findViewById(R.id.emergencyCall); + mEmergencyCall.setOnClickListener(this); + + Log.v("AccountUnlockScreen", "debug: Connecting to accounts service"); + final boolean connected = mContext.bindService(AccountsServiceConstants.SERVICE_INTENT, + this, Context.BIND_AUTO_CREATE); + if (!connected) { + Log.v("AccountUnlockScreen", "debug: Couldn't connect to accounts service"); + throw new IllegalStateException("couldn't bind to accounts service"); + } + } + + public void afterTextChanged(Editable s) { + } + + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + public void onTextChanged(CharSequence s, int start, int before, int count) { + mCallback.pokeWakelock(AWAKE_POKE_MILLIS); + } + + @Override + protected boolean onRequestFocusInDescendants(int direction, + Rect previouslyFocusedRect) { + // send focus to the login field + return mLogin.requestFocus(direction, previouslyFocusedRect); + } + + /** {@inheritDoc} */ + public boolean needsInput() { + return true; + } + + /** {@inheritDoc} */ + public void onPause() { + + } + + /** {@inheritDoc} */ + public void onResume() { + // start fresh + mLogin.setText(""); + mPassword.setText(""); + mLogin.requestFocus(); + } + + /** {@inheritDoc} */ + public void cleanUp() { + mContext.unbindService(this); + } + + /** {@inheritDoc} */ + public void onClick(View v) { + mCallback.pokeWakelock(); + if (v == mOk) { + if (checkPassword()) { + // clear out forgotten password + mLockPatternUtils.setPermanentlyLocked(false); + + // launch the 'choose lock pattern' activity so + // the user can pick a new one if they want to + Intent intent = new Intent(); + intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + + // close the keyguard + mCallback.keyguardDone(true); + } else { + mInstructions.setText(R.string.lockscreen_glogin_invalid_input); + mPassword.setText(""); + } + } + + if (v == mEmergencyCall) { + mCallback.takeEmergencyCallAction(); + } + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_DOWN + && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { + mCallback.goToLockScreen(); + return true; + } + return super.dispatchKeyEvent(event); + } + + /** + * Given the string the user entered in the 'username' field, find + * the stored account that they probably intended. Prefer, in order: + * + * - an exact match for what was typed, or + * - a case-insensitive match for what was typed, or + * - if they didn't include a domain, an exact match of the username, or + * - if they didn't include a domain, a case-insensitive + * match of the username. + * + * If there is a tie for the best match, choose neither -- + * the user needs to be more specific. + * + * @return an account name from the database, or null if we can't + * find a single best match. + */ + private String findIntendedAccount(String username) { + String[] accounts = null; + try { + accounts = mAccountsService.getAccounts(); + } catch (RemoteException e) { + return null; + } + if (accounts == null) { + return null; + } + + // Try to figure out which account they meant if they + // typed only the username (and not the domain), or got + // the case wrong. + + String bestAccount = null; + int bestScore = 0; + for (String a: accounts) { + int score = 0; + if (username.equals(a)) { + score = 4; + } else if (username.equalsIgnoreCase(a)) { + score = 3; + } else if (username.indexOf('@') < 0) { + int i = a.indexOf('@'); + if (i >= 0) { + String aUsername = a.substring(0, i); + if (username.equals(aUsername)) { + score = 2; + } else if (username.equalsIgnoreCase(aUsername)) { + score = 1; + } + } + } + if (score > bestScore) { + bestAccount = a; + bestScore = score; + } else if (score == bestScore) { + bestAccount = null; + } + } + return bestAccount; + } + + private boolean checkPassword() { + final String login = mLogin.getText().toString(); + final String password = mPassword.getText().toString(); + try { + String account = findIntendedAccount(login); + if (account == null) { + return false; + } + return mAccountsService.shouldUnlock(account, password); + } catch (RemoteException e) { + return false; + } + } + + /** {@inheritDoc} */ + public void onServiceConnected(ComponentName name, IBinder service) { + Log.v("AccountUnlockScreen", "debug: About to grab as interface"); + mAccountsService = IAccountsService.Stub.asInterface(service); + } + + /** {@inheritDoc} */ + public void onServiceDisconnected(ComponentName name) { + mAccountsService = null; + } +} diff --git a/policy/com/android/internal/policy/impl/GlobalActions.java b/policy/com/android/internal/policy/impl/GlobalActions.java new file mode 100644 index 000000000000..eeb875a2f4be --- /dev/null +++ b/policy/com/android/internal/policy/impl/GlobalActions.java @@ -0,0 +1,514 @@ +/* + * Copyright (C) 2008 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 android.app.AlertDialog; +import android.app.StatusBarManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.AudioManager; +import android.os.Handler; +import android.os.Message; +import android.provider.Settings; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; +import com.android.internal.R; +import com.google.android.collect.Lists; + +import java.util.ArrayList; + +/** + * Helper to show the global actions dialog. Each item is an {@link Action} that + * may show depending on whether the keyguard is showing, and whether the device + * is provisioned. + */ +class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener { + + private static final String TAG = "GlobalActions"; + + private StatusBarManager mStatusBar; + + private final Context mContext; + private final AudioManager mAudioManager; + + private ArrayList mItems; + private AlertDialog mDialog; + + private ToggleAction mSilentModeToggle; + private ToggleAction mAirplaneModeOn; + + private MyAdapter mAdapter; + + private boolean mKeyguardShowing = false; + private boolean mDeviceProvisioned = false; + private ToggleAction.State mAirplaneState = ToggleAction.State.Off; + + /** + * @param context everything needs a context :( + */ + public GlobalActions(Context context) { + mContext = context; + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + + // receive broadcasts + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + context.registerReceiver(mBroadcastReceiver, filter); + + // get notified of phone state changes + TelephonyManager telephonyManager = + (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE); + } + + /** + * Show the global actions dialog (creating if necessary) + * @param keyguardShowing True if keyguard is showing + */ + public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) { + mKeyguardShowing = keyguardShowing; + mDeviceProvisioned = isDeviceProvisioned; + if (mDialog == null) { + mStatusBar = (StatusBarManager)mContext.getSystemService(Context.STATUS_BAR_SERVICE); + mDialog = createDialog(); + } + prepareDialog(); + + mStatusBar.disable(StatusBarManager.DISABLE_EXPAND); + mDialog.show(); + } + + /** + * Create the global actions dialog. + * @return A new dialog. + */ + private AlertDialog createDialog() { + + mSilentModeToggle = new ToggleAction( + R.drawable.ic_lock_silent_mode, + R.drawable.ic_lock_silent_mode_off, + R.string.global_action_toggle_silent_mode, + R.string.global_action_silent_mode_on_status, + R.string.global_action_silent_mode_off_status) { + + void onToggle(boolean on) { + mAudioManager.setRingerMode(on ? AudioManager.RINGER_MODE_SILENT + : AudioManager.RINGER_MODE_NORMAL); + } + + public boolean showDuringKeyguard() { + return true; + } + + public boolean showBeforeProvisioning() { + return false; + } + }; + + mAirplaneModeOn = new ToggleAction( + R.drawable.ic_lock_airplane_mode, + R.drawable.ic_lock_airplane_mode_off, + R.string.global_actions_toggle_airplane_mode, + R.string.global_actions_airplane_mode_on_status, + R.string.global_actions_airplane_mode_off_status) { + + void onToggle(boolean on) { + // Change the system setting + Settings.System.putInt( + mContext.getContentResolver(), + Settings.System.AIRPLANE_MODE_ON, + on ? 1 : 0); + Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.putExtra("state", on); + mContext.sendBroadcast(intent); + } + + @Override + protected void changeStateFromPress(boolean buttonOn) { + mState = buttonOn ? State.TurningOn : State.TurningOff; + mAirplaneState = mState; + } + + public boolean showDuringKeyguard() { + return true; + } + + public boolean showBeforeProvisioning() { + return false; + } + }; + + mItems = Lists.newArrayList( + // silent mode + mSilentModeToggle, + // next: airplane mode + mAirplaneModeOn, + // last: power off + new SinglePressAction( + com.android.internal.R.drawable.ic_lock_power_off, + R.string.global_action_power_off) { + + public void onPress() { + // shutdown by making sure radio and power are handled accordingly. + ShutdownThread.shutdownAfterDisablingRadio(mContext, true); + } + + public boolean showDuringKeyguard() { + return true; + } + + public boolean showBeforeProvisioning() { + return true; + } + }); + + mAdapter = new MyAdapter(); + + final AlertDialog.Builder ab = new AlertDialog.Builder(mContext); + + ab.setAdapter(mAdapter, this) + .setInverseBackgroundForced(true) + .setTitle(R.string.global_actions); + + final AlertDialog dialog = ab.create(); + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); + dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + + dialog.setOnDismissListener(this); + + return dialog; + } + + private void prepareDialog() { + final boolean silentModeOn = + mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; + mSilentModeToggle.updateState( + silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off); + mAirplaneModeOn.updateState(mAirplaneState); + mAdapter.notifyDataSetChanged(); + if (mKeyguardShowing) { + mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + } else { + mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); + } + } + + + /** {@inheritDoc} */ + public void onDismiss(DialogInterface dialog) { + mStatusBar.disable(StatusBarManager.DISABLE_NONE); + } + + /** {@inheritDoc} */ + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + mAdapter.getItem(which).onPress(); + } + + + /** + * The adapter used for the list within the global actions dialog, taking + * into account whether the keyguard is showing via + * {@link GlobalActions#mKeyguardShowing} and whether the device is provisioned + * via {@link GlobalActions#mDeviceProvisioned}. + */ + private class MyAdapter extends BaseAdapter { + + public int getCount() { + int count = 0; + + for (int i = 0; i < mItems.size(); i++) { + final Action action = mItems.get(i); + + if (mKeyguardShowing && !action.showDuringKeyguard()) { + continue; + } + if (!mDeviceProvisioned && !action.showBeforeProvisioning()) { + continue; + } + count++; + } + return count; + } + + @Override + public boolean isEnabled(int position) { + return getItem(position).isEnabled(); + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + + public Action getItem(int position) { + + int filteredPos = 0; + for (int i = 0; i < mItems.size(); i++) { + final Action action = mItems.get(i); + if (mKeyguardShowing && !action.showDuringKeyguard()) { + continue; + } + if (!mDeviceProvisioned && !action.showBeforeProvisioning()) { + continue; + } + if (filteredPos == position) { + return action; + } + filteredPos++; + } + + throw new IllegalArgumentException("position " + position + " out of " + + "range of showable actions, filtered count = " + + "= " + getCount() + ", keyguardshowing=" + mKeyguardShowing + + ", provisioned=" + mDeviceProvisioned); + } + + + public long getItemId(int position) { + return position; + } + + public View getView(int position, View convertView, ViewGroup parent) { + Action action = getItem(position); + return action.create(mContext, convertView, parent, LayoutInflater.from(mContext)); + } + } + + // note: the scheme below made more sense when we were planning on having + // 8 different things in the global actions dialog. seems overkill with + // only 3 items now, but may as well keep this flexible approach so it will + // be easy should someone decide at the last minute to include something + // else, such as 'enable wifi', or 'enable bluetooth' + + /** + * What each item in the global actions dialog must be able to support. + */ + private interface Action { + View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater); + + void onPress(); + + /** + * @return whether this action should appear in the dialog when the keygaurd + * is showing. + */ + boolean showDuringKeyguard(); + + /** + * @return whether this action should appear in the dialog before the + * device is provisioned. + */ + boolean showBeforeProvisioning(); + + boolean isEnabled(); + } + + /** + * A single press action maintains no state, just responds to a press + * and takes an action. + */ + private static abstract class SinglePressAction implements Action { + private final int mIconResId; + private final int mMessageResId; + + protected SinglePressAction(int iconResId, int messageResId) { + mIconResId = iconResId; + mMessageResId = messageResId; + } + + public boolean isEnabled() { + return true; + } + + abstract public void onPress(); + + public View create( + Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { + View v = (convertView != null) ? + convertView : + inflater.inflate(R.layout.global_actions_item, parent, false); + + ImageView icon = (ImageView) v.findViewById(R.id.icon); + TextView messageView = (TextView) v.findViewById(R.id.message); + + v.findViewById(R.id.status).setVisibility(View.GONE); + + icon.setImageDrawable(context.getResources().getDrawable(mIconResId)); + messageView.setText(mMessageResId); + + return v; + } + } + + /** + * A toggle action knows whether it is on or off, and displays an icon + * and status message accordingly. + */ + private static abstract class ToggleAction implements Action { + + enum State { + Off(false), + TurningOn(true), + TurningOff(true), + On(false); + + private final boolean inTransition; + + State(boolean intermediate) { + inTransition = intermediate; + } + + public boolean inTransition() { + return inTransition; + } + } + + protected State mState = State.Off; + + // prefs + private final int mEnabledIconResId; + private final int mDisabledIconResid; + private final int mMessageResId; + private final int mEnabledStatusMessageResId; + private final int mDisabledStatusMessageResId; + + /** + * @param enabledIconResId The icon for when this action is on. + * @param disabledIconResid The icon for when this action is off. + * @param essage The general information message, e.g 'Silent Mode' + * @param enabledStatusMessageResId The on status message, e.g 'sound disabled' + * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled' + */ + public ToggleAction(int enabledIconResId, + int disabledIconResid, + int essage, + int enabledStatusMessageResId, + int disabledStatusMessageResId) { + mEnabledIconResId = enabledIconResId; + mDisabledIconResid = disabledIconResid; + mMessageResId = essage; + mEnabledStatusMessageResId = enabledStatusMessageResId; + mDisabledStatusMessageResId = disabledStatusMessageResId; + } + + public View create(Context context, View convertView, ViewGroup parent, + LayoutInflater inflater) { + View v = (convertView != null) ? + convertView : + inflater.inflate(R + .layout.global_actions_item, parent, false); + + ImageView icon = (ImageView) v.findViewById(R.id.icon); + TextView messageView = (TextView) v.findViewById(R.id.message); + TextView statusView = (TextView) v.findViewById(R.id.status); + + messageView.setText(mMessageResId); + + boolean on = ((mState == State.On) || (mState == State.TurningOn)); + icon.setImageDrawable(context.getResources().getDrawable( + (on ? mEnabledIconResId : mDisabledIconResid))); + statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); + statusView.setVisibility(View.VISIBLE); + + final boolean enabled = isEnabled(); + messageView.setEnabled(enabled); + statusView.setEnabled(enabled); + icon.setEnabled(enabled); + v.setEnabled(enabled); + + return v; + } + + public final void onPress() { + if (mState.inTransition()) { + Log.w(TAG, "shouldn't be able to toggle when in transition"); + return; + } + + final boolean nowOn = !(mState == State.On); + onToggle(nowOn); + changeStateFromPress(nowOn); + } + + public boolean isEnabled() { + return !mState.inTransition(); + } + + /** + * Implementations may override this if their state can be in on of the intermediate + * states until some notification is received (e.g airplane mode is 'turning off' until + * we know the wireless connections are back online + * @param buttonOn Whether the button was turned on or off + */ + protected void changeStateFromPress(boolean buttonOn) { + mState = buttonOn ? State.On : State.Off; + } + + abstract void onToggle(boolean on); + + public void updateState(State state) { + mState = state; + } + } + + private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { + String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY); + if (! PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) { + mHandler.sendEmptyMessage(MESSAGE_DISMISS); + } + } + } + }; + + PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + @Override + public void onServiceStateChanged(ServiceState serviceState) { + final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF; + mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off; + mAirplaneModeOn.updateState(mAirplaneState); + mAdapter.notifyDataSetChanged(); + } + }; + + private static final int MESSAGE_DISMISS = 0; + private Handler mHandler = new Handler() { + public void handleMessage(Message msg) { + if (msg.what == MESSAGE_DISMISS) { + if (mDialog != null) { + mDialog.dismiss(); + } + } + } + }; +} diff --git a/policy/com/android/internal/policy/impl/KeyguardScreen.java b/policy/com/android/internal/policy/impl/KeyguardScreen.java new file mode 100644 index 000000000000..bbb687554e73 --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardScreen.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008 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; + +/** + * Common interface of each {@link android.view.View} that is a screen of + * {@link LockPatternKeyguardView}. + */ +public interface KeyguardScreen { + + /** + * Return true if your view needs input, so should allow the soft + * keyboard to be displayed. + */ + boolean needsInput(); + + /** + * This screen is no longer in front of the user. + */ + void onPause(); + + /** + * This screen is going to be in front of the user. + */ + void onResume(); + + /** + * This view is going away; a hook to do cleanup. + */ + void cleanUp(); +} diff --git a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java new file mode 100644 index 000000000000..b46b37d04db0 --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008 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; + +/** + * Within a keyguard, there may be several screens that need a callback + * to the host keyguard view. + */ +public interface KeyguardScreenCallback extends KeyguardViewCallback { + + /** + * Transition to the lock screen. + */ + void goToLockScreen(); + + /** + * Transitino to th unlock screen. + */ + void goToUnlockScreen(); + + /** + * @return Whether the keyguard requires some sort of PIN. + */ + boolean isSecure(); + + /** + * @return Whether we are in a mode where we only want to verify the + * user can get past the keyguard. + */ + boolean isVerifyUnlockOnly(); + + /** + * Stay on me, but recreate me (so I can use a different layout). + */ + void recreateMe(); + + /** + * Take action to send an emergency call. + */ + void takeEmergencyCallAction(); + + /** + * Report that the user had a failed attempt unlocking via the pattern. + */ + void reportFailedPatternAttempt(); + + /** + * Report whether we there's another way to unlock the device. + * @return true + */ + boolean doesFallbackUnlockScreenExist(); +} diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java new file mode 100644 index 000000000000..3a25d38d9ef6 --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -0,0 +1,552 @@ +/* + * Copyright (C) 2008 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 android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Configuration; +import android.database.ContentObserver; +import static android.os.BatteryManager.BATTERY_STATUS_CHARGING; +import static android.os.BatteryManager.BATTERY_STATUS_FULL; +import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; +import android.os.Handler; +import android.os.Message; +import android.provider.Settings; +import android.provider.Telephony; +import static android.provider.Telephony.Intents.EXTRA_PLMN; +import static android.provider.Telephony.Intents.EXTRA_SHOW_PLMN; +import static android.provider.Telephony.Intents.EXTRA_SHOW_SPN; +import static android.provider.Telephony.Intents.EXTRA_SPN; +import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION; +import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.TelephonyIntents; +import android.util.Log; +import com.android.internal.R; +import com.google.android.collect.Lists; + +import java.util.ArrayList; + +/** + * Watches for updates that may be interesting to the keyguard, and provides + * the up to date information as well as a registration for callbacks that care + * to be updated. + * + * Note: under time crunch, this has been extended to include some stuff that + * doesn't really belong here. see {@link #handleBatteryUpdate} where it shutdowns + * the device, and {@link #getFailedAttempts()}, {@link #reportFailedAttempt()} + * and {@link #clearFailedAttempts()}. Maybe we should rename this 'KeyguardContext'... + */ +public class KeyguardUpdateMonitor { + + static private final String TAG = "KeyguardUpdateMonitor"; + static private final boolean DEBUG = false; + + private static final int LOW_BATTERY_THRESHOLD = 20; + + private final Context mContext; + + private SimCard.State mSimState = SimCard.State.READY; + private boolean mInPortrait; + private boolean mKeyboardOpen; + + private boolean mDevicePluggedIn; + + private boolean mDeviceProvisioned; + + private int mBatteryLevel; + + private CharSequence mTelephonyPlmn; + private CharSequence mTelephonySpn; + + private int mFailedAttempts = 0; + + private Handler mHandler; + + private ArrayList mConfigurationChangeCallbacks + = Lists.newArrayList(); + private ArrayList mInfoCallbacks = Lists.newArrayList(); + private ArrayList mSimStateCallbacks = Lists.newArrayList(); + private ContentObserver mContentObserver; + + + // messages for the handler + private static final int MSG_CONFIGURATION_CHANGED = 300; + private static final int MSG_TIME_UPDATE = 301; + private static final int MSG_BATTERY_UPDATE = 302; + private static final int MSG_CARRIER_INFO_UPDATE = 303; + private static final int MSG_SIM_STATE_CHANGE = 304; + + + /** + * When we receive a {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, and + * then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange}, + * we need a single object to pass to the handler. This class helps decode + * the intent and provide a {@link SimCard.State} result. + */ + private static class SimArgs { + + public final SimCard.State simState; + + private SimArgs(Intent intent) { + if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) { + throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED"); + } + String stateExtra = intent.getStringExtra(SimCard.INTENT_KEY_SIM_STATE); + if (SimCard.INTENT_VALUE_SIM_ABSENT.equals(stateExtra)) { + this.simState = SimCard.State.ABSENT; + } else if (SimCard.INTENT_VALUE_SIM_READY.equals(stateExtra)) { + this.simState = SimCard.State.READY; + } else if (SimCard.INTENT_VALUE_SIM_LOCKED.equals(stateExtra)) { + final String lockedReason = intent + .getStringExtra(SimCard.INTENT_KEY_LOCKED_REASON); + if (SimCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { + this.simState = SimCard.State.PIN_REQUIRED; + } else if (SimCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { + this.simState = SimCard.State.PUK_REQUIRED; + } else { + this.simState = SimCard.State.UNKNOWN; + } + } else if (SimCard.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) { + this.simState = SimCard.State.NETWORK_LOCKED; + } else { + this.simState = SimCard.State.UNKNOWN; + } + } + + public String toString() { + return simState.toString(); + } + } + + public KeyguardUpdateMonitor(Context context) { + mContext = context; + + mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_CONFIGURATION_CHANGED: + handleConfigurationChange(); + break; + case MSG_TIME_UPDATE: + handleTimeUpdate(); + break; + case MSG_BATTERY_UPDATE: + handleBatteryUpdate(msg.arg1, msg.arg2); + break; + case MSG_CARRIER_INFO_UPDATE: + handleCarrierInfoUpdate(); + break; + case MSG_SIM_STATE_CHANGE: + handleSimStateChange((SimArgs) msg.obj); + break; + } + } + }; + + mDeviceProvisioned = Settings.Secure.getInt( + mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; + + // Since device can't be un-provisioned, we only need to register a content observer + // to update mDeviceProvisioned when we are... + if (!mDeviceProvisioned) { + mContentObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.DEVICE_PROVISIONED, 0) != 0; + if (mDeviceProvisioned && mContentObserver != null) { + // We don't need the observer anymore... + mContext.getContentResolver().unregisterContentObserver(mContentObserver); + mContentObserver = null; + } + if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned); + } + }; + + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.DEVICE_PROVISIONED), + false, mContentObserver); + + // prevent a race condition between where we check the flag and where we register the + // observer by grabbing the value once again... + mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.DEVICE_PROVISIONED, 0) != 0; + } + + mInPortrait = queryInPortrait(); + mKeyboardOpen = queryKeyboardOpen(); + + // take a guess to start + mSimState = SimCard.State.READY; + mDevicePluggedIn = true; + mBatteryLevel = 100; + + mTelephonyPlmn = getDefaultPlmn(); + + // setup receiver + final IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + filter.addAction(Intent.ACTION_TIME_TICK); + filter.addAction(Intent.ACTION_TIME_CHANGED); + filter.addAction(Intent.ACTION_BATTERY_CHANGED); + filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); + filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + filter.addAction(SPN_STRINGS_UPDATED_ACTION); + context.registerReceiver(new BroadcastReceiver() { + + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (DEBUG) Log.d(TAG, "received broadcast " + action); + + if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_CONFIGURATION_CHANGED)); + } else if (Intent.ACTION_TIME_TICK.equals(action) + || Intent.ACTION_TIME_CHANGED.equals(action) + || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_TIME_UPDATE)); + } else if (SPN_STRINGS_UPDATED_ACTION.equals(action)) { + mTelephonyPlmn = getTelephonyPlmnFrom(intent); + mTelephonySpn = getTelephonySpnFrom(intent); + mHandler.sendMessage(mHandler.obtainMessage(MSG_CARRIER_INFO_UPDATE)); + } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { + final int pluggedInStatus = intent + .getIntExtra("status", BATTERY_STATUS_UNKNOWN); + int batteryLevel = intent.getIntExtra("level", 0); + final Message msg = mHandler.obtainMessage( + MSG_BATTERY_UPDATE, + pluggedInStatus, + batteryLevel); + mHandler.sendMessage(msg); + } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){ + mHandler.sendMessage(mHandler.obtainMessage( + MSG_SIM_STATE_CHANGE, + new SimArgs(intent))); + } + } + }, filter); + } + + /** + * Handle {@link #MSG_CONFIGURATION_CHANGED} + */ + private void handleConfigurationChange() { + if (DEBUG) Log.d(TAG, "handleConfigurationChange"); + + final boolean inPortrait = queryInPortrait(); + if (mInPortrait != inPortrait) { + mInPortrait = inPortrait; + for (int i = 0; i < mConfigurationChangeCallbacks.size(); i++) { + mConfigurationChangeCallbacks.get(i).onOrientationChange(inPortrait); + } + } + + final boolean keyboardOpen = queryKeyboardOpen(); + if (mKeyboardOpen != keyboardOpen) { + mKeyboardOpen = keyboardOpen; + for (int i = 0; i < mConfigurationChangeCallbacks.size(); i++) { + mConfigurationChangeCallbacks.get(i).onKeyboardChange(keyboardOpen); + } + } + } + + /** + * Handle {@link #MSG_TIME_UPDATE} + */ + private void handleTimeUpdate() { + if (DEBUG) Log.d(TAG, "handleTimeUpdate"); + for (int i = 0; i < mInfoCallbacks.size(); i++) { + mInfoCallbacks.get(i).onTimeChanged(); + } + } + + /** + * Handle {@link #MSG_BATTERY_UPDATE} + */ + private void handleBatteryUpdate(int pluggedInStatus, int batteryLevel) { + if (DEBUG) Log.d(TAG, "handleBatteryUpdate"); + final boolean pluggedIn = isPluggedIn(pluggedInStatus); + + if (isBatteryUpdateInteresting(pluggedIn, batteryLevel)) { + mBatteryLevel = batteryLevel; + mDevicePluggedIn = pluggedIn; + for (int i = 0; i < mInfoCallbacks.size(); i++) { + mInfoCallbacks.get(i).onRefreshBatteryInfo( + shouldShowBatteryInfo(), pluggedIn, batteryLevel); + } + } + + // shut down gracefully if our battery is critically low and we are not powered + if (batteryLevel == 0 && + pluggedInStatus != BATTERY_STATUS_CHARGING && + pluggedInStatus != BATTERY_STATUS_UNKNOWN) { + ShutdownThread.shutdownAfterDisablingRadio(mContext, false); + } + } + + /** + * Handle {@link #MSG_CARRIER_INFO_UPDATE} + */ + private void handleCarrierInfoUpdate() { + if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn + + ", spn = " + mTelephonySpn); + + for (int i = 0; i < mInfoCallbacks.size(); i++) { + mInfoCallbacks.get(i).onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn); + } + } + + /** + * Handle {@link #MSG_SIM_STATE_CHANGE} + */ + private void handleSimStateChange(SimArgs simArgs) { + final SimCard.State state = simArgs.simState; + + if (DEBUG) { + Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " " + + "state resolved to " + state.toString()); + } + + if (state != SimCard.State.UNKNOWN && state != mSimState) { + mSimState = state; + for (int i = 0; i < mSimStateCallbacks.size(); i++) { + mSimStateCallbacks.get(i).onSimStateChanged(state); + } + } + } + + /** + * @param status One of the statuses of {@link android.os.BatteryManager} + * @return Whether the status maps to a status for being plugged in. + */ + private boolean isPluggedIn(int status) { + return status == BATTERY_STATUS_CHARGING || status == BATTERY_STATUS_FULL; + } + + private boolean isBatteryUpdateInteresting(boolean pluggedIn, int batteryLevel) { + // change in plug is always interesting + if (mDevicePluggedIn != pluggedIn) { + return true; + } + + // change in battery level while plugged in + if (pluggedIn && mBatteryLevel != batteryLevel) { + return true; + } + + if (!pluggedIn) { + // not plugged in and going below threshold + if (batteryLevel < LOW_BATTERY_THRESHOLD + && mBatteryLevel >= LOW_BATTERY_THRESHOLD) { + return true; + } + // not plugged in and going above threshold (sounds impossible, but, meh...) + if (mBatteryLevel < LOW_BATTERY_THRESHOLD + && batteryLevel >= LOW_BATTERY_THRESHOLD) { + return true; + } + } + return false; + } + + /** + * What is the current orientation? + */ + boolean queryInPortrait() { + final Configuration configuration = mContext.getResources().getConfiguration(); + return configuration.orientation == Configuration.ORIENTATION_PORTRAIT; + } + + /** + * Is the (hard) keyboard currently open? + */ + boolean queryKeyboardOpen() { + final Configuration configuration = mContext.getResources().getConfiguration(); + + return configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO; + } + + /** + * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION} + * @return The string to use for the plmn, or null if it should not be shown. + */ + private CharSequence getTelephonyPlmnFrom(Intent intent) { + if (intent.getBooleanExtra(EXTRA_SHOW_PLMN, false)) { + final String plmn = intent.getStringExtra(EXTRA_PLMN); + if (plmn != null) { + return plmn; + } else { + return getDefaultPlmn(); + } + } + return null; + } + + /** + * @return The default plmn (no service) + */ + private CharSequence getDefaultPlmn() { + return mContext.getResources().getText( + R.string.lockscreen_carrier_default); + } + + /** + * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION} + * @return The string to use for the plmn, or null if it should not be shown. + */ + private CharSequence getTelephonySpnFrom(Intent intent) { + if (intent.getBooleanExtra(EXTRA_SHOW_SPN, false)) { + final String spn = intent.getStringExtra(EXTRA_SPN); + if (spn != null) { + return spn; + } + } + return null; + } + + /** + * Remove the given observer from being registered from any of the kinds + * of callbacks. + * @param observer The observer to remove (an instance of {@link ConfigurationChangeCallback}, + * {@link InfoCallback} or {@link SimStateCallback} + */ + public void removeCallback(Object observer) { + mConfigurationChangeCallbacks.remove(observer); + mInfoCallbacks.remove(observer); + mSimStateCallbacks.remove(observer); + } + + /** + * Callback for configuration changes. + */ + interface ConfigurationChangeCallback { + void onOrientationChange(boolean inPortrait); + + void onKeyboardChange(boolean isKeyboardOpen); + } + + /** + * Callback for general information releveant to lock screen. + */ + interface InfoCallback { + void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel); + void onTimeChanged(); + + /** + * @param plmn The operator name of the registered network. May be null if it shouldn't + * be displayed. + * @param spn The service provider name. May be null if it shouldn't be displayed. + */ + void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn); + } + + /** + * Callback to notify of sim state change. + */ + interface SimStateCallback { + void onSimStateChanged(SimCard.State simState); + } + + /** + * Register to receive notifications about configuration changes. + * @param callback The callback. + */ + public void registerConfigurationChangeCallback(ConfigurationChangeCallback callback) { + mConfigurationChangeCallbacks.add(callback); + } + + /** + * Register to receive notifications about general keyguard information + * (see {@link InfoCallback}. + * @param callback The callback. + */ + public void registerInfoCallback(InfoCallback callback) { + mInfoCallbacks.add(callback); + } + + /** + * Register to be notified of sim state changes. + * @param callback The callback. + */ + public void registerSimStateCallback(SimStateCallback callback) { + mSimStateCallbacks.add(callback); + } + + public SimCard.State getSimState() { + return mSimState; + } + + /** + * Report that the user succesfully entered the sim pin so we + * have the information earlier than waiting for the intent + * broadcast from the telephony code. + */ + public void reportSimPinUnlocked() { + mSimState = SimCard.State.READY; + } + + public boolean isInPortrait() { + return mInPortrait; + } + + public boolean isKeyboardOpen() { + return mKeyboardOpen; + } + + public boolean isDevicePluggedIn() { + return mDevicePluggedIn; + } + + public int getBatteryLevel() { + return mBatteryLevel; + } + + public boolean shouldShowBatteryInfo() { + return mDevicePluggedIn || mBatteryLevel < LOW_BATTERY_THRESHOLD; + } + + public CharSequence getTelephonyPlmn() { + return mTelephonyPlmn; + } + + public CharSequence getTelephonySpn() { + return mTelephonySpn; + } + + /** + * @return Whether the device is provisioned (whether they have gone through + * the setup wizard) + */ + public boolean isDeviceProvisioned() { + return mDeviceProvisioned; + } + + public int getFailedAttempts() { + return mFailedAttempts; + } + + public void clearFailedAttempts() { + mFailedAttempts = 0; + } + + public void reportFailedAttempt() { + mFailedAttempts++; + } +} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/com/android/internal/policy/impl/KeyguardViewBase.java new file mode 100644 index 000000000000..a565808e76c9 --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardViewBase.java @@ -0,0 +1,188 @@ +/* + * 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 android.content.Context; +import android.content.Intent; +import android.media.AudioManager; +import android.view.KeyEvent; +import android.view.View; +import android.widget.FrameLayout; + +/** + * Base class for keyguard views. {@link #reset} is where you should + * reset the state of your view. Use the {@link KeyguardViewCallback} via + * {@link #getCallback()} to send information back (such as poking the wake lock, + * or finishing the keyguard). + * + * Handles intercepting of media keys that still work when the keyguard is + * showing. + */ +public abstract class KeyguardViewBase extends FrameLayout { + + private KeyguardViewCallback mCallback; + private AudioManager mAudioManager; + + public KeyguardViewBase(Context context) { + super(context); + } + + // used to inject callback + void setCallback(KeyguardViewCallback callback) { + mCallback = callback; + } + + public KeyguardViewCallback getCallback() { + return mCallback; + } + + /** + * Called when you need to reset the state of your view. + */ + abstract public void reset(); + + /** + * Called when the screen turned off. + */ + abstract public void onScreenTurnedOff(); + + /** + * Called when the screen turned on. + */ + abstract public void onScreenTurnedOn(); + + /** + * Called when a key has woken the device to give us a chance to adjust our + * state according the the key. We are responsible for waking the device + * (by poking the wake lock) once we are ready. + * + * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}. + * Be sure not to take any action that takes a long time; any significant + * action should be posted to a handler. + * + * @param keyCode The wake key, which may be relevant for configuring the + * keyguard. + */ + abstract public void wakeWhenReadyTq(int keyCode); + + /** + * Verify that the user can get past the keyguard securely. This is called, + * for example, when the phone disables the keyguard but then wants to launch + * something else that requires secure access. + * + * The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)} + */ + abstract public void verifyUnlock(); + + /** + * Called before this view is being removed. + */ + abstract public void cleanUp(); + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (shouldEventKeepScreenOnWhileKeyguardShowing(event)) { + mCallback.pokeWakelock(); + } + + if (interceptMediaKey(event)) { + return true; + } + return super.dispatchKeyEvent(event); + } + + private boolean shouldEventKeepScreenOnWhileKeyguardShowing(KeyEvent event) { + if (event.getAction() != KeyEvent.ACTION_DOWN) { + return false; + } + switch (event.getKeyCode()) { + case KeyEvent.KEYCODE_DPAD_DOWN: + case KeyEvent.KEYCODE_DPAD_LEFT: + case KeyEvent.KEYCODE_DPAD_RIGHT: + case KeyEvent.KEYCODE_DPAD_UP: + return false; + default: + return true; + } + } + + /** + * Allows the media keys to work when the keygaurd is showing. + * The media keys should be of no interest to the actualy keygaurd view(s), + * so intercepting them here should not be of any harm. + * @param event The key event + * @return whether the event was consumed as a media key. + */ + private boolean interceptMediaKey(KeyEvent event) { + final int keyCode = event.getKeyCode(); + if (event.getAction() == KeyEvent.ACTION_DOWN) { + switch (keyCode) { + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: { + Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, event); + getContext().sendOrderedBroadcast(intent, null); + return true; + } + + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: { + synchronized (this) { + if (mAudioManager == null) { + mAudioManager = (AudioManager) getContext().getSystemService( + Context.AUDIO_SERVICE); + } + } + // Volume buttons should only function for music. + if (mAudioManager.isMusicActive()) { + mAudioManager.adjustStreamVolume( + AudioManager.STREAM_MUSIC, + keyCode == KeyEvent.KEYCODE_VOLUME_UP + ? AudioManager.ADJUST_RAISE + : AudioManager.ADJUST_LOWER, + 0); + } + // Don't execute default volume behavior + return true; + } + } + } else if (event.getAction() == KeyEvent.ACTION_UP) { + switch (keyCode) { + case KeyEvent.KEYCODE_MUTE: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: { + Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, event); + getContext().sendOrderedBroadcast(intent, null); + return true; + } + } + } + return false; + } + +} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewCallback.java b/policy/com/android/internal/policy/impl/KeyguardViewCallback.java new file mode 100644 index 000000000000..b376d657cc80 --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardViewCallback.java @@ -0,0 +1,49 @@ +/* + * 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; + +/** + * The callback used by the keyguard view to tell the {@link KeyguardViewMediator} + * various things. + */ +public interface KeyguardViewCallback { + + /** + * Request the wakelock to be poked for the default amount of time. + */ + void pokeWakelock(); + + /** + * Request the wakelock to be poked for a specific amount of time. + * @param millis The amount of time in millis. + */ + void pokeWakelock(int millis); + + /** + * Report that the keyguard is done. + * @param authenticated Whether the user securely got past the keyguard. + * the only reason for this to be false is if the keyguard was instructed + * to appear temporarily to verify the user is supposed to get past the + * keyguard, and the user fails to do so. + */ + void keyguardDone(boolean authenticated); + + /** + * Report that the keyguard is done drawing. + */ + void keyguardDoneDrawing(); +} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java new file mode 100644 index 000000000000..297d62f4a4bf --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -0,0 +1,226 @@ +/* + * 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.content.Context; +import android.content.pm.ActivityInfo; +import android.graphics.PixelFormat; +import android.graphics.Canvas; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewManager; +import android.view.WindowManager; +import android.widget.FrameLayout; + +/** + * Manages creating, showing, hiding and resetting the keyguard. Calls back + * via {@link com.android.internal.policy.impl.KeyguardViewCallback} to poke + * the wake lock and report that the keyguard is done, which is in turn, + * reported to this class by the current {@link KeyguardViewBase}. + */ +public class KeyguardViewManager implements KeyguardWindowController { + private final static boolean DEBUG = false; + private static String TAG = "KeyguardViewManager"; + + private final Context mContext; + private final ViewManager mViewManager; + private final KeyguardViewCallback mCallback; + private final KeyguardViewProperties mKeyguardViewProperties; + + private final KeyguardUpdateMonitor mUpdateMonitor; + + private WindowManager.LayoutParams mWindowLayoutParams; + private boolean mNeedsInput = false; + + private FrameLayout mKeyguardHost; + private KeyguardViewBase mKeyguardView; + + private boolean mScreenOn = false; + + /** + * @param context Used to create views. + * @param viewManager Keyguard will be attached to this. + * @param callback Used to notify of changes. + */ + public KeyguardViewManager(Context context, ViewManager viewManager, + KeyguardViewCallback callback, KeyguardViewProperties keyguardViewProperties, KeyguardUpdateMonitor updateMonitor) { + mContext = context; + mViewManager = viewManager; + mCallback = callback; + mKeyguardViewProperties = keyguardViewProperties; + + mUpdateMonitor = updateMonitor; + } + + /** + * Helper class to host the keyguard view. + */ + private static class KeyguardViewHost extends FrameLayout { + private final KeyguardViewCallback mCallback; + + private KeyguardViewHost(Context context, KeyguardViewCallback callback) { + super(context); + mCallback = callback; + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + mCallback.keyguardDoneDrawing(); + } + } + + /** + * Show the keyguard. Will handle creating and attaching to the view manager + * lazily. + */ + public synchronized void show() { + if (DEBUG) Log.d(TAG, "show()"); + + if (mKeyguardHost == null) { + if (DEBUG) Log.d(TAG, "keyguard host is null, creating it..."); + + mKeyguardHost = new KeyguardViewHost(mContext, mCallback); + + final int stretch = ViewGroup.LayoutParams.FILL_PARENT; + int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN + /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ; + if (!mNeedsInput) { + flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + } + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD, + flags, PixelFormat.OPAQUE); + lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; + lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen; + lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; + lp.setTitle("Keyguard"); + mWindowLayoutParams = lp; + + mViewManager.addView(mKeyguardHost, lp); + } + + if (mKeyguardView == null) { + if (DEBUG) Log.d(TAG, "keyguard view is null, creating it..."); + mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor, this); + mKeyguardView.setId(R.id.lock_screen); + mKeyguardView.setCallback(mCallback); + + final ViewGroup.LayoutParams lp = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.FILL_PARENT); + + mKeyguardHost.addView(mKeyguardView, lp); + + if (mScreenOn) { + mKeyguardView.onScreenTurnedOn(); + } + } + + mKeyguardHost.setVisibility(View.VISIBLE); + mKeyguardView.requestFocus(); + } + + public void setNeedsInput(boolean needsInput) { + mNeedsInput = needsInput; + if (mWindowLayoutParams != null) { + if (needsInput) { + mWindowLayoutParams.flags &= + ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + } else { + mWindowLayoutParams.flags |= + WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + } + mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); + } + } + + /** + * Reset the state of the view. + */ + public synchronized void reset() { + if (DEBUG) Log.d(TAG, "reset()"); + if (mKeyguardView != null) { + mKeyguardView.reset(); + } + } + + public synchronized void onScreenTurnedOff() { + if (DEBUG) Log.d(TAG, "onScreenTurnedOff()"); + mScreenOn = false; + if (mKeyguardView != null) { + mKeyguardView.onScreenTurnedOff(); + } + } + + public synchronized void onScreenTurnedOn() { + if (DEBUG) Log.d(TAG, "onScreenTurnedOn()"); + mScreenOn = true; + if (mKeyguardView != null) { + mKeyguardView.onScreenTurnedOn(); + } + } + + public synchronized void verifyUnlock() { + if (DEBUG) Log.d(TAG, "verifyUnlock()"); + show(); + mKeyguardView.verifyUnlock(); + } + + /** + * A key has woken the device. We use this to potentially adjust the state + * of the lock screen based on the key. + * + * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}. + * Be sure not to take any action that takes a long time; any significant + * action should be posted to a handler. + * + * @param keyCode The wake key. + */ + public void wakeWhenReadyTq(int keyCode) { + if (DEBUG) Log.d(TAG, "wakeWhenReady(" + keyCode + ")"); + if (mKeyguardView != null) { + mKeyguardView.wakeWhenReadyTq(keyCode); + } + } + + /** + * Hides the keyguard view + */ + public synchronized void hide() { + if (DEBUG) Log.d(TAG, "hide()"); + if (mKeyguardHost != null) { + mKeyguardHost.setVisibility(View.GONE); + if (mKeyguardView != null) { + mKeyguardHost.removeView(mKeyguardView); + mKeyguardView.cleanUp(); + mKeyguardView = null; + } + } + } + + /** + * @return Whether the keyguard is showing + */ + public synchronized boolean isShowing() { + return (mKeyguardHost != null && mKeyguardHost.getVisibility() == View.VISIBLE); + } +} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java new file mode 100644 index 000000000000..e7366c2a72d6 --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -0,0 +1,915 @@ +/* + * 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 android.app.AlarmManager; +import android.app.PendingIntent; +import android.app.StatusBarManager; +import static android.app.StatusBarManager.DISABLE_NONE; +import static android.app.StatusBarManager.DISABLE_EXPAND; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.os.LocalPowerManager; +import android.os.Message; +import android.os.PowerManager; +import android.os.SystemClock; +import android.util.Config; +import android.util.Log; +import android.util.EventLog; +import android.view.KeyEvent; +import android.view.WindowManagerImpl; +import android.view.WindowManagerPolicy; +import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.widget.LockPatternUtils; + +/** + * Mediates requests related to the keyguard. This includes queries about the + * state of the keyguard, power management events that effect whether the keyguard + * should be shown or reset, callbacks to the phone window manager to notify + * it of when the keyguard is showing, and events from the keyguard view itself + * stating that the keyguard was succesfully unlocked. + * + * Note that the keyguard view is shown when the screen is off (as appropriate) + * so that once the screen comes on, it will be ready immediately. + * + * Example queries about the keyguard: + * - is {movement, key} one that should wake the keygaurd? + * - is the keyguard showing? + * - are input events restricted due to the state of the keyguard? + * + * Callbacks to the phone window manager: + * - the keyguard is showing + * + * Example external events that translate to keyguard view changes: + * - screen turned off -> reset the keyguard, and show it so it will be ready + * next time the screen turns on + * - keyboard is slid open -> if the keyguard is not secure, hide it + * + * Events from the keyguard view: + * - user succesfully unlocked keyguard -> hide keyguard view, and no longer + * restrict input events. + * + * Note: in addition to normal power managment events that effect the state of + * whether the keyguard should be showing, external apps and services may request + * that the keyguard be disabled via {@link #setKeyguardEnabled(boolean)}. When + * false, this will override all other conditions for turning on the keyguard. + * + * Threading and synchronization: + * This class is created by the initialization routine of the {@link WindowManagerPolicy}, + * and runs on its thread. The keyguard UI is created from that thread in the + * constructor of this class. The apis may be called from other threads, including the + * {@link com.android.server.KeyInputQueue}'s and {@link android.view.WindowManager}'s. + * Therefore, methods on this class are synchronized, and any action that is pointed + * directly to the keyguard UI is posted to a {@link Handler} to ensure it is taken on the UI + * thread of the keyguard. + */ +public class KeyguardViewMediator implements KeyguardViewCallback, + KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.SimStateCallback { + private final static boolean DEBUG = false && Config.LOGD; + private final static boolean DBG_WAKE = DEBUG || true; + + private final static String TAG = "KeyguardViewMediator"; + + private static final String DELAYED_KEYGUARD_ACTION = "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD"; + + // used for handler messages + private static final int TIMEOUT = 1; + private static final int SHOW = 2; + private static final int HIDE = 3; + private static final int RESET = 4; + private static final int VERIFY_UNLOCK = 5; + private static final int NOTIFY_SCREEN_OFF = 6; + private static final int NOTIFY_SCREEN_ON = 7; + private static final int WAKE_WHEN_READY = 8; + private static final int KEYGUARD_DONE = 9; + private static final int KEYGUARD_DONE_DRAWING = 10; + + /** + * The default amount of time we stay awake (used for all key input) + */ + protected static final int AWAKE_INTERVAL_DEFAULT_MS = 5000; + + + /** + * The default amount of time we stay awake (used for all key input) when + * the keyboard is open + */ + protected static final int AWAKE_INTERVAL_DEFAULT_KEYBOARD_OPEN_MS = 10000; + + /** + * How long to wait after the screen turns off due to timeout before + * 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 = 0; + + /** + * How long we'll wait for the {@link KeyguardViewCallback#keyguardDoneDrawing()} + * callback before unblocking a call to {@link #setKeyguardEnabled(boolean)} + * that is reenabling the keyguard. + */ + private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000; + + private Context mContext; + private AlarmManager mAlarmManager; + + private boolean mSystemReady; + + /** Low level access to the power manager for enableUserActivity. Having this + * requires that we run in the system process. */ + LocalPowerManager mRealPowerManager; + + /** High level access to the power manager for WakeLocks */ + private PowerManager mPM; + + /** + * Used to keep the device awake while the keyguard is showing, i.e for + * calls to {@link #pokeWakelock()} + */ + private PowerManager.WakeLock mWakeLock; + + /** + * Does not turn on screen, held while a call to {@link KeyguardViewManager#wakeWhenReadyTq(int)} + * is called to make sure the device doesn't sleep before it has a chance to poke + * the wake lock. + * @see #wakeWhenReadyLocked(int) + */ + private PowerManager.WakeLock mWakeAndHandOff; + + /** + * Used to disable / reenable status bar expansion. + */ + private StatusBarManager mStatusBarManager; + + private KeyguardViewManager mKeyguardViewManager; + + // these are protected by synchronized (this) + + /** + * External apps (like the phone app) can tell us to disable the keygaurd. + */ + private boolean mExternallyEnabled = true; + + /** + * Remember if an external call to {@link #setKeyguardEnabled} with value + * false caused us to hide the keyguard, so that we need to reshow it once + * the keygaurd is reenabled with another call with value true. + */ + private boolean mNeedToReshowWhenReenabled = false; + + // cached value of whether we are showing (need to know this to quickly + // answer whether the input should be restricted) + private boolean mShowing = false; + + /** + * Helps remember whether the screen has turned on since the last time + * it turned off due to timeout. see {@link #onScreenTurnedOff(int)} + */ + private int mDelayedShowingSequence; + + private int mWakelockSequence; + + private PhoneWindowManager mCallback; + + /** + * If the user has disabled the keyguard, then requests to exit, this is + * how we'll ultimately let them know whether it was successful. We use this + * var being non-null as an indicator that there is an in progress request. + */ + private WindowManagerPolicy.OnKeyguardExitResult mExitSecureCallback; + + // the properties of the keyguard + private KeyguardViewProperties mKeyguardViewProperties; + + private KeyguardUpdateMonitor mUpdateMonitor; + + private boolean mKeyboardOpen = false; + + /** + * {@link #setKeyguardEnabled} waits on this condition when it reenables + * the keyguard. + */ + private boolean mWaitingUntilKeyguardVisible = false; + + public KeyguardViewMediator(Context context, PhoneWindowManager callback, + LocalPowerManager powerManager) { + mContext = context; + + mRealPowerManager = powerManager; + mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + mWakeLock = mPM.newWakeLock( + PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, + "keyguard"); + mWakeLock.setReferenceCounted(false); + + mWakeAndHandOff = mPM.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, + "keyguardWakeAndHandOff"); + mWakeAndHandOff.setReferenceCounted(false); + + IntentFilter filter = new IntentFilter(); + filter.addAction(DELAYED_KEYGUARD_ACTION); + filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + context.registerReceiver(mBroadCastReceiver, filter); + mAlarmManager = (AlarmManager) context + .getSystemService(Context.ALARM_SERVICE); + mCallback = callback; + + mUpdateMonitor = new KeyguardUpdateMonitor(context); + + mUpdateMonitor.registerConfigurationChangeCallback(this); + mUpdateMonitor.registerSimStateCallback(this); + + mKeyguardViewProperties = + new LockPatternKeyguardViewProperties( + new LockPatternUtils(mContext.getContentResolver()), + mUpdateMonitor); + + mKeyguardViewManager = new KeyguardViewManager( + context, WindowManagerImpl.getDefault(), this, + mKeyguardViewProperties, mUpdateMonitor); + + } + + /** + * Let us know that the system is ready after startup. + */ + public void onSystemReady() { + synchronized (this) { + if (DEBUG) Log.d(TAG, "onSystemReady"); + mSystemReady = true; + doKeyguard(); + } + } + + /** + * Called to let us know the screen was turned off. + * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER} or + * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}. + */ + public void onScreenTurnedOff(int why) { + synchronized (this) { + if (DEBUG) Log.d(TAG, "onScreenTurnedOff(" + why + ")"); + + if (mExitSecureCallback != null) { + if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled"); + mExitSecureCallback.onKeyguardExitResult(false); + mExitSecureCallback = null; + if (!mExternallyEnabled) { + hideLocked(); + } + } else if (mShowing) { + notifyScreenOffLocked(); + resetStateLocked(); + } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT) { + // if the screen turned off because of timeout, set an alarm + // 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); + } else { + doKeyguard(); + } + } + } + + /** + * Let's us know the screen was turned on. + */ + public void onScreenTurnedOn() { + synchronized (this) { + mDelayedShowingSequence++; + if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence); + notifyScreenOnLocked(); + } + } + + /** + * Same semantics as {@link WindowManagerPolicy#enableKeyguard}; provide + * a way for external stuff to override normal keyguard behavior. For instance + * the phone app disables the keyguard when it receives incoming calls. + */ + public void setKeyguardEnabled(boolean enabled) { + synchronized (this) { + if (DEBUG) Log.d(TAG, "setKeyguardEnabled(" + enabled + ")"); + + + mExternallyEnabled = enabled; + + if (!enabled && mShowing) { + if (mExitSecureCallback != null) { + if (DEBUG) Log.d(TAG, "in process of verifyUnlock request, ignoring"); + // we're in the process of handling a request to verify the user + // can get past the keyguard. ignore extraneous requests to disable / reenable + return; + } + + // hiding keyguard that is showing, remember to reshow later + if (DEBUG) Log.d(TAG, "remembering to reshow, hiding keyguard, " + + "disabling status bar expansion"); + mNeedToReshowWhenReenabled = true; + setStatusBarExpandable(false); + hideLocked(); + } else if (enabled && mNeedToReshowWhenReenabled) { + // reenabled after previously hidden, reshow + if (DEBUG) Log.d(TAG, "previously hidden, reshowing, reenabling " + + "status bar expansion"); + mNeedToReshowWhenReenabled = false; + setStatusBarExpandable(true); + + if (mExitSecureCallback != null) { + if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting"); + mExitSecureCallback.onKeyguardExitResult(false); + mExitSecureCallback = null; + resetStateLocked(); + } else { + showLocked(); + + // block until we know the keygaurd is done drawing (and post a message + // to unblock us after a timeout so we don't risk blocking too long + // and causing an ANR). + mWaitingUntilKeyguardVisible = true; + mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_DRAWING, KEYGUARD_DONE_DRAWING_TIMEOUT_MS); + if (DEBUG) Log.d(TAG, "waiting until mWaitingUntilKeyguardVisible is false"); + while (mWaitingUntilKeyguardVisible) { + try { + wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + if (DEBUG) Log.d(TAG, "done waiting for mWaitingUntilKeyguardVisible"); + } + } + } + } + + /** + * @see android.app.KeyguardManager#exitKeyguardSecurely + */ + public void verifyUnlock(WindowManagerPolicy.OnKeyguardExitResult callback) { + synchronized (this) { + if (DEBUG) Log.d(TAG, "verifyUnlock"); + if (!mUpdateMonitor.isDeviceProvisioned()) { + // don't allow this api when the device isn't provisioned + if (DEBUG) Log.d(TAG, "ignoring because device isn't provisioned"); + callback.onKeyguardExitResult(false); + } else if (mExternallyEnabled) { + // this only applies when the user has externally disabled the + // keyguard. this is unexpected and means the user is not + // using the api properly. + Log.w(TAG, "verifyUnlock called when not externally disabled"); + callback.onKeyguardExitResult(false); + } else if (mExitSecureCallback != null) { + // already in progress with someone else + callback.onKeyguardExitResult(false); + } else { + mExitSecureCallback = callback; + verifyUnlockLocked(); + } + } + } + + + private void setStatusBarExpandable(boolean isExpandable) { + if (mStatusBarManager == null) { + mStatusBarManager = + (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); + } + mStatusBarManager.disable(isExpandable ? DISABLE_NONE : DISABLE_EXPAND); + } + + /** + * Is the keyguard currently showing? + */ + public boolean isShowing() { + return mShowing; + } + + /** + * Given the state of the keyguard, is the input restricted? + * Input is restricted when the keyguard is showing, or when the keyguard + * was suppressed by an app that disabled the keyguard or we haven't been provisioned yet. + */ + public boolean isInputRestricted() { + return mShowing || mNeedToReshowWhenReenabled || !mUpdateMonitor.isDeviceProvisioned(); + } + + + /** + * Enable the keyguard if the settings are appropriate. + */ + private void doKeyguard() { + synchronized (this) { + // if another app is disabling us, don't show + if (!mExternallyEnabled) { + if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled"); + return; + } + + // if the keyguard is already showing, don't bother + if (mKeyguardViewManager.isShowing()) { + if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing"); + return; + } + + // if the setup wizard hasn't run yet, don't show + final boolean provisioned = mUpdateMonitor.isDeviceProvisioned(); + final SimCard.State state = mUpdateMonitor.getSimState(); + final boolean lockedOrMissing = state.isPinLocked() || (state == SimCard.State.ABSENT); + if (!lockedOrMissing && !provisioned) { + if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned" + + " and the sim is not locked or missing"); + return; + } + + if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen"); + showLocked(); + } + } + + /** + * Send message to keyguard telling it to reset its state. + * @see #handleReset() + */ + private void resetStateLocked() { + if (DEBUG) Log.d(TAG, "resetStateLocked"); + Message msg = mHandler.obtainMessage(RESET); + mHandler.sendMessage(msg); + } + + /** + * Send message to keyguard telling it to verify unlock + * @see #handleVerifyUnlock() + */ + private void verifyUnlockLocked() { + if (DEBUG) Log.d(TAG, "verifyUnlockLocked"); + mHandler.sendEmptyMessage(VERIFY_UNLOCK); + } + + + /** + * Send a message to keyguard telling it the screen just turned on. + * @see #onScreenTurnedOff(int) + * @see #handleNotifyScreenOff + */ + private void notifyScreenOffLocked() { + if (DEBUG) Log.d(TAG, "notifyScreenOffLocked"); + mHandler.sendEmptyMessage(NOTIFY_SCREEN_OFF); + } + + /** + * Send a message to keyguard telling it the screen just turned on. + * @see #onScreenTurnedOn() + * @see #handleNotifyScreenOn + */ + private void notifyScreenOnLocked() { + if (DEBUG) Log.d(TAG, "notifyScreenOnLocked"); + mHandler.sendEmptyMessage(NOTIFY_SCREEN_ON); + } + + /** + * Send message to keyguard telling it about a wake key so it can adjust + * its state accordingly and then poke the wake lock when it is ready. + * @param keyCode The wake key. + * @see #handleWakeWhenReady + * @see #onWakeKeyWhenKeyguardShowingTq(int) + */ + private void wakeWhenReadyLocked(int keyCode) { + if (DBG_WAKE) Log.d(TAG, "wakeWhenReadyLocked(" + keyCode + ")"); + + /** + * acquire the handoff lock that will keep the cpu running. this will + * be released once the keyguard has set itself up and poked the other wakelock + * in {@link #handleWakeWhenReady(int)} + */ + mWakeAndHandOff.acquire(); + + Message msg = mHandler.obtainMessage(WAKE_WHEN_READY, keyCode, 0); + mHandler.sendMessage(msg); + } + + /** + * Send message to keyguard telling it to show itself + * @see #handleShow() + */ + private void showLocked() { + if (DEBUG) Log.d(TAG, "showLocked"); + Message msg = mHandler.obtainMessage(SHOW); + mHandler.sendMessage(msg); + } + + /** + * Send message to keyguard telling it to hide itself + * @see #handleHide() + */ + private void hideLocked() { + if (DEBUG) Log.d(TAG, "hideLocked"); + Message msg = mHandler.obtainMessage(HIDE); + mHandler.sendMessage(msg); + } + + /** + * {@link KeyguardUpdateMonitor} callbacks. + */ + + /** {@inheritDoc} */ + public void onOrientationChange(boolean inPortrait) { + + } + + /** {@inheritDoc} */ + public void onKeyboardChange(boolean isKeyboardOpen) { + mKeyboardOpen = isKeyboardOpen; + + if (mKeyboardOpen && !mKeyguardViewProperties.isSecure() + && mKeyguardViewManager.isShowing()) { + if (DEBUG) Log.d(TAG, "bypassing keyguard on sliding open of keyboard with non-secure keyguard"); + keyguardDone(true); + } + } + + /** {@inheritDoc} */ + public void onSimStateChanged(SimCard.State simState) { + if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState); + + switch (simState) { + case ABSENT: + // only force lock screen in case of missing sim if user hasn't + // gone through setup wizard + if (!mUpdateMonitor.isDeviceProvisioned()) { + if (!isShowing()) { + if (DEBUG) Log.d(TAG, "INTENT_VALUE_SIM_ABSENT and keygaurd isn't showing, we need " + + "to show the keyguard since the device isn't provisioned yet."); + doKeyguard(); + } else { + resetStateLocked(); + } + } + break; + case PIN_REQUIRED: + case PUK_REQUIRED: + if (!isShowing()) { + if (DEBUG) Log.d(TAG, "INTENT_VALUE_SIM_LOCKED and keygaurd isn't showing, we need " + + "to show the keyguard so the user can enter their sim pin"); + doKeyguard(); + } else { + resetStateLocked(); + } + + break; + case READY: + if (isShowing()) { + resetStateLocked(); + } + break; + } + } + + private BroadcastReceiver mBroadCastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(DELAYED_KEYGUARD_ACTION)) { + + int sequence = intent.getIntExtra("seq", 0); + + if (false) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = " + + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence); + + if (mDelayedShowingSequence == sequence) { + doKeyguard(); + } + } + } + }; + + + /** + * When a key is received when the screen is off and the keyguard is showing, + * we need to decide whether to actually turn on the screen, and if so, tell + * the keyguard to prepare itself and poke the wake lock when it is ready. + * + * The 'Tq' suffix is per the documentation in {@link WindowManagerPolicy}. + * Be sure not to take any action that takes a long time; any significant + * action should be posted to a handler. + * + * @param keyCode The keycode of the key that woke the device + * @return Whether we poked the wake lock (and turned the screen on) + */ + public boolean onWakeKeyWhenKeyguardShowingTq(int keyCode) { + if (DEBUG) Log.d(TAG, "onWakeKeyWhenKeyguardShowing(" + keyCode + ")"); + + if (isWakeKeyWhenKeyguardShowing(keyCode)) { + // give the keyguard view manager a chance to adjust the state of the + // keyguard based on the key that woke the device before poking + // the wake lock + wakeWhenReadyLocked(keyCode); + return true; + } else { + return false; + } + } + + private boolean isWakeKeyWhenKeyguardShowing(int keyCode) { + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: + case KeyEvent.KEYCODE_MUTE: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: + case KeyEvent.KEYCODE_CAMERA: + return false; + } + return true; + } + + /** + * Callbacks from {@link KeyguardViewManager}. + */ + + /** {@inheritDoc} */ + public void pokeWakelock() { + pokeWakelock(mKeyboardOpen ? + AWAKE_INTERVAL_DEFAULT_KEYBOARD_OPEN_MS : AWAKE_INTERVAL_DEFAULT_MS); + } + + /** {@inheritDoc} */ + public void pokeWakelock(int holdMs) { + synchronized (this) { + if (DBG_WAKE) Log.d(TAG, "pokeWakelock(" + holdMs + ")"); + mWakeLock.acquire(); + mHandler.removeMessages(TIMEOUT); + mWakelockSequence++; + Message msg = mHandler.obtainMessage(TIMEOUT, mWakelockSequence, 0); + mHandler.sendMessageDelayed(msg, holdMs); + } + } + + /** + * {@inheritDoc} + * + * @see #handleKeyguardDone + */ + public void keyguardDone(boolean authenticated) { + synchronized (this) { + EventLog.writeEvent(70000, 2); + if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")"); + Message msg = mHandler.obtainMessage(KEYGUARD_DONE); + mHandler.sendMessage(msg); + + if (authenticated) { + mUpdateMonitor.clearFailedAttempts(); + } + + if (mExitSecureCallback != null) { + mExitSecureCallback.onKeyguardExitResult(authenticated); + mExitSecureCallback = null; + + if (authenticated) { + // after succesfully exiting securely, no need to reshow + // the keyguard when they've released the lock + mExternallyEnabled = true; + mNeedToReshowWhenReenabled = false; + setStatusBarExpandable(true); + } + } + } + } + + /** + * {@inheritDoc} + * + * @see #handleKeyguardDoneDrawing + */ + public void keyguardDoneDrawing() { + mHandler.sendEmptyMessage(KEYGUARD_DONE_DRAWING); + } + + /** + * This handler will be associated with the policy thread, which will also + * be the UI thread of the keyguard. Since the apis of the policy, and therefore + * this class, can be called by other threads, any action that directly + * interacts with the keyguard ui should be posted to this handler, rather + * than called directly. + */ + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) + { + switch (msg.what) + { + case TIMEOUT: + handleTimeout(msg.arg1); + return ; + case SHOW: + handleShow(); + return ; + case HIDE: + handleHide(); + return ; + case RESET: + handleReset(); + return ; + case VERIFY_UNLOCK: + handleVerifyUnlock(); + return; + case NOTIFY_SCREEN_OFF: + handleNotifyScreenOff(); + return; + case NOTIFY_SCREEN_ON: + handleNotifyScreenOn(); + return; + case WAKE_WHEN_READY: + handleWakeWhenReady(msg.arg1); + return; + case KEYGUARD_DONE: + handleKeyguardDone(); + return; + case KEYGUARD_DONE_DRAWING: + handleKeyguardDoneDrawing(); + } + } + }; + + /** + * @see #keyguardDone + * @see #KEYGUARD_DONE + */ + private void handleKeyguardDone() { + if (DEBUG) Log.d(TAG, "handleKeyguardDone"); + handleHide(); + mPM.userActivity(SystemClock.uptimeMillis(), true); + mWakeLock.release(); + } + + /** + * @see #keyguardDoneDrawing + * @see #KEYGUARD_DONE_DRAWING + */ + private void handleKeyguardDoneDrawing() { + synchronized(this) { + if (false) Log.d(TAG, "handleKeyguardDoneDrawing"); + if (mWaitingUntilKeyguardVisible) { + if (DEBUG) Log.d(TAG, "handleKeyguardDoneDrawing: notifying mWaitingUntilKeyguardVisible"); + mWaitingUntilKeyguardVisible = false; + notifyAll(); + + // there will usually be two of these sent, one as a timeout, and one + // as a result of the callback, so remove any remaining messages from + // the queue + mHandler.removeMessages(KEYGUARD_DONE_DRAWING); + } + } + } + + /** + * Handles the message sent by {@link #pokeWakelock} + * @param seq used to determine if anything has changed since the message + * was sent. + * @see #TIMEOUT + */ + private void handleTimeout(int seq) { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleTimeout"); + if (seq == mWakelockSequence) { + mWakeLock.release(); + } + } + } + + /** + * Handle message sent by {@link #showLocked}. + * @see #SHOW + */ + private void handleShow() { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleShow"); + if (!mSystemReady) return; + + // while we're showing, we control the wake state, so ask the power + // manager not to honor request for userActivity. + mRealPowerManager.enableUserActivity(false); + + mCallback.onKeyguardShow(); + mKeyguardViewManager.show(); + mShowing = true; + } + } + + /** + * Handle message sent by {@link #hideLocked()} + * @see #HIDE + */ + private void handleHide() { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleHide"); + // When we go away, tell the poewr manager to honor requests from userActivity. + mRealPowerManager.enableUserActivity(true); + + mKeyguardViewManager.hide(); + mShowing = false; + } + } + + /** + * Handle message sent by {@link #wakeWhenReadyLocked(int)} + * @param keyCode The key that woke the device. + * @see #WAKE_WHEN_READY + */ + private void handleWakeWhenReady(int keyCode) { + synchronized (KeyguardViewMediator.this) { + if (DBG_WAKE) Log.d(TAG, "handleWakeWhenReady(" + keyCode + ")"); + + // this should result in a call to 'poke wakelock' which will set a timeout + // on releasing the wakelock + mKeyguardViewManager.wakeWhenReadyTq(keyCode); + + /** + * Now that the keyguard is ready and has poked the wake lock, we can + * release the handoff wakelock + */ + mWakeAndHandOff.release(); + + if (!mWakeLock.isHeld()) { + Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock"); + } + } + } + + /** + * Handle message sent by {@link #resetStateLocked()} + * @see #RESET + */ + private void handleReset() { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleReset"); + mKeyguardViewManager.reset(); + } + } + + /** + * Handle message sent by {@link #verifyUnlock} + * @see #RESET + */ + private void handleVerifyUnlock() { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleVerifyUnlock"); + mKeyguardViewManager.verifyUnlock(); + mShowing = true; + } + } + + /** + * Handle message sent by {@link #notifyScreenOffLocked()} + * @see #NOTIFY_SCREEN_OFF + */ + private void handleNotifyScreenOff() { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleNotifyScreenOff"); + mKeyguardViewManager.onScreenTurnedOff(); + } + } + + /** + * Handle message sent by {@link #notifyScreenOnLocked()} + * @see #NOTIFY_SCREEN_ON + */ + private void handleNotifyScreenOn() { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleNotifyScreenOn"); + mKeyguardViewManager.onScreenTurnedOn(); + } + } +} diff --git a/policy/com/android/internal/policy/impl/KeyguardViewProperties.java b/policy/com/android/internal/policy/impl/KeyguardViewProperties.java new file mode 100644 index 000000000000..bda08eb4252e --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardViewProperties.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2008 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 android.content.Context; + +/** + * Defines operations necessary for showing a keyguard, including how to create + * it, and various properties that are useful to be able to query independant + * of whether the keyguard instance is around or not. + */ +public interface KeyguardViewProperties { + + /** + * Create a keyguard view. + * @param context the context to use when creating the view. + * @param updateMonitor configuration may be based on this. + * @param controller for talking back with the containing window. + * @return the view. + */ + KeyguardViewBase createKeyguardView(Context context, + KeyguardUpdateMonitor updateMonitor, + KeyguardWindowController controller); + + /** + * Would the keyguard be secure right now? + * @return Whether the keyguard is currently secure, meaning it will block + * the user from getting past it until the user enters some sort of PIN. + */ + boolean isSecure(); + +} diff --git a/policy/com/android/internal/policy/impl/KeyguardWindowController.java b/policy/com/android/internal/policy/impl/KeyguardWindowController.java new file mode 100644 index 000000000000..4ad48fb8e007 --- /dev/null +++ b/policy/com/android/internal/policy/impl/KeyguardWindowController.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2009 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; + +/** + * Interface passed to the keyguard view, for it to call up to control + * its containing window. + */ +public interface KeyguardWindowController { + /** + * Control whether the window needs input -- that is if it has + * text fields and thus should allow input method interaction. + */ + void setNeedsInput(boolean needsInput); +} diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java new file mode 100644 index 000000000000..cb3131d0e8b4 --- /dev/null +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -0,0 +1,639 @@ +/* + * 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 android.accounts.AccountsServiceConstants; +import android.accounts.IAccountsService; +import android.app.AlertDialog; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.SystemProperties; +import com.android.internal.telephony.SimCard; +import android.text.TextUtils; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.view.WindowManager; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.PixelFormat; +import android.graphics.ColorFilter; +import com.android.internal.R; +import com.android.internal.widget.LockPatternUtils; + +/** + * The host view for all of the screens of the pattern unlock screen. There are + * two {@link Mode}s of operation, lock and unlock. This will show the appropriate + * screen, and listen for callbacks via {@link com.android.internal.policy.impl.KeyguardScreenCallback + * from the current screen. + * + * This view, in turn, communicates back to {@link com.android.internal.policy.impl.KeyguardViewManager} + * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate. + */ +public class LockPatternKeyguardView extends KeyguardViewBase { + + // intent action for launching emergency dialer activity. + static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL"; + + private static final boolean DEBUG = false; + private static final String TAG = "LockPatternKeyguardView"; + + private final KeyguardUpdateMonitor mUpdateMonitor; + private final KeyguardWindowController mWindowController; + + private View mLockScreen; + private View mUnlockScreen; + + private boolean mScreenOn = false; + private boolean mHasAccount = false; // assume they don't have an account until we know better + + + /** + * The current {@link KeyguardScreen} will use this to communicate back to us. + */ + KeyguardScreenCallback mKeyguardScreenCallback; + + + private boolean mRequiresSim; + + + /** + * Either a lock screen (an informational keyguard screen), or an unlock + * screen (a means for unlocking the device) is shown at any given time. + */ + enum Mode { + LockScreen, + UnlockScreen + } + + /** + * The different types screens available for {@link Mode#UnlockScreen}. + * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode() + */ + enum UnlockMode { + + /** + * Unlock by drawing a pattern. + */ + Pattern, + + /** + * Unlock by entering a sim pin. + */ + SimPin, + + /** + * Unlock by entering an account's login and password. + */ + Account + } + + /** + * The current mode. + */ + private Mode mMode = Mode.LockScreen; + + /** + * Keeps track of what mode the current unlock screen is + */ + private UnlockMode mUnlockScreenMode; + + /** + * If true, it means we are in the process of verifying that the user + * can get past the lock screen per {@link #verifyUnlock()} + */ + private boolean mIsVerifyUnlockOnly = false; + + + /** + * Used to lookup the state of the lock pattern + */ + private final LockPatternUtils mLockPatternUtils; + + /** + * Used to fetch accounts from GLS. + */ + private ServiceConnection mServiceConnection; + + /** + * @return Whether we are stuck on the lock screen because the sim is + * missing. + */ + private boolean stuckOnLockScreenBecauseSimMissing() { + return mRequiresSim + && (!mUpdateMonitor.isDeviceProvisioned()) + && (mUpdateMonitor.getSimState() == SimCard.State.ABSENT); + } + + /** + * @param context Used to inflate, and create views. + * @param updateMonitor Knows the state of the world, and passed along to each + * screen so they can use the knowledge, and also register for callbacks + * on dynamic information. + * @param lockPatternUtils Used to look up state of lock pattern. + */ + public LockPatternKeyguardView( + Context context, + KeyguardUpdateMonitor updateMonitor, + LockPatternUtils lockPatternUtils, + KeyguardWindowController controller) { + super(context); + + asyncCheckForAccount(); + + mRequiresSim = + TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); + + mUpdateMonitor = updateMonitor; + mLockPatternUtils = lockPatternUtils; + mWindowController = controller; + + mMode = getInitialMode(); + + mKeyguardScreenCallback = new KeyguardScreenCallback() { + + public void goToLockScreen() { + if (mIsVerifyUnlockOnly) { + // navigating away from unlock screen during verify mode means + // we are done and the user failed to authenticate. + mIsVerifyUnlockOnly = false; + getCallback().keyguardDone(false); + } else { + updateScreen(Mode.LockScreen); + } + } + + public void goToUnlockScreen() { + final SimCard.State simState = mUpdateMonitor.getSimState(); + if (stuckOnLockScreenBecauseSimMissing() + || (simState == SimCard.State.PUK_REQUIRED)){ + // stuck on lock screen when sim missing or puk'd + return; + } + if (!isSecure()) { + getCallback().keyguardDone(true); + } else { + updateScreen(Mode.UnlockScreen); + } + } + + public boolean isSecure() { + return LockPatternKeyguardView.this.isSecure(); + } + + public boolean isVerifyUnlockOnly() { + return mIsVerifyUnlockOnly; + } + + public void recreateMe() { + recreateScreens(); + } + + public void takeEmergencyCallAction() { + Intent intent = new Intent(ACTION_EMERGENCY_DIAL); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + getContext().startActivity(intent); + } + + public void pokeWakelock() { + getCallback().pokeWakelock(); + } + + public void pokeWakelock(int millis) { + getCallback().pokeWakelock(millis); + } + + public void keyguardDone(boolean authenticated) { + getCallback().keyguardDone(authenticated); + } + + public void keyguardDoneDrawing() { + // irrelevant to keyguard screen, they shouldn't be calling this + } + + public void reportFailedPatternAttempt() { + mUpdateMonitor.reportFailedAttempt(); + final int failedAttempts = mUpdateMonitor.getFailedAttempts(); + if (mHasAccount && failedAttempts == + (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET + - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { + showAlmostAtAccountLoginDialog(); + } else if (mHasAccount + && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { + mLockPatternUtils.setPermanentlyLocked(true); + updateScreen(mMode); + } else if ((failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) + == 0) { + showTimeoutDialog(); + } + } + + public boolean doesFallbackUnlockScreenExist() { + return mHasAccount; + } + }; + + /** + * We'll get key events the current screen doesn't use. see + * {@link KeyguardViewBase#onKeyDown(int, android.view.KeyEvent)} + */ + setFocusableInTouchMode(true); + setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); + + // wall paper background + final BitmapDrawable drawable = (BitmapDrawable) context.getWallpaper(); + setBackgroundDrawable( + new FastBitmapDrawable(drawable.getBitmap())); + + // create both the lock and unlock screen so they are quickly available + // when the screen turns on + mLockScreen = createLockScreen(); + addView(mLockScreen); + final UnlockMode unlockMode = getUnlockMode(); + mUnlockScreen = createUnlockScreenFor(unlockMode); + mUnlockScreenMode = unlockMode; + addView(mUnlockScreen); + updateScreen(mMode); + } + + /** + * Asynchronously checks for at least one account. This will set mHasAccount + * to true if an account is found. + */ + private void asyncCheckForAccount() { + + mServiceConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + try { + IAccountsService accountsService = IAccountsService.Stub.asInterface(service); + String accounts[] = accountsService.getAccounts(); + mHasAccount = (accounts.length > 0); + } catch (RemoteException e) { + // Not much we can do here... + Log.e(TAG, "Gls died while attempting to get accounts: " + e); + } finally { + getContext().unbindService(mServiceConnection); + mServiceConnection = null; + } + } + + public void onServiceDisconnected(ComponentName className) { + // nothing to do here + } + }; + boolean status = getContext().bindService(AccountsServiceConstants.SERVICE_INTENT, + mServiceConnection, Context.BIND_AUTO_CREATE); + if (!status) Log.e(TAG, "Failed to bind to GLS while checking for account"); + } + + @Override + public void reset() { + mIsVerifyUnlockOnly = false; + updateScreen(getInitialMode()); + } + + @Override + public void onScreenTurnedOff() { + mScreenOn = false; + if (mMode == Mode.LockScreen) { + ((KeyguardScreen) mLockScreen).onPause(); + } else { + ((KeyguardScreen) mUnlockScreen).onPause(); + } + } + + @Override + public void onScreenTurnedOn() { + mScreenOn = true; + if (mMode == Mode.LockScreen) { + ((KeyguardScreen) mLockScreen).onResume(); + } else { + ((KeyguardScreen) mUnlockScreen).onResume(); + } + } + + + private void recreateScreens() { + if (mLockScreen.getVisibility() == View.VISIBLE) { + ((KeyguardScreen) mLockScreen).onPause(); + } + ((KeyguardScreen) mLockScreen).cleanUp(); + removeViewInLayout(mLockScreen); + + mLockScreen = createLockScreen(); + mLockScreen.setVisibility(View.INVISIBLE); + addView(mLockScreen); + + if (mUnlockScreen.getVisibility() == View.VISIBLE) { + ((KeyguardScreen) mUnlockScreen).onPause(); + } + ((KeyguardScreen) mUnlockScreen).cleanUp(); + removeViewInLayout(mUnlockScreen); + + final UnlockMode unlockMode = getUnlockMode(); + mUnlockScreen = createUnlockScreenFor(unlockMode); + mUnlockScreen.setVisibility(View.INVISIBLE); + mUnlockScreenMode = unlockMode; + addView(mUnlockScreen); + + updateScreen(mMode); + } + + + @Override + public void wakeWhenReadyTq(int keyCode) { + if (DEBUG) Log.d(TAG, "onWakeKey"); + if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen) + && (mUpdateMonitor.getSimState() != SimCard.State.PUK_REQUIRED)) { + if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); + updateScreen(Mode.UnlockScreen); + getCallback().pokeWakelock(); + } else { + if (DEBUG) Log.d(TAG, "poking wake lock immediately"); + getCallback().pokeWakelock(); + } + } + + @Override + public void verifyUnlock() { + if (!isSecure()) { + // non-secure keyguard screens are successfull by default + getCallback().keyguardDone(true); + } else if (mUnlockScreenMode != UnlockMode.Pattern) { + // can only verify unlock when in pattern mode + getCallback().keyguardDone(false); + } else { + // otherwise, go to the unlock screen, see if they can verify it + mIsVerifyUnlockOnly = true; + updateScreen(Mode.UnlockScreen); + } + } + + @Override + public void cleanUp() { + ((KeyguardScreen) mLockScreen).onPause(); + ((KeyguardScreen) mLockScreen).cleanUp(); + ((KeyguardScreen) mUnlockScreen).onPause(); + ((KeyguardScreen) mUnlockScreen).cleanUp(); + } + + private boolean isSecure() { + UnlockMode unlockMode = getUnlockMode(); + if (unlockMode == UnlockMode.Pattern) { + return mLockPatternUtils.isLockPatternEnabled(); + } else if (unlockMode == UnlockMode.SimPin) { + return mUpdateMonitor.getSimState() == SimCard.State.PIN_REQUIRED + || mUpdateMonitor.getSimState() == SimCard.State.PUK_REQUIRED; + } else if (unlockMode == UnlockMode.Account) { + return true; + } else { + throw new IllegalStateException("unknown unlock mode " + unlockMode); + } + } + + private void updateScreen(final Mode mode) { + + mMode = mode; + + final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen; + final View visibleScreen = (mode == Mode.LockScreen) + ? mLockScreen : getUnlockScreenForCurrentUnlockMode(); + + // do this before changing visibility so focus isn't requested before the input + // flag is set + mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); + + + if (mScreenOn) { + if (goneScreen.getVisibility() == View.VISIBLE) { + ((KeyguardScreen) goneScreen).onPause(); + } + if (visibleScreen.getVisibility() != View.VISIBLE) { + ((KeyguardScreen) visibleScreen).onResume(); + } + } + + goneScreen.setVisibility(View.GONE); + visibleScreen.setVisibility(View.VISIBLE); + + + if (!visibleScreen.requestFocus()) { + throw new IllegalStateException("keyguard screen must be able to take " + + "focus when shown " + visibleScreen.getClass().getCanonicalName()); + } + } + + View createLockScreen() { + return new LockScreen( + mContext, + mLockPatternUtils, + mUpdateMonitor, + mKeyguardScreenCallback); + } + + View createUnlockScreenFor(UnlockMode unlockMode) { + if (unlockMode == UnlockMode.Pattern) { + return new UnlockScreen( + mContext, + mLockPatternUtils, + mUpdateMonitor, + mKeyguardScreenCallback, + mUpdateMonitor.getFailedAttempts()); + } else if (unlockMode == UnlockMode.SimPin) { + return new SimUnlockScreen( + mContext, + mUpdateMonitor, + mKeyguardScreenCallback); + } else if (unlockMode == UnlockMode.Account) { + try { + return new AccountUnlockScreen( + mContext, + mKeyguardScreenCallback, + mLockPatternUtils); + } catch (IllegalStateException e) { + Log.i(TAG, "Couldn't instantiate AccountUnlockScreen" + + " (IAccountsService isn't available)"); + // TODO: Need a more general way to provide a + // platform-specific fallback UI here. + // For now, if we can't display the account login + // unlock UI, just bring back the regular "Pattern" unlock mode. + + // (We do this by simply returning a regular UnlockScreen + // here. This means that the user will still see the + // regular pattern unlock UI, regardless of the value of + // mUnlockScreenMode or whether or not we're in the + // "permanently locked" state.) + return createUnlockScreenFor(UnlockMode.Pattern); + } + } else { + throw new IllegalArgumentException("unknown unlock mode " + unlockMode); + } + } + + private View getUnlockScreenForCurrentUnlockMode() { + final UnlockMode unlockMode = getUnlockMode(); + + // if a screen exists for the correct mode, we're done + if (unlockMode == mUnlockScreenMode) { + return mUnlockScreen; + } + + // remember the mode + mUnlockScreenMode = unlockMode; + + // unlock mode has changed and we have an existing old unlock screen + // to clean up + if (mScreenOn && (mUnlockScreen.getVisibility() == View.VISIBLE)) { + ((KeyguardScreen) mUnlockScreen).onPause(); + } + ((KeyguardScreen) mUnlockScreen).cleanUp(); + removeViewInLayout(mUnlockScreen); + + // create the new one + mUnlockScreen = createUnlockScreenFor(unlockMode); + mUnlockScreen.setVisibility(View.INVISIBLE); + addView(mUnlockScreen); + return mUnlockScreen; + } + + /** + * Given the current state of things, what should be the initial mode of + * the lock screen (lock or unlock). + */ + private Mode getInitialMode() { + final SimCard.State simState = mUpdateMonitor.getSimState(); + if (stuckOnLockScreenBecauseSimMissing() || (simState == SimCard.State.PUK_REQUIRED)) { + return Mode.LockScreen; + } else if (mUpdateMonitor.isKeyboardOpen() && isSecure()) { + return Mode.UnlockScreen; + } else { + return Mode.LockScreen; + } + } + + /** + * Given the current state of things, what should the unlock screen be? + */ + private UnlockMode getUnlockMode() { + final SimCard.State simState = mUpdateMonitor.getSimState(); + if (simState == SimCard.State.PIN_REQUIRED || simState == SimCard.State.PUK_REQUIRED) { + return UnlockMode.SimPin; + } else { + return mLockPatternUtils.isPermanentlyLocked() ? + UnlockMode.Account: + UnlockMode.Pattern; + } + } + + private void showTimeoutDialog() { + int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; + String message = mContext.getString( + R.string.lockscreen_too_many_failed_attempts_dialog_message, + mUpdateMonitor.getFailedAttempts(), + timeoutInSeconds); + final AlertDialog dialog = new AlertDialog.Builder(mContext) + .setTitle(null) + .setMessage(message) + .setNeutralButton(R.string.ok, null) + .create(); + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + dialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + dialog.show(); + } + + private void showAlmostAtAccountLoginDialog() { + int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; + String message = mContext.getString( + R.string.lockscreen_failed_attempts_almost_glogin, + LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, + LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, + timeoutInSeconds); + final AlertDialog dialog = new AlertDialog.Builder(mContext) + .setTitle(null) + .setMessage(message) + .setNeutralButton(R.string.ok, null) + .create(); + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + dialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + dialog.show(); + } + + /** + * Used to put wallpaper on the background of the lock screen. Centers it Horizontally and + * vertically. + */ + static private class FastBitmapDrawable extends Drawable { + private Bitmap mBitmap; + + private FastBitmapDrawable(Bitmap bitmap) { + mBitmap = bitmap; + } + + @Override + public void draw(Canvas canvas) { + canvas.drawBitmap( + mBitmap, + (getBounds().width() - mBitmap.getWidth()) / 2, + (getBounds().height() - mBitmap.getHeight()) / 2, + null); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public void setAlpha(int alpha) { + } + + @Override + public void setColorFilter(ColorFilter cf) { + } + + @Override + public int getIntrinsicWidth() { + return mBitmap.getWidth(); + } + + @Override + public int getIntrinsicHeight() { + return mBitmap.getHeight(); + } + + @Override + public int getMinimumWidth() { + return mBitmap.getWidth(); + } + + @Override + public int getMinimumHeight() { + return mBitmap.getHeight(); + } + } +} diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java new file mode 100644 index 000000000000..4e0cf09c2ad0 --- /dev/null +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2008 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.widget.LockPatternUtils; + +import android.content.Context; +import com.android.internal.telephony.SimCard; + +/** + * Knows how to create a lock pattern keyguard view, and answer questions about + * it (even if it hasn't been created, per the interface specs). + */ +public class LockPatternKeyguardViewProperties implements KeyguardViewProperties { + + private final LockPatternUtils mLockPatternUtils; + private final KeyguardUpdateMonitor mUpdateMonitor; + + /** + * @param lockPatternUtils Used to know whether the pattern enabled, and passed + * onto the keygaurd view when it is created. + * @param updateMonitor Used to know whether the sim pin is enabled, and passed + * onto the keyguard view when it is created. + */ + public LockPatternKeyguardViewProperties(LockPatternUtils lockPatternUtils, + KeyguardUpdateMonitor updateMonitor) { + mLockPatternUtils = lockPatternUtils; + mUpdateMonitor = updateMonitor; + } + + public KeyguardViewBase createKeyguardView(Context context, + KeyguardUpdateMonitor updateMonitor, + KeyguardWindowController controller) { + return new LockPatternKeyguardView(context, updateMonitor, + mLockPatternUtils, controller); + } + + public boolean isSecure() { + return isLockPatternSecure() || isSimPinSecure(); + } + + private boolean isLockPatternSecure() { + return mLockPatternUtils.isLockPatternEnabled() && mLockPatternUtils + .savedPatternExists(); + } + + private boolean isSimPinSecure() { + final SimCard.State simState = mUpdateMonitor.getSimState(); + return (simState == SimCard.State.PIN_REQUIRED || simState == SimCard.State.PUK_REQUIRED + || simState == SimCard.State.ABSENT); + } + +} diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java new file mode 100644 index 000000000000..82a52f9ed993 --- /dev/null +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2008 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 com.android.internal.widget.LockPatternUtils; + +import android.content.Context; +import android.text.format.DateFormat; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import com.android.internal.telephony.SimCard; + +import java.util.Date; + +/** + * The screen within {@link LockPatternKeyguardView} that shows general + * 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, KeyguardUpdateMonitor.ConfigurationChangeCallback { + private final LockPatternUtils mLockPatternUtils; + private final KeyguardUpdateMonitor mUpdateMonitor; + private final KeyguardScreenCallback mCallback; + + private TextView mHeaderSimOk1; + private TextView mHeaderSimOk2; + + private TextView mHeaderSimBad1; + private TextView mHeaderSimBad2; + + private TextView mTime; + private TextView mDate; + + private ViewGroup mBatteryInfoGroup; + private ImageView mBatteryInfoIcon; + private TextView mBatteryInfoText; + private View mBatteryInfoSpacer; + + private ViewGroup mNextAlarmGroup; + private TextView mAlarmText; + private View mAlarmSpacer; + + private ViewGroup mScreenLockedMessageGroup; + + private TextView mLockInstructions; + + private Button mEmergencyCallButton; + + /** + * false means sim is missing or PUK'd + */ + private boolean mSimOk = true; + + // 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 View[] mOnlyVisibleWhenSimOk; + + private View[] mOnlyVisibleWhenSimNotOk; + + /** + * @param context Used to setup the view. + * @param lockPatternUtils Used to know the state of the lock pattern settings. + * @param updateMonitor Used to register for updates on various keyguard related + * state, and query the initial state at setup. + * @param callback Used to communicate back to the host keyguard view. + */ + LockScreen(Context context, LockPatternUtils lockPatternUtils, + KeyguardUpdateMonitor updateMonitor, + KeyguardScreenCallback callback) { + super(context); + mLockPatternUtils = lockPatternUtils; + mUpdateMonitor = updateMonitor; + mCallback = callback; + + final LayoutInflater inflater = LayoutInflater.from(context); + inflater.inflate(R.layout.keyguard_screen_lock, this, true); + + mSimOk = isSimOk(updateMonitor.getSimState()); + mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo(); + mPluggedIn = updateMonitor.isDevicePluggedIn(); + mBatteryLevel = updateMonitor.getBatteryLevel(); + + mHeaderSimOk1 = (TextView) findViewById(R.id.headerSimOk1); + mHeaderSimOk2 = (TextView) findViewById(R.id.headerSimOk2); + + mHeaderSimBad1 = (TextView) findViewById(R.id.headerSimBad1); + mHeaderSimBad2 = (TextView) findViewById(R.id.headerSimBad2); + + mTime = (TextView) findViewById(R.id.time); + mDate = (TextView) findViewById(R.id.date); + + mBatteryInfoGroup = (ViewGroup) findViewById(R.id.batteryInfo); + mBatteryInfoIcon = (ImageView) findViewById(R.id.batteryInfoIcon); + mBatteryInfoText = (TextView) findViewById(R.id.batteryInfoText); + mBatteryInfoSpacer = findViewById(R.id.batteryInfoSpacer); + + mNextAlarmGroup = (ViewGroup) findViewById(R.id.nextAlarmInfo); + mAlarmText = (TextView) findViewById(R.id.nextAlarmText); + mAlarmSpacer = findViewById(R.id.nextAlarmSpacer); + + mScreenLockedMessageGroup = (ViewGroup) findViewById(R.id.screenLockedInfo); + + mLockInstructions = (TextView) findViewById(R.id.lockInstructions); + + mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); + + mEmergencyCallButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + mCallback.takeEmergencyCallAction(); + } + }); + + mOnlyVisibleWhenSimOk = new View[] { + mHeaderSimOk1, + mHeaderSimOk2, + mBatteryInfoGroup, + mBatteryInfoSpacer, + mNextAlarmGroup, + mAlarmSpacer, + mScreenLockedMessageGroup, + mLockInstructions + }; + + mOnlyVisibleWhenSimNotOk = new View[] { + mHeaderSimBad1, + mHeaderSimBad2, + mEmergencyCallButton + }; + + setFocusable(true); + setFocusableInTouchMode(true); + setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); + + refreshBatteryDisplay(); + refreshAlarmDisplay(); + refreshTimeAndDateDisplay(); + refreshUnlockIntructions(); + refreshViewsWRTSimOk(); + refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn()); + + updateMonitor.registerInfoCallback(this); + updateMonitor.registerSimStateCallback(this); + updateMonitor.registerConfigurationChangeCallback(this); + } + + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_MENU) { + mCallback.goToUnlockScreen(); + } + return false; + } + + private void refreshViewsWRTSimOk() { + if (mSimOk) { + for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) { + final View view = mOnlyVisibleWhenSimOk[i]; + if (view == null) throw new RuntimeException("index " + i + " null"); + view.setVisibility(View.VISIBLE); + } + for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) { + final View view = mOnlyVisibleWhenSimNotOk[i]; + view.setVisibility(View.GONE); + } + refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn()); + refreshAlarmDisplay(); + refreshBatteryDisplay(); + } else { + for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) { + final View view = mOnlyVisibleWhenSimOk[i]; + view.setVisibility(View.GONE); + } + for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) { + final View view = mOnlyVisibleWhenSimNotOk[i]; + view.setVisibility(View.VISIBLE); + } + refreshSimBadInfo(); + } + } + + private void refreshSimBadInfo() { + final SimCard.State simState = mUpdateMonitor.getSimState(); + if (simState == SimCard.State.PUK_REQUIRED) { + mHeaderSimBad1.setText(R.string.lockscreen_sim_puk_locked_message); + mHeaderSimBad2.setText(R.string.lockscreen_sim_puk_locked_instructions); + } else if (simState == SimCard.State.ABSENT) { + mHeaderSimBad1.setText(R.string.lockscreen_missing_sim_message); + mHeaderSimBad2.setVisibility(View.GONE); + //mHeaderSimBad2.setText(R.string.lockscreen_missing_sim_instructions); + } else { + mHeaderSimBad1.setVisibility(View.GONE); + mHeaderSimBad2.setVisibility(View.GONE); + } + } + + private void refreshUnlockIntructions() { + if (mLockPatternUtils.isLockPatternEnabled() + || mUpdateMonitor.getSimState() == SimCard.State.PIN_REQUIRED) { + mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_enabled); + } else { + mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_disabled); + } + } + + private void refreshAlarmDisplay() { + String nextAlarmText = mLockPatternUtils.getNextAlarm(); + if (nextAlarmText != null && mSimOk) { + setAlarmInfoVisible(true); + mAlarmText.setText(nextAlarmText); + } else { + setAlarmInfoVisible(false); + } + } + + private void setAlarmInfoVisible(boolean visible) { + final int visibilityFlag = visible ? View.VISIBLE : View.GONE; + mNextAlarmGroup.setVisibility(visibilityFlag); + mAlarmSpacer.setVisibility(visibilityFlag); + } + + + public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, + int batteryLevel) { + mShowingBatteryInfo = showBatteryInfo; + mPluggedIn = pluggedIn; + mBatteryLevel = batteryLevel; + + refreshBatteryDisplay(); + } + + private void refreshBatteryDisplay() { + if (!mShowingBatteryInfo || !mSimOk) { + mBatteryInfoGroup.setVisibility(View.GONE); + mBatteryInfoSpacer.setVisibility(View.GONE); + return; + } + mBatteryInfoGroup.setVisibility(View.VISIBLE); + mBatteryInfoSpacer.setVisibility(View.VISIBLE); + + if (mPluggedIn) { + mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_charging); + mBatteryInfoText.setText( + getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel)); + } else { + mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_low_battery); + mBatteryInfoText.setText(R.string.lockscreen_low_battery); + } + } + + public void onTimeChanged() { + refreshTimeAndDateDisplay(); + } + + private void refreshTimeAndDateDisplay() { + Date now = new Date(); + mTime.setText(DateFormat.getTimeFormat(getContext()).format(now)); + mDate.setText(DateFormat.getDateFormat(getContext()).format(now)); + } + + public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + refreshSimOkHeaders(plmn, spn); + } + + private void refreshSimOkHeaders(CharSequence plmn, CharSequence spn) { + final SimCard.State simState = mUpdateMonitor.getSimState(); + if (simState == SimCard.State.READY) { + if (plmn != null) { + mHeaderSimOk1.setVisibility(View.VISIBLE); + mHeaderSimOk1.setText(plmn); + } else { + mHeaderSimOk1.setVisibility(View.GONE); + } + + if (spn != null) { + mHeaderSimOk2.setVisibility(View.VISIBLE); + mHeaderSimOk2.setText(spn); + } else { + mHeaderSimOk2.setVisibility(View.GONE); + } + } else if (simState == SimCard.State.PIN_REQUIRED) { + mHeaderSimOk1.setVisibility(View.VISIBLE); + mHeaderSimOk1.setText(R.string.lockscreen_sim_locked_message); + mHeaderSimOk2.setVisibility(View.GONE); + } else if (simState == SimCard.State.ABSENT) { + mHeaderSimOk1.setVisibility(View.VISIBLE); + mHeaderSimOk1.setText(R.string.lockscreen_missing_sim_message_short); + mHeaderSimOk2.setVisibility(View.GONE); + } else if (simState == SimCard.State.NETWORK_LOCKED) { + mHeaderSimOk1.setVisibility(View.VISIBLE); + mHeaderSimOk1.setText(R.string.lockscreen_network_locked_message); + mHeaderSimOk2.setVisibility(View.GONE); + } + } + + public void onSimStateChanged(SimCard.State simState) { + mSimOk = isSimOk(simState); + refreshViewsWRTSimOk(); + } + + /** + * @return Whether the sim state is ok, meaning we don't need to show + * a special screen with the emergency call button and keep them from + * doing anything else. + */ + private boolean isSimOk(SimCard.State simState) { + boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned() + && simState == SimCard.State.ABSENT); + return !(missingAndNotProvisioned || simState == SimCard.State.PUK_REQUIRED); + } + + public void onOrientationChange(boolean inPortrait) { + } + + public void onKeyboardChange(boolean isKeyboardOpen) { + if (isKeyboardOpen) { + mCallback.goToUnlockScreen(); + } + } + + + /** {@inheritDoc} */ + public boolean needsInput() { + return false; + } + + /** {@inheritDoc} */ + public void onPause() { + + } + + /** {@inheritDoc} */ + public void onResume() { + + } + + /** {@inheritDoc} */ + public void cleanUp() { + mUpdateMonitor.removeCallback(this); + } +} diff --git a/policy/com/android/internal/policy/impl/PhoneLayoutInflater.java b/policy/com/android/internal/policy/impl/PhoneLayoutInflater.java new file mode 100644 index 000000000000..6bf4beb0ea57 --- /dev/null +++ b/policy/com/android/internal/policy/impl/PhoneLayoutInflater.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2006 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 java.util.Map; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.LayoutInflater; + +public class PhoneLayoutInflater extends LayoutInflater { + private static final String[] sClassPrefixList = { + "android.widget.", + "android.webkit." + }; + + /** + * Instead of instantiating directly, you should retrieve an instance + * through {@link Context#getSystemService} + * + * @param context The Context in which in which to find resources and other + * application-specific things. + * + * @see Context#getSystemService + */ + public PhoneLayoutInflater(Context context) { + super(context); + } + + protected PhoneLayoutInflater(LayoutInflater original, Context newContext) { + super(original, newContext); + } + + /** Override onCreateView to instantiate names that correspond to the + widgets known to the Widget factory. If we don't find a match, + call through to our super class. + */ + @Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException { + for (String prefix : sClassPrefixList) { + try { + View view = createView(name, prefix, attrs); + if (view != null) { + return view; + } + } catch (ClassNotFoundException e) { + // In this case we want to let the base class take a crack + // at it. + } + } + + return super.onCreateView(name, attrs); + } + + public LayoutInflater cloneInContext(Context newContext) { + return new PhoneLayoutInflater(this, newContext); + } +} + diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java new file mode 100644 index 000000000000..0d26bfbbfac3 --- /dev/null +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -0,0 +1,2688 @@ +/* + * + * 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.view.menu.ContextMenuBuilder; +import com.android.internal.view.menu.MenuBuilder; +import com.android.internal.view.menu.MenuDialogHelper; +import com.android.internal.view.menu.MenuView; +import com.android.internal.view.menu.SubMenuBuilder; + +import android.app.KeyguardManager; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.media.AudioManager; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.SystemClock; +import android.util.AndroidRuntimeException; +import android.util.Config; +import android.util.EventLog; +import android.util.Log; +import android.util.SparseArray; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import static android.view.ViewGroup.LayoutParams.FILL_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import android.view.ViewManager; +import android.view.VolumePanel; +import android.view.Window; +import android.view.WindowManager; +import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.view.inputmethod.InputMethodManager; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +/** + * Android-specific Window. + *

    + * todo: need to pull the generic functionality out into a base class + * in android.widget. + */ +public class PhoneWindow extends Window implements MenuBuilder.Callback { + private final static String TAG = "PhoneWindow"; + + private final static boolean SWEEP_OPEN_MENU = false; + + /** + * 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); + + // This is the top-level view of the window, containing the window decor. + private DecorView mDecor; + + // This is the view in which the window contents are placed. It is either + // mDecor itself, or a child of mDecor where the contents go. + private ViewGroup mContentParent; + + private boolean mIsFloating; + + private LayoutInflater mLayoutInflater; + + private TextView mTitleView; + + private DrawableFeatureState[] mDrawables; + + private PanelFeatureState[] mPanels; + + /** + * The panel that is prepared or opened (the most recent one if there are + * multiple panels). Shortcuts will go to this panel. It gets set in + * {@link #preparePanel} and cleared in {@link #closePanel}. + */ + private PanelFeatureState mPreparedPanel; + + /** + * The keycode that is currently held down (as a modifier) for chording. If + * this is 0, there is no key held down. + */ + private int mPanelChordingKey; + + private ImageView mLeftIconView; + + private ImageView mRightIconView; + + private ProgressBar mCircularProgressBar; + + private ProgressBar mHorizontalProgressBar; + + private int mBackgroundResource = 0; + + private Drawable mBackgroundDrawable; + + private int mFrameResource = 0; + + private int mTextColor = 0; + + private CharSequence mTitle = null; + + private int mTitleColor = 0; + + private ContextMenuBuilder mContextMenu; + private MenuDialogHelper mContextMenuHelper; + + private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; + private long mVolumeKeyUpTime; + + private KeyguardManager mKeyguardManager = null; + + private boolean mSearchKeyDownReceived; + + private boolean mKeycodeCallTimeoutActive = false; + + private boolean mKeycodeCameraTimeoutActive = false; + + static final int MSG_MENU_LONG_PRESS = 1; + static final int MSG_MENU_LONG_PRESS_COMPLETE = 2; + static final int MSG_CALL_LONG_PRESS = 3; + static final int MSG_CALL_LONG_PRESS_COMPLETE = 4; + static final int MSG_CAMERA_LONG_PRESS = 5; + static final int MSG_CAMERA_LONG_PRESS_COMPLETE = 6; + + private final Handler mKeycodeMenuTimeoutHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_MENU_LONG_PRESS: { + if (mPanelChordingKey == 0) return; + // Before actually doing the long press, enqueue another + // message and do the processing there. This helps if + // the app isn't being responsive, and finally woke up -- + // if the window manager wasn't told about it processing + // the down key for too long, it would enqueue the key up + // at a time after the timeout of this message. So we go + // through another message, to make sure we process an up + // before continuing. + mKeycodeMenuTimeoutHandler.sendEmptyMessage( + MSG_MENU_LONG_PRESS_COMPLETE); + break; + } + case MSG_CALL_LONG_PRESS: { + if (!mKeycodeCallTimeoutActive) return; + // See above. + mKeycodeMenuTimeoutHandler.sendEmptyMessage( + MSG_CALL_LONG_PRESS_COMPLETE); + break; + } + case MSG_CAMERA_LONG_PRESS: { + if (!mKeycodeCameraTimeoutActive) return; + // See above. + mKeycodeMenuTimeoutHandler.sendEmptyMessage( + MSG_CAMERA_LONG_PRESS_COMPLETE); + break; + } + case MSG_MENU_LONG_PRESS_COMPLETE: { + if (mPanelChordingKey == 0) return; + mPanelChordingKey = 0; + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + InputMethodManager imm = (InputMethodManager) + getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + imm.showSoftInputUnchecked(InputMethodManager.SHOW_FORCED); + } + } break; + case MSG_CALL_LONG_PRESS_COMPLETE: { + if (!mKeycodeCallTimeoutActive) return; + mKeycodeCallTimeoutActive = false; + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + // launch the VoiceDialer + Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + sendCloseSystemWindows(); + getContext().startActivity(intent); + } catch (ActivityNotFoundException e) { + startCallActivity(); + } + } break; + case MSG_CAMERA_LONG_PRESS_COMPLETE: { + if (!mKeycodeCameraTimeoutActive) return; + mKeycodeCameraTimeoutActive = false; + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + // Broadcast an intent that the Camera button was longpressed + Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj); + getContext().sendOrderedBroadcast(intent, null); + sendCloseSystemWindows(); + } break; + } + } + }; + + public PhoneWindow(Context context) { + super(context); + mLayoutInflater = LayoutInflater.from(context); + } + + @Override + public final void setContainer(Window container) { + super.setContainer(container); + } + + @Override + public boolean requestFeature(int featureId) { + if (mContentParent != null) { + throw new AndroidRuntimeException("requestFeature() must be called before adding content"); + } + final int features = getFeatures(); + if ((features != DEFAULT_FEATURES) && (featureId == FEATURE_CUSTOM_TITLE)) { + + /* Another feature is enabled and the user is trying to enable the custom title feature */ + throw new AndroidRuntimeException("You cannot combine custom titles with other title features"); + } + if (((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) && (featureId != FEATURE_CUSTOM_TITLE)) { + + /* 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"); + } + /* FEATURE_OPENGL disabled for 1.0 + if (featureId == FEATURE_OPENGL) { + getAttributes().memoryType = WindowManager.LayoutParams.MEMORY_TYPE_GPU; + } + */ + return super.requestFeature(featureId); + } + + @Override + public void setContentView(int layoutResID) { + if (mContentParent == null) { + installDecor(); + } else { + mContentParent.removeAllViews(); + } + mLayoutInflater.inflate(layoutResID, mContentParent); + final Callback cb = getCallback(); + if (cb != null) { + cb.onContentChanged(); + } + } + + @Override + public void setContentView(View view) { + setContentView(view, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT)); + } + + @Override + public void setContentView(View view, ViewGroup.LayoutParams params) { + if (mContentParent == null) { + installDecor(); + } else { + mContentParent.removeAllViews(); + } + mContentParent.addView(view, params); + final Callback cb = getCallback(); + if (cb != null) { + cb.onContentChanged(); + } + } + + @Override + public void addContentView(View view, ViewGroup.LayoutParams params) { + if (mContentParent == null) { + installDecor(); + } + mContentParent.addView(view, params); + final Callback cb = getCallback(); + if (cb != null) { + cb.onContentChanged(); + } + } + + @Override + public View getCurrentFocus() { + return mDecor != null ? mDecor.findFocus() : null; + } + + @Override + public boolean isFloating() { + return mIsFloating; + } + + /** + * Return a LayoutInflater instance that can be used to inflate XML view layout + * resources for use in this Window. + * + * @return LayoutInflater The shared LayoutInflater. + */ + @Override + public LayoutInflater getLayoutInflater() { + return mLayoutInflater; + } + + @Override + public void setTitle(CharSequence title) { + if (mTitleView != null) { + mTitleView.setText(title); + } + mTitle = title; + } + + @Override + public void setTitleColor(int textColor) { + if (mTitleView != null) { + mTitleView.setTextColor(textColor); + } + mTitleColor = textColor; + } + + /** + * Prepares the panel to either be opened or chorded. This creates the Menu + * instance for the panel and populates it via the Activity callbacks. + * + * @param st The panel state to prepare. + * @param event The event that triggered the preparing of the panel. + * @return Whether the panel was prepared. If the panel should not be shown, + * returns false. + */ + public final boolean preparePanel(PanelFeatureState st, KeyEvent event) { + // 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); + } + + final Callback cb = getCallback(); + + if (cb != null) { + st.createdPanelView = cb.onCreatePanelView(st.featureId); + } + + 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; + } + // Call callback, and return if it doesn't want to display menu + if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) { + // Ditch the menu created above + st.menu = null; + + return false; + } + } + + // Callback and return if the callback does not want to show the menu + if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) { + return false; + } + + // Set the proper keymap + KeyCharacterMap kmap = KeyCharacterMap.load(event != null ? event.getDeviceId() : 0); + st.qwertyMode = kmap.getKeyboardType() != KeyCharacterMap.NUMERIC; + st.menu.setQwertyMode(st.qwertyMode); + } + + // Set other state + st.isPrepared = true; + st.isHandled = false; + mPreparedPanel = st; + + return true; + } + + @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; + + 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); + + // Re-open the same menu + reopenMenu(false); + + // Restore state + menuBuilder.restoreHierarchyState(state); + + } 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. + + // Allow the callback to create a new panel view + st.createdPanelView = null; + + // Causes the decor view to be recreated + st.refreshDecorView = true; + + ((MenuBuilder) st.menu).clearMenuViews(); + } + + @Override + public final void openPanel(int featureId, KeyEvent event) { + openPanel(getPanelState(featureId, true), event); + } + + private void openPanel(PanelFeatureState st, KeyEvent event) { + // System.out.println("Open panel: isOpen=" + st.isOpen); + + // Already open, return + if (st.isOpen) { + return; + } + + Callback cb = getCallback(); + if ((cb != null) && (!cb.onMenuOpened(st.featureId, st.menu))) { + // Callback doesn't want the menu to open, reset any state + closePanel(st, true); + return; + } + + final WindowManager wm = getWindowManager(); + if (wm == null) { + return; + } + + // Prepare panel (should have been done before, but just in case) + if (!preparePanel(st, event)) { + return; + } + + if (st.decorView == null || st.refreshDecorView) { + if (st.decorView == null) { + // Initialize the panel decor, this will populate st.decorView + if (!initializePanelDecor(st) || (st.decorView == null)) + return; + } else if (st.refreshDecorView && (st.decorView.getChildCount() > 0)) { + // Decor needs refreshing, so remove its views + st.decorView.removeAllViews(); + } + + // This will populate st.shownPanelView + if (!initializePanelContent(st) || (st.shownPanelView == null)) { + return; + } + + ViewGroup.LayoutParams lp = st.shownPanelView.getLayoutParams(); + if (lp == null) { + lp = new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); + } + + int backgroundResId; + if (lp.width == ViewGroup.LayoutParams.FILL_PARENT) { + // If the contents is fill parent for the width, set the + // corresponding background + backgroundResId = st.fullBackground; + } else { + // Otherwise, set the normal panel background + backgroundResId = st.background; + } + st.decorView.setWindowBackground(getContext().getResources().getDrawable( + backgroundResId)); + + + st.decorView.addView(st.shownPanelView, lp); + + /* + * Give focus to the view, if it or one of its children does not + * already have it. + */ + if (!st.shownPanelView.hasFocus()) { + st.shownPanelView.requestFocus(); + } + } + + st.isOpen = true; + st.isHandled = false; + + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + WRAP_CONTENT, WRAP_CONTENT, + st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, + WindowManager.LayoutParams.FLAG_DITHER + | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, + st.decorView.mDefaultOpacity); + + lp.gravity = st.gravity; + lp.windowAnimations = st.windowAnimations; + wm.addView(st.decorView, lp); + // Log.v(TAG, "Adding main menu to window manager."); + } + + @Override + public final void closePanel(int featureId) { + if (featureId == FEATURE_CONTEXT_MENU) { + closeContextMenu(); + } else { + closePanel(getPanelState(featureId, true), true); + } + } + + /** + * Closes the given panel. + * + * @param st The panel to be closed. + * @param doCallback Whether to notify the callback that the panel was + * closed. If the panel is in the process of re-opening or + * opening another panel (e.g., menu opening a sub menu), the + * callback should not happen and this variable should be false. + * In addition, this method internally will only perform the + * callback if the panel is open. + */ + public final void closePanel(PanelFeatureState st, boolean doCallback) { + // System.out.println("Close panel: isOpen=" + st.isOpen); + final ViewManager wm = getWindowManager(); + if ((wm != null) && st.isOpen) { + if (st.decorView != null) { + wm.removeView(st.decorView); + // Log.v(TAG, "Removing main menu from window manager."); + } + + if (doCallback) { + callOnPanelClosed(st.featureId, st, null); + } + } + st.isPrepared = false; + st.isHandled = false; + st.isOpen = false; + + // This view is no longer shown, so null it out + st.shownPanelView = null; + + if (st.isInExpandedMode) { + // Next time the menu opens, it should not be in expanded mode, so + // force a refresh of the decor + st.refreshDecorView = true; + st.isInExpandedMode = false; + } + + if (mPreparedPanel == st) { + mPreparedPanel = null; + mPanelChordingKey = 0; + } + } + + @Override + public final void togglePanel(int featureId, KeyEvent event) { + PanelFeatureState st = getPanelState(featureId, true); + if (st.isOpen) { + closePanel(st, true); + } else { + openPanel(st, event); + } + } + + /** + * Called when the panel key is pushed down. + * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}. + * @param event The key event. + * @return Whether the key was handled. + */ + public final boolean onKeyDownPanel(int featureId, KeyEvent event) { + // The panel key was pushed, so set the chording key + mPanelChordingKey = event.getKeyCode(); + + PanelFeatureState st = getPanelState(featureId, true); + if (!st.isOpen) { + if (getContext().getResources().getConfiguration().keyboard + == Configuration.KEYBOARD_NOKEYS) { + mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); + mKeycodeMenuTimeoutHandler.sendMessageDelayed( + mKeycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS), + ViewConfiguration.getLongPressTimeout()); + } + return preparePanel(st, event); + } + + return false; + } + + /** + * Called when the panel key is released. + * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}. + * @param event The key event. + */ + public final void onKeyUpPanel(int featureId, KeyEvent event) { + // The panel key was released, so clear the chording key + if (mPanelChordingKey != 0) { + mPanelChordingKey = 0; + mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); + + boolean playSoundEffect = false; + PanelFeatureState st = getPanelState(featureId, true); + 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; + + // Close menu + closePanel(st, true); + + } else if (st.isPrepared) { + + // Write 'menu opened' to event log + EventLog.writeEvent(50001, 0); + + // Show menu + openPanel(st, event); + + playSoundEffect = true; + } + + if (playSoundEffect) { + AudioManager audioManager = (AudioManager) getContext().getSystemService( + Context.AUDIO_SERVICE); + if (audioManager != null) { + audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); + } else { + Log.w(TAG, "Couldn't get audio manager"); + } + } + } + } + + @Override + public final void closeAllPanels() { + final ViewManager wm = getWindowManager(); + if (wm == null) { + return; + } + + final PanelFeatureState[] panels = mPanels; + final int N = panels != null ? panels.length : 0; + for (int i = 0; i < N; i++) { + final PanelFeatureState panel = panels[i]; + if (panel != null) { + closePanel(panel, true); + } + } + + closeContextMenu(); + } + + /** + * Closes the context menu. This notifies the menu logic of the close, along + * with dismissing it from the UI. + */ + private synchronized void closeContextMenu() { + if (mContextMenu != null) { + mContextMenu.close(); + dismissContextMenu(); + } + } + + /** + * Dismisses just the context menu UI. To close the context menu, use + * {@link #closeContextMenu()}. + */ + private synchronized void dismissContextMenu() { + mContextMenu = null; + + if (mContextMenuHelper != null) { + mContextMenuHelper.dismiss(); + mContextMenuHelper = null; + } + } + + @Override + public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) { + return performPanelShortcut(getPanelState(featureId, true), keyCode, event, flags); + } + + private boolean performPanelShortcut(PanelFeatureState st, int keyCode, KeyEvent event, + int flags) { + if (event.isSystem() || (st == null)) { + return false; + } + + boolean handled = false; + + // Only try to perform menu shortcuts if preparePanel returned true (possible false + // return value from application not wanting to show the menu). + if ((st.isPrepared || preparePanel(st, event)) && st.menu != null) { + // The menu is prepared now, perform the shortcut on it + handled = st.menu.performShortcut(keyCode, event, flags); + } + + if (handled) { + // Mark as handled + st.isHandled = true; + + if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0) { + closePanel(st, true); + } + } + + return handled; + } + + @Override + public boolean performPanelIdentifierAction(int featureId, int id, int flags) { + + PanelFeatureState st = getPanelState(featureId, true); + if (!preparePanel(st, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU))) { + return false; + } + if (st.menu == null) { + return false; + } + + boolean res = st.menu.performIdentifierAction(id, flags); + + closePanel(st, true); + + return res; + } + + public PanelFeatureState findMenuPanel(Menu menu) { + final PanelFeatureState[] panels = mPanels; + final int N = panels != null ? panels.length : 0; + for (int i = 0; i < N; i++) { + final PanelFeatureState panel = panels[i]; + if (panel != null && panel.menu == menu) { + return panel; + } + } + return null; + } + + public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { + final Callback cb = getCallback(); + if (cb != null) { + final PanelFeatureState panel = findMenuPanel(menu.getRootMenu()); + if (panel != null) { + return cb.onMenuItemSelected(panel.featureId, item); + } + } + return false; + } + + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + final PanelFeatureState panel = findMenuPanel(menu); + if (panel != null) { + // Close the panel and only do the callback if the menu is being + // closed + // completely, not if opening a sub menu + closePanel(panel, allMenusAreClosing); + } + } + + public void onCloseSubMenu(SubMenuBuilder subMenu) { + final Menu parentMenu = subMenu.getRootMenu(); + final PanelFeatureState panel = findMenuPanel(parentMenu); + + // Callback + if (panel != null) { + callOnPanelClosed(panel.featureId, panel, parentMenu); + closePanel(panel, true); + } + } + + public boolean onSubMenuSelected(final SubMenuBuilder subMenu) { + if (!subMenu.hasVisibleItems()) { + return true; + } + + // The window manager will give us a valid window token + new MenuDialogHelper(subMenu).show(null); + + return true; + } + + public void onMenuModeChange(MenuBuilder menu) { + reopenMenu(true); + } + + private void reopenMenu(boolean toggleMenuMode) { + PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); + + // Save the future expanded mode state since closePanel will reset it + boolean newExpandedMode = toggleMenuMode ? !st.isInExpandedMode : st.isInExpandedMode; + + st.refreshDecorView = true; + closePanel(st, false); + + // Set the expanded mode state + st.isInExpandedMode = newExpandedMode; + + openPanel(st, null); + } + + /** + * Initializes the menu associated with the given panel feature state. You + * must at the very least set PanelFeatureState.menu to the Menu to be + * associated with the given panel state. The default implementation creates + * a new menu for the panel state. + * + * @param st The panel whose menu is being initialized. + * @return Whether the initialization was successful. + */ + protected boolean initializePanelMenu(final PanelFeatureState st) { + final MenuBuilder menu = new MenuBuilder(getContext()); + + menu.setCallback(this); + st.setMenu(menu); + + return true; + } + + /** + * Perform initial setup of a panel. This should at the very least set the + * style information in the PanelFeatureState and must set + * PanelFeatureState.decor to the panel's window decor view. + * + * @param st The panel being initialized. + */ + protected boolean initializePanelDecor(PanelFeatureState st) { + st.decorView = new DecorView(getContext(), st.featureId); + st.gravity = Gravity.CENTER | Gravity.BOTTOM; + st.setStyle(getContext()); + + return true; + } + + /** + * Initializes the panel associated with the panel feature state. You must + * at the very least set PanelFeatureState.panel to the View implementing + * its contents. The default implementation gets the panel from the menu. + * + * @param st The panel state being initialized. + * @return Whether the initialization was successful. + */ + protected boolean initializePanelContent(PanelFeatureState st) { + + if (st.createdPanelView != null) { + st.shownPanelView = st.createdPanelView; + return true; + } + + final MenuBuilder menu = (MenuBuilder)st.menu; + if (menu == null) { + return false; + } + + st.shownPanelView = menu.getMenuView((st.isInExpandedMode) ? MenuBuilder.TYPE_EXPANDED + : MenuBuilder.TYPE_ICON, st.decorView); + + if (st.shownPanelView != null) { + // Use the menu View's default animations if it has any + final int defaultAnimations = ((MenuView) st.shownPanelView).getWindowAnimations(); + if (defaultAnimations != 0) { + st.windowAnimations = defaultAnimations; + } + return true; + } else { + return false; + } + } + + @Override + public boolean performContextMenuIdentifierAction(int id, int flags) { + return (mContextMenu != null) ? mContextMenu.performIdentifierAction(id, flags) : false; + } + + @Override + public final void setBackgroundDrawable(Drawable drawable) { + if (drawable != mBackgroundDrawable) { + mBackgroundResource = 0; + mBackgroundDrawable = drawable; + if (mDecor != null) { + mDecor.setWindowBackground(drawable); + } + } + } + + @Override + public final void setFeatureDrawableResource(int featureId, int resId) { + if (resId != 0) { + DrawableFeatureState st = getDrawableState(featureId, true); + if (st.resid != resId) { + st.resid = resId; + st.uri = null; + st.local = getContext().getResources().getDrawable(resId); + updateDrawable(featureId, st, false); + } + } else { + setFeatureDrawable(featureId, null); + } + } + + @Override + public final void setFeatureDrawableUri(int featureId, Uri uri) { + if (uri != null) { + DrawableFeatureState st = getDrawableState(featureId, true); + if (st.uri == null || !st.uri.equals(uri)) { + st.resid = 0; + st.uri = uri; + st.local = loadImageURI(uri); + updateDrawable(featureId, st, false); + } + } else { + setFeatureDrawable(featureId, null); + } + } + + @Override + public final void setFeatureDrawable(int featureId, Drawable drawable) { + DrawableFeatureState st = getDrawableState(featureId, true); + st.resid = 0; + st.uri = null; + if (st.local != drawable) { + st.local = drawable; + updateDrawable(featureId, st, false); + } + } + + @Override + public void setFeatureDrawableAlpha(int featureId, int alpha) { + DrawableFeatureState st = getDrawableState(featureId, true); + if (st.alpha != alpha) { + st.alpha = alpha; + updateDrawable(featureId, st, false); + } + } + + protected final void setFeatureDefaultDrawable(int featureId, Drawable drawable) { + DrawableFeatureState st = getDrawableState(featureId, true); + if (st.def != drawable) { + st.def = drawable; + updateDrawable(featureId, st, false); + } + } + + @Override + public final void setFeatureInt(int featureId, int value) { + // XXX Should do more management (as with drawable features) to + // deal with interactions between multiple window policies. + updateInt(featureId, value, false); + } + + /** + * Update the state of a drawable feature. This should be called, for every + * drawable feature supported, as part of onActive(), to make sure that the + * contents of a containing window is properly updated. + * + * @see #onActive + * @param featureId The desired drawable feature to change. + * @param fromActive Always true when called from onActive(). + */ + protected final void updateDrawable(int featureId, boolean fromActive) { + final DrawableFeatureState st = getDrawableState(featureId, false); + if (st != null) { + updateDrawable(featureId, st, fromActive); + } + } + + /** + * Called when a Drawable feature changes, for the window to update its + * graphics. + * + * @param featureId The feature being changed. + * @param drawable The new Drawable to show, or null if none. + * @param alpha The new alpha blending of the Drawable. + */ + protected void onDrawableChanged(int featureId, Drawable drawable, int alpha) { + ImageView view; + if (featureId == FEATURE_LEFT_ICON) { + view = getLeftIconView(); + } else if (featureId == FEATURE_RIGHT_ICON) { + view = getRightIconView(); + } else { + return; + } + + if (drawable != null) { + drawable.setAlpha(alpha); + view.setImageDrawable(drawable); + view.setVisibility(View.VISIBLE); + } else { + view.setVisibility(View.GONE); + } + } + + /** + * Called when an int feature changes, for the window to update its + * graphics. + * + * @param featureId The feature being changed. + * @param value The new integer value. + */ + protected void onIntChanged(int featureId, int value) { + if (featureId == FEATURE_PROGRESS || featureId == FEATURE_INDETERMINATE_PROGRESS) { + updateProgressBars(value); + } else if (featureId == FEATURE_CUSTOM_TITLE) { + FrameLayout titleContainer = (FrameLayout) findViewById(com.android.internal.R.id.title_container); + if (titleContainer != null) { + mLayoutInflater.inflate(value, titleContainer); + } + } + } + + /** + * Updates the progress bars that are shown in the title bar. + * + * @param value Can be one of {@link Window#PROGRESS_VISIBILITY_ON}, + * {@link Window#PROGRESS_VISIBILITY_OFF}, + * {@link Window#PROGRESS_INDETERMINATE_ON}, + * {@link Window#PROGRESS_INDETERMINATE_OFF}, or a value + * starting at {@link Window#PROGRESS_START} through + * {@link Window#PROGRESS_END} for setting the default + * progress (if {@link Window#PROGRESS_END} is given, + * the progress bar widgets in the title will be hidden after an + * animation), a value between + * {@link Window#PROGRESS_SECONDARY_START} - + * {@link Window#PROGRESS_SECONDARY_END} for the + * secondary progress (if + * {@link Window#PROGRESS_SECONDARY_END} is given, the + * progress bar widgets will still be shown with the secondary + * progress bar will be completely filled in.) + */ + private void updateProgressBars(int value) { + ProgressBar circularProgressBar = getCircularProgressBar(true); + ProgressBar horizontalProgressBar = getHorizontalProgressBar(true); + + final int features = getLocalFeatures(); + if (value == PROGRESS_VISIBILITY_ON) { + if ((features & (1 << FEATURE_PROGRESS)) != 0) { + int level = horizontalProgressBar.getProgress(); + int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ? + View.VISIBLE : View.INVISIBLE; + horizontalProgressBar.setVisibility(visibility); + } + if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { + circularProgressBar.setVisibility(View.VISIBLE); + } + } else if (value == PROGRESS_VISIBILITY_OFF) { + if ((features & (1 << FEATURE_PROGRESS)) != 0) { + horizontalProgressBar.setVisibility(View.GONE); + } + if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { + circularProgressBar.setVisibility(View.GONE); + } + } else if (value == PROGRESS_INDETERMINATE_ON) { + horizontalProgressBar.setIndeterminate(true); + } else if (value == PROGRESS_INDETERMINATE_OFF) { + horizontalProgressBar.setIndeterminate(false); + } else if (PROGRESS_START <= value && value <= PROGRESS_END) { + // We want to set the progress value before testing for visibility + // so that when the progress bar becomes visible again, it has the + // correct level. + horizontalProgressBar.setProgress(value - PROGRESS_START); + + if (value < PROGRESS_END) { + showProgressBars(horizontalProgressBar, circularProgressBar); + } else { + hideProgressBars(horizontalProgressBar, circularProgressBar); + } + } else if (PROGRESS_SECONDARY_START <= value && value <= PROGRESS_SECONDARY_END) { + horizontalProgressBar.setSecondaryProgress(value - PROGRESS_SECONDARY_START); + + showProgressBars(horizontalProgressBar, circularProgressBar); + } + + } + + private void showProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) { + final int features = getLocalFeatures(); + if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 && + spinnyProgressBar.getVisibility() == View.INVISIBLE) { + spinnyProgressBar.setVisibility(View.VISIBLE); + } + // Only show the progress bars if the primary progress is not complete + if ((features & (1 << FEATURE_PROGRESS)) != 0 && + horizontalProgressBar.getProgress() < 10000) { + horizontalProgressBar.setVisibility(View.VISIBLE); + } + } + + private void hideProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) { + final int features = getLocalFeatures(); + Animation anim = AnimationUtils.loadAnimation(getContext(), com.android.internal.R.anim.fade_out); + anim.setDuration(1000); + if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 && + spinnyProgressBar.getVisibility() == View.VISIBLE) { + spinnyProgressBar.startAnimation(anim); + spinnyProgressBar.setVisibility(View.INVISIBLE); + } + if ((features & (1 << FEATURE_PROGRESS)) != 0 && + horizontalProgressBar.getVisibility() == View.VISIBLE) { + horizontalProgressBar.startAnimation(anim); + horizontalProgressBar.setVisibility(View.INVISIBLE); + } + } + + /** + * Request that key events come to this activity. Use this if your activity + * has no views with focus, but the activity still wants a chance to process + * key events. + */ + @Override + public void takeKeyEvents(boolean get) { + mDecor.setFocusable(get); + } + + @Override + public boolean superDispatchKeyEvent(KeyEvent event) { + return mDecor.superDispatchKeyEvent(event); + } + + @Override + public boolean superDispatchTouchEvent(MotionEvent event) { + return mDecor.superDispatchTouchEvent(event); + } + + @Override + public boolean superDispatchTrackballEvent(MotionEvent event) { + return mDecor.superDispatchTrackballEvent(event); + } + + /** + * A key was pressed down and not handled by anything else in the window. + * + * @see #onKeyUp + * @see android.view.KeyEvent + */ + protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) { + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: { + AudioManager audioManager = (AudioManager) getContext().getSystemService( + Context.AUDIO_SERVICE); + if (audioManager != null) { + /* + * Adjust the volume in on key down since it is more + * responsive to the user. + */ + audioManager.adjustSuggestedStreamVolume( + keyCode == KeyEvent.KEYCODE_VOLUME_UP + ? AudioManager.ADJUST_RAISE + : AudioManager.ADJUST_LOWER, + mVolumeControlStreamType, + AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE); + } + return true; + } + + case KeyEvent.KEYCODE_MUTE: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: { + Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, event); + getContext().sendOrderedBroadcast(intent, null); + return true; + } + + case KeyEvent.KEYCODE_CAMERA: { + if (getKeyguardManager().inKeyguardRestrictedInputMode()) { + break; + } + if (event.getRepeatCount() > 0) break; + mKeycodeCameraTimeoutActive = true; + mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); + Message message = mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CAMERA_LONG_PRESS); + message.obj = event; + mKeycodeMenuTimeoutHandler.sendMessageDelayed(message, + ViewConfiguration.getLongPressTimeout()); + return true; + } + + case KeyEvent.KEYCODE_MENU: { + if (event.getRepeatCount() > 0) break; + onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event); + return true; + } + + case KeyEvent.KEYCODE_BACK: { + if (event.getRepeatCount() > 0) break; + if (featureId < 0) break; + if (featureId == FEATURE_OPTIONS_PANEL) { + PanelFeatureState st = getPanelState(featureId, false); + if (st != null && st.isInExpandedMode) { + // If the user is in an expanded menu and hits back, it + // should go back to the icon menu + reopenMenu(true); + return true; + } + } + closePanel(featureId); + return true; + } + + case KeyEvent.KEYCODE_CALL: { + if (getKeyguardManager().inKeyguardRestrictedInputMode()) { + break; + } + if (event.getRepeatCount() > 0) break; + mKeycodeCallTimeoutActive = true; + mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); + mKeycodeMenuTimeoutHandler.sendMessageDelayed( + mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CALL_LONG_PRESS), + ViewConfiguration.getLongPressTimeout()); + return true; + } + + case KeyEvent.KEYCODE_SEARCH: { + if (event.getRepeatCount() == 0) { + mSearchKeyDownReceived = true; + } + break; + } + } + + return false; + } + + /** + * @return A handle to the keyguard manager. + */ + private KeyguardManager getKeyguardManager() { + if (mKeyguardManager == null) { + mKeyguardManager = (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE); + } + return mKeyguardManager; + } + + /** + * A key was released and not handled by anything else in the window. + * + * @see #onKeyDown + * @see android.view.KeyEvent + */ + protected boolean onKeyUp(int featureId, int keyCode, KeyEvent event) { + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: { + AudioManager audioManager = (AudioManager) getContext().getSystemService( + Context.AUDIO_SERVICE); + if (audioManager != null) { + /* + * Play a sound. This is done on key up since we don't want the + * sound to play when a user holds down volume down to mute. + */ + audioManager.adjustSuggestedStreamVolume( + AudioManager.ADJUST_SAME, + mVolumeControlStreamType, + AudioManager.FLAG_PLAY_SOUND); + mVolumeKeyUpTime = SystemClock.uptimeMillis(); + } + return true; + } + + case KeyEvent.KEYCODE_MENU: { + onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId, + event); + return true; + } + + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: { + Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, event); + getContext().sendOrderedBroadcast(intent, null); + return true; + } + + case KeyEvent.KEYCODE_CAMERA: { + if (getKeyguardManager().inKeyguardRestrictedInputMode()) { + break; + } + if (event.getRepeatCount() > 0) break; // Can a key up event repeat? + mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); + if (!mKeycodeCameraTimeoutActive) break; + mKeycodeCameraTimeoutActive = false; + // Add short press behavior here if desired + return true; + } + + case KeyEvent.KEYCODE_CALL: { + if (getKeyguardManager().inKeyguardRestrictedInputMode()) { + break; + } + if (event.getRepeatCount() > 0) break; + mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); + if (!mKeycodeCallTimeoutActive) break; + mKeycodeCallTimeoutActive = false; + startCallActivity(); + return true; + } + + case KeyEvent.KEYCODE_SEARCH: { + /* + * Do this in onKeyUp since the Search key is also used for + * chording quick launch shortcuts. + */ + if (getKeyguardManager().inKeyguardRestrictedInputMode() || + !mSearchKeyDownReceived) { + break; + } + mSearchKeyDownReceived = false; + launchDefaultSearch(); + return true; + } + } + + return false; + } + + private void startCallActivity() { + sendCloseSystemWindows(); + Intent intent = new Intent(Intent.ACTION_CALL_BUTTON); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + getContext().startActivity(intent); + } + + @Override + protected void onActive() { + } + + @Override + public final View getDecorView() { + if (mDecor == null) { + installDecor(); + } + return mDecor; + } + + @Override + public final View peekDecorView() { + return mDecor; + } + + 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"; + + /** {@inheritDoc} */ + @Override + public Bundle saveHierarchyState() { + Bundle outState = new Bundle(); + if (mContentParent == null) { + return outState; + } + + SparseArray states = new SparseArray(); + mContentParent.saveHierarchyState(states); + outState.putSparseParcelableArray(VIEWS_TAG, states); + + // save the focused view id + View focusedView = mContentParent.findFocus(); + if (focusedView != null) { + if (focusedView.getId() != View.NO_ID) { + outState.putInt(FOCUSED_ID_TAG, focusedView.getId()); + } else { + if (Config.LOGD) { + Log.d(TAG, "couldn't save which view has focus because the focused view " + + focusedView + " has no id."); + } + } + } + + // save the panels + SparseArray panelStates = new SparseArray(); + savePanelState(panelStates); + if (panelStates.size() > 0) { + outState.putSparseParcelableArray(PANELS_TAG, panelStates); + } + + return outState; + } + + /** {@inheritDoc} */ + @Override + public void restoreHierarchyState(Bundle savedInstanceState) { + if (mContentParent == null) { + return; + } + + SparseArray savedStates + = savedInstanceState.getSparseParcelableArray(VIEWS_TAG); + if (savedStates != null) { + mContentParent.restoreHierarchyState(savedStates); + } + + // restore the focused view + int focusedViewId = savedInstanceState.getInt(FOCUSED_ID_TAG, View.NO_ID); + if (focusedViewId != View.NO_ID) { + View needsFocus = mContentParent.findViewById(focusedViewId); + if (needsFocus != null) { + needsFocus.requestFocus(); + } else { + Log.w(TAG, + "Previously focused view reported id " + focusedViewId + + " during save, but can't be found during restore."); + } + } + + // restore the panels + SparseArray panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG); + if (panelStates != null) { + restorePanelState(panelStates); + } + } + + /** + * Invoked when the panels should freeze their state. + * + * @param icicles Save state into this. This is usually indexed by the + * featureId. This will be given to {@link #restorePanelState} in the + * future. + */ + private void savePanelState(SparseArray icicles) { + PanelFeatureState[] panels = mPanels; + if (panels == null) { + return; + } + + for (int curFeatureId = panels.length - 1; curFeatureId >= 0; curFeatureId--) { + if (panels[curFeatureId] != null) { + icicles.put(curFeatureId, panels[curFeatureId].onSaveInstanceState()); + } + } + } + + /** + * Invoked when the panels should thaw their state from a previously frozen state. + * + * @param icicles The state saved by {@link #savePanelState} that needs to be thawed. + */ + private void restorePanelState(SparseArray icicles) { + PanelFeatureState st; + for (int curFeatureId = icicles.size() - 1; curFeatureId >= 0; curFeatureId--) { + st = getPanelState(curFeatureId, false /* required */); + if (st == null) { + // The panel must not have been required, and is currently not around, skip it + continue; + } + + st.onRestoreInstanceState(icicles.get(curFeatureId)); + } + + /* + * Implementation note: call openPanelsAfterRestore later to actually open the + * restored panels. + */ + } + + /** + * Opens the panels that have had their state restored. This should be + * called sometime after {@link #restorePanelState} when it is safe to add + * to the window manager. + */ + private void openPanelsAfterRestore() { + PanelFeatureState[] panels = mPanels; + + if (panels == null) { + return; + } + + PanelFeatureState st; + for (int i = panels.length - 1; i >= 0; i--) { + st = panels[i]; + if ((st != null) && st.isOpen) { + // Clear st.isOpen (openPanel will not open if it's already open) + st.isOpen = false; + openPanel(st, null); + } + } + } + + private final class DecorView extends FrameLayout { + /* package */int mDefaultOpacity = PixelFormat.OPAQUE; + + /** The feature ID of the panel, or -1 if this is the application's DecorView */ + private final int mFeatureId; + + private final Rect mDrawingBounds = new Rect(); + + private final Rect mBackgroundPadding = new Rect(); + + private final Rect mFramePadding = new Rect(); + + private final Rect mFrameOffsets = new Rect(); + + private final Paint mBlackPaint = new Paint(); + + private boolean mChanging; + + private Drawable mMenuBackground; + private boolean mWatchingForMenu; + private int mDownY; + + public DecorView(Context context, int featureId) { + super(context); + mFeatureId = featureId; + mBlackPaint.setColor(0xFF000000); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + final int keyCode = event.getKeyCode(); + final boolean isDown = event.getAction() == KeyEvent.ACTION_DOWN; + + /* + * If the user hits another key within the play sound delay, then + * cancel the sound + */ + if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP + && mVolumeKeyUpTime + VolumePanel.PLAY_SOUND_DELAY + > SystemClock.uptimeMillis()) { + /* + * The user has hit another key during the delay (e.g., 300ms) + * since the last volume key up, so cancel any sounds. + */ + AudioManager audioManager = (AudioManager) getContext().getSystemService( + Context.AUDIO_SERVICE); + if (audioManager != null) { + audioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_SAME, + mVolumeControlStreamType, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); + } + } + + if (isDown && (event.getRepeatCount() == 0)) { + // First handle chording of panel key: if a panel key is held + // but not released, try to execute a shortcut in it. + if ((mPanelChordingKey > 0) && (mPanelChordingKey != keyCode)) { + // Perform the shortcut (mPreparedPanel can be null since + // global shortcuts (such as search) don't rely on a + // prepared panel or menu). + boolean handled = performPanelShortcut(mPreparedPanel, keyCode, event, + Menu.FLAG_PERFORM_NO_CLOSE); + + if (!handled) { + /* + * If not handled, then pass it to the view hierarchy + * and anyone else that may be interested. + */ + handled = dispatchKeyShortcutEvent(event); + + if (handled && mPreparedPanel != null) { + mPreparedPanel.isHandled = true; + } + } + + if (handled) { + return true; + } + } + + // If a panel is open, perform a shortcut on it without the + // chorded panel key + if ((mPreparedPanel != null) && mPreparedPanel.isOpen) { + if (performPanelShortcut(mPreparedPanel, keyCode, event, 0)) { + return true; + } + } + } + + final Callback cb = getCallback(); + final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event) + : super.dispatchKeyEvent(event); + if (handled) { + return true; + } + return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event) + : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + final Callback cb = getCallback(); + return cb != null && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super + .dispatchTouchEvent(ev); + } + + @Override + public boolean dispatchTrackballEvent(MotionEvent ev) { + final Callback cb = getCallback(); + return cb != null && mFeatureId < 0 ? cb.dispatchTrackballEvent(ev) : super + .dispatchTrackballEvent(ev); + } + + public boolean superDispatchKeyEvent(KeyEvent event) { + return super.dispatchKeyEvent(event); + } + + public boolean superDispatchTouchEvent(MotionEvent event) { + return super.dispatchTouchEvent(event); + } + + public boolean superDispatchTrackballEvent(MotionEvent event) { + return super.dispatchTrackballEvent(event); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return onInterceptTouchEvent(event); + } + + private boolean isOutOfBounds(int x, int y) { + return x < -5 || y < -5 || x > (getWidth() + 5) + || y > (getHeight() + 5); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + int action = event.getAction(); + if (mFeatureId >= 0) { + if (action == MotionEvent.ACTION_DOWN) { + int x = (int)event.getX(); + int y = (int)event.getY(); + if (isOutOfBounds(x, y)) { + closePanel(mFeatureId); + return true; + } + } + } + + if (!SWEEP_OPEN_MENU) { + return false; + } + + if (mFeatureId >= 0) { + if (action == MotionEvent.ACTION_DOWN) { + Log.i(TAG, "Watchiing!"); + mWatchingForMenu = true; + mDownY = (int) event.getY(); + return false; + } + + if (!mWatchingForMenu) { + return false; + } + + int y = (int)event.getY(); + if (action == MotionEvent.ACTION_MOVE) { + if (y > (mDownY+30)) { + Log.i(TAG, "Closing!"); + closePanel(mFeatureId); + mWatchingForMenu = false; + return true; + } + } else if (action == MotionEvent.ACTION_UP) { + mWatchingForMenu = false; + } + + return false; + } + + //Log.i(TAG, "Intercept: action=" + action + " y=" + event.getY() + // + " (in " + getHeight() + ")"); + + if (action == MotionEvent.ACTION_DOWN) { + int y = (int)event.getY(); + if (y >= (getHeight()-5) && !hasChildren()) { + Log.i(TAG, "Watchiing!"); + mWatchingForMenu = true; + } + return false; + } + + if (!mWatchingForMenu) { + return false; + } + + int y = (int)event.getY(); + if (action == MotionEvent.ACTION_MOVE) { + if (y < (getHeight()-30)) { + Log.i(TAG, "Opening!"); + openPanel(FEATURE_OPTIONS_PANEL, new KeyEvent( + KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU)); + mWatchingForMenu = false; + return true; + } + } else if (action == MotionEvent.ACTION_UP) { + mWatchingForMenu = false; + } + + return false; + } + + @Override + protected boolean setFrame(int l, int t, int r, int b) { + boolean changed = super.setFrame(l, t, r, b); + if (changed) { + final Rect drawingBounds = mDrawingBounds; + getDrawingRect(drawingBounds); + + Drawable fg = getForeground(); + if (fg != null) { + final Rect frameOffsets = mFrameOffsets; + drawingBounds.left += frameOffsets.left; + drawingBounds.top += frameOffsets.top; + drawingBounds.right -= frameOffsets.right; + drawingBounds.bottom -= frameOffsets.bottom; + fg.setBounds(drawingBounds); + final Rect framePadding = mFramePadding; + drawingBounds.left += framePadding.left - frameOffsets.left; + drawingBounds.top += framePadding.top - frameOffsets.top; + drawingBounds.right -= framePadding.right - frameOffsets.right; + drawingBounds.bottom -= framePadding.bottom - frameOffsets.bottom; + } + + Drawable bg = getBackground(); + if (bg != null) { + bg.setBounds(drawingBounds); + } + + if (SWEEP_OPEN_MENU) { + if (mMenuBackground == null && mFeatureId < 0 + && getAttributes().height + == WindowManager.LayoutParams.FILL_PARENT) { + mMenuBackground = getContext().getResources().getDrawable( + com.android.internal.R.drawable.menu_background); + } + if (mMenuBackground != null) { + mMenuBackground.setBounds(drawingBounds.left, + drawingBounds.bottom-6, drawingBounds.right, + drawingBounds.bottom+20); + } + } + } + return changed; + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + + if (mMenuBackground != null) { + mMenuBackground.draw(canvas); + } + } + + + @Override + public boolean showContextMenuForChild(View originalView) { + // Reuse the context menu builder + if (mContextMenu == null) { + mContextMenu = new ContextMenuBuilder(getContext()); + mContextMenu.setCallback(mContextMenuCallback); + } else { + mContextMenu.clearAll(); + } + + mContextMenuHelper = mContextMenu.show(originalView, originalView.getWindowToken()); + return mContextMenuHelper != null; + } + + public void startChanging() { + mChanging = true; + } + + public void finishChanging() { + mChanging = false; + drawableChanged(); + } + + public void setWindowBackground(Drawable drawable) { + if (getBackground() != drawable) { + setBackgroundDrawable(drawable); + if (drawable != null) { + drawable.getPadding(mBackgroundPadding); + } else { + mBackgroundPadding.setEmpty(); + } + drawableChanged(); + } + } + + public void setWindowFrame(Drawable drawable) { + if (getForeground() != drawable) { + setForeground(drawable); + if (drawable != null) { + drawable.getPadding(mFramePadding); + } else { + mFramePadding.setEmpty(); + } + drawableChanged(); + } + } + + @Override + protected boolean fitSystemWindows(Rect insets) { + mFrameOffsets.set(insets); + if (getForeground() != null) { + drawableChanged(); + } + return super.fitSystemWindows(insets); + } + + private void drawableChanged() { + if (mChanging) { + return; + } + + setPadding(mFramePadding.left + mBackgroundPadding.left, mFramePadding.top + + mBackgroundPadding.top, mFramePadding.right + mBackgroundPadding.right, + mFramePadding.bottom + mBackgroundPadding.bottom); + requestLayout(); + invalidate(); + + int opacity = PixelFormat.OPAQUE; + + // Note: if there is no background, we will assume opaque. The + // common case seems to be that an application sets there to be + // no background so it can draw everything itself. For that, + // we would like to assume OPAQUE and let the app force it to + // the slower TRANSLUCENT mode if that is really what it wants. + Drawable bg = getBackground(); + Drawable fg = getForeground(); + if (bg != null) { + if (fg == null) { + opacity = bg.getOpacity(); + } else if (mFramePadding.left <= 0 && mFramePadding.top <= 0 + && mFramePadding.right <= 0 && mFramePadding.bottom <= 0) { + // If the frame padding is zero, then we can be opaque + // if either the frame -or- the background is opaque. + int fop = fg.getOpacity(); + int bop = bg.getOpacity(); + if (Config.LOGV) + Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop); + if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) { + opacity = PixelFormat.OPAQUE; + } else if (fop == PixelFormat.UNKNOWN) { + opacity = bop; + } else if (bop == PixelFormat.UNKNOWN) { + opacity = fop; + } else { + opacity = Drawable.resolveOpacity(fop, bop); + } + } else { + // For now we have to assume translucent if there is a + // frame with padding... there is no way to tell if the + // frame and background together will draw all pixels. + if (Config.LOGV) + Log.v(TAG, "Padding: " + mFramePadding); + opacity = PixelFormat.TRANSLUCENT; + } + } + + if (Config.LOGV) + Log.v(TAG, "Background: " + bg + ", Frame: " + fg); + if (Config.LOGV) + Log.v(TAG, "Selected default opacity: " + opacity); + + mDefaultOpacity = opacity; + if (mFeatureId < 0) { + setDefaultWindowFormat(opacity); + } + } + + @Override + public void onWindowFocusChanged(boolean hasWindowFocus) { + super.onWindowFocusChanged(hasWindowFocus); + + // no KEYCODE_CALL events active across focus changes + mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); + mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); + mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); + mKeycodeCallTimeoutActive = false; + mKeycodeCameraTimeoutActive = false; + + // If the user is chording a menu shortcut, release the chord since + // this window lost focus + if (!hasWindowFocus && mPanelChordingKey > 0) { + closePanel(FEATURE_OPTIONS_PANEL); + } + + final Callback cb = getCallback(); + if (cb != null && mFeatureId < 0) { + cb.onWindowFocusChanged(hasWindowFocus); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + if (mFeatureId == -1) { + /* + * The main window has been attached, try to restore any panels + * that may have been open before. This is called in cases where + * an activity is being killed for configuration change and the + * menu was open. When the activity is recreated, the menu + * should be shown again. + */ + openPanelsAfterRestore(); + } + } + } + + protected DecorView generateDecor() { + return new DecorView(getContext(), -1); + } + + protected void setFeatureFromAttrs(int featureId, TypedArray attrs, + int drawableAttr, int alphaAttr) { + Drawable d = attrs.getDrawable(drawableAttr); + if (d != null) { + requestFeature(featureId); + setFeatureDefaultDrawable(featureId, d); + } + if ((getFeatures() & (1 << featureId)) != 0) { + int alpha = attrs.getInt(alphaAttr, -1); + if (alpha >= 0) { + setFeatureDrawableAlpha(featureId, alpha); + } + } + } + + protected ViewGroup generateLayout(DecorView decor) { + // Apply data from current theme. + + TypedArray a = getWindowStyle(); + + if (false) { + System.out.println("From style:"); + String s = "Attrs:"; + for (int i = 0; i < com.android.internal.R.styleable.Window.length; i++) { + s = s + " " + Integer.toHexString(com.android.internal.R.styleable.Window[i]) + "=" + + a.getString(i); + } + System.out.println(s); + } + + mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false); + int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR) + & (~getForcedWindowFlags()); + if (mIsFloating) { + setLayout(WRAP_CONTENT, WRAP_CONTENT); + setFlags(0, flagsToUpdate); + } else { + setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate); + } + + if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) { + requestFeature(FEATURE_NO_TITLE); + } + + if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) { + setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags())); + } + + WindowManager.LayoutParams params = getAttributes(); + + if (!hasSoftInputMode()) { + params.softInputMode = a.getInt( + com.android.internal.R.styleable.Window_windowSoftInputMode, + params.softInputMode); + } + + if (a.getBoolean(com.android.internal.R.styleable.Window_backgroundDimEnabled, + mIsFloating)) { + /* All dialogs should have the window dimmed */ + if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) { + params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; + } + params.dimAmount = a.getFloat( + android.R.styleable.Window_backgroundDimAmount, 0.5f); + } + + if (params.windowAnimations == 0) { + params.windowAnimations = a.getResourceId( + com.android.internal.R.styleable.Window_windowAnimationStyle, 0); + } + + // The rest are only done if this window is not embedded; otherwise, + // the values are inherited from our container. + if (getContainer() == null) { + if (mBackgroundDrawable == null) { + if (mBackgroundResource == 0) { + mBackgroundResource = a.getResourceId( + com.android.internal.R.styleable.Window_windowBackground, 0); + } + if (mFrameResource == 0) { + mFrameResource = a.getResourceId(com.android.internal.R.styleable.Window_windowFrame, 0); + } + if (false) { + System.out.println("Background: " + + Integer.toHexString(mBackgroundResource) + " Frame: " + + Integer.toHexString(mFrameResource)); + } + } + mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000); + } + + // Inflate the window decor. + + int layoutResource; + int features = getLocalFeatures(); + // System.out.println("Features: 0x" + Integer.toHexString(features)); + if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) { + if (mIsFloating) { + layoutResource = com.android.internal.R.layout.dialog_title_icons; + } else { + layoutResource = com.android.internal.R.layout.screen_title_icons; + } + // 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; + // System.out.println("Progress!"); + } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) { + // Special case for a window with a custom title. + // If the window is floating, we need a dialog layout + if (mIsFloating) { + layoutResource = com.android.internal.R.layout.dialog_custom_title; + } else { + layoutResource = com.android.internal.R.layout.screen_custom_title; + } + } 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 { + layoutResource = com.android.internal.R.layout.screen_title; + } + // System.out.println("Title!"); + } else { + // Embedded, so no decoration is needed. + layoutResource = com.android.internal.R.layout.screen_simple; + // System.out.println("Simple!"); + } + + mDecor.startChanging(); + + View in = mLayoutInflater.inflate(layoutResource, null); + decor.addView(in, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT)); + + ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); + if (contentParent == null) { + throw new RuntimeException("Window couldn't find content container view"); + } + + if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { + ProgressBar progress = getCircularProgressBar(false); + if (progress != null) { + progress.setIndeterminate(true); + } + } + + // Remaining setup -- of background and title -- that only applies + // to top-level windows. + if (getContainer() == null) { + Drawable drawable = mBackgroundDrawable; + if (mBackgroundResource != 0) { + drawable = getContext().getResources().getDrawable(mBackgroundResource); + } + mDecor.setWindowBackground(drawable); + drawable = null; + if (mFrameResource != 0) { + drawable = getContext().getResources().getDrawable(mFrameResource); + } + mDecor.setWindowFrame(drawable); + + // System.out.println("Text=" + Integer.toHexString(mTextColor) + + // " Sel=" + Integer.toHexString(mTextSelectedColor) + + // " Title=" + Integer.toHexString(mTitleColor)); + + if (mTitleColor == 0) { + mTitleColor = mTextColor; + } + + if (mTitle != null) { + setTitle(mTitle); + } + setTitleColor(mTitleColor); + } + + mDecor.finishChanging(); + + return contentParent; + } + + private void installDecor() { + if (mDecor == null) { + mDecor = generateDecor(); + mDecor.setIsRootNamespace(true); + } + if (mContentParent == null) { + mContentParent = generateLayout(mDecor); + + mTitleView = (TextView)findViewById(com.android.internal.R.id.title); + if (mTitleView != null) { + if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) { + View titleContainer = findViewById(com.android.internal.R.id.title_container); + if (titleContainer != null) { + titleContainer.setVisibility(View.GONE); + } else { + mTitleView.setVisibility(View.GONE); + } + if (mContentParent instanceof FrameLayout) { + ((FrameLayout)mContentParent).setForeground(null); + } + } else { + mTitleView.setText(mTitle); + } + } + } + } + + private Drawable loadImageURI(Uri uri) { + try { + return Drawable.createFromStream( + getContext().getContentResolver().openInputStream(uri), null); + } catch (Exception e) { + Log.w(TAG, "Unable to open content: " + uri); + } + return null; + } + + private DrawableFeatureState getDrawableState(int featureId, boolean required) { + if ((getFeatures() & (1 << featureId)) == 0) { + if (!required) { + return null; + } + throw new RuntimeException("The feature has not been requested"); + } + + DrawableFeatureState[] ar; + if ((ar = mDrawables) == null || ar.length <= featureId) { + DrawableFeatureState[] nar = new DrawableFeatureState[featureId + 1]; + if (ar != null) { + System.arraycopy(ar, 0, nar, 0, ar.length); + } + mDrawables = ar = nar; + } + + DrawableFeatureState st = ar[featureId]; + if (st == null) { + ar[featureId] = st = new DrawableFeatureState(featureId); + } + return st; + } + + /** + * Gets a panel's state based on its feature ID. + * + * @param featureId The feature ID of the panel. + * @param required Whether the panel is required (if it is required and it + * isn't in our features, this throws an exception). + * @return The panel state. + */ + private PanelFeatureState getPanelState(int featureId, boolean required) { + return getPanelState(featureId, required, null); + } + + /** + * Gets a panel's state based on its feature ID. + * + * @param featureId The feature ID of the panel. + * @param required Whether the panel is required (if it is required and it + * isn't in our features, this throws an exception). + * @param convertPanelState Optional: If the panel state does not exist, use + * this as the panel state. + * @return The panel state. + */ + private PanelFeatureState getPanelState(int featureId, boolean required, + PanelFeatureState convertPanelState) { + if ((getFeatures() & (1 << featureId)) == 0) { + if (!required) { + return null; + } + throw new RuntimeException("The feature has not been requested"); + } + + PanelFeatureState[] ar; + if ((ar = mPanels) == null || ar.length <= featureId) { + PanelFeatureState[] nar = new PanelFeatureState[featureId + 1]; + if (ar != null) { + System.arraycopy(ar, 0, nar, 0, ar.length); + } + mPanels = ar = nar; + } + + PanelFeatureState st = ar[featureId]; + if (st == null) { + ar[featureId] = st = (convertPanelState != null) + ? convertPanelState + : new PanelFeatureState(featureId); + } + return st; + } + + @Override + public final void setChildDrawable(int featureId, Drawable drawable) { + DrawableFeatureState st = getDrawableState(featureId, true); + st.child = drawable; + updateDrawable(featureId, st, false); + } + + @Override + public final void setChildInt(int featureId, int value) { + updateInt(featureId, value, false); + } + + @Override + public boolean isShortcutKey(int keyCode, KeyEvent event) { + PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); + return st.menu != null && st.menu.isShortcutKey(keyCode, event); + } + + private void updateDrawable(int featureId, DrawableFeatureState st, boolean fromResume) { + // Do nothing if the decor is not yet installed... an update will + // need to be forced when we eventually become active. + if (mContentParent == null) { + return; + } + + final int featureMask = 1 << featureId; + + if ((getFeatures() & featureMask) == 0 && !fromResume) { + return; + } + + Drawable drawable = null; + if (st != null) { + drawable = st.child; + if (drawable == null) + drawable = st.local; + if (drawable == null) + drawable = st.def; + } + if ((getLocalFeatures() & featureMask) == 0) { + if (getContainer() != null) { + if (isActive() || fromResume) { + getContainer().setChildDrawable(featureId, drawable); + } + } + } else if (st != null && (st.cur != drawable || st.curAlpha != st.alpha)) { + // System.out.println("Drawable changed: old=" + st.cur + // + ", new=" + drawable); + st.cur = drawable; + st.curAlpha = st.alpha; + onDrawableChanged(featureId, drawable, st.alpha); + } + } + + private void updateInt(int featureId, int value, boolean fromResume) { + + // Do nothing if the decor is not yet installed... an update will + // need to be forced when we eventually become active. + if (mContentParent == null) { + return; + } + + final int featureMask = 1 << featureId; + + if ((getFeatures() & featureMask) == 0 && !fromResume) { + return; + } + + if ((getLocalFeatures() & featureMask) == 0) { + if (getContainer() != null) { + getContainer().setChildInt(featureId, value); + } + } else { + onIntChanged(featureId, value); + } + } + + private ImageView getLeftIconView() { + if (mLeftIconView != null) { + return mLeftIconView; + } + if (mContentParent == null) { + installDecor(); + } + return (mLeftIconView = (ImageView)findViewById(com.android.internal.R.id.left_icon)); + } + + private ProgressBar getCircularProgressBar(boolean shouldInstallDecor) { + if (mCircularProgressBar != null) { + return mCircularProgressBar; + } + if (mContentParent == null && shouldInstallDecor) { + installDecor(); + } + mCircularProgressBar = (ProgressBar)findViewById(com.android.internal.R.id.progress_circular); + mCircularProgressBar.setVisibility(View.INVISIBLE); + return mCircularProgressBar; + } + + private ProgressBar getHorizontalProgressBar(boolean shouldInstallDecor) { + if (mHorizontalProgressBar != null) { + return mHorizontalProgressBar; + } + if (mContentParent == null && shouldInstallDecor) { + installDecor(); + } + mHorizontalProgressBar = (ProgressBar)findViewById(com.android.internal.R.id.progress_horizontal); + mHorizontalProgressBar.setVisibility(View.INVISIBLE); + return mHorizontalProgressBar; + } + + private ImageView getRightIconView() { + if (mRightIconView != null) { + return mRightIconView; + } + if (mContentParent == null) { + installDecor(); + } + return (mRightIconView = (ImageView)findViewById(com.android.internal.R.id.right_icon)); + } + + /** + * Helper method for calling the {@link Callback#onPanelClosed(int, Menu)} + * callback. This method will grab whatever extra state is needed for the + * callback that isn't given in the parameters. If the panel is not open, + * this will not perform the callback. + * + * @param featureId Feature ID of the panel that was closed. Must be given. + * @param panel Panel that was closed. Optional but useful if there is no + * menu given. + * @param menu The menu that was closed. Optional, but give if you have. + */ + private void callOnPanelClosed(int featureId, PanelFeatureState panel, Menu menu) { + final Callback cb = getCallback(); + if (cb == null) + return; + + // Try to get a menu + if (menu == null) { + // Need a panel to grab the menu, so try to get that + if (panel == null) { + if ((featureId >= 0) && (featureId < mPanels.length)) { + panel = mPanels[featureId]; + } + } + + if (panel != null) { + // menu still may be null, which is okay--we tried our best + menu = panel.menu; + } + } + + // If the panel is not open, do not callback + if ((panel != null) && (!panel.isOpen)) + return; + + cb.onPanelClosed(featureId, menu); + } + + /** + * Helper method for adding launch-search to most applications. Opens the + * search window using default settings. + * + * @return true if search window opened + */ + private boolean launchDefaultSearch() { + final Callback cb = getCallback(); + if (cb == null) { + return false; + } else { + return cb.onSearchRequested(); + } + } + + @Override + public void setVolumeControlStream(int streamType) { + mVolumeControlStreamType = streamType; + } + + @Override + public int getVolumeControlStream() { + return mVolumeControlStreamType; + } + + private static final class DrawableFeatureState { + DrawableFeatureState(int _featureId) { + featureId = _featureId; + } + + final int featureId; + + int resid; + + Uri uri; + + Drawable local; + + Drawable child; + + Drawable def; + + Drawable cur; + + int alpha = 255; + + int curAlpha = 255; + } + + private static final class PanelFeatureState { + + /** Feature ID for this panel. */ + int featureId; + + // Information pulled from the style for this panel. + + int background; + + /** The background when the panel spans the entire available width. */ + int fullBackground; + + int gravity; + + int x; + + int y; + + int windowAnimations; + + /** Dynamic state of the panel. */ + DecorView decorView; + + /** The panel that was returned by onCreatePanelView(). */ + View createdPanelView; + + /** The panel that we are actually showing. */ + View shownPanelView; + + /** Use {@link #setMenu} to set this. */ + Menu menu; + + /** + * Whether the panel has been prepared (see + * {@link PhoneWindow#preparePanel}). + */ + boolean isPrepared; + + /** + * Whether an item's action has been performed. This happens in obvious + * scenarios (user clicks on menu item), but can also happen with + * chording menu+(shortcut key). + */ + boolean isHandled; + + boolean isOpen; + + /** + * True if the menu is in expanded mode, false if the menu is in icon + * mode + */ + boolean isInExpandedMode; + + public boolean qwertyMode; + + boolean refreshDecorView; + + /** + * Contains the state of the menu when told to freeze. + */ + Bundle frozenMenuState; + + PanelFeatureState(int featureId) { + this.featureId = featureId; + + refreshDecorView = false; + } + + void setStyle(Context context) { + TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme); + background = a.getResourceId( + com.android.internal.R.styleable.Theme_panelBackground, 0); + fullBackground = a.getResourceId( + com.android.internal.R.styleable.Theme_panelFullBackground, 0); + windowAnimations = a.getResourceId( + com.android.internal.R.styleable.Theme_windowAnimationStyle, 0); + a.recycle(); + } + + void setMenu(Menu menu) { + this.menu = menu; + + if (frozenMenuState != null) { + ((MenuBuilder) menu).restoreHierarchyState(frozenMenuState); + frozenMenuState = null; + } + } + + Parcelable onSaveInstanceState() { + SavedState savedState = new SavedState(); + savedState.featureId = featureId; + savedState.isOpen = isOpen; + savedState.isInExpandedMode = isInExpandedMode; + + if (menu != null) { + savedState.menuState = new Bundle(); + ((MenuBuilder) menu).saveHierarchyState(savedState.menuState); + } + + return savedState; + } + + void onRestoreInstanceState(Parcelable state) { + SavedState savedState = (SavedState) state; + featureId = savedState.featureId; + isOpen = savedState.isOpen; + isInExpandedMode = savedState.isInExpandedMode; + frozenMenuState = savedState.menuState; + + /* + * A LocalActivityManager keeps the same instance of this class around. + * The first time the menu is being shown after restoring, the + * Activity.onCreateOptionsMenu should be called. But, if it is the + * same instance then menu != null and we won't call that method. + * So, clear this. Also clear any cached views. + */ + menu = null; + createdPanelView = null; + shownPanelView = null; + decorView = null; + } + + private static class SavedState implements Parcelable { + int featureId; + boolean isOpen; + boolean isInExpandedMode; + Bundle menuState; + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(featureId); + dest.writeInt(isOpen ? 1 : 0); + dest.writeInt(isInExpandedMode ? 1 : 0); + + if (isOpen) { + dest.writeBundle(menuState); + } + } + + private static SavedState readFromParcel(Parcel source) { + SavedState savedState = new SavedState(); + savedState.featureId = source.readInt(); + savedState.isOpen = source.readInt() == 1; + savedState.isInExpandedMode = source.readInt() == 1; + + if (savedState.isOpen) { + savedState.menuState = source.readBundle(); + } + + return savedState; + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public SavedState createFromParcel(Parcel in) { + return readFromParcel(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + } + + /** + * Simple implementation of MenuBuilder.Callback that: + *

  • Opens a submenu when selected. + *
  • Calls back to the callback's onMenuItemSelected when an item is + * selected. + */ + private final class ContextMenuCallback implements MenuBuilder.Callback { + private int mFeatureId; + private MenuDialogHelper mSubMenuHelper; + + public ContextMenuCallback(int featureId) { + mFeatureId = featureId; + } + + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + if (allMenusAreClosing) { + Callback callback = getCallback(); + if (callback != null) callback.onPanelClosed(mFeatureId, menu); + + if (menu == mContextMenu) { + dismissContextMenu(); + } + + // Dismiss the submenu, if it is showing + if (mSubMenuHelper != null) { + mSubMenuHelper.dismiss(); + mSubMenuHelper = null; + } + } + } + + public void onCloseSubMenu(SubMenuBuilder menu) { + Callback callback = getCallback(); + if (callback != null) callback.onPanelClosed(mFeatureId, menu.getRootMenu()); + } + + public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { + Callback callback = getCallback(); + return (callback != null) && callback.onMenuItemSelected(mFeatureId, item); + } + + public void onMenuModeChange(MenuBuilder menu) { + } + + public boolean onSubMenuSelected(SubMenuBuilder subMenu) { + // Set a simple callback for the submenu + subMenu.setCallback(this); + + // The window manager will give us a valid window token + mSubMenuHelper = new MenuDialogHelper(subMenu); + mSubMenuHelper.show(null); + + return true; + } + } + + void sendCloseSystemWindows() { + PhoneWindowManager.sendCloseSystemWindows(getContext(), null); + } + + void sendCloseSystemWindows(String reason) { + PhoneWindowManager.sendCloseSystemWindows(getContext(), reason); + } +} diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java new file mode 100644 index 000000000000..d1b757604465 --- /dev/null +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -0,0 +1,1800 @@ +/* + * Copyright (C) 2006 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 android.app.Activity; +import android.app.ActivityManagerNative; +import android.app.IActivityManager; +import android.app.IStatusBar; +import android.content.BroadcastReceiver; +import android.content.ContentQueryMap; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.database.ContentObserver; +import android.graphics.Rect; +import android.os.Handler; +import android.os.IBinder; +import android.os.LocalPowerManager; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.os.Vibrator; +import android.provider.Settings; + +import com.android.internal.policy.PolicyManager; +import com.android.internal.telephony.ITelephony; +import android.util.Config; +import android.util.EventLog; +import android.util.Log; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.IWindowManager; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.WindowOrientationListener; +import android.view.RawInputEvent; +import android.view.Surface; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.Window; +import android.view.WindowManager; +import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; +import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; +import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; +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_KEYGUARD; +import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_PHONE; +import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE; +import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_TOAST; +import android.view.WindowManagerImpl; +import android.view.WindowManagerPolicy; +import android.view.WindowManagerPolicy.WindowState; +import android.media.IAudioService; +import android.media.AudioManager; + +/** + * WindowManagerPolicy implementation for the Android phone UI. + */ +public class PhoneWindowManager implements WindowManagerPolicy { + static final String TAG = "WindowManager"; + static final boolean DEBUG = false; + static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; + static final boolean SHOW_STARTING_ANIMATIONS = true; + static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; + + static final int APPLICATION_LAYER = 1; + static final int PHONE_LAYER = 2; + static final int SEARCH_BAR_LAYER = 3; + static final int STATUS_BAR_PANEL_LAYER = 4; + // toasts and the plugged-in battery thing + static final int TOAST_LAYER = 5; + static final int STATUS_BAR_LAYER = 6; + // SIM errors and unlock. Not sure if this really should be in a high layer. + static final int PRIORITY_PHONE_LAYER = 7; + // like the ANR / app crashed dialogs + static final int SYSTEM_ALERT_LAYER = 8; + // system-level error dialogs + static final int SYSTEM_ERROR_LAYER = 9; + // on-screen keyboards and other such input method user interfaces go here. + static final int INPUT_METHOD_LAYER = 10; + // on-screen keyboards and other such input method user interfaces go here. + static final int INPUT_METHOD_DIALOG_LAYER = 11; + // the keyguard; nothing on top of these can take focus, since they are + // responsible for power management when displayed. + static final int KEYGUARD_LAYER = 12; + static final int KEYGUARD_DIALOG_LAYER = 13; + // things in here CAN NOT take focus, but are shown on top of everything else. + static final int SYSTEM_OVERLAY_LAYER = 14; + + static final int APPLICATION_PANEL_SUBLAYER = 1; + static final int APPLICATION_MEDIA_SUBLAYER = -1; + static final int APPLICATION_SUB_PANEL_SUBLAYER = 2; + + static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f; + + // Debugging: set this to have the system act like there is no hard keyboard. + static final boolean KEYBOARD_ALWAYS_HIDDEN = false; + + static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; + static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; + static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; + + // Vibrator pattern for haptic feedback of a long press. + private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21}; + // Vibrator pattern for haptic feedback of a zoom ring tick + private static final long[] ZOOM_RING_TICK_VIBE_PATTERN = {0, 10}; + + Context mContext; + IWindowManager mWindowManager; + LocalPowerManager mPowerManager; + Vibrator mVibrator; // Vibrator for giving feedback of orientation changes + + /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ + boolean mEnableShiftMenuBugReports = false; + + boolean mSafeMode; + WindowState mStatusBar = null; + WindowState mSearchBar = null; + WindowState mKeyguard = null; + KeyguardViewMediator mKeyguardMediator; + GlobalActions mGlobalActions; + boolean mShouldTurnOffOnKeyUp; + RecentApplicationsDialog mRecentAppsDialog; + Handler mHandler; + + boolean mLidOpen; + int mSensorRotation = -1; + boolean mScreenOn = false; + boolean mOrientationSensorEnabled = false; + int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + static final int DEFAULT_ACCELEROMETER_ROTATION = 0; + int mAccelerometerDefault = DEFAULT_ACCELEROMETER_ROTATION; + boolean mHasSoftInput = false; + + // The current size of the screen. + int mW, mH; + // During layout, the current screen borders with all outer decoration + // (status bar, input method dock) accounted for. + int mCurLeft, mCurTop, mCurRight, mCurBottom; + // During layout, the frame in which content should be displayed + // to the user, accounting for all screen decoration except for any + // space they deem as available for other content. This is usually + // the same as mCur*, but may be larger if the screen decor has supplied + // content insets. + int mContentLeft, mContentTop, mContentRight, mContentBottom; + // During layout, the current screen borders along with input method + // windows are placed. + int mDockLeft, mDockTop, mDockRight, mDockBottom; + // During layout, the layer at which the doc window is placed. + int mDockLayer; + + static final Rect mTmpParentFrame = new Rect(); + static final Rect mTmpDisplayFrame = new Rect(); + static final Rect mTmpContentFrame = new Rect(); + static final Rect mTmpVisibleFrame = new Rect(); + + WindowState mTopFullscreenOpaqueWindowState; + boolean mForceStatusBar; + boolean mHomePressed; + Intent mHomeIntent; + boolean mSearchKeyPressed; + boolean mConsumeSearchKeyUp; + + static final int ENDCALL_HOME = 0x1; + static final int ENDCALL_SLEEPS = 0x2; + static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; + int mEndcallBehavior; + + ShortcutManager mShortcutManager; + PowerManager.WakeLock mBroadcastWakeLock; + + class SettingsObserver extends ContentObserver { + private ContentQueryMap mSettings; + + SettingsObserver(Handler handler) { + super(handler); + } + + void observe() { + ContentResolver resolver = mContext.getContentResolver(); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.END_BUTTON_BEHAVIOR), false, this); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.ACCELEROMETER_ROTATION), false, this); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.DEFAULT_INPUT_METHOD), false, this); + update(); + } + + @Override public void onChange(boolean selfChange) { + update(); + try { + mWindowManager.setRotation(USE_LAST_ROTATION, false); + } catch (RemoteException e) { + // Ignore + } + } + + public void update() { + ContentResolver resolver = mContext.getContentResolver(); + mEndcallBehavior = Settings.System.getInt(resolver, + Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); + int accelerometerDefault = Settings.System.getInt(resolver, + Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); + if (mAccelerometerDefault != accelerometerDefault) { + mAccelerometerDefault = accelerometerDefault; + updateOrientationListener(); + } + String imId = Settings.Secure.getString(resolver, + Settings.Secure.DEFAULT_INPUT_METHOD); + boolean hasSoftInput = imId != null && imId.length() > 0; + if (mHasSoftInput != hasSoftInput) { + mHasSoftInput = hasSoftInput; + updateRotation(); + } + } + } + + class MyOrientationListener extends WindowOrientationListener { + private static final int _LOWER_THRESHOLD = 30; + private static final int _UPPER_THRESHOLD = 60; + + MyOrientationListener(Context context) { + super(context); + } + + @Override + public void onOrientationChanged(int orientation) { + // ignore orientation changes unless the value is in a range + // When switching from portrait to landscape try to use a lower threshold limit + // Use upper threshold limit when switching from landscape to portrait + // this is to delay the switch as much as we can + int rotation; + int threshold = (mSensorRotation == Surface.ROTATION_90) ? _UPPER_THRESHOLD : + _LOWER_THRESHOLD; + + if ((orientation >= 0 && orientation <= _UPPER_THRESHOLD) || + (orientation >= 270 - _LOWER_THRESHOLD)) { + rotation = (orientation >= 270 - _LOWER_THRESHOLD + && orientation <= 270 + threshold) + ? Surface.ROTATION_90 : Surface.ROTATION_0; + } else if (orientation == WindowOrientationListener.ORIENTATION_FLAT) { + // return portrait + rotation = Surface.ROTATION_0; + } else { + // ignore orientation value + return; + } + // Send updates based on orientation value + if (rotation != mSensorRotation) { + if(localLOGV) Log.i(TAG, "onOrientationChanged, rotation changed from "+rotation+" to "+mSensorRotation); + // Update window manager. The lid rotation hasn't changed, + // but we want it to re-evaluate the final rotation in case + // it needs to call back and get the sensor orientation. + mSensorRotation = rotation; + try { + mWindowManager.setRotation(rotation, false); + } catch (RemoteException e) { + // Ignore + } + } + } + } + MyOrientationListener mOrientationListener; + + boolean useSensorForOrientation() { + if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { + return true; + } + if (mAccelerometerDefault != 0 && ( + mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || + mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { + return true; + } + return false; + } + + boolean needSensorRunning() { + if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { + // If the application has explicitly requested to follow the + // orientation, then we need to turn the sensor or. + return true; + } + if (mAccelerometerDefault != 0) { + // If the setting for using the sensor by default is enabled, then + // we will always leave it on. Note that the user could go to + // a window that forces an orientation that does not use the + // sensor and in theory we could turn it off... however, when next + // turning it on we won't have a good value for the current + // orientation for a little bit, which can cause orientation + // changes to lag, so we'd like to keep it always on. (It will + // still be turned off when the screen is off.) + return true; + } + return false; + } + + /* + * Various use cases for invoking this function + * screen turning off, should always disable listeners if already enabled + * screen turned on and current app has sensor based orientation, enable listeners + * if not already enabled + * screen turned on and current app does not have sensor orientation, disable listeners if + * already enabled + * screen turning on and current app has sensor based orientation, enable listeners if needed + * screen turning on and current app has nosensor based orientation, do nothing + */ + void updateOrientationListener() { + if (!mOrientationListener.canDetectOrientation()) { + // If sensor is turned off or nonexistent for some reason + return; + } + //Could have been invoked due to screen turning on or off or + //change of the currently visible window's orientation + if(localLOGV) Log.i(TAG, "Screen status="+mScreenOn+ + ", current orientation="+mCurrentAppOrientation+ + ", SensorEnabled="+mOrientationSensorEnabled); + boolean disable = true; + if(mScreenOn) { + if(needSensorRunning()) { + disable = false; + //enable listener if not already enabled + if(!mOrientationSensorEnabled) { + mOrientationListener.enable(); + if(localLOGV) Log.i(TAG, "Enabling listeners"); + // We haven't had the sensor on, so don't yet know + // the rotation. + mSensorRotation = -1; + mOrientationSensorEnabled = true; + } + } + } + //check if sensors need to be disabled + if(disable && mOrientationSensorEnabled) { + mOrientationListener.disable(); + if(localLOGV) Log.i(TAG, "Disabling listeners"); + mSensorRotation = -1; + mOrientationSensorEnabled = false; + } + } + + Runnable mEndCallLongPress = new Runnable() { + public void run() { + mShouldTurnOffOnKeyUp = false; + performHapticFeedback(null, HapticFeedbackConstants.LONG_PRESS, false); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); + showGlobalActionsDialog(); + } + }; + + void showGlobalActionsDialog() { + if (mGlobalActions == null) { + mGlobalActions = new GlobalActions(mContext); + } + final boolean keyguardShowing = mKeyguardMediator.isShowing(); + mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); + if (keyguardShowing) { + // since it took two seconds of long press to bring this up, + // poke the wake lock so they have some time to see the dialog. + mKeyguardMediator.pokeWakelock(); + } + } + + boolean isDeviceProvisioned() { + return Settings.Secure.getInt( + mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; + } + + /** + * When a home-key longpress expires, close other system windows and launch the recent apps + */ + Runnable mHomeLongPress = new Runnable() { + public void run() { + /* + * Eat the longpress so it won't dismiss the recent apps dialog when + * the user lets go of the home key + */ + mHomePressed = false; + performHapticFeedback(null, HapticFeedbackConstants.LONG_PRESS, false); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS); + showRecentAppsDialog(); + } + }; + + /** + * Create (if necessary) and launch the recent apps dialog + */ + void showRecentAppsDialog() { + if (mRecentAppsDialog == null) { + mRecentAppsDialog = new RecentApplicationsDialog(mContext); + } + mRecentAppsDialog.show(); + } + + /** {@inheritDoc} */ + public void init(Context context, IWindowManager windowManager, + LocalPowerManager powerManager) { + mContext = context; + mWindowManager = windowManager; + mPowerManager = powerManager; + mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager); + mHandler = new Handler(); + mOrientationListener = new MyOrientationListener(mContext); + SettingsObserver settingsObserver = new SettingsObserver(mHandler); + settingsObserver.observe(); + mShortcutManager = new ShortcutManager(context, mHandler); + mShortcutManager.observe(); + mHomeIntent = new Intent(Intent.ACTION_MAIN, null); + mHomeIntent.addCategory(Intent.CATEGORY_HOME); + mHomeIntent.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"); + mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); + } + + /** {@inheritDoc} */ + public int checkAddPermission(WindowManager.LayoutParams attrs) { + int type = attrs.type; + if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW + || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { + return WindowManagerImpl.ADD_OKAY; + } + String permission = null; + switch (type) { + case TYPE_TOAST: + // XXX right now the app process has complete control over + // this... should introduce a token to let the system + // monitor/control what they are doing. + break; + case TYPE_INPUT_METHOD: + // The window manager will check this. + break; + case TYPE_PHONE: + case TYPE_PRIORITY_PHONE: + case TYPE_SYSTEM_ALERT: + case TYPE_SYSTEM_ERROR: + case TYPE_SYSTEM_OVERLAY: + permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW; + break; + default: + permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; + } + if (permission != null) { + if (mContext.checkCallingOrSelfPermission(permission) + != PackageManager.PERMISSION_GRANTED) { + return WindowManagerImpl.ADD_PERMISSION_DENIED; + } + } + return WindowManagerImpl.ADD_OKAY; + } + + public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) { + switch (attrs.type) { + case TYPE_SYSTEM_OVERLAY: + case TYPE_TOAST: + // These types of windows can't receive input events. + attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + break; + } + } + + void readLidState() { + try { + int sw = mWindowManager.getSwitchState(0); + if (sw >= 0) { + mLidOpen = sw == 0; + } + } catch (RemoteException e) { + // Ignore + } + } + + /** {@inheritDoc} */ + public void adjustConfigurationLw(Configuration config) { + readLidState(); + final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen; + mPowerManager.setKeyboardVisibility(lidOpen); + config.keyboardHidden = (lidOpen || mHasSoftInput) + ? Configuration.KEYBOARDHIDDEN_NO + : Configuration.KEYBOARDHIDDEN_YES; + config.hardKeyboardHidden = lidOpen + ? Configuration.KEYBOARDHIDDEN_NO + : Configuration.KEYBOARDHIDDEN_YES; + } + + public boolean isCheekPressedAgainstScreen(MotionEvent ev) { + if(ev.getSize() > SLIDE_TOUCH_EVENT_SIZE_LIMIT) { + return true; + } + int size = ev.getHistorySize(); + for(int i = 0; i < size; i++) { + if(ev.getHistoricalSize(i) > SLIDE_TOUCH_EVENT_SIZE_LIMIT) { + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public int windowTypeToLayerLw(int type) { + if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) { + return APPLICATION_LAYER; + } + switch (type) { + case TYPE_STATUS_BAR: + return STATUS_BAR_LAYER; + case TYPE_STATUS_BAR_PANEL: + return STATUS_BAR_PANEL_LAYER; + case TYPE_SEARCH_BAR: + return SEARCH_BAR_LAYER; + case TYPE_PHONE: + return PHONE_LAYER; + case TYPE_KEYGUARD: + return KEYGUARD_LAYER; + case TYPE_KEYGUARD_DIALOG: + return KEYGUARD_DIALOG_LAYER; + case TYPE_SYSTEM_ALERT: + return SYSTEM_ALERT_LAYER; + case TYPE_SYSTEM_ERROR: + return SYSTEM_ERROR_LAYER; + case TYPE_INPUT_METHOD: + return INPUT_METHOD_LAYER; + case TYPE_INPUT_METHOD_DIALOG: + return INPUT_METHOD_DIALOG_LAYER; + case TYPE_SYSTEM_OVERLAY: + return SYSTEM_OVERLAY_LAYER; + case TYPE_PRIORITY_PHONE: + return PRIORITY_PHONE_LAYER; + case TYPE_TOAST: + return TOAST_LAYER; + } + Log.e(TAG, "Unknown window type: " + type); + return APPLICATION_LAYER; + } + + /** {@inheritDoc} */ + public int subWindowTypeToLayerLw(int type) { + switch (type) { + case TYPE_APPLICATION_PANEL: + case TYPE_APPLICATION_ATTACHED_DIALOG: + return APPLICATION_PANEL_SUBLAYER; + case TYPE_APPLICATION_MEDIA: + return APPLICATION_MEDIA_SUBLAYER; + case TYPE_APPLICATION_SUB_PANEL: + return APPLICATION_SUB_PANEL_SUBLAYER; + } + Log.e(TAG, "Unknown sub-window type: " + type); + return 0; + } + + /** {@inheritDoc} */ + public View addStartingWindow(IBinder appToken, String packageName, + int theme, CharSequence nonLocalizedLabel, + int labelRes, int icon) { + if (!SHOW_STARTING_ANIMATIONS) { + return null; + } + if (packageName == null) { + return null; + } + + Context context = mContext; + boolean setTheme = false; + //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel=" + // + nonLocalizedLabel + " theme=" + Integer.toHexString(theme)); + if (theme != 0 || labelRes != 0) { + try { + context = context.createPackageContext(packageName, 0); + if (theme != 0) { + context.setTheme(theme); + setTheme = true; + } + } catch (PackageManager.NameNotFoundException e) { + // Ignore + } + } + if (!setTheme) { + context.setTheme(com.android.internal.R.style.Theme); + } + + Window win = PolicyManager.makeNewWindow(context); + if (win.getWindowStyle().getBoolean( + com.android.internal.R.styleable.Window_windowDisablePreview, false)) { + return null; + } + + Resources r = context.getResources(); + win.setTitle(r.getText(labelRes, nonLocalizedLabel)); + + win.setType( + WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); + // Force the window flags: this is a fake window, so it is not really + // touchable or focusable by the user. We also add in the ALT_FOCUSABLE_IM + // flag because we do know that the next window will take input + // focus, so we want to get the IME window up on top of us right away. + win.setFlags( + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| + WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| + WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + + win.setLayout(WindowManager.LayoutParams.FILL_PARENT, + WindowManager.LayoutParams.FILL_PARENT); + + final WindowManager.LayoutParams params = win.getAttributes(); + params.token = appToken; + params.packageName = packageName; + params.windowAnimations = win.getWindowStyle().getResourceId( + com.android.internal.R.styleable.Window_windowAnimationStyle, 0); + params.setTitle("Starting " + packageName); + + try { + WindowManagerImpl wm = (WindowManagerImpl) + context.getSystemService(Context.WINDOW_SERVICE); + View view = win.getDecorView(); + + if (win.isFloating()) { + // Whoops, there is no way to display an animation/preview + // of such a thing! After all that work... let's skip it. + // (Note that we must do this here because it is in + // getDecorView() where the theme is evaluated... maybe + // we should peek the floating attribute from the theme + // earlier.) + return null; + } + + if (localLOGV) Log.v( + TAG, "Adding starting window for " + packageName + + " / " + appToken + ": " + + (view.getParent() != null ? view : null)); + + wm.addView(view, params); + + // Only return the view if it was successfully added to the + // window manager... which we can tell by it having a parent. + return view.getParent() != null ? view : null; + } catch (WindowManagerImpl.BadTokenException e) { + // ignore + Log.w(TAG, appToken + " already running, starting window not displayed"); + } + + return null; + } + + /** {@inheritDoc} */ + public void removeStartingWindow(IBinder appToken, View window) { + // RuntimeException e = new RuntimeException(); + // Log.i(TAG, "remove " + appToken + " " + window, e); + + if (localLOGV) Log.v( + TAG, "Removing starting window for " + appToken + ": " + window); + + if (window != null) { + WindowManagerImpl wm = (WindowManagerImpl) mContext.getSystemService(Context.WINDOW_SERVICE); + wm.removeView(window); + } + } + + /** + * Preflight adding a window to the system. + * + * Currently enforces that three window types are singletons: + * + * + * @param win The window to be added + * @param attrs Information about the window to be added + * + * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, WindowManagerImpl.ADD_MULTIPLE_SINGLETON + */ + public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) { + switch (attrs.type) { + case TYPE_STATUS_BAR: + if (mStatusBar != null) { + return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; + } + mStatusBar = win; + break; + case TYPE_SEARCH_BAR: + if (mSearchBar != null) { + return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; + } + mSearchBar = win; + break; + case TYPE_KEYGUARD: + if (mKeyguard != null) { + return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; + } + mKeyguard = win; + break; + } + return WindowManagerImpl.ADD_OKAY; + } + + /** {@inheritDoc} */ + public void removeWindowLw(WindowState win) { + if (mStatusBar == win) { + mStatusBar = null; + } + else if (mSearchBar == win) { + mSearchBar = null; + } + else if (mKeyguard == win) { + mKeyguard = null; + } + } + + static final boolean PRINT_ANIM = false; + + /** {@inheritDoc} */ + public int selectAnimationLw(WindowState win, int transit) { + if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win + + ": transit=" + transit); + if (transit == TRANSIT_PREVIEW_DONE) { + if (win.hasAppShownWindows()) { + if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT"); + return com.android.internal.R.anim.app_starting_exit; + } + } + + return 0; + } + + static ITelephony getPhoneInterface() { + return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE)); + } + + static IAudioService getAudioInterface() { + return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE)); + } + + boolean keyguardOn() { + return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode(); + } + + private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = { + WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, + WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, + }; + + /** {@inheritDoc} */ + public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, + int repeatCount) { + boolean keyguardOn = keyguardOn(); + + if (false) { + Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount=" + + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed); + } + + // Clear a pending HOME longpress if the user releases Home + // TODO: This could probably be inside the next bit of logic, but that code + // turned out to be a bit fragile so I'm doing it here explicitly, for now. + if ((code == KeyEvent.KEYCODE_HOME) && !down) { + mHandler.removeCallbacks(mHomeLongPress); + } + + // If the HOME button is currently being held, then we do special + // chording with it. + if (mHomePressed) { + + // If we have released the home key, and didn't do anything else + // while it was pressed, then it is time to go home! + if (code == KeyEvent.KEYCODE_HOME) { + if (!down) { + mHomePressed = false; + + // If an incoming call is ringing, HOME is totally disabled. + // (The user is already on the InCallScreen at this point, + // and his ONLY options are to answer or reject the call.) + boolean incomingRinging = false; + try { + ITelephony phoneServ = getPhoneInterface(); + if (phoneServ != null) { + incomingRinging = phoneServ.isRinging(); + } else { + Log.w(TAG, "Unable to find ITelephony interface"); + } + } catch (RemoteException ex) { + Log.w(TAG, "RemoteException from getPhoneInterface()", ex); + } + + if (incomingRinging) { + Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); + } else { + launchHomeFromHotKey(); + } + } + } + + return true; + } + + // First we always handle the home key here, so applications + // can never break it, although if keyguard is on, we do let + // it handle it, because that gives us the correct 5 second + // timeout. + if (code == KeyEvent.KEYCODE_HOME) { + + // If a system window has focus, then it doesn't make sense + // right now to interact with applications. + WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null; + if (attrs != null) { + final int type = attrs.type; + if (type == WindowManager.LayoutParams.TYPE_KEYGUARD + || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) { + // the "app" is keyguard, so give it the key + return false; + } + final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length; + for (int i=0; i launch home action was detected. Take the appropriate action + * given the situation with the keyguard. + */ + void launchHomeFromHotKey() { + if (mKeyguardMediator.isShowing()) { + // don't launch home if keyguard showing + } else if (mKeyguardMediator.isInputRestricted()) { + // when in keyguard restricted mode, must first verify unlock + // before launching home + mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() { + public void onKeyguardExitResult(boolean success) { + if (success) { + mContext.startActivity(mHomeIntent); + sendCloseSystemWindows(); + } + } + }); + } else { + // no keyguard stuff to worry about, just launch home! + mContext.startActivity(mHomeIntent); + sendCloseSystemWindows(); + } + } + + public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) { + final int fl = attrs.flags; + + if ((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); + } else { + contentInset.setEmpty(); + } + } + + /** {@inheritDoc} */ + public void beginLayoutLw(int displayWidth, int displayHeight) { + mW = displayWidth; + mH = displayHeight; + mDockLeft = mContentLeft = mCurLeft = 0; + mDockTop = mContentTop = mCurTop = 0; + mDockRight = mContentRight = mCurRight = displayWidth; + mDockBottom = mContentBottom = mCurBottom = displayHeight; + mDockLayer = 0x10000000; + + // decide where the status bar goes ahead of time + if (mStatusBar != null) { + final Rect pf = mTmpParentFrame; + final Rect df = mTmpDisplayFrame; + final Rect vf = mTmpVisibleFrame; + pf.left = df.left = vf.left = 0; + pf.top = df.top = vf.top = 0; + pf.right = df.right = vf.right = displayWidth; + pf.bottom = df.bottom = vf.bottom = displayHeight; + + mStatusBar.computeFrameLw(pf, df, vf, vf); + 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; + } + } + } + + void setAttachedWindowFrames(WindowState win, int fl, int sim, + WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) { + if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) { + // Here's a special case: if this attached window is a panel that is + // above the dock window, and the window it is attached to is below + // the dock window, then the frames we computed for the window it is + // attached to can not be used because the dock is effectively part + // of the underlying window and the attached window is floating on top + // of the whole thing. So, we ignore the attached window and explicitly + // compute the frames that would be appropriate without the dock. + df.left = cf.left = vf.left = mDockLeft; + df.top = cf.top = vf.top = mDockTop; + df.right = cf.right = vf.right = mDockRight; + df.bottom = cf.bottom = vf.bottom = mDockBottom; + } else { + // The effective display frame of the attached window depends on + // whether it is taking care of insetting its content. If not, + // we need to use the parent's content frame so that the entire + // window is positioned within that content. Otherwise we can use + // the display frame and let the attached window take care of + // positioning its content appropriately. + if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { + cf.set(attached.getDisplayFrameLw()); + } else { + // If the window is resizing, then we want to base the content + // frame on our attached content frame to resize... however, + // things can be tricky if the attached window is NOT in resize + // mode, in which case its content frame will be larger. + // Ungh. So to deal with that, make sure the content frame + // we end up using is not covering the IM dock. + cf.set(attached.getContentFrameLw()); + if (attached.getSurfaceLayer() < mDockLayer) { + if (cf.left < mContentLeft) cf.left = mContentLeft; + if (cf.top < mContentTop) cf.top = mContentTop; + if (cf.right > mContentRight) cf.right = mContentRight; + if (cf.bottom > mContentBottom) cf.bottom = mContentBottom; + } + } + df.set(insetDecors ? attached.getDisplayFrameLw() : cf); + vf.set(attached.getVisibleFrameLw()); + } + // The LAYOUT_IN_SCREEN flag is used to determine whether the attached + // window should be positioned relative to its parent or the entire + // screen. + pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 + ? attached.getFrameLw() : df); + } + + /** {@inheritDoc} */ + public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached) { + // we've already done the status bar + if (win == mStatusBar) { + return; + } + + if (false) { + if ("com.google.android.youtube".equals(attrs.packageName) + && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { + Log.i(TAG, "GOTCHA!"); + } + } + + final int fl = attrs.flags; + final int sim = attrs.softInputMode; + + final Rect pf = mTmpParentFrame; + final Rect df = mTmpDisplayFrame; + final Rect cf = mTmpContentFrame; + final Rect vf = mTmpVisibleFrame; + + if (attrs.type == TYPE_INPUT_METHOD) { + pf.left = df.left = cf.left = vf.left = mDockLeft; + pf.top = df.top = cf.top = vf.top = mDockTop; + pf.right = df.right = cf.right = vf.right = mDockRight; + pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom; + // IM dock windows always go to the bottom of the screen. + attrs.gravity = Gravity.BOTTOM; + mDockLayer = win.getSurfaceLayer(); + } else { + if ((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 + // to cover all of the screen space, and it can take care of + // moving its contents to account for screen decorations that + // intrude into that space. + if (attached != null) { + // If this window is attached to another, our display + // frame is the same as the one we are attached to. + setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf); + } else { + pf.left = df.left = 0; + pf.top = df.top = 0; + pf.right = df.right = mW; + pf.bottom = df.bottom = mH; + if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { + cf.left = mDockLeft; + cf.top = mDockTop; + cf.right = mDockRight; + cf.bottom = mDockBottom; + } else { + cf.left = mContentLeft; + cf.top = mContentTop; + cf.right = mContentRight; + cf.bottom = mContentBottom; + } + vf.left = mCurLeft; + vf.top = mCurTop; + vf.right = mCurRight; + vf.bottom = mCurBottom; + } + } else if ((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; + pf.top = df.top = cf.top = 0; + pf.right = df.right = cf.right = mW; + pf.bottom = df.bottom = cf.bottom = mH; + vf.left = mCurLeft; + vf.top = mCurTop; + vf.right = mCurRight; + vf.bottom = mCurBottom; + } else if (attached != null) { + // A child window should be placed inside of the same visible + // frame that its parent had. + setAttachedWindowFrames(win, fl, sim, attached, false, pf, df, cf, vf); + } else { + // Otherwise, a normal window must be placed inside the content + // of all screen decorations. + pf.left = mContentLeft; + pf.top = mContentTop; + pf.right = mContentRight; + pf.bottom = mContentBottom; + if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { + df.left = cf.left = mDockLeft; + df.top = cf.top = mDockTop; + df.right = cf.right = mDockRight; + df.bottom = cf.bottom = mDockBottom; + } else { + df.left = cf.left = mContentLeft; + df.top = cf.top = mContentTop; + df.right = cf.right = mContentRight; + df.bottom = cf.bottom = mContentBottom; + } + vf.left = mCurLeft; + vf.top = mCurTop; + vf.right = mCurRight; + vf.bottom = mCurBottom; + } + } + + if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) { + df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000; + df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000; + } + + if (false) { + if ("com.google.android.youtube".equals(attrs.packageName) + && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { + if (true || localLOGV) Log.v(TAG, "Computing frame of " + win + + ": pf=" + pf.toShortString() + " df=" + df.toShortString() + + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()); + } + } + + win.computeFrameLw(pf, df, cf, vf); + + // Dock windows carve out the bottom of the screen, so normal windows + // can't appear underneath them. + if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) { + int top = win.getContentFrameLw().top; + top += win.getGivenContentInsetsLw().top; + if (mContentBottom > top) { + mContentBottom = top; + } + top = win.getVisibleFrameLw().top; + top += win.getGivenVisibleInsetsLw().top; + if (mCurBottom > top) { + mCurBottom = top; + } + } + } + + /** {@inheritDoc} */ + public void finishLayoutLw() { + } + + /** {@inheritDoc} */ + public void beginAnimationLw(int displayWidth, int displayHeight) { + mTopFullscreenOpaqueWindowState = null; + mForceStatusBar = false; + } + + /** {@inheritDoc} */ + public void animatingWindowLw(WindowState win, + WindowManager.LayoutParams attrs) { + if (win.isVisibleLw()) { + if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { + mForceStatusBar = true; + } else if (mTopFullscreenOpaqueWindowState == null + && attrs.type >= FIRST_APPLICATION_WINDOW + && attrs.type <= LAST_APPLICATION_WINDOW + && win.fillsScreenLw(mW, mH, true, false) + && win.isVisibleLw()) { + mTopFullscreenOpaqueWindowState = win; + } + } + } + + /** {@inheritDoc} */ + public boolean finishAnimationLw() { + boolean changed = false; + if (mStatusBar != null) { + //Log.i(TAG, "force=" + mForceStatusBar + // + " top=" + mTopFullscreenOpaqueWindowState); + if (mForceStatusBar) { + changed |= mStatusBar.showLw(true); + } 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) { + changed |= mStatusBar.hideLw(true); + } else { + changed |= mStatusBar.showLw(true); + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean preprocessInputEventTq(RawInputEvent event) { + switch (event.type) { + case RawInputEvent.EV_SW: + if (event.keycode == 0) { + // lid changed state + mLidOpen = event.value == 0; + updateRotation(); + if (keyguardIsShowingTq()) { + if (mLidOpen) { + // only do this if it's opening -- closing the device shouldn't turn it + // off, but it also shouldn't turn it on. + mKeyguardMediator.pokeWakelock(); + } + } else { + // Light up the keyboard if we are sliding up. + if (mLidOpen) { + mPowerManager.userActivity(SystemClock.uptimeMillis(), false, + LocalPowerManager.BUTTON_EVENT); + } else { + mPowerManager.userActivity(SystemClock.uptimeMillis(), false, + LocalPowerManager.OTHER_EVENT); + } + } + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean isAppSwitchKeyTqTiLwLi(int keycode) { + return keycode == KeyEvent.KEYCODE_HOME + || keycode == KeyEvent.KEYCODE_ENDCALL; + } + + /** {@inheritDoc} */ + public boolean isMovementKeyTi(int keycode) { + switch (keycode) { + case KeyEvent.KEYCODE_DPAD_UP: + case KeyEvent.KEYCODE_DPAD_DOWN: + case KeyEvent.KEYCODE_DPAD_LEFT: + case KeyEvent.KEYCODE_DPAD_RIGHT: + return true; + } + return false; + } + + + /** + * @return Whether a telephone call is in progress right now. + */ + boolean isInCall() { + final ITelephony phone = getPhoneInterface(); + if (phone == null) { + Log.w(TAG, "couldn't get ITelephony reference"); + return false; + } + try { + return phone.isOffhook(); + } catch (RemoteException e) { + Log.w(TAG, "ITelephony.isOffhhook threw RemoteException " + e); + return false; + } + } + + /** + * @return Whether music is being played right now. + */ + boolean isMusicActive() { + final IAudioService audio = getAudioInterface(); + if (audio == null) { + Log.w(TAG, "isMusicActive: couldn't get IAudioService reference"); + return false; + } + try { + return audio.isMusicActive(); + } catch (RemoteException e) { + Log.w(TAG, "IAudioService.isMusicActive() threw RemoteException " + e); + return false; + } + } + + /** + * Tell the audio service to adjust the volume appropriate to the event. + * @param keycode + */ + void sendVolToMusic(int keycode) { + final IAudioService audio = getAudioInterface(); + if (audio == null) { + Log.w(TAG, "sendVolToMusic: couldn't get IAudioService reference"); + return; + } + try { + // since audio is playing, we shouldn't have to hold a wake lock + // during the call, but we do it as a precaution for the rare possibility + // that the music stops right before we call this + mBroadcastWakeLock.acquire(); + audio.adjustStreamVolume( + AudioManager.STREAM_MUSIC, + keycode == KeyEvent.KEYCODE_VOLUME_UP + ? AudioManager.ADJUST_RAISE + : AudioManager.ADJUST_LOWER, + 0); + } catch (RemoteException e) { + Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e); + } finally { + mBroadcastWakeLock.release(); + } + } + + static boolean isMediaKey(int code) { + if (code == KeyEvent.KEYCODE_HEADSETHOOK || + code == KeyEvent.KEYCODE_PLAYPAUSE || + code == KeyEvent.KEYCODE_STOP || + code == KeyEvent.KEYCODE_NEXTSONG || + code == KeyEvent.KEYCODE_PREVIOUSSONG || + code == KeyEvent.KEYCODE_PREVIOUSSONG || + code == KeyEvent.KEYCODE_FORWARD) { + return true; + } + return false; + } + + /** {@inheritDoc} */ + public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) { + int result = ACTION_PASS_TO_USER; + final boolean isWakeKey = isWakeKeyTq(event); + final boolean keyguardShowing = keyguardIsShowingTq(); + + if (false) { + Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode + + " screenIsOn=" + screenIsOn + " keyguardShowing=" + keyguardShowing); + } + + if (keyguardShowing) { + if (screenIsOn) { + // when the screen is on, always give the event to the keyguard + result |= ACTION_PASS_TO_USER; + } else { + // otherwise, don't pass it to the user + result &= ~ACTION_PASS_TO_USER; + + final boolean isKeyDown = + (event.type == RawInputEvent.EV_KEY) && (event.value != 0); + if (isWakeKey && isKeyDown) { + + // tell the mediator about a wake key, it may decide to + // turn on the screen depending on whether the key is + // appropriate. + if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode) + && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN + || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) { + if (isInCall()) { + // if the keyguard didn't wake the device, we are in call, and + // it is a volume key, turn on the screen so that the user + // can more easily adjust the in call volume. + mKeyguardMediator.pokeWakelock(); + } else if (isMusicActive()) { + // when keyguard is showing and screen off, we need + // to handle the volume key for music here + sendVolToMusic(event.keycode); + } + } + } + } + } else if (!screenIsOn) { + if (isWakeKey) { + // a wake key has a sole purpose of waking the device; don't pass + // it to the user + result |= ACTION_POKE_USER_ACTIVITY; + result &= ~ACTION_PASS_TO_USER; + } + } + + int type = event.type; + int code = event.keycode; + boolean down = event.value != 0; + + if (type == RawInputEvent.EV_KEY) { + if (code == KeyEvent.KEYCODE_ENDCALL) { + if (down) { + boolean hungUp = false; + // key repeats are generated by the window manager, and we don't see them + // here, so unless the driver is doing something it shouldn't be, we know + // this is the real press event. + try { + ITelephony phoneServ = getPhoneInterface(); + if (phoneServ != null) { + hungUp = phoneServ.endCall(); + } else { + Log.w(TAG, "!!! Unable to find ITelephony interface !!!"); + } + } catch (RemoteException ex) { + Log.w(TAG, "ITelephony.endCall() threw RemoteException" + ex); + } + if (hungUp || !screenIsOn) { + mShouldTurnOffOnKeyUp = false; + } else { + // only try to turn off the screen if we didn't already hang up + mShouldTurnOffOnKeyUp = true; + mHandler.postDelayed(mEndCallLongPress, + ViewConfiguration.getGlobalActionKeyTimeout()); + result &= ~ACTION_PASS_TO_USER; + } + } else { + mHandler.removeCallbacks(mEndCallLongPress); + if (mShouldTurnOffOnKeyUp) { + mShouldTurnOffOnKeyUp = false; + boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0; + boolean sleeps = (mEndcallBehavior & ENDCALL_SLEEPS) != 0; + if (keyguardShowing + || (sleeps && !gohome) + || (gohome && !goHome() && sleeps)) { + // they must already be on the keyguad or home screen, + // go to sleep instead + Log.d(TAG, "I'm tired mEndcallBehavior=0x" + + Integer.toHexString(mEndcallBehavior)); + result &= ~ACTION_POKE_USER_ACTIVITY; + result |= ACTION_GO_TO_SLEEP; + } + result &= ~ACTION_PASS_TO_USER; + } + } + } else if (isMediaKey(code)) { + // This key needs to be handled even if the screen is off. + // If others need to be handled while it's off, this is a reasonable + // pattern to follow. + if ((result & ACTION_PASS_TO_USER) == 0) { + // Only do this if we would otherwise not pass it to the user. In that + // case, the PhoneWindow class will do the same thing, except it will + // only do it if the showing app doesn't process the key on its own. + KeyEvent keyEvent = new KeyEvent(event.when, event.when, + down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP, + code, 0); + mBroadcastWakeLock.acquire(); + mHandler.post(new PassHeadsetKey(keyEvent)); + } + } else if (code == KeyEvent.KEYCODE_CALL) { + // If an incoming call is ringing, answer it! + // (We handle this key here, rather than in the InCallScreen, to make + // sure we'll respond to the key even if the InCallScreen hasn't come to + // the foreground yet.) + + // We answer the call on the DOWN event, to agree with + // the "fallback" behavior in the InCallScreen. + if (down) { + try { + ITelephony phoneServ = getPhoneInterface(); + if (phoneServ != null) { + if (phoneServ.isRinging()) { + Log.i(TAG, "interceptKeyTq:" + + " CALL key-down while ringing: Answer the call!"); + phoneServ.answerRingingCall(); + + // And *don't* pass this key thru to the current activity + // (which is presumably the InCallScreen.) + result &= ~ACTION_PASS_TO_USER; + } + } else { + Log.w(TAG, "CALL button: Unable to find ITelephony interface"); + } + } catch (RemoteException ex) { + Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex); + } + } + } else if ((code == KeyEvent.KEYCODE_VOLUME_UP) + || (code == KeyEvent.KEYCODE_VOLUME_DOWN)) { + // If an incoming call is ringing, either VOLUME key means + // "silence ringer". We handle these keys here, rather than + // in the InCallScreen, to make sure we'll respond to them + // even if the InCallScreen hasn't come to the foreground yet. + + // Look for the DOWN event here, to agree with the "fallback" + // behavior in the InCallScreen. + if (down) { + try { + ITelephony phoneServ = getPhoneInterface(); + if (phoneServ != null) { + if (phoneServ.isRinging()) { + Log.i(TAG, "interceptKeyTq:" + + " VOLUME key-down while ringing: Silence ringer!"); + // Silence the ringer. (It's safe to call this + // even if the ringer has already been silenced.) + phoneServ.silenceRinger(); + + // And *don't* pass this key thru to the current activity + // (which is probably the InCallScreen.) + result &= ~ACTION_PASS_TO_USER; + } + } else { + Log.w(TAG, "VOLUME button: Unable to find ITelephony interface"); + } + } catch (RemoteException ex) { + Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex); + } + } + } + } + + return result; + } + + class PassHeadsetKey implements Runnable { + KeyEvent mKeyEvent; + + PassHeadsetKey(KeyEvent keyEvent) { + mKeyEvent = keyEvent; + } + + public void run() { + if (ActivityManagerNative.isSystemReady()) { + Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent); + mContext.sendOrderedBroadcast(intent, null, mBroadcastDone, + mHandler, Activity.RESULT_OK, null, null); + } + } + } + + BroadcastReceiver mBroadcastDone = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + mBroadcastWakeLock.release(); + } + }; + + /** {@inheritDoc} */ + public boolean isWakeRelMovementTq(int device, int classes, + RawInputEvent event) { + // if it's tagged with one of the wake bits, it wakes up the device + return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0); + } + + /** {@inheritDoc} */ + public boolean isWakeAbsMovementTq(int device, int classes, + RawInputEvent event) { + // if it's tagged with one of the wake bits, it wakes up the device + return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0); + } + + /** + * Given the current state of the world, should this key wake up the device? + */ + protected boolean isWakeKeyTq(RawInputEvent event) { + // There are not key maps for trackball devices, but we'd still + // like to have pressing it wake the device up, so force it here. + int keycode = event.keycode; + int flags = event.flags; + if (keycode == RawInputEvent.BTN_MOUSE) { + flags |= WindowManagerPolicy.FLAG_WAKE; + } + return (flags + & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; + } + + /** {@inheritDoc} */ + public void screenTurnedOff(int why) { + EventLog.writeEvent(70000, 0); + mKeyguardMediator.onScreenTurnedOff(why); + mScreenOn = false; + updateOrientationListener(); + } + + /** {@inheritDoc} */ + public void screenTurnedOn() { + EventLog.writeEvent(70000, 1); + mKeyguardMediator.onScreenTurnedOn(); + mScreenOn = true; + updateOrientationListener(); + } + + /** {@inheritDoc} */ + public void enableKeyguard(boolean enabled) { + mKeyguardMediator.setKeyguardEnabled(enabled); + } + + /** {@inheritDoc} */ + public void exitKeyguardSecurely(OnKeyguardExitResult callback) { + mKeyguardMediator.verifyUnlock(callback); + } + + /** {@inheritDoc} */ + public boolean keyguardIsShowingTq() { + return mKeyguardMediator.isShowing(); + } + + /** {@inheritDoc} */ + public boolean inKeyguardRestrictedKeyInputMode() { + return mKeyguardMediator.isInputRestricted(); + } + + /** + * Callback from {@link KeyguardViewMediator} + */ + public void onKeyguardShow() { + sendCloseSystemWindows(); + } + + void sendCloseSystemWindows() { + sendCloseSystemWindows(mContext, null); + } + + void sendCloseSystemWindows(String reason) { + sendCloseSystemWindows(mContext, reason); + } + + static void sendCloseSystemWindows(Context context, String reason) { + if (ActivityManagerNative.isSystemReady()) { + Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + if (reason != null) { + intent.putExtra(SYSTEM_DIALOG_REASON_KEY, reason); + } + context.sendBroadcast(intent); + } + } + + public int rotationForOrientation(int orientation, int lastRotation, + boolean displayEnabled) { + switch (orientation) { + case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: + //always return landscape if orientation set to landscape + return Surface.ROTATION_90; + case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: + //always return portrait if orientation set to portrait + return Surface.ROTATION_0; + } + // case for nosensor meaning ignore sensor and consider only lid + // or orientation sensor disabled + //or case.unspecified + if (mLidOpen) { + return Surface.ROTATION_90; + } else { + if (useSensorForOrientation()) { + // If the user has enabled auto rotation by default, do it. + return mSensorRotation >= 0 ? mSensorRotation : lastRotation; + } + return Surface.ROTATION_0; + } + } + + public boolean detectSafeMode() { + try { + int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU); + mSafeMode = menuState > 0; + Log.i(TAG, "Menu key state: " + menuState + " safeMode=" + mSafeMode); + return mSafeMode; + } catch (RemoteException e) { + // Doom! (it's also local) + throw new RuntimeException("window manager dead"); + } + } + + /** {@inheritDoc} */ + public void systemReady() { + try { + if (mSafeMode) { + // If the user is holding the menu key code, then we are + // going to boot into safe mode. + ActivityManagerNative.getDefault().enterSafeMode(); + } + // tell the keyguard + mKeyguardMediator.onSystemReady(); + android.os.SystemProperties.set("dev.bootcomplete", "1"); + updateOrientationListener(); + mVibrator = new Vibrator(); + } catch (RemoteException e) { + // Ignore + } + } + + + /** {@inheritDoc} */ + public void enableScreenAfterBoot() { + readLidState(); + updateRotation(); + } + + void updateRotation() { + mPowerManager.setKeyboardVisibility(mLidOpen); + int rotation= Surface.ROTATION_0; + if (mLidOpen) { + // always use landscape if lid is open + rotation = Surface.ROTATION_90; + } + //if lid is closed orientation will be portrait + try { + //set orientation on WindowManager + mWindowManager.setRotation(rotation, true); + } catch (RemoteException e) { + // Ignore + } + } + + /** + * goes to the home screen + * @return whether it did anything + */ + boolean goHome() { + if (false) { + // This code always brings home to the front. + mContext.startActivity(mHomeIntent); + } else { + // This code brings home to the front or, if it is already + // at the front, puts the device to sleep. + try { + int result = ActivityManagerNative.getDefault() + .startActivity(null, mHomeIntent, + mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()), + null, 0, null, null, 0, true /* onlyIfNeeded*/, false); + if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) { + return false; + } + } catch (RemoteException ex) { + // bummer, the activity manager, which is in this process, is dead + } + } + sendCloseSystemWindows(); + return true; + } + + public void setCurrentOrientation(int newOrientation) { + if(newOrientation != mCurrentAppOrientation) { + mCurrentAppOrientation = newOrientation; + updateOrientationListener(); + } + } + + public boolean performHapticFeedback(WindowState win, int effectId, boolean always) { + if (!always && Settings.System.getInt(mContext.getContentResolver(), + Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) { + return false; + } + switch (effectId) { + case HapticFeedbackConstants.LONG_PRESS: + mVibrator.vibrate(LONG_PRESS_VIBE_PATTERN, -1); + return true; + case HapticFeedbackConstants.ZOOM_RING_TICK: + mVibrator.vibrate(ZOOM_RING_TICK_VIBE_PATTERN, -1); + } + return false; + } + + public void screenOnStopped() { + if (!mKeyguardMediator.isShowing()) { + long curTime = SystemClock.uptimeMillis(); + mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); + } + } +} diff --git a/policy/com/android/internal/policy/impl/Policy.java b/policy/com/android/internal/policy/impl/Policy.java new file mode 100644 index 000000000000..17f3e9129666 --- /dev/null +++ b/policy/com/android/internal/policy/impl/Policy.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008 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 android.content.Context; +import android.util.Log; + +import com.android.internal.policy.IPolicy; +import com.android.internal.policy.impl.PhoneLayoutInflater; +import com.android.internal.policy.impl.PhoneWindow; +import com.android.internal.policy.impl.PhoneWindowManager; + +/** + * {@hide} + */ + +// Simple implementation of the policy interface that spawns the right +// set of objects +public class Policy implements IPolicy { + private static final String TAG = "PhonePolicy"; + + private static final String[] preload_classes = { + "com.android.internal.policy.impl.PhoneLayoutInflater", + "com.android.internal.policy.impl.PhoneWindow", + "com.android.internal.policy.impl.PhoneWindow$1", + "com.android.internal.policy.impl.PhoneWindow$ContextMenuCallback", + "com.android.internal.policy.impl.PhoneWindow$DecorView", + "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState", + "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState", + }; + + static { + // For performance reasons, preload some policy specific classes when + // the policy gets loaded. + for (String s : preload_classes) { + try { + Class.forName(s); + } catch (ClassNotFoundException ex) { + Log.e(TAG, "Could not preload class for phone policy: " + s); + } + } + } + + public PhoneWindow makeNewWindow(Context context) { + return new PhoneWindow(context); + } + + public PhoneLayoutInflater makeNewLayoutInflater(Context context) { + return new PhoneLayoutInflater(context); + } + + public PhoneWindowManager makeNewWindowManager() { + return new PhoneWindowManager(); + } +} diff --git a/policy/com/android/internal/policy/impl/PowerDialog.java b/policy/com/android/internal/policy/impl/PowerDialog.java new file mode 100644 index 000000000000..77c42abcd402 --- /dev/null +++ b/policy/com/android/internal/policy/impl/PowerDialog.java @@ -0,0 +1,179 @@ +/* + * 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.IServiceManager; +import android.os.LocalPowerManager; +import android.os.ServiceManager; +import android.os.ServiceManagerNative; +import android.os.SystemClock; +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); + 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.shutdownAfterDisablingRadio(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/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java new file mode 100644 index 000000000000..5442dd4e4bde --- /dev/null +++ b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2008 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 android.app.ActivityManager; +import android.app.Dialog; +import android.app.StatusBarManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.view.View.OnClickListener; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.List; + +public class RecentApplicationsDialog extends Dialog implements OnClickListener { + // Elements for debugging support +// private static final String LOG_TAG = "RecentApplicationsDialog"; + private static final boolean DBG_FORCE_EMPTY_LIST = false; + + static private StatusBarManager sStatusBar; + + private static final int NUM_BUTTONS = 6; + private static final int MAX_RECENT_TASKS = NUM_BUTTONS * 2; // allow for some discards + + final View[] mButtons = new View[NUM_BUTTONS]; + View mNoAppsText; + IntentFilter mBroadcastIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + + public RecentApplicationsDialog(Context context) { + super(context); + } + + /** + * We create the recent applications dialog just once, and it stays around (hidden) + * until activated by the user. + * + * @see PhoneWindowManager#showRecentAppsDialog + */ + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Context context = getContext(); + + if (sStatusBar == null) { + sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE); + } + + Window theWindow = getWindow(); + theWindow.requestFeature(Window.FEATURE_NO_TITLE); + theWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); + theWindow.setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + theWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, + WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + + setContentView(com.android.internal.R.layout.recent_apps_dialog); + + mButtons[0] = findViewById(com.android.internal.R.id.button1); + mButtons[1] = findViewById(com.android.internal.R.id.button2); + mButtons[2] = findViewById(com.android.internal.R.id.button3); + mButtons[3] = findViewById(com.android.internal.R.id.button4); + mButtons[4] = findViewById(com.android.internal.R.id.button5); + mButtons[5] = findViewById(com.android.internal.R.id.button6); + mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message); + + for (View b : mButtons) { + b.setOnClickListener(this); + } + } + + /** + * Handler for user clicks. If a button was clicked, launch the corresponding activity. + */ + public void onClick(View v) { + + for (View b : mButtons) { + if (b == v) { + // prepare a launch intent and send it + Intent intent = (Intent)b.getTag(); + intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); + getContext().startActivity(intent); + } + } + dismiss(); + } + + /** + * Set up and show the recent activities dialog. + */ + @Override + public void onStart() { + super.onStart(); + reloadButtons(); + if (sStatusBar != null) { + sStatusBar.disable(StatusBarManager.DISABLE_EXPAND); + } + + // receive broadcasts + getContext().registerReceiver(mBroadcastReceiver, mBroadcastIntentFilter); + } + + /** + * Dismiss the recent activities dialog. + */ + @Override + public void onStop() { + super.onStop(); + + // dump extra memory we're hanging on to + for (View b : mButtons) { + setButtonAppearance(b, null, null); + b.setTag(null); + } + + if (sStatusBar != null) { + sStatusBar.disable(StatusBarManager.DISABLE_NONE); + } + + // stop receiving broadcasts + getContext().unregisterReceiver(mBroadcastReceiver); + } + + /** + * Reload the 6 buttons with recent activities + */ + private void reloadButtons() { + + final Context context = getContext(); + final PackageManager pm = context.getPackageManager(); + final ActivityManager am = (ActivityManager) + context.getSystemService(Context.ACTIVITY_SERVICE); + final List recentTasks = + am.getRecentTasks(MAX_RECENT_TASKS, 0); + + ResolveInfo homeInfo = pm.resolveActivity( + new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME), + 0); + + // Performance note: Our android performance guide says to prefer Iterator when + // using a List class, but because we know that getRecentTasks() always returns + // an ArrayList<>, we'll use a simple index instead. + int button = 0; + int numTasks = recentTasks.size(); + for (int i = 0; i < numTasks && (button < NUM_BUTTONS); ++i) { + final ActivityManager.RecentTaskInfo info = recentTasks.get(i); + + // for debug purposes only, disallow first result to create empty lists + if (DBG_FORCE_EMPTY_LIST && (i == 0)) continue; + + Intent intent = new Intent(info.baseIntent); + if (info.origActivity != null) { + intent.setComponent(info.origActivity); + } + + // Skip the current home activity. + if (homeInfo != null) { + if (homeInfo.activityInfo.packageName.equals( + intent.getComponent().getPackageName()) + && homeInfo.activityInfo.name.equals( + intent.getComponent().getClassName())) { + continue; + } + } + + intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) + | Intent.FLAG_ACTIVITY_NEW_TASK); + final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0); + if (resolveInfo != null) { + final ActivityInfo activityInfo = resolveInfo.activityInfo; + final String title = activityInfo.loadLabel(pm).toString(); + final Drawable icon = activityInfo.loadIcon(pm); + + if (title != null && title.length() > 0 && icon != null) { + final View b = mButtons[button]; + setButtonAppearance(b, title, icon); + b.setTag(intent); + b.setVisibility(View.VISIBLE); + b.setPressed(false); + b.clearFocus(); + ++button; + } + } + } + + // handle the case of "no icons to show" + mNoAppsText.setVisibility((button == 0) ? View.VISIBLE : View.GONE); + + // hide the rest + for ( ; button < NUM_BUTTONS; ++button) { + mButtons[button].setVisibility(View.GONE); + } + } + + /** + * Adjust appearance of each icon-button + */ + private void setButtonAppearance(View theButton, final String theTitle, final Drawable icon) { + TextView tv = (TextView) theButton.findViewById(com.android.internal.R.id.label); + tv.setText(theTitle); + ImageView iv = (ImageView) theButton.findViewById(com.android.internal.R.id.icon); + iv.setImageDrawable(icon); + } + + /** + * This is the listener for the ACTION_CLOSE_SYSTEM_DIALOGS intent. It's an indication that + * we should close ourselves immediately, in order to allow a higher-priority UI to take over + * (e.g. phone call received). + * + * TODO: This is a really heavyweight solution for something that should be so simple. + * For example, we already have a handler, in our superclass, why aren't we sharing that? + * I think we need to investigate simplifying this entire methodology, or perhaps boosting + * it up into the Dialog class. + */ + private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { + String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY); + if (! PhoneWindowManager.SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) { + dismiss(); + } + } + } + }; +} diff --git a/policy/com/android/internal/policy/impl/ShortcutManager.java b/policy/com/android/internal/policy/impl/ShortcutManager.java new file mode 100644 index 000000000000..d86ac44cf87f --- /dev/null +++ b/policy/com/android/internal/policy/impl/ShortcutManager.java @@ -0,0 +1,120 @@ +/* + * 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 android.content.Context; +import android.content.Intent; +import android.database.ContentObserver; +import android.database.Cursor; +import android.os.Handler; +import android.provider.Settings; +import android.util.Log; +import android.util.SparseArray; +import android.view.KeyCharacterMap; + +import java.net.URISyntaxException; + +/** + * Manages quick launch shortcuts by: + *
  • Keeping the local copy in sync with the database (this is an observer) + *
  • Returning a shortcut-matching intent to clients + */ +class ShortcutManager extends ContentObserver { + + private static final String TAG = "ShortcutManager"; + + private static final int COLUMN_SHORTCUT = 0; + private static final int COLUMN_INTENT = 1; + private static final String[] sProjection = new String[] { + Settings.Bookmarks.SHORTCUT, Settings.Bookmarks.INTENT + }; + + private Context mContext; + private Cursor mCursor; + /** Map of a shortcut to its intent. */ + private SparseArray mShortcutIntents; + + public ShortcutManager(Context context, Handler handler) { + super(handler); + + mContext = context; + mShortcutIntents = new SparseArray(); + } + + /** Observes the provider of shortcut+intents */ + public void observe() { + mCursor = mContext.getContentResolver().query( + Settings.Bookmarks.CONTENT_URI, sProjection, null, null, null); + mCursor.registerContentObserver(this); + updateShortcuts(); + } + + @Override + public void onChange(boolean selfChange) { + updateShortcuts(); + } + + private void updateShortcuts() { + Cursor c = mCursor; + if (!c.requery()) { + Log.e(TAG, "ShortcutObserver could not re-query shortcuts."); + return; + } + + mShortcutIntents.clear(); + while (c.moveToNext()) { + int shortcut = c.getInt(COLUMN_SHORTCUT); + if (shortcut == 0) continue; + String intentURI = c.getString(COLUMN_INTENT); + Intent intent = null; + try { + intent = Intent.getIntent(intentURI); + } catch (URISyntaxException e) { + Log.w(TAG, "Intent URI for shortcut invalid.", e); + } + if (intent == null) continue; + mShortcutIntents.put(shortcut, intent); + } + } + + /** + * Gets the shortcut intent for a given keycode+modifier. Make sure you + * strip whatever modifier is used for invoking shortcuts (for example, + * if 'Sym+A' should invoke a shortcut on 'A', you should strip the + * 'Sym' bit from the modifiers before calling this method. + *

    + * This will first try an exact match (with modifiers), and then try a + * match without modifiers (primary character on a key). + * + * @param keyCode The keycode of the key pushed. + * @param modifiers The modifiers without any that are used for chording + * to invoke a shortcut. + * @return The intent that matches the shortcut, or null if not found. + */ + public Intent getIntent(int keyCode, int modifiers) { + KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD); + // First try the exact keycode (with modifiers) + int shortcut = kcm.get(keyCode, modifiers); + Intent intent = shortcut != 0 ? mShortcutIntents.get(shortcut) : null; + if (intent != null) return intent; + + // Next try the keycode without modifiers (the primary character on that key) + shortcut = Character.toLowerCase(kcm.get(keyCode, 0)); + return shortcut != 0 ? mShortcutIntents.get(shortcut) : null; + } + +} diff --git a/policy/com/android/internal/policy/impl/ShutdownThread.java b/policy/com/android/internal/policy/impl/ShutdownThread.java new file mode 100644 index 000000000000..994b1d50bdf9 --- /dev/null +++ b/policy/com/android/internal/policy/impl/ShutdownThread.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2008 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 android.app.ProgressDialog; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.RemoteException; +import android.os.Power; +import android.os.ServiceManager; +import android.os.SystemClock; +import com.android.internal.telephony.ITelephony; +import android.util.Log; +import android.view.WindowManager; + + +final class ShutdownThread extends Thread { + // constants + private static final String TAG = "ShutdownThread"; + private static final int MAX_NUM_PHONE_STATE_READS = 16; + private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500; + private static final ITelephony sPhone = + ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); + + // state tracking + private static Object sIsStartedGuard = new Object(); + private static boolean sIsStarted = false; + + // static instance of this thread + private static final ShutdownThread sInstance = new ShutdownThread(); + + private ShutdownThread() { + } + + /** + * request a shutdown. + * + * @param context Context used to display the shutdown progress dialog. + */ + public static void shutdownAfterDisablingRadio(final Context context, boolean confirm){ + // ensure that only one thread is trying to power down. + // any additional calls are just returned + synchronized (sIsStartedGuard){ + if (sIsStarted) { + Log.d(TAG, "Request to shutdown already running, returning."); + return; + } + } + + Log.d(TAG, "Notifying thread to start radio shutdown"); + + if (confirm) { + final AlertDialog dialog = new AlertDialog.Builder(context) + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(com.android.internal.R.string.power_off) + .setMessage(com.android.internal.R.string.shutdown_confirm) + .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + beginShutdownSequence(context); + } + }) + .setNegativeButton(com.android.internal.R.string.no, null) + .create(); + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + dialog.show(); + } else { + beginShutdownSequence(context); + } + } + + private static void beginShutdownSequence(Context context) { + synchronized (sIsStartedGuard) { + sIsStarted = true; + } + + // throw up an indeterminate system dialog to indicate radio is + // shutting down. + ProgressDialog pd = new ProgressDialog(context); + pd.setTitle(context.getText(com.android.internal.R.string.power_off)); + pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress)); + pd.setIndeterminate(true); + pd.setCancelable(false); + pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + + pd.show(); + + // start the thread that initiates shutdown + sInstance.start(); + } + + /** + * Makes sure we handle the shutdown gracefully. + * Shuts off power regardless of radio state if the alloted time has passed. + */ + public void run() { + //shutdown the phone radio if possible. + if (sPhone != null) { + try { + //shutdown radio + sPhone.setRadio(false); + + for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++){ + // poll radio up to 64 times, with a 0.5 sec delay between each call, + // totaling 32 sec. + if (!sPhone.isRadioOn()) { + Log.d(TAG, "Radio shutdown complete."); + break; + } + SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC); + } + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException caught from failed radio shutdown.", ex); + } + } + + //shutdown power + Log.d(TAG, "Shutting down power."); + Power.shutdown(); + } +} diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java new file mode 100644 index 000000000000..9453212d4ad1 --- /dev/null +++ b/policy/com/android/internal/policy/impl/SimUnlockScreen.java @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2008 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 android.app.Dialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.os.RemoteException; +import android.os.ServiceManager; +import com.android.internal.telephony.ITelephony; +import android.text.Editable; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; +import com.android.internal.R; + +/** + * Displays a dialer like interface to unlock the SIM PIN. + */ +public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener, + KeyguardUpdateMonitor.ConfigurationChangeCallback { + + private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; + + private final KeyguardUpdateMonitor mUpdateMonitor; + private final KeyguardScreenCallback mCallback; + + private final boolean mCreatedWithKeyboardOpen; + + private TextView mHeaderText; + private EditText mPinText; + + private TextView mOkButton; + private TextView mEmergencyCallButton; + + private View mBackSpaceButton; + + private final int[] mEnteredPin = {0, 0, 0, 0, 0, 0, 0, 0}; + private int mEnteredDigits = 0; + + private ProgressDialog mSimUnlockProgressDialog = null; + + private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + + public SimUnlockScreen(Context context, KeyguardUpdateMonitor updateMonitor, + KeyguardScreenCallback callback) { + super(context); + mUpdateMonitor = updateMonitor; + mCallback = callback; + mCreatedWithKeyboardOpen = mUpdateMonitor.isKeyboardOpen(); + + if (mCreatedWithKeyboardOpen) { + LayoutInflater.from(context).inflate(R.layout.keyguard_screen_sim_pin_landscape, this, true); + } else { + LayoutInflater.from(context).inflate(R.layout.keyguard_screen_sim_pin_portrait, this, true); + new TouchInput(); + } + + mHeaderText = (TextView) findViewById(R.id.headerText); + mPinText = (EditText) findViewById(R.id.pinDisplay); + mBackSpaceButton = findViewById(R.id.backspace); + mBackSpaceButton.setOnClickListener(this); + + mEmergencyCallButton = (TextView) findViewById(R.id.emergencyCall); + mOkButton = (TextView) findViewById(R.id.ok); + + mHeaderText.setText(R.string.keyguard_password_enter_pin_code); + mPinText.setFocusable(false); + + mEmergencyCallButton.setOnClickListener(this); + mOkButton.setOnClickListener(this); + + mUpdateMonitor.registerConfigurationChangeCallback(this); + setFocusableInTouchMode(true); + } + + /** {@inheritDoc} */ + public boolean needsInput() { + return true; + } + + /** {@inheritDoc} */ + public void onPause() { + + } + + /** {@inheritDoc} */ + public void onResume() { + // start fresh + mHeaderText.setText(R.string.keyguard_password_enter_pin_code); + + // make sure that the number of entered digits is consistent when we + // erase the SIM unlock code, including orientation changes. + mPinText.setText(""); + mEnteredDigits = 0; + } + + /** {@inheritDoc} */ + public void cleanUp() { + // hide the dialog. + if (mSimUnlockProgressDialog != null) { + mSimUnlockProgressDialog.hide(); + } + mUpdateMonitor.removeCallback(this); + } + + + /** + * Since the IPC can block, we want to run the request in a separate thread + * with a callback. + */ + private abstract class CheckSimPin extends Thread { + + private final String mPin; + + protected CheckSimPin(String pin) { + mPin = pin; + } + + abstract void onSimLockChangedResponse(boolean success); + + @Override + public void run() { + try { + final boolean result = ITelephony.Stub.asInterface(ServiceManager + .checkService("phone")).supplyPin(mPin); + post(new Runnable() { + public void run() { + onSimLockChangedResponse(result); + } + }); + } catch (RemoteException e) { + post(new Runnable() { + public void run() { + onSimLockChangedResponse(false); + } + }); + } + } + } + + public void onClick(View v) { + if (v == mBackSpaceButton) { + final Editable digits = mPinText.getText(); + final int len = digits.length(); + if (len > 0) { + digits.delete(len-1, len); + mEnteredDigits--; + } + mCallback.pokeWakelock(); + } else if (v == mEmergencyCallButton) { + mCallback.takeEmergencyCallAction(); + } else if (v == mOkButton) { + checkPin(); + } + } + + private Dialog getSimUnlockProgressDialog() { + if (mSimUnlockProgressDialog == null) { + mSimUnlockProgressDialog = new ProgressDialog(mContext); + mSimUnlockProgressDialog.setMessage( + mContext.getString(R.string.lockscreen_sim_unlock_progress_dialog_message)); + mSimUnlockProgressDialog.setIndeterminate(true); + mSimUnlockProgressDialog.setCancelable(false); + mSimUnlockProgressDialog.getWindow().setType( + WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + mSimUnlockProgressDialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + } + return mSimUnlockProgressDialog; + } + + private void checkPin() { + + // make sure that the pin is at least 4 digits long. + if (mEnteredDigits < 4) { + // otherwise, display a message to the user, and don't submit. + mHeaderText.setText(R.string.invalidPin); + mPinText.setText(""); + mEnteredDigits = 0; + mCallback.pokeWakelock(); + return; + } + getSimUnlockProgressDialog().show(); + + new CheckSimPin(mPinText.getText().toString()) { + void onSimLockChangedResponse(boolean success) { + if (mSimUnlockProgressDialog != null) { + mSimUnlockProgressDialog.hide(); + } + if (success) { + // before closing the keyguard, report back that + // the sim is unlocked so it knows right away + mUpdateMonitor.reportSimPinUnlocked(); + mCallback.goToUnlockScreen(); + } else { + mHeaderText.setText(R.string.keyguard_password_wrong_pin_code); + mPinText.setText(""); + mEnteredDigits = 0; + mCallback.pokeWakelock(); + } + } + }.start(); + } + + + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + mCallback.goToLockScreen(); + return true; + } + + final char match = event.getMatch(DIGITS); + if (match != 0) { + reportDigit(match - '0'); + return true; + } + if (keyCode == KeyEvent.KEYCODE_DEL) { + if (mEnteredDigits > 0) { + mPinText.onKeyDown(keyCode, event); + mEnteredDigits--; + } + return true; + } + + if (keyCode == KeyEvent.KEYCODE_ENTER) { + checkPin(); + return true; + } + + return false; + } + + private void reportDigit(int digit) { + if (mEnteredDigits == 0) { + mPinText.setText(""); + } + if (mEnteredDigits == 8) { + return; + } + mPinText.append(Integer.toString(digit)); + mEnteredPin[mEnteredDigits++] = digit; + } + + public void onOrientationChange(boolean inPortrait) {} + + public void onKeyboardChange(boolean isKeyboardOpen) { + if (isKeyboardOpen != mCreatedWithKeyboardOpen) { + mCallback.recreateMe(); + } + } + + /** + * Helper class to handle input from touch dialer. Only relevant when + * the keyboard is shut. + */ + private class TouchInput implements View.OnClickListener { + private TextView mZero; + private TextView mOne; + private TextView mTwo; + private TextView mThree; + private TextView mFour; + private TextView mFive; + private TextView mSix; + private TextView mSeven; + private TextView mEight; + private TextView mNine; + private TextView mCancelButton; + + private TouchInput() { + mZero = (TextView) findViewById(R.id.zero); + mOne = (TextView) findViewById(R.id.one); + mTwo = (TextView) findViewById(R.id.two); + mThree = (TextView) findViewById(R.id.three); + mFour = (TextView) findViewById(R.id.four); + mFive = (TextView) findViewById(R.id.five); + mSix = (TextView) findViewById(R.id.six); + mSeven = (TextView) findViewById(R.id.seven); + mEight = (TextView) findViewById(R.id.eight); + mNine = (TextView) findViewById(R.id.nine); + mCancelButton = (TextView) findViewById(R.id.cancel); + + mZero.setText("0"); + mOne.setText("1"); + mTwo.setText("2"); + mThree.setText("3"); + mFour.setText("4"); + mFive.setText("5"); + mSix.setText("6"); + mSeven.setText("7"); + mEight.setText("8"); + mNine.setText("9"); + + mZero.setOnClickListener(this); + mOne.setOnClickListener(this); + mTwo.setOnClickListener(this); + mThree.setOnClickListener(this); + mFour.setOnClickListener(this); + mFive.setOnClickListener(this); + mSix.setOnClickListener(this); + mSeven.setOnClickListener(this); + mEight.setOnClickListener(this); + mNine.setOnClickListener(this); + mCancelButton.setOnClickListener(this); + } + + + public void onClick(View v) { + if (v == mCancelButton) { + mCallback.goToLockScreen(); + return; + } + + final int digit = checkDigit(v); + if (digit >= 0) { + mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS); + reportDigit(digit); + } + } + + private int checkDigit(View v) { + int digit = -1; + if (v == mZero) { + digit = 0; + } else if (v == mOne) { + digit = 1; + } else if (v == mTwo) { + digit = 2; + } else if (v == mThree) { + digit = 3; + } else if (v == mFour) { + digit = 4; + } else if (v == mFive) { + digit = 5; + } else if (v == mSix) { + digit = 6; + } else if (v == mSeven) { + digit = 7; + } else if (v == mEight) { + digit = 8; + } else if (v == mNine) { + digit = 9; + } + return digit; + } + } +} diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java new file mode 100644 index 000000000000..9aedf901d232 --- /dev/null +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2008 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 android.content.Context; +import android.content.ServiceConnection; +import android.os.CountDownTimer; +import android.os.SystemClock; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.MotionEvent; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import com.android.internal.R; +import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient; +import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockPatternView; + +import java.util.List; + +/** + * This is the screen that shows the 9 circle unlock widget and instructs + * the user how to unlock their device, or make an emergency call. + */ +class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient + implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback { + + private static final String TAG = "UnlockScreen"; + + // how long before we clear the wrong pattern + private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000; + + // how long we stay awake once the user is ready to enter a pattern + private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000; + + private int mFailedPatternAttemptsSinceLastTimeout = 0; + private int mTotalFailedPatternAttempts = 0; + private CountDownTimer mCountdownTimer = null; + + private final LockPatternUtils mLockPatternUtils; + private final KeyguardUpdateMonitor mUpdateMonitor; + private final KeyguardScreenCallback mCallback; + + private boolean mCreatedInPortrait; + + private ImageView mUnlockIcon; + private TextView mUnlockHeader; + private LockPatternView mLockPatternView; + + private ViewGroup mFooterNormal; + private ViewGroup mFooterForgotPattern; + + /** + * Keeps track of the last time we poked the wake lock during dispatching + * of the touch event, initalized to something gauranteed to make us + * poke it when the user starts drawing the pattern. + * @see #dispatchTouchEvent(android.view.MotionEvent) + */ + private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS; + + /** + * Useful for clearing out the wrong pattern after a delay + */ + private Runnable mCancelPatternRunnable = new Runnable() { + public void run() { + mLockPatternView.clearPattern(); + } + }; + + private Button mForgotPatternButton; + + private ServiceConnection mServiceConnection; + + + enum FooterMode { + Normal, + ForgotLockPattern, + VerifyUnlocked + } + + private void updateFooter(FooterMode mode) { + switch (mode) { + case Normal: + mFooterNormal.setVisibility(View.VISIBLE); + mFooterForgotPattern.setVisibility(View.GONE); + break; + case ForgotLockPattern: + mFooterNormal.setVisibility(View.GONE); + mFooterForgotPattern.setVisibility(View.VISIBLE); + break; + case VerifyUnlocked: + mFooterNormal.setVisibility(View.GONE); + mFooterForgotPattern.setVisibility(View.GONE); + } + } + + /** + * @param context The context. + * @param lockPatternUtils Used to lookup lock pattern settings. + * @param updateMonitor Used to lookup state affecting keyguard. + * @param callback Used to notify the manager when we're done, etc. + * @param totalFailedAttempts The current number of failed attempts. + */ + UnlockScreen(Context context, + LockPatternUtils lockPatternUtils, + KeyguardUpdateMonitor updateMonitor, + KeyguardScreenCallback callback, + int totalFailedAttempts) { + super(context); + mLockPatternUtils = lockPatternUtils; + mUpdateMonitor = updateMonitor; + mCallback = callback; + mTotalFailedPatternAttempts = totalFailedAttempts; + mFailedPatternAttemptsSinceLastTimeout = totalFailedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; + + if (mUpdateMonitor.isInPortrait()) { + LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_portrait, this, true); + } else { + LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_landscape, this, true); + } + + mUnlockIcon = (ImageView) findViewById(R.id.unlockLockIcon); + + mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern); + mUnlockHeader = (TextView) findViewById(R.id.headerText); + + mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); + + mFooterNormal = (ViewGroup) findViewById(R.id.footerNormal); + mFooterForgotPattern = (ViewGroup) findViewById(R.id.footerForgotPattern); + + // emergency call buttons + final OnClickListener emergencyClick = new OnClickListener() { + public void onClick(View v) { + mCallback.takeEmergencyCallAction(); + } + }; + Button emergencyAlone = (Button) findViewById(R.id.emergencyCallAlone); + emergencyAlone.setFocusable(false); // touch only! + emergencyAlone.setOnClickListener(emergencyClick); + Button emergencyTogether = (Button) findViewById(R.id.emergencyCallTogether); + emergencyTogether.setFocusable(false); + emergencyTogether.setOnClickListener(emergencyClick); + + mForgotPatternButton = (Button) findViewById(R.id.forgotPattern); + mForgotPatternButton.setText(R.string.lockscreen_forgot_pattern_button_text); + mForgotPatternButton.setOnClickListener(new OnClickListener() { + + public void onClick(View v) { + mLockPatternUtils.setPermanentlyLocked(true); + mCallback.goToUnlockScreen(); + } + }); + + // make it so unhandled touch events within the unlock screen go to the + // lock pattern view. + setDefaultTouchRecepient(mLockPatternView); + + mLockPatternView.setSaveEnabled(false); + mLockPatternView.setFocusable(false); + mLockPatternView.setOnPatternListener(new UnlockPatternListener()); + + // stealth mode will be the same for the life of this screen + mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled()); + + // vibrate mode will be the same for the life of this screen + mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled()); + + // assume normal footer mode for now + updateFooter(FooterMode.Normal); + + mCreatedInPortrait = updateMonitor.isInPortrait(); + updateMonitor.registerConfigurationChangeCallback(this); + setFocusableInTouchMode(true); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + mCallback.goToLockScreen(); + return true; + } + return false; + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + // as long as the user is entering a pattern (i.e sending a touch + // event that was handled by this screen), keep poking the + // wake lock so that the screen will stay on. + final boolean result = super.dispatchTouchEvent(ev); + if (result && + ((SystemClock.elapsedRealtime() - mLastPokeTime) + > (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) { + mLastPokeTime = SystemClock.elapsedRealtime(); + mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); + } + return result; + } + + /** {@inheritDoc} */ + public void onOrientationChange(boolean inPortrait) { + if (inPortrait != mCreatedInPortrait) { + mCallback.recreateMe(); + } + } + + /** {@inheritDoc} */ + public void onKeyboardChange(boolean isKeyboardOpen) {} + + /** {@inheritDoc} */ + public boolean needsInput() { + return false; + } + + /** {@inheritDoc} */ + public void onPause() { + if (mCountdownTimer != null) { + mCountdownTimer.cancel(); + mCountdownTimer = null; + } + } + + /** {@inheritDoc} */ + public void onResume() { + // reset header + mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); + mUnlockIcon.setVisibility(View.VISIBLE); + + // reset lock pattern + mLockPatternView.enableInput(); + mLockPatternView.setEnabled(true); + mLockPatternView.clearPattern(); + + // show "forgot pattern?" button if we have an alternate authentication method + mForgotPatternButton.setVisibility(mCallback.doesFallbackUnlockScreenExist() + ? View.VISIBLE : View.INVISIBLE); + + // if the user is currently locked out, enforce it. + long deadline = mLockPatternUtils.getLockoutAttemptDeadline(); + if (deadline != 0) { + handleAttemptLockout(deadline); + } + + // the footer depends on how many total attempts the user has failed + if (mCallback.isVerifyUnlockOnly()) { + updateFooter(FooterMode.VerifyUnlocked); + } else if (mTotalFailedPatternAttempts < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { + updateFooter(FooterMode.Normal); + } else { + updateFooter(FooterMode.ForgotLockPattern); + } + } + + /** {@inheritDoc} */ + public void cleanUp() { + mUpdateMonitor.removeCallback(this); + } + + private class UnlockPatternListener + implements LockPatternView.OnPatternListener { + + public void onPatternStart() { + mLockPatternView.removeCallbacks(mCancelPatternRunnable); + } + + public void onPatternCleared() { + } + + public void onPatternDetected(List pattern) { + if (mLockPatternUtils.checkPattern(pattern)) { + mLockPatternView + .setDisplayMode(LockPatternView.DisplayMode.Correct); + mUnlockIcon.setVisibility(View.GONE); + mUnlockHeader.setText(""); + mCallback.keyguardDone(true); + } else { + mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); + mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong); + if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { + mTotalFailedPatternAttempts++; + mFailedPatternAttemptsSinceLastTimeout++; + mCallback.reportFailedPatternAttempt(); + } + if (mFailedPatternAttemptsSinceLastTimeout >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { + long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); + handleAttemptLockout(deadline); + return; + } + mUnlockIcon.setVisibility(View.VISIBLE); + mUnlockHeader.setText(R.string.lockscreen_pattern_wrong); + mLockPatternView.postDelayed( + mCancelPatternRunnable, + PATTERN_CLEAR_TIMEOUT_MS); + } + } + } + + private void handleAttemptLockout(long elapsedRealtimeDeadline) { + mLockPatternView.clearPattern(); + mLockPatternView.setEnabled(false); + long elapsedRealtime = SystemClock.elapsedRealtime(); + mCountdownTimer = new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) { + + @Override + public void onTick(long millisUntilFinished) { + int secondsRemaining = (int) (millisUntilFinished / 1000); + mUnlockHeader.setText(getContext().getString( + R.string.lockscreen_too_many_failed_attempts_countdown, + secondsRemaining)); + } + + @Override + public void onFinish() { + mLockPatternView.setEnabled(true); + mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); + mUnlockIcon.setVisibility(View.VISIBLE); + mFailedPatternAttemptsSinceLastTimeout = 0; + updateFooter(FooterMode.ForgotLockPattern); + } + }.start(); + } + +} diff --git a/policy/com/android/internal/policy/impl/package.html b/policy/com/android/internal/policy/impl/package.html new file mode 100644 index 000000000000..c9f96a66ab3b --- /dev/null +++ b/policy/com/android/internal/policy/impl/package.html @@ -0,0 +1,5 @@ + + +{@hide} + + -- GitLab From 919607c9e5de670a3634c321cd42eb9d418dc695 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Thu, 5 Mar 2009 14:34:37 -0800 Subject: [PATCH 016/458] auto import from //depot/cupcake/@136594 --- policy/com/android/internal/policy/impl/PhoneWindow.java | 2 +- .../com/android/internal/policy/impl/PhoneWindowManager.java | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 0d26bfbbfac3..f3f166bba551 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -200,7 +200,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); if (imm != null) { - imm.showSoftInputUnchecked(InputMethodManager.SHOW_FORCED); + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); } } break; case MSG_CALL_LONG_PRESS_COMPLETE: { diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index d1b757604465..8ecb2b671a61 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -277,9 +277,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { rotation = (orientation >= 270 - _LOWER_THRESHOLD && orientation <= 270 + threshold) ? Surface.ROTATION_90 : Surface.ROTATION_0; - } else if (orientation == WindowOrientationListener.ORIENTATION_FLAT) { - // return portrait - rotation = Surface.ROTATION_0; } else { // ignore orientation value return; -- GitLab From bc8d29f85757ac0d8fa9a1065bf492105f98cea2 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Thu, 5 Mar 2009 20:00:44 -0800 Subject: [PATCH 017/458] auto import from //depot/cupcake/@136745 --- .../policy/impl/KeyguardViewBase.java | 14 +- .../internal/policy/impl/PhoneWindow.java | 171 ++++++++++-------- 2 files changed, 106 insertions(+), 79 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/com/android/internal/policy/impl/KeyguardViewBase.java index a565808e76c9..975c820d7bca 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewBase.java @@ -19,6 +19,7 @@ package com.android.internal.policy.impl; import android.content.Context; import android.content.Intent; import android.media.AudioManager; +import android.telephony.TelephonyManager; import android.view.KeyEvent; import android.view.View; import android.widget.FrameLayout; @@ -36,6 +37,7 @@ public abstract class KeyguardViewBase extends FrameLayout { private KeyguardViewCallback mCallback; private AudioManager mAudioManager; + private TelephonyManager mTelephonyManager = null; public KeyguardViewBase(Context context) { super(context); @@ -131,8 +133,18 @@ public abstract class KeyguardViewBase extends FrameLayout { final int keyCode = event.getKeyCode(); if (event.getAction() == KeyEvent.ACTION_DOWN) { switch (keyCode) { + case KeyEvent.KEYCODE_PLAYPAUSE: + /* Suppress PLAYPAUSE toggle when phone is ringing or + * in-call to avoid music playback */ + if (mTelephonyManager == null) { + mTelephonyManager = (TelephonyManager) getContext().getSystemService( + Context.TELEPHONY_SERVICE); + } + if (mTelephonyManager != null && + mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) { + return true; // suppress key event + } case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: case KeyEvent.KEYCODE_STOP: case KeyEvent.KEYCODE_NEXTSONG: case KeyEvent.KEYCODE_PREVIOUSSONG: diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index f3f166bba551..ceee0c0fe2f6 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -40,6 +40,7 @@ import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; +import android.telephony.TelephonyManager; import android.util.AndroidRuntimeException; import android.util.Config; import android.util.EventLog; @@ -142,14 +143,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private ContextMenuBuilder mContextMenu; private MenuDialogHelper mContextMenuHelper; - + private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; private long mVolumeKeyUpTime; private KeyguardManager mKeyguardManager = null; + + private TelephonyManager mTelephonyManager = null; private boolean mSearchKeyDownReceived; - + private boolean mKeycodeCallTimeoutActive = false; private boolean mKeycodeCameraTimeoutActive = false; @@ -160,7 +163,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { static final int MSG_CALL_LONG_PRESS_COMPLETE = 4; static final int MSG_CAMERA_LONG_PRESS = 5; static final int MSG_CAMERA_LONG_PRESS_COMPLETE = 6; - + private final Handler mKeycodeMenuTimeoutHandler = new Handler() { @Override public void handleMessage(Message msg) { @@ -189,8 +192,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { case MSG_CAMERA_LONG_PRESS: { if (!mKeycodeCameraTimeoutActive) return; // See above. - mKeycodeMenuTimeoutHandler.sendEmptyMessage( - MSG_CAMERA_LONG_PRESS_COMPLETE); + Message newMessage = Message.obtain(msg); + newMessage.what = MSG_CAMERA_LONG_PRESS_COMPLETE; + mKeycodeMenuTimeoutHandler.sendMessage(newMessage); break; } case MSG_MENU_LONG_PRESS_COMPLETE: { @@ -230,7 +234,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } }; - + public PhoneWindow(Context context) { super(context); mLayoutInflater = LayoutInflater.from(context); @@ -371,7 +375,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (cb != null) { st.createdPanelView = cb.onCreatePanelView(st.featureId); } - + if (st.createdPanelView == null) { // Init the panel state's menu--return false if init failed if (st.menu == null) { @@ -382,16 +386,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) { // Ditch the menu created above st.menu = null; - + return false; } } - + // Callback and return if the callback does not want to show the menu if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) { return false; } - + // Set the proper keymap KeyCharacterMap kmap = KeyCharacterMap.load(event != null ? event.getDeviceId() : 0); st.qwertyMode = kmap.getKeyboardType() != KeyCharacterMap.NUMERIC; @@ -411,7 +415,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { 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(); @@ -420,7 +424,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // Remove the menu views since they need to be recreated // according to the new configuration clearMenuViews(st); - + // Re-open the same menu reopenMenu(false); @@ -433,23 +437,23 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { 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. - + // Allow the callback to create a new panel view st.createdPanelView = null; - - // Causes the decor view to be recreated + + // Causes the decor view to be recreated st.refreshDecorView = true; - + ((MenuBuilder) st.menu).clearMenuViews(); } - + @Override public final void openPanel(int featureId, KeyEvent event) { openPanel(getPanelState(featureId, true), event); @@ -469,7 +473,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { closePanel(st, true); return; } - + final WindowManager wm = getWindowManager(); if (wm == null) { return; @@ -500,7 +504,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { lp = new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); } - int backgroundResId; + int backgroundResId; if (lp.width == ViewGroup.LayoutParams.FILL_PARENT) { // If the contents is fill parent for the width, set the // corresponding background @@ -511,10 +515,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } st.decorView.setWindowBackground(getContext().getResources().getDrawable( backgroundResId)); - + st.decorView.addView(st.shownPanelView, lp); - + /* * Give focus to the view, if it or one of its children does not * already have it. @@ -579,7 +583,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // This view is no longer shown, so null it out st.shownPanelView = null; - + if (st.isInExpandedMode) { // Next time the menu opens, it should not be in expanded mode, so // force a refresh of the decor @@ -638,29 +642,29 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mPanelChordingKey != 0) { mPanelChordingKey = 0; mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); - + boolean playSoundEffect = false; PanelFeatureState st = getPanelState(featureId, true); 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; - + // Close menu closePanel(st, true); - + } else if (st.isPrepared) { - + // Write 'menu opened' to event log EventLog.writeEvent(50001, 0); - + // Show menu openPanel(st, event); - + playSoundEffect = true; } - + if (playSoundEffect) { AudioManager audioManager = (AudioManager) getContext().getSystemService( Context.AUDIO_SERVICE); @@ -709,7 +713,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { */ private synchronized void dismissContextMenu() { mContextMenu = null; - + if (mContextMenuHelper != null) { mContextMenuHelper.dismiss(); mContextMenuHelper = null; @@ -882,12 +886,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * @return Whether the initialization was successful. */ protected boolean initializePanelContent(PanelFeatureState st) { - + if (st.createdPanelView != null) { st.shownPanelView = st.createdPanelView; return true; } - + final MenuBuilder menu = (MenuBuilder)st.menu; if (menu == null) { return false; @@ -1195,9 +1199,20 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return true; } + + case KeyEvent.KEYCODE_PLAYPAUSE: + /* Suppress PLAYPAUSE toggle when phone is ringing or in-call + * to avoid music playback */ + if (mTelephonyManager == null) { + mTelephonyManager = (TelephonyManager) getContext().getSystemService( + Context.TELEPHONY_SERVICE); + } + if (mTelephonyManager != null && + mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) { + return true; // suppress key event + } case KeyEvent.KEYCODE_MUTE: case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: case KeyEvent.KEYCODE_STOP: case KeyEvent.KEYCODE_NEXTSONG: case KeyEvent.KEYCODE_PREVIOUSSONG: @@ -1257,7 +1272,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { ViewConfiguration.getLongPressTimeout()); return true; } - + case KeyEvent.KEYCODE_SEARCH: { if (event.getRepeatCount() == 0) { mSearchKeyDownReceived = true; @@ -1311,12 +1326,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return true; } - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: case KeyEvent.KEYCODE_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); @@ -1495,7 +1510,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // The panel must not have been required, and is currently not around, skip it continue; } - + st.onRestoreInstanceState(icicles.get(curFeatureId)); } @@ -1579,7 +1594,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mVolumeControlStreamType, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); } } - + if (isDown && (event.getRepeatCount() == 0)) { // First handle chording of panel key: if a panel key is held // but not released, try to execute a shortcut in it. @@ -1589,7 +1604,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // prepared panel or menu). boolean handled = performPanelShortcut(mPreparedPanel, keyCode, event, Menu.FLAG_PERFORM_NO_CLOSE); - + if (!handled) { /* * If not handled, then pass it to the view hierarchy @@ -1625,7 +1640,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event) : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event); } - + @Override public boolean dispatchTouchEvent(MotionEvent ev) { final Callback cb = getCallback(); @@ -1792,7 +1807,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } - + @Override public boolean showContextMenuForChild(View originalView) { // Reuse the context menu builder @@ -1839,7 +1854,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { drawableChanged(); } } - + @Override protected boolean fitSystemWindows(Rect insets) { mFrameOffsets.set(insets); @@ -1913,7 +1928,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); - + // no KEYCODE_CALL events active across focus changes mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); @@ -1926,7 +1941,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (!hasWindowFocus && mPanelChordingKey > 0) { closePanel(FEATURE_OPTIONS_PANEL); } - + final Callback cb = getCallback(); if (cb != null && mFeatureId < 0) { cb.onWindowFocusChanged(hasWindowFocus); @@ -1993,7 +2008,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } else { setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate); } - + if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) { requestFeature(FEATURE_NO_TITLE); } @@ -2003,13 +2018,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } WindowManager.LayoutParams params = getAttributes(); - + if (!hasSoftInputMode()) { params.softInputMode = a.getInt( com.android.internal.R.styleable.Window_windowSoftInputMode, params.softInputMode); } - + if (a.getBoolean(com.android.internal.R.styleable.Window_backgroundDimEnabled, mIsFloating)) { /* All dialogs should have the window dimmed */ @@ -2024,7 +2039,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { params.windowAnimations = a.getResourceId( com.android.internal.R.styleable.Window_windowAnimationStyle, 0); } - + // The rest are only done if this window is not embedded; otherwise, // the values are inherited from our container. if (getContainer() == null) { @@ -2198,7 +2213,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { /** * Gets a panel's state based on its feature ID. - * + * * @param featureId The feature ID of the panel. * @param required Whether the panel is required (if it is required and it * isn't in our features, this throws an exception). @@ -2207,10 +2222,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private PanelFeatureState getPanelState(int featureId, boolean required) { return getPanelState(featureId, required, null); } - + /** * Gets a panel's state based on its feature ID. - * + * * @param featureId The feature ID of the panel. * @param required Whether the panel is required (if it is required and it * isn't in our features, this throws an exception). @@ -2300,7 +2315,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } private void updateInt(int featureId, int value, boolean fromResume) { - + // Do nothing if the decor is not yet installed... an update will // need to be forced when we eventually become active. if (mContentParent == null) { @@ -2371,7 +2386,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * callback. This method will grab whatever extra state is needed for the * callback that isn't given in the parameters. If the panel is not open, * this will not perform the callback. - * + * * @param featureId Feature ID of the panel that was closed. Must be given. * @param panel Panel that was closed. Optional but useful if there is no * menu given. @@ -2407,7 +2422,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { /** * Helper method for adding launch-search to most applications. Opens the * search window using default settings. - * + * * @return true if search window opened */ private boolean launchDefaultSearch() { @@ -2418,7 +2433,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return cb.onSearchRequested(); } } - + @Override public void setVolumeControlStream(int streamType) { mVolumeControlStreamType = streamType; @@ -2454,7 +2469,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } private static final class PanelFeatureState { - + /** Feature ID for this panel. */ int featureId; @@ -2478,11 +2493,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { /** The panel that was returned by onCreatePanelView(). */ View createdPanelView; - + /** The panel that we are actually showing. */ View shownPanelView; - /** Use {@link #setMenu} to set this. */ + /** Use {@link #setMenu} to set this. */ Menu menu; /** @@ -2514,7 +2529,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * Contains the state of the menu when told to freeze. */ Bundle frozenMenuState; - + PanelFeatureState(int featureId) { this.featureId = featureId; @@ -2534,7 +2549,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { void setMenu(Menu menu) { this.menu = menu; - + if (frozenMenuState != null) { ((MenuBuilder) menu).restoreHierarchyState(frozenMenuState); frozenMenuState = null; @@ -2551,7 +2566,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { savedState.menuState = new Bundle(); ((MenuBuilder) menu).saveHierarchyState(savedState.menuState); } - + return savedState; } @@ -2574,13 +2589,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { shownPanelView = null; decorView = null; } - + private static class SavedState implements Parcelable { int featureId; boolean isOpen; boolean isInExpandedMode; Bundle menuState; - + public int describeContents() { return 0; } @@ -2594,20 +2609,20 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { dest.writeBundle(menuState); } } - + private static SavedState readFromParcel(Parcel source) { SavedState savedState = new SavedState(); savedState.featureId = source.readInt(); savedState.isOpen = source.readInt() == 1; savedState.isInExpandedMode = source.readInt() == 1; - + if (savedState.isOpen) { savedState.menuState = source.readBundle(); } - + return savedState; } - + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public SavedState createFromParcel(Parcel in) { @@ -2619,7 +2634,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } }; } - + } /** @@ -2631,7 +2646,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private final class ContextMenuCallback implements MenuBuilder.Callback { private int mFeatureId; private MenuDialogHelper mSubMenuHelper; - + public ContextMenuCallback(int featureId) { mFeatureId = featureId; } @@ -2640,11 +2655,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (allMenusAreClosing) { Callback callback = getCallback(); if (callback != null) callback.onPanelClosed(mFeatureId, menu); - + if (menu == mContextMenu) { dismissContextMenu(); } - + // Dismiss the submenu, if it is showing if (mSubMenuHelper != null) { mSubMenuHelper.dismiss(); @@ -2673,7 +2688,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // The window manager will give us a valid window token mSubMenuHelper = new MenuDialogHelper(subMenu); mSubMenuHelper.show(null); - + return true; } } -- GitLab From c84bf28b74972b98351e2481168833c84cfcbd85 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Mon, 9 Mar 2009 11:52:14 -0700 Subject: [PATCH 018/458] auto import from //branches/cupcake/...@137197 --- .../policy/impl/KeyguardViewMediator.java | 7 +++++++ .../policy/impl/PhoneWindowManager.java | 18 ++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index e7366c2a72d6..ead1348612fb 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -203,6 +203,11 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private boolean mKeyboardOpen = false; + /** + * we send this intent when the keyguard is dismissed. + */ + private Intent mUserPresentIntent; + /** * {@link #setKeyguardEnabled} waits on this condition when it reenables * the keyguard. @@ -248,6 +253,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, context, WindowManagerImpl.getDefault(), this, mKeyguardViewProperties, mUpdateMonitor); + mUserPresentIntent = new Intent(Intent.ACTION_USER_PRESENT); } /** @@ -772,6 +778,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, handleHide(); mPM.userActivity(SystemClock.uptimeMillis(), true); mWakeLock.release(); + mContext.sendBroadcast(mUserPresentIntent); } /** diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 8ecb2b671a61..5bbd5e920868 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -140,8 +140,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Vibrator pattern for haptic feedback of a long press. private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21}; - // Vibrator pattern for haptic feedback of a zoom ring tick - private static final long[] ZOOM_RING_TICK_VIBE_PATTERN = {0, 10}; Context mContext; IWindowManager mWindowManager; @@ -1223,6 +1221,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public boolean finishAnimationLw() { boolean changed = false; + boolean hiding = false; if (mStatusBar != null) { //Log.i(TAG, "force=" + mForceStatusBar // + " top=" + mTopFullscreenOpaqueWindowState); @@ -1238,11 +1237,24 @@ public class PhoneWindowManager implements WindowManagerPolicy { (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; if (hideStatusBar) { changed |= mStatusBar.hideLw(true); + hiding = true; } else { changed |= mStatusBar.showLw(true); } } } + + if (changed && hiding) { + IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar")); + if (sbs != null) { + try { + // Make sure the window shade is hidden. + sbs.deactivate(); + } catch (RemoteException e) { + } + } + } + return changed; } @@ -1782,8 +1794,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { case HapticFeedbackConstants.LONG_PRESS: mVibrator.vibrate(LONG_PRESS_VIBE_PATTERN, -1); return true; - case HapticFeedbackConstants.ZOOM_RING_TICK: - mVibrator.vibrate(ZOOM_RING_TICK_VIBE_PATTERN, -1); } return false; } -- GitLab From 0727d22ece1f346d4a79a6b173cf992dd190f00a Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Wed, 11 Mar 2009 12:11:58 -0700 Subject: [PATCH 019/458] auto import from //branches/cupcake/...@137873 --- .../policy/impl/PhoneWindowManager.java | 137 ++++++++++-------- 1 file changed, 77 insertions(+), 60 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 5bbd5e920868..9a254bcfae2b 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -87,12 +87,15 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; -import android.view.WindowManagerPolicy.WindowState; import android.media.IAudioService; import android.media.AudioManager; /** - * WindowManagerPolicy implementation for the Android phone UI. + * WindowManagerPolicy implementation for the Android phone UI. This + * introduces a new method suffix, Lp, for an internal lock of the + * PhoneWindowManager. This is used to protect some internal state, and + * can be acquired with either thw Lw and Li lock held, so has the restrictions + * of both of those when held. */ public class PhoneWindowManager implements WindowManagerPolicy { static final String TAG = "WindowManager"; @@ -141,6 +144,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Vibrator pattern for haptic feedback of a long press. private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21}; + final Object mLock = new Object(); + Context mContext; IWindowManager mWindowManager; LocalPowerManager mPowerManager; @@ -234,20 +239,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void update() { ContentResolver resolver = mContext.getContentResolver(); - mEndcallBehavior = Settings.System.getInt(resolver, - Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); - int accelerometerDefault = Settings.System.getInt(resolver, - Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); - if (mAccelerometerDefault != accelerometerDefault) { - mAccelerometerDefault = accelerometerDefault; - updateOrientationListener(); - } - String imId = Settings.Secure.getString(resolver, - Settings.Secure.DEFAULT_INPUT_METHOD); - boolean hasSoftInput = imId != null && imId.length() > 0; - if (mHasSoftInput != hasSoftInput) { - mHasSoftInput = hasSoftInput; - updateRotation(); + synchronized (mLock) { + mEndcallBehavior = Settings.System.getInt(resolver, + Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); + int accelerometerDefault = Settings.System.getInt(resolver, + Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); + if (mAccelerometerDefault != accelerometerDefault) { + mAccelerometerDefault = accelerometerDefault; + updateOrientationListenerLp(); + } + String imId = Settings.Secure.getString(resolver, + Settings.Secure.DEFAULT_INPUT_METHOD); + boolean hasSoftInput = imId != null && imId.length() > 0; + if (mHasSoftInput != hasSoftInput) { + mHasSoftInput = hasSoftInput; + updateRotation(); + } } } } @@ -296,7 +303,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } MyOrientationListener mOrientationListener; - boolean useSensorForOrientation() { + boolean useSensorForOrientationLp() { if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { return true; } @@ -308,8 +315,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } - boolean needSensorRunning() { - if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { + boolean needSensorRunningLp() { + if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { // If the application has explicitly requested to follow the // orientation, then we need to turn the sensor or. return true; @@ -338,22 +345,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { * screen turning on and current app has sensor based orientation, enable listeners if needed * screen turning on and current app has nosensor based orientation, do nothing */ - void updateOrientationListener() { + void updateOrientationListenerLp() { if (!mOrientationListener.canDetectOrientation()) { // If sensor is turned off or nonexistent for some reason return; } //Could have been invoked due to screen turning on or off or //change of the currently visible window's orientation - if(localLOGV) Log.i(TAG, "Screen status="+mScreenOn+ + if (localLOGV) Log.i(TAG, "Screen status="+mScreenOn+ ", current orientation="+mCurrentAppOrientation+ ", SensorEnabled="+mOrientationSensorEnabled); boolean disable = true; - if(mScreenOn) { - if(needSensorRunning()) { + if (mScreenOn) { + if (needSensorRunningLp()) { disable = false; //enable listener if not already enabled - if(!mOrientationSensorEnabled) { + if (!mOrientationSensorEnabled) { mOrientationListener.enable(); if(localLOGV) Log.i(TAG, "Enabling listeners"); // We haven't had the sensor on, so don't yet know @@ -364,7 +371,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } //check if sensors need to be disabled - if(disable && mOrientationSensorEnabled) { + if (disable && mOrientationSensorEnabled) { mOrientationListener.disable(); if(localLOGV) Log.i(TAG, "Disabling listeners"); mSensorRotation = -1; @@ -375,7 +382,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Runnable mEndCallLongPress = new Runnable() { public void run() { mShouldTurnOffOnKeyUp = false; - performHapticFeedback(null, HapticFeedbackConstants.LONG_PRESS, false); + performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); showGlobalActionsDialog(); } @@ -409,7 +416,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * the user lets go of the home key */ mHomePressed = false; - performHapticFeedback(null, HapticFeedbackConstants.LONG_PRESS, false); + performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS); showRecentAppsDialog(); } @@ -1615,18 +1622,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void screenTurnedOff(int why) { - EventLog.writeEvent(70000, 0); - mKeyguardMediator.onScreenTurnedOff(why); - mScreenOn = false; - updateOrientationListener(); + synchronized (mLock) { + EventLog.writeEvent(70000, 0); + mKeyguardMediator.onScreenTurnedOff(why); + mScreenOn = false; + updateOrientationListenerLp(); + } } /** {@inheritDoc} */ public void screenTurnedOn() { - EventLog.writeEvent(70000, 1); - mKeyguardMediator.onScreenTurnedOn(); - mScreenOn = true; - updateOrientationListener(); + synchronized (mLock) { + EventLog.writeEvent(70000, 1); + mKeyguardMediator.onScreenTurnedOn(); + mScreenOn = true; + updateOrientationListenerLp(); + } } /** {@inheritDoc} */ @@ -1674,27 +1685,29 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - public int rotationForOrientation(int orientation, int lastRotation, + public int rotationForOrientationLw(int orientation, int lastRotation, boolean displayEnabled) { - switch (orientation) { - case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: - //always return landscape if orientation set to landscape + synchronized (mLock) { + switch (orientation) { + case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: + //always return landscape if orientation set to landscape + return Surface.ROTATION_90; + case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: + //always return portrait if orientation set to portrait + return Surface.ROTATION_0; + } + // case for nosensor meaning ignore sensor and consider only lid + // or orientation sensor disabled + //or case.unspecified + if (mLidOpen) { return Surface.ROTATION_90; - case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: - //always return portrait if orientation set to portrait + } else { + if (useSensorForOrientationLp()) { + // If the user has enabled auto rotation by default, do it. + return mSensorRotation >= 0 ? mSensorRotation : lastRotation; + } return Surface.ROTATION_0; - } - // case for nosensor meaning ignore sensor and consider only lid - // or orientation sensor disabled - //or case.unspecified - if (mLidOpen) { - return Surface.ROTATION_90; - } else { - if (useSensorForOrientation()) { - // If the user has enabled auto rotation by default, do it. - return mSensorRotation >= 0 ? mSensorRotation : lastRotation; } - return Surface.ROTATION_0; } } @@ -1721,8 +1734,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // tell the keyguard mKeyguardMediator.onSystemReady(); android.os.SystemProperties.set("dev.bootcomplete", "1"); - updateOrientationListener(); - mVibrator = new Vibrator(); + synchronized (mLock) { + updateOrientationListenerLp(); + mVibrator = new Vibrator(); + } } catch (RemoteException e) { // Ignore } @@ -1778,14 +1793,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { return true; } - public void setCurrentOrientation(int newOrientation) { - if(newOrientation != mCurrentAppOrientation) { - mCurrentAppOrientation = newOrientation; - updateOrientationListener(); + public void setCurrentOrientationLw(int newOrientation) { + synchronized (mLock) { + if (newOrientation != mCurrentAppOrientation) { + mCurrentAppOrientation = newOrientation; + updateOrientationListenerLp(); + } } } - public boolean performHapticFeedback(WindowState win, int effectId, boolean always) { + public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) { if (!always && Settings.System.getInt(mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) { return false; @@ -1798,7 +1815,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } - public void screenOnStopped() { + public void screenOnStoppedLw() { if (!mKeyguardMediator.isShowing()) { long curTime = SystemClock.uptimeMillis(); mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); -- GitLab From d06b097626bd83745c2ef3400d7044d675f01b70 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Fri, 13 Mar 2009 13:04:23 -0700 Subject: [PATCH 020/458] auto import from //branches/cupcake_rel/...@138607 --- .../internal/policy/impl/PhoneWindow.java | 44 +++++++++++++++++++ .../policy/impl/PhoneWindowManager.java | 22 +--------- .../internal/policy/impl/SimUnlockScreen.java | 6 +-- 3 files changed, 48 insertions(+), 24 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index ceee0c0fe2f6..8d9a73333584 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -163,6 +163,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { static final int MSG_CALL_LONG_PRESS_COMPLETE = 4; static final int MSG_CAMERA_LONG_PRESS = 5; static final int MSG_CAMERA_LONG_PRESS_COMPLETE = 6; + static final int MSG_SEARCH_LONG_PRESS = 7; + static final int MSG_SEARCH_LONG_PRESS_COMPLETE = 8; private final Handler mKeycodeMenuTimeoutHandler = new Handler() { @Override @@ -197,6 +199,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mKeycodeMenuTimeoutHandler.sendMessage(newMessage); break; } + case MSG_SEARCH_LONG_PRESS: { + if (!mSearchKeyDownReceived) return; + // See above. + Message newMessage = Message.obtain(msg); + newMessage.what = MSG_SEARCH_LONG_PRESS_COMPLETE; + mKeycodeMenuTimeoutHandler.sendMessage(newMessage); + break; + } case MSG_MENU_LONG_PRESS_COMPLETE: { if (mPanelChordingKey == 0) return; mPanelChordingKey = 0; @@ -231,6 +241,26 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { getContext().sendOrderedBroadcast(intent, null); sendCloseSystemWindows(); } break; + case MSG_SEARCH_LONG_PRESS_COMPLETE: { + if (getKeyguardManager().inKeyguardRestrictedInputMode() || + !mSearchKeyDownReceived) { + mSearchKeyDownReceived = false; + return; + } + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + // launch the search activity + Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + sendCloseSystemWindows(); + getContext().startActivity(intent); + // Only clear this if we successfully start the + // activity; otherwise we will allow the normal short + // press action to be performed. + mSearchKeyDownReceived = false; + } catch (ActivityNotFoundException e) { + } + } break; } } }; @@ -1276,6 +1306,19 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { case KeyEvent.KEYCODE_SEARCH: { if (event.getRepeatCount() == 0) { mSearchKeyDownReceived = true; + Configuration config = getContext().getResources().getConfiguration(); + if (config.keyboard == Configuration.KEYBOARD_NOKEYS + || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { + // If this device does not have a hardware keyboard, + // or that keyboard is hidden, then we can't use the + // search key for chording to perform shortcuts; + // instead, we will let the user long press, + mKeycodeMenuTimeoutHandler.removeMessages(MSG_SEARCH_LONG_PRESS); + mKeycodeMenuTimeoutHandler.sendMessageDelayed( + mKeycodeMenuTimeoutHandler.obtainMessage(MSG_SEARCH_LONG_PRESS), + ViewConfiguration.getLongPressTimeout()); + } + return true; } break; } @@ -1370,6 +1413,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { */ if (getKeyguardManager().inKeyguardRestrictedInputMode() || !mSearchKeyDownReceived) { + mSearchKeyDownReceived = false; break; } mSearchKeyDownReceived = false; diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 9a254bcfae2b..3e2b9276fee9 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -260,32 +260,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } class MyOrientationListener extends WindowOrientationListener { - private static final int _LOWER_THRESHOLD = 30; - private static final int _UPPER_THRESHOLD = 60; - MyOrientationListener(Context context) { super(context); } @Override - public void onOrientationChanged(int orientation) { - // ignore orientation changes unless the value is in a range - // When switching from portrait to landscape try to use a lower threshold limit - // Use upper threshold limit when switching from landscape to portrait - // this is to delay the switch as much as we can - int rotation; - int threshold = (mSensorRotation == Surface.ROTATION_90) ? _UPPER_THRESHOLD : - _LOWER_THRESHOLD; - - if ((orientation >= 0 && orientation <= _UPPER_THRESHOLD) || - (orientation >= 270 - _LOWER_THRESHOLD)) { - rotation = (orientation >= 270 - _LOWER_THRESHOLD - && orientation <= 270 + threshold) - ? Surface.ROTATION_90 : Surface.ROTATION_0; - } else { - // ignore orientation value - return; - } + public void onOrientationChanged(int rotation) { // Send updates based on orientation value if (rotation != mSensorRotation) { if(localLOGV) Log.i(TAG, "onOrientationChanged, rotation changed from "+rotation+" to "+mSensorRotation); diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java index 9453212d4ad1..0f7fe32a8278 100644 --- a/policy/com/android/internal/policy/impl/SimUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/SimUnlockScreen.java @@ -46,7 +46,7 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie private final boolean mCreatedWithKeyboardOpen; private TextView mHeaderText; - private EditText mPinText; + private TextView mPinText; private TextView mOkButton; private TextView mEmergencyCallButton; @@ -75,7 +75,7 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie } mHeaderText = (TextView) findViewById(R.id.headerText); - mPinText = (EditText) findViewById(R.id.pinDisplay); + mPinText = (TextView) findViewById(R.id.pinDisplay); mBackSpaceButton = findViewById(R.id.backspace); mBackSpaceButton.setOnClickListener(this); @@ -159,7 +159,7 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie public void onClick(View v) { if (v == mBackSpaceButton) { - final Editable digits = mPinText.getText(); + final Editable digits = mPinText.getEditableText(); final int len = digits.length(); if (len > 0) { digits.delete(len-1, len); -- GitLab From 1126766d7643db2b4028e2e5217af3db0a01b2aa Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Wed, 18 Mar 2009 17:39:47 -0700 Subject: [PATCH 021/458] auto import from //branches/cupcake_rel/...@140373 --- .../policy/impl/PhoneWindowManager.java | 15 +++- .../internal/policy/impl/ShutdownThread.java | 77 ++++++++++++++----- 2 files changed, 70 insertions(+), 22 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 3e2b9276fee9..5ea73bde9f5c 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -101,6 +101,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final String TAG = "WindowManager"; static final boolean DEBUG = false; static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; + static final boolean DEBUG_LAYOUT = false; static final boolean SHOW_STARTING_ANIMATIONS = true; static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; @@ -992,6 +993,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // 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); } } } @@ -1152,11 +1156,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000; } + if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle() + + ": sim=#" + Integer.toHexString(sim) + + " pf=" + pf.toShortString() + " df=" + df.toShortString() + + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()); + if (false) { if ("com.google.android.youtube".equals(attrs.packageName) && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { if (true || localLOGV) Log.v(TAG, "Computing frame of " + win + - ": pf=" + pf.toShortString() + " df=" + df.toShortString() + ": sim=#" + Integer.toHexString(sim) + + " pf=" + pf.toShortString() + " df=" + df.toShortString() + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()); } } @@ -1176,6 +1186,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mCurBottom > top) { mCurBottom = top; } + if (DEBUG_LAYOUT) Log.v(TAG, "Input method: mDockBottom=" + + mDockBottom + " mContentBottom=" + + mContentBottom + " mCurBottom=" + mCurBottom); } } diff --git a/policy/com/android/internal/policy/impl/ShutdownThread.java b/policy/com/android/internal/policy/impl/ShutdownThread.java index 994b1d50bdf9..c61d60b52426 100644 --- a/policy/com/android/internal/policy/impl/ShutdownThread.java +++ b/policy/com/android/internal/policy/impl/ShutdownThread.java @@ -19,6 +19,8 @@ package com.android.internal.policy.impl; import android.app.ProgressDialog; import android.app.AlertDialog; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.IBluetoothDevice; import android.content.Context; import android.content.DialogInterface; import android.os.RemoteException; @@ -35,9 +37,12 @@ final class ShutdownThread extends Thread { private static final String TAG = "ShutdownThread"; private static final int MAX_NUM_PHONE_STATE_READS = 16; private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500; - private static final ITelephony sPhone = + private static final ITelephony sPhone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); - + private static final IBluetoothDevice sBluetooth = + IBluetoothDevice.Stub.asInterface(ServiceManager.getService(Context.BLUETOOTH_SERVICE)); + + // state tracking private static Object sIsStartedGuard = new Object(); private static boolean sIsStarted = false; @@ -62,7 +67,7 @@ final class ShutdownThread extends Thread { return; } } - + Log.d(TAG, "Notifying thread to start radio shutdown"); if (confirm) { @@ -106,31 +111,61 @@ final class ShutdownThread extends Thread { sInstance.start(); } - /** - * Makes sure we handle the shutdown gracefully. - * Shuts off power regardless of radio state if the alloted time has passed. + /** + * Makes sure we handle the shutdown gracefully. + * Shuts off power regardless of radio and bluetooth state if the alloted time has passed. */ public void run() { - //shutdown the phone radio if possible. - if (sPhone != null) { - try { - //shutdown radio + boolean bluetoothOff; + boolean radioOff; + + try { + bluetoothOff = sBluetooth == null || + sBluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF; + if (!bluetoothOff) { + sBluetooth.disable(false); // disable but don't persist new state + } + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during bluetooth shutdown", ex); + bluetoothOff = true; + } + + try { + radioOff = sPhone == null || !sPhone.isRadioOn(); + if (!radioOff) { sPhone.setRadio(false); + } + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during radio shutdown", ex); + radioOff = true; + } - for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++){ - // poll radio up to 64 times, with a 0.5 sec delay between each call, - // totaling 32 sec. - if (!sPhone.isRadioOn()) { - Log.d(TAG, "Radio shutdown complete."); - break; - } - SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC); + // Wait a max of 32 seconds for clean shutdown + for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++) { + if (!bluetoothOff) { + try { + bluetoothOff = + sBluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF; + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during bluetooth shutdown", ex); + bluetoothOff = true; } - } catch (RemoteException ex) { - Log.e(TAG, "RemoteException caught from failed radio shutdown.", ex); } + if (!radioOff) { + try { + radioOff = !sPhone.isRadioOn(); + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during radio shutdown", ex); + radioOff = true; + } + } + if (radioOff && bluetoothOff) { + Log.d(TAG, "Radio and Bluetooth shutdown complete."); + break; + } + SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC); } - + //shutdown power Log.d(TAG, "Shutting down power."); Power.shutdown(); -- GitLab From 092639eccf1ac6b854b7c18774f9e9f891e0ac61 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Thu, 19 Mar 2009 23:08:56 -0700 Subject: [PATCH 022/458] auto import from //branches/cupcake_rel/...@141571 --- .../android/internal/policy/impl/KeyguardViewBase.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/com/android/internal/policy/impl/KeyguardViewBase.java index 975c820d7bca..f67f6a9773e4 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewBase.java @@ -22,7 +22,9 @@ import android.media.AudioManager; import android.telephony.TelephonyManager; import android.view.KeyEvent; import android.view.View; +import android.view.Gravity; import android.widget.FrameLayout; +import android.util.AttributeSet; /** * Base class for keyguard views. {@link #reset} is where you should @@ -41,6 +43,13 @@ public abstract class KeyguardViewBase extends FrameLayout { public KeyguardViewBase(Context context) { super(context); + + // drop shadow below status bar in keyguard too + mForegroundInPadding = false; + setForegroundGravity(Gravity.FILL_HORIZONTAL | Gravity.TOP); + setForeground( + context.getResources().getDrawable( + com.android.internal.R.drawable.title_bar_shadow)); } // used to inject callback -- GitLab From 75898be585d5e075b7d4bfc0af74a73a318ece2e Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Tue, 24 Mar 2009 18:18:49 -0700 Subject: [PATCH 023/458] Automated import from //branches/cupcake/...@141745,141745 --- .../android/internal/policy/impl/PhoneWindowManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 5ea73bde9f5c..c6c053e0e425 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1615,9 +1615,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void screenTurnedOff(int why) { + EventLog.writeEvent(70000, 0); + mKeyguardMediator.onScreenTurnedOff(why); synchronized (mLock) { - EventLog.writeEvent(70000, 0); - mKeyguardMediator.onScreenTurnedOff(why); mScreenOn = false; updateOrientationListenerLp(); } @@ -1625,9 +1625,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void screenTurnedOn() { + EventLog.writeEvent(70000, 1); + mKeyguardMediator.onScreenTurnedOn(); synchronized (mLock) { - EventLog.writeEvent(70000, 1); - mKeyguardMediator.onScreenTurnedOn(); mScreenOn = true; updateOrientationListenerLp(); } -- GitLab From ad2973418253cf489a8f94d008ca2e82cfb6576c Mon Sep 17 00:00:00 2001 From: Karl Rosaen <> Date: Tue, 24 Mar 2009 18:55:19 -0700 Subject: [PATCH 024/458] Automated import from //branches/donutburger/...@140911,140911 --- .../android/internal/policy/impl/KeyguardViewBase.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/com/android/internal/policy/impl/KeyguardViewBase.java index 975c820d7bca..f67f6a9773e4 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewBase.java @@ -22,7 +22,9 @@ import android.media.AudioManager; import android.telephony.TelephonyManager; import android.view.KeyEvent; import android.view.View; +import android.view.Gravity; import android.widget.FrameLayout; +import android.util.AttributeSet; /** * Base class for keyguard views. {@link #reset} is where you should @@ -41,6 +43,13 @@ public abstract class KeyguardViewBase extends FrameLayout { public KeyguardViewBase(Context context) { super(context); + + // drop shadow below status bar in keyguard too + mForegroundInPadding = false; + setForegroundGravity(Gravity.FILL_HORIZONTAL | Gravity.TOP); + setForeground( + context.getResources().getDrawable( + com.android.internal.R.drawable.title_bar_shadow)); } // used to inject callback -- GitLab From eb7f363c647746c946f378f29e08b329c34ab937 Mon Sep 17 00:00:00 2001 From: Karl Rosaen <> Date: Tue, 24 Mar 2009 18:55:23 -0700 Subject: [PATCH 025/458] Automated import from //branches/master/...@140913,140913 --- .../android/internal/policy/impl/KeyguardViewBase.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/com/android/internal/policy/impl/KeyguardViewBase.java index 975c820d7bca..f67f6a9773e4 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewBase.java @@ -22,7 +22,9 @@ import android.media.AudioManager; import android.telephony.TelephonyManager; import android.view.KeyEvent; import android.view.View; +import android.view.Gravity; import android.widget.FrameLayout; +import android.util.AttributeSet; /** * Base class for keyguard views. {@link #reset} is where you should @@ -41,6 +43,13 @@ public abstract class KeyguardViewBase extends FrameLayout { public KeyguardViewBase(Context context) { super(context); + + // drop shadow below status bar in keyguard too + mForegroundInPadding = false; + setForegroundGravity(Gravity.FILL_HORIZONTAL | Gravity.TOP); + setForeground( + context.getResources().getDrawable( + com.android.internal.R.drawable.title_bar_shadow)); } // used to inject callback -- GitLab From ad22c18b7ce346ec0fcd751f50ab39474804d312 Mon Sep 17 00:00:00 2001 From: Suchi Amalapurapu <> Date: Tue, 24 Mar 2009 19:18:40 -0700 Subject: [PATCH 026/458] Automated import from //branches/cupcake/...@142231,142231 --- .../internal/policy/impl/PhoneWindowManager.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index c6c053e0e425..8334a0c6e273 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -296,13 +296,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } + /* + * We always let the sensor be switched on by default except when + * the user has explicitly disabled sensor based rotation or when the + * screen is switched off. + */ boolean needSensorRunningLp() { if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { // If the application has explicitly requested to follow the // orientation, then we need to turn the sensor or. return true; } - if (mAccelerometerDefault != 0) { + if (mAccelerometerDefault == 0) { // If the setting for using the sensor by default is enabled, then // we will always leave it on. Note that the user could go to // a window that forces an orientation that does not use the @@ -311,9 +316,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // orientation for a little bit, which can cause orientation // changes to lag, so we'd like to keep it always on. (It will // still be turned off when the screen is off.) - return true; + return false; } - return false; + return true; } /* -- GitLab From d3a60997ebcba710bbf192554d055aaaad8e1bed Mon Sep 17 00:00:00 2001 From: Karl Rosaen <> Date: Tue, 24 Mar 2009 19:31:39 -0700 Subject: [PATCH 027/458] Automated import from //branches/cupcake/...@142360,142360 --- .../policy/impl/KeyguardViewMediator.java | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index ead1348612fb..71acef90aa83 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -16,11 +16,14 @@ package com.android.internal.policy.impl; +import com.android.internal.telephony.SimCard; +import com.android.internal.widget.LockPatternUtils; + import android.app.AlarmManager; import android.app.PendingIntent; import android.app.StatusBarManager; -import static android.app.StatusBarManager.DISABLE_NONE; import static android.app.StatusBarManager.DISABLE_EXPAND; +import static android.app.StatusBarManager.DISABLE_NONE; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -30,15 +33,13 @@ import android.os.LocalPowerManager; import android.os.Message; import android.os.PowerManager; import android.os.SystemClock; +import android.telephony.TelephonyManager; import android.util.Config; -import android.util.Log; import android.util.EventLog; +import android.util.Log; import android.view.KeyEvent; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; -import com.android.internal.telephony.SimCard; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.widget.LockPatternUtils; /** * Mediates requests related to the keyguard. This includes queries about the @@ -203,6 +204,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private boolean mKeyboardOpen = false; + private boolean mScreenOn = false; + /** * we send this intent when the keyguard is dismissed. */ @@ -232,8 +235,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, IntentFilter filter = new IntentFilter(); filter.addAction(DELAYED_KEYGUARD_ACTION); - filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); - filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); context.registerReceiver(mBroadCastReceiver, filter); mAlarmManager = (AlarmManager) context .getSystemService(Context.ALARM_SERVICE); @@ -274,6 +276,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ public void onScreenTurnedOff(int why) { synchronized (this) { + mScreenOn = false; if (DEBUG) Log.d(TAG, "onScreenTurnedOff(" + why + ")"); if (mExitSecureCallback != null) { @@ -310,6 +313,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ public void onScreenTurnedOn() { synchronized (this) { + mScreenOn = true; mDelayedShowingSequence++; if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence); notifyScreenOnLocked(); @@ -436,6 +440,16 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // if another app is disabling us, don't show if (!mExternallyEnabled) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled"); + + // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes + // for an occasional ugly flicker in this situation: + // 1) receive a call with the screen on (no keyguard) or make a call + // 2) screen times out + // 3) user hits key to turn screen back on + // instead, we reenable the keyguard when we know the screen is off and the call + // ends (see the broadcast receiver below) + // TODO: clean this up when we have better support at the window manager level + // for apps that wish to be on top of the keyguard return; } @@ -612,6 +626,19 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (mDelayedShowingSequence == sequence) { doKeyguard(); } + } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action) + && TelephonyManager.EXTRA_STATE_IDLE.equals(intent.getStringExtra( + TelephonyManager.EXTRA_STATE)) // call ending + && !mScreenOn // screen off + && mExternallyEnabled) { // not disabled by any app + + // note: this is a way to gracefully reenable the keyguard when the call + // ends and the screen is off without always reenabling the keyguard + // each time the screen turns off while in call (and having an occasional ugly + // flicker while turning back on the screen and disabling the keyguard again). + if (DEBUG) Log.d(TAG, "screen is off and call ended, let's make sure the " + + "keyguard is showing"); + doKeyguard(); } } }; -- GitLab From 7448901deed5885df11ffb9fdc29e5d3c07b1418 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Tue, 24 Mar 2009 20:50:09 -0700 Subject: [PATCH 028/458] Automated import from //branches/donutburger/...@141746,141746 --- .../android/internal/policy/impl/PhoneWindowManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 5ea73bde9f5c..c6c053e0e425 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1615,9 +1615,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void screenTurnedOff(int why) { + EventLog.writeEvent(70000, 0); + mKeyguardMediator.onScreenTurnedOff(why); synchronized (mLock) { - EventLog.writeEvent(70000, 0); - mKeyguardMediator.onScreenTurnedOff(why); mScreenOn = false; updateOrientationListenerLp(); } @@ -1625,9 +1625,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void screenTurnedOn() { + EventLog.writeEvent(70000, 1); + mKeyguardMediator.onScreenTurnedOn(); synchronized (mLock) { - EventLog.writeEvent(70000, 1); - mKeyguardMediator.onScreenTurnedOn(); mScreenOn = true; updateOrientationListenerLp(); } -- GitLab From afe270f4d11daf2c352ee2b60b183adb3f3fb4fd Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Tue, 24 Mar 2009 20:51:57 -0700 Subject: [PATCH 029/458] Automated import from //branches/master/...@141749,141749 --- .../android/internal/policy/impl/PhoneWindowManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 5ea73bde9f5c..c6c053e0e425 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1615,9 +1615,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void screenTurnedOff(int why) { + EventLog.writeEvent(70000, 0); + mKeyguardMediator.onScreenTurnedOff(why); synchronized (mLock) { - EventLog.writeEvent(70000, 0); - mKeyguardMediator.onScreenTurnedOff(why); mScreenOn = false; updateOrientationListenerLp(); } @@ -1625,9 +1625,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void screenTurnedOn() { + EventLog.writeEvent(70000, 1); + mKeyguardMediator.onScreenTurnedOn(); synchronized (mLock) { - EventLog.writeEvent(70000, 1); - mKeyguardMediator.onScreenTurnedOn(); mScreenOn = true; updateOrientationListenerLp(); } -- GitLab From a9e1b169adb1c59f0971e980ec86ea73e61ba7cb Mon Sep 17 00:00:00 2001 From: Suchi Amalapurapu <> Date: Tue, 24 Mar 2009 22:24:47 -0700 Subject: [PATCH 030/458] Automated import from //branches/donutburger/...@142291,142291 --- .../internal/policy/impl/PhoneWindowManager.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index c6c053e0e425..8334a0c6e273 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -296,13 +296,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } + /* + * We always let the sensor be switched on by default except when + * the user has explicitly disabled sensor based rotation or when the + * screen is switched off. + */ boolean needSensorRunningLp() { if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { // If the application has explicitly requested to follow the // orientation, then we need to turn the sensor or. return true; } - if (mAccelerometerDefault != 0) { + if (mAccelerometerDefault == 0) { // If the setting for using the sensor by default is enabled, then // we will always leave it on. Note that the user could go to // a window that forces an orientation that does not use the @@ -311,9 +316,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // orientation for a little bit, which can cause orientation // changes to lag, so we'd like to keep it always on. (It will // still be turned off when the screen is off.) - return true; + return false; } - return false; + return true; } /* -- GitLab From 5f5aed707d5955174381e6849dba9b20eef2107c Mon Sep 17 00:00:00 2001 From: Suchi Amalapurapu <> Date: Tue, 24 Mar 2009 22:32:56 -0700 Subject: [PATCH 031/458] Automated import from //branches/master/...@142306,142306 --- .../internal/policy/impl/PhoneWindowManager.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index c6c053e0e425..8334a0c6e273 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -296,13 +296,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } + /* + * We always let the sensor be switched on by default except when + * the user has explicitly disabled sensor based rotation or when the + * screen is switched off. + */ boolean needSensorRunningLp() { if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { // If the application has explicitly requested to follow the // orientation, then we need to turn the sensor or. return true; } - if (mAccelerometerDefault != 0) { + if (mAccelerometerDefault == 0) { // If the setting for using the sensor by default is enabled, then // we will always leave it on. Note that the user could go to // a window that forces an orientation that does not use the @@ -311,9 +316,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // orientation for a little bit, which can cause orientation // changes to lag, so we'd like to keep it always on. (It will // still be turned off when the screen is off.) - return true; + return false; } - return false; + return true; } /* -- GitLab From ab1000856df7108236919ec4ab0f7ba17c445986 Mon Sep 17 00:00:00 2001 From: Karl Rosaen <> Date: Tue, 24 Mar 2009 22:35:17 -0700 Subject: [PATCH 032/458] Automated import from //branches/donutburger/...@142361,142361 --- .../policy/impl/KeyguardViewMediator.java | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index ead1348612fb..71acef90aa83 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -16,11 +16,14 @@ package com.android.internal.policy.impl; +import com.android.internal.telephony.SimCard; +import com.android.internal.widget.LockPatternUtils; + import android.app.AlarmManager; import android.app.PendingIntent; import android.app.StatusBarManager; -import static android.app.StatusBarManager.DISABLE_NONE; import static android.app.StatusBarManager.DISABLE_EXPAND; +import static android.app.StatusBarManager.DISABLE_NONE; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -30,15 +33,13 @@ import android.os.LocalPowerManager; import android.os.Message; import android.os.PowerManager; import android.os.SystemClock; +import android.telephony.TelephonyManager; import android.util.Config; -import android.util.Log; import android.util.EventLog; +import android.util.Log; import android.view.KeyEvent; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; -import com.android.internal.telephony.SimCard; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.widget.LockPatternUtils; /** * Mediates requests related to the keyguard. This includes queries about the @@ -203,6 +204,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private boolean mKeyboardOpen = false; + private boolean mScreenOn = false; + /** * we send this intent when the keyguard is dismissed. */ @@ -232,8 +235,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, IntentFilter filter = new IntentFilter(); filter.addAction(DELAYED_KEYGUARD_ACTION); - filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); - filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); context.registerReceiver(mBroadCastReceiver, filter); mAlarmManager = (AlarmManager) context .getSystemService(Context.ALARM_SERVICE); @@ -274,6 +276,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ public void onScreenTurnedOff(int why) { synchronized (this) { + mScreenOn = false; if (DEBUG) Log.d(TAG, "onScreenTurnedOff(" + why + ")"); if (mExitSecureCallback != null) { @@ -310,6 +313,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ public void onScreenTurnedOn() { synchronized (this) { + mScreenOn = true; mDelayedShowingSequence++; if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence); notifyScreenOnLocked(); @@ -436,6 +440,16 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // if another app is disabling us, don't show if (!mExternallyEnabled) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled"); + + // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes + // for an occasional ugly flicker in this situation: + // 1) receive a call with the screen on (no keyguard) or make a call + // 2) screen times out + // 3) user hits key to turn screen back on + // instead, we reenable the keyguard when we know the screen is off and the call + // ends (see the broadcast receiver below) + // TODO: clean this up when we have better support at the window manager level + // for apps that wish to be on top of the keyguard return; } @@ -612,6 +626,19 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (mDelayedShowingSequence == sequence) { doKeyguard(); } + } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action) + && TelephonyManager.EXTRA_STATE_IDLE.equals(intent.getStringExtra( + TelephonyManager.EXTRA_STATE)) // call ending + && !mScreenOn // screen off + && mExternallyEnabled) { // not disabled by any app + + // note: this is a way to gracefully reenable the keyguard when the call + // ends and the screen is off without always reenabling the keyguard + // each time the screen turns off while in call (and having an occasional ugly + // flicker while turning back on the screen and disabling the keyguard again). + if (DEBUG) Log.d(TAG, "screen is off and call ended, let's make sure the " + + "keyguard is showing"); + doKeyguard(); } } }; -- GitLab From bc192314032a4cd42379a11c548a7f92cd518cc6 Mon Sep 17 00:00:00 2001 From: Karl Rosaen <> Date: Tue, 24 Mar 2009 22:42:29 -0700 Subject: [PATCH 033/458] Automated import from //branches/master/...@142363,142363 --- .../policy/impl/KeyguardViewMediator.java | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index ead1348612fb..71acef90aa83 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -16,11 +16,14 @@ package com.android.internal.policy.impl; +import com.android.internal.telephony.SimCard; +import com.android.internal.widget.LockPatternUtils; + import android.app.AlarmManager; import android.app.PendingIntent; import android.app.StatusBarManager; -import static android.app.StatusBarManager.DISABLE_NONE; import static android.app.StatusBarManager.DISABLE_EXPAND; +import static android.app.StatusBarManager.DISABLE_NONE; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -30,15 +33,13 @@ import android.os.LocalPowerManager; import android.os.Message; import android.os.PowerManager; import android.os.SystemClock; +import android.telephony.TelephonyManager; import android.util.Config; -import android.util.Log; import android.util.EventLog; +import android.util.Log; import android.view.KeyEvent; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; -import com.android.internal.telephony.SimCard; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.widget.LockPatternUtils; /** * Mediates requests related to the keyguard. This includes queries about the @@ -203,6 +204,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private boolean mKeyboardOpen = false; + private boolean mScreenOn = false; + /** * we send this intent when the keyguard is dismissed. */ @@ -232,8 +235,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, IntentFilter filter = new IntentFilter(); filter.addAction(DELAYED_KEYGUARD_ACTION); - filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); - filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); context.registerReceiver(mBroadCastReceiver, filter); mAlarmManager = (AlarmManager) context .getSystemService(Context.ALARM_SERVICE); @@ -274,6 +276,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ public void onScreenTurnedOff(int why) { synchronized (this) { + mScreenOn = false; if (DEBUG) Log.d(TAG, "onScreenTurnedOff(" + why + ")"); if (mExitSecureCallback != null) { @@ -310,6 +313,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ public void onScreenTurnedOn() { synchronized (this) { + mScreenOn = true; mDelayedShowingSequence++; if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence); notifyScreenOnLocked(); @@ -436,6 +440,16 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // if another app is disabling us, don't show if (!mExternallyEnabled) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled"); + + // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes + // for an occasional ugly flicker in this situation: + // 1) receive a call with the screen on (no keyguard) or make a call + // 2) screen times out + // 3) user hits key to turn screen back on + // instead, we reenable the keyguard when we know the screen is off and the call + // ends (see the broadcast receiver below) + // TODO: clean this up when we have better support at the window manager level + // for apps that wish to be on top of the keyguard return; } @@ -612,6 +626,19 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (mDelayedShowingSequence == sequence) { doKeyguard(); } + } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action) + && TelephonyManager.EXTRA_STATE_IDLE.equals(intent.getStringExtra( + TelephonyManager.EXTRA_STATE)) // call ending + && !mScreenOn // screen off + && mExternallyEnabled) { // not disabled by any app + + // note: this is a way to gracefully reenable the keyguard when the call + // ends and the screen is off without always reenabling the keyguard + // each time the screen turns off while in call (and having an occasional ugly + // flicker while turning back on the screen and disabling the keyguard again). + if (DEBUG) Log.d(TAG, "screen is off and call ended, let's make sure the " + + "keyguard is showing"); + doKeyguard(); } } }; -- GitLab From 4e8f62fbcb4c1edf0e6ef379ad231fa74b12a248 Mon Sep 17 00:00:00 2001 From: Fred Quintana <> Date: Tue, 24 Mar 2009 22:48:13 -0700 Subject: [PATCH 034/458] Automated import from //branches/master/...@142414,142414 --- .../policy/impl/AccountUnlockScreen.java | 76 ++++++------------- .../policy/impl/LockPatternKeyguardView.java | 49 ++---------- 2 files changed, 28 insertions(+), 97 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index 65102c67fc8b..aae1c7fe4082 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -19,21 +19,15 @@ package com.android.internal.policy.impl; import com.android.internal.R; import com.android.internal.widget.LockPatternUtils; -import android.accounts.AccountsServiceConstants; -import android.accounts.IAccountsService; -import android.content.ComponentName; +import android.accounts.Account; +import android.accounts.AccountManager; import android.content.Context; import android.content.Intent; -import android.content.ServiceConnection; import android.graphics.Rect; -import android.os.IBinder; -import android.os.RemoteException; import android.text.Editable; import android.text.InputFilter; import android.text.LoginFilter; import android.text.TextWatcher; -import android.text.TextUtils; -import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -45,12 +39,9 @@ import android.widget.TextView; /** * When the user forgets their password a bunch of times, we fall back on their * account's login/password to unlock the phone (and reset their lock pattern). - * - *

    This class is useful only on platforms that support the - * IAccountsService. */ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen, - View.OnClickListener, ServiceConnection, TextWatcher { + View.OnClickListener, TextWatcher { private static final String LOCK_PATTERN_PACKAGE = "com.android.settings"; private static final String LOCK_PATTERN_CLASS = "com.android.settings.ChooseLockPattern"; @@ -62,7 +53,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree private final KeyguardScreenCallback mCallback; private final LockPatternUtils mLockPatternUtils; - private IAccountsService mAccountsService; + private AccountManager mAccountManager; private TextView mTopHeader; private TextView mInstructions; @@ -73,9 +64,6 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree /** * AccountUnlockScreen constructor. - * - * @throws IllegalStateException if the IAccountsService is not - * available on the current platform. */ public AccountUnlockScreen(Context context, KeyguardScreenCallback callback, @@ -103,13 +91,11 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree mEmergencyCall = (Button) findViewById(R.id.emergencyCall); mEmergencyCall.setOnClickListener(this); + } - Log.v("AccountUnlockScreen", "debug: Connecting to accounts service"); - final boolean connected = mContext.bindService(AccountsServiceConstants.SERVICE_INTENT, - this, Context.BIND_AUTO_CREATE); - if (!connected) { - Log.v("AccountUnlockScreen", "debug: Couldn't connect to accounts service"); - throw new IllegalStateException("couldn't bind to accounts service"); + void ensureAccountManager() { + if (mAccountManager == null) { + mAccountManager = (AccountManager)mContext.getSystemService(Context.ACCOUNT_SERVICE); } } @@ -150,7 +136,6 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree /** {@inheritDoc} */ public void cleanUp() { - mContext.unbindService(this); } /** {@inheritDoc} */ @@ -207,13 +192,9 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree * @return an account name from the database, or null if we can't * find a single best match. */ - private String findIntendedAccount(String username) { - String[] accounts = null; - try { - accounts = mAccountsService.getAccounts(); - } catch (RemoteException e) { - return null; - } + private Account findIntendedAccount(String username) { + ensureAccountManager(); + Account[] accounts = mAccountManager.blockingGetAccounts(); if (accounts == null) { return null; } @@ -222,18 +203,18 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree // typed only the username (and not the domain), or got // the case wrong. - String bestAccount = null; + Account bestAccount = null; int bestScore = 0; - for (String a: accounts) { + for (Account a: accounts) { int score = 0; - if (username.equals(a)) { + if (username.equals(a.mName)) { score = 4; - } else if (username.equalsIgnoreCase(a)) { + } else if (username.equalsIgnoreCase(a.mName)) { score = 3; } else if (username.indexOf('@') < 0) { - int i = a.indexOf('@'); + int i = a.mName.indexOf('@'); if (i >= 0) { - String aUsername = a.substring(0, i); + String aUsername = a.mName.substring(0, i); if (username.equals(aUsername)) { score = 2; } else if (username.equalsIgnoreCase(aUsername)) { @@ -254,25 +235,12 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree private boolean checkPassword() { final String login = mLogin.getText().toString(); final String password = mPassword.getText().toString(); - try { - String account = findIntendedAccount(login); - if (account == null) { - return false; - } - return mAccountsService.shouldUnlock(account, password); - } catch (RemoteException e) { + Account account = findIntendedAccount(login); + if (account == null) { return false; } - } - - /** {@inheritDoc} */ - public void onServiceConnected(ComponentName name, IBinder service) { - Log.v("AccountUnlockScreen", "debug: About to grab as interface"); - mAccountsService = IAccountsService.Stub.asInterface(service); - } - - /** {@inheritDoc} */ - public void onServiceDisconnected(ComponentName name) { - mAccountsService = null; + // change this to asynchronously issue the request and wait for the response + ensureAccountManager(); + return mAccountManager.authenticateAccount(account, password); } } diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index cb3131d0e8b4..e8fb7fdd924a 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -16,15 +16,10 @@ package com.android.internal.policy.impl; -import android.accounts.AccountsServiceConstants; -import android.accounts.IAccountsService; +import android.accounts.AccountManager; import android.app.AlertDialog; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.ServiceConnection; -import android.os.IBinder; -import android.os.RemoteException; import android.os.SystemProperties; import com.android.internal.telephony.SimCard; import android.text.TextUtils; @@ -130,11 +125,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase { */ private final LockPatternUtils mLockPatternUtils; - /** - * Used to fetch accounts from GLS. - */ - private ServiceConnection mServiceConnection; - /** * @return Whether we are stuck on the lock screen because the sim is * missing. @@ -158,9 +148,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase { LockPatternUtils lockPatternUtils, KeyguardWindowController controller) { super(context); - - asyncCheckForAccount(); - + + AccountManager accountManager = + (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE); + mHasAccount = accountManager.blockingGetAccounts().length > 0; + mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); @@ -277,35 +269,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase { updateScreen(mMode); } - /** - * Asynchronously checks for at least one account. This will set mHasAccount - * to true if an account is found. - */ - private void asyncCheckForAccount() { - - mServiceConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - try { - IAccountsService accountsService = IAccountsService.Stub.asInterface(service); - String accounts[] = accountsService.getAccounts(); - mHasAccount = (accounts.length > 0); - } catch (RemoteException e) { - // Not much we can do here... - Log.e(TAG, "Gls died while attempting to get accounts: " + e); - } finally { - getContext().unbindService(mServiceConnection); - mServiceConnection = null; - } - } - - public void onServiceDisconnected(ComponentName className) { - // nothing to do here - } - }; - boolean status = getContext().bindService(AccountsServiceConstants.SERVICE_INTENT, - mServiceConnection, Context.BIND_AUTO_CREATE); - if (!status) Log.e(TAG, "Failed to bind to GLS while checking for account"); - } @Override public void reset() { -- GitLab From 42c1397842d65768e0714f6e21ce3d64de6e11e7 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Wed, 25 Mar 2009 22:39:21 -0700 Subject: [PATCH 035/458] Automated import from //branches/cupcake/...@142870,142870 --- .../policy/impl/PhoneWindowManager.java | 53 +++++++++---------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 8334a0c6e273..d8009e778fbe 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -166,7 +166,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { Handler mHandler; boolean mLidOpen; - int mSensorRotation = -1; boolean mScreenOn = false; boolean mOrientationSensorEnabled = false; int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -207,6 +206,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int ENDCALL_SLEEPS = 0x2; static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; int mEndcallBehavior; + + // Nothing to see here, move along... + int mFancyRotationAnimation; ShortcutManager mShortcutManager; PowerManager.WakeLock mBroadcastWakeLock; @@ -226,13 +228,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.System.ACCELEROMETER_ROTATION), false, this); resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.DEFAULT_INPUT_METHOD), false, this); + resolver.registerContentObserver(Settings.System.getUriFor( + "fancy_rotation_anim"), false, this); update(); } @Override public void onChange(boolean selfChange) { update(); try { - mWindowManager.setRotation(USE_LAST_ROTATION, false); + mWindowManager.setRotation(USE_LAST_ROTATION, false, 1); } catch (RemoteException e) { // Ignore } @@ -243,6 +247,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { synchronized (mLock) { mEndcallBehavior = Settings.System.getInt(resolver, Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); + mFancyRotationAnimation = Settings.System.getInt(resolver, + "fancy_rotation_animation", 0); int accelerometerDefault = Settings.System.getInt(resolver, Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); if (mAccelerometerDefault != accelerometerDefault) { @@ -254,7 +260,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean hasSoftInput = imId != null && imId.length() > 0; if (mHasSoftInput != hasSoftInput) { mHasSoftInput = hasSoftInput; - updateRotation(); + updateRotation(1); } } } @@ -268,29 +274,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void onOrientationChanged(int rotation) { // Send updates based on orientation value - if (rotation != mSensorRotation) { - if(localLOGV) Log.i(TAG, "onOrientationChanged, rotation changed from "+rotation+" to "+mSensorRotation); - // Update window manager. The lid rotation hasn't changed, - // but we want it to re-evaluate the final rotation in case - // it needs to call back and get the sensor orientation. - mSensorRotation = rotation; - try { - mWindowManager.setRotation(rotation, false); - } catch (RemoteException e) { - // Ignore - } + if (true) Log.i(TAG, "onOrientationChanged, rotation changed to " +rotation); + try { + mWindowManager.setRotation(rotation, false, 1); + } catch (RemoteException e) { + // Ignore } } } MyOrientationListener mOrientationListener; - boolean useSensorForOrientationLp() { - if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { + boolean useSensorForOrientationLp(int appOrientation) { + if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { return true; } if (mAccelerometerDefault != 0 && ( - mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || - mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { + appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || + appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { return true; } return false; @@ -349,9 +349,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (!mOrientationSensorEnabled) { mOrientationListener.enable(); if(localLOGV) Log.i(TAG, "Enabling listeners"); - // We haven't had the sensor on, so don't yet know - // the rotation. - mSensorRotation = -1; mOrientationSensorEnabled = true; } } @@ -360,7 +357,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (disable && mOrientationSensorEnabled) { mOrientationListener.disable(); if(localLOGV) Log.i(TAG, "Disabling listeners"); - mSensorRotation = -1; mOrientationSensorEnabled = false; } } @@ -1270,7 +1266,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (event.keycode == 0) { // lid changed state mLidOpen = event.value == 0; - updateRotation(); + updateRotation(0); if (keyguardIsShowingTq()) { if (mLidOpen) { // only do this if it's opening -- closing the device shouldn't turn it @@ -1700,9 +1696,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mLidOpen) { return Surface.ROTATION_90; } else { - if (useSensorForOrientationLp()) { + if (useSensorForOrientationLp(orientation)) { // If the user has enabled auto rotation by default, do it. - return mSensorRotation >= 0 ? mSensorRotation : lastRotation; + int curRotation = mOrientationListener.getCurrentRotation(); + return curRotation >= 0 ? curRotation : lastRotation; } return Surface.ROTATION_0; } @@ -1745,10 +1742,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void enableScreenAfterBoot() { readLidState(); - updateRotation(); + updateRotation(0); } - void updateRotation() { + void updateRotation(int animFlags) { mPowerManager.setKeyboardVisibility(mLidOpen); int rotation= Surface.ROTATION_0; if (mLidOpen) { @@ -1758,7 +1755,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { //if lid is closed orientation will be portrait try { //set orientation on WindowManager - mWindowManager.setRotation(rotation, true); + mWindowManager.setRotation(rotation, true, animFlags); } catch (RemoteException e) { // Ignore } -- GitLab From d63323bb542c02c056b119ae667edc625823e992 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Thu, 26 Mar 2009 00:04:52 -0700 Subject: [PATCH 036/458] Automated import from //branches/cupcake/...@142879,142879 --- .../policy/impl/PhoneWindowManager.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index d8009e778fbe..bf0f81518c11 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -236,7 +236,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void onChange(boolean selfChange) { update(); try { - mWindowManager.setRotation(USE_LAST_ROTATION, false, 1); + mWindowManager.setRotation(USE_LAST_ROTATION, false, + mFancyRotationAnimation); } catch (RemoteException e) { // Ignore } @@ -248,7 +249,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mEndcallBehavior = Settings.System.getInt(resolver, Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); mFancyRotationAnimation = Settings.System.getInt(resolver, - "fancy_rotation_animation", 0); + "fancy_rotation_anim", 0) != 0 ? 0x80 : 0; int accelerometerDefault = Settings.System.getInt(resolver, Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); if (mAccelerometerDefault != accelerometerDefault) { @@ -260,7 +261,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean hasSoftInput = imId != null && imId.length() > 0; if (mHasSoftInput != hasSoftInput) { mHasSoftInput = hasSoftInput; - updateRotation(1); + updateRotation(0); } } } @@ -276,7 +277,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Send updates based on orientation value if (true) Log.i(TAG, "onOrientationChanged, rotation changed to " +rotation); try { - mWindowManager.setRotation(rotation, false, 1); + mWindowManager.setRotation(rotation, false, + mFancyRotationAnimation); } catch (RemoteException e) { // Ignore } @@ -1266,7 +1268,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (event.keycode == 0) { // lid changed state mLidOpen = event.value == 0; - updateRotation(0); + updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); if (keyguardIsShowingTq()) { if (mLidOpen) { // only do this if it's opening -- closing the device shouldn't turn it @@ -1742,7 +1744,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void enableScreenAfterBoot() { readLidState(); - updateRotation(0); + updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); } void updateRotation(int animFlags) { @@ -1755,7 +1757,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { //if lid is closed orientation will be portrait try { //set orientation on WindowManager - mWindowManager.setRotation(rotation, true, animFlags); + mWindowManager.setRotation(rotation, true, + mFancyRotationAnimation | animFlags); } catch (RemoteException e) { // Ignore } -- GitLab From 03759ed36d0a56ae8dbdccf8e1f6c8e3d14165b7 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Fri, 27 Mar 2009 16:04:08 -0700 Subject: [PATCH 037/458] AI 143169: am: CL 142870 Fix issue #1724917 (Applications (browser, maps, gmail) fail to retain their landscape state after coming out of sleep mode). We now rely on the listeners last known orientation, and make sure to clear it when enabling/disabling. Also do most of the work for issue #1732012 (Only show screen rotation animation when triggered by sensor). This just needs to be hooked up to the surface flinger API when that appears. Original author: hackbod Merged from: //branches/cupcake/... Automated import of CL 143169 --- .../policy/impl/PhoneWindowManager.java | 53 +++++++++---------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 8334a0c6e273..d8009e778fbe 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -166,7 +166,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { Handler mHandler; boolean mLidOpen; - int mSensorRotation = -1; boolean mScreenOn = false; boolean mOrientationSensorEnabled = false; int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -207,6 +206,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int ENDCALL_SLEEPS = 0x2; static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; int mEndcallBehavior; + + // Nothing to see here, move along... + int mFancyRotationAnimation; ShortcutManager mShortcutManager; PowerManager.WakeLock mBroadcastWakeLock; @@ -226,13 +228,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.System.ACCELEROMETER_ROTATION), false, this); resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.DEFAULT_INPUT_METHOD), false, this); + resolver.registerContentObserver(Settings.System.getUriFor( + "fancy_rotation_anim"), false, this); update(); } @Override public void onChange(boolean selfChange) { update(); try { - mWindowManager.setRotation(USE_LAST_ROTATION, false); + mWindowManager.setRotation(USE_LAST_ROTATION, false, 1); } catch (RemoteException e) { // Ignore } @@ -243,6 +247,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { synchronized (mLock) { mEndcallBehavior = Settings.System.getInt(resolver, Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); + mFancyRotationAnimation = Settings.System.getInt(resolver, + "fancy_rotation_animation", 0); int accelerometerDefault = Settings.System.getInt(resolver, Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); if (mAccelerometerDefault != accelerometerDefault) { @@ -254,7 +260,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean hasSoftInput = imId != null && imId.length() > 0; if (mHasSoftInput != hasSoftInput) { mHasSoftInput = hasSoftInput; - updateRotation(); + updateRotation(1); } } } @@ -268,29 +274,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void onOrientationChanged(int rotation) { // Send updates based on orientation value - if (rotation != mSensorRotation) { - if(localLOGV) Log.i(TAG, "onOrientationChanged, rotation changed from "+rotation+" to "+mSensorRotation); - // Update window manager. The lid rotation hasn't changed, - // but we want it to re-evaluate the final rotation in case - // it needs to call back and get the sensor orientation. - mSensorRotation = rotation; - try { - mWindowManager.setRotation(rotation, false); - } catch (RemoteException e) { - // Ignore - } + if (true) Log.i(TAG, "onOrientationChanged, rotation changed to " +rotation); + try { + mWindowManager.setRotation(rotation, false, 1); + } catch (RemoteException e) { + // Ignore } } } MyOrientationListener mOrientationListener; - boolean useSensorForOrientationLp() { - if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { + boolean useSensorForOrientationLp(int appOrientation) { + if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { return true; } if (mAccelerometerDefault != 0 && ( - mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || - mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { + appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || + appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { return true; } return false; @@ -349,9 +349,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (!mOrientationSensorEnabled) { mOrientationListener.enable(); if(localLOGV) Log.i(TAG, "Enabling listeners"); - // We haven't had the sensor on, so don't yet know - // the rotation. - mSensorRotation = -1; mOrientationSensorEnabled = true; } } @@ -360,7 +357,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (disable && mOrientationSensorEnabled) { mOrientationListener.disable(); if(localLOGV) Log.i(TAG, "Disabling listeners"); - mSensorRotation = -1; mOrientationSensorEnabled = false; } } @@ -1270,7 +1266,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (event.keycode == 0) { // lid changed state mLidOpen = event.value == 0; - updateRotation(); + updateRotation(0); if (keyguardIsShowingTq()) { if (mLidOpen) { // only do this if it's opening -- closing the device shouldn't turn it @@ -1700,9 +1696,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mLidOpen) { return Surface.ROTATION_90; } else { - if (useSensorForOrientationLp()) { + if (useSensorForOrientationLp(orientation)) { // If the user has enabled auto rotation by default, do it. - return mSensorRotation >= 0 ? mSensorRotation : lastRotation; + int curRotation = mOrientationListener.getCurrentRotation(); + return curRotation >= 0 ? curRotation : lastRotation; } return Surface.ROTATION_0; } @@ -1745,10 +1742,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void enableScreenAfterBoot() { readLidState(); - updateRotation(); + updateRotation(0); } - void updateRotation() { + void updateRotation(int animFlags) { mPowerManager.setKeyboardVisibility(mLidOpen); int rotation= Surface.ROTATION_0; if (mLidOpen) { @@ -1758,7 +1755,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { //if lid is closed orientation will be portrait try { //set orientation on WindowManager - mWindowManager.setRotation(rotation, true); + mWindowManager.setRotation(rotation, true, animFlags); } catch (RemoteException e) { // Ignore } -- GitLab From 32bc91d6f66d85137670144e1d40b069c16d3e9d Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Fri, 27 Mar 2009 16:16:03 -0700 Subject: [PATCH 038/458] AI 143173: am: CL 142879 Fix issue #1732012 (Only show screen rotation animation when triggered by sensor) -- set the new surface flag as appropriate. Original author: hackbod Merged from: //branches/cupcake/... Automated import of CL 143173 --- .../policy/impl/PhoneWindowManager.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index d8009e778fbe..bf0f81518c11 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -236,7 +236,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void onChange(boolean selfChange) { update(); try { - mWindowManager.setRotation(USE_LAST_ROTATION, false, 1); + mWindowManager.setRotation(USE_LAST_ROTATION, false, + mFancyRotationAnimation); } catch (RemoteException e) { // Ignore } @@ -248,7 +249,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mEndcallBehavior = Settings.System.getInt(resolver, Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); mFancyRotationAnimation = Settings.System.getInt(resolver, - "fancy_rotation_animation", 0); + "fancy_rotation_anim", 0) != 0 ? 0x80 : 0; int accelerometerDefault = Settings.System.getInt(resolver, Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); if (mAccelerometerDefault != accelerometerDefault) { @@ -260,7 +261,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean hasSoftInput = imId != null && imId.length() > 0; if (mHasSoftInput != hasSoftInput) { mHasSoftInput = hasSoftInput; - updateRotation(1); + updateRotation(0); } } } @@ -276,7 +277,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Send updates based on orientation value if (true) Log.i(TAG, "onOrientationChanged, rotation changed to " +rotation); try { - mWindowManager.setRotation(rotation, false, 1); + mWindowManager.setRotation(rotation, false, + mFancyRotationAnimation); } catch (RemoteException e) { // Ignore } @@ -1266,7 +1268,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (event.keycode == 0) { // lid changed state mLidOpen = event.value == 0; - updateRotation(0); + updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); if (keyguardIsShowingTq()) { if (mLidOpen) { // only do this if it's opening -- closing the device shouldn't turn it @@ -1742,7 +1744,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void enableScreenAfterBoot() { readLidState(); - updateRotation(0); + updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); } void updateRotation(int animFlags) { @@ -1755,7 +1757,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { //if lid is closed orientation will be portrait try { //set orientation on WindowManager - mWindowManager.setRotation(rotation, true, animFlags); + mWindowManager.setRotation(rotation, true, + mFancyRotationAnimation | animFlags); } catch (RemoteException e) { // Ignore } -- GitLab From 8632450c72c56f088cd8eb83d94edf9e31968e9d Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Fri, 27 Mar 2009 18:09:17 -0700 Subject: [PATCH 039/458] AI 143318: am: CL 143169 am: CL 142870 Fix issue #1724917 (Applications (browser, maps, gmail) fail to retain their landscape state after coming out of sleep mode). We now rely on the listeners last known orientation, and make sure to clear it when enabling/disabling. Also do most of the work for issue #1732012 (Only show screen rotation animation when triggered by sensor). This just needs to be hooked up to the surface flinger API when that appears. Original author: hackbod Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143318 --- .../policy/impl/PhoneWindowManager.java | 53 +++++++++---------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 8334a0c6e273..d8009e778fbe 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -166,7 +166,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { Handler mHandler; boolean mLidOpen; - int mSensorRotation = -1; boolean mScreenOn = false; boolean mOrientationSensorEnabled = false; int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -207,6 +206,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int ENDCALL_SLEEPS = 0x2; static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; int mEndcallBehavior; + + // Nothing to see here, move along... + int mFancyRotationAnimation; ShortcutManager mShortcutManager; PowerManager.WakeLock mBroadcastWakeLock; @@ -226,13 +228,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.System.ACCELEROMETER_ROTATION), false, this); resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.DEFAULT_INPUT_METHOD), false, this); + resolver.registerContentObserver(Settings.System.getUriFor( + "fancy_rotation_anim"), false, this); update(); } @Override public void onChange(boolean selfChange) { update(); try { - mWindowManager.setRotation(USE_LAST_ROTATION, false); + mWindowManager.setRotation(USE_LAST_ROTATION, false, 1); } catch (RemoteException e) { // Ignore } @@ -243,6 +247,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { synchronized (mLock) { mEndcallBehavior = Settings.System.getInt(resolver, Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); + mFancyRotationAnimation = Settings.System.getInt(resolver, + "fancy_rotation_animation", 0); int accelerometerDefault = Settings.System.getInt(resolver, Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); if (mAccelerometerDefault != accelerometerDefault) { @@ -254,7 +260,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean hasSoftInput = imId != null && imId.length() > 0; if (mHasSoftInput != hasSoftInput) { mHasSoftInput = hasSoftInput; - updateRotation(); + updateRotation(1); } } } @@ -268,29 +274,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void onOrientationChanged(int rotation) { // Send updates based on orientation value - if (rotation != mSensorRotation) { - if(localLOGV) Log.i(TAG, "onOrientationChanged, rotation changed from "+rotation+" to "+mSensorRotation); - // Update window manager. The lid rotation hasn't changed, - // but we want it to re-evaluate the final rotation in case - // it needs to call back and get the sensor orientation. - mSensorRotation = rotation; - try { - mWindowManager.setRotation(rotation, false); - } catch (RemoteException e) { - // Ignore - } + if (true) Log.i(TAG, "onOrientationChanged, rotation changed to " +rotation); + try { + mWindowManager.setRotation(rotation, false, 1); + } catch (RemoteException e) { + // Ignore } } } MyOrientationListener mOrientationListener; - boolean useSensorForOrientationLp() { - if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { + boolean useSensorForOrientationLp(int appOrientation) { + if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { return true; } if (mAccelerometerDefault != 0 && ( - mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || - mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { + appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || + appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { return true; } return false; @@ -349,9 +349,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (!mOrientationSensorEnabled) { mOrientationListener.enable(); if(localLOGV) Log.i(TAG, "Enabling listeners"); - // We haven't had the sensor on, so don't yet know - // the rotation. - mSensorRotation = -1; mOrientationSensorEnabled = true; } } @@ -360,7 +357,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (disable && mOrientationSensorEnabled) { mOrientationListener.disable(); if(localLOGV) Log.i(TAG, "Disabling listeners"); - mSensorRotation = -1; mOrientationSensorEnabled = false; } } @@ -1270,7 +1266,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (event.keycode == 0) { // lid changed state mLidOpen = event.value == 0; - updateRotation(); + updateRotation(0); if (keyguardIsShowingTq()) { if (mLidOpen) { // only do this if it's opening -- closing the device shouldn't turn it @@ -1700,9 +1696,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mLidOpen) { return Surface.ROTATION_90; } else { - if (useSensorForOrientationLp()) { + if (useSensorForOrientationLp(orientation)) { // If the user has enabled auto rotation by default, do it. - return mSensorRotation >= 0 ? mSensorRotation : lastRotation; + int curRotation = mOrientationListener.getCurrentRotation(); + return curRotation >= 0 ? curRotation : lastRotation; } return Surface.ROTATION_0; } @@ -1745,10 +1742,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void enableScreenAfterBoot() { readLidState(); - updateRotation(); + updateRotation(0); } - void updateRotation() { + void updateRotation(int animFlags) { mPowerManager.setKeyboardVisibility(mLidOpen); int rotation= Surface.ROTATION_0; if (mLidOpen) { @@ -1758,7 +1755,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { //if lid is closed orientation will be portrait try { //set orientation on WindowManager - mWindowManager.setRotation(rotation, true); + mWindowManager.setRotation(rotation, true, animFlags); } catch (RemoteException e) { // Ignore } -- GitLab From 9ac7cf83f07070776ba1c2972e1cf21792ee9b55 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Fri, 27 Mar 2009 18:13:59 -0700 Subject: [PATCH 040/458] AI 143323: am: CL 143173 am: CL 142879 Fix issue #1732012 (Only show screen rotation animation when triggered by sensor) -- set the new surface flag as appropriate. Original author: hackbod Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143323 --- .../policy/impl/PhoneWindowManager.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index d8009e778fbe..bf0f81518c11 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -236,7 +236,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void onChange(boolean selfChange) { update(); try { - mWindowManager.setRotation(USE_LAST_ROTATION, false, 1); + mWindowManager.setRotation(USE_LAST_ROTATION, false, + mFancyRotationAnimation); } catch (RemoteException e) { // Ignore } @@ -248,7 +249,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mEndcallBehavior = Settings.System.getInt(resolver, Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); mFancyRotationAnimation = Settings.System.getInt(resolver, - "fancy_rotation_animation", 0); + "fancy_rotation_anim", 0) != 0 ? 0x80 : 0; int accelerometerDefault = Settings.System.getInt(resolver, Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); if (mAccelerometerDefault != accelerometerDefault) { @@ -260,7 +261,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean hasSoftInput = imId != null && imId.length() > 0; if (mHasSoftInput != hasSoftInput) { mHasSoftInput = hasSoftInput; - updateRotation(1); + updateRotation(0); } } } @@ -276,7 +277,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Send updates based on orientation value if (true) Log.i(TAG, "onOrientationChanged, rotation changed to " +rotation); try { - mWindowManager.setRotation(rotation, false, 1); + mWindowManager.setRotation(rotation, false, + mFancyRotationAnimation); } catch (RemoteException e) { // Ignore } @@ -1266,7 +1268,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (event.keycode == 0) { // lid changed state mLidOpen = event.value == 0; - updateRotation(0); + updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); if (keyguardIsShowingTq()) { if (mLidOpen) { // only do this if it's opening -- closing the device shouldn't turn it @@ -1742,7 +1744,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void enableScreenAfterBoot() { readLidState(); - updateRotation(0); + updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); } void updateRotation(int animFlags) { @@ -1755,7 +1757,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { //if lid is closed orientation will be portrait try { //set orientation on WindowManager - mWindowManager.setRotation(rotation, true, animFlags); + mWindowManager.setRotation(rotation, true, + mFancyRotationAnimation | animFlags); } catch (RemoteException e) { // Ignore } -- GitLab From 7a489fdbac672a375dd381f539f08d71f8b79596 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Fri, 27 Mar 2009 18:51:15 -0700 Subject: [PATCH 041/458] AI 143413: Fix issue #1742588 (Crash phone while switching between keyboard settings and Gmail) BUG=1742588 Automated import of CL 143413 --- .../android/internal/policy/impl/PhoneWindowManager.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index bf0f81518c11..cc0588d9dda9 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -245,6 +245,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void update() { ContentResolver resolver = mContext.getContentResolver(); + boolean updateRotation = false; synchronized (mLock) { mEndcallBehavior = Settings.System.getInt(resolver, Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); @@ -261,9 +262,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean hasSoftInput = imId != null && imId.length() > 0; if (mHasSoftInput != hasSoftInput) { mHasSoftInput = hasSoftInput; - updateRotation(0); + updateRotation = true; } } + if (updateRotation) { + updateRotation(0); + } } } -- GitLab From 42259f8ce6e0bede5ffd0e49d32f747856b661e7 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Fri, 27 Mar 2009 20:07:28 -0700 Subject: [PATCH 042/458] AI 143415: am: CL 143414 am: CL 143413 Fix issue #1742588 (Crash phone while switching between keyboard settings and Gmail) Original author: hackbod Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143415 --- .../android/internal/policy/impl/PhoneWindowManager.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index bf0f81518c11..cc0588d9dda9 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -245,6 +245,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void update() { ContentResolver resolver = mContext.getContentResolver(); + boolean updateRotation = false; synchronized (mLock) { mEndcallBehavior = Settings.System.getInt(resolver, Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); @@ -261,9 +262,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean hasSoftInput = imId != null && imId.length() > 0; if (mHasSoftInput != hasSoftInput) { mHasSoftInput = hasSoftInput; - updateRotation(0); + updateRotation = true; } } + if (updateRotation) { + updateRotation(0); + } } } -- GitLab From ae585e83a796ddb691a7eb48026473edaddc775e Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Fri, 27 Mar 2009 20:56:50 -0700 Subject: [PATCH 043/458] AI 143414: am: CL 143413 Fix issue #1742588 (Crash phone while switching between keyboard settings and Gmail) Original author: hackbod Merged from: //branches/cupcake/... Automated import of CL 143414 --- .../android/internal/policy/impl/PhoneWindowManager.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index bf0f81518c11..cc0588d9dda9 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -245,6 +245,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void update() { ContentResolver resolver = mContext.getContentResolver(); + boolean updateRotation = false; synchronized (mLock) { mEndcallBehavior = Settings.System.getInt(resolver, Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); @@ -261,9 +262,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean hasSoftInput = imId != null && imId.length() > 0; if (mHasSoftInput != hasSoftInput) { mHasSoftInput = hasSoftInput; - updateRotation(0); + updateRotation = true; } } + if (updateRotation) { + updateRotation(0); + } } } -- GitLab From 070615ad9f41a2a9af75d1ed08d66edb4d1613ea Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Tue, 31 Mar 2009 17:58:46 -0700 Subject: [PATCH 044/458] AI 143896: Fix issue #1748954 and #1737952: #1748954 (New status bar fades into all white background): FrameLayout wasn't updating its foreground drawable when its padding changed, which would happen as the status bar is shown and hidden. To fix this I also ended up fixing a problem in the view debug stuff where we couldn't get a bitmap for a view that is the full screen size because it is too big... actually I just went ahead and added another function to snapshot the view hierarchy which works a lot better for us anyway. #1737952 (Home screen icons overlap with the notification bar after exiting any camera app): Originally I punted this because it only happened in rare situations, but now that home is always portrait it happens a lot more so it is more important to fix. This involved a few things to clean up hiding/showing the status bar: - We now determine when to hide and show it during layout, which allows us to do this at the time it is actually needed rather than during animation after we can actually catch it for the initial display of a window. This required tweaking the layout API so the policy can request a second layout pass if needed. - When doing layout, we are now much more aggressive about skipping the layout of windows. Basically anything that we know will be hidden in the near future is ignored for layout, so that it doesn't glitch as it is transfered out of the screen. The theory being that it is better to leave it as it was originally placed while we are transitioning it out, than to switch it to something slightly more correct. BUG=1748954,1737952 Automated import of CL 143896 --- .../policy/impl/PhoneWindowManager.java | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index cc0588d9dda9..95dda57eb1ad 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -985,6 +985,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mDockBottom = mContentBottom = mCurBottom = displayHeight; mDockLayer = 0x10000000; + mTopFullscreenOpaqueWindowState = null; + mForceStatusBar = false; + // decide where the status bar goes ahead of time if (mStatusBar != null) { final Rect pf = mTmpParentFrame; @@ -1056,7 +1059,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ - public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached) { + public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, + WindowState attached) { // we've already done the status bar if (win == mStatusBar) { return; @@ -1180,6 +1184,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { win.computeFrameLw(pf, df, cf, vf); + if (win.isVisibleLw()) { + if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { + mForceStatusBar = true; + } else if (mTopFullscreenOpaqueWindowState == null + && attrs.type >= FIRST_APPLICATION_WINDOW + && attrs.type <= LAST_APPLICATION_WINDOW + && win.fillsScreenLw(mW, mH, false, false)) { + if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win); + mTopFullscreenOpaqueWindowState = win; + } + } + // Dock windows carve out the bottom of the screen, so normal windows // can't appear underneath them. if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) { @@ -1200,39 +1216,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ - public void finishLayoutLw() { - } - - /** {@inheritDoc} */ - public void beginAnimationLw(int displayWidth, int displayHeight) { - mTopFullscreenOpaqueWindowState = null; - mForceStatusBar = false; - } - - /** {@inheritDoc} */ - public void animatingWindowLw(WindowState win, - WindowManager.LayoutParams attrs) { - if (win.isVisibleLw()) { - if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { - mForceStatusBar = true; - } else if (mTopFullscreenOpaqueWindowState == null - && attrs.type >= FIRST_APPLICATION_WINDOW - && attrs.type <= LAST_APPLICATION_WINDOW - && win.fillsScreenLw(mW, mH, true, false) - && win.isVisibleLw()) { - mTopFullscreenOpaqueWindowState = win; - } - } - } - - /** {@inheritDoc} */ - public boolean finishAnimationLw() { + public boolean finishLayoutLw() { boolean changed = false; boolean hiding = false; if (mStatusBar != null) { //Log.i(TAG, "force=" + mForceStatusBar // + " top=" + mTopFullscreenOpaqueWindowState); if (mForceStatusBar) { + if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); changed |= mStatusBar.showLw(true); } else if (mTopFullscreenOpaqueWindowState != null) { //Log.i(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw() @@ -1243,9 +1234,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean hideStatusBar = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; if (hideStatusBar) { + if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar"); changed |= mStatusBar.hideLw(true); hiding = true; } else { + if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); changed |= mStatusBar.showLw(true); } } @@ -1265,6 +1258,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { return changed; } + /** {@inheritDoc} */ + public void beginAnimationLw(int displayWidth, int displayHeight) { + } + + /** {@inheritDoc} */ + public void animatingWindowLw(WindowState win, + WindowManager.LayoutParams attrs) { + } + + /** {@inheritDoc} */ + public boolean finishAnimationLw() { + return false; + } + /** {@inheritDoc} */ public boolean preprocessInputEventTq(RawInputEvent event) { switch (event.type) { -- GitLab From 0ecadf71e084208a5c92420e10bdfc69b40ec160 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Tue, 31 Mar 2009 18:00:37 -0700 Subject: [PATCH 045/458] AI 143899: am: CL 143896 Fix issue #1748954 and #1737952: #1748954 (New status bar fades into all white background): FrameLayout wasn't updating its foreground drawable when its padding changed, which would happen as the status bar is shown and hidden. To fix this I also ended up fixing a problem in the view debug stuff where we couldn't get a bitmap for a view that is the full screen size because it is too big... actually I just went ahead and added another function to snapshot the view hierarchy which works a lot better for us anyway. #1737952 (Home screen icons overlap with the notification bar after exiting any camera app): Originally I punted this because it only happened in rare situations, but now that home is always portrait it happens a lot more so it is more important to fix. This involved a few things to clean up hiding/showing the status bar: - We now determine when to hide and show it during layout, which allows us to do this at the time it is actually needed rather than during animation after we can actually catch it for the initial display of a window. This required tweaking the layout API so the policy can request a second layout pass if needed. - When doing layout, we are now much more aggressive about skipping the layout of windows. Basically anything that we know will be hidden in the near future is ignored for layout, so that it doesn't glitch as it is transfered out of the screen. The theory being that it is better to leave it as it was originally placed while we are transitioning it out, than to switch it to something slightly more correct. Original author: hackbod Merged from: //branches/cupcake/... Automated import of CL 143899 --- .../policy/impl/PhoneWindowManager.java | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index cc0588d9dda9..95dda57eb1ad 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -985,6 +985,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mDockBottom = mContentBottom = mCurBottom = displayHeight; mDockLayer = 0x10000000; + mTopFullscreenOpaqueWindowState = null; + mForceStatusBar = false; + // decide where the status bar goes ahead of time if (mStatusBar != null) { final Rect pf = mTmpParentFrame; @@ -1056,7 +1059,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ - public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached) { + public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, + WindowState attached) { // we've already done the status bar if (win == mStatusBar) { return; @@ -1180,6 +1184,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { win.computeFrameLw(pf, df, cf, vf); + if (win.isVisibleLw()) { + if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { + mForceStatusBar = true; + } else if (mTopFullscreenOpaqueWindowState == null + && attrs.type >= FIRST_APPLICATION_WINDOW + && attrs.type <= LAST_APPLICATION_WINDOW + && win.fillsScreenLw(mW, mH, false, false)) { + if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win); + mTopFullscreenOpaqueWindowState = win; + } + } + // Dock windows carve out the bottom of the screen, so normal windows // can't appear underneath them. if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) { @@ -1200,39 +1216,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ - public void finishLayoutLw() { - } - - /** {@inheritDoc} */ - public void beginAnimationLw(int displayWidth, int displayHeight) { - mTopFullscreenOpaqueWindowState = null; - mForceStatusBar = false; - } - - /** {@inheritDoc} */ - public void animatingWindowLw(WindowState win, - WindowManager.LayoutParams attrs) { - if (win.isVisibleLw()) { - if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { - mForceStatusBar = true; - } else if (mTopFullscreenOpaqueWindowState == null - && attrs.type >= FIRST_APPLICATION_WINDOW - && attrs.type <= LAST_APPLICATION_WINDOW - && win.fillsScreenLw(mW, mH, true, false) - && win.isVisibleLw()) { - mTopFullscreenOpaqueWindowState = win; - } - } - } - - /** {@inheritDoc} */ - public boolean finishAnimationLw() { + public boolean finishLayoutLw() { boolean changed = false; boolean hiding = false; if (mStatusBar != null) { //Log.i(TAG, "force=" + mForceStatusBar // + " top=" + mTopFullscreenOpaqueWindowState); if (mForceStatusBar) { + if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); changed |= mStatusBar.showLw(true); } else if (mTopFullscreenOpaqueWindowState != null) { //Log.i(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw() @@ -1243,9 +1234,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean hideStatusBar = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; if (hideStatusBar) { + if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar"); changed |= mStatusBar.hideLw(true); hiding = true; } else { + if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); changed |= mStatusBar.showLw(true); } } @@ -1265,6 +1258,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { return changed; } + /** {@inheritDoc} */ + public void beginAnimationLw(int displayWidth, int displayHeight) { + } + + /** {@inheritDoc} */ + public void animatingWindowLw(WindowState win, + WindowManager.LayoutParams attrs) { + } + + /** {@inheritDoc} */ + public boolean finishAnimationLw() { + return false; + } + /** {@inheritDoc} */ public boolean preprocessInputEventTq(RawInputEvent event) { switch (event.type) { -- GitLab From 86d07f551a7fda5dd394e3458cc3489de27f5714 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Tue, 31 Mar 2009 18:00:53 -0700 Subject: [PATCH 046/458] AI 143901: am: CL 143899 am: CL 143896 Fix issue #1748954 and #1737952: #1748954 (New status bar fades into all white background): FrameLayout wasn't updating its foreground drawable when its padding changed, which would happen as the status bar is shown and hidden. To fix this I also ended up fixing a problem in the view debug stuff where we couldn't get a bitmap for a view that is the full screen size because it is too big... actually I just went ahead and added another function to snapshot the view hierarchy which works a lot better for us anyway. #1737952 (Home screen icons overlap with the notification bar after exiting any camera app): Originally I punted this because it only happened in rare situations, but now that home is always portrait it happens a lot more so it is more important to fix. This involved a few things to clean up hiding/showing the status bar: - We now determine when to hide and show it during layout, which allows us to do this at the time it is actually needed rather than during animation after we can actually catch it for the initial display of a window. This required tweaking the layout API so the policy can request a second layout pass if needed. - When doing layout, we are now much more aggressive about skipping the layout of windows. Basically anything that we know will be hidden in the near future is ignored for layout, so that it doesn't glitch as it is transfered out of the screen. The theory being that it is better to leave it as it was originally placed while we are transitioning it out, than to switch it to something slightly more correct. Original author: hackbod Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143901 --- .../policy/impl/PhoneWindowManager.java | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index cc0588d9dda9..95dda57eb1ad 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -985,6 +985,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mDockBottom = mContentBottom = mCurBottom = displayHeight; mDockLayer = 0x10000000; + mTopFullscreenOpaqueWindowState = null; + mForceStatusBar = false; + // decide where the status bar goes ahead of time if (mStatusBar != null) { final Rect pf = mTmpParentFrame; @@ -1056,7 +1059,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ - public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached) { + public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, + WindowState attached) { // we've already done the status bar if (win == mStatusBar) { return; @@ -1180,6 +1184,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { win.computeFrameLw(pf, df, cf, vf); + if (win.isVisibleLw()) { + if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { + mForceStatusBar = true; + } else if (mTopFullscreenOpaqueWindowState == null + && attrs.type >= FIRST_APPLICATION_WINDOW + && attrs.type <= LAST_APPLICATION_WINDOW + && win.fillsScreenLw(mW, mH, false, false)) { + if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win); + mTopFullscreenOpaqueWindowState = win; + } + } + // Dock windows carve out the bottom of the screen, so normal windows // can't appear underneath them. if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) { @@ -1200,39 +1216,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ - public void finishLayoutLw() { - } - - /** {@inheritDoc} */ - public void beginAnimationLw(int displayWidth, int displayHeight) { - mTopFullscreenOpaqueWindowState = null; - mForceStatusBar = false; - } - - /** {@inheritDoc} */ - public void animatingWindowLw(WindowState win, - WindowManager.LayoutParams attrs) { - if (win.isVisibleLw()) { - if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { - mForceStatusBar = true; - } else if (mTopFullscreenOpaqueWindowState == null - && attrs.type >= FIRST_APPLICATION_WINDOW - && attrs.type <= LAST_APPLICATION_WINDOW - && win.fillsScreenLw(mW, mH, true, false) - && win.isVisibleLw()) { - mTopFullscreenOpaqueWindowState = win; - } - } - } - - /** {@inheritDoc} */ - public boolean finishAnimationLw() { + public boolean finishLayoutLw() { boolean changed = false; boolean hiding = false; if (mStatusBar != null) { //Log.i(TAG, "force=" + mForceStatusBar // + " top=" + mTopFullscreenOpaqueWindowState); if (mForceStatusBar) { + if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); changed |= mStatusBar.showLw(true); } else if (mTopFullscreenOpaqueWindowState != null) { //Log.i(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw() @@ -1243,9 +1234,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean hideStatusBar = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; if (hideStatusBar) { + if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar"); changed |= mStatusBar.hideLw(true); hiding = true; } else { + if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); changed |= mStatusBar.showLw(true); } } @@ -1265,6 +1258,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { return changed; } + /** {@inheritDoc} */ + public void beginAnimationLw(int displayWidth, int displayHeight) { + } + + /** {@inheritDoc} */ + public void animatingWindowLw(WindowState win, + WindowManager.LayoutParams attrs) { + } + + /** {@inheritDoc} */ + public boolean finishAnimationLw() { + return false; + } + /** {@inheritDoc} */ public boolean preprocessInputEventTq(RawInputEvent event) { switch (event.type) { -- GitLab From 37c124c3fa3078af98c0ebd3e52c9a4ca477a767 Mon Sep 17 00:00:00 2001 From: Wink Saville <> Date: Thu, 2 Apr 2009 01:37:02 -0700 Subject: [PATCH 047/458] AI 144185: Integrate cdma into the main code base. Automated import of CL 144185 --- .../policy/impl/KeyguardUpdateMonitor.java | 53 ++++++++++--------- .../policy/impl/KeyguardViewMediator.java | 27 +++++----- .../policy/impl/LockPatternKeyguardView.java | 26 ++++----- .../LockPatternKeyguardViewProperties.java | 8 +-- .../internal/policy/impl/LockScreen.java | 32 +++++------ .../policy/impl/PhoneWindowManager.java | 2 + 6 files changed, 79 insertions(+), 69 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 3a25d38d9ef6..eb25a092b3ef 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -34,7 +34,7 @@ import static android.provider.Telephony.Intents.EXTRA_SHOW_PLMN; import static android.provider.Telephony.Intents.EXTRA_SHOW_SPN; import static android.provider.Telephony.Intents.EXTRA_SPN; import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION; -import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.IccCard; import com.android.internal.telephony.TelephonyIntents; import android.util.Log; import com.android.internal.R; @@ -61,7 +61,7 @@ public class KeyguardUpdateMonitor { private final Context mContext; - private SimCard.State mSimState = SimCard.State.READY; + private IccCard.State mSimState = IccCard.State.READY; private boolean mInPortrait; private boolean mKeyboardOpen; @@ -94,38 +94,39 @@ public class KeyguardUpdateMonitor { /** - * When we receive a {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, and - * then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange}, + * When we receive a + * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, + * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange}, * we need a single object to pass to the handler. This class helps decode * the intent and provide a {@link SimCard.State} result. */ private static class SimArgs { - public final SimCard.State simState; + public final IccCard.State simState; private SimArgs(Intent intent) { if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) { throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED"); } - String stateExtra = intent.getStringExtra(SimCard.INTENT_KEY_SIM_STATE); - if (SimCard.INTENT_VALUE_SIM_ABSENT.equals(stateExtra)) { - this.simState = SimCard.State.ABSENT; - } else if (SimCard.INTENT_VALUE_SIM_READY.equals(stateExtra)) { - this.simState = SimCard.State.READY; - } else if (SimCard.INTENT_VALUE_SIM_LOCKED.equals(stateExtra)) { + String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE); + if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { + this.simState = IccCard.State.ABSENT; + } else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) { + this.simState = IccCard.State.READY; + } else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { final String lockedReason = intent - .getStringExtra(SimCard.INTENT_KEY_LOCKED_REASON); - if (SimCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { - this.simState = SimCard.State.PIN_REQUIRED; - } else if (SimCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { - this.simState = SimCard.State.PUK_REQUIRED; + .getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON); + if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { + this.simState = IccCard.State.PIN_REQUIRED; + } else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { + this.simState = IccCard.State.PUK_REQUIRED; } else { - this.simState = SimCard.State.UNKNOWN; + this.simState = IccCard.State.UNKNOWN; } - } else if (SimCard.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) { - this.simState = SimCard.State.NETWORK_LOCKED; + } else if (IccCard.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) { + this.simState = IccCard.State.NETWORK_LOCKED; } else { - this.simState = SimCard.State.UNKNOWN; + this.simState = IccCard.State.UNKNOWN; } } @@ -195,7 +196,7 @@ public class KeyguardUpdateMonitor { mKeyboardOpen = queryKeyboardOpen(); // take a guess to start - mSimState = SimCard.State.READY; + mSimState = IccCard.State.READY; mDevicePluggedIn = true; mBatteryLevel = 100; @@ -317,14 +318,14 @@ public class KeyguardUpdateMonitor { * Handle {@link #MSG_SIM_STATE_CHANGE} */ private void handleSimStateChange(SimArgs simArgs) { - final SimCard.State state = simArgs.simState; + final IccCard.State state = simArgs.simState; if (DEBUG) { Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " " + "state resolved to " + state.toString()); } - if (state != SimCard.State.UNKNOWN && state != mSimState) { + if (state != IccCard.State.UNKNOWN && state != mSimState) { mSimState = state; for (int i = 0; i < mSimStateCallbacks.size(); i++) { mSimStateCallbacks.get(i).onSimStateChanged(state); @@ -461,7 +462,7 @@ public class KeyguardUpdateMonitor { * Callback to notify of sim state change. */ interface SimStateCallback { - void onSimStateChanged(SimCard.State simState); + void onSimStateChanged(IccCard.State simState); } /** @@ -489,7 +490,7 @@ public class KeyguardUpdateMonitor { mSimStateCallbacks.add(callback); } - public SimCard.State getSimState() { + public IccCard.State getSimState() { return mSimState; } @@ -499,7 +500,7 @@ public class KeyguardUpdateMonitor { * broadcast from the telephony code. */ public void reportSimPinUnlocked() { - mSimState = SimCard.State.READY; + mSimState = IccCard.State.READY; } public boolean isInPortrait() { diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 71acef90aa83..99480e79d0f8 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -16,7 +16,7 @@ package com.android.internal.policy.impl; -import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.IccCard; import com.android.internal.widget.LockPatternUtils; import android.app.AlarmManager; @@ -41,6 +41,7 @@ import android.view.KeyEvent; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; + /** * Mediates requests related to the keyguard. This includes queries about the * state of the keyguard, power management events that effect whether the keyguard @@ -89,7 +90,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private final static String TAG = "KeyguardViewMediator"; - private static final String DELAYED_KEYGUARD_ACTION = "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD"; + private static final String DELAYED_KEYGUARD_ACTION = + "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD"; // used for handler messages private static final int TIMEOUT = 1; @@ -301,7 +303,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, 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); + if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = " + + mDelayedShowingSequence); } else { doKeyguard(); } @@ -461,8 +464,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // if the setup wizard hasn't run yet, don't show final boolean provisioned = mUpdateMonitor.isDeviceProvisioned(); - final SimCard.State state = mUpdateMonitor.getSimState(); - final boolean lockedOrMissing = state.isPinLocked() || (state == SimCard.State.ABSENT); + final IccCard.State state = mUpdateMonitor.getSimState(); + final boolean lockedOrMissing = state.isPinLocked() || (state == IccCard.State.ABSENT); if (!lockedOrMissing && !provisioned) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned" + " and the sim is not locked or missing"); @@ -576,7 +579,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } /** {@inheritDoc} */ - public void onSimStateChanged(SimCard.State simState) { + public void onSimStateChanged(IccCard.State simState) { if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState); switch (simState) { @@ -585,7 +588,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // gone through setup wizard if (!mUpdateMonitor.isDeviceProvisioned()) { if (!isShowing()) { - if (DEBUG) Log.d(TAG, "INTENT_VALUE_SIM_ABSENT and keygaurd isn't showing, we need " + if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_ABSENT and keygaurd isn't showing, we need " + "to show the keyguard since the device isn't provisioned yet."); doKeyguard(); } else { @@ -596,7 +599,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, case PIN_REQUIRED: case PUK_REQUIRED: if (!isShowing()) { - if (DEBUG) Log.d(TAG, "INTENT_VALUE_SIM_LOCKED and keygaurd isn't showing, we need " + if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_LOCKED and keygaurd isn't showing, we need " + "to show the keyguard so the user can enter their sim pin"); doKeyguard(); } else { @@ -759,10 +762,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ private Handler mHandler = new Handler() { @Override - public void handleMessage(Message msg) - { - switch (msg.what) - { + public void handleMessage(Message msg) { + switch (msg.what) { case TIMEOUT: handleTimeout(msg.arg1); return ; @@ -947,3 +948,5 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } } } + + diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index cb3131d0e8b4..1758deb4c5e4 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -26,7 +26,7 @@ import android.content.ServiceConnection; import android.os.IBinder; import android.os.RemoteException; import android.os.SystemProperties; -import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.IccCard; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; @@ -142,7 +142,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { private boolean stuckOnLockScreenBecauseSimMissing() { return mRequiresSim && (!mUpdateMonitor.isDeviceProvisioned()) - && (mUpdateMonitor.getSimState() == SimCard.State.ABSENT); + && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT); } /** @@ -184,9 +184,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase { } public void goToUnlockScreen() { - final SimCard.State simState = mUpdateMonitor.getSimState(); + final IccCard.State simState = mUpdateMonitor.getSimState(); if (stuckOnLockScreenBecauseSimMissing() - || (simState == SimCard.State.PUK_REQUIRED)){ + || (simState == IccCard.State.PUK_REQUIRED)){ // stuck on lock screen when sim missing or puk'd return; } @@ -365,7 +365,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { public void wakeWhenReadyTq(int keyCode) { if (DEBUG) Log.d(TAG, "onWakeKey"); if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen) - && (mUpdateMonitor.getSimState() != SimCard.State.PUK_REQUIRED)) { + && (mUpdateMonitor.getSimState() != IccCard.State.PUK_REQUIRED)) { if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); updateScreen(Mode.UnlockScreen); getCallback().pokeWakelock(); @@ -403,8 +403,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { if (unlockMode == UnlockMode.Pattern) { return mLockPatternUtils.isLockPatternEnabled(); } else if (unlockMode == UnlockMode.SimPin) { - return mUpdateMonitor.getSimState() == SimCard.State.PIN_REQUIRED - || mUpdateMonitor.getSimState() == SimCard.State.PUK_REQUIRED; + return mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED + || mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED; } else if (unlockMode == UnlockMode.Account) { return true; } else { @@ -522,8 +522,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { * the lock screen (lock or unlock). */ private Mode getInitialMode() { - final SimCard.State simState = mUpdateMonitor.getSimState(); - if (stuckOnLockScreenBecauseSimMissing() || (simState == SimCard.State.PUK_REQUIRED)) { + final IccCard.State simState = mUpdateMonitor.getSimState(); + if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED)) { return Mode.LockScreen; } else if (mUpdateMonitor.isKeyboardOpen() && isSecure()) { return Mode.UnlockScreen; @@ -536,8 +536,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { * Given the current state of things, what should the unlock screen be? */ private UnlockMode getUnlockMode() { - final SimCard.State simState = mUpdateMonitor.getSimState(); - if (simState == SimCard.State.PIN_REQUIRED || simState == SimCard.State.PUK_REQUIRED) { + final IccCard.State simState = mUpdateMonitor.getSimState(); + if (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED) { return UnlockMode.SimPin; } else { return mLockPatternUtils.isPermanentlyLocked() ? @@ -568,7 +568,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; String message = mContext.getString( R.string.lockscreen_failed_attempts_almost_glogin, - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, + LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET + - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds); final AlertDialog dialog = new AlertDialog.Builder(mContext) @@ -637,3 +638,4 @@ public class LockPatternKeyguardView extends KeyguardViewBase { } } } + diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java index 4e0cf09c2ad0..8a62cbd79c4f 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java @@ -19,7 +19,7 @@ package com.android.internal.policy.impl; import com.android.internal.widget.LockPatternUtils; import android.content.Context; -import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.IccCard; /** * Knows how to create a lock pattern keyguard view, and answer questions about @@ -59,9 +59,9 @@ public class LockPatternKeyguardViewProperties implements KeyguardViewProperties } private boolean isSimPinSecure() { - final SimCard.State simState = mUpdateMonitor.getSimState(); - return (simState == SimCard.State.PIN_REQUIRED || simState == SimCard.State.PUK_REQUIRED - || simState == SimCard.State.ABSENT); + final IccCard.State simState = mUpdateMonitor.getSimState(); + return (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED + || simState == IccCard.State.ABSENT); } } diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 82a52f9ed993..6d2b2a4dd97e 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -29,7 +29,7 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.IccCard; import java.util.Date; @@ -193,7 +193,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM final View view = mOnlyVisibleWhenSimNotOk[i]; view.setVisibility(View.GONE); } - refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn()); + refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), + mUpdateMonitor.getTelephonySpn()); refreshAlarmDisplay(); refreshBatteryDisplay(); } else { @@ -210,11 +211,11 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } private void refreshSimBadInfo() { - final SimCard.State simState = mUpdateMonitor.getSimState(); - if (simState == SimCard.State.PUK_REQUIRED) { + final IccCard.State simState = mUpdateMonitor.getSimState(); + if (simState == IccCard.State.PUK_REQUIRED) { mHeaderSimBad1.setText(R.string.lockscreen_sim_puk_locked_message); mHeaderSimBad2.setText(R.string.lockscreen_sim_puk_locked_instructions); - } else if (simState == SimCard.State.ABSENT) { + } else if (simState == IccCard.State.ABSENT) { mHeaderSimBad1.setText(R.string.lockscreen_missing_sim_message); mHeaderSimBad2.setVisibility(View.GONE); //mHeaderSimBad2.setText(R.string.lockscreen_missing_sim_instructions); @@ -226,7 +227,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private void refreshUnlockIntructions() { if (mLockPatternUtils.isLockPatternEnabled() - || mUpdateMonitor.getSimState() == SimCard.State.PIN_REQUIRED) { + || mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED) { mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_enabled); } else { mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_disabled); @@ -293,8 +294,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } private void refreshSimOkHeaders(CharSequence plmn, CharSequence spn) { - final SimCard.State simState = mUpdateMonitor.getSimState(); - if (simState == SimCard.State.READY) { + final IccCard.State simState = mUpdateMonitor.getSimState(); + if (simState == IccCard.State.READY) { if (plmn != null) { mHeaderSimOk1.setVisibility(View.VISIBLE); mHeaderSimOk1.setText(plmn); @@ -308,22 +309,22 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } else { mHeaderSimOk2.setVisibility(View.GONE); } - } else if (simState == SimCard.State.PIN_REQUIRED) { + } else if (simState == IccCard.State.PIN_REQUIRED) { mHeaderSimOk1.setVisibility(View.VISIBLE); mHeaderSimOk1.setText(R.string.lockscreen_sim_locked_message); mHeaderSimOk2.setVisibility(View.GONE); - } else if (simState == SimCard.State.ABSENT) { + } else if (simState == IccCard.State.ABSENT) { mHeaderSimOk1.setVisibility(View.VISIBLE); mHeaderSimOk1.setText(R.string.lockscreen_missing_sim_message_short); mHeaderSimOk2.setVisibility(View.GONE); - } else if (simState == SimCard.State.NETWORK_LOCKED) { + } else if (simState == IccCard.State.NETWORK_LOCKED) { mHeaderSimOk1.setVisibility(View.VISIBLE); mHeaderSimOk1.setText(R.string.lockscreen_network_locked_message); mHeaderSimOk2.setVisibility(View.GONE); } } - public void onSimStateChanged(SimCard.State simState) { + public void onSimStateChanged(IccCard.State simState) { mSimOk = isSimOk(simState); refreshViewsWRTSimOk(); } @@ -333,10 +334,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM * a special screen with the emergency call button and keep them from * doing anything else. */ - private boolean isSimOk(SimCard.State simState) { + private boolean isSimOk(IccCard.State simState) { boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned() - && simState == SimCard.State.ABSENT); - return !(missingAndNotProvisioned || simState == SimCard.State.PUK_REQUIRED); + && simState == IccCard.State.ABSENT); + return !(missingAndNotProvisioned || simState == IccCard.State.PUK_REQUIRED); } public void onOrientationChange(boolean inPortrait) { @@ -369,3 +370,4 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mUpdateMonitor.removeCallback(this); } } + diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 95dda57eb1ad..10067bd48387 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -285,6 +285,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mFancyRotationAnimation); } catch (RemoteException e) { // Ignore + } } } @@ -1831,3 +1832,4 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } + -- GitLab From 76c65a66884ae1b7ab06c908632dd2a66182422c Mon Sep 17 00:00:00 2001 From: Wink Saville <> Date: Thu, 2 Apr 2009 11:00:56 -0700 Subject: [PATCH 048/458] AI 144245: Fix merge conflict for megering in the CDMA changes in to master from donutburger. Automated import of CL 144245 --- .../policy/impl/KeyguardUpdateMonitor.java | 53 ++++++++++--------- .../policy/impl/KeyguardViewMediator.java | 27 +++++----- .../policy/impl/LockPatternKeyguardView.java | 26 ++++----- .../LockPatternKeyguardViewProperties.java | 8 +-- .../internal/policy/impl/LockScreen.java | 32 +++++------ .../policy/impl/PhoneWindowManager.java | 2 + 6 files changed, 79 insertions(+), 69 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 3a25d38d9ef6..eb25a092b3ef 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -34,7 +34,7 @@ import static android.provider.Telephony.Intents.EXTRA_SHOW_PLMN; import static android.provider.Telephony.Intents.EXTRA_SHOW_SPN; import static android.provider.Telephony.Intents.EXTRA_SPN; import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION; -import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.IccCard; import com.android.internal.telephony.TelephonyIntents; import android.util.Log; import com.android.internal.R; @@ -61,7 +61,7 @@ public class KeyguardUpdateMonitor { private final Context mContext; - private SimCard.State mSimState = SimCard.State.READY; + private IccCard.State mSimState = IccCard.State.READY; private boolean mInPortrait; private boolean mKeyboardOpen; @@ -94,38 +94,39 @@ public class KeyguardUpdateMonitor { /** - * When we receive a {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, and - * then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange}, + * When we receive a + * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, + * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange}, * we need a single object to pass to the handler. This class helps decode * the intent and provide a {@link SimCard.State} result. */ private static class SimArgs { - public final SimCard.State simState; + public final IccCard.State simState; private SimArgs(Intent intent) { if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) { throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED"); } - String stateExtra = intent.getStringExtra(SimCard.INTENT_KEY_SIM_STATE); - if (SimCard.INTENT_VALUE_SIM_ABSENT.equals(stateExtra)) { - this.simState = SimCard.State.ABSENT; - } else if (SimCard.INTENT_VALUE_SIM_READY.equals(stateExtra)) { - this.simState = SimCard.State.READY; - } else if (SimCard.INTENT_VALUE_SIM_LOCKED.equals(stateExtra)) { + String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE); + if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { + this.simState = IccCard.State.ABSENT; + } else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) { + this.simState = IccCard.State.READY; + } else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { final String lockedReason = intent - .getStringExtra(SimCard.INTENT_KEY_LOCKED_REASON); - if (SimCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { - this.simState = SimCard.State.PIN_REQUIRED; - } else if (SimCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { - this.simState = SimCard.State.PUK_REQUIRED; + .getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON); + if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { + this.simState = IccCard.State.PIN_REQUIRED; + } else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { + this.simState = IccCard.State.PUK_REQUIRED; } else { - this.simState = SimCard.State.UNKNOWN; + this.simState = IccCard.State.UNKNOWN; } - } else if (SimCard.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) { - this.simState = SimCard.State.NETWORK_LOCKED; + } else if (IccCard.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) { + this.simState = IccCard.State.NETWORK_LOCKED; } else { - this.simState = SimCard.State.UNKNOWN; + this.simState = IccCard.State.UNKNOWN; } } @@ -195,7 +196,7 @@ public class KeyguardUpdateMonitor { mKeyboardOpen = queryKeyboardOpen(); // take a guess to start - mSimState = SimCard.State.READY; + mSimState = IccCard.State.READY; mDevicePluggedIn = true; mBatteryLevel = 100; @@ -317,14 +318,14 @@ public class KeyguardUpdateMonitor { * Handle {@link #MSG_SIM_STATE_CHANGE} */ private void handleSimStateChange(SimArgs simArgs) { - final SimCard.State state = simArgs.simState; + final IccCard.State state = simArgs.simState; if (DEBUG) { Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " " + "state resolved to " + state.toString()); } - if (state != SimCard.State.UNKNOWN && state != mSimState) { + if (state != IccCard.State.UNKNOWN && state != mSimState) { mSimState = state; for (int i = 0; i < mSimStateCallbacks.size(); i++) { mSimStateCallbacks.get(i).onSimStateChanged(state); @@ -461,7 +462,7 @@ public class KeyguardUpdateMonitor { * Callback to notify of sim state change. */ interface SimStateCallback { - void onSimStateChanged(SimCard.State simState); + void onSimStateChanged(IccCard.State simState); } /** @@ -489,7 +490,7 @@ public class KeyguardUpdateMonitor { mSimStateCallbacks.add(callback); } - public SimCard.State getSimState() { + public IccCard.State getSimState() { return mSimState; } @@ -499,7 +500,7 @@ public class KeyguardUpdateMonitor { * broadcast from the telephony code. */ public void reportSimPinUnlocked() { - mSimState = SimCard.State.READY; + mSimState = IccCard.State.READY; } public boolean isInPortrait() { diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 71acef90aa83..99480e79d0f8 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -16,7 +16,7 @@ package com.android.internal.policy.impl; -import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.IccCard; import com.android.internal.widget.LockPatternUtils; import android.app.AlarmManager; @@ -41,6 +41,7 @@ import android.view.KeyEvent; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; + /** * Mediates requests related to the keyguard. This includes queries about the * state of the keyguard, power management events that effect whether the keyguard @@ -89,7 +90,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private final static String TAG = "KeyguardViewMediator"; - private static final String DELAYED_KEYGUARD_ACTION = "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD"; + private static final String DELAYED_KEYGUARD_ACTION = + "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD"; // used for handler messages private static final int TIMEOUT = 1; @@ -301,7 +303,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, 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); + if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = " + + mDelayedShowingSequence); } else { doKeyguard(); } @@ -461,8 +464,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // if the setup wizard hasn't run yet, don't show final boolean provisioned = mUpdateMonitor.isDeviceProvisioned(); - final SimCard.State state = mUpdateMonitor.getSimState(); - final boolean lockedOrMissing = state.isPinLocked() || (state == SimCard.State.ABSENT); + final IccCard.State state = mUpdateMonitor.getSimState(); + final boolean lockedOrMissing = state.isPinLocked() || (state == IccCard.State.ABSENT); if (!lockedOrMissing && !provisioned) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned" + " and the sim is not locked or missing"); @@ -576,7 +579,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } /** {@inheritDoc} */ - public void onSimStateChanged(SimCard.State simState) { + public void onSimStateChanged(IccCard.State simState) { if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState); switch (simState) { @@ -585,7 +588,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // gone through setup wizard if (!mUpdateMonitor.isDeviceProvisioned()) { if (!isShowing()) { - if (DEBUG) Log.d(TAG, "INTENT_VALUE_SIM_ABSENT and keygaurd isn't showing, we need " + if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_ABSENT and keygaurd isn't showing, we need " + "to show the keyguard since the device isn't provisioned yet."); doKeyguard(); } else { @@ -596,7 +599,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, case PIN_REQUIRED: case PUK_REQUIRED: if (!isShowing()) { - if (DEBUG) Log.d(TAG, "INTENT_VALUE_SIM_LOCKED and keygaurd isn't showing, we need " + if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_LOCKED and keygaurd isn't showing, we need " + "to show the keyguard so the user can enter their sim pin"); doKeyguard(); } else { @@ -759,10 +762,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ private Handler mHandler = new Handler() { @Override - public void handleMessage(Message msg) - { - switch (msg.what) - { + public void handleMessage(Message msg) { + switch (msg.what) { case TIMEOUT: handleTimeout(msg.arg1); return ; @@ -947,3 +948,5 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } } } + + diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index e8fb7fdd924a..12e735a89a3d 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -21,7 +21,7 @@ import android.app.AlertDialog; import android.content.Context; import android.content.Intent; import android.os.SystemProperties; -import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.IccCard; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; @@ -132,7 +132,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { private boolean stuckOnLockScreenBecauseSimMissing() { return mRequiresSim && (!mUpdateMonitor.isDeviceProvisioned()) - && (mUpdateMonitor.getSimState() == SimCard.State.ABSENT); + && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT); } /** @@ -176,9 +176,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase { } public void goToUnlockScreen() { - final SimCard.State simState = mUpdateMonitor.getSimState(); + final IccCard.State simState = mUpdateMonitor.getSimState(); if (stuckOnLockScreenBecauseSimMissing() - || (simState == SimCard.State.PUK_REQUIRED)){ + || (simState == IccCard.State.PUK_REQUIRED)){ // stuck on lock screen when sim missing or puk'd return; } @@ -328,7 +328,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { public void wakeWhenReadyTq(int keyCode) { if (DEBUG) Log.d(TAG, "onWakeKey"); if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen) - && (mUpdateMonitor.getSimState() != SimCard.State.PUK_REQUIRED)) { + && (mUpdateMonitor.getSimState() != IccCard.State.PUK_REQUIRED)) { if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); updateScreen(Mode.UnlockScreen); getCallback().pokeWakelock(); @@ -366,8 +366,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { if (unlockMode == UnlockMode.Pattern) { return mLockPatternUtils.isLockPatternEnabled(); } else if (unlockMode == UnlockMode.SimPin) { - return mUpdateMonitor.getSimState() == SimCard.State.PIN_REQUIRED - || mUpdateMonitor.getSimState() == SimCard.State.PUK_REQUIRED; + return mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED + || mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED; } else if (unlockMode == UnlockMode.Account) { return true; } else { @@ -485,8 +485,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { * the lock screen (lock or unlock). */ private Mode getInitialMode() { - final SimCard.State simState = mUpdateMonitor.getSimState(); - if (stuckOnLockScreenBecauseSimMissing() || (simState == SimCard.State.PUK_REQUIRED)) { + final IccCard.State simState = mUpdateMonitor.getSimState(); + if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED)) { return Mode.LockScreen; } else if (mUpdateMonitor.isKeyboardOpen() && isSecure()) { return Mode.UnlockScreen; @@ -499,8 +499,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { * Given the current state of things, what should the unlock screen be? */ private UnlockMode getUnlockMode() { - final SimCard.State simState = mUpdateMonitor.getSimState(); - if (simState == SimCard.State.PIN_REQUIRED || simState == SimCard.State.PUK_REQUIRED) { + final IccCard.State simState = mUpdateMonitor.getSimState(); + if (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED) { return UnlockMode.SimPin; } else { return mLockPatternUtils.isPermanentlyLocked() ? @@ -531,7 +531,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; String message = mContext.getString( R.string.lockscreen_failed_attempts_almost_glogin, - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, + LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET + - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds); final AlertDialog dialog = new AlertDialog.Builder(mContext) @@ -600,3 +601,4 @@ public class LockPatternKeyguardView extends KeyguardViewBase { } } } + diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java index 4e0cf09c2ad0..8a62cbd79c4f 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java @@ -19,7 +19,7 @@ package com.android.internal.policy.impl; import com.android.internal.widget.LockPatternUtils; import android.content.Context; -import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.IccCard; /** * Knows how to create a lock pattern keyguard view, and answer questions about @@ -59,9 +59,9 @@ public class LockPatternKeyguardViewProperties implements KeyguardViewProperties } private boolean isSimPinSecure() { - final SimCard.State simState = mUpdateMonitor.getSimState(); - return (simState == SimCard.State.PIN_REQUIRED || simState == SimCard.State.PUK_REQUIRED - || simState == SimCard.State.ABSENT); + final IccCard.State simState = mUpdateMonitor.getSimState(); + return (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED + || simState == IccCard.State.ABSENT); } } diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 82a52f9ed993..6d2b2a4dd97e 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -29,7 +29,7 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.IccCard; import java.util.Date; @@ -193,7 +193,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM final View view = mOnlyVisibleWhenSimNotOk[i]; view.setVisibility(View.GONE); } - refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn()); + refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), + mUpdateMonitor.getTelephonySpn()); refreshAlarmDisplay(); refreshBatteryDisplay(); } else { @@ -210,11 +211,11 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } private void refreshSimBadInfo() { - final SimCard.State simState = mUpdateMonitor.getSimState(); - if (simState == SimCard.State.PUK_REQUIRED) { + final IccCard.State simState = mUpdateMonitor.getSimState(); + if (simState == IccCard.State.PUK_REQUIRED) { mHeaderSimBad1.setText(R.string.lockscreen_sim_puk_locked_message); mHeaderSimBad2.setText(R.string.lockscreen_sim_puk_locked_instructions); - } else if (simState == SimCard.State.ABSENT) { + } else if (simState == IccCard.State.ABSENT) { mHeaderSimBad1.setText(R.string.lockscreen_missing_sim_message); mHeaderSimBad2.setVisibility(View.GONE); //mHeaderSimBad2.setText(R.string.lockscreen_missing_sim_instructions); @@ -226,7 +227,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private void refreshUnlockIntructions() { if (mLockPatternUtils.isLockPatternEnabled() - || mUpdateMonitor.getSimState() == SimCard.State.PIN_REQUIRED) { + || mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED) { mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_enabled); } else { mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_disabled); @@ -293,8 +294,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } private void refreshSimOkHeaders(CharSequence plmn, CharSequence spn) { - final SimCard.State simState = mUpdateMonitor.getSimState(); - if (simState == SimCard.State.READY) { + final IccCard.State simState = mUpdateMonitor.getSimState(); + if (simState == IccCard.State.READY) { if (plmn != null) { mHeaderSimOk1.setVisibility(View.VISIBLE); mHeaderSimOk1.setText(plmn); @@ -308,22 +309,22 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } else { mHeaderSimOk2.setVisibility(View.GONE); } - } else if (simState == SimCard.State.PIN_REQUIRED) { + } else if (simState == IccCard.State.PIN_REQUIRED) { mHeaderSimOk1.setVisibility(View.VISIBLE); mHeaderSimOk1.setText(R.string.lockscreen_sim_locked_message); mHeaderSimOk2.setVisibility(View.GONE); - } else if (simState == SimCard.State.ABSENT) { + } else if (simState == IccCard.State.ABSENT) { mHeaderSimOk1.setVisibility(View.VISIBLE); mHeaderSimOk1.setText(R.string.lockscreen_missing_sim_message_short); mHeaderSimOk2.setVisibility(View.GONE); - } else if (simState == SimCard.State.NETWORK_LOCKED) { + } else if (simState == IccCard.State.NETWORK_LOCKED) { mHeaderSimOk1.setVisibility(View.VISIBLE); mHeaderSimOk1.setText(R.string.lockscreen_network_locked_message); mHeaderSimOk2.setVisibility(View.GONE); } } - public void onSimStateChanged(SimCard.State simState) { + public void onSimStateChanged(IccCard.State simState) { mSimOk = isSimOk(simState); refreshViewsWRTSimOk(); } @@ -333,10 +334,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM * a special screen with the emergency call button and keep them from * doing anything else. */ - private boolean isSimOk(SimCard.State simState) { + private boolean isSimOk(IccCard.State simState) { boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned() - && simState == SimCard.State.ABSENT); - return !(missingAndNotProvisioned || simState == SimCard.State.PUK_REQUIRED); + && simState == IccCard.State.ABSENT); + return !(missingAndNotProvisioned || simState == IccCard.State.PUK_REQUIRED); } public void onOrientationChange(boolean inPortrait) { @@ -369,3 +370,4 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mUpdateMonitor.removeCallback(this); } } + diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 95dda57eb1ad..10067bd48387 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -285,6 +285,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mFancyRotationAnimation); } catch (RemoteException e) { // Ignore + } } } @@ -1831,3 +1832,4 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } + -- GitLab From f29d580185e68bc23750d528511d2717d0de99aa Mon Sep 17 00:00:00 2001 From: Fred Quintana <> Date: Wed, 8 Apr 2009 19:14:54 -0700 Subject: [PATCH 049/458] AI 145177: phase two of the AccountManager - added an AccountManagerActivity, a base Activity that can be used by activities that are launched by AccountAuthenticator intents. This makes it easy for an Activity to send a result using an AccountAuthenticatorResponse - added debug strings to the AccountAuthenticatorCache - improved the API for the AccountAuthenticatorResponse and made it Parcelable so that it can be passed to an Activity via an Intent - changed the AccountManager to use Futures for the asynchronous calls and to notify the user via a callback when the request is complete - changed the AccountManager to convert any errors that are returned into Exceptions - added constants for the error codes that are passed across the IAccountManagerResponse and IAccountAuthenticatorResponse interfaces - added a dump() method to the AccountManagerService so that it can display the list of active sessions and registered authenticators - added an way to interrogate the AccountManagerService for the list of registered authenticators - removed more methods from the GoogleLoginServiceHelper and GoogleLoginServiceBlockingHelper and changed the callers to use the AccountManager Automated import of CL 145177 --- .../policy/impl/AccountUnlockScreen.java | 25 ++++++++----------- .../policy/impl/LockPatternKeyguardView.java | 4 +-- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index aae1c7fe4082..098a65118445 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -53,7 +53,6 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree private final KeyguardScreenCallback mCallback; private final LockPatternUtils mLockPatternUtils; - private AccountManager mAccountManager; private TextView mTopHeader; private TextView mInstructions; @@ -93,12 +92,6 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree mEmergencyCall.setOnClickListener(this); } - void ensureAccountManager() { - if (mAccountManager == null) { - mAccountManager = (AccountManager)mContext.getSystemService(Context.ACCOUNT_SERVICE); - } - } - public void afterTextChanged(Editable s) { } @@ -193,11 +186,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree * find a single best match. */ private Account findIntendedAccount(String username) { - ensureAccountManager(); - Account[] accounts = mAccountManager.blockingGetAccounts(); - if (accounts == null) { - return null; - } + Account[] accounts = AccountManager.get(mContext).blockingGetAccounts(); // Try to figure out which account they meant if they // typed only the username (and not the domain), or got @@ -239,8 +228,14 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree if (account == null) { return false; } - // change this to asynchronously issue the request and wait for the response - ensureAccountManager(); - return mAccountManager.authenticateAccount(account, password); + // TODO(fredq) change this to asynchronously issue the request and wait for the response (by + // supplying a callback rather than calling get() immediately) + try { + return AccountManager.get(mContext).confirmPassword( + account, password, null /* callback */, null /* handler */).getResult(); + } catch (android.accounts.OperationCanceledException e) { + // the request was canceled + return false; + } } } diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 12e735a89a3d..486f364ebc71 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -149,9 +149,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { KeyguardWindowController controller) { super(context); - AccountManager accountManager = - (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE); - mHasAccount = accountManager.blockingGetAccounts().length > 0; + mHasAccount = AccountManager.get(context).blockingGetAccounts().length > 0; mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); -- GitLab From 3ee81a951a9000ae313ea2193640daa8996b83cf Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Thu, 9 Apr 2009 12:31:16 -0700 Subject: [PATCH 050/458] AI 145382: API review: change new media keycode names to avoid ambiguity. Updates the key maps. During this I noticed that the dream keymap didn't have all of the media buttons like the sapphire key map...! So this is now changed to match. BUG=1779435 Automated import of CL 145382 --- .../policy/impl/KeyguardViewBase.java | 24 +++++++++---------- .../policy/impl/KeyguardViewMediator.java | 12 +++++----- .../internal/policy/impl/PhoneWindow.java | 24 +++++++++---------- .../policy/impl/PhoneWindowManager.java | 12 +++++----- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/com/android/internal/policy/impl/KeyguardViewBase.java index f67f6a9773e4..2b44d45b1cb3 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewBase.java @@ -142,7 +142,7 @@ public abstract class KeyguardViewBase extends FrameLayout { final int keyCode = event.getKeyCode(); if (event.getAction() == KeyEvent.ACTION_DOWN) { switch (keyCode) { - case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: /* Suppress PLAYPAUSE toggle when phone is ringing or * in-call to avoid music playback */ if (mTelephonyManager == null) { @@ -154,11 +154,11 @@ public abstract class KeyguardViewBase extends FrameLayout { return true; // suppress key event } case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); @@ -190,12 +190,12 @@ public abstract class KeyguardViewBase extends FrameLayout { switch (keyCode) { case KeyEvent.KEYCODE_MUTE: case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 71acef90aa83..a032cb1c6a63 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -676,12 +676,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_MUTE: case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: case KeyEvent.KEYCODE_CAMERA: return false; } diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 8d9a73333584..da922751b448 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -1230,7 +1230,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } - case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: /* Suppress PLAYPAUSE toggle when phone is ringing or in-call * to avoid music playback */ if (mTelephonyManager == null) { @@ -1243,11 +1243,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } case KeyEvent.KEYCODE_MUTE: case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); @@ -1370,12 +1370,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 95dda57eb1ad..21c3267c1e91 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1385,12 +1385,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { static boolean isMediaKey(int code) { if (code == KeyEvent.KEYCODE_HEADSETHOOK || - code == KeyEvent.KEYCODE_PLAYPAUSE || - code == KeyEvent.KEYCODE_STOP || - code == KeyEvent.KEYCODE_NEXTSONG || - code == KeyEvent.KEYCODE_PREVIOUSSONG || - code == KeyEvent.KEYCODE_PREVIOUSSONG || - code == KeyEvent.KEYCODE_FORWARD) { + code == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || + code == KeyEvent.KEYCODE_MEDIA_STOP || + code == KeyEvent.KEYCODE_MEDIA_NEXT || + code == KeyEvent.KEYCODE_MEDIA_PREVIOUS || + code == KeyEvent.KEYCODE_MEDIA_PREVIOUS || + code == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) { return true; } return false; -- GitLab From 8b89d69a37bf417d14a170cfef1299c6d4987b24 Mon Sep 17 00:00:00 2001 From: Andy Stadler <> Date: Fri, 10 Apr 2009 16:24:49 -0700 Subject: [PATCH 051/458] AI 145778: Manual merge changes 145382-145384 from cupcake. Automated import of CL 145778 --- .../policy/impl/KeyguardViewBase.java | 24 +++++++++---------- .../policy/impl/KeyguardViewMediator.java | 12 +++++----- .../internal/policy/impl/PhoneWindow.java | 24 +++++++++---------- .../policy/impl/PhoneWindowManager.java | 12 +++++----- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/com/android/internal/policy/impl/KeyguardViewBase.java index f67f6a9773e4..2b44d45b1cb3 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewBase.java @@ -142,7 +142,7 @@ public abstract class KeyguardViewBase extends FrameLayout { final int keyCode = event.getKeyCode(); if (event.getAction() == KeyEvent.ACTION_DOWN) { switch (keyCode) { - case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: /* Suppress PLAYPAUSE toggle when phone is ringing or * in-call to avoid music playback */ if (mTelephonyManager == null) { @@ -154,11 +154,11 @@ public abstract class KeyguardViewBase extends FrameLayout { return true; // suppress key event } case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); @@ -190,12 +190,12 @@ public abstract class KeyguardViewBase extends FrameLayout { switch (keyCode) { case KeyEvent.KEYCODE_MUTE: case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 99480e79d0f8..112d7b2149e8 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -679,12 +679,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_MUTE: case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: case KeyEvent.KEYCODE_CAMERA: return false; } diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 8d9a73333584..da922751b448 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -1230,7 +1230,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } - case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: /* Suppress PLAYPAUSE toggle when phone is ringing or in-call * to avoid music playback */ if (mTelephonyManager == null) { @@ -1243,11 +1243,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } case KeyEvent.KEYCODE_MUTE: case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); @@ -1370,12 +1370,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 10067bd48387..2a54e3dc7469 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1386,12 +1386,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { static boolean isMediaKey(int code) { if (code == KeyEvent.KEYCODE_HEADSETHOOK || - code == KeyEvent.KEYCODE_PLAYPAUSE || - code == KeyEvent.KEYCODE_STOP || - code == KeyEvent.KEYCODE_NEXTSONG || - code == KeyEvent.KEYCODE_PREVIOUSSONG || - code == KeyEvent.KEYCODE_PREVIOUSSONG || - code == KeyEvent.KEYCODE_FORWARD) { + code == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || + code == KeyEvent.KEYCODE_MEDIA_STOP || + code == KeyEvent.KEYCODE_MEDIA_NEXT || + code == KeyEvent.KEYCODE_MEDIA_PREVIOUS || + code == KeyEvent.KEYCODE_MEDIA_PREVIOUS || + code == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) { return true; } return false; -- GitLab From 1096ea5657e9ffa851509ab38cb4eb08ee9ed9c3 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn <> Date: Mon, 13 Apr 2009 16:11:59 -0700 Subject: [PATCH 052/458] AI 145994: Integrate #145778 from Donut. Automated import of CL 145994 --- .../policy/impl/KeyguardViewBase.java | 24 +++++++++---------- .../policy/impl/KeyguardViewMediator.java | 12 +++++----- .../internal/policy/impl/PhoneWindow.java | 24 +++++++++---------- .../policy/impl/PhoneWindowManager.java | 12 +++++----- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/com/android/internal/policy/impl/KeyguardViewBase.java index f67f6a9773e4..2b44d45b1cb3 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewBase.java @@ -142,7 +142,7 @@ public abstract class KeyguardViewBase extends FrameLayout { final int keyCode = event.getKeyCode(); if (event.getAction() == KeyEvent.ACTION_DOWN) { switch (keyCode) { - case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: /* Suppress PLAYPAUSE toggle when phone is ringing or * in-call to avoid music playback */ if (mTelephonyManager == null) { @@ -154,11 +154,11 @@ public abstract class KeyguardViewBase extends FrameLayout { return true; // suppress key event } case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); @@ -190,12 +190,12 @@ public abstract class KeyguardViewBase extends FrameLayout { switch (keyCode) { case KeyEvent.KEYCODE_MUTE: case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 99480e79d0f8..112d7b2149e8 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -679,12 +679,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_MUTE: case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: case KeyEvent.KEYCODE_CAMERA: return false; } diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 8d9a73333584..da922751b448 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -1230,7 +1230,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } - case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: /* Suppress PLAYPAUSE toggle when phone is ringing or in-call * to avoid music playback */ if (mTelephonyManager == null) { @@ -1243,11 +1243,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } case KeyEvent.KEYCODE_MUTE: case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); @@ -1370,12 +1370,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_PLAYPAUSE: - case KeyEvent.KEYCODE_STOP: - case KeyEvent.KEYCODE_NEXTSONG: - case KeyEvent.KEYCODE_PREVIOUSSONG: - case KeyEvent.KEYCODE_REWIND: - case KeyEvent.KEYCODE_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 10067bd48387..2a54e3dc7469 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1386,12 +1386,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { static boolean isMediaKey(int code) { if (code == KeyEvent.KEYCODE_HEADSETHOOK || - code == KeyEvent.KEYCODE_PLAYPAUSE || - code == KeyEvent.KEYCODE_STOP || - code == KeyEvent.KEYCODE_NEXTSONG || - code == KeyEvent.KEYCODE_PREVIOUSSONG || - code == KeyEvent.KEYCODE_PREVIOUSSONG || - code == KeyEvent.KEYCODE_FORWARD) { + code == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || + code == KeyEvent.KEYCODE_MEDIA_STOP || + code == KeyEvent.KEYCODE_MEDIA_NEXT || + code == KeyEvent.KEYCODE_MEDIA_PREVIOUS || + code == KeyEvent.KEYCODE_MEDIA_PREVIOUS || + code == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) { return true; } return false; -- GitLab From b7e787fd409a6135eecdd5e32bbe9c60872a4f6f Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 7 May 2009 15:55:42 -0700 Subject: [PATCH 053/458] Switch to new improves shutdown class that is now in framework. --- .../internal/policy/impl/GlobalActions.java | 3 +- .../policy/impl/KeyguardUpdateMonitor.java | 4 +- .../internal/policy/impl/PowerDialog.java | 6 +- .../internal/policy/impl/ShutdownThread.java | 173 ------------------ 4 files changed, 8 insertions(+), 178 deletions(-) delete mode 100644 policy/com/android/internal/policy/impl/ShutdownThread.java diff --git a/policy/com/android/internal/policy/impl/GlobalActions.java b/policy/com/android/internal/policy/impl/GlobalActions.java index eeb875a2f4be..10ac01c03b13 100644 --- a/policy/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/com/android/internal/policy/impl/GlobalActions.java @@ -39,6 +39,7 @@ import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import com.android.internal.R; +import com.android.internal.app.ShutdownThread; import com.google.android.collect.Lists; import java.util.ArrayList; @@ -176,7 +177,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac public void onPress() { // shutdown by making sure radio and power are handled accordingly. - ShutdownThread.shutdownAfterDisablingRadio(mContext, true); + ShutdownThread.shutdown(mContext, true); } public boolean showDuringKeyguard() { diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index eb25a092b3ef..cd21427e1342 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -34,6 +34,8 @@ import static android.provider.Telephony.Intents.EXTRA_SHOW_PLMN; import static android.provider.Telephony.Intents.EXTRA_SHOW_SPN; import static android.provider.Telephony.Intents.EXTRA_SPN; import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION; + +import com.android.internal.app.ShutdownThread; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.TelephonyIntents; import android.util.Log; @@ -298,7 +300,7 @@ public class KeyguardUpdateMonitor { if (batteryLevel == 0 && pluggedInStatus != BATTERY_STATUS_CHARGING && pluggedInStatus != BATTERY_STATUS_UNKNOWN) { - ShutdownThread.shutdownAfterDisablingRadio(mContext, false); + ShutdownThread.shutdown(mContext, false); } } diff --git a/policy/com/android/internal/policy/impl/PowerDialog.java b/policy/com/android/internal/policy/impl/PowerDialog.java index 77c42abcd402..f4d4b049b397 100644 --- a/policy/com/android/internal/policy/impl/PowerDialog.java +++ b/policy/com/android/internal/policy/impl/PowerDialog.java @@ -23,11 +23,11 @@ import android.app.StatusBarManager; import android.content.Context; import android.os.Bundle; import android.os.RemoteException; -import android.os.IServiceManager; import android.os.LocalPowerManager; import android.os.ServiceManager; -import android.os.ServiceManagerNative; import android.os.SystemClock; + +import com.android.internal.app.ShutdownThread; import com.android.internal.telephony.ITelephony; import android.view.KeyEvent; import android.util.Log; @@ -123,7 +123,7 @@ public class PowerDialog extends Dialog implements OnClickListener, this.dismiss(); if (v == mPower) { // shutdown by making sure radio and power are handled accordingly. - ShutdownThread.shutdownAfterDisablingRadio(getContext(), true); + ShutdownThread.shutdown(getContext(), true); } else if (v == mRadioPower) { try { ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); diff --git a/policy/com/android/internal/policy/impl/ShutdownThread.java b/policy/com/android/internal/policy/impl/ShutdownThread.java deleted file mode 100644 index c61d60b52426..000000000000 --- a/policy/com/android/internal/policy/impl/ShutdownThread.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2008 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 android.app.ProgressDialog; -import android.app.AlertDialog; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.IBluetoothDevice; -import android.content.Context; -import android.content.DialogInterface; -import android.os.RemoteException; -import android.os.Power; -import android.os.ServiceManager; -import android.os.SystemClock; -import com.android.internal.telephony.ITelephony; -import android.util.Log; -import android.view.WindowManager; - - -final class ShutdownThread extends Thread { - // constants - private static final String TAG = "ShutdownThread"; - private static final int MAX_NUM_PHONE_STATE_READS = 16; - private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500; - private static final ITelephony sPhone = - ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); - private static final IBluetoothDevice sBluetooth = - IBluetoothDevice.Stub.asInterface(ServiceManager.getService(Context.BLUETOOTH_SERVICE)); - - - // state tracking - private static Object sIsStartedGuard = new Object(); - private static boolean sIsStarted = false; - - // static instance of this thread - private static final ShutdownThread sInstance = new ShutdownThread(); - - private ShutdownThread() { - } - - /** - * request a shutdown. - * - * @param context Context used to display the shutdown progress dialog. - */ - public static void shutdownAfterDisablingRadio(final Context context, boolean confirm){ - // ensure that only one thread is trying to power down. - // any additional calls are just returned - synchronized (sIsStartedGuard){ - if (sIsStarted) { - Log.d(TAG, "Request to shutdown already running, returning."); - return; - } - } - - Log.d(TAG, "Notifying thread to start radio shutdown"); - - if (confirm) { - final AlertDialog dialog = new AlertDialog.Builder(context) - .setIcon(android.R.drawable.ic_dialog_alert) - .setTitle(com.android.internal.R.string.power_off) - .setMessage(com.android.internal.R.string.shutdown_confirm) - .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - beginShutdownSequence(context); - } - }) - .setNegativeButton(com.android.internal.R.string.no, null) - .create(); - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - dialog.show(); - } else { - beginShutdownSequence(context); - } - } - - private static void beginShutdownSequence(Context context) { - synchronized (sIsStartedGuard) { - sIsStarted = true; - } - - // throw up an indeterminate system dialog to indicate radio is - // shutting down. - ProgressDialog pd = new ProgressDialog(context); - pd.setTitle(context.getText(com.android.internal.R.string.power_off)); - pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress)); - pd.setIndeterminate(true); - pd.setCancelable(false); - pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - - pd.show(); - - // start the thread that initiates shutdown - sInstance.start(); - } - - /** - * Makes sure we handle the shutdown gracefully. - * Shuts off power regardless of radio and bluetooth state if the alloted time has passed. - */ - public void run() { - boolean bluetoothOff; - boolean radioOff; - - try { - bluetoothOff = sBluetooth == null || - sBluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF; - if (!bluetoothOff) { - sBluetooth.disable(false); // disable but don't persist new state - } - } catch (RemoteException ex) { - Log.e(TAG, "RemoteException during bluetooth shutdown", ex); - bluetoothOff = true; - } - - try { - radioOff = sPhone == null || !sPhone.isRadioOn(); - if (!radioOff) { - sPhone.setRadio(false); - } - } catch (RemoteException ex) { - Log.e(TAG, "RemoteException during radio shutdown", ex); - radioOff = true; - } - - // Wait a max of 32 seconds for clean shutdown - for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++) { - if (!bluetoothOff) { - try { - bluetoothOff = - sBluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF; - } catch (RemoteException ex) { - Log.e(TAG, "RemoteException during bluetooth shutdown", ex); - bluetoothOff = true; - } - } - if (!radioOff) { - try { - radioOff = !sPhone.isRadioOn(); - } catch (RemoteException ex) { - Log.e(TAG, "RemoteException during radio shutdown", ex); - radioOff = true; - } - } - if (radioOff && bluetoothOff) { - Log.d(TAG, "Radio and Bluetooth shutdown complete."); - break; - } - SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC); - } - - //shutdown power - Log.d(TAG, "Shutting down power."); - Power.shutdown(); - } -} -- GitLab From 9593e0a0073d77ab65cc97156da4d0e890e4cf27 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Mon, 11 May 2009 15:28:49 -0700 Subject: [PATCH 054/458] Improve the rendering speed of the lock screen by reporting the appropriate opacity for the background wallpaper. --- .../android/internal/policy/impl/LockPatternKeyguardView.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 1758deb4c5e4..6a1c2794a76f 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -590,9 +590,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase { */ static private class FastBitmapDrawable extends Drawable { private Bitmap mBitmap; + private int mOpacity; private FastBitmapDrawable(Bitmap bitmap) { mBitmap = bitmap; + mOpacity = mBitmap.hasAlpha() ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; } @Override @@ -606,7 +608,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { @Override public int getOpacity() { - return PixelFormat.TRANSLUCENT; + return mOpacity; } @Override -- GitLab From 24d1056ec4b268280fbbdc1535801c045ba02205 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 12 May 2009 14:15:17 -0700 Subject: [PATCH 055/458] Fix typos --- policy/com/android/internal/policy/impl/KeyguardViewBase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/com/android/internal/policy/impl/KeyguardViewBase.java index 2b44d45b1cb3..9dcbcb6500ca 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewBase.java @@ -132,8 +132,8 @@ public abstract class KeyguardViewBase extends FrameLayout { } /** - * Allows the media keys to work when the keygaurd is showing. - * The media keys should be of no interest to the actualy keygaurd view(s), + * Allows the media keys to work when the keyguard is showing. + * The media keys should be of no interest to the actual keyguard view(s), * so intercepting them here should not be of any harm. * @param event The key event * @return whether the event was consumed as a media key. -- GitLab From 491293ef234d093adccf442d76cbd0db12632692 Mon Sep 17 00:00:00 2001 From: svetoslavganov Date: Tue, 28 Apr 2009 19:17:02 -0700 Subject: [PATCH 056/458] Accessibility feature - event population and firing --- .../internal/policy/impl/PhoneWindow.java | 46 +++++++++++++++++-- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index da922751b448..b40255a46fe7 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -15,6 +15,12 @@ package com.android.internal.policy.impl; +import static android.view.ViewGroup.LayoutParams.FILL_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +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 com.android.internal.view.menu.ContextMenuBuilder; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuDialogHelper; @@ -57,15 +63,12 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; -import static android.view.ViewGroup.LayoutParams.FILL_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import android.view.ViewManager; import android.view.VolumePanel; import android.view.Window; import android.view.WindowManager; -import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.inputmethod.InputMethodManager; @@ -81,6 +84,7 @@ import android.widget.TextView; * in android.widget. */ public class PhoneWindow extends Window implements MenuBuilder.Callback { + private final static String TAG = "PhoneWindow"; private final static boolean SWEEP_OPEN_MENU = false; @@ -570,6 +574,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { lp.gravity = st.gravity; lp.windowAnimations = st.windowAnimations; + wm.addView(st.decorView, lp); // Log.v(TAG, "Adding main menu to window manager."); } @@ -1798,6 +1803,37 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return false; } + @Override + public void sendAccessibilityEvent(int eventType) { + if (!AccessibilityManager.getInstance(mContext).isEnabled()) { + return; + } + + // if we are showing a feature that should be announced and one child + // make this child the event source since this is the feature itself + // otherwise the callback will take over and announce its client + if ((mFeatureId == FEATURE_OPTIONS_PANEL || + mFeatureId == FEATURE_CONTEXT_MENU || + mFeatureId == FEATURE_PROGRESS || + mFeatureId == FEATURE_INDETERMINATE_PROGRESS) + && getChildCount() == 1) { + getChildAt(0).sendAccessibilityEvent(eventType); + } else { + super.sendAccessibilityEvent(eventType); + } + } + + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + final Callback cb = getCallback(); + if (cb != null) { + if (cb.dispatchPopulateAccessibilityEvent(event)) { + return true; + } + } + return super.dispatchPopulateAccessibilityEvent(event); + } + @Override protected boolean setFrame(int l, int t, int r, int b) { boolean changed = super.setFrame(l, t, r, b); -- GitLab From 9cdc90365f6aeedc7fe0a041944c066d0fd73c88 Mon Sep 17 00:00:00 2001 From: Suchi Amalapurapu Date: Thu, 14 May 2009 18:01:07 -0700 Subject: [PATCH 057/458] If a window specifies flag to show even when screen is locked, the keyguard is hidden and conversely if the keyguard has been hidden its shown. this lets the window manager to hide or unhide the keyguard based on activities that specify if they want to be displayed inspite of the keyguard being shown or not. --- .../policy/impl/PhoneWindowManager.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 2a54e3dc7469..bb41538ac838 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -65,6 +65,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; +import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; @@ -197,6 +198,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowState mTopFullscreenOpaqueWindowState; boolean mForceStatusBar; + boolean mHideKeyguard; boolean mHomePressed; Intent mHomeIntent; boolean mSearchKeyPressed; @@ -988,6 +990,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mTopFullscreenOpaqueWindowState = null; mForceStatusBar = false; + mHideKeyguard = false; // decide where the status bar goes ahead of time if (mStatusBar != null) { @@ -1195,6 +1198,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win); mTopFullscreenOpaqueWindowState = win; } + if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { + // TODO Add a check for the window to be full screen + if (localLOGV) Log.i(TAG, "Setting mHideKeyguard to true by win " + win); + mHideKeyguard = true; + } } // Dock windows carve out the bottom of the screen, so normal windows @@ -1244,6 +1252,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } + // 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.i(TAG, "finishLayoutLw::mHideKeyguard="+mHideKeyguard); + if (mHideKeyguard) { + changed |= mKeyguard.hideLw(true); + } else { + changed |= mKeyguard.showLw(true); + } + } if (changed && hiding) { IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar")); -- GitLab From 256dd3ba3c7e602091325563251a7314b165fbfd Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 19 May 2009 18:51:21 -0700 Subject: [PATCH 058/458] Fix issue #1737531: Don't allow applications to prevent the user from leaving them --- .../internal/policy/impl/PhoneWindowManager.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index bb41538ac838..8964c6d4ec36 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -954,6 +954,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() { public void onKeyguardExitResult(boolean success) { if (success) { + try { + ActivityManagerNative.getDefault().stopAppSwitches(); + } catch (RemoteException e) { + } mContext.startActivity(mHomeIntent); sendCloseSystemWindows(); } @@ -961,6 +965,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { }); } else { // no keyguard stuff to worry about, just launch home! + try { + ActivityManagerNative.getDefault().stopAppSwitches(); + } catch (RemoteException e) { + } mContext.startActivity(mHomeIntent); sendCloseSystemWindows(); } @@ -1801,11 +1809,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean goHome() { if (false) { // This code always brings home to the front. + try { + ActivityManagerNative.getDefault().stopAppSwitches(); + } catch (RemoteException e) { + } mContext.startActivity(mHomeIntent); } else { // This code brings home to the front or, if it is already // at the front, puts the device to sleep. try { + ActivityManagerNative.getDefault().stopAppSwitches(); int result = ActivityManagerNative.getDefault() .startActivity(null, mHomeIntent, mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()), -- GitLab From 5cb8d79f8a346587de299373a9701906c2a057c9 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 21 May 2009 17:34:15 -0700 Subject: [PATCH 059/458] Implement support for new second-level media window type. --- .../android/internal/policy/impl/PhoneWindowManager.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 8964c6d4ec36..6c66b3fcdef7 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -70,6 +70,7 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY; 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; @@ -130,8 +131,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // things in here CAN NOT take focus, but are shown on top of everything else. static final int SYSTEM_OVERLAY_LAYER = 14; + static final int APPLICATION_MEDIA_SUBLAYER = -2; + static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; static final int APPLICATION_PANEL_SUBLAYER = 1; - static final int APPLICATION_MEDIA_SUBLAYER = -1; static final int APPLICATION_SUB_PANEL_SUBLAYER = 2; static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f; @@ -575,6 +577,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return APPLICATION_PANEL_SUBLAYER; case TYPE_APPLICATION_MEDIA: return APPLICATION_MEDIA_SUBLAYER; + case TYPE_APPLICATION_MEDIA_OVERLAY: + return APPLICATION_MEDIA_OVERLAY_SUBLAYER; case TYPE_APPLICATION_SUB_PANEL: return APPLICATION_SUB_PANEL_SUBLAYER; } -- GitLab From f4cd7a31872838c7c351aab3d7eafde49ede50b3 Mon Sep 17 00:00:00 2001 From: Mike Reed Date: Tue, 2 Jun 2009 15:31:45 -0400 Subject: [PATCH 060/458] respect FEATURE_OPENGL (at least while we test it) --- policy/com/android/internal/policy/impl/PhoneWindow.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index b40255a46fe7..b8ecd13dca61 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -295,11 +295,9 @@ 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"); } - /* FEATURE_OPENGL disabled for 1.0 if (featureId == FEATURE_OPENGL) { getAttributes().memoryType = WindowManager.LayoutParams.MEMORY_TYPE_GPU; } - */ return super.requestFeature(featureId); } -- GitLab From a163bdcf5cb2db9ae1497ebd5881a05bdcea1dba Mon Sep 17 00:00:00 2001 From: Bjorn Bringert Date: Mon, 8 Jun 2009 23:20:15 +0100 Subject: [PATCH 061/458] Don't enforce that search dialog is a singleton. There was code in PhoneWindowManager from last time when the search dialog was a system dialog that caused an exception if the search was added to the window manager twice. Generally there should only be one search bar, but because window manager calls are asynchronous and don't execute in order, we can't be sure that a call to stopSearch() has removed the search dialog before a subsequent call to startSearch() tries to add it again. SearchManagerTest.testSearchManagerFastInvocations() crashed the system process before this change. --- .../internal/policy/impl/PhoneWindowManager.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 6c66b3fcdef7..afad7bbe5364 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -160,7 +160,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mSafeMode; WindowState mStatusBar = null; - WindowState mSearchBar = null; WindowState mKeyguard = null; KeyguardViewMediator mKeyguardMediator; GlobalActions mGlobalActions; @@ -702,7 +701,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { * Currently enforces that three window types are singletons: *

      *
    • STATUS_BAR_TYPE
    • - *
    • SEARCH_BAR_TYPE
    • *
    • KEYGUARD_TYPE
    • *
    * @@ -719,12 +717,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } mStatusBar = win; break; - case TYPE_SEARCH_BAR: - if (mSearchBar != null) { - return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; - } - mSearchBar = win; - break; case TYPE_KEYGUARD: if (mKeyguard != null) { return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; @@ -740,9 +732,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mStatusBar == win) { mStatusBar = null; } - else if (mSearchBar == win) { - mSearchBar = null; - } else if (mKeyguard == win) { mKeyguard = null; } -- GitLab From 831d0d9c408138bdac4a7011db3e07c01d023abb Mon Sep 17 00:00:00 2001 From: Mitsuru Oshima Date: Tue, 16 Jun 2009 18:27:18 -0700 Subject: [PATCH 062/458] Pick the right rotation based on window's width/height. --- .../policy/impl/PhoneWindowManager.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index afad7bbe5364..caffb7fde7dc 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -47,6 +47,7 @@ import com.android.internal.telephony.ITelephony; import android.util.Config; import android.util.EventLog; import android.util.Log; +import android.view.Display; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.IWindowManager; @@ -210,6 +211,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; int mEndcallBehavior; + int mLandscapeRotation = -1; + int mPortraitRotation = -1; + // Nothing to see here, move along... int mFancyRotationAnimation; @@ -450,6 +454,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public int checkAddPermission(WindowManager.LayoutParams attrs) { int type = attrs.type; + if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { return WindowManagerImpl.ADD_OKAY; @@ -1714,14 +1719,28 @@ public class PhoneWindowManager implements WindowManagerPolicy { public int rotationForOrientationLw(int orientation, int lastRotation, boolean displayEnabled) { + + if (mPortraitRotation < 0) { + // Initialize the rotation angles for each orientation once. + Display d = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay(); + if (d.getWidth() > d.getHeight()) { + mPortraitRotation = Surface.ROTATION_90; + mLandscapeRotation = Surface.ROTATION_0; + } else { + mPortraitRotation = Surface.ROTATION_0; + mLandscapeRotation = Surface.ROTATION_90; + } + } + synchronized (mLock) { switch (orientation) { case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: //always return landscape if orientation set to landscape - return Surface.ROTATION_90; + return mLandscapeRotation; case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: //always return portrait if orientation set to portrait - return Surface.ROTATION_0; + return mPortraitRotation; } // case for nosensor meaning ignore sensor and consider only lid // or orientation sensor disabled -- GitLab From d0ffc10947977a445e22adcd50cf0e08ef503ead Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Wed, 17 Jun 2009 10:39:48 -0700 Subject: [PATCH 063/458] Fixes #1414069. Display recent activities with two lines of text. --- .../policy/impl/RecentApplicationsDialog.java | 61 ++++++++++--------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java index 5442dd4e4bde..a680cc83b3d6 100644 --- a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java +++ b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java @@ -24,6 +24,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -46,22 +47,28 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener private static final boolean DBG_FORCE_EMPTY_LIST = false; static private StatusBarManager sStatusBar; - + private static final int NUM_BUTTONS = 6; private static final int MAX_RECENT_TASKS = NUM_BUTTONS * 2; // allow for some discards - + final View[] mButtons = new View[NUM_BUTTONS]; View mNoAppsText; IntentFilter mBroadcastIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + + private int mIconSize; + public RecentApplicationsDialog(Context context) { super(context); + + final Resources resources = context.getResources(); + mIconSize = (int) resources.getDimension(android.R.dimen.app_icon_size); } /** * We create the recent applications dialog just once, and it stays around (hidden) * until activated by the user. - * + * * @see PhoneWindowManager#showRecentAppsDialog */ @Override @@ -81,7 +88,8 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener WindowManager.LayoutParams.FLAG_BLUR_BEHIND); theWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - + theWindow.setTitle("Recents"); + setContentView(com.android.internal.R.layout.recent_apps_dialog); mButtons[0] = findViewById(com.android.internal.R.id.button1); @@ -91,7 +99,7 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener mButtons[4] = findViewById(com.android.internal.R.id.button5); mButtons[5] = findViewById(com.android.internal.R.id.button6); mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message); - + for (View b : mButtons) { b.setOnClickListener(this); } @@ -101,7 +109,7 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener * Handler for user clicks. If a button was clicked, launch the corresponding activity. */ public void onClick(View v) { - + for (View b : mButtons) { if (b == v) { // prepare a launch intent and send it @@ -134,7 +142,7 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener @Override public void onStop() { super.onStop(); - + // dump extra memory we're hanging on to for (View b : mButtons) { setButtonAppearance(b, null, null); @@ -148,23 +156,23 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener // stop receiving broadcasts getContext().unregisterReceiver(mBroadcastReceiver); } - + /** * Reload the 6 buttons with recent activities */ private void reloadButtons() { - + final Context context = getContext(); final PackageManager pm = context.getPackageManager(); - final ActivityManager am = (ActivityManager) + final ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); - final List recentTasks = + final List recentTasks = am.getRecentTasks(MAX_RECENT_TASKS, 0); - + ResolveInfo homeInfo = pm.resolveActivity( new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME), 0); - + // Performance note: Our android performance guide says to prefer Iterator when // using a List class, but because we know that getRecentTasks() always returns // an ArrayList<>, we'll use a simple index instead. @@ -172,15 +180,15 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener int numTasks = recentTasks.size(); for (int i = 0; i < numTasks && (button < NUM_BUTTONS); ++i) { final ActivityManager.RecentTaskInfo info = recentTasks.get(i); - + // for debug purposes only, disallow first result to create empty lists if (DBG_FORCE_EMPTY_LIST && (i == 0)) continue; - + Intent intent = new Intent(info.baseIntent); if (info.origActivity != null) { intent.setComponent(info.origActivity); } - + // Skip the current home activity. if (homeInfo != null) { if (homeInfo.activityInfo.packageName.equals( @@ -190,7 +198,7 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener continue; } } - + intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) | Intent.FLAG_ACTIVITY_NEW_TASK); final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0); @@ -210,35 +218,32 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener } } } - + // handle the case of "no icons to show" mNoAppsText.setVisibility((button == 0) ? View.VISIBLE : View.GONE); - + // hide the rest for ( ; button < NUM_BUTTONS; ++button) { mButtons[button].setVisibility(View.GONE); } } - + /** * Adjust appearance of each icon-button */ private void setButtonAppearance(View theButton, final String theTitle, final Drawable icon) { - TextView tv = (TextView) theButton.findViewById(com.android.internal.R.id.label); + TextView tv = (TextView) theButton; tv.setText(theTitle); - ImageView iv = (ImageView) theButton.findViewById(com.android.internal.R.id.icon); - iv.setImageDrawable(icon); + if (icon != null) { + icon.setBounds(0, 0, mIconSize, mIconSize); + } + tv.setCompoundDrawables(null, icon, null, null); } /** * This is the listener for the ACTION_CLOSE_SYSTEM_DIALOGS intent. It's an indication that * we should close ourselves immediately, in order to allow a higher-priority UI to take over * (e.g. phone call received). - * - * TODO: This is a really heavyweight solution for something that should be so simple. - * For example, we already have a handler, in our superclass, why aren't we sharing that? - * I think we need to investigate simplifying this entire methodology, or perhaps boosting - * it up into the Dialog class. */ private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override -- GitLab From a7c176c341b73c870a0df0ac2bcd156ab188513b Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 22 Jun 2009 20:56:57 -0700 Subject: [PATCH 064/458] Fix issue #1806217. We were not clearing the background drawable if it had been set as a resource reference. --- policy/com/android/internal/policy/impl/PhoneWindow.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index b40255a46fe7..59c87a5b4076 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -954,7 +954,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public final void setBackgroundDrawable(Drawable drawable) { - if (drawable != mBackgroundDrawable) { + if (drawable != mBackgroundDrawable || mBackgroundResource != 0) { mBackgroundResource = 0; mBackgroundDrawable = drawable; if (mDecor != null) { -- GitLab From 50645d4a096070966cec11f7da739eb5e1ae22f6 Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Tue, 23 Jun 2009 17:54:58 -0700 Subject: [PATCH 065/458] When the sim is missing, show "press menu to unlock or place emergency call" on lock screen instead of just "press menu to unlock". This is to make it clearer to users that they can still place an emergency call using the dialer even with no SIM card. --- policy/com/android/internal/policy/impl/LockScreen.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 6d2b2a4dd97e..2ec642630554 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -227,7 +227,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private void refreshUnlockIntructions() { if (mLockPatternUtils.isLockPatternEnabled() - || mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED) { + || mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED + || mUpdateMonitor.getSimState() == IccCard.State.ABSENT) { mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_enabled); } else { mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_disabled); @@ -327,6 +328,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM public void onSimStateChanged(IccCard.State simState) { mSimOk = isSimOk(simState); refreshViewsWRTSimOk(); + refreshUnlockIntructions(); } /** -- GitLab From 3af5ee44a42f64b8db012ccacc565e0a6debd0c5 Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Tue, 23 Jun 2009 17:54:58 -0700 Subject: [PATCH 066/458] Fix case where the lock screen information won't fit on screen. The case is in landscape, 'next alarm' showing, and the plmn is showing. In this case, don't show the next alarm. --- .../android/internal/policy/impl/LockScreen.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 2ec642630554..f2216889c4d4 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -21,6 +21,7 @@ import com.android.internal.widget.LockPatternUtils; import android.content.Context; import android.text.format.DateFormat; +import android.text.TextUtils; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -236,8 +237,14 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } private void refreshAlarmDisplay() { - String nextAlarmText = mLockPatternUtils.getNextAlarm(); - if (nextAlarmText != null && mSimOk) { + final String nextAlarmText = mLockPatternUtils.getNextAlarm(); + + // bug 1685880: if we are in landscape and showing plmn, the information can end up not + // fitting on screen. in this case, the alarm will get cut. + final CharSequence plmn = mUpdateMonitor.getTelephonyPlmn(); + final boolean showingPlmn = plmn != null && !TextUtils.isEmpty(plmn); + final boolean wontFit = !mUpdateMonitor.isInPortrait() && showingPlmn; + if (nextAlarmText != null && mSimOk && !wontFit) { setAlarmInfoVisible(true); mAlarmText.setText(nextAlarmText); } else { @@ -292,19 +299,20 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { refreshSimOkHeaders(plmn, spn); + refreshAlarmDisplay(); // in case alarm won't fit anymore } private void refreshSimOkHeaders(CharSequence plmn, CharSequence spn) { final IccCard.State simState = mUpdateMonitor.getSimState(); if (simState == IccCard.State.READY) { - if (plmn != null) { + if (plmn != null && !TextUtils.isEmpty(plmn)) { mHeaderSimOk1.setVisibility(View.VISIBLE); mHeaderSimOk1.setText(plmn); } else { mHeaderSimOk1.setVisibility(View.GONE); } - if (spn != null) { + if (spn != null && !TextUtils.isEmpty(spn)) { mHeaderSimOk2.setVisibility(View.VISIBLE); mHeaderSimOk2.setText(spn); } else { -- GitLab From 0a88e648b544dfa9b62a66a227c9e828dc7d62dc Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Fri, 26 Jun 2009 18:19:32 -0700 Subject: [PATCH 067/458] Remove unnused variable. --- policy/com/android/internal/policy/impl/PhoneWindowManager.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index caffb7fde7dc..e921a80e854b 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -221,8 +221,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { PowerManager.WakeLock mBroadcastWakeLock; class SettingsObserver extends ContentObserver { - private ContentQueryMap mSettings; - SettingsObserver(Handler handler) { super(handler); } -- GitLab From 56cfd6681aa4e5bb3088a283f10438dd6b746f98 Mon Sep 17 00:00:00 2001 From: Shin-ichiro KAWASAKI Date: Fri, 3 Jul 2009 16:37:46 +0900 Subject: [PATCH 068/458] Modified libdrm to support SuperH platform Added USTL_ANDROID_SH defination while build on SuperH platform --- media/libdrm/mobile2/Android.mk | 4 ++++ media/libdrm/mobile2/src/util/ustl-1.0/uutility.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/media/libdrm/mobile2/Android.mk b/media/libdrm/mobile2/Android.mk index e18713987024..70c66836249d 100644 --- a/media/libdrm/mobile2/Android.mk +++ b/media/libdrm/mobile2/Android.mk @@ -74,6 +74,10 @@ LOCAL_MODULE := libdrm2 ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86) LOCAL_CFLAGS += -DUSTL_ANDROID_X86 +else + ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-sh) + LOCAL_CFLAGS += -DUSTL_ANDROID_SH + endif endif include $(BUILD_STATIC_LIBRARY) diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uutility.h b/media/libdrm/mobile2/src/util/ustl-1.0/uutility.h index 7b5ae649768e..2ee9a81c1b6a 100644 --- a/media/libdrm/mobile2/src/util/ustl-1.0/uutility.h +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uutility.h @@ -370,7 +370,7 @@ namespace simd { /// implicit casts to pointer from an integral type. Ironically, such an /// implicit cast is already detected by gcc. /// -#if defined(USTL_ANDROID_X86) +#if defined(USTL_ANDROID_X86) || defined(USTL_ANDROID_SH) #define OVERLOAD_POINTER_AND_SIZE_T_V2(name, arg1type) #else #define OVERLOAD_POINTER_AND_SIZE_T_V2(name, arg1type) \ -- GitLab From f46d2db9326e22682668220e61bf2e71a77e3f5b Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Mon, 6 Jul 2009 14:58:50 -0400 Subject: [PATCH 069/458] Fix bug 1317754 - "Idle screen displays "Charging (100%)" even when fully charged." --- policy/com/android/internal/policy/impl/LockScreen.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index f2216889c4d4..0495a76b7c0c 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -279,8 +279,12 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM if (mPluggedIn) { mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_charging); - mBatteryInfoText.setText( - getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel)); + if (mBatteryLevel >= 100) { + mBatteryInfoText.setText(R.string.lockscreen_charged); + } else { + mBatteryInfoText.setText( + getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel)); + } } else { mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_low_battery); mBatteryInfoText.setText(R.string.lockscreen_low_battery); -- GitLab From 32a9cd8f69e761966a0f05cc455fac7f13f77dd8 Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Tue, 14 Jul 2009 14:56:53 -0700 Subject: [PATCH 070/458] Dismiss system windows when search is launched. --- policy/com/android/internal/policy/impl/PhoneWindow.java | 1 + 1 file changed, 1 insertion(+) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 59c87a5b4076..d2d1421b248d 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -2510,6 +2510,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (cb == null) { return false; } else { + sendCloseSystemWindows(); return cb.onSearchRequested(); } } -- GitLab From 24cfa450fa46a333ea9fa7de20a8755e592e1bed Mon Sep 17 00:00:00 2001 From: Ilia Tulchinsky Date: Tue, 14 Jul 2009 20:53:39 -0700 Subject: [PATCH 071/458] Disable fallback screen that asks for usr/pwd if we have SAML accounts which require web login. --- .../policy/impl/LockPatternKeyguardView.java | 64 +++++++++++++------ 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 982f9ffcb7e4..4294de401304 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -16,33 +16,36 @@ package com.android.internal.policy.impl; +import com.android.internal.R; +import com.android.internal.telephony.IccCard; +import com.android.internal.widget.LockPatternUtils; + import android.accounts.AccountManager; import android.app.AlertDialog; import android.content.Context; import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.PixelFormat; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.os.SystemProperties; -import com.android.internal.telephony.IccCard; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.WindowManager; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.PixelFormat; -import android.graphics.ColorFilter; -import com.android.internal.R; -import com.android.internal.widget.LockPatternUtils; /** * The host view for all of the screens of the pattern unlock screen. There are * two {@link Mode}s of operation, lock and unlock. This will show the appropriate - * screen, and listen for callbacks via {@link com.android.internal.policy.impl.KeyguardScreenCallback + * screen, and listen for callbacks via + * {@link com.android.internal.policy.impl.KeyguardScreenCallback} * from the current screen. * - * This view, in turn, communicates back to {@link com.android.internal.policy.impl.KeyguardViewManager} + * This view, in turn, communicates back to + * {@link com.android.internal.policy.impl.KeyguardViewManager} * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate. */ public class LockPatternKeyguardView extends KeyguardViewBase { @@ -55,12 +58,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase { private final KeyguardUpdateMonitor mUpdateMonitor; private final KeyguardWindowController mWindowController; - + private View mLockScreen; private View mUnlockScreen; private boolean mScreenOn = false; - private boolean mHasAccount = false; // assume they don't have an account until we know better + private boolean mEnableFallback = false; // assume no fallback UI until we know better /** @@ -149,7 +152,26 @@ public class LockPatternKeyguardView extends KeyguardViewBase { KeyguardWindowController controller) { super(context); - mHasAccount = AccountManager.get(context).blockingGetAccounts().length > 0; + final boolean hasAccount = AccountManager.get(context).blockingGetAccounts().length > 0; + boolean hasSAMLAccount = false; + if (hasAccount) { + /* If we have a SAML account which requires web login we can not use the + fallback screen UI to ask the user for credentials. + For now we will disable fallback screen in this case. + Ultimately we could consider bringing up a web login from GLS + but need to make sure that it will work in the "locked screen" mode. */ + + try { + hasSAMLAccount = + AccountManager.get(context).blockingGetAccountsWithTypeAndFeatures( + "com.GOOGLE.GAIA", new String[] {"saml"}).length > 0; + } catch (Exception e) { + // We err on the side of caution. + // In case of error we assume we have a SAML account. + hasSAMLAccount = true; + } + } + mEnableFallback = hasAccount && !hasSAMLAccount; mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); @@ -159,7 +181,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { mWindowController = controller; mMode = getInitialMode(); - + mKeyguardScreenCallback = new KeyguardScreenCallback() { public void goToLockScreen() { @@ -225,11 +247,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase { public void reportFailedPatternAttempt() { mUpdateMonitor.reportFailedAttempt(); final int failedAttempts = mUpdateMonitor.getFailedAttempts(); - if (mHasAccount && failedAttempts == - (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET + if (mEnableFallback && failedAttempts == + (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { showAlmostAtAccountLoginDialog(); - } else if (mHasAccount + } else if (mEnableFallback && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { mLockPatternUtils.setPermanentlyLocked(true); updateScreen(mMode); @@ -238,9 +260,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase { showTimeoutDialog(); } } - + public boolean doesFallbackUnlockScreenExist() { - return mHasAccount; + return mEnableFallback; } }; @@ -384,7 +406,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { // do this before changing visibility so focus isn't requested before the input // flag is set mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); - + if (mScreenOn) { if (goneScreen.getVisibility() == View.VISIBLE) { -- GitLab From 78866b1e07b1006f6ebf4adbc8e64b558c6040eb Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Fri, 17 Jul 2009 13:09:27 -0400 Subject: [PATCH 072/458] Close the global actions menu when the screen goes off. Previously, the global actions menu was closed when the keyguard was shown, but when the menu was shown from within the keyguard, it wasn't closed ever again when the screen goes off. That had the result that if your pocket managed to bring up the dialog, the menu would likely never go away on its own, and eventually do something awful like go into airplane mode. --- policy/com/android/internal/policy/impl/GlobalActions.java | 6 ++++-- .../android/internal/policy/impl/KeyguardViewMediator.java | 1 - .../android/internal/policy/impl/PhoneWindowManager.java | 7 ------- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/policy/com/android/internal/policy/impl/GlobalActions.java b/policy/com/android/internal/policy/impl/GlobalActions.java index 10ac01c03b13..377ff7828e75 100644 --- a/policy/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/com/android/internal/policy/impl/GlobalActions.java @@ -80,6 +80,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac // receive broadcasts IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + filter.addAction(Intent.ACTION_SCREEN_OFF); context.registerReceiver(mBroadcastReceiver, filter); // get notified of phone state changes @@ -483,9 +484,10 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { + if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action) + || Intent.ACTION_SCREEN_OFF.equals(action)) { String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY); - if (! PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) { + if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) { mHandler.sendEmptyMessage(MESSAGE_DISMISS); } } diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 112d7b2149e8..043f72712690 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -857,7 +857,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // manager not to honor request for userActivity. mRealPowerManager.enableUserActivity(false); - mCallback.onKeyguardShow(); mKeyguardViewManager.show(); mShowing = true; } diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index e921a80e854b..0392c7e4a8be 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1690,13 +1690,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mKeyguardMediator.isInputRestricted(); } - /** - * Callback from {@link KeyguardViewMediator} - */ - public void onKeyguardShow() { - sendCloseSystemWindows(); - } - void sendCloseSystemWindows() { sendCloseSystemWindows(mContext, null); } -- GitLab From 323216beeb6f7f63f28f0dd10666f3c10617a6b7 Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Mon, 20 Jul 2009 14:00:29 -0700 Subject: [PATCH 073/458] have "search" as the reason when dismissing system dialogs for search. this way search can't dismiss itself. can't use the constant because it is in policy. would rather leave it this way instead of moving constants for system dialog dismissal to framework. --- policy/com/android/internal/policy/impl/PhoneWindow.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index d2d1421b248d..db43a9c8aa74 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -2510,7 +2510,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (cb == null) { return false; } else { - sendCloseSystemWindows(); + sendCloseSystemWindows("search"); return cb.onSearchRequested(); } } -- GitLab From 413cb9debdbc65a42495f324de6b94061abf3557 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 17 Jul 2009 11:52:43 -0700 Subject: [PATCH 074/458] Fix issue 1795088 Improve audio routing code Initial commit for review. --- .../internal/policy/impl/PhoneWindowManager.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 0392c7e4a8be..a905fe1648a0 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1365,17 +1365,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { * @return Whether music is being played right now. */ boolean isMusicActive() { - final IAudioService audio = getAudioInterface(); - if (audio == null) { - Log.w(TAG, "isMusicActive: couldn't get IAudioService reference"); - return false; - } - try { - return audio.isMusicActive(); - } catch (RemoteException e) { - Log.w(TAG, "IAudioService.isMusicActive() threw RemoteException " + e); + final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); + if (am == null) { + Log.w(TAG, "isMusicActive: couldn't get AudioManager reference"); return false; } + return am.isMusicActive(); } /** -- GitLab From 0041e97ce6c6e35a8280877c77fcd57ed278eec4 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Fri, 24 Jul 2009 17:14:43 -0700 Subject: [PATCH 075/458] Update for virtual key haptic feedback, deal with canceled keys. --- .../internal/policy/impl/PhoneWindow.java | 16 +++- .../policy/impl/PhoneWindowManager.java | 77 +++++++++++-------- 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 44933c9c0c81..a810e1603145 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -676,6 +676,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mPanelChordingKey = 0; mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); + if (event.isCanceled()) { + return; + } + boolean playSoundEffect = false; PanelFeatureState st = getPanelState(featureId, true); if (st.isOpen || st.isHandled) { @@ -1393,7 +1397,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); if (!mKeycodeCameraTimeoutActive) break; mKeycodeCameraTimeoutActive = false; - // Add short press behavior here if desired + if (!event.isCanceled()) { + // Add short press behavior here if desired + } return true; } @@ -1405,7 +1411,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); if (!mKeycodeCallTimeoutActive) break; mKeycodeCallTimeoutActive = false; - startCallActivity(); + if (!event.isCanceled()) { + startCallActivity(); + } return true; } @@ -1420,7 +1428,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { break; } mSearchKeyDownReceived = false; - launchDefaultSearch(); + if (!event.isCanceled()) { + launchDefaultSearch(); + } return true; } } diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index a905fe1648a0..cfe25e277a81 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -149,6 +149,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Vibrator pattern for haptic feedback of a long press. private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21}; + // Vibrator pattern for haptic feedback of virtual key press. + private static final long[] VIRTUAL_KEY_VIBE_PATTERN = {0, 1, 20, 21}; + final Object mLock = new Object(); Context mContext; @@ -373,7 +376,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - Runnable mEndCallLongPress = new Runnable() { + Runnable mPowerLongPress = new Runnable() { public void run() { mShouldTurnOffOnKeyUp = false; performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); @@ -775,7 +778,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, - int repeatCount) { + int repeatCount, int flags) { boolean keyguardOn = keyguardOn(); if (false) { @@ -800,32 +803,36 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (!down) { mHomePressed = false; - // If an incoming call is ringing, HOME is totally disabled. - // (The user is already on the InCallScreen at this point, - // and his ONLY options are to answer or reject the call.) - boolean incomingRinging = false; - try { - ITelephony phoneServ = getPhoneInterface(); - if (phoneServ != null) { - incomingRinging = phoneServ.isRinging(); + if ((flags&KeyEvent.FLAG_CANCELED) == 0) { + // If an incoming call is ringing, HOME is totally disabled. + // (The user is already on the InCallScreen at this point, + // and his ONLY options are to answer or reject the call.) + boolean incomingRinging = false; + try { + ITelephony phoneServ = getPhoneInterface(); + if (phoneServ != null) { + incomingRinging = phoneServ.isRinging(); + } else { + Log.w(TAG, "Unable to find ITelephony interface"); + } + } catch (RemoteException ex) { + Log.w(TAG, "RemoteException from getPhoneInterface()", ex); + } + + if (incomingRinging) { + Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); } else { - Log.w(TAG, "Unable to find ITelephony interface"); + launchHomeFromHotKey(); } - } catch (RemoteException ex) { - Log.w(TAG, "RemoteException from getPhoneInterface()", ex); - } - - if (incomingRinging) { - Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); } else { - launchHomeFromHotKey(); + Log.i(TAG, "Ignoring HOME; event canceled."); } } } return true; } - + // First we always handle the home key here, so applications // can never break it, although if keyguard is on, we do let // it handle it, because that gives us the correct 5 second @@ -1470,33 +1477,36 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean down = event.value != 0; if (type == RawInputEvent.EV_KEY) { - if (code == KeyEvent.KEYCODE_ENDCALL) { + if (code == KeyEvent.KEYCODE_ENDCALL + || code == KeyEvent.KEYCODE_POWER) { if (down) { boolean hungUp = false; // key repeats are generated by the window manager, and we don't see them // here, so unless the driver is doing something it shouldn't be, we know // this is the real press event. - try { - ITelephony phoneServ = getPhoneInterface(); - if (phoneServ != null) { - hungUp = phoneServ.endCall(); - } else { - Log.w(TAG, "!!! Unable to find ITelephony interface !!!"); + if (code == KeyEvent.KEYCODE_ENDCALL) { + try { + ITelephony phoneServ = getPhoneInterface(); + if (phoneServ != null) { + hungUp = phoneServ.endCall(); + } else { + Log.w(TAG, "!!! Unable to find ITelephony interface !!!"); + } + } catch (RemoteException ex) { + Log.w(TAG, "ITelephony.endCall() threw RemoteException" + ex); } - } catch (RemoteException ex) { - Log.w(TAG, "ITelephony.endCall() threw RemoteException" + ex); } if (hungUp || !screenIsOn) { mShouldTurnOffOnKeyUp = false; } else { // only try to turn off the screen if we didn't already hang up mShouldTurnOffOnKeyUp = true; - mHandler.postDelayed(mEndCallLongPress, + mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout()); result &= ~ACTION_PASS_TO_USER; } } else { - mHandler.removeCallbacks(mEndCallLongPress); + mHandler.removeCallbacks(mPowerLongPress); if (mShouldTurnOffOnKeyUp) { mShouldTurnOffOnKeyUp = false; boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0; @@ -1854,6 +1864,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } + public void keyFeedbackFromInput(KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_DOWN + && (event.getFlags()&KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) { + mVibrator.vibrate(VIRTUAL_KEY_VIBE_PATTERN, -1); + } + } + public void screenOnStoppedLw() { if (!mKeyguardMediator.isShowing()) { long curTime = SystemClock.uptimeMillis(); -- GitLab From 94a679daba6e07a600966b1cb034f04f2ec20003 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 28 Jul 2009 17:51:07 -0700 Subject: [PATCH 076/458] Fix issue #1999179: search -> click result -> press home = search dialog is shown then hidden Re-arrange various things to ensure that the search dialog is told about system windows being closed before it is told about the navigation back to home. --- .../android/internal/policy/impl/PhoneWindow.java | 2 +- .../internal/policy/impl/PhoneWindowManager.java | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index db43a9c8aa74..6341771ac0f6 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -239,11 +239,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (!mKeycodeCameraTimeoutActive) return; mKeycodeCameraTimeoutActive = false; mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + sendCloseSystemWindows(); // Broadcast an intent that the Camera button was longpressed Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj); getContext().sendOrderedBroadcast(intent, null); - sendCloseSystemWindows(); } break; case MSG_SEARCH_LONG_PRESS_COMPLETE: { if (getKeyguardManager().inKeyguardRestrictedInputMode() || diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 0392c7e4a8be..8140b3dbf7ee 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -954,8 +954,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { ActivityManagerNative.getDefault().stopAppSwitches(); } catch (RemoteException e) { } - mContext.startActivity(mHomeIntent); sendCloseSystemWindows(); + mContext.startActivity(mHomeIntent); } } }); @@ -965,8 +965,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { ActivityManagerNative.getDefault().stopAppSwitches(); } catch (RemoteException e) { } - mContext.startActivity(mHomeIntent); sendCloseSystemWindows(); + mContext.startActivity(mHomeIntent); } } @@ -1700,11 +1700,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { static void sendCloseSystemWindows(Context context, String reason) { if (ActivityManagerNative.isSystemReady()) { - Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - if (reason != null) { - intent.putExtra(SYSTEM_DIALOG_REASON_KEY, reason); + try { + ActivityManagerNative.getDefault().closeSystemDialogs(reason); + } catch (RemoteException e) { } - context.sendBroadcast(intent); } } @@ -1816,12 +1815,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { ActivityManagerNative.getDefault().stopAppSwitches(); } catch (RemoteException e) { } + sendCloseSystemWindows(); mContext.startActivity(mHomeIntent); } else { // This code brings home to the front or, if it is already // at the front, puts the device to sleep. try { ActivityManagerNative.getDefault().stopAppSwitches(); + sendCloseSystemWindows(); int result = ActivityManagerNative.getDefault() .startActivity(null, mHomeIntent, mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()), @@ -1833,7 +1834,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { // bummer, the activity manager, which is in this process, is dead } } - sendCloseSystemWindows(); return true; } -- GitLab From 51afe5c40426d3dc4c9aa9bce701b9db80dab337 Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Tue, 28 Jul 2009 18:20:08 -0700 Subject: [PATCH 077/458] Fix bug 1982892 - batteryservice turns off device even while plugged in Also, make the battery service do it, not some keyguard thing. --- .../internal/policy/impl/KeyguardUpdateMonitor.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index cd21427e1342..44e893b498f9 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -35,7 +35,6 @@ import static android.provider.Telephony.Intents.EXTRA_SHOW_SPN; import static android.provider.Telephony.Intents.EXTRA_SPN; import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION; -import com.android.internal.app.ShutdownThread; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.TelephonyIntents; import android.util.Log; @@ -295,13 +294,6 @@ public class KeyguardUpdateMonitor { shouldShowBatteryInfo(), pluggedIn, batteryLevel); } } - - // shut down gracefully if our battery is critically low and we are not powered - if (batteryLevel == 0 && - pluggedInStatus != BATTERY_STATUS_CHARGING && - pluggedInStatus != BATTERY_STATUS_UNKNOWN) { - ShutdownThread.shutdown(mContext, false); - } } /** -- GitLab From b7cd8b9144e170e12a838de5dc33a132a51419fe Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Sat, 8 Aug 2009 20:53:03 -0700 Subject: [PATCH 078/458] Add knowledge about new wallpaper window type. --- .../policy/impl/PhoneWindowManager.java | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 8c0e95db9dde..1c7da0e15011 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -88,6 +88,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; import android.media.IAudioService; @@ -108,29 +109,31 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final boolean SHOW_STARTING_ANIMATIONS = true; static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; - static final int APPLICATION_LAYER = 1; - static final int PHONE_LAYER = 2; - static final int SEARCH_BAR_LAYER = 3; - static final int STATUS_BAR_PANEL_LAYER = 4; + // wallpaper is at the bottom, though the window manager may move it. + static final int WALLPAPER_LAYER = 1; + static final int APPLICATION_LAYER = 2; + static final int PHONE_LAYER = 3; + static final int SEARCH_BAR_LAYER = 4; + static final int STATUS_BAR_PANEL_LAYER = 5; // toasts and the plugged-in battery thing - static final int TOAST_LAYER = 5; - static final int STATUS_BAR_LAYER = 6; + static final int TOAST_LAYER = 6; + static final int STATUS_BAR_LAYER = 7; // SIM errors and unlock. Not sure if this really should be in a high layer. - static final int PRIORITY_PHONE_LAYER = 7; + static final int PRIORITY_PHONE_LAYER = 8; // like the ANR / app crashed dialogs - static final int SYSTEM_ALERT_LAYER = 8; + static final int SYSTEM_ALERT_LAYER = 9; // system-level error dialogs - static final int SYSTEM_ERROR_LAYER = 9; + static final int SYSTEM_ERROR_LAYER = 10; // on-screen keyboards and other such input method user interfaces go here. - static final int INPUT_METHOD_LAYER = 10; + static final int INPUT_METHOD_LAYER = 11; // on-screen keyboards and other such input method user interfaces go here. - static final int INPUT_METHOD_DIALOG_LAYER = 11; + static final int INPUT_METHOD_DIALOG_LAYER = 12; // the keyguard; nothing on top of these can take focus, since they are // responsible for power management when displayed. - static final int KEYGUARD_LAYER = 12; - static final int KEYGUARD_DIALOG_LAYER = 13; + static final int KEYGUARD_LAYER = 13; + static final int KEYGUARD_DIALOG_LAYER = 14; // things in here CAN NOT take focus, but are shown on top of everything else. - static final int SYSTEM_OVERLAY_LAYER = 14; + static final int SYSTEM_OVERLAY_LAYER = 15; static final int APPLICATION_MEDIA_SUBLAYER = -2; static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; @@ -468,7 +471,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // monitor/control what they are doing. break; case TYPE_INPUT_METHOD: - // The window manager will check this. + case TYPE_WALLPAPER: + // The window manager will check these. break; case TYPE_PHONE: case TYPE_PRIORITY_PHONE: @@ -569,6 +573,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return PRIORITY_PHONE_LAYER; case TYPE_TOAST: return TOAST_LAYER; + case TYPE_WALLPAPER: + return WALLPAPER_LAYER; } Log.e(TAG, "Unknown window type: " + type); return APPLICATION_LAYER; -- GitLab From 4bf7bcf89b459132e743ebbd8df895dc5e129989 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Sun, 9 Aug 2009 17:23:00 -0700 Subject: [PATCH 079/458] Add support for new wallpaper theme attribute. --- policy/com/android/internal/policy/impl/PhoneWindow.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 345b6200e7b7..4a1011b7dced 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -20,6 +20,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; 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 com.android.internal.view.menu.ContextMenuBuilder; import com.android.internal.view.menu.MenuBuilder; @@ -2105,6 +2106,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags())); } + if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) { + setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags())); + } + WindowManager.LayoutParams params = getAttributes(); if (!hasSoftInputMode()) { -- GitLab From 4aaab1583ad393de827981eafa7a53ac73395fcd Mon Sep 17 00:00:00 2001 From: Fred Quintana Date: Fri, 14 Aug 2009 16:52:24 -0700 Subject: [PATCH 080/458] cleanup the AccountManager API --- .../policy/impl/AccountUnlockScreen.java | 81 +++++++++++-------- .../policy/impl/LockPatternKeyguardView.java | 8 +- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index 098a65118445..e1181453d619 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -21,6 +21,10 @@ import com.android.internal.widget.LockPatternUtils; import android.accounts.Account; import android.accounts.AccountManager; +import android.accounts.OperationCanceledException; +import android.accounts.AccountManagerFuture; +import android.accounts.AuthenticatorException; +import android.accounts.AccountManagerCallback; import android.content.Context; import android.content.Intent; import android.graphics.Rect; @@ -36,6 +40,8 @@ import android.widget.EditText; import android.widget.RelativeLayout; import android.widget.TextView; +import java.io.IOException; + /** * When the user forgets their password a bunch of times, we fall back on their * account's login/password to unlock the phone (and reset their lock pattern). @@ -135,23 +141,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree public void onClick(View v) { mCallback.pokeWakelock(); if (v == mOk) { - if (checkPassword()) { - // clear out forgotten password - mLockPatternUtils.setPermanentlyLocked(false); - - // launch the 'choose lock pattern' activity so - // the user can pick a new one if they want to - Intent intent = new Intent(); - intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(intent); - - // close the keyguard - mCallback.keyguardDone(true); - } else { - mInstructions.setText(R.string.lockscreen_glogin_invalid_input); - mPassword.setText(""); - } + asyncCheckPassword(); } if (v == mEmergencyCall) { @@ -159,6 +149,26 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree } } + private void onCheckPasswordResult(boolean flag) { + if (flag) { + // clear out forgotten password + mLockPatternUtils.setPermanentlyLocked(false); + + // launch the 'choose lock pattern' activity so + // the user can pick a new one if they want to + Intent intent = new Intent(); + intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + + // close the keyguard + mCallback.keyguardDone(true); + } else { + mInstructions.setText(R.string.lockscreen_glogin_invalid_input); + mPassword.setText(""); + } + } + @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN @@ -186,7 +196,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree * find a single best match. */ private Account findIntendedAccount(String username) { - Account[] accounts = AccountManager.get(mContext).blockingGetAccounts(); + Account[] accounts = AccountManager.get(mContext).getAccounts(); // Try to figure out which account they meant if they // typed only the username (and not the domain), or got @@ -196,14 +206,14 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree int bestScore = 0; for (Account a: accounts) { int score = 0; - if (username.equals(a.mName)) { + if (username.equals(a.name)) { score = 4; - } else if (username.equalsIgnoreCase(a.mName)) { + } else if (username.equalsIgnoreCase(a.name)) { score = 3; } else if (username.indexOf('@') < 0) { - int i = a.mName.indexOf('@'); + int i = a.name.indexOf('@'); if (i >= 0) { - String aUsername = a.mName.substring(0, i); + String aUsername = a.name.substring(0, i); if (username.equals(aUsername)) { score = 2; } else if (username.equalsIgnoreCase(aUsername)) { @@ -221,21 +231,26 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree return bestAccount; } - private boolean checkPassword() { + private void asyncCheckPassword() { final String login = mLogin.getText().toString(); final String password = mPassword.getText().toString(); Account account = findIntendedAccount(login); if (account == null) { - return false; - } - // TODO(fredq) change this to asynchronously issue the request and wait for the response (by - // supplying a callback rather than calling get() immediately) - try { - return AccountManager.get(mContext).confirmPassword( - account, password, null /* callback */, null /* handler */).getResult(); - } catch (android.accounts.OperationCanceledException e) { - // the request was canceled - return false; + onCheckPasswordResult(false); + return; } + AccountManager.get(mContext).confirmPassword( + account, password, new AccountManagerCallback() { + public void run(AccountManagerFuture future) { + boolean result = false; + try { + result = future.getResult(); + } catch (OperationCanceledException e) { + } catch (IOException e) { + } catch (AuthenticatorException e) { + } + onCheckPasswordResult(result); + } + }, null /* handler */); } } diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 4294de401304..0c45cd56e4fa 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -152,7 +152,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { KeyguardWindowController controller) { super(context); - final boolean hasAccount = AccountManager.get(context).blockingGetAccounts().length > 0; + final boolean hasAccount = AccountManager.get(context).getAccounts().length > 0; boolean hasSAMLAccount = false; if (hasAccount) { /* If we have a SAML account which requires web login we can not use the @@ -160,11 +160,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase { For now we will disable fallback screen in this case. Ultimately we could consider bringing up a web login from GLS but need to make sure that it will work in the "locked screen" mode. */ - try { + String[] features = new String[] {"saml"}; hasSAMLAccount = - AccountManager.get(context).blockingGetAccountsWithTypeAndFeatures( - "com.GOOGLE.GAIA", new String[] {"saml"}).length > 0; + AccountManager.get(context).getAccountsByTypeAndFeatures( + "com.google.GAIA", features, null, null).getResult().length > 0; } catch (Exception e) { // We err on the side of caution. // In case of error we assume we have a SAML account. -- GitLab From 1c01c8bc79941471857338bae011fd0a6790f89f Mon Sep 17 00:00:00 2001 From: Fred Quintana Date: Sat, 15 Aug 2009 21:46:24 -0700 Subject: [PATCH 081/458] do not merge: cherrypicked 53f5bc273b81a3761242d3356ed8490b5e6797f2 from master branch --- .../policy/impl/AccountUnlockScreen.java | 81 +++++++++++-------- .../policy/impl/LockPatternKeyguardView.java | 8 +- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index 098a65118445..e1181453d619 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -21,6 +21,10 @@ import com.android.internal.widget.LockPatternUtils; import android.accounts.Account; import android.accounts.AccountManager; +import android.accounts.OperationCanceledException; +import android.accounts.AccountManagerFuture; +import android.accounts.AuthenticatorException; +import android.accounts.AccountManagerCallback; import android.content.Context; import android.content.Intent; import android.graphics.Rect; @@ -36,6 +40,8 @@ import android.widget.EditText; import android.widget.RelativeLayout; import android.widget.TextView; +import java.io.IOException; + /** * When the user forgets their password a bunch of times, we fall back on their * account's login/password to unlock the phone (and reset their lock pattern). @@ -135,23 +141,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree public void onClick(View v) { mCallback.pokeWakelock(); if (v == mOk) { - if (checkPassword()) { - // clear out forgotten password - mLockPatternUtils.setPermanentlyLocked(false); - - // launch the 'choose lock pattern' activity so - // the user can pick a new one if they want to - Intent intent = new Intent(); - intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(intent); - - // close the keyguard - mCallback.keyguardDone(true); - } else { - mInstructions.setText(R.string.lockscreen_glogin_invalid_input); - mPassword.setText(""); - } + asyncCheckPassword(); } if (v == mEmergencyCall) { @@ -159,6 +149,26 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree } } + private void onCheckPasswordResult(boolean flag) { + if (flag) { + // clear out forgotten password + mLockPatternUtils.setPermanentlyLocked(false); + + // launch the 'choose lock pattern' activity so + // the user can pick a new one if they want to + Intent intent = new Intent(); + intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + + // close the keyguard + mCallback.keyguardDone(true); + } else { + mInstructions.setText(R.string.lockscreen_glogin_invalid_input); + mPassword.setText(""); + } + } + @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN @@ -186,7 +196,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree * find a single best match. */ private Account findIntendedAccount(String username) { - Account[] accounts = AccountManager.get(mContext).blockingGetAccounts(); + Account[] accounts = AccountManager.get(mContext).getAccounts(); // Try to figure out which account they meant if they // typed only the username (and not the domain), or got @@ -196,14 +206,14 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree int bestScore = 0; for (Account a: accounts) { int score = 0; - if (username.equals(a.mName)) { + if (username.equals(a.name)) { score = 4; - } else if (username.equalsIgnoreCase(a.mName)) { + } else if (username.equalsIgnoreCase(a.name)) { score = 3; } else if (username.indexOf('@') < 0) { - int i = a.mName.indexOf('@'); + int i = a.name.indexOf('@'); if (i >= 0) { - String aUsername = a.mName.substring(0, i); + String aUsername = a.name.substring(0, i); if (username.equals(aUsername)) { score = 2; } else if (username.equalsIgnoreCase(aUsername)) { @@ -221,21 +231,26 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree return bestAccount; } - private boolean checkPassword() { + private void asyncCheckPassword() { final String login = mLogin.getText().toString(); final String password = mPassword.getText().toString(); Account account = findIntendedAccount(login); if (account == null) { - return false; - } - // TODO(fredq) change this to asynchronously issue the request and wait for the response (by - // supplying a callback rather than calling get() immediately) - try { - return AccountManager.get(mContext).confirmPassword( - account, password, null /* callback */, null /* handler */).getResult(); - } catch (android.accounts.OperationCanceledException e) { - // the request was canceled - return false; + onCheckPasswordResult(false); + return; } + AccountManager.get(mContext).confirmPassword( + account, password, new AccountManagerCallback() { + public void run(AccountManagerFuture future) { + boolean result = false; + try { + result = future.getResult(); + } catch (OperationCanceledException e) { + } catch (IOException e) { + } catch (AuthenticatorException e) { + } + onCheckPasswordResult(result); + } + }, null /* handler */); } } diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 4294de401304..0c45cd56e4fa 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -152,7 +152,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { KeyguardWindowController controller) { super(context); - final boolean hasAccount = AccountManager.get(context).blockingGetAccounts().length > 0; + final boolean hasAccount = AccountManager.get(context).getAccounts().length > 0; boolean hasSAMLAccount = false; if (hasAccount) { /* If we have a SAML account which requires web login we can not use the @@ -160,11 +160,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase { For now we will disable fallback screen in this case. Ultimately we could consider bringing up a web login from GLS but need to make sure that it will work in the "locked screen" mode. */ - try { + String[] features = new String[] {"saml"}; hasSAMLAccount = - AccountManager.get(context).blockingGetAccountsWithTypeAndFeatures( - "com.GOOGLE.GAIA", new String[] {"saml"}).length > 0; + AccountManager.get(context).getAccountsByTypeAndFeatures( + "com.google.GAIA", features, null, null).getResult().length > 0; } catch (Exception e) { // We err on the side of caution. // In case of error we assume we have a SAML account. -- GitLab From 3c3bd44fd48d7f17735adc3666602145fa2a9a24 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 19 Aug 2009 17:09:46 -0700 Subject: [PATCH 082/458] New wallpaper transition constants. --- policy/com/android/internal/policy/impl/PhoneWindowManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 1c7da0e15011..22669516b3ea 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -110,7 +110,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; // wallpaper is at the bottom, though the window manager may move it. - static final int WALLPAPER_LAYER = 1; + static final int WALLPAPER_LAYER = 2; static final int APPLICATION_LAYER = 2; static final int PHONE_LAYER = 3; static final int SEARCH_BAR_LAYER = 4; -- GitLab From 93a0a5f2cac599224faff7774a6142af06802ca3 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 20 Aug 2009 19:33:02 -0700 Subject: [PATCH 083/458] Update to implement new APIs. --- .../internal/policy/impl/PhoneWindow.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 4a1011b7dced..ee96e1cd0c32 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -568,7 +568,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { WRAP_CONTENT, WRAP_CONTENT, st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, WindowManager.LayoutParams.FLAG_DITHER - | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, + | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM + | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, st.decorView.mDefaultOpacity); lp.gravity = st.gravity; @@ -2040,6 +2041,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); + + final Callback cb = getCallback(); + if (cb != null && mFeatureId < 0) { + cb.onAttachedToWindow(); + } if (mFeatureId == -1) { /* @@ -2052,6 +2058,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { openPanelsAfterRestore(); } } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + final Callback cb = getCallback(); + if (cb != null && mFeatureId < 0) { + cb.onDetachedFromWindow(); + } + } } protected DecorView generateDecor() { -- GitLab From 8e9a594936c1ffca7cdb5bd4d8a1442380333854 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Thu, 20 Aug 2009 23:34:42 -0700 Subject: [PATCH 084/458] Remove unused field from PhoneWindow.DecorView. --- policy/com/android/internal/policy/impl/PhoneWindow.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index ee96e1cd0c32..72dec29749c1 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -35,7 +35,6 @@ import android.content.Intent; import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Canvas; -import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -264,6 +263,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // press action to be performed. mSearchKeyDownReceived = false; } catch (ActivityNotFoundException e) { + // Ignore } } break; } @@ -1616,8 +1616,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private final Rect mFrameOffsets = new Rect(); - private final Paint mBlackPaint = new Paint(); - private boolean mChanging; private Drawable mMenuBackground; @@ -1627,7 +1625,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public DecorView(Context context, int featureId) { super(context); mFeatureId = featureId; - mBlackPaint.setColor(0xFF000000); } @Override -- GitLab From 1753f7f64dbd91dc3961f6fc01b8110c79f6e5de Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Mon, 24 Aug 2009 14:49:07 -0700 Subject: [PATCH 085/458] PhoneWindowManager: Rotate display when phone is docked Also moved the number of degrees of rotation for keyboard open state to a resource. Signed-off-by: Mike Lockwood --- .../policy/impl/PhoneWindowManager.java | 56 ++++++++++++++++--- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 22669516b3ea..0167e0a1ab42 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -25,6 +25,7 @@ import android.content.ContentQueryMap; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; @@ -175,6 +176,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { Handler mHandler; boolean mLidOpen; + boolean mDocked; + int mLidOpenRotation; + int mDockedRotation; boolean mScreenOn = false; boolean mOrientationSensorEnabled = false; int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -453,6 +457,32 @@ public class PhoneWindowManager implements WindowManagerPolicy { mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PhoneWindowManager.mBroadcastWakeLock"); mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); + mLidOpenRotation = readRotation(com.android.internal.R.integer.config_lidOpenRotation, + Surface.ROTATION_90); + mDockedRotation = readRotation(com.android.internal.R.integer.config_dockedRotation, + Surface.ROTATION_90); + // register for dock events + context.registerReceiver(mDockReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT)); + } + + private int readRotation(int resID, int defaultRotation) { + try { + int rotation = mContext.getResources().getInteger(resID); + switch (rotation) { + case 0: + return Surface.ROTATION_0; + case 90: + return Surface.ROTATION_90; + case 180: + return Surface.ROTATION_180; + case 270: + return Surface.ROTATION_270; + default: + return defaultRotation; + } + } catch (Resources.NotFoundException e) { + return defaultRotation; + } } /** {@inheritDoc} */ @@ -506,7 +536,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { void readLidState() { try { - int sw = mWindowManager.getSwitchState(0); + int sw = mWindowManager.getSwitchState(RawInputEvent.SW_LID); if (sw >= 0) { mLidOpen = sw == 0; } @@ -1312,7 +1342,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public boolean preprocessInputEventTq(RawInputEvent event) { switch (event.type) { case RawInputEvent.EV_SW: - if (event.keycode == 0) { + if (event.keycode == RawInputEvent.SW_LID) { // lid changed state mLidOpen = event.value == 0; updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); @@ -1631,7 +1661,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { mBroadcastWakeLock.release(); } }; - + + BroadcastReceiver mDockReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, + Intent.EXTRA_DOCK_STATE_UNDOCKED); + mDocked = (state != Intent.EXTRA_DOCK_STATE_UNDOCKED); + updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); + } + }; + /** {@inheritDoc} */ public boolean isWakeRelMovementTq(int device, int classes, RawInputEvent event) { @@ -1747,7 +1786,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // or orientation sensor disabled //or case.unspecified if (mLidOpen) { - return Surface.ROTATION_90; + return mLidOpenRotation; + } else if (mDocked) { + return mDockedRotation; } else { if (useSensorForOrientationLp(orientation)) { // If the user has enabled auto rotation by default, do it. @@ -1800,10 +1841,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { void updateRotation(int animFlags) { mPowerManager.setKeyboardVisibility(mLidOpen); - int rotation= Surface.ROTATION_0; + int rotation = Surface.ROTATION_0; if (mLidOpen) { - // always use landscape if lid is open - rotation = Surface.ROTATION_90; + rotation = mLidOpenRotation; + } else if (mDocked) { + rotation = mDockedRotation; } //if lid is closed orientation will be portrait try { -- GitLab From 84999d69e0a70f5e510577b09ea1e788142252a8 Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Mon, 24 Aug 2009 17:18:02 -0700 Subject: [PATCH 086/458] Adjust 'account unlock' scenario to make 'forgot pattern' more forgiving. When a user hits the 'forgot pattern' button, they aren't permanently forced into using the account to unlock the screen; they can get back to the pattern screen by hitting the back key, or by turning off the screen (e.g it's not sticky). Also, show progress dialog while checking account, and make sure we are on the UI thread when doing stuff from the account callback. --- .../policy/impl/AccountUnlockScreen.java | 68 ++++++++++++++++--- .../policy/impl/KeyguardScreenCallback.java | 11 ++- .../policy/impl/LockPatternKeyguardView.java | 17 ++++- .../internal/policy/impl/UnlockScreen.java | 14 +++- 4 files changed, 96 insertions(+), 14 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index e1181453d619..069f97e6e3c4 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -35,10 +35,13 @@ import android.text.TextWatcher; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; +import android.view.WindowManager; import android.widget.Button; import android.widget.EditText; import android.widget.RelativeLayout; import android.widget.TextView; +import android.app.Dialog; +import android.app.ProgressDialog; import java.io.IOException; @@ -67,12 +70,17 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree private Button mOk; private Button mEmergencyCall; + /** + * Shown while making asynchronous check of password. + */ + private ProgressDialog mCheckingDialog; + /** * AccountUnlockScreen constructor. */ public AccountUnlockScreen(Context context, - KeyguardScreenCallback callback, - LockPatternUtils lockPatternUtils) { + KeyguardScreenCallback callback, + LockPatternUtils lockPatternUtils) { super(context); mCallback = callback; mLockPatternUtils = lockPatternUtils; @@ -81,6 +89,9 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree R.layout.keyguard_screen_glogin_unlock, this, true); mTopHeader = (TextView) findViewById(R.id.topHeader); + mTopHeader.setText(mLockPatternUtils.isPermanentlyLocked() ? + R.string.lockscreen_glogin_too_many_attempts : + R.string.lockscreen_glogin_forgot_pattern); mInstructions = (TextView) findViewById(R.id.instructions); @@ -135,6 +146,9 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree /** {@inheritDoc} */ public void cleanUp() { + if (mCheckingDialog != null) { + mCheckingDialog.hide(); + } } /** {@inheritDoc} */ @@ -149,10 +163,12 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree } } - private void onCheckPasswordResult(boolean flag) { - if (flag) { + private void onCheckPasswordResult(boolean success) { + if (success) { // clear out forgotten password mLockPatternUtils.setPermanentlyLocked(false); + mLockPatternUtils.setLockPatternEnabled(false); + mLockPatternUtils.saveLockPattern(null); // launch the 'choose lock pattern' activity so // the user can pick a new one if they want to @@ -173,7 +189,11 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree public boolean dispatchKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { - mCallback.goToLockScreen(); + if (mLockPatternUtils.isPermanentlyLocked()) { + mCallback.goToLockScreen(); + } else { + mCallback.forgotPattern(false); + } return true; } return super.dispatchKeyEvent(event); @@ -232,6 +252,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree } private void asyncCheckPassword() { + mCallback.pokeWakelock(AWAKE_POKE_MILLIS); final String login = mLogin.getText().toString(); final String password = mPassword.getText().toString(); Account account = findIntendedAccount(login); @@ -239,18 +260,49 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree onCheckPasswordResult(false); return; } + getProgressDialog().show(); AccountManager.get(mContext).confirmPassword( account, password, new AccountManagerCallback() { public void run(AccountManagerFuture future) { - boolean result = false; try { - result = future.getResult(); + mCallback.pokeWakelock(AWAKE_POKE_MILLIS); + final boolean result = future.getResult(); + // ensure on UI thread + mLogin.post(new Runnable() { + public void run() { + onCheckPasswordResult(result); + } + }); } catch (OperationCanceledException e) { + onCheckPasswordResult(false); } catch (IOException e) { + onCheckPasswordResult(false); } catch (AuthenticatorException e) { + onCheckPasswordResult(false); + } finally { + mLogin.post(new Runnable() { + public void run() { + getProgressDialog().hide(); + } + }); } - onCheckPasswordResult(result); } }, null /* handler */); } + + private Dialog getProgressDialog() { + if (mCheckingDialog == null) { + mCheckingDialog = new ProgressDialog(mContext); + mCheckingDialog.setMessage( + mContext.getString(R.string.lockscreen_glogin_checking_password)); + mCheckingDialog.setIndeterminate(true); + mCheckingDialog.setCancelable(false); + mCheckingDialog.getWindow().setType( + WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + mCheckingDialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + } + return mCheckingDialog; + } } diff --git a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java index b46b37d04db0..6bb6a45a7e34 100644 --- a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java +++ b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java @@ -28,10 +28,19 @@ public interface KeyguardScreenCallback extends KeyguardViewCallback { void goToLockScreen(); /** - * Transitino to th unlock screen. + * Transition to the unlock screen. */ void goToUnlockScreen(); + /** + * The user reported that they forgot their pattern (or not, when they want to back out of the + * forgot pattern screen). + * + * @param isForgotten True if the user hit the forgot pattern, false if they want to back out + * of the account screen. + */ + void forgotPattern(boolean isForgotten); + /** * @return Whether the keyguard requires some sort of PIN. */ diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 0c45cd56e4fa..31bfd47af84a 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -112,10 +112,13 @@ public class LockPatternKeyguardView extends KeyguardViewBase { private Mode mMode = Mode.LockScreen; /** - * Keeps track of what mode the current unlock screen is + * Keeps track of what mode the current unlock screen is (cached from most recent computation in + * {@link #getUnlockMode}). */ private UnlockMode mUnlockScreenMode; + private boolean mForgotPattern; + /** * If true, it means we are in the process of verifying that the user * can get past the lock screen per {@link #verifyUnlock()} @@ -185,6 +188,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { mKeyguardScreenCallback = new KeyguardScreenCallback() { public void goToLockScreen() { + mForgotPattern = false; if (mIsVerifyUnlockOnly) { // navigating away from unlock screen during verify mode means // we are done and the user failed to authenticate. @@ -209,6 +213,13 @@ public class LockPatternKeyguardView extends KeyguardViewBase { } } + public void forgotPattern(boolean isForgotten) { + if (mEnableFallback) { + mForgotPattern = isForgotten; + updateScreen(Mode.UnlockScreen); + } + } + public boolean isSecure() { return LockPatternKeyguardView.this.isSecure(); } @@ -293,12 +304,14 @@ public class LockPatternKeyguardView extends KeyguardViewBase { @Override public void reset() { mIsVerifyUnlockOnly = false; + mForgotPattern = false; updateScreen(getInitialMode()); } @Override public void onScreenTurnedOff() { mScreenOn = false; + mForgotPattern = false; if (mMode == Mode.LockScreen) { ((KeyguardScreen) mLockScreen).onPause(); } else { @@ -523,7 +536,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { if (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED) { return UnlockMode.SimPin; } else { - return mLockPatternUtils.isPermanentlyLocked() ? + return (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) ? UnlockMode.Account: UnlockMode.Pattern; } diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index 9aedf901d232..74e03192c052 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -104,6 +104,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient case ForgotLockPattern: mFooterNormal.setVisibility(View.GONE); mFooterForgotPattern.setVisibility(View.VISIBLE); + mForgotPatternButton.setVisibility(View.VISIBLE); break; case VerifyUnlocked: mFooterNormal.setVisibility(View.GONE); @@ -164,8 +165,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mForgotPatternButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { - mLockPatternUtils.setPermanentlyLocked(true); - mCallback.goToUnlockScreen(); + mCallback.forgotPattern(true); } }); @@ -274,6 +274,15 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mUpdateMonitor.removeCallback(this); } + @Override + public void onWindowFocusChanged(boolean hasWindowFocus) { + super.onWindowFocusChanged(hasWindowFocus); + if (hasWindowFocus) { + // when timeout dialog closes we want to update our state + onResume(); + } + } + private class UnlockPatternListener implements LockPatternView.OnPatternListener { @@ -337,5 +346,4 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient } }.start(); } - } -- GitLab From ab97c84da56b2484e4441d2958358ff1c5d07395 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Mon, 24 Aug 2009 17:35:52 -0500 Subject: [PATCH 087/458] policy/impl: Add option to disable screen-unlock-on-slider-open Signed-off-by: Dan Murphy --- .../internal/policy/impl/KeyguardUpdateMonitor.java | 9 +++++++++ .../internal/policy/impl/KeyguardViewMediator.java | 4 ++-- .../internal/policy/impl/LockPatternKeyguardView.java | 3 ++- policy/com/android/internal/policy/impl/LockScreen.java | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 44e893b498f9..58905a10c435 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -66,6 +66,8 @@ public class KeyguardUpdateMonitor { private boolean mInPortrait; private boolean mKeyboardOpen; + private boolean mKeyguardBypassEnabled; + private boolean mDevicePluggedIn; private boolean mDeviceProvisioned; @@ -162,6 +164,9 @@ public class KeyguardUpdateMonitor { } }; + mKeyguardBypassEnabled = context.getResources().getBoolean( + com.android.internal.R.bool.config_bypass_keyguard_if_slider_open); + mDeviceProvisioned = Settings.Secure.getInt( mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; @@ -505,6 +510,10 @@ public class KeyguardUpdateMonitor { return mKeyboardOpen; } + public boolean isKeyguardBypassEnabled() { + return mKeyguardBypassEnabled; + } + public boolean isDevicePluggedIn() { return mDevicePluggedIn; } diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 043f72712690..b1ce74679477 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -571,8 +571,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, public void onKeyboardChange(boolean isKeyboardOpen) { mKeyboardOpen = isKeyboardOpen; - if (mKeyboardOpen && !mKeyguardViewProperties.isSecure() - && mKeyguardViewManager.isShowing()) { + if (mUpdateMonitor.isKeyguardBypassEnabled() && mKeyboardOpen + && !mKeyguardViewProperties.isSecure() && mKeyguardViewManager.isShowing()) { if (DEBUG) Log.d(TAG, "bypassing keyguard on sliding open of keyboard with non-secure keyguard"); keyguardDone(true); } diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 31bfd47af84a..332d58061371 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -521,7 +521,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { final IccCard.State simState = mUpdateMonitor.getSimState(); if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED)) { return Mode.LockScreen; - } else if (mUpdateMonitor.isKeyboardOpen() && isSecure()) { + } else if (mUpdateMonitor.isKeyguardBypassEnabled() && mUpdateMonitor.isKeyboardOpen() + && isSecure()) { return Mode.UnlockScreen; } else { return Mode.LockScreen; diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 0495a76b7c0c..f3f99a200380 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -358,7 +358,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } public void onKeyboardChange(boolean isKeyboardOpen) { - if (isKeyboardOpen) { + if (mUpdateMonitor.isKeyguardBypassEnabled() && isKeyboardOpen) { mCallback.goToUnlockScreen(); } } -- GitLab From 33303d76ccf78b3c7f690b1bb18f5bae73821dd3 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Thu, 27 Aug 2009 13:27:51 -0700 Subject: [PATCH 088/458] Don't activate keyguard if screen is turned off while proximity sensor is active. Signed-off-by: Mike Lockwood --- .../android/internal/policy/impl/KeyguardViewMediator.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index b1ce74679477..2daab27f2f8b 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -273,8 +273,9 @@ public class KeyguardViewMediator implements KeyguardViewCallback, /** * Called to let us know the screen was turned off. - * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER} or - * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}. + * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER}, + * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or + * {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROXIMITY_SENSOR}. */ public void onScreenTurnedOff(int why) { synchronized (this) { @@ -305,7 +306,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, sender); if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = " + mDelayedShowingSequence); - } else { + } else if (why != WindowManagerPolicy.OFF_BECAUSE_OF_PROXIMITY_SENSOR) { doKeyguard(); } } -- GitLab From d6b903d9507d66b37ec96e932c3e5d5046a4e483 Mon Sep 17 00:00:00 2001 From: Paul Eastham Date: Thu, 27 Aug 2009 14:11:23 -0700 Subject: [PATCH 089/458] Increase vibrate duration on vkey haptics so they can be felt. --- policy/com/android/internal/policy/impl/PhoneWindowManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 0167e0a1ab42..b4b6612ea7fc 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -154,7 +154,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21}; // Vibrator pattern for haptic feedback of virtual key press. - private static final long[] VIRTUAL_KEY_VIBE_PATTERN = {0, 1, 20, 21}; + private static final long[] VIRTUAL_KEY_VIBE_PATTERN = {0, 35}; final Object mLock = new Object(); -- GitLab From 181ceb5c78e51133dd4cd3bfbb9385565a27821c Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 27 Aug 2009 22:16:40 -0700 Subject: [PATCH 090/458] Put vibration patterns in resources. Change-Id: If7c9d4c3bee4bc3319379fbb588265d6202c2bee --- .../policy/impl/PhoneWindowManager.java | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index b4b6612ea7fc..b664cb405b2e 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -150,12 +150,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; - // Vibrator pattern for haptic feedback of a long press. - private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21}; - - // Vibrator pattern for haptic feedback of virtual key press. - private static final long[] VIRTUAL_KEY_VIBE_PATTERN = {0, 35}; - final Object mLock = new Object(); Context mContext; @@ -163,6 +157,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { LocalPowerManager mPowerManager; Vibrator mVibrator; // Vibrator for giving feedback of orientation changes + // Vibrator pattern for haptic feedback of a long press. + long[] mLongPressVibePattern; + + // Vibrator pattern for haptic feedback of virtual key press. + long[] mVirtualKeyVibePattern; + /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ boolean mEnableShiftMenuBugReports = false; @@ -1812,6 +1812,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + static long[] getLongIntArray(Resources r, int resid) { + int[] ar = r.getIntArray(resid); + if (ar == null) { + return null; + } + long[] out = new long[ar.length]; + for (int i=0; i Date: Sun, 6 Sep 2009 22:12:28 -0700 Subject: [PATCH 091/458] Tweak so lock screen wallpaper is aligned with real wallpaper. Change-Id: Iee117ae1496c0c4e9d12d16eeba69bcad351a57a --- .../internal/policy/impl/LockPatternKeyguardView.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 332d58061371..8474b9c913ef 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -582,8 +582,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase { } /** - * Used to put wallpaper on the background of the lock screen. Centers it Horizontally and - * vertically. + * Used to put wallpaper on the background of the lock screen. Centers it + * Horizontally and pins the bottom (assuming that the lock screen is aligned + * with the bottom, so the wallpaper should extend above the top into the + * status bar). */ static private class FastBitmapDrawable extends Drawable { private Bitmap mBitmap; @@ -599,7 +601,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { canvas.drawBitmap( mBitmap, (getBounds().width() - mBitmap.getWidth()) / 2, - (getBounds().height() - mBitmap.getHeight()) / 2, + (getBounds().height() - mBitmap.getHeight()), null); } -- GitLab From a207baaf2c0ae405a8dd787846b892972d25fcd8 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Sun, 13 Sep 2009 16:14:44 -0700 Subject: [PATCH 092/458] Follow key event API changes. We now use the new tracking and long press dispatching in the framework to greatly simplify this code. Change-Id: I4c0ed51dc2d07ed3bb20c64c67eede83bdb123b9 --- .../internal/policy/impl/PhoneWindow.java | 294 +++++++----------- 1 file changed, 117 insertions(+), 177 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 72dec29749c1..fac41823ed5f 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -124,6 +124,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * this is 0, there is no key held down. */ private int mPanelChordingKey; + private boolean mPanelMayLongPress; private ImageView mLeftIconView; @@ -155,121 +156,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private TelephonyManager mTelephonyManager = null; - private boolean mSearchKeyDownReceived; - - private boolean mKeycodeCallTimeoutActive = false; - - private boolean mKeycodeCameraTimeoutActive = false; - - static final int MSG_MENU_LONG_PRESS = 1; - static final int MSG_MENU_LONG_PRESS_COMPLETE = 2; - static final int MSG_CALL_LONG_PRESS = 3; - static final int MSG_CALL_LONG_PRESS_COMPLETE = 4; - static final int MSG_CAMERA_LONG_PRESS = 5; - static final int MSG_CAMERA_LONG_PRESS_COMPLETE = 6; - static final int MSG_SEARCH_LONG_PRESS = 7; - static final int MSG_SEARCH_LONG_PRESS_COMPLETE = 8; - - private final Handler mKeycodeMenuTimeoutHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_MENU_LONG_PRESS: { - if (mPanelChordingKey == 0) return; - // Before actually doing the long press, enqueue another - // message and do the processing there. This helps if - // the app isn't being responsive, and finally woke up -- - // if the window manager wasn't told about it processing - // the down key for too long, it would enqueue the key up - // at a time after the timeout of this message. So we go - // through another message, to make sure we process an up - // before continuing. - mKeycodeMenuTimeoutHandler.sendEmptyMessage( - MSG_MENU_LONG_PRESS_COMPLETE); - break; - } - case MSG_CALL_LONG_PRESS: { - if (!mKeycodeCallTimeoutActive) return; - // See above. - mKeycodeMenuTimeoutHandler.sendEmptyMessage( - MSG_CALL_LONG_PRESS_COMPLETE); - break; - } - case MSG_CAMERA_LONG_PRESS: { - if (!mKeycodeCameraTimeoutActive) return; - // See above. - Message newMessage = Message.obtain(msg); - newMessage.what = MSG_CAMERA_LONG_PRESS_COMPLETE; - mKeycodeMenuTimeoutHandler.sendMessage(newMessage); - break; - } - case MSG_SEARCH_LONG_PRESS: { - if (!mSearchKeyDownReceived) return; - // See above. - Message newMessage = Message.obtain(msg); - newMessage.what = MSG_SEARCH_LONG_PRESS_COMPLETE; - mKeycodeMenuTimeoutHandler.sendMessage(newMessage); - break; - } - case MSG_MENU_LONG_PRESS_COMPLETE: { - if (mPanelChordingKey == 0) return; - mPanelChordingKey = 0; - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - InputMethodManager imm = (InputMethodManager) - getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - if (imm != null) { - imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); - } - } break; - case MSG_CALL_LONG_PRESS_COMPLETE: { - if (!mKeycodeCallTimeoutActive) return; - mKeycodeCallTimeoutActive = false; - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - // launch the VoiceDialer - Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - sendCloseSystemWindows(); - getContext().startActivity(intent); - } catch (ActivityNotFoundException e) { - startCallActivity(); - } - } break; - case MSG_CAMERA_LONG_PRESS_COMPLETE: { - if (!mKeycodeCameraTimeoutActive) return; - mKeycodeCameraTimeoutActive = false; - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - sendCloseSystemWindows(); - // Broadcast an intent that the Camera button was longpressed - Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); - intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj); - getContext().sendOrderedBroadcast(intent, null); - } break; - case MSG_SEARCH_LONG_PRESS_COMPLETE: { - if (getKeyguardManager().inKeyguardRestrictedInputMode() || - !mSearchKeyDownReceived) { - mSearchKeyDownReceived = false; - return; - } - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - // launch the search activity - Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - sendCloseSystemWindows(); - getContext().startActivity(intent); - // Only clear this if we successfully start the - // activity; otherwise we will allow the normal short - // press action to be performed. - mSearchKeyDownReceived = false; - } catch (ActivityNotFoundException e) { - // Ignore - } - } break; - } - } - }; - public PhoneWindow(Context context) { super(context); mLayoutInflater = LayoutInflater.from(context); @@ -649,19 +535,35 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * @return Whether the key was handled. */ public final boolean onKeyDownPanel(int featureId, KeyEvent event) { - // The panel key was pushed, so set the chording key - mPanelChordingKey = event.getKeyCode(); - - PanelFeatureState st = getPanelState(featureId, true); - if (!st.isOpen) { - if (getContext().getResources().getConfiguration().keyboard - == Configuration.KEYBOARD_NOKEYS) { - mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); - mKeycodeMenuTimeoutHandler.sendMessageDelayed( - mKeycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS), - ViewConfiguration.getLongPressTimeout()); + final int keyCode = event.getKeyCode(); + + if (event.getRepeatCount() == 0) { + // 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 + == Configuration.KEYBOARD_NOKEYS) { + mPanelMayLongPress = true; + } + 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 + // should be executed... do it! + mPanelChordingKey = 0; + mPanelMayLongPress = false; + InputMethodManager imm = (InputMethodManager) + getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); } - return preparePanel(st, event); + } return false; @@ -676,7 +578,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // The panel key was released, so clear the chording key if (mPanelChordingKey != 0) { mPanelChordingKey = 0; - mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); + mPanelMayLongPress = false; if (event.isCanceled()) { return; @@ -1218,6 +1120,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * @see android.view.KeyEvent */ protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) { + final KeyEvent.DispatcherState dispatcher = + mDecor != null ? mDecor.getKeyDispatcherState() : null; + //Log.i(TAG, "Key down: repeat=" + event.getRepeatCount() + // + " flags=0x" + Integer.toHexString(event.getFlags())); + switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: { @@ -1264,26 +1171,31 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } case KeyEvent.KEYCODE_CAMERA: { - if (getKeyguardManager().inKeyguardRestrictedInputMode()) { + if (getKeyguardManager().inKeyguardRestrictedInputMode() + || dispatcher == null) { break; } - if (event.getRepeatCount() > 0) break; - mKeycodeCameraTimeoutActive = true; - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); - Message message = mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CAMERA_LONG_PRESS); - message.obj = event; - mKeycodeMenuTimeoutHandler.sendMessageDelayed(message, - ViewConfiguration.getLongPressTimeout()); + if (event.getRepeatCount() == 0) { + dispatcher.startTracking(event, this); + } else if (event.isLongPress() && dispatcher.isTracking(event)) { + dispatcher.performedLongPress(event); + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + sendCloseSystemWindows(); + // Broadcast an intent that the Camera button was longpressed + Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, event); + getContext().sendOrderedBroadcast(intent, null); + } return true; } case KeyEvent.KEYCODE_MENU: { - if (event.getRepeatCount() > 0) break; onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event); return true; } case KeyEvent.KEYCODE_BACK: { + // Currently don't do anything with long presses. if (event.getRepeatCount() > 0) break; if (featureId < 0) break; if (featureId == FEATURE_OPTIONS_PANEL) { @@ -1300,34 +1212,55 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } case KeyEvent.KEYCODE_CALL: { - if (getKeyguardManager().inKeyguardRestrictedInputMode()) { + if (getKeyguardManager().inKeyguardRestrictedInputMode() + || dispatcher == null) { break; } - if (event.getRepeatCount() > 0) break; - mKeycodeCallTimeoutActive = true; - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); - mKeycodeMenuTimeoutHandler.sendMessageDelayed( - mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CALL_LONG_PRESS), - ViewConfiguration.getLongPressTimeout()); + if (event.getRepeatCount() == 0) { + dispatcher.startTracking(event, this); + } else if (event.isLongPress() && dispatcher.isTracking(event)) { + dispatcher.performedLongPress(event); + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + // launch the VoiceDialer + Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + sendCloseSystemWindows(); + getContext().startActivity(intent); + } catch (ActivityNotFoundException e) { + startCallActivity(); + } + } return true; } case KeyEvent.KEYCODE_SEARCH: { + if (getKeyguardManager().inKeyguardRestrictedInputMode() + || dispatcher == null) { + break; + } if (event.getRepeatCount() == 0) { - mSearchKeyDownReceived = true; + dispatcher.startTracking(event, this); + } else if (event.isLongPress() && dispatcher.isTracking(event)) { Configuration config = getContext().getResources().getConfiguration(); if (config.keyboard == Configuration.KEYBOARD_NOKEYS - || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { - // If this device does not have a hardware keyboard, - // or that keyboard is hidden, then we can't use the - // search key for chording to perform shortcuts; - // instead, we will let the user long press, - mKeycodeMenuTimeoutHandler.removeMessages(MSG_SEARCH_LONG_PRESS); - mKeycodeMenuTimeoutHandler.sendMessageDelayed( - mKeycodeMenuTimeoutHandler.obtainMessage(MSG_SEARCH_LONG_PRESS), - ViewConfiguration.getLongPressTimeout()); + || config.hardKeyboardHidden + == Configuration.HARDKEYBOARDHIDDEN_YES) { + // launch the search activity + Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + sendCloseSystemWindows(); + getContext().startActivity(intent); + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + // Only clear this if we successfully start the + // activity; otherwise we will allow the normal short + // press action to be performed. + dispatcher.performedLongPress(event); + } catch (ActivityNotFoundException e) { + // Ignore + } } - return true; } break; } @@ -1353,6 +1286,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * @see android.view.KeyEvent */ protected boolean onKeyUp(int featureId, int keyCode, KeyEvent event) { + final KeyEvent.DispatcherState dispatcher = + mDecor != null ? mDecor.getKeyDispatcherState() : null; + if (dispatcher != null) { + dispatcher.handleUpEvent(event); + } + //Log.i(TAG, "Key up: repeat=" + event.getRepeatCount() + // + " flags=0x" + Integer.toHexString(event.getFlags())); + switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: { @@ -1378,6 +1319,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return true; } + case KeyEvent.KEYCODE_BACK: { + if (featureId < 0) break; + if (featureId == FEATURE_OPTIONS_PANEL) { + PanelFeatureState st = getPanelState(featureId, false); + if (st != null && st.isInExpandedMode) { + // If the user is in an expanded menu and hits back, it + // should go back to the icon menu + reopenMenu(true); + return true; + } + } + closePanel(featureId); + return true; + } + case KeyEvent.KEYCODE_HEADSETHOOK: case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: case KeyEvent.KEYCODE_MEDIA_STOP: @@ -1395,11 +1351,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (getKeyguardManager().inKeyguardRestrictedInputMode()) { break; } - if (event.getRepeatCount() > 0) break; // Can a key up event repeat? - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); - if (!mKeycodeCameraTimeoutActive) break; - mKeycodeCameraTimeoutActive = false; - if (!event.isCanceled()) { + if (event.isTracking() && !event.isCanceled()) { // Add short press behavior here if desired } return true; @@ -1409,11 +1361,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (getKeyguardManager().inKeyguardRestrictedInputMode()) { break; } - if (event.getRepeatCount() > 0) break; - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); - if (!mKeycodeCallTimeoutActive) break; - mKeycodeCallTimeoutActive = false; - if (!event.isCanceled()) { + if (event.isTracking() && !event.isCanceled()) { startCallActivity(); } return true; @@ -1424,13 +1372,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * Do this in onKeyUp since the Search key is also used for * chording quick launch shortcuts. */ - if (getKeyguardManager().inKeyguardRestrictedInputMode() || - !mSearchKeyDownReceived) { - mSearchKeyDownReceived = false; + if (getKeyguardManager().inKeyguardRestrictedInputMode()) { break; } - mSearchKeyDownReceived = false; - if (!event.isCanceled()) { + if (event.isTracking() && !event.isCanceled()) { launchDefaultSearch(); } return true; @@ -2016,16 +1961,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); - // no KEYCODE_CALL events active across focus changes - mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); - mKeycodeCallTimeoutActive = false; - mKeycodeCameraTimeoutActive = false; + mPanelMayLongPress = false; // If the user is chording a menu shortcut, release the chord since // this window lost focus - if (!hasWindowFocus && mPanelChordingKey > 0) { + if (!hasWindowFocus && mPanelChordingKey != 0) { closePanel(FEATURE_OPTIONS_PANEL); } -- GitLab From fed9cb561095040446449244fbc09a361678d6a3 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 14 Sep 2009 21:23:11 -0700 Subject: [PATCH 093/458] Various fixes for back key handling. Change-Id: I8ad314722ce38711ce5c57c4fd3b2942cfe099a7 --- .../internal/policy/impl/PhoneWindow.java | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index fac41823ed5f..d8d278824d2f 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -1195,19 +1195,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } case KeyEvent.KEYCODE_BACK: { - // Currently don't do anything with long presses. if (event.getRepeatCount() > 0) break; if (featureId < 0) break; - if (featureId == FEATURE_OPTIONS_PANEL) { - PanelFeatureState st = getPanelState(featureId, false); - if (st != null && st.isInExpandedMode) { - // If the user is in an expanded menu and hits back, it - // should go back to the icon menu - reopenMenu(true); - return true; - } - } - closePanel(featureId); + // Currently don't do anything with long press. + dispatcher.startTracking(event, this); return true; } @@ -1321,17 +1312,20 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { case KeyEvent.KEYCODE_BACK: { if (featureId < 0) break; - if (featureId == FEATURE_OPTIONS_PANEL) { - PanelFeatureState st = getPanelState(featureId, false); - if (st != null && st.isInExpandedMode) { - // If the user is in an expanded menu and hits back, it - // should go back to the icon menu - reopenMenu(true); - return true; + if (event.isTracking() && !event.isCanceled()) { + if (featureId == FEATURE_OPTIONS_PANEL) { + PanelFeatureState st = getPanelState(featureId, false); + if (st != null && st.isInExpandedMode) { + // If the user is in an expanded menu and hits back, it + // should go back to the icon menu + reopenMenu(true); + return true; + } } + closePanel(featureId); + return true; } - closePanel(featureId); - return true; + break; } case KeyEvent.KEYCODE_HEADSETHOOK: -- GitLab From d3715100b326b7b1383eb43d47028eac25313ca2 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 15 Sep 2009 19:28:03 -0700 Subject: [PATCH 094/458] Fix issue #1401973 and #2111181 (menu placement problems). Issue 1401973: A dialog with menu has wrong menu placement Issue 2111181: status bar overlaps the more menu in browser Menus are now dialog panels, so they are placed within the entire screen and not attached to their parent window. Change-Id: Ia9702d5e30a6ba5ebb0254abe6a94cbbdfa9866d --- policy/com/android/internal/policy/impl/PhoneWindow.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index d8d278824d2f..05dc936d0fd9 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -452,10 +452,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { WindowManager.LayoutParams lp = new WindowManager.LayoutParams( WRAP_CONTENT, WRAP_CONTENT, - st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, + st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG, WindowManager.LayoutParams.FLAG_DITHER - | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM - | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, + | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, st.decorView.mDefaultOpacity); lp.gravity = st.gravity; -- GitLab From d322c437fe48dc03f0df94492267b3783e3411cb Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Mon, 7 Sep 2009 12:43:05 -0700 Subject: [PATCH 095/458] Add rotary based lock screen, and only show security pattern screen when pattern is set. When a pattern is enabled, there is no informational lock screen, just the pattern screen. Eventually we will get a new layout that manages to show the relevent information (date / time / charging info / alarm) on the pattern screen. Also: I noticed that when there is no backup option available, we still showed the "forgot pattern?" button, which would do nothing. I fixed that; we no longer show the "forgot pattern" button if there is no account unlock option available. a --- .../policy/impl/LockPatternKeyguardView.java | 6 +- .../internal/policy/impl/LockScreen.java | 484 ++++++++++-------- .../internal/policy/impl/UnlockScreen.java | 43 +- 3 files changed, 309 insertions(+), 224 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 8474b9c913ef..f961f47f9ce9 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -455,7 +455,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { mLockPatternUtils, mUpdateMonitor, mKeyguardScreenCallback, - mUpdateMonitor.getFailedAttempts()); + mUpdateMonitor.getFailedAttempts(), + mEnableFallback); } else if (unlockMode == UnlockMode.SimPin) { return new SimUnlockScreen( mContext, @@ -521,8 +522,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { final IccCard.State simState = mUpdateMonitor.getSimState(); if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED)) { return Mode.LockScreen; - } else if (mUpdateMonitor.isKeyguardBypassEnabled() && mUpdateMonitor.isKeyboardOpen() - && isSecure()) { + } else if (isSecure()) { return Mode.UnlockScreen; } else { return Mode.LockScreen; diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index f3f99a200380..99aef334f947 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -18,18 +18,18 @@ package com.android.internal.policy.impl; import com.android.internal.R; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.RotarySelector; import android.content.Context; import android.text.format.DateFormat; -import android.text.TextUtils; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; +import android.widget.*; +import android.graphics.drawable.Drawable; +import android.util.Log; +import android.media.AudioManager; import com.android.internal.telephony.IccCard; import java.util.Date; @@ -40,40 +40,27 @@ import java.util.Date; * past it, as applicable. */ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateMonitor.InfoCallback, - KeyguardUpdateMonitor.SimStateCallback, KeyguardUpdateMonitor.ConfigurationChangeCallback { + KeyguardUpdateMonitor.SimStateCallback, KeyguardUpdateMonitor.ConfigurationChangeCallback, + RotarySelector.OnDialTriggerListener { + + static private final boolean DBG = false; + static private final String TAG = "LockScreen"; + + private Status mStatus = Status.Normal; + private final LockPatternUtils mLockPatternUtils; private final KeyguardUpdateMonitor mUpdateMonitor; private final KeyguardScreenCallback mCallback; - private TextView mHeaderSimOk1; - private TextView mHeaderSimOk2; - - private TextView mHeaderSimBad1; - private TextView mHeaderSimBad2; - + private TextView mCarrier; + private RotarySelector mRotary; private TextView mTime; private TextView mDate; - - private ViewGroup mBatteryInfoGroup; - private ImageView mBatteryInfoIcon; - private TextView mBatteryInfoText; - private View mBatteryInfoSpacer; - - private ViewGroup mNextAlarmGroup; - private TextView mAlarmText; - private View mAlarmSpacer; - - private ViewGroup mScreenLockedMessageGroup; - - private TextView mLockInstructions; - + private TextView mStatus1; + private TextView mStatus2; + private TextView mScreenLocked; private Button mEmergencyCallButton; - /** - * false means sim is missing or PUK'd - */ - private boolean mSimOk = true; - // are we showing battery information? private boolean mShowingBatteryInfo = false; @@ -83,10 +70,65 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // last known battery level private int mBatteryLevel = 100; + private String mNextAlarm = null; + private Drawable mAlarmIcon = null; + private String mCharging = null; + private Drawable mChargingIcon = null; + + private boolean mSilentMode; + private AudioManager mAudioManager; + + /** + * The status of this lock screen. + */ + enum Status { + /** + * Normal case (sim card present, it's not locked) + */ + Normal(true), + + /** + * The sim card is 'network locked'. + */ + NetworkLocked(true), + + /** + * The sim card is missing. + */ + SimMissing(false), + + /** + * The sim card is missing, and this is the device isn't provisioned, so we don't let + * them get past the screen. + */ + SimMissingLocked(false), + + /** + * The sim card is PUK locked, meaning they've entered the wrong sim unlock code too many + * times. + */ + SimPukLocked(false), + + /** + * The sim card is locked. + */ + SimLocked(true); + + private final boolean mShowStatusLines; + + Status(boolean mShowStatusLines) { + this.mShowStatusLines = mShowStatusLines; + } - private View[] mOnlyVisibleWhenSimOk; + /** + * @return Whether the status lines (battery level and / or next alarm) are shown while + * in this state. Mostly dictated by whether this is room for them. + */ + public boolean showStatusLines() { + return mShowStatusLines; + } + } - private View[] mOnlyVisibleWhenSimNotOk; /** * @param context Used to setup the view. @@ -104,76 +146,51 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mCallback = callback; final LayoutInflater inflater = LayoutInflater.from(context); - inflater.inflate(R.layout.keyguard_screen_lock, this, true); + inflater.inflate(R.layout.keyguard_screen_rotary_unlock, this, true); - mSimOk = isSimOk(updateMonitor.getSimState()); mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo(); mPluggedIn = updateMonitor.isDevicePluggedIn(); mBatteryLevel = updateMonitor.getBatteryLevel(); - mHeaderSimOk1 = (TextView) findViewById(R.id.headerSimOk1); - mHeaderSimOk2 = (TextView) findViewById(R.id.headerSimOk2); - - mHeaderSimBad1 = (TextView) findViewById(R.id.headerSimBad1); - mHeaderSimBad2 = (TextView) findViewById(R.id.headerSimBad2); - + mCarrier = (TextView) findViewById(R.id.carrier); mTime = (TextView) findViewById(R.id.time); mDate = (TextView) findViewById(R.id.date); - - mBatteryInfoGroup = (ViewGroup) findViewById(R.id.batteryInfo); - mBatteryInfoIcon = (ImageView) findViewById(R.id.batteryInfoIcon); - mBatteryInfoText = (TextView) findViewById(R.id.batteryInfoText); - mBatteryInfoSpacer = findViewById(R.id.batteryInfoSpacer); - - mNextAlarmGroup = (ViewGroup) findViewById(R.id.nextAlarmInfo); - mAlarmText = (TextView) findViewById(R.id.nextAlarmText); - mAlarmSpacer = findViewById(R.id.nextAlarmSpacer); - - mScreenLockedMessageGroup = (ViewGroup) findViewById(R.id.screenLockedInfo); - - mLockInstructions = (TextView) findViewById(R.id.lockInstructions); + mStatus1 = (TextView) findViewById(R.id.status1); + mStatus2 = (TextView) findViewById(R.id.status2); mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); - + mEmergencyCallButton.setText(R.string.lockscreen_emergency_call); + mScreenLocked = (TextView) findViewById(R.id.screenLocked); + mRotary = (RotarySelector) findViewById(R.id.rotary); mEmergencyCallButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mCallback.takeEmergencyCallAction(); } }); - mOnlyVisibleWhenSimOk = new View[] { - mHeaderSimOk1, - mHeaderSimOk2, - mBatteryInfoGroup, - mBatteryInfoSpacer, - mNextAlarmGroup, - mAlarmSpacer, - mScreenLockedMessageGroup, - mLockInstructions - }; - - mOnlyVisibleWhenSimNotOk = new View[] { - mHeaderSimBad1, - mHeaderSimBad2, - mEmergencyCallButton - }; - setFocusable(true); setFocusableInTouchMode(true); setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); - refreshBatteryDisplay(); + mStatus = getCurrentStatus(updateMonitor.getSimState()); + updateLayout(mStatus); + + refreshBatteryStringAndIcon(); refreshAlarmDisplay(); refreshTimeAndDateDisplay(); - refreshUnlockIntructions(); - refreshViewsWRTSimOk(); - refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn()); + updateStatusLines(); updateMonitor.registerInfoCallback(this); updateMonitor.registerSimStateCallback(this); updateMonitor.registerConfigurationChangeCallback(this); - } + mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); + mSilentMode = mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT; + + mRotary.setOnDialTriggerListener(this); + mRotary.setLeftHandleResource(R.drawable.ic_jog_dial_unlock); + mRotary.setRightHandleResource(R.drawable.ic_jog_dial_turn_ring_vol_off); + } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { @@ -183,114 +200,67 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM return false; } - private void refreshViewsWRTSimOk() { - if (mSimOk) { - for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) { - final View view = mOnlyVisibleWhenSimOk[i]; - if (view == null) throw new RuntimeException("index " + i + " null"); - view.setVisibility(View.VISIBLE); - } - for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) { - final View view = mOnlyVisibleWhenSimNotOk[i]; - view.setVisibility(View.GONE); - } - refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), - mUpdateMonitor.getTelephonySpn()); - refreshAlarmDisplay(); - refreshBatteryDisplay(); - } else { - for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) { - final View view = mOnlyVisibleWhenSimOk[i]; - view.setVisibility(View.GONE); - } - for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) { - final View view = mOnlyVisibleWhenSimNotOk[i]; - view.setVisibility(View.VISIBLE); - } - refreshSimBadInfo(); - } - } - - private void refreshSimBadInfo() { - final IccCard.State simState = mUpdateMonitor.getSimState(); - if (simState == IccCard.State.PUK_REQUIRED) { - mHeaderSimBad1.setText(R.string.lockscreen_sim_puk_locked_message); - mHeaderSimBad2.setText(R.string.lockscreen_sim_puk_locked_instructions); - } else if (simState == IccCard.State.ABSENT) { - mHeaderSimBad1.setText(R.string.lockscreen_missing_sim_message); - mHeaderSimBad2.setVisibility(View.GONE); - //mHeaderSimBad2.setText(R.string.lockscreen_missing_sim_instructions); - } else { - mHeaderSimBad1.setVisibility(View.GONE); - mHeaderSimBad2.setVisibility(View.GONE); - } - } - - private void refreshUnlockIntructions() { - if (mLockPatternUtils.isLockPatternEnabled() - || mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED - || mUpdateMonitor.getSimState() == IccCard.State.ABSENT) { - mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_enabled); - } else { - mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_disabled); + /** {@inheritDoc} */ + public boolean onDialTrigger(View v, int whichHandle) { + if (whichHandle == RotarySelector.OnDialTriggerListener.LEFT_HANDLE) { + mCallback.goToUnlockScreen(); + return mStatus == Status.Normal; // only want to freeze drawing when actually unlocking + } else if (whichHandle == RotarySelector.OnDialTriggerListener.RIGHT_HANDLE) { + // toggle silent mode + mSilentMode = !mSilentMode; + mAudioManager.setRingerMode(mSilentMode ? AudioManager.RINGER_MODE_SILENT + : AudioManager.RINGER_MODE_NORMAL); + mRotary.setRightHandleResource(mSilentMode ? + R.drawable.ic_jog_dial_turn_ring_vol_on : + R.drawable.ic_jog_dial_turn_ring_vol_off); + mCallback.pokeWakelock(); } + return false; } private void refreshAlarmDisplay() { - final String nextAlarmText = mLockPatternUtils.getNextAlarm(); - - // bug 1685880: if we are in landscape and showing plmn, the information can end up not - // fitting on screen. in this case, the alarm will get cut. - final CharSequence plmn = mUpdateMonitor.getTelephonyPlmn(); - final boolean showingPlmn = plmn != null && !TextUtils.isEmpty(plmn); - final boolean wontFit = !mUpdateMonitor.isInPortrait() && showingPlmn; - if (nextAlarmText != null && mSimOk && !wontFit) { - setAlarmInfoVisible(true); - mAlarmText.setText(nextAlarmText); - } else { - setAlarmInfoVisible(false); + mNextAlarm = mLockPatternUtils.getNextAlarm(); + if (mNextAlarm != null) { + mAlarmIcon = getContext().getResources().getDrawable(R.drawable.ic_lock_idle_alarm); } + updateStatusLines(); } - private void setAlarmInfoVisible(boolean visible) { - final int visibilityFlag = visible ? View.VISIBLE : View.GONE; - mNextAlarmGroup.setVisibility(visibilityFlag); - mAlarmSpacer.setVisibility(visibilityFlag); - } - - + /** {@inheritDoc} */ public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + if (DBG) Log.d(TAG, "onRefreshBatteryInfo(" + showBatteryInfo + ", " + pluggedIn + ")"); mShowingBatteryInfo = showBatteryInfo; mPluggedIn = pluggedIn; mBatteryLevel = batteryLevel; - refreshBatteryDisplay(); + refreshBatteryStringAndIcon(); + updateStatusLines(); } - private void refreshBatteryDisplay() { - if (!mShowingBatteryInfo || !mSimOk) { - mBatteryInfoGroup.setVisibility(View.GONE); - mBatteryInfoSpacer.setVisibility(View.GONE); + private void refreshBatteryStringAndIcon() { + if (!mShowingBatteryInfo) { + mCharging = null; return; } - mBatteryInfoGroup.setVisibility(View.VISIBLE); - mBatteryInfoSpacer.setVisibility(View.VISIBLE); + + if (mChargingIcon == null) { + mChargingIcon = + getContext().getResources().getDrawable(R.drawable.ic_lock_idle_low_battery); + } if (mPluggedIn) { - mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_charging); if (mBatteryLevel >= 100) { - mBatteryInfoText.setText(R.string.lockscreen_charged); + mCharging = getContext().getString(R.string.lockscreen_charged); } else { - mBatteryInfoText.setText( - getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel)); + mCharging = getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel); } } else { - mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_low_battery); - mBatteryInfoText.setText(R.string.lockscreen_low_battery); + mCharging = getContext().getString(R.string.lockscreen_low_battery); } } + /** {@inheritDoc} */ public void onTimeChanged() { refreshTimeAndDateDisplay(); } @@ -298,62 +268,174 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private void refreshTimeAndDateDisplay() { Date now = new Date(); mTime.setText(DateFormat.getTimeFormat(getContext()).format(now)); - mDate.setText(DateFormat.getDateFormat(getContext()).format(now)); + mDate.setText(DateFormat.getMediumDateFormat(getContext()).format(now)); } - public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { - refreshSimOkHeaders(plmn, spn); - refreshAlarmDisplay(); // in case alarm won't fit anymore + private void updateStatusLines() { + if (!mStatus.showStatusLines()) { + 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.setCompoundDrawables(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.setCompoundDrawables(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.setCompoundDrawables(mChargingIcon, null, null, null); + mStatus2.setText(mNextAlarm); + mStatus2.setCompoundDrawables(mAlarmIcon, null, null, null); + } } - private void refreshSimOkHeaders(CharSequence plmn, CharSequence spn) { - final IccCard.State simState = mUpdateMonitor.getSimState(); - if (simState == IccCard.State.READY) { - if (plmn != null && !TextUtils.isEmpty(plmn)) { - mHeaderSimOk1.setVisibility(View.VISIBLE); - mHeaderSimOk1.setText(plmn); - } else { - mHeaderSimOk1.setVisibility(View.GONE); - } - - if (spn != null && !TextUtils.isEmpty(spn)) { - mHeaderSimOk2.setVisibility(View.VISIBLE); - mHeaderSimOk2.setText(spn); - } else { - mHeaderSimOk2.setVisibility(View.GONE); - } - } else if (simState == IccCard.State.PIN_REQUIRED) { - mHeaderSimOk1.setVisibility(View.VISIBLE); - mHeaderSimOk1.setText(R.string.lockscreen_sim_locked_message); - mHeaderSimOk2.setVisibility(View.GONE); - } else if (simState == IccCard.State.ABSENT) { - mHeaderSimOk1.setVisibility(View.VISIBLE); - mHeaderSimOk1.setText(R.string.lockscreen_missing_sim_message_short); - mHeaderSimOk2.setVisibility(View.GONE); - } else if (simState == IccCard.State.NETWORK_LOCKED) { - mHeaderSimOk1.setVisibility(View.VISIBLE); - mHeaderSimOk1.setText(R.string.lockscreen_network_locked_message); - mHeaderSimOk2.setVisibility(View.GONE); - } + /** {@inheritDoc} */ + public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + if (DBG) Log.d(TAG, "onRefreshCarrierInfo(" + plmn + ", " + spn + ")"); + updateLayout(mStatus); } - public void onSimStateChanged(IccCard.State simState) { - mSimOk = isSimOk(simState); - refreshViewsWRTSimOk(); - refreshUnlockIntructions(); + private void putEmergencyBelow(int viewId) { + final RelativeLayout.LayoutParams layoutParams = + (RelativeLayout.LayoutParams) mEmergencyCallButton.getLayoutParams(); + layoutParams.addRule(RelativeLayout.BELOW, viewId); + mEmergencyCallButton.setLayoutParams(layoutParams); } /** - * @return Whether the sim state is ok, meaning we don't need to show - * a special screen with the emergency call button and keep them from - * doing anything else. + * Determine the current status of the lock screen given the sim state and other stuff. */ - private boolean isSimOk(IccCard.State simState) { + private Status getCurrentStatus(IccCard.State simState) { boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned() && simState == IccCard.State.ABSENT); - return !(missingAndNotProvisioned || simState == IccCard.State.PUK_REQUIRED); + if (missingAndNotProvisioned) { + return Status.SimMissingLocked; + } + + switch (simState) { + case ABSENT: + return Status.SimMissing; + case NETWORK_LOCKED: + return Status.SimMissingLocked; + case NOT_READY: + return Status.SimMissing; + case PIN_REQUIRED: + return Status.SimLocked; + case PUK_REQUIRED: + return Status.SimPukLocked; + case READY: + return Status.Normal; + case UNKNOWN: + return Status.SimMissing; + } + return Status.SimMissing; + } + + /** + * Update the layout to match the current status. + */ + private void updateLayout(Status status) { + switch (status) { + case Normal: + // text + mCarrier.setText( + getCarrierString( + mUpdateMonitor.getTelephonyPlmn(), + mUpdateMonitor.getTelephonySpn())); + mScreenLocked.setText(R.string.lockscreen_screen_locked); + + // layout + mScreenLocked.setVisibility(View.VISIBLE); + mRotary.setVisibility(View.VISIBLE); + mEmergencyCallButton.setVisibility(View.GONE); + break; + case NetworkLocked: + // text + mCarrier.setText(R.string.lockscreen_network_locked_message); + mScreenLocked.setText(R.string.lockscreen_instructions_when_pattern_disabled); + + // layout + mScreenLocked.setVisibility(View.VISIBLE); + mRotary.setVisibility(View.VISIBLE); + mEmergencyCallButton.setVisibility(View.GONE); + break; + case SimMissing: + // text + mCarrier.setText(R.string.lockscreen_missing_sim_message_short); + mScreenLocked.setText(R.string.lockscreen_instructions_when_pattern_disabled); + + // layout + mScreenLocked.setVisibility(View.INVISIBLE); + mRotary.setVisibility(View.VISIBLE); + mEmergencyCallButton.setVisibility(View.VISIBLE); + putEmergencyBelow(R.id.divider); + break; + case SimMissingLocked: + // text + mCarrier.setText(R.string.lockscreen_missing_sim_message_short); + mScreenLocked.setText(R.string.lockscreen_missing_sim_instructions); + + // layout + mScreenLocked.setVisibility(View.VISIBLE); + mRotary.setVisibility(View.INVISIBLE); + mEmergencyCallButton.setVisibility(View.VISIBLE); + putEmergencyBelow(R.id.screenLocked); + break; + case SimLocked: + // text + mCarrier.setText(R.string.lockscreen_sim_locked_message); + + // layout + mScreenLocked.setVisibility(View.INVISIBLE); + mRotary.setVisibility(View.VISIBLE); + mEmergencyCallButton.setVisibility(View.GONE); + break; + case SimPukLocked: + // text + mCarrier.setText(R.string.lockscreen_sim_puk_locked_message); + mScreenLocked.setText(R.string.lockscreen_sim_puk_locked_instructions); + + // layout + mScreenLocked.setVisibility(View.VISIBLE); + mRotary.setVisibility(View.INVISIBLE); + mEmergencyCallButton.setVisibility(View.VISIBLE); + putEmergencyBelow(R.id.screenLocked); + break; + } + } + + private CharSequence getCarrierString(CharSequence telephonyPlmn, CharSequence telephonySpn) { + if (telephonyPlmn != null && telephonySpn == null) { + return telephonyPlmn; + } else if (telephonyPlmn != null && telephonySpn != null) { + return telephonyPlmn + "\n" + telephonySpn; + } else if (telephonyPlmn == null && telephonySpn != null) { + return telephonySpn; + } else { + return ""; + } } + public void onSimStateChanged(IccCard.State simState) { + if (DBG) Log.d(TAG, "onSimStateChanged(" + simState + ")"); + mStatus = getCurrentStatus(simState); + updateLayout(mStatus); + updateStatusLines(); + } + + public void onOrientationChange(boolean inPortrait) { } diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index 74e03192c052..00809d720e46 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -58,6 +58,11 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient private final KeyguardUpdateMonitor mUpdateMonitor; private final KeyguardScreenCallback mCallback; + /** + * whether there is a fallback option available when the pattern is forgotten. + */ + private final boolean mEnableFallback; + private boolean mCreatedInPortrait; private ImageView mUnlockIcon; @@ -86,9 +91,6 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient private Button mForgotPatternButton; - private ServiceConnection mServiceConnection; - - enum FooterMode { Normal, ForgotLockPattern, @@ -118,17 +120,22 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient * @param updateMonitor Used to lookup state affecting keyguard. * @param callback Used to notify the manager when we're done, etc. * @param totalFailedAttempts The current number of failed attempts. + * @param enableFallback True if a backup unlock option is available when the user has forgotten + * their pattern (e.g they have a google account so we can show them the account based + * backup option). */ UnlockScreen(Context context, - LockPatternUtils lockPatternUtils, - KeyguardUpdateMonitor updateMonitor, - KeyguardScreenCallback callback, - int totalFailedAttempts) { + LockPatternUtils lockPatternUtils, + KeyguardUpdateMonitor updateMonitor, + KeyguardScreenCallback callback, + int totalFailedAttempts, + boolean enableFallback) { super(context); mLockPatternUtils = lockPatternUtils; mUpdateMonitor = updateMonitor; mCallback = callback; mTotalFailedPatternAttempts = totalFailedAttempts; + mEnableFallback = enableFallback; mFailedPatternAttemptsSinceLastTimeout = totalFailedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; if (mUpdateMonitor.isInPortrait()) { @@ -191,15 +198,6 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient setFocusableInTouchMode(true); } - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - mCallback.goToLockScreen(); - return true; - } - return false; - } - @Override public boolean dispatchTouchEvent(MotionEvent ev) { // as long as the user is entering a pattern (i.e sending a touch @@ -262,10 +260,11 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient // the footer depends on how many total attempts the user has failed if (mCallback.isVerifyUnlockOnly()) { updateFooter(FooterMode.VerifyUnlocked); - } else if (mTotalFailedPatternAttempts < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { - updateFooter(FooterMode.Normal); - } else { + } else if (mEnableFallback && + (mTotalFailedPatternAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { updateFooter(FooterMode.ForgotLockPattern); + } else { + updateFooter(FooterMode.Normal); } } @@ -342,7 +341,11 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); mUnlockIcon.setVisibility(View.VISIBLE); mFailedPatternAttemptsSinceLastTimeout = 0; - updateFooter(FooterMode.ForgotLockPattern); + if (mEnableFallback) { + updateFooter(FooterMode.ForgotLockPattern); + } else { + updateFooter(FooterMode.Normal); + } } }.start(); } -- GitLab From 2862fff6c2bdf45d009b3bec34e60f26059cf2e0 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 15 Sep 2009 22:56:29 -0700 Subject: [PATCH 096/458] Update policy for hiding navigation keys, configuration. Change-Id: Ieeb523cdc05316d34501872d684531142132b402 --- .../policy/impl/PhoneWindowManager.java | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index b664cb405b2e..7178678e7a9c 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -179,6 +179,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mDocked; int mLidOpenRotation; int mDockedRotation; + int mLidKeyboardAccessibility; + int mLidNavigationAccessibility; boolean mScreenOn = false; boolean mOrientationSensorEnabled = false; int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -457,10 +459,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PhoneWindowManager.mBroadcastWakeLock"); mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); - mLidOpenRotation = readRotation(com.android.internal.R.integer.config_lidOpenRotation, - Surface.ROTATION_90); - mDockedRotation = readRotation(com.android.internal.R.integer.config_dockedRotation, - Surface.ROTATION_90); + mLidOpenRotation = readRotation( + com.android.internal.R.integer.config_lidOpenRotation, Surface.ROTATION_90); + mDockedRotation = readRotation( + com.android.internal.R.integer.config_dockedRotation, Surface.ROTATION_90); + mLidKeyboardAccessibility = mContext.getResources().getInteger( + com.android.internal.R.integer.config_lidKeyboardAccessibility); + mLidNavigationAccessibility = mContext.getResources().getInteger( + com.android.internal.R.integer.config_lidNavigationAccessibility); // register for dock events context.registerReceiver(mDockReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT)); } @@ -545,17 +551,32 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private int determineHiddenState(boolean lidOpen, + int mode, int hiddenValue, int visibleValue) { + switch (mode) { + case 1: + return lidOpen ? visibleValue : hiddenValue; + case 2: + return lidOpen ? hiddenValue : visibleValue; + } + return visibleValue; + } + /** {@inheritDoc} */ public void adjustConfigurationLw(Configuration config) { readLidState(); final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen; mPowerManager.setKeyboardVisibility(lidOpen); - config.keyboardHidden = (lidOpen || mHasSoftInput) - ? Configuration.KEYBOARDHIDDEN_NO - : Configuration.KEYBOARDHIDDEN_YES; - config.hardKeyboardHidden = lidOpen - ? Configuration.KEYBOARDHIDDEN_NO - : Configuration.KEYBOARDHIDDEN_YES; + config.hardKeyboardHidden = determineHiddenState(lidOpen, + mLidKeyboardAccessibility, Configuration.HARDKEYBOARDHIDDEN_YES, + Configuration.HARDKEYBOARDHIDDEN_NO); + config.navigationHidden = determineHiddenState(lidOpen, + mLidNavigationAccessibility, Configuration.NAVIGATIONHIDDEN_YES, + Configuration.NAVIGATIONHIDDEN_NO); + config.keyboardHidden = (config.hardKeyboardHidden + == Configuration.HARDKEYBOARDHIDDEN_NO || mHasSoftInput) + ? Configuration.KEYBOARDHIDDEN_NO + : Configuration.KEYBOARDHIDDEN_YES; } public boolean isCheekPressedAgainstScreen(MotionEvent ev) { -- GitLab From 2d1efbde2f4c0336e32557dda953acee02b53b8d Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 16 Sep 2009 12:15:53 -0400 Subject: [PATCH 097/458] Allow specifying separate orientation rotations for car and desk dock. Change-Id: Ic6762d6f2882420bd7d5a13d36057599d51dfc66 Signed-off-by: Mike Lockwood --- .../policy/impl/PhoneWindowManager.java | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 7178678e7a9c..3b948707950f 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -176,9 +176,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { Handler mHandler; boolean mLidOpen; - boolean mDocked; + int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; int mLidOpenRotation; - int mDockedRotation; + int mCarDockRotation; + int mDeskDockRotation; int mLidKeyboardAccessibility; int mLidNavigationAccessibility; boolean mScreenOn = false; @@ -460,9 +461,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { "PhoneWindowManager.mBroadcastWakeLock"); mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); mLidOpenRotation = readRotation( - com.android.internal.R.integer.config_lidOpenRotation, Surface.ROTATION_90); - mDockedRotation = readRotation( - com.android.internal.R.integer.config_dockedRotation, Surface.ROTATION_90); + com.android.internal.R.integer.config_lidOpenRotation); + mCarDockRotation = readRotation( + com.android.internal.R.integer.config_carDockRotation); + mDeskDockRotation = readRotation( + com.android.internal.R.integer.config_deskDockRotation); mLidKeyboardAccessibility = mContext.getResources().getInteger( com.android.internal.R.integer.config_lidKeyboardAccessibility); mLidNavigationAccessibility = mContext.getResources().getInteger( @@ -471,7 +474,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { context.registerReceiver(mDockReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT)); } - private int readRotation(int resID, int defaultRotation) { + private int readRotation(int resID) { try { int rotation = mContext.getResources().getInteger(resID); switch (rotation) { @@ -483,12 +486,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { return Surface.ROTATION_180; case 270: return Surface.ROTATION_270; - default: - return defaultRotation; } } catch (Resources.NotFoundException e) { - return defaultRotation; + // fall through } + return -1; } /** {@inheritDoc} */ @@ -1685,9 +1687,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { BroadcastReceiver mDockReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { - int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, + mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); - mDocked = (state != Intent.EXTRA_DOCK_STATE_UNDOCKED); updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); } }; @@ -1808,8 +1809,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { //or case.unspecified if (mLidOpen) { return mLidOpenRotation; - } else if (mDocked) { - return mDockedRotation; + } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) { + return mCarDockRotation; + } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) { + return mDeskDockRotation; } else { if (useSensorForOrientationLp(orientation)) { // If the user has enabled auto rotation by default, do it. @@ -1881,8 +1884,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { int rotation = Surface.ROTATION_0; if (mLidOpen) { rotation = mLidOpenRotation; - } else if (mDocked) { - rotation = mDockedRotation; + } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) { + rotation = mCarDockRotation; + } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) { + rotation = mDeskDockRotation; } //if lid is closed orientation will be portrait try { -- GitLab From bf019065f0ccf7e85cfbbfa5f25b200bf326e0eb Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Thu, 17 Sep 2009 03:00:15 -0700 Subject: [PATCH 098/458] First pass at pattern lock screen that includes date / time and carrier info (andoid.policy portion) - code to update carrier / date and time --- .../internal/policy/impl/LockScreen.java | 2 +- .../internal/policy/impl/UnlockScreen.java | 69 +++++++++++++++++-- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 99aef334f947..3eac21671440 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -416,7 +416,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } } - private CharSequence getCarrierString(CharSequence telephonyPlmn, CharSequence telephonySpn) { + static CharSequence getCarrierString(CharSequence telephonyPlmn, CharSequence telephonySpn) { if (telephonyPlmn != null && telephonySpn == null) { return telephonyPlmn; } else if (telephonyPlmn != null && telephonySpn != null) { diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index 00809d720e46..db5afc8e843b 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -28,19 +28,22 @@ import android.view.MotionEvent; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; +import android.text.format.DateFormat; import com.android.internal.R; +import com.android.internal.telephony.IccCard; import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; import java.util.List; +import java.util.Date; /** * This is the screen that shows the 9 circle unlock widget and instructs * the user how to unlock their device, or make an emergency call. */ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient - implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback { + implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback { private static final String TAG = "UnlockScreen"; @@ -65,7 +68,11 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient private boolean mCreatedInPortrait; - private ImageView mUnlockIcon; + private TextView mCarrier; + private TextView mCenterDot; + private TextView mDate; + private TextView mTime; + private TextView mUnlockHeader; private LockPatternView mLockPatternView; @@ -144,7 +151,14 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_landscape, this, true); } - mUnlockIcon = (ImageView) findViewById(R.id.unlockLockIcon); + mCarrier = (TextView) findViewById(R.id.carrier); + mCenterDot = (TextView) findViewById(R.id.centerDot); + mDate = (TextView) findViewById(R.id.date); + mTime = (TextView) findViewById(R.id.time); + + mCarrier.setText("Verizon Wireless"); + mCenterDot.setText("|"); + refreshTimeAndDateDisplay(); mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern); mUnlockHeader = (TextView) findViewById(R.id.headerText); @@ -194,10 +208,25 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient updateFooter(FooterMode.Normal); mCreatedInPortrait = updateMonitor.isInPortrait(); + updateMonitor.registerInfoCallback(this); + updateMonitor.registerSimStateCallback(this); updateMonitor.registerConfigurationChangeCallback(this); setFocusableInTouchMode(true); + + // until we get an update... + mCarrier.setText( + LockScreen.getCarrierString( + mUpdateMonitor.getTelephonyPlmn(), + mUpdateMonitor.getTelephonySpn())); } + private void refreshTimeAndDateDisplay() { + Date now = new Date(); + mTime.setText(DateFormat.getTimeFormat(getContext()).format(now)); + mDate.setText(DateFormat.getMediumDateFormat(getContext()).format(now)); + } + + @Override public boolean dispatchTouchEvent(MotionEvent ev) { // as long as the user is entering a pattern (i.e sending a touch @@ -213,6 +242,32 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient return result; } + + // ---------- InfoCallback + + /** {@inheritDoc} */ + public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + } + + /** {@inheritDoc} */ + public void onTimeChanged() { + refreshTimeAndDateDisplay(); + } + + /** {@inheritDoc} */ + public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + mCarrier.setText(LockScreen.getCarrierString(plmn, spn)); + } + + // ---------- SimStateCallback + + /** {@inheritDoc} */ + public void onSimStateChanged(IccCard.State simState) { + } + + + + /** {@inheritDoc} */ public void onOrientationChange(boolean inPortrait) { if (inPortrait != mCreatedInPortrait) { @@ -240,7 +295,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient public void onResume() { // reset header mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); - mUnlockIcon.setVisibility(View.VISIBLE); + // TODO mUnlockIcon.setVisibility(View.VISIBLE); // reset lock pattern mLockPatternView.enableInput(); @@ -296,7 +351,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient if (mLockPatternUtils.checkPattern(pattern)) { mLockPatternView .setDisplayMode(LockPatternView.DisplayMode.Correct); - mUnlockIcon.setVisibility(View.GONE); + // TODO mUnlockIcon.setVisibility(View.GONE); mUnlockHeader.setText(""); mCallback.keyguardDone(true); } else { @@ -312,7 +367,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient handleAttemptLockout(deadline); return; } - mUnlockIcon.setVisibility(View.VISIBLE); + // TODO mUnlockIcon.setVisibility(View.VISIBLE); mUnlockHeader.setText(R.string.lockscreen_pattern_wrong); mLockPatternView.postDelayed( mCancelPatternRunnable, @@ -339,7 +394,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient public void onFinish() { mLockPatternView.setEnabled(true); mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); - mUnlockIcon.setVisibility(View.VISIBLE); + // TODO mUnlockIcon.setVisibility(View.VISIBLE); mFailedPatternAttemptsSinceLastTimeout = 0; if (mEnableFallback) { updateFooter(FooterMode.ForgotLockPattern); -- GitLab From cfe3e90b301e3b1543f4b230b05372be16289f59 Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Thu, 17 Sep 2009 03:46:54 -0700 Subject: [PATCH 099/458] Minor tweaks to address code review. --- policy/com/android/internal/policy/impl/UnlockScreen.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index db5afc8e843b..1d5f22006787 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -43,7 +43,8 @@ import java.util.Date; * the user how to unlock their device, or make an emergency call. */ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient - implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback { + implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback, + KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback { private static final String TAG = "UnlockScreen"; @@ -156,7 +157,6 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mDate = (TextView) findViewById(R.id.date); mTime = (TextView) findViewById(R.id.time); - mCarrier.setText("Verizon Wireless"); mCenterDot.setText("|"); refreshTimeAndDateDisplay(); @@ -217,7 +217,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mCarrier.setText( LockScreen.getCarrierString( mUpdateMonitor.getTelephonyPlmn(), - mUpdateMonitor.getTelephonySpn())); + mUpdateMonitor.getTelephonySpn())); } private void refreshTimeAndDateDisplay() { -- GitLab From 016e39780b857c09ba689ec820a04c7930bd8a7f Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Thu, 17 Sep 2009 11:45:06 -0400 Subject: [PATCH 100/458] Revert "Don't activate keyguard if screen is turned off while proximity sensor is active." This reverts commit 4daf9485eca9bab9591bef83dd117cbde1e8beec. --- .../android/internal/policy/impl/KeyguardViewMediator.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 2daab27f2f8b..b1ce74679477 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -273,9 +273,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, /** * Called to let us know the screen was turned off. - * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER}, - * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or - * {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROXIMITY_SENSOR}. + * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER} or + * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}. */ public void onScreenTurnedOff(int why) { synchronized (this) { @@ -306,7 +305,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, sender); if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = " + mDelayedShowingSequence); - } else if (why != WindowManagerPolicy.OFF_BECAUSE_OF_PROXIMITY_SENSOR) { + } else { doKeyguard(); } } -- GitLab From 871be31f54c9a87a661b099c59141dad33a0192c Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Thu, 17 Sep 2009 17:50:37 -0700 Subject: [PATCH 101/458] Show a message about silent mode being toggled after user rotates widget to left. This is based on feedback that users had a hard time knowing what happened when they toggle silent mode using the lock screen. --- .../internal/policy/impl/LockScreen.java | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 3eac21671440..2226326c994b 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -213,11 +213,47 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mRotary.setRightHandleResource(mSilentMode ? R.drawable.ic_jog_dial_turn_ring_vol_on : R.drawable.ic_jog_dial_turn_ring_vol_off); + String message = mSilentMode ? + getContext().getString(R.string.global_action_silent_mode_on_status) : + getContext().getString(R.string.global_action_silent_mode_off_status); + toastMessage(mScreenLocked, message); mCallback.pokeWakelock(); } return false; } + /** + * Displays a message in a text view and then removes it. + * @param textView The text view. + * @param text The text. + */ + private void toastMessage(final TextView textView, final String text) { + if (mPendingR1 != null) { + textView.removeCallbacks(mPendingR1); + mPendingR1 = null; + } + if (mPendingR2 != null) { + textView.removeCallbacks(mPendingR2); + mPendingR2 = null; + } + + mPendingR1 = new Runnable() { + public void run() { + textView.setText(text); + } + }; + textView.postDelayed(mPendingR1, 400); + mPendingR2 = new Runnable() { + public void run() { + textView.setText(""); + } + }; + textView.postDelayed(mPendingR2, 2000); + } + private Runnable mPendingR1; + private Runnable mPendingR2; + + private void refreshAlarmDisplay() { mNextAlarm = mLockPatternUtils.getNextAlarm(); if (mNextAlarm != null) { @@ -354,7 +390,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM getCarrierString( mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn())); - mScreenLocked.setText(R.string.lockscreen_screen_locked); +// mScreenLocked.setText(R.string.lockscreen_screen_locked); // layout mScreenLocked.setVisibility(View.VISIBLE); -- GitLab From abe0da0a79a2312c347e16095488e192bb615037 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Fri, 18 Sep 2009 01:55:39 -0700 Subject: [PATCH 102/458] Policy changes for lock screen on live wallpaper. Change-Id: Ib875ef839b7727194461b13684b77bf38ad3c52e --- .../internal/policy/impl/KeyguardViewManager.java | 5 +++-- .../internal/policy/impl/LockPatternKeyguardView.java | 8 +++++--- .../internal/policy/impl/PhoneWindowManager.java | 4 ++++ .../internal/policy/impl/RecentApplicationsDialog.java | 10 +++------- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index 297d62f4a4bf..f05c2fbb8f3e 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -101,6 +101,7 @@ public class KeyguardViewManager implements KeyguardWindowController { final int stretch = ViewGroup.LayoutParams.FILL_PARENT; int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN + | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ; if (!mNeedsInput) { @@ -108,9 +109,9 @@ public class KeyguardViewManager implements KeyguardWindowController { } WindowManager.LayoutParams lp = new WindowManager.LayoutParams( stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD, - flags, PixelFormat.OPAQUE); + flags, PixelFormat.TRANSLUCENT); lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; - lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen; + //lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen; lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; lp.setTitle("Keyguard"); mWindowLayoutParams = lp; diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index f961f47f9ce9..7a81c056b732 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -285,9 +285,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase { setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); // wall paper background - final BitmapDrawable drawable = (BitmapDrawable) context.getWallpaper(); - setBackgroundDrawable( - new FastBitmapDrawable(drawable.getBitmap())); + if (false) { + final BitmapDrawable drawable = (BitmapDrawable) context.getWallpaper(); + setBackgroundDrawable( + new FastBitmapDrawable(drawable.getBitmap())); + } // create both the lock and unlock screen so they are quickly available // when the screen turns on diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 3b948707950f..523d3b47c34e 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -650,6 +650,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } + public int getMaxWallpaperLayer() { + return STATUS_BAR_LAYER; + } + /** {@inheritDoc} */ public View addStartingWindow(IBinder appToken, String packageName, int theme, CharSequence nonLocalizedLabel, diff --git a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java index a680cc83b3d6..4c46be5bdfc5 100644 --- a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java +++ b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java @@ -20,7 +20,6 @@ import android.app.ActivityManager; import android.app.Dialog; import android.app.StatusBarManager; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -30,13 +29,10 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.view.View.OnClickListener; -import android.widget.ImageView; import android.widget.TextView; import java.util.List; @@ -59,7 +55,7 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener private int mIconSize; public RecentApplicationsDialog(Context context) { - super(context); + super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications); final Resources resources = context.getResources(); mIconSize = (int) resources.getDimension(android.R.dimen.app_icon_size); @@ -84,8 +80,8 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener Window theWindow = getWindow(); theWindow.requestFeature(Window.FEATURE_NO_TITLE); theWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); - theWindow.setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + theWindow.setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND, + WindowManager.LayoutParams.FLAG_DIM_BEHIND); theWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); theWindow.setTitle("Recents"); -- GitLab From ec3fc0a6415319a5f4f292b8f3d95eb400b33fbc Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Fri, 18 Sep 2009 12:05:51 -0700 Subject: [PATCH 103/458] Tweak the lock screen date format to be like "Fri, Sep 18, 2009". --- .../internal/policy/impl/LockScreen.java | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 2226326c994b..297762256091 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -33,6 +33,7 @@ import android.media.AudioManager; import com.android.internal.telephony.IccCard; import java.util.Date; +import java.text.SimpleDateFormat; /** * The screen within {@link LockPatternKeyguardView} that shows general @@ -76,7 +77,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private Drawable mChargingIcon = null; private boolean mSilentMode; - private AudioManager mAudioManager; + private AudioManager mAudioManager; + private java.text.DateFormat mDateFormat; + private java.text.DateFormat mTimeFormat; /** * The status of this lock screen. @@ -177,6 +180,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM refreshBatteryStringAndIcon(); refreshAlarmDisplay(); + + mTimeFormat = DateFormat.getTimeFormat(getContext()); + mDateFormat = getLockScreenDateFormat(); refreshTimeAndDateDisplay(); updateStatusLines(); @@ -303,8 +309,29 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private void refreshTimeAndDateDisplay() { Date now = new Date(); - mTime.setText(DateFormat.getTimeFormat(getContext()).format(now)); - mDate.setText(DateFormat.getMediumDateFormat(getContext()).format(now)); + mTime.setText(mTimeFormat.format(now)); + mDate.setText(mDateFormat.format(now)); + } + + /** + * @return A localized format like "Fri, Sep 18, 2009" + */ + private java.text.DateFormat getLockScreenDateFormat() { + SimpleDateFormat adjusted = null; + try { + // this call gives us the localized order + final SimpleDateFormat dateFormat = (SimpleDateFormat) + java.text.DateFormat.getDateInstance(java.text.DateFormat.FULL); + adjusted = new SimpleDateFormat(dateFormat.toPattern() + .replace("MMMM", "MMM") // we want "Sep", not "September" + .replace("EEEE", "EEE")); // we want "Fri", no "Friday" + } catch (ClassCastException e) { + // in case the library implementation changes and this throws a class cast exception + // or anything else that is funky + Log.e("LockScreen", "couldn't finnagle our custom date format :(", e); + return java.text.DateFormat.getDateInstance(java.text.DateFormat.MEDIUM); + } + return adjusted; } private void updateStatusLines() { -- GitLab From f54c8f9dd8d124a9f0b55d7cf657a9905395e3bf Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Sat, 19 Sep 2009 14:03:57 -0700 Subject: [PATCH 104/458] Add ability to keep screen on while docked. Change-Id: I11f22e92e85d0fb384c70b614d0a55633f74902e --- .../policy/impl/PhoneWindowManager.java | 58 ++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 523d3b47c34e..d6f083b322f5 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -21,7 +21,6 @@ import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.IStatusBar; import android.content.BroadcastReceiver; -import android.content.ContentQueryMap; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -32,6 +31,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Rect; +import android.os.BatteryManager; import android.os.Handler; import android.os.IBinder; import android.os.LocalPowerManager; @@ -176,10 +176,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { Handler mHandler; boolean mLidOpen; + boolean mPlugged; int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; int mLidOpenRotation; int mCarDockRotation; int mDeskDockRotation; + boolean mCarDockKeepsScreenOn; + boolean mDeskDockKeepsScreenOn; int mLidKeyboardAccessibility; int mLidNavigationAccessibility; boolean mScreenOn = false; @@ -232,6 +235,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { ShortcutManager mShortcutManager; PowerManager.WakeLock mBroadcastWakeLock; + PowerManager.WakeLock mDockWakeLock; class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler) { @@ -459,6 +463,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PhoneWindowManager.mBroadcastWakeLock"); + mDockWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, + "PhoneWindowManager.mDockWakeLock"); + mDockWakeLock.setReferenceCounted(false); mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); mLidOpenRotation = readRotation( com.android.internal.R.integer.config_lidOpenRotation); @@ -466,10 +473,25 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.integer.config_carDockRotation); mDeskDockRotation = readRotation( com.android.internal.R.integer.config_deskDockRotation); + mCarDockKeepsScreenOn = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_carDockKeepsScreenOn); + mDeskDockKeepsScreenOn = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_deskDockKeepsScreenOn); mLidKeyboardAccessibility = mContext.getResources().getInteger( com.android.internal.R.integer.config_lidKeyboardAccessibility); mLidNavigationAccessibility = mContext.getResources().getInteger( com.android.internal.R.integer.config_lidNavigationAccessibility); + // register for battery events + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_POWER_CONNECTED); + intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED); + context.registerReceiver(mPowerReceiver, intentFilter); + Intent powerIntent = context.registerReceiver(null, + new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + mPlugged = false; + if (powerIntent != null) { + mPlugged = powerIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; + } // register for dock events context.registerReceiver(mDockReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT)); } @@ -1689,11 +1711,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; + BroadcastReceiver mPowerReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())) { + mPlugged = true; + } else if (Intent.ACTION_POWER_DISCONNECTED.equals(intent.getAction())) { + mPlugged = false; + } + updateKeepScreenOn(); + } + }; + BroadcastReceiver mDockReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); + updateKeepScreenOn(); } }; @@ -1883,6 +1917,28 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); } + void updateKeepScreenOn() { + if (mPlugged) { + if (mDockState == Intent.EXTRA_DOCK_STATE_CAR + && mCarDockKeepsScreenOn) { + if (!mDockWakeLock.isHeld()) { + mDockWakeLock.acquire(); + } + return; + } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK + && mDeskDockKeepsScreenOn) { + if (!mDockWakeLock.isHeld()) { + mDockWakeLock.acquire(); + } + return; + } + } + + if (mDockWakeLock.isHeld()) { + mDockWakeLock.release(); + } + } + void updateRotation(int animFlags) { mPowerManager.setKeyboardVisibility(mLidOpen); int rotation = Surface.ROTATION_0; -- GitLab From e9867d286233ec4d49c3db2a3d85e6784dfb4bf1 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Sun, 20 Sep 2009 01:59:02 -0400 Subject: [PATCH 105/458] Support for forcing accelerometer based orientation management when docked. Change-Id: I5436a7191263a0a2a5ca8108da2f7c094c49b88a Signed-off-by: Mike Lockwood --- .../policy/impl/PhoneWindowManager.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index d6f083b322f5..52b6796e44ad 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -183,6 +183,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mDeskDockRotation; boolean mCarDockKeepsScreenOn; boolean mDeskDockKeepsScreenOn; + boolean mCarDockEnablesAccelerometer; + boolean mDeskDockEnablesAccelerometer; int mLidKeyboardAccessibility; int mLidNavigationAccessibility; boolean mScreenOn = false; @@ -317,8 +319,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { return true; } - if (mAccelerometerDefault != 0 && ( - appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || + if ((mAccelerometerDefault != 0 || + (mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR) || + (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) + && (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { return true; } @@ -336,6 +340,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // orientation, then we need to turn the sensor or. return true; } + if ((mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR) || + (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) { + // enable accelerometer if we are docked in a dock that enables accelerometer + // orientation management, + return true; + } if (mAccelerometerDefault == 0) { // If the setting for using the sensor by default is enabled, then // we will always leave it on. Note that the user could go to @@ -477,6 +487,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.bool.config_carDockKeepsScreenOn); mDeskDockKeepsScreenOn = mContext.getResources().getBoolean( com.android.internal.R.bool.config_deskDockKeepsScreenOn); + mCarDockEnablesAccelerometer = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_carDockEnablesAccelerometer); + mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_deskDockEnablesAccelerometer); mLidKeyboardAccessibility = mContext.getResources().getInteger( com.android.internal.R.integer.config_lidKeyboardAccessibility); mLidNavigationAccessibility = mContext.getResources().getInteger( @@ -1728,6 +1742,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Intent.EXTRA_DOCK_STATE_UNDOCKED); updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); updateKeepScreenOn(); + updateOrientationListenerLp(); } }; -- GitLab From 2a138a4e7e2391afa879ee45c8c593b4e61c66cd Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Sun, 20 Sep 2009 09:53:35 -0700 Subject: [PATCH 106/458] Show silent mode icon associated with current state instead of what it will be. Also: - fix bug where icons weren't showing for charging, next alarm - tweak layout --- .../internal/policy/impl/LockScreen.java | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 297762256091..45fb08b1b0d2 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -195,7 +195,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mRotary.setOnDialTriggerListener(this); mRotary.setLeftHandleResource(R.drawable.ic_jog_dial_unlock); - mRotary.setRightHandleResource(R.drawable.ic_jog_dial_turn_ring_vol_off); + mRotary.setRightHandleResource(mSilentMode ? + R.drawable.ic_jog_dial_turn_ring_vol_off : + R.drawable.ic_jog_dial_turn_ring_vol_on); } @Override @@ -207,33 +209,36 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } /** {@inheritDoc} */ - public boolean onDialTrigger(View v, int whichHandle) { + public void onDialTrigger(View v, int whichHandle) { if (whichHandle == RotarySelector.OnDialTriggerListener.LEFT_HANDLE) { mCallback.goToUnlockScreen(); - return mStatus == Status.Normal; // only want to freeze drawing when actually unlocking } else if (whichHandle == RotarySelector.OnDialTriggerListener.RIGHT_HANDLE) { // toggle silent mode mSilentMode = !mSilentMode; mAudioManager.setRingerMode(mSilentMode ? AudioManager.RINGER_MODE_SILENT : AudioManager.RINGER_MODE_NORMAL); - mRotary.setRightHandleResource(mSilentMode ? - R.drawable.ic_jog_dial_turn_ring_vol_on : - R.drawable.ic_jog_dial_turn_ring_vol_off); + final int handleIcon = mSilentMode ? + R.drawable.ic_jog_dial_turn_ring_vol_off : + R.drawable.ic_jog_dial_turn_ring_vol_on; + final int toastIcon = mSilentMode ? + R.drawable.ic_lock_ringer_off : + R.drawable.ic_lock_ringer_on; + mRotary.setRightHandleResource(handleIcon); String message = mSilentMode ? getContext().getString(R.string.global_action_silent_mode_on_status) : getContext().getString(R.string.global_action_silent_mode_off_status); - toastMessage(mScreenLocked, message); + toastMessage(mScreenLocked, message, toastIcon); mCallback.pokeWakelock(); } - return false; } /** * Displays a message in a text view and then removes it. * @param textView The text view. * @param text The text. + * @param iconResourceId The left hand icon. */ - private void toastMessage(final TextView textView, final String text) { + private void toastMessage(final TextView textView, final String text, final int iconResourceId) { if (mPendingR1 != null) { textView.removeCallbacks(mPendingR1); mPendingR1 = null; @@ -246,12 +251,15 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mPendingR1 = new Runnable() { public void run() { textView.setText(text); + textView.setCompoundDrawablesWithIntrinsicBounds(iconResourceId, 0, 0, 0); + textView.setCompoundDrawablePadding(4); } }; textView.postDelayed(mPendingR1, 400); mPendingR2 = new Runnable() { public void run() { textView.setText(""); + textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); } }; textView.postDelayed(mPendingR2, 2000); @@ -288,7 +296,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM if (mChargingIcon == null) { mChargingIcon = - getContext().getResources().getDrawable(R.drawable.ic_lock_idle_low_battery); + getContext().getResources().getDrawable(R.drawable.ic_lock_idle_charging); } if (mPluggedIn) { @@ -344,23 +352,23 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mStatus2.setVisibility(View.INVISIBLE); mStatus1.setText(mCharging); - mStatus1.setCompoundDrawables(mChargingIcon, null, null, null); + 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.setCompoundDrawables(mAlarmIcon, null, null, null); + 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.setCompoundDrawables(mChargingIcon, null, null, null); + mStatus1.setCompoundDrawablesWithIntrinsicBounds(mChargingIcon, null, null, null); mStatus2.setText(mNextAlarm); - mStatus2.setCompoundDrawables(mAlarmIcon, null, null, null); + mStatus2.setCompoundDrawablesWithIntrinsicBounds(mAlarmIcon, null, null, null); } } -- GitLab From 7b8a5cf16a6eb9a7fab54838ebf4880d59ce367d Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Sun, 20 Sep 2009 14:01:09 -0700 Subject: [PATCH 107/458] Don't show battery info when unplugging (fixes bug 2128323). --- policy/com/android/internal/policy/impl/LockScreen.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 45fb08b1b0d2..afde89503993 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -343,7 +343,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } private void updateStatusLines() { - if (!mStatus.showStatusLines()) { + if (!mStatus.showStatusLines() + || (mCharging == null && mNextAlarm == null)) { mStatus1.setVisibility(View.INVISIBLE); mStatus2.setVisibility(View.INVISIBLE); } else if (mCharging != null && mNextAlarm == null) { -- GitLab From 36a64148b4efc246384e2010e5d0a37f16dbbd01 Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Sun, 20 Sep 2009 15:09:42 -0700 Subject: [PATCH 108/458] Show silent mode toast immediately, and for 3.5 seconds instead of 2. --- policy/com/android/internal/policy/impl/LockScreen.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index afde89503993..8ed035f65abe 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -255,18 +255,18 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM textView.setCompoundDrawablePadding(4); } }; - textView.postDelayed(mPendingR1, 400); + textView.postDelayed(mPendingR1, 0); mPendingR2 = new Runnable() { public void run() { textView.setText(""); textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); } }; - textView.postDelayed(mPendingR2, 2000); + textView.postDelayed(mPendingR2, 3500); } private Runnable mPendingR1; private Runnable mPendingR2; - + private void refreshAlarmDisplay() { mNextAlarm = mLockPatternUtils.getNextAlarm(); -- GitLab From fe1fee5545fee91ca0d267067f6ddf2887a7bdd3 Mon Sep 17 00:00:00 2001 From: Jinghui Guo Date: Thu, 17 Sep 2009 14:05:27 -0500 Subject: [PATCH 109/458] Handle Emergency Callback Mode and Airplane Mode interactions For UI interface consistency with airplane mode change from setting menu, an ECM exit dialog should also be shown up when user wants to change airplane mode in ECM after long key pressing power key. Then based on the user's choice to change airplane mode. i.e. press Yes to exit ECM and turn on airplane mode or press No to keep ECM and do not change airplane mode. Change-Id: I0fe7e5cdeec0f33852615b491b75f65a46257590 --- .../internal/policy/impl/GlobalActions.java | 58 +++++++++++++++---- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/policy/com/android/internal/policy/impl/GlobalActions.java b/policy/com/android/internal/policy/impl/GlobalActions.java index 377ff7828e75..7e15e647567a 100644 --- a/policy/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/com/android/internal/policy/impl/GlobalActions.java @@ -16,6 +16,7 @@ package com.android.internal.policy.impl; +import android.app.Activity; import android.app.AlertDialog; import android.app.StatusBarManager; import android.content.BroadcastReceiver; @@ -26,6 +27,7 @@ import android.content.IntentFilter; import android.media.AudioManager; import android.os.Handler; import android.os.Message; +import android.os.SystemProperties; import android.provider.Settings; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; @@ -40,6 +42,8 @@ import android.widget.ImageView; import android.widget.TextView; import com.android.internal.R; import com.android.internal.app.ShutdownThread; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.TelephonyProperties; import com.google.android.collect.Lists; import java.util.ArrayList; @@ -69,6 +73,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private boolean mKeyguardShowing = false; private boolean mDeviceProvisioned = false; private ToggleAction.State mAirplaneState = ToggleAction.State.Off; + private boolean mIsWaitingForEcmExit = false; /** * @param context everything needs a context :( @@ -81,6 +86,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); context.registerReceiver(mBroadcastReceiver, filter); // get notified of phone state changes @@ -141,20 +147,27 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac R.string.global_actions_airplane_mode_off_status) { void onToggle(boolean on) { - // Change the system setting - Settings.System.putInt( - mContext.getContentResolver(), - Settings.System.AIRPLANE_MODE_ON, - on ? 1 : 0); - Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - intent.putExtra("state", on); - mContext.sendBroadcast(intent); + if (Boolean.parseBoolean( + SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) { + mIsWaitingForEcmExit = true; + // Launch ECM exit dialog + Intent ecmDialogIntent = + new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null); + ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(ecmDialogIntent); + } else { + changeAirplaneModeSystemSetting(on); + } } @Override protected void changeStateFromPress(boolean buttonOn) { - mState = buttonOn ? State.TurningOn : State.TurningOff; - mAirplaneState = mState; + // In ECM mode airplane state cannot be changed + if (!(Boolean.parseBoolean( + SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) { + mState = buttonOn ? State.TurningOn : State.TurningOff; + mAirplaneState = mState; + } } public boolean showDuringKeyguard() { @@ -201,7 +214,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac final AlertDialog dialog = ab.create(); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); dialog.setOnDismissListener(this); @@ -218,7 +231,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac if (mKeyguardShowing) { mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); } else { - mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); + mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); } } @@ -490,6 +503,14 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) { mHandler.sendEmptyMessage(MESSAGE_DISMISS); } + } else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) { + // Airplane mode can be changed after ECM exits if airplane toggle button + // is pressed during ECM mode + if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) && + mIsWaitingForEcmExit) { + mIsWaitingForEcmExit = false; + changeAirplaneModeSystemSetting(true); + } } } }; @@ -514,4 +535,17 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } } }; + + /** + * Change the airplane mode system setting + */ + private void changeAirplaneModeSystemSetting(boolean on) { + Settings.System.putInt( + mContext.getContentResolver(), + Settings.System.AIRPLANE_MODE_ON, + on ? 1 : 0); + Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.putExtra("state", on); + mContext.sendBroadcast(intent); + } } -- GitLab From cbc51607ac0c397cbf0886f8a28b1a782b482b13 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Mon, 21 Sep 2009 13:40:31 -0400 Subject: [PATCH 110/458] Dock event overrides SCREEN_ORIENTATION_NOSENSOR so Home will rotate in the car dock. Change-Id: Id768332d846d85f3d37a36bdf41a70cbaceb5332 Signed-off-by: Mike Lockwood --- policy/com/android/internal/policy/impl/PhoneWindowManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 52b6796e44ad..4d02a9df7757 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -323,6 +323,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { (mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR) || (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) && (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || + // dock overrides SCREEN_ORIENTATION_NOSENSOR + appOrientation == ActivityInfo. SCREEN_ORIENTATION_NOSENSOR || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { return true; } -- GitLab From b446e9767a99b8b3ae4e91a9fd797beb70bf99df Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Sun, 20 Sep 2009 15:23:25 -0700 Subject: [PATCH 111/458] Improvements to lock screen management: - The window flag to hide the lock screen will now allow you to press home, and automatically dismiss the lock screen if it is not needed for security. - When opening the lid, if the lock screen will be shown, try to avoid turning on the screen until it is ready. There is actually still some problem with this. Change-Id: I51d769b8e6cff7b439b1ffea927c0a01376427b1 --- .../policy/impl/KeyguardViewMediator.java | 47 ++++++++++--------- .../policy/impl/PhoneWindowManager.java | 27 ++++++++--- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index b1ce74679477..682ea9f3102d 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -84,7 +84,7 @@ import android.view.WindowManagerPolicy; * thread of the keyguard. */ public class KeyguardViewMediator implements KeyguardViewCallback, - KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.SimStateCallback { + KeyguardUpdateMonitor.SimStateCallback { private final static boolean DEBUG = false && Config.LOGD; private final static boolean DBG_WAKE = DEBUG || true; @@ -104,6 +104,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private static final int WAKE_WHEN_READY = 8; private static final int KEYGUARD_DONE = 9; private static final int KEYGUARD_DONE_DRAWING = 10; + private static final int HIDE_KEYGUARD = 11; /** * The default amount of time we stay awake (used for all key input) @@ -245,7 +246,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mUpdateMonitor = new KeyguardUpdateMonitor(context); - mUpdateMonitor.registerConfigurationChangeCallback(this); mUpdateMonitor.registerSimStateCallback(this); mKeyguardViewProperties = @@ -434,6 +434,21 @@ public class KeyguardViewMediator implements KeyguardViewCallback, return mShowing || mNeedToReshowWhenReenabled || !mUpdateMonitor.isDeviceProvisioned(); } + /** + * Returns true if the change is resulting in the keyguard beign dismissed, + * meaning the screen can turn on immediately. Otherwise returns false. + */ + public boolean doLidChangeTq(boolean isLidOpen) { + mKeyboardOpen = isLidOpen; + + if (mUpdateMonitor.isKeyguardBypassEnabled() && mKeyboardOpen + && !mKeyguardViewProperties.isSecure() && mKeyguardViewManager.isShowing()) { + if (DEBUG) Log.d(TAG, "bypassing keyguard on sliding open of keyboard with non-secure keyguard"); + mHandler.sendEmptyMessage(HIDE_KEYGUARD); + return true; + } + return false; + } /** * Enable the keyguard if the settings are appropriate. @@ -558,26 +573,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mHandler.sendMessage(msg); } - /** - * {@link KeyguardUpdateMonitor} callbacks. - */ - - /** {@inheritDoc} */ - public void onOrientationChange(boolean inPortrait) { - - } - - /** {@inheritDoc} */ - public void onKeyboardChange(boolean isKeyboardOpen) { - mKeyboardOpen = isKeyboardOpen; - - if (mUpdateMonitor.isKeyguardBypassEnabled() && mKeyboardOpen - && !mKeyguardViewProperties.isSecure() && mKeyguardViewManager.isShowing()) { - if (DEBUG) Log.d(TAG, "bypassing keyguard on sliding open of keyboard with non-secure keyguard"); - keyguardDone(true); - } - } - /** {@inheritDoc} */ public void onSimStateChanged(IccCard.State simState) { if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState); @@ -615,6 +610,10 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } } + public boolean isSecure() { + return mKeyguardViewProperties.isSecure(); + } + private BroadcastReceiver mBroadCastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -793,6 +792,10 @@ public class KeyguardViewMediator implements KeyguardViewCallback, return; case KEYGUARD_DONE_DRAWING: handleKeyguardDoneDrawing(); + return; + case HIDE_KEYGUARD: + keyguardDone(true); + return; } } }; diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 4d02a9df7757..41d76e8b2899 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1050,9 +1050,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { * given the situation with the keyguard. */ void launchHomeFromHotKey() { - if (mKeyguardMediator.isShowing()) { + if (!mHideKeyguard && mKeyguardMediator.isShowing()) { // don't launch home if keyguard showing - } else if (mKeyguardMediator.isInputRestricted()) { + } else if (!mHideKeyguard && mKeyguardMediator.isInputRestricted()) { // when in keyguard restricted mode, must first verify unlock // before launching home mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() { @@ -1370,6 +1370,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (localLOGV) Log.i(TAG, "finishLayoutLw::mHideKeyguard="+mHideKeyguard); if (mHideKeyguard) { changed |= mKeyguard.hideLw(true); + if (!mKeyguardMediator.isShowing()) { + mHandler.post(new Runnable() { + public void run() { + mKeyguardMediator.keyguardDone(true); + } + }); + } } else { changed |= mKeyguard.showLw(true); } @@ -1410,12 +1417,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (event.keycode == RawInputEvent.SW_LID) { // lid changed state mLidOpen = event.value == 0; + boolean awakeNow = mKeyguardMediator.doLidChangeTq(mLidOpen); updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); - if (keyguardIsShowingTq()) { + if (awakeNow) { + // If the lid opening and we don't have to keep the + // keyguard up, then we can turn on the screen + // immediately. + mKeyguardMediator.pokeWakelock(); + } else if (keyguardIsShowingTq()) { if (mLidOpen) { - // only do this if it's opening -- closing the device shouldn't turn it - // off, but it also shouldn't turn it on. - mKeyguardMediator.pokeWakelock(); + // If we are opening the lid and not hiding the + // keyguard, then we need to have it turn on the + // screen once it is shown. + mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq( + KeyEvent.KEYCODE_POWER); } } else { // Light up the keyboard if we are sliding up. -- GitLab From 39c2d71950a5ecccb2881613dd69b74ba8de55f9 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 22 Sep 2009 11:41:31 -0700 Subject: [PATCH 112/458] Fixes and improvements to lock screen hiding, dock launching. - Implement new window flags for dismissing non-secure lock screens. - Implement launching of docks from the home key. Change-Id: If29f299db47e3759c3e146983f59d0f86ed22c4c --- .../policy/impl/KeyguardViewMediator.java | 6 +- .../policy/impl/PhoneWindowManager.java | 135 +++++++++++++++--- 2 files changed, 115 insertions(+), 26 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 682ea9f3102d..adcd86b9a022 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -104,7 +104,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private static final int WAKE_WHEN_READY = 8; private static final int KEYGUARD_DONE = 9; private static final int KEYGUARD_DONE_DRAWING = 10; - private static final int HIDE_KEYGUARD = 11; + private static final int KEYGUARD_DONE_AUTHENTICATING = 11; /** * The default amount of time we stay awake (used for all key input) @@ -444,7 +444,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (mUpdateMonitor.isKeyguardBypassEnabled() && mKeyboardOpen && !mKeyguardViewProperties.isSecure() && mKeyguardViewManager.isShowing()) { if (DEBUG) Log.d(TAG, "bypassing keyguard on sliding open of keyboard with non-secure keyguard"); - mHandler.sendEmptyMessage(HIDE_KEYGUARD); + mHandler.sendEmptyMessage(KEYGUARD_DONE_AUTHENTICATING); return true; } return false; @@ -793,7 +793,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, case KEYGUARD_DONE_DRAWING: handleKeyguardDoneDrawing(); return; - case HIDE_KEYGUARD: + case KEYGUARD_DONE_AUTHENTICATING: keyguardDone(true); return; } diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 41d76e8b2899..032e1f41d34c 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -20,6 +20,7 @@ import android.app.Activity; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.IStatusBar; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -68,6 +69,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; +import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; @@ -218,9 +220,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowState mTopFullscreenOpaqueWindowState; boolean mForceStatusBar; - boolean mHideKeyguard; + boolean mHideLockScreen; + boolean mDismissKeyguard; boolean mHomePressed; Intent mHomeIntent; + Intent mCarDockIntent; + Intent mDeskDockIntent; boolean mSearchKeyPressed; boolean mConsumeSearchKeyUp; @@ -472,6 +477,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHomeIntent.addCategory(Intent.CATEGORY_HOME); mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + mCarDockIntent = new Intent(Intent.ACTION_MAIN, null); + mCarDockIntent.addCategory(Intent.CATEGORY_CAR_DOCK); + mCarDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + mDeskDockIntent = new Intent(Intent.ACTION_MAIN, null); + 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"); @@ -1050,9 +1063,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { * given the situation with the keyguard. */ void launchHomeFromHotKey() { - if (!mHideKeyguard && mKeyguardMediator.isShowing()) { + if (!mHideLockScreen && mKeyguardMediator.isShowing()) { // don't launch home if keyguard showing - } else if (!mHideKeyguard && mKeyguardMediator.isInputRestricted()) { + } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) { // when in keyguard restricted mode, must first verify unlock // before launching home mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() { @@ -1063,7 +1076,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } catch (RemoteException e) { } sendCloseSystemWindows(); - mContext.startActivity(mHomeIntent); + startDockOrHome(); } } }); @@ -1074,7 +1087,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } catch (RemoteException e) { } sendCloseSystemWindows(); - mContext.startActivity(mHomeIntent); + startDockOrHome(); } } @@ -1102,7 +1115,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mTopFullscreenOpaqueWindowState = null; mForceStatusBar = false; - mHideKeyguard = false; + mHideLockScreen = false; + mDismissKeyguard = false; // decide where the status bar goes ahead of time if (mStatusBar != null) { @@ -1309,11 +1323,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { && win.fillsScreenLw(mW, mH, false, false)) { if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win); mTopFullscreenOpaqueWindowState = win; + if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { + if (localLOGV) Log.i(TAG, "Setting mHideLockScreen to true by win " + win); + mHideLockScreen = true; + } } - if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { - // TODO Add a check for the window to be full screen - if (localLOGV) Log.i(TAG, "Setting mHideKeyguard to true by win " + win); - mHideKeyguard = true; + if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) { + if (localLOGV) Log.i(TAG, "Setting mDismissKeyguard to true by win " + win); + mDismissKeyguard = true; } } @@ -1337,15 +1354,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ - public boolean finishLayoutLw() { - boolean changed = false; + public int finishLayoutLw() { + int changes = 0; boolean hiding = false; if (mStatusBar != null) { //Log.i(TAG, "force=" + mForceStatusBar // + " top=" + mTopFullscreenOpaqueWindowState); if (mForceStatusBar) { if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); - changed |= mStatusBar.showLw(true); + if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; } else if (mTopFullscreenOpaqueWindowState != null) { //Log.i(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw() // + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw()); @@ -1356,33 +1373,48 @@ public class PhoneWindowManager implements WindowManagerPolicy { (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; if (hideStatusBar) { if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar"); - changed |= mStatusBar.hideLw(true); + if (mStatusBar.hideLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; hiding = true; } else { if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); - changed |= mStatusBar.showLw(true); + if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; } } } // 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.i(TAG, "finishLayoutLw::mHideKeyguard="+mHideKeyguard); - if (mHideKeyguard) { - changed |= mKeyguard.hideLw(true); - if (!mKeyguardMediator.isShowing()) { + if (localLOGV) Log.i(TAG, "finishLayoutLw::mHideKeyguard="+mHideLockScreen); + if (mDismissKeyguard && mKeyguardMediator.isShowing() + && !mKeyguardMediator.isSecure()) { + if (mKeyguard.hideLw(true)) { + changes |= FINISH_LAYOUT_REDO_LAYOUT + | FINISH_LAYOUT_REDO_CONFIG + | FINISH_LAYOUT_REDO_WALLPAPER; + } + if (!mKeyguardMediator.isSecure()) { mHandler.post(new Runnable() { public void run() { mKeyguardMediator.keyguardDone(true); } }); } + } else if (mHideLockScreen && mKeyguardMediator.isShowing()) { + if (mKeyguard.hideLw(true)) { + changes |= FINISH_LAYOUT_REDO_LAYOUT + | FINISH_LAYOUT_REDO_CONFIG + | FINISH_LAYOUT_REDO_WALLPAPER; + } } else { - changed |= mKeyguard.showLw(true); + if (mKeyguard.showLw(false)) { + changes |= FINISH_LAYOUT_REDO_LAYOUT + | FINISH_LAYOUT_REDO_CONFIG + | FINISH_LAYOUT_REDO_WALLPAPER; + } } } - if (changed && hiding) { + if (changes != 0 && hiding) { IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar")); if (sbs != null) { try { @@ -1393,7 +1425,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - return changed; + return changes; } /** {@inheritDoc} */ @@ -1991,6 +2023,53 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + /** + * Return an Intent to launch the currently active dock as home. Returns + * null if the standard home should be launched. + * @return + */ + Intent createHomeDockIntent() { + if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) { + return null; + } + + Intent intent; + if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) { + intent = mCarDockIntent; + } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { + intent = mDeskDockIntent; + } else { + Log.w(TAG, "Unknown dock state: " + mDockState); + return null; + } + + ActivityInfo ai = intent.resolveActivityInfo( + mContext.getPackageManager(), PackageManager.GET_META_DATA); + if (ai == null) { + return null; + } + + if (ai.metaData != null && ai.metaData.getBoolean(Intent.METADATA_DOCK_HOME)) { + intent = new Intent(intent); + intent.setClassName(ai.packageName, ai.name); + return intent; + } + + return null; + } + + void startDockOrHome() { + Intent dock = createHomeDockIntent(); + if (dock != null) { + try { + mContext.startActivity(dock); + return; + } catch (ActivityNotFoundException e) { + } + } + mContext.startActivity(mHomeIntent); + } + /** * goes to the home screen * @return whether it did anything @@ -2003,13 +2082,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { } catch (RemoteException e) { } sendCloseSystemWindows(); - mContext.startActivity(mHomeIntent); + startDockOrHome(); } else { // This code brings home to the front or, if it is already // at the front, puts the device to sleep. try { ActivityManagerNative.getDefault().stopAppSwitches(); sendCloseSystemWindows(); + Intent dock = createHomeDockIntent(); + if (dock != null) { + int result = ActivityManagerNative.getDefault() + .startActivity(null, dock, + dock.resolveTypeIfNeeded(mContext.getContentResolver()), + null, 0, null, null, 0, true /* onlyIfNeeded*/, false); + if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) { + return false; + } + } int result = ActivityManagerNative.getDefault() .startActivity(null, mHomeIntent, mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()), -- GitLab From 1b58b3ebeee8624f9f1e3c93eeb6d2c5a4d176b9 Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Tue, 22 Sep 2009 16:44:16 -0700 Subject: [PATCH 113/458] The nosensor flag wasn't being honored. --- .../policy/impl/PhoneWindowManager.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 032e1f41d34c..59283a23bcea 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -321,18 +321,27 @@ public class PhoneWindowManager implements WindowManagerPolicy { MyOrientationListener mOrientationListener; boolean useSensorForOrientationLp(int appOrientation) { + // The app says use the sensor. if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { return true; } - if ((mAccelerometerDefault != 0 || - (mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR) || - (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) - && (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || - // dock overrides SCREEN_ORIENTATION_NOSENSOR - appOrientation == ActivityInfo. SCREEN_ORIENTATION_NOSENSOR || - appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { + // The user preference says we can rotate, and the app is willing to rotate. + if (mAccelerometerDefault != 0 && + (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER + || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { return true; } + // We're in a dock that has a rotation affinity, an the app is willing to rotate. + if ((mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR) + || (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) { + // Note we override the nosensor flag here. + if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER + || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { + return true; + } + } + // Else, don't use the sensor. return false; } -- GitLab From 0572658afdfcc08cbcdcc509b11691646d5f237d Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 22 Sep 2009 17:28:24 -0700 Subject: [PATCH 114/458] Allow dock keep screen on to select between AC and USB power. Change-Id: I2309992f5ad7b93006eb52f31758f71c48ed98f1 --- .../policy/impl/KeyguardViewMediator.java | 13 +++- .../policy/impl/PhoneWindowManager.java | 71 +++++++++++-------- 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index adcd86b9a022..0cb69e347965 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -718,10 +718,15 @@ public class KeyguardViewMediator implements KeyguardViewCallback, * @see #handleKeyguardDone */ public void keyguardDone(boolean authenticated) { + keyguardDone(authenticated, true); + } + + public void keyguardDone(boolean authenticated, boolean wakeup) { synchronized (this) { EventLog.writeEvent(70000, 2); if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")"); Message msg = mHandler.obtainMessage(KEYGUARD_DONE); + msg.arg1 = wakeup ? 1 : 0; mHandler.sendMessage(msg); if (authenticated) { @@ -788,7 +793,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, handleWakeWhenReady(msg.arg1); return; case KEYGUARD_DONE: - handleKeyguardDone(); + handleKeyguardDone(msg.arg1 != 0); return; case KEYGUARD_DONE_DRAWING: handleKeyguardDoneDrawing(); @@ -804,10 +809,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, * @see #keyguardDone * @see #KEYGUARD_DONE */ - private void handleKeyguardDone() { + private void handleKeyguardDone(boolean wakeup) { if (DEBUG) Log.d(TAG, "handleKeyguardDone"); handleHide(); - mPM.userActivity(SystemClock.uptimeMillis(), true); + if (wakeup) { + mPM.userActivity(SystemClock.uptimeMillis(), true); + } mWakeLock.release(); mContext.sendBroadcast(mUserPresentIntent); } diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 59283a23bcea..b5d41d869a53 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -177,14 +177,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { RecentApplicationsDialog mRecentAppsDialog; Handler mHandler; + final IntentFilter mBatteryStatusFilter = new IntentFilter(); + boolean mLidOpen; - boolean mPlugged; + int mPlugged; int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; int mLidOpenRotation; int mCarDockRotation; int mDeskDockRotation; - boolean mCarDockKeepsScreenOn; - boolean mDeskDockKeepsScreenOn; + int mCarDockKeepsScreenOn; + int mDeskDockKeepsScreenOn; boolean mCarDockEnablesAccelerometer; boolean mDeskDockEnablesAccelerometer; int mLidKeyboardAccessibility; @@ -308,7 +310,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void onOrientationChanged(int rotation) { // Send updates based on orientation value - if (true) Log.i(TAG, "onOrientationChanged, rotation changed to " +rotation); + if (localLOGV) Log.v(TAG, "onOrientationChanged, rotation changed to " +rotation); try { mWindowManager.setRotation(rotation, false, mFancyRotationAnimation); @@ -393,7 +395,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } //Could have been invoked due to screen turning on or off or //change of the currently visible window's orientation - if (localLOGV) Log.i(TAG, "Screen status="+mScreenOn+ + if (localLOGV) Log.v(TAG, "Screen status="+mScreenOn+ ", current orientation="+mCurrentAppOrientation+ ", SensorEnabled="+mOrientationSensorEnabled); boolean disable = true; @@ -403,7 +405,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { //enable listener if not already enabled if (!mOrientationSensorEnabled) { mOrientationListener.enable(); - if(localLOGV) Log.i(TAG, "Enabling listeners"); + if(localLOGV) Log.v(TAG, "Enabling listeners"); mOrientationSensorEnabled = true; } } @@ -411,7 +413,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { //check if sensors need to be disabled if (disable && mOrientationSensorEnabled) { mOrientationListener.disable(); - if(localLOGV) Log.i(TAG, "Disabling listeners"); + if(localLOGV) Log.v(TAG, "Disabling listeners"); mOrientationSensorEnabled = false; } } @@ -507,10 +509,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.integer.config_carDockRotation); mDeskDockRotation = readRotation( com.android.internal.R.integer.config_deskDockRotation); - mCarDockKeepsScreenOn = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_carDockKeepsScreenOn); - mDeskDockKeepsScreenOn = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_deskDockKeepsScreenOn); + mCarDockKeepsScreenOn = mContext.getResources().getInteger( + com.android.internal.R.integer.config_carDockKeepsScreenOn); + mDeskDockKeepsScreenOn = mContext.getResources().getInteger( + com.android.internal.R.integer.config_deskDockKeepsScreenOn); mCarDockEnablesAccelerometer = mContext.getResources().getBoolean( com.android.internal.R.bool.config_carDockEnablesAccelerometer); mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean( @@ -524,16 +526,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { intentFilter.addAction(Intent.ACTION_POWER_CONNECTED); intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED); context.registerReceiver(mPowerReceiver, intentFilter); - Intent powerIntent = context.registerReceiver(null, - new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - mPlugged = false; - if (powerIntent != null) { - mPlugged = powerIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; - } + mBatteryStatusFilter.addAction(Intent.ACTION_BATTERY_CHANGED); + mPlugged = 0; + updatePlugged(); // register for dock events context.registerReceiver(mDockReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT)); } + void updatePlugged() { + Intent powerIntent = mContext.registerReceiver(null, mBatteryStatusFilter); + if (localLOGV) Log.v(TAG, "New battery status: " + powerIntent.getExtras()); + if (powerIntent != null) { + mPlugged = powerIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); + if (localLOGV) Log.v(TAG, "PLUGGED: " + mPlugged); + } + } + private int readRotation(int resID) { try { int rotation = mContext.getResources().getInteger(resID); @@ -1333,12 +1341,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win); mTopFullscreenOpaqueWindowState = win; if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { - if (localLOGV) Log.i(TAG, "Setting mHideLockScreen to true by win " + win); + if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win); mHideLockScreen = true; } } if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) { - if (localLOGV) Log.i(TAG, "Setting mDismissKeyguard to true by win " + win); + if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win); mDismissKeyguard = true; } } @@ -1393,22 +1401,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { // 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.i(TAG, "finishLayoutLw::mHideKeyguard="+mHideLockScreen); - if (mDismissKeyguard && mKeyguardMediator.isShowing() - && !mKeyguardMediator.isSecure()) { + if (localLOGV) Log.v(TAG, "finishLayoutLw::mHideKeyguard="+mHideLockScreen); + if (mDismissKeyguard && !mKeyguardMediator.isSecure()) { if (mKeyguard.hideLw(true)) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; } - if (!mKeyguardMediator.isSecure()) { + if (mKeyguardMediator.isShowing()) { mHandler.post(new Runnable() { public void run() { - mKeyguardMediator.keyguardDone(true); + mKeyguardMediator.keyguardDone(false, false); } }); } - } else if (mHideLockScreen && mKeyguardMediator.isShowing()) { + } else if (mHideLockScreen) { if (mKeyguard.hideLw(true)) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG @@ -1786,9 +1793,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { BroadcastReceiver mPowerReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())) { - mPlugged = true; + updatePlugged(); } else if (Intent.ACTION_POWER_DISCONNECTED.equals(intent.getAction())) { - mPlugged = false; + updatePlugged(); } updateKeepScreenOn(); } @@ -1991,15 +1998,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { } void updateKeepScreenOn() { - if (mPlugged) { + if (mPlugged != 0) { + if (localLOGV) Log.v(TAG, "Update: mDockState=" + mDockState + + " mPlugged=" + mPlugged + + " mCarDockKeepsScreenOn" + mCarDockKeepsScreenOn + + " mDeskDockKeepsScreenOn" + mDeskDockKeepsScreenOn); if (mDockState == Intent.EXTRA_DOCK_STATE_CAR - && mCarDockKeepsScreenOn) { + && (mPlugged&mCarDockKeepsScreenOn) != 0) { if (!mDockWakeLock.isHeld()) { mDockWakeLock.acquire(); } return; } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK - && mDeskDockKeepsScreenOn) { + && (mPlugged&mDeskDockKeepsScreenOn) != 0) { if (!mDockWakeLock.isHeld()) { mDockWakeLock.acquire(); } -- GitLab From 4994c66c0982a29898c7d1bf74f6777c0d4dd559 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 23 Sep 2009 22:21:23 -0700 Subject: [PATCH 115/458] Fix issue #2133206: dialogs/menus should auto-dismiss when screen turns off Perform clear system dialogs when turning on the lock screen. Change-Id: I2a3104a9df942d59308a94377f93787f17dbb2ce --- .../internal/policy/impl/KeyguardViewMediator.java | 8 +++++++- policy/com/android/internal/policy/impl/PhoneWindow.java | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 0cb69e347965..f8bc3e67fb00 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -19,6 +19,7 @@ package com.android.internal.policy.impl; import com.android.internal.telephony.IccCard; import com.android.internal.widget.LockPatternUtils; +import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.StatusBarManager; @@ -32,6 +33,7 @@ import android.os.Handler; import android.os.LocalPowerManager; import android.os.Message; import android.os.PowerManager; +import android.os.RemoteException; import android.os.SystemClock; import android.telephony.TelephonyManager; import android.util.Config; @@ -123,7 +125,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 = 0; + private static final int KEYGUARD_DELAY_MS = 5000; /** * How long we'll wait for the {@link KeyguardViewCallback#keyguardDoneDrawing()} @@ -869,6 +871,10 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mKeyguardViewManager.show(); mShowing = true; + try { + ActivityManagerNative.getDefault().closeSystemDialogs("lock"); + } catch (RemoteException e) { + } } } diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 05dc936d0fd9..3d6fdeb4b4a7 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -1998,6 +1998,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { cb.onDetachedFromWindow(); } } + + @Override + public void onCloseSystemDialogs(String reason) { + if (mFeatureId >= 0) { + closeAllPanels(); + } + } } protected DecorView generateDecor() { -- GitLab From 80be841eafe3b7b9f8dba820ba3201843717e610 Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Thu, 24 Sep 2009 10:17:42 -0700 Subject: [PATCH 116/458] Tweak LockScreen to make use of landscape layout. --- .../internal/policy/impl/LockScreen.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 8ed035f65abe..8899ac323cef 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -80,6 +80,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private AudioManager mAudioManager; private java.text.DateFormat mDateFormat; private java.text.DateFormat mTimeFormat; + private boolean mCreatedInPortrait; /** * The status of this lock screen. @@ -148,8 +149,14 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mUpdateMonitor = updateMonitor; mCallback = callback; + mCreatedInPortrait = updateMonitor.isInPortrait(); + final LayoutInflater inflater = LayoutInflater.from(context); - inflater.inflate(R.layout.keyguard_screen_rotary_unlock, this, true); + if (mCreatedInPortrait) { + inflater.inflate(R.layout.keyguard_screen_rotary_unlock, this, true); + } else { + inflater.inflate(R.layout.keyguard_screen_rotary_unlock_land, this, true); + } mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo(); mPluggedIn = updateMonitor.isDevicePluggedIn(); @@ -196,8 +203,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mRotary.setOnDialTriggerListener(this); mRotary.setLeftHandleResource(R.drawable.ic_jog_dial_unlock); mRotary.setRightHandleResource(mSilentMode ? - R.drawable.ic_jog_dial_turn_ring_vol_off : - R.drawable.ic_jog_dial_turn_ring_vol_on); + R.drawable.ic_jog_dial_sound_off : + R.drawable.ic_jog_dial_sound_on); } @Override @@ -218,8 +225,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mAudioManager.setRingerMode(mSilentMode ? AudioManager.RINGER_MODE_SILENT : AudioManager.RINGER_MODE_NORMAL); final int handleIcon = mSilentMode ? - R.drawable.ic_jog_dial_turn_ring_vol_off : - R.drawable.ic_jog_dial_turn_ring_vol_on; + R.drawable.ic_jog_dial_sound_off : + R.drawable.ic_jog_dial_sound_on; final int toastIcon = mSilentMode ? R.drawable.ic_lock_ringer_off : R.drawable.ic_lock_ringer_on; @@ -461,7 +468,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mRotary.setVisibility(View.INVISIBLE); + mRotary.setVisibility(View.GONE); mEmergencyCallButton.setVisibility(View.VISIBLE); putEmergencyBelow(R.id.screenLocked); break; @@ -481,7 +488,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mRotary.setVisibility(View.INVISIBLE); + mRotary.setVisibility(View.GONE); mEmergencyCallButton.setVisibility(View.VISIBLE); putEmergencyBelow(R.id.screenLocked); break; @@ -509,6 +516,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM public void onOrientationChange(boolean inPortrait) { + if (inPortrait != mCreatedInPortrait) { + mCallback.recreateMe(); + } } public void onKeyboardChange(boolean isKeyboardOpen) { -- GitLab From add3930c01370ac2b5b1e052130e578487b42cda Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Thu, 24 Sep 2009 16:48:14 -0700 Subject: [PATCH 117/458] Update unlock screen logic to display battery, next alarm info. --- .../internal/policy/impl/UnlockScreen.java | 120 ++++++++++++++++-- 1 file changed, 109 insertions(+), 11 deletions(-) diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index 1d5f22006787..5a4dfdadad36 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -29,6 +29,7 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import android.text.format.DateFormat; +import android.text.TextUtils; import com.android.internal.R; import com.android.internal.telephony.IccCard; import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient; @@ -74,7 +75,23 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient private TextView mDate; private TextView mTime; - private TextView mUnlockHeader; + // 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 LockPatternView mLockPatternView; private ViewGroup mFooterNormal; @@ -160,10 +177,18 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mCenterDot.setText("|"); refreshTimeAndDateDisplay(); - mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern); - mUnlockHeader = (TextView) findViewById(R.id.headerText); + mStatus1 = (TextView) findViewById(R.id.status1); + mStatusSep = (TextView) findViewById(R.id.statusSep); + mStatus2 = (TextView) findViewById(R.id.status2); + + mShowingBatteryInfo = true; + mPluggedIn = true; + mBatteryLevel = 100; + mNextAlarm = mLockPatternUtils.getNextAlarm(); + updateStatusLines(); + - mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); + mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern); mFooterNormal = (ViewGroup) findViewById(R.id.footerNormal); mFooterForgotPattern = (ViewGroup) findViewById(R.id.footerForgotPattern); @@ -220,6 +245,74 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mUpdateMonitor.getTelephonySpn())); } + 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() { Date now = new Date(); mTime.setText(DateFormat.getTimeFormat(getContext()).format(now)); @@ -247,6 +340,10 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient /** {@inheritDoc} */ public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + mShowingBatteryInfo = showBatteryInfo; + mPluggedIn = pluggedIn; + mBatteryLevel = batteryLevel; + updateStatusLines(); } /** {@inheritDoc} */ @@ -294,7 +391,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient /** {@inheritDoc} */ public void onResume() { // reset header - mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); + updateStatusLines(); // TODO mUnlockIcon.setVisibility(View.VISIBLE); // reset lock pattern @@ -351,8 +448,8 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient if (mLockPatternUtils.checkPattern(pattern)) { mLockPatternView .setDisplayMode(LockPatternView.DisplayMode.Correct); - // TODO mUnlockIcon.setVisibility(View.GONE); - mUnlockHeader.setText(""); + mInstructions = ""; + updateStatusLines(); mCallback.keyguardDone(true); } else { mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); @@ -368,7 +465,8 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient return; } // TODO mUnlockIcon.setVisibility(View.VISIBLE); - mUnlockHeader.setText(R.string.lockscreen_pattern_wrong); + mInstructions = getContext().getString(R.string.lockscreen_pattern_wrong); + updateStatusLines(); mLockPatternView.postDelayed( mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS); @@ -385,15 +483,15 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient @Override public void onTick(long millisUntilFinished) { int secondsRemaining = (int) (millisUntilFinished / 1000); - mUnlockHeader.setText(getContext().getString( + mInstructions = getContext().getString( R.string.lockscreen_too_many_failed_attempts_countdown, - secondsRemaining)); + secondsRemaining); } @Override public void onFinish() { mLockPatternView.setEnabled(true); - mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); + mInstructions = getContext().getString(R.string.lockscreen_pattern_instructions); // TODO mUnlockIcon.setVisibility(View.VISIBLE); mFailedPatternAttemptsSinceLastTimeout = 0; if (mEnableFallback) { -- GitLab From 18fe8a502228157e34a6519ca3b070d561576778 Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Thu, 24 Sep 2009 17:13:56 -0700 Subject: [PATCH 118/458] Whoops, count down text is not updating... fixed! --- policy/com/android/internal/policy/impl/UnlockScreen.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index 5a4dfdadad36..cfffcf241a17 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -486,12 +486,14 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mInstructions = getContext().getString( R.string.lockscreen_too_many_failed_attempts_countdown, secondsRemaining); + updateStatusLines(); } @Override public void onFinish() { mLockPatternView.setEnabled(true); mInstructions = getContext().getString(R.string.lockscreen_pattern_instructions); + updateStatusLines(); // TODO mUnlockIcon.setVisibility(View.VISIBLE); mFailedPatternAttemptsSinceLastTimeout = 0; if (mEnableFallback) { -- GitLab From b17dc443c639a4ed0327f8e7aad48316d271f129 Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Thu, 24 Sep 2009 18:11:28 -0700 Subject: [PATCH 119/458] Initialze battery state properly in pattern unlock screen. --- policy/com/android/internal/policy/impl/UnlockScreen.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index cfffcf241a17..5245c7cafa0d 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -181,9 +181,9 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mStatusSep = (TextView) findViewById(R.id.statusSep); mStatus2 = (TextView) findViewById(R.id.status2); - mShowingBatteryInfo = true; - mPluggedIn = true; - mBatteryLevel = 100; + mShowingBatteryInfo = mUpdateMonitor.shouldShowBatteryInfo(); + mPluggedIn = mUpdateMonitor.isDevicePluggedIn(); + mBatteryLevel = mUpdateMonitor.getBatteryLevel(); mNextAlarm = mLockPatternUtils.getNextAlarm(); updateStatusLines(); -- GitLab From 01ad2f4a2d86faad2058159ad67840f1797955c0 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 24 Sep 2009 19:24:56 -0700 Subject: [PATCH 120/458] Implement fade out of lock screen. Change-Id: I516aa2257c788a9fb618ac37c9d227b1e7a3c2ae --- .../policy/impl/KeyguardViewManager.java | 15 ++++++++++----- .../policy/impl/PhoneWindowManager.java | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index f05c2fbb8f3e..61515d855311 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -102,6 +102,7 @@ public class KeyguardViewManager implements KeyguardWindowController { final int stretch = ViewGroup.LayoutParams.FILL_PARENT; int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER + | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ; if (!mNeedsInput) { @@ -111,7 +112,7 @@ public class KeyguardViewManager implements KeyguardWindowController { stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD, flags, PixelFormat.TRANSLUCENT); lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; - //lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen; + lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen; lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; lp.setTitle("Keyguard"); mWindowLayoutParams = lp; @@ -210,10 +211,14 @@ public class KeyguardViewManager implements KeyguardWindowController { if (DEBUG) Log.d(TAG, "hide()"); if (mKeyguardHost != null) { mKeyguardHost.setVisibility(View.GONE); - if (mKeyguardView != null) { - mKeyguardHost.removeView(mKeyguardView); - mKeyguardView.cleanUp(); - mKeyguardView = null; + // Don't do this, so we can let the view continue to animate + // as it goes away. + if (false) { + if (mKeyguardView != null) { + mKeyguardHost.removeView(mKeyguardView); + mKeyguardView.cleanUp(); + mKeyguardView = null; + } } } } diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index b5d41d869a53..448265c5406b 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -94,6 +94,9 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; +import android.view.WindowManagerPolicy.WindowState; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; import android.media.IAudioService; import android.media.AudioManager; @@ -722,6 +725,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { return STATUS_BAR_LAYER; } + public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) { + return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD; + } + + public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) { + return attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR + && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER; + } + /** {@inheritDoc} */ public View addStartingWindow(IBinder appToken, String packageName, int theme, CharSequence nonLocalizedLabel, @@ -890,6 +902,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } + public Animation createForceHideEnterAnimation() { + return AnimationUtils.loadAnimation(mContext, + com.android.internal.R.anim.lock_screen_behind_enter); + } + static ITelephony getPhoneInterface() { return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE)); } -- GitLab From d0071448ccea1c5e7832b63b8299fff68568dd46 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Fri, 25 Sep 2009 01:35:29 -0700 Subject: [PATCH 121/458] Maybe fix #2127747: IllegalStateException from window manager when resuming from sleep It looks like there may have been a race when restoring that would allow you to show the menu before it is restored. I couldn't repro on my current device before the fix, though. Change-Id: I624e1306871344d3ee39f69dde832b3db2530a5f --- .../internal/policy/impl/PhoneWindow.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 3d6fdeb4b4a7..6dd5d934b713 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -1532,9 +1532,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { PanelFeatureState st; for (int i = panels.length - 1; i >= 0; i--) { st = panels[i]; - if ((st != null) && st.isOpen) { - // Clear st.isOpen (openPanel will not open if it's already open) - st.isOpen = false; + // We restore the panel if it was last open; we skip it if it + // now is open, to avoid a race condition if the user immediately + // opens it when we are resuming. + if ((st != null) && !st.isOpen && st.wasLastOpen) { + st.isInExpandedMode = st.wasLastExpanded; openPanel(st, null); } } @@ -2572,6 +2574,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { boolean refreshDecorView; + boolean wasLastOpen; + + boolean wasLastExpanded; + /** * Contains the state of the menu when told to freeze. */ @@ -2620,8 +2626,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { void onRestoreInstanceState(Parcelable state) { SavedState savedState = (SavedState) state; featureId = savedState.featureId; - isOpen = savedState.isOpen; - isInExpandedMode = savedState.isInExpandedMode; + wasLastOpen = savedState.isOpen; + wasLastExpanded = savedState.isInExpandedMode; frozenMenuState = savedState.menuState; /* -- GitLab From a35d753adda055582e319bc98f30f11b138b2936 Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Fri, 25 Sep 2009 10:24:26 -0700 Subject: [PATCH 122/458] Remove keyguard view after a delay instead of just hiding it. The delay should make sure the animation works, and by still removing it, we preserve the initialization logic that depends on being reinstantiated each time the screen turns off. The logic could be adjusted to work without this, but seems safer to maintain the existing behavior. Also reduces risk from having keyguard around all the time. --- .../policy/impl/KeyguardViewManager.java | 16 +++++---- .../internal/policy/impl/LockScreen.java | 36 ++++++++++--------- .../internal/policy/impl/UnlockScreen.java | 21 +++++------ 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index 61515d855311..a1d3576c8133 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -211,14 +211,16 @@ public class KeyguardViewManager implements KeyguardWindowController { if (DEBUG) Log.d(TAG, "hide()"); if (mKeyguardHost != null) { mKeyguardHost.setVisibility(View.GONE); - // Don't do this, so we can let the view continue to animate + // Don't do this right away, so we can let the view continue to animate // as it goes away. - if (false) { - if (mKeyguardView != null) { - mKeyguardHost.removeView(mKeyguardView); - mKeyguardView.cleanUp(); - mKeyguardView = null; - } + if (mKeyguardView != null) { + mKeyguardHost.postDelayed(new Runnable() { + public void run() { + mKeyguardHost.removeView(mKeyguardView); + mKeyguardView.cleanUp(); + mKeyguardView = null; + } + }, 500); } } } diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 8899ac323cef..67533242f514 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -158,10 +158,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM inflater.inflate(R.layout.keyguard_screen_rotary_unlock_land, this, true); } - mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo(); - mPluggedIn = updateMonitor.isDevicePluggedIn(); - mBatteryLevel = updateMonitor.getBatteryLevel(); - mCarrier = (TextView) findViewById(R.id.carrier); mTime = (TextView) findViewById(R.id.time); mDate = (TextView) findViewById(R.id.date); @@ -182,17 +178,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM setFocusableInTouchMode(true); setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); - mStatus = getCurrentStatus(updateMonitor.getSimState()); - updateLayout(mStatus); - - refreshBatteryStringAndIcon(); - refreshAlarmDisplay(); - - mTimeFormat = DateFormat.getTimeFormat(getContext()); - mDateFormat = getLockScreenDateFormat(); - refreshTimeAndDateDisplay(); - updateStatusLines(); - updateMonitor.registerInfoCallback(this); updateMonitor.registerSimStateCallback(this); updateMonitor.registerConfigurationChangeCallback(this); @@ -205,6 +190,25 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mRotary.setRightHandleResource(mSilentMode ? R.drawable.ic_jog_dial_sound_off : R.drawable.ic_jog_dial_sound_on); + + resetStatusInfo(updateMonitor); + } + + private void resetStatusInfo(KeyguardUpdateMonitor updateMonitor) { + mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo(); + mPluggedIn = updateMonitor.isDevicePluggedIn(); + mBatteryLevel = updateMonitor.getBatteryLevel(); + + mStatus = getCurrentStatus(updateMonitor.getSimState()); + updateLayout(mStatus); + + refreshBatteryStringAndIcon(); + refreshAlarmDisplay(); + + mTimeFormat = DateFormat.getTimeFormat(getContext()); + mDateFormat = getLockScreenDateFormat(); + refreshTimeAndDateDisplay(); + updateStatusLines(); } @Override @@ -540,7 +544,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM /** {@inheritDoc} */ public void onResume() { - + resetStatusInfo(mUpdateMonitor); } /** {@inheritDoc} */ diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index 5245c7cafa0d..f599b51f6084 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -17,16 +17,13 @@ package com.android.internal.policy.impl; import android.content.Context; -import android.content.ServiceConnection; import android.os.CountDownTimer; import android.os.SystemClock; -import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.MotionEvent; import android.widget.Button; -import android.widget.ImageView; import android.widget.TextView; import android.text.format.DateFormat; import android.text.TextUtils; @@ -181,11 +178,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mStatusSep = (TextView) findViewById(R.id.statusSep); mStatus2 = (TextView) findViewById(R.id.status2); - mShowingBatteryInfo = mUpdateMonitor.shouldShowBatteryInfo(); - mPluggedIn = mUpdateMonitor.isDevicePluggedIn(); - mBatteryLevel = mUpdateMonitor.getBatteryLevel(); - mNextAlarm = mLockPatternUtils.getNextAlarm(); - updateStatusLines(); + resetStatusInfo(); mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern); @@ -245,6 +238,15 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mUpdateMonitor.getTelephonySpn())); } + 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 @@ -391,8 +393,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient /** {@inheritDoc} */ public void onResume() { // reset header - updateStatusLines(); - // TODO mUnlockIcon.setVisibility(View.VISIBLE); + resetStatusInfo(); // reset lock pattern mLockPatternView.enableInput(); -- GitLab From a53e3816656b145bfdc165e81849d245883a2884 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Fri, 25 Sep 2009 10:51:39 -0400 Subject: [PATCH 123/458] Fix volume key handling when in-call and screen is off due to proximity sensor. Fixes bug b/2136633 Change-Id: If963d0267496878978ad82d915f821af2bd03383 Signed-off-by: Mike Lockwood --- .../policy/impl/PhoneWindowManager.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 448265c5406b..967817c54e2c 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1565,10 +1565,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { * Tell the audio service to adjust the volume appropriate to the event. * @param keycode */ - void sendVolToMusic(int keycode) { + void handleVolumeKey(int stream, int keycode) { final IAudioService audio = getAudioInterface(); if (audio == null) { - Log.w(TAG, "sendVolToMusic: couldn't get IAudioService reference"); + Log.w(TAG, "handleVolumeKey: couldn't get IAudioService reference"); return; } try { @@ -1576,8 +1576,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // during the call, but we do it as a precaution for the rare possibility // that the music stops right before we call this mBroadcastWakeLock.acquire(); - audio.adjustStreamVolume( - AudioManager.STREAM_MUSIC, + audio.adjustStreamVolume(stream, keycode == KeyEvent.KEYCODE_VOLUME_UP ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER, @@ -1639,12 +1638,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else if (isMusicActive()) { // when keyguard is showing and screen off, we need // to handle the volume key for music here - sendVolToMusic(event.keycode); + handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode); } } } } } else if (!screenIsOn) { + // If we are in-call with screen off and keyguard is not showing, + // then handle the volume key ourselves. + // This is necessary because the phone app will disable the keyguard + // when the proximity sensor is in use. + if (isInCall() && event.type == RawInputEvent.EV_KEY && + (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN + || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) { + result &= ~ACTION_PASS_TO_USER; + handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode); + } if (isWakeKey) { // a wake key has a sole purpose of waking the device; don't pass // it to the user -- GitLab From cd3d3f22ab6f5dd33b67fc0df58cce6ef46209c5 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Tue, 22 Sep 2009 11:44:29 -0500 Subject: [PATCH 124/458] fw/policy/base:Phonewindowmanager: Make vkey button haptics part of global haptic setting This change ties the virtual key haptics to the global haptics settings Signed-off-by: Dan Murphy --- .../com/android/internal/policy/impl/PhoneWindowManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) mode change 100644 => 100755 policy/com/android/internal/policy/impl/PhoneWindowManager.java diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java old mode 100644 new mode 100755 index 967817c54e2c..4234247cef21 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -2184,7 +2184,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void keyFeedbackFromInput(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN && (event.getFlags()&KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) { - mVibrator.vibrate(mVirtualKeyVibePattern, -1); + if (Settings.System.getInt(mContext.getContentResolver(), + Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) != 0) { + mVibrator.vibrate(mVirtualKeyVibePattern, -1); + } } } -- GitLab From d7f7deb2862fcfe830df15b6dc1be041f2741d3d Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Fri, 25 Sep 2009 17:35:10 -0700 Subject: [PATCH 125/458] Fix potential race when removing keyguard view. Change-Id: Ia636bc8a73d18b8ebe2dca2b29bb74793a3f0396 --- .../internal/policy/impl/KeyguardViewManager.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index a1d3576c8133..0facbf6cbbd2 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -214,11 +214,16 @@ public class KeyguardViewManager implements KeyguardWindowController { // Don't do this right away, so we can let the view continue to animate // as it goes away. if (mKeyguardView != null) { + final View lastView = mKeyguardView; mKeyguardHost.postDelayed(new Runnable() { public void run() { - mKeyguardHost.removeView(mKeyguardView); - mKeyguardView.cleanUp(); - mKeyguardView = null; + synchronized (KeyguardViewManager.this) { + if (mKeyguardView == lastView) { + mKeyguardHost.removeView(mKeyguardView); + mKeyguardView.cleanUp(); + mKeyguardView = null; + } + } } }, 500); } -- GitLab From 72f230e32ec889607f7d85594396cc3b002bae8c Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Tue, 29 Sep 2009 14:16:41 -0700 Subject: [PATCH 126/458] Fix for 2137900: Be more conservative about poking the wakelock --- .../internal/policy/impl/UnlockScreen.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index f599b51f6084..915e6ab40e24 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -32,6 +32,7 @@ import com.android.internal.telephony.IccCard; import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; +import com.android.internal.widget.LockPatternView.Cell; import java.util.List; import java.util.Date; @@ -52,6 +53,9 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient // how long we stay awake once the user is ready to enter a pattern private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000; + // how many cells the user has to cross before we poke the wakelock + private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2; + private int mFailedPatternAttemptsSinceLastTimeout = 0; private int mTotalFailedPatternAttempts = 0; private CountDownTimer mCountdownTimer = null; @@ -332,7 +336,6 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient ((SystemClock.elapsedRealtime() - mLastPokeTime) > (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) { mLastPokeTime = SystemClock.elapsedRealtime(); - mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); } return result; } @@ -445,6 +448,14 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient public void onPatternCleared() { } + public void onPatternCellAdded(List pattern) { + // To guard against accidental poking of the wakelock, look for + // the user actually trying to draw a pattern of some minimal length. + if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { + mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); + } + } + public void onPatternDetected(List pattern) { if (mLockPatternUtils.checkPattern(pattern)) { mLockPatternView @@ -453,7 +464,9 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient updateStatusLines(); mCallback.keyguardDone(true); } else { - mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); + if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { + mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); + } mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong); if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { mTotalFailedPatternAttempts++; -- GitLab From b1a798080016d30b4cb21bca074856e8baadffa3 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 29 Sep 2009 15:18:31 -0700 Subject: [PATCH 127/458] Whoops forgot the change to actually check for safe mode! Change-Id: Iba0ad151ed786be8ae8659bfefe2a29776ce6311 --- .../policy/impl/PhoneWindowManager.java | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 4234247cef21..b6b6b777e310 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -168,6 +168,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Vibrator pattern for haptic feedback of virtual key press. long[] mVirtualKeyVibePattern; + // Vibrator pattern for haptic feedback during boot when safe mode is disabled. + long[] mSafeModeDisabledVibePattern; + + // Vibrator pattern for haptic feedback during boot when safe mode is enabled. + long[] mSafeModeEnabledVibePattern; + /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ boolean mEnableShiftMenuBugReports = false; @@ -534,6 +540,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { updatePlugged(); // register for dock events context.registerReceiver(mDockReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT)); + mVibrator = new Vibrator(); + mLongPressVibePattern = getLongIntArray(mContext.getResources(), + com.android.internal.R.array.config_longPressVibePattern); + mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(), + com.android.internal.R.array.config_virtualKeyVibePattern); + mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(), + com.android.internal.R.array.config_safeModeDisabledVibePattern); + mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), + com.android.internal.R.array.config_safeModeEnabledVibePattern); } void updatePlugged() { @@ -1971,8 +1986,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { public boolean detectSafeMode() { try { int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU); - mSafeMode = menuState > 0; - Log.i(TAG, "Menu key state: " + menuState + " safeMode=" + mSafeMode); + int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S); + int dpadState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER); + int trackballState = mWindowManager.getScancodeState(RawInputEvent.BTN_MOUSE); + mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0; + performHapticFeedbackLw(null, mSafeMode + ? HapticFeedbackConstants.SAFE_MODE_ENABLED + : HapticFeedbackConstants.SAFE_MODE_DISABLED, true); + Log.i(TAG, "SAFEMODE: " + mSafeMode + "menu=" + menuState + " s=" + sState + + " dpad=" + dpadState + " trackball=" + trackballState + ")"); return mSafeMode; } catch (RemoteException e) { // Doom! (it's also local) @@ -1994,25 +2016,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void systemReady() { - try { - if (mSafeMode) { - // If the user is holding the menu key code, then we are - // going to boot into safe mode. - ActivityManagerNative.getDefault().enterSafeMode(); - } - // tell the keyguard - mKeyguardMediator.onSystemReady(); - android.os.SystemProperties.set("dev.bootcomplete", "1"); - synchronized (mLock) { - updateOrientationListenerLp(); - mVibrator = new Vibrator(); - mLongPressVibePattern = getLongIntArray(mContext.getResources(), - com.android.internal.R.array.config_longPressVibePattern); - mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(), - com.android.internal.R.array.config_virtualKeyVibePattern); - } - } catch (RemoteException e) { - // Ignore + // tell the keyguard + mKeyguardMediator.onSystemReady(); + android.os.SystemProperties.set("dev.bootcomplete", "1"); + synchronized (mLock) { + updateOrientationListenerLp(); } } @@ -2177,6 +2185,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { case HapticFeedbackConstants.LONG_PRESS: mVibrator.vibrate(mLongPressVibePattern, -1); return true; + case HapticFeedbackConstants.VIRTUAL_KEY: + mVibrator.vibrate(mVirtualKeyVibePattern, -1); + return true; + case HapticFeedbackConstants.SAFE_MODE_DISABLED: + mVibrator.vibrate(mSafeModeDisabledVibePattern, -1); + return true; + case HapticFeedbackConstants.SAFE_MODE_ENABLED: + mVibrator.vibrate(mSafeModeEnabledVibePattern, -1); + return true; } return false; } @@ -2184,10 +2201,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void keyFeedbackFromInput(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN && (event.getFlags()&KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) { - if (Settings.System.getInt(mContext.getContentResolver(), - Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) != 0) { - mVibrator.vibrate(mVirtualKeyVibePattern, -1); - } + performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false); } } -- GitLab From 8ed9870f54eb06e32f3639cd4f2852876bfc1666 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Tue, 29 Sep 2009 02:52:12 -0700 Subject: [PATCH 128/458] Fix for 2133391: Allow menu hard key to be disabled in LockScreen on some devices Changed to use config.xml and overlays to enable. --- policy/com/android/internal/policy/impl/LockScreen.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 67533242f514..13207b70b0c7 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -81,6 +81,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private java.text.DateFormat mDateFormat; private java.text.DateFormat mTimeFormat; private boolean mCreatedInPortrait; + private boolean mDisableMenuKeyInLockScreen; /** * The status of this lock screen. @@ -149,6 +150,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mUpdateMonitor = updateMonitor; mCallback = callback; + mDisableMenuKeyInLockScreen = getResources() + .getBoolean(R.bool.config_disableMenuKeyInLockScreen); + mCreatedInPortrait = updateMonitor.isInPortrait(); final LayoutInflater inflater = LayoutInflater.from(context); @@ -213,7 +217,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU) { + if (keyCode == KeyEvent.KEYCODE_MENU && !mDisableMenuKeyInLockScreen) { mCallback.goToUnlockScreen(); } return false; -- GitLab From 63b90f28858b9d259a1d4a145f51bdd36ada8730 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 29 Sep 2009 16:14:59 -0700 Subject: [PATCH 129/458] Fix issue #2153749: Window manager deadlock around the Eclair lock screen Don't synchronously call into the account manager from the lock screen. Change-Id: I2741c81bb31537ddfcce96b1b199ac50fd48e727 --- .../policy/impl/LockPatternKeyguardView.java | 50 +++++++++++++------ .../internal/policy/impl/UnlockScreen.java | 10 ++-- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 7a81c056b732..b5add6483444 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -20,7 +20,12 @@ import com.android.internal.R; import com.android.internal.telephony.IccCard; import com.android.internal.widget.LockPatternUtils; +import android.accounts.Account; import android.accounts.AccountManager; +import android.accounts.AccountManagerCallback; +import android.accounts.AccountManagerFuture; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; import android.app.AlertDialog; import android.content.Context; import android.content.Intent; @@ -37,6 +42,8 @@ import android.view.KeyEvent; import android.view.View; import android.view.WindowManager; +import java.io.IOException; + /** * The host view for all of the screens of the pattern unlock screen. There are * two {@link Mode}s of operation, lock and unlock. This will show the appropriate @@ -48,7 +55,8 @@ import android.view.WindowManager; * {@link com.android.internal.policy.impl.KeyguardViewManager} * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate. */ -public class LockPatternKeyguardView extends KeyguardViewBase { +public class LockPatternKeyguardView extends KeyguardViewBase + implements AccountManagerCallback { // intent action for launching emergency dialer activity. static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL"; @@ -141,6 +149,22 @@ public class LockPatternKeyguardView extends KeyguardViewBase { && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT); } + public void run(AccountManagerFuture future) { + // We err on the side of caution. + // In case of error we assume we have a SAML account. + boolean hasSAMLAccount = true; + try { + hasSAMLAccount = future.getResult().length > 0; + } catch (OperationCanceledException e) { + } catch (IOException e) { + } catch (AuthenticatorException e) { + } + mEnableFallback = !hasSAMLAccount; + if (mUnlockScreen instanceof UnlockScreen) { + ((UnlockScreen)mUnlockScreen).setEnableFallback(true); + } + } + /** * @param context Used to inflate, and create views. * @param updateMonitor Knows the state of the world, and passed along to each @@ -156,25 +180,18 @@ public class LockPatternKeyguardView extends KeyguardViewBase { super(context); final boolean hasAccount = AccountManager.get(context).getAccounts().length > 0; - boolean hasSAMLAccount = false; if (hasAccount) { /* If we have a SAML account which requires web login we can not use the fallback screen UI to ask the user for credentials. For now we will disable fallback screen in this case. Ultimately we could consider bringing up a web login from GLS but need to make sure that it will work in the "locked screen" mode. */ - try { - String[] features = new String[] {"saml"}; - hasSAMLAccount = - AccountManager.get(context).getAccountsByTypeAndFeatures( - "com.google.GAIA", features, null, null).getResult().length > 0; - } catch (Exception e) { - // We err on the side of caution. - // In case of error we assume we have a SAML account. - hasSAMLAccount = true; - } + String[] features = new String[] {"saml"}; + AccountManager.get(context).getAccountsByTypeAndFeatures( + "com.google.GAIA", features, this, null); } - mEnableFallback = hasAccount && !hasSAMLAccount; + + mEnableFallback = false; mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); @@ -452,13 +469,14 @@ public class LockPatternKeyguardView extends KeyguardViewBase { View createUnlockScreenFor(UnlockMode unlockMode) { if (unlockMode == UnlockMode.Pattern) { - return new UnlockScreen( + UnlockScreen view = new UnlockScreen( mContext, mLockPatternUtils, mUpdateMonitor, mKeyguardScreenCallback, - mUpdateMonitor.getFailedAttempts(), - mEnableFallback); + mUpdateMonitor.getFailedAttempts()); + view.setEnableFallback(mEnableFallback); + return view; } else if (unlockMode == UnlockMode.SimPin) { return new SimUnlockScreen( mContext, diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index 915e6ab40e24..a5032b3ae0c5 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -67,7 +67,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient /** * whether there is a fallback option available when the pattern is forgotten. */ - private final boolean mEnableFallback; + private boolean mEnableFallback; private boolean mCreatedInPortrait; @@ -154,14 +154,12 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient LockPatternUtils lockPatternUtils, KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback, - int totalFailedAttempts, - boolean enableFallback) { + int totalFailedAttempts) { super(context); mLockPatternUtils = lockPatternUtils; mUpdateMonitor = updateMonitor; mCallback = callback; mTotalFailedPatternAttempts = totalFailedAttempts; - mEnableFallback = enableFallback; mFailedPatternAttemptsSinceLastTimeout = totalFailedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; if (mUpdateMonitor.isInPortrait()) { @@ -242,6 +240,10 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mUpdateMonitor.getTelephonySpn())); } + public void setEnableFallback(boolean state) { + mEnableFallback = state; + } + private void resetStatusInfo() { mInstructions = null; mShowingBatteryInfo = mUpdateMonitor.shouldShowBatteryInfo(); -- GitLab From 563b3e61caee2471d7021cf46851e262108cb454 Mon Sep 17 00:00:00 2001 From: Costin Manolache Date: Tue, 29 Sep 2009 18:58:36 -0700 Subject: [PATCH 130/458] Remove GAIA string --- .../android/internal/policy/impl/LockPatternKeyguardView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index b5add6483444..1f1a1d48ae4e 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -188,7 +188,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase but need to make sure that it will work in the "locked screen" mode. */ String[] features = new String[] {"saml"}; AccountManager.get(context).getAccountsByTypeAndFeatures( - "com.google.GAIA", features, this, null); + "com.google", features, this, null); } mEnableFallback = false; -- GitLab From db460fe7cfbf7f1dc5fda3cf5686af830edcc395 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Thu, 1 Oct 2009 08:15:40 -0400 Subject: [PATCH 131/458] Move status bar disabling from KeyguardViewMediator to Phone app This allows us to disable the keyguard while docked without disabling the status bar. Change-Id: I06ff48dcb1922a26e356faee0aefa91b7c871e6a Signed-off-by: Mike Lockwood --- .../policy/impl/KeyguardViewMediator.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index f8bc3e67fb00..3ae1dee6bba9 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -22,9 +22,6 @@ import com.android.internal.widget.LockPatternUtils; import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.PendingIntent; -import android.app.StatusBarManager; -import static android.app.StatusBarManager.DISABLE_EXPAND; -import static android.app.StatusBarManager.DISABLE_NONE; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -160,11 +157,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ private PowerManager.WakeLock mWakeAndHandOff; - /** - * Used to disable / reenable status bar expansion. - */ - private StatusBarManager mStatusBarManager; - private KeyguardViewManager mKeyguardViewManager; // these are protected by synchronized (this) @@ -349,14 +341,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (DEBUG) Log.d(TAG, "remembering to reshow, hiding keyguard, " + "disabling status bar expansion"); mNeedToReshowWhenReenabled = true; - setStatusBarExpandable(false); hideLocked(); } else if (enabled && mNeedToReshowWhenReenabled) { // reenabled after previously hidden, reshow if (DEBUG) Log.d(TAG, "previously hidden, reshowing, reenabling " + "status bar expansion"); mNeedToReshowWhenReenabled = false; - setStatusBarExpandable(true); if (mExitSecureCallback != null) { if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting"); @@ -411,15 +401,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } } - - private void setStatusBarExpandable(boolean isExpandable) { - if (mStatusBarManager == null) { - mStatusBarManager = - (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); - } - mStatusBarManager.disable(isExpandable ? DISABLE_NONE : DISABLE_EXPAND); - } - /** * Is the keyguard currently showing? */ @@ -744,7 +725,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // the keyguard when they've released the lock mExternallyEnabled = true; mNeedToReshowWhenReenabled = false; - setStatusBarExpandable(true); } } } -- GitLab From 3754b0d5635c699fac0bc24757d531b54f336c09 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Thu, 1 Oct 2009 14:50:15 -0400 Subject: [PATCH 132/458] Make sure we wake up the screen if the keyguard is not visible when we think it should be. I am hoping this will fix bug b/2155529 Change-Id: I46ea34898864d7b39391d76b802858c0f092b578 Signed-off-by: Mike Lockwood --- .../android/internal/policy/impl/KeyguardViewManager.java | 6 +++++- .../android/internal/policy/impl/KeyguardViewMediator.java | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index 0facbf6cbbd2..910df8d0e870 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -197,10 +197,14 @@ public class KeyguardViewManager implements KeyguardWindowController { * * @param keyCode The wake key. */ - public void wakeWhenReadyTq(int keyCode) { + public boolean wakeWhenReadyTq(int keyCode) { if (DEBUG) Log.d(TAG, "wakeWhenReady(" + keyCode + ")"); if (mKeyguardView != null) { mKeyguardView.wakeWhenReadyTq(keyCode); + return true; + } else { + Log.w(TAG, "mKeyguardView is null in wakeWhenReadyTq"); + return false; } } diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 3ae1dee6bba9..5a527726293d 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -884,7 +884,10 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // this should result in a call to 'poke wakelock' which will set a timeout // on releasing the wakelock - mKeyguardViewManager.wakeWhenReadyTq(keyCode); + if (!mKeyguardViewManager.wakeWhenReadyTq(keyCode)) { + // poke wakelock ourselves if keyguard is no longer active + pokeWakelock(); + } /** * Now that the keyguard is ready and has poked the wake lock, we can -- GitLab From 4c48b6b410dca901437b838b98e1b0923303ce9a Mon Sep 17 00:00:00 2001 From: David Brown Date: Thu, 1 Oct 2009 19:27:44 -0700 Subject: [PATCH 133/458] Add placeholder onGrabbedStateChange() method. Update LockScreen to implement the latest RotarySelector OnDialTriggerListener interface. In a followup CL we'll use this to display onscreen hint text while dragging. BUG=2158434 DRNO=timsullivan TESTED=exercised the lock screen widget, confirmed there's no new behavior. --- policy/com/android/internal/policy/impl/LockScreen.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 13207b70b0c7..32736f838d36 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -247,6 +247,11 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } } + /** {@inheritDoc} */ + public void onGrabbedStateChange(View v, int grabbedState) { + // TODO: Update onscreen hint text based on the new state. + } + /** * Displays a message in a text view and then removes it. * @param textView The text view. @@ -556,4 +561,3 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mUpdateMonitor.removeCallback(this); } } - -- GitLab From 36931ac9b3cc2e8f60f730c51e715744b5c4f6c0 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Fri, 2 Oct 2009 16:49:10 -0700 Subject: [PATCH 134/458] Fix for 2129239: Always enable the menu hard key in LockScreen when 'ro.monkey' is set. BUG=2129239 DRNO=discussed with hiroshi/mcleron who gave thumbs up. --- policy/com/android/internal/policy/impl/LockScreen.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 32736f838d36..a9f35467293e 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -30,6 +30,8 @@ import android.widget.*; import android.graphics.drawable.Drawable; import android.util.Log; import android.media.AudioManager; +import android.os.SystemProperties; + import com.android.internal.telephony.IccCard; import java.util.Date; @@ -151,7 +153,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mCallback = callback; mDisableMenuKeyInLockScreen = getResources() - .getBoolean(R.bool.config_disableMenuKeyInLockScreen); + .getBoolean(R.bool.config_disableMenuKeyInLockScreen) + && !SystemProperties.getBoolean("ro.monkey", false); mCreatedInPortrait = updateMonitor.isInPortrait(); -- GitLab From 73b1ec8961d33776d5d55e3402a7dd9acafca763 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Sun, 4 Oct 2009 13:33:00 -0700 Subject: [PATCH 135/458] Work on issue #2163789: Way too much logging Dr.No from mcleron. Change-Id: I44d49221b15a6ae2c22504869b14d610d234ccc9 --- .../android/internal/policy/impl/PhoneWindowManager.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index b6b6b777e310..12821e98af0b 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1993,8 +1993,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { performHapticFeedbackLw(null, mSafeMode ? HapticFeedbackConstants.SAFE_MODE_ENABLED : HapticFeedbackConstants.SAFE_MODE_DISABLED, true); - Log.i(TAG, "SAFEMODE: " + mSafeMode + "menu=" + menuState + " s=" + sState - + " dpad=" + dpadState + " trackball=" + trackballState + ")"); + if (mSafeMode) { + Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState + + " dpad=" + dpadState + " trackball=" + trackballState + ")"); + } else { + Log.i(TAG, "SAFE MODE not enabled"); + } return mSafeMode; } catch (RemoteException e) { // Doom! (it's also local) -- GitLab From 261259b673fbc86e4b04c458e12342f292e7a4f3 Mon Sep 17 00:00:00 2001 From: Fred Quintana Date: Fri, 2 Oct 2009 17:19:24 -0700 Subject: [PATCH 136/458] account manager api review changes --- .../internal/policy/impl/AccountUnlockScreen.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index 069f97e6e3c4..d80949d86d83 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -42,6 +42,7 @@ import android.widget.RelativeLayout; import android.widget.TextView; import android.app.Dialog; import android.app.ProgressDialog; +import android.os.Bundle; import java.io.IOException; @@ -261,16 +262,19 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree return; } getProgressDialog().show(); - AccountManager.get(mContext).confirmPassword( - account, password, new AccountManagerCallback() { - public void run(AccountManagerFuture future) { + Bundle options = new Bundle(); + options.putString(AccountManager.KEY_PASSWORD, password); + AccountManager.get(mContext).confirmCredentials(account, options, null /* activity */, + new AccountManagerCallback() { + public void run(AccountManagerFuture future) { try { mCallback.pokeWakelock(AWAKE_POKE_MILLIS); - final boolean result = future.getResult(); + final Bundle result = future.getResult(); + final boolean verified = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT); // ensure on UI thread mLogin.post(new Runnable() { public void run() { - onCheckPasswordResult(result); + onCheckPasswordResult(verified); } }); } catch (OperationCanceledException e) { -- GitLab From 206f07d3bebb6716bca8d1bcd56d507a5c97bf76 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Mon, 5 Oct 2009 16:03:31 -0400 Subject: [PATCH 137/458] Add some logging to help diagnose b/2164183 Change-Id: I0f10425e89cba9e9ddbd3ce58ad1ae0a3ae74f34 Signed-off-by: Mike Lockwood --- .../com/android/internal/policy/impl/KeyguardViewMediator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 5a527726293d..680f94217752 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -886,6 +886,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // on releasing the wakelock if (!mKeyguardViewManager.wakeWhenReadyTq(keyCode)) { // poke wakelock ourselves if keyguard is no longer active + Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock, so poke it ourselves"); pokeWakelock(); } @@ -896,7 +897,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mWakeAndHandOff.release(); if (!mWakeLock.isHeld()) { - Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock"); + Log.w(TAG, "mWakeLock not held in mKeyguardViewManager.wakeWhenReadyTq"); } } } -- GitLab From 674d3e40212d077c06f46589992f6e16c6c1b22d Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Tue, 6 Oct 2009 09:28:54 -0400 Subject: [PATCH 138/458] Hold a partial wakelock while showing the keyguard This ensures that the keyguard is fully displayed before the processor suspends, which avoids a race condition when the device is powered back up. Fixes one instance of bug b/2164183 Change-Id: Ifd7f928068cf779ec725937db82af69306c02107 Signed-off-by: Mike Lockwood --- .../internal/policy/impl/KeyguardViewMediator.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 680f94217752..34b5e3a3850e 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -149,6 +149,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ private PowerManager.WakeLock mWakeLock; + /** + * Used to keep the device awake while to ensure the keyguard finishes opening before + * we sleep. + */ + private PowerManager.WakeLock mShowKeyguardWakeLock; + /** * Does not turn on screen, held while a call to {@link KeyguardViewManager#wakeWhenReadyTq(int)} * is called to make sure the device doesn't sleep before it has a chance to poke @@ -224,6 +230,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "keyguard"); mWakeLock.setReferenceCounted(false); + mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard"); + mShowKeyguardWakeLock.setReferenceCounted(false); mWakeAndHandOff = mPM.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, @@ -542,6 +550,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ private void showLocked() { if (DEBUG) Log.d(TAG, "showLocked"); + // ensure we stay awake until we are finished displaying the keyguard + mShowKeyguardWakeLock.acquire(); Message msg = mHandler.obtainMessage(SHOW); mHandler.sendMessage(msg); } @@ -855,6 +865,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, ActivityManagerNative.getDefault().closeSystemDialogs("lock"); } catch (RemoteException e) { } + mShowKeyguardWakeLock.release(); } } -- GitLab From d70bc2f662b315e09a2afbb0e2331c9de0f7fecd Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 6 Oct 2009 23:25:51 -0700 Subject: [PATCH 139/458] Fix #2163209: alarm clock rings but is hidden behind lock screen The lock screen's flag to force the status bar on was sometimes interfering with the flag of the alarm behind to hide the lock screen. Change-Id: I91368c56d09d35b03db548530aa1eb59197206bd --- .../internal/policy/impl/PhoneWindowManager.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 12821e98af0b..cec41f79ddfd 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1366,7 +1366,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (win.isVisibleLw()) { if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { mForceStatusBar = true; - } else if (mTopFullscreenOpaqueWindowState == null + } + if (mTopFullscreenOpaqueWindowState == null && attrs.type >= FIRST_APPLICATION_WINDOW && attrs.type <= LAST_APPLICATION_WINDOW && win.fillsScreenLw(mW, mH, false, false)) { @@ -1407,8 +1408,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { int changes = 0; boolean hiding = false; if (mStatusBar != null) { - //Log.i(TAG, "force=" + mForceStatusBar - // + " top=" + mTopFullscreenOpaqueWindowState); + if (localLOGV) Log.i(TAG, "force=" + mForceStatusBar + + " top=" + mTopFullscreenOpaqueWindowState); if (mForceStatusBar) { if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; @@ -1435,7 +1436,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mKeyguard != null) { if (localLOGV) Log.v(TAG, "finishLayoutLw::mHideKeyguard="+mHideLockScreen); if (mDismissKeyguard && !mKeyguardMediator.isSecure()) { - if (mKeyguard.hideLw(true)) { + if (mKeyguard.hideLw(false)) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; @@ -1448,7 +1449,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { }); } } else if (mHideLockScreen) { - if (mKeyguard.hideLw(true)) { + if (mKeyguard.hideLw(false)) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; -- GitLab From 6c0a563e6770fcd5d5efc7896b7db3708d50cc38 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Wed, 7 Oct 2009 01:30:21 -0700 Subject: [PATCH 140/458] Partial fix for 2069703: Fix race condition in KeyguardViewManager.hide() that could result in a blank screen. This fixes a race condition seen whenever show() is called before the timer in hide() triggers. This can happen for example if the user hits "Emergency Dial" followed by the back button before the 0.5s timeout completes. The result is a blank screen with no keyguard view and no means to recover on devices w/o a keyboard. The bug caused us to sometimes remove the newly created KeyguardView instead of the old one, leaving the view empty. The fix is to always remove the last view. --- .../internal/policy/impl/KeyguardViewManager.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index 910df8d0e870..bac2fcada11f 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -48,7 +48,7 @@ public class KeyguardViewManager implements KeyguardWindowController { private WindowManager.LayoutParams mWindowLayoutParams; private boolean mNeedsInput = false; - + private FrameLayout mKeyguardHost; private KeyguardViewBase mKeyguardView; @@ -154,7 +154,7 @@ public class KeyguardViewManager implements KeyguardWindowController { mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); } } - + /** * Reset the state of the view. */ @@ -218,15 +218,13 @@ public class KeyguardViewManager implements KeyguardWindowController { // Don't do this right away, so we can let the view continue to animate // as it goes away. if (mKeyguardView != null) { - final View lastView = mKeyguardView; + final KeyguardViewBase lastView = mKeyguardView; + mKeyguardView = null; mKeyguardHost.postDelayed(new Runnable() { public void run() { synchronized (KeyguardViewManager.this) { - if (mKeyguardView == lastView) { - mKeyguardHost.removeView(mKeyguardView); - mKeyguardView.cleanUp(); - mKeyguardView = null; - } + mKeyguardHost.removeView(lastView); + lastView.cleanUp(); } } }, 500); -- GitLab From 80fa166bf6da3eb4f39f9f021e753537f1d3a2f5 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 7 Oct 2009 14:02:10 -0700 Subject: [PATCH 141/458] Fix issue #2171766: Device can go to sleep while in dock The issue I saw was then when plugging into the dock, we the battery first is in the "USB" state before going to "AC". The phone window manager would pick up the first state, but not the second. This change reworks this code to always monitor the battery status while plugged in to the dock, to update itself whenever that state changes. When not in the dock, we don't monitor, since this is only used to determine whether to keep the device on while in the dock. Change-Id: Ic1e8b584082a44c4e5df13ee19dab450775027f6 --- .../policy/impl/PhoneWindowManager.java | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index cec41f79ddfd..549fb8729647 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -190,6 +190,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mLidOpen; int mPlugged; + boolean mRegisteredBatteryReceiver; int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; int mLidOpenRotation; int mCarDockRotation; @@ -531,13 +532,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mLidNavigationAccessibility = mContext.getResources().getInteger( com.android.internal.R.integer.config_lidNavigationAccessibility); // register for battery events - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_POWER_CONNECTED); - intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED); - context.registerReceiver(mPowerReceiver, intentFilter); mBatteryStatusFilter.addAction(Intent.ACTION_BATTERY_CHANGED); mPlugged = 0; - updatePlugged(); + updatePlugged(context.registerReceiver(null, mBatteryStatusFilter)); // register for dock events context.registerReceiver(mDockReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT)); mVibrator = new Vibrator(); @@ -551,8 +548,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.array.config_safeModeEnabledVibePattern); } - void updatePlugged() { - Intent powerIntent = mContext.registerReceiver(null, mBatteryStatusFilter); + void updatePlugged(Intent powerIntent) { if (localLOGV) Log.v(TAG, "New battery status: " + powerIntent.getExtras()); if (powerIntent != null) { mPlugged = powerIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); @@ -1832,14 +1828,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; - BroadcastReceiver mPowerReceiver = new BroadcastReceiver() { + BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())) { - updatePlugged(); - } else if (Intent.ACTION_POWER_DISCONNECTED.equals(intent.getAction())) { - updatePlugged(); - } - updateKeepScreenOn(); + updatePlugged(intent); + updateDockKeepingScreenOn(); } }; @@ -1847,8 +1839,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void onReceive(Context context, Intent intent) { mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); + boolean watchBattery = mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED; + if (watchBattery != mRegisteredBatteryReceiver) { + mRegisteredBatteryReceiver = watchBattery; + if (watchBattery) { + updatePlugged(mContext.registerReceiver(mBatteryReceiver, + mBatteryStatusFilter)); + } else { + mContext.unregisterReceiver(mBatteryReceiver); + } + } updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); - updateKeepScreenOn(); + updateDockKeepingScreenOn(); updateOrientationListenerLp(); } }; @@ -2036,7 +2038,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); } - void updateKeepScreenOn() { + void updateDockKeepingScreenOn() { if (mPlugged != 0) { if (localLOGV) Log.v(TAG, "Update: mDockState=" + mDockState + " mPlugged=" + mPlugged -- GitLab From 8d93c3e46cc975b93a6c56d2813e5600d643b99d Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 7 Oct 2009 16:14:02 -0700 Subject: [PATCH 142/458] Fix issue #2171460: Turn off background blurring of power dialog Change-Id: I233929c363cac232de26dad20bc4011f12e3a5ab --- .../policy/impl/AccountUnlockScreen.java | 9 ++++++--- .../internal/policy/impl/GlobalActions.java | 7 +++++-- .../policy/impl/LockPatternKeyguardView.java | 18 ++++++++++++------ .../internal/policy/impl/PowerDialog.java | 7 +++++-- .../internal/policy/impl/SimUnlockScreen.java | 9 ++++++--- 5 files changed, 34 insertions(+), 16 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index d80949d86d83..7992dd8856a6 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -303,9 +303,12 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree mCheckingDialog.setCancelable(false); mCheckingDialog.getWindow().setType( WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - mCheckingDialog.getWindow().setFlags( - WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_sf_slowBlur)) { + mCheckingDialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + } } return mCheckingDialog; } diff --git a/policy/com/android/internal/policy/impl/GlobalActions.java b/policy/com/android/internal/policy/impl/GlobalActions.java index 7e15e647567a..2f1f024c5d89 100644 --- a/policy/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/com/android/internal/policy/impl/GlobalActions.java @@ -213,8 +213,11 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac final AlertDialog dialog = ab.create(); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); - dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_sf_slowBlur)) { + dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + } dialog.setOnDismissListener(this); diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 1f1a1d48ae4e..0ebd945600ef 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -575,9 +575,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase .setNeutralButton(R.string.ok, null) .create(); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - dialog.getWindow().setFlags( - WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_sf_slowBlur)) { + dialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + } dialog.show(); } @@ -595,9 +598,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase .setNeutralButton(R.string.ok, null) .create(); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - dialog.getWindow().setFlags( - WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_sf_slowBlur)) { + dialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + } dialog.show(); } diff --git a/policy/com/android/internal/policy/impl/PowerDialog.java b/policy/com/android/internal/policy/impl/PowerDialog.java index f4d4b049b397..de35bd7bd2cf 100644 --- a/policy/com/android/internal/policy/impl/PowerDialog.java +++ b/policy/com/android/internal/policy/impl/PowerDialog.java @@ -70,8 +70,11 @@ public class PowerDialog extends Dialog implements OnClickListener, setContentView(com.android.internal.R.layout.power_dialog); getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); - getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + 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); diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java index 0f7fe32a8278..3881d116fdfd 100644 --- a/policy/com/android/internal/policy/impl/SimUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/SimUnlockScreen.java @@ -182,9 +182,12 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie mSimUnlockProgressDialog.setCancelable(false); mSimUnlockProgressDialog.getWindow().setType( WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - mSimUnlockProgressDialog.getWindow().setFlags( - WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_sf_slowBlur)) { + mSimUnlockProgressDialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + } } return mSimUnlockProgressDialog; } -- GitLab From e7c8c7c1a49c05fcb075c362c67ac61f7dfdbed5 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 7 Oct 2009 21:27:43 -0700 Subject: [PATCH 143/458] More fix #2163209: alarm clock rings but is hidden behind lock screen Another way we could miss the application's flags is because the system now force hides application windows behind the lock screen. So we need to use this new API to actually take those into account when looking for the top-most window that can specify for the lock screen to be removed or hidden. I have tested with pulling the device in and out of the desktop with all kinds of random speeds and ways and this -seems- to now cover everything. Keeping fingers crossed. Change-Id: Ice640eea6ee06ee27f069d60856fb394c7eeae51 --- .../android/internal/policy/impl/PhoneWindowManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 549fb8729647..4699638bb104 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1359,12 +1359,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { win.computeFrameLw(pf, df, cf, vf); - if (win.isVisibleLw()) { + if (mTopFullscreenOpaqueWindowState == null && + win.isVisibleOrBehindKeyguardLw()) { if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { mForceStatusBar = true; } - if (mTopFullscreenOpaqueWindowState == null - && attrs.type >= FIRST_APPLICATION_WINDOW + if (attrs.type >= FIRST_APPLICATION_WINDOW && attrs.type <= LAST_APPLICATION_WINDOW && win.fillsScreenLw(mW, mH, false, false)) { if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win); -- GitLab From b4a584215719c3c2ec27d020654d9e143bc33bc1 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Thu, 8 Oct 2009 14:31:25 -0400 Subject: [PATCH 144/458] Ignore requests to hide the keyguard if we are in the process of waking up. This should fix a race condition that results in the screen waking up and displaying nothing but wall paper Bug b/2168660 Change-Id: I55bac0aaab8425cde282e7fc7e7c6b82217fbc9d Signed-off-by: Mike Lockwood --- .../android/internal/policy/impl/KeyguardViewMediator.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 34b5e3a3850e..dc243c45f4b0 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -876,6 +876,10 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private void handleHide() { synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleHide"); + if (mWakeAndHandOff.isHeld()) { + Log.w(TAG, "attempt to hide the keyguard while waking, ignored"); + return; + } // When we go away, tell the poewr manager to honor requests from userActivity. mRealPowerManager.enableUserActivity(true); -- GitLab From 22dfe722dfb1094cfc5be0f155f3930bf39e5d61 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Wed, 7 Oct 2009 01:30:21 -0700 Subject: [PATCH 145/458] Cherry-pick from mr2 to eclair: DO NOT MERGE commit 149c0543a3d5f450686b7c3d142ac5f8fcf61ed4 BUG=2176949 Partial fix for 2069703: Fix race condition in KeyguardViewManager.hide() that could result in a blank screen. This fixes a race condition seen whenever show() is called before the timer in hide() triggers. This can happen for example if the user hits "Emergency Dial" followed by the back button before the 0.5s timeout completes. The result is a blank screen with no keyguard view and no means to recover on devices w/o a keyboard. The bug caused us to sometimes remove the newly created KeyguardView instead of the old one, leaving the view empty. The fix is to always remove the last view. --- .../internal/policy/impl/KeyguardViewManager.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index 910df8d0e870..bac2fcada11f 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -48,7 +48,7 @@ public class KeyguardViewManager implements KeyguardWindowController { private WindowManager.LayoutParams mWindowLayoutParams; private boolean mNeedsInput = false; - + private FrameLayout mKeyguardHost; private KeyguardViewBase mKeyguardView; @@ -154,7 +154,7 @@ public class KeyguardViewManager implements KeyguardWindowController { mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); } } - + /** * Reset the state of the view. */ @@ -218,15 +218,13 @@ public class KeyguardViewManager implements KeyguardWindowController { // Don't do this right away, so we can let the view continue to animate // as it goes away. if (mKeyguardView != null) { - final View lastView = mKeyguardView; + final KeyguardViewBase lastView = mKeyguardView; + mKeyguardView = null; mKeyguardHost.postDelayed(new Runnable() { public void run() { synchronized (KeyguardViewManager.this) { - if (mKeyguardView == lastView) { - mKeyguardHost.removeView(mKeyguardView); - mKeyguardView.cleanUp(); - mKeyguardView = null; - } + mKeyguardHost.removeView(lastView); + lastView.cleanUp(); } } }, 500); -- GitLab From fcb39240b15402c2f5e4ba6fe91c916e9a6039f1 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 21 Oct 2009 23:01:07 -0400 Subject: [PATCH 146/458] Disable key repeats when the screen is off. This prevents an endless stream of key repeats spamming the keyguard if a volume key is pressed at the same time you turn off the screen with the power button. This is part of a fix for bug b/2198537 Change-Id: I0d7e335fee79cbebba96b2cd908458c3c94c839e Signed-off-by: Mike Lockwood --- .../com/android/internal/policy/impl/PhoneWindowManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 4699638bb104..d376341df618 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -2218,5 +2218,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); } } + + public boolean allowKeyRepeat() { + // disable key repeat when screen is off + return mScreenOn; + } } -- GitLab From 75d3caafc48987ea4477672d8608cde463af8123 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Thu, 22 Oct 2009 13:14:31 -0400 Subject: [PATCH 147/458] When phone is ringing, power button should hang up phone in addition to turning off the screen. Fixes bug b/2201585 (Pressing power button when phone ringing should mute ringer) Change-Id: Ief3e26044f9b0ceaf41c5dc6be52f0d1e9897810 Signed-off-by: Mike Lockwood --- .../policy/impl/PhoneWindowManager.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index d376341df618..135dc83e6577 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1686,19 +1686,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { // key repeats are generated by the window manager, and we don't see them // here, so unless the driver is doing something it shouldn't be, we know // this is the real press event. - if (code == KeyEvent.KEYCODE_ENDCALL) { + ITelephony phoneServ = getPhoneInterface(); + if (phoneServ != null) { try { - ITelephony phoneServ = getPhoneInterface(); - if (phoneServ != null) { + // power button should hang up only when ringing + // but not after the call has been answered + if (code == KeyEvent.KEYCODE_ENDCALL || phoneServ.isRinging()) { hungUp = phoneServ.endCall(); - } else { - Log.w(TAG, "!!! Unable to find ITelephony interface !!!"); } } catch (RemoteException ex) { - Log.w(TAG, "ITelephony.endCall() threw RemoteException" + ex); + Log.w(TAG, "ITelephony threw RemoteException" + ex); } + } else { + Log.w(TAG, "!!! Unable to find ITelephony interface !!!"); } - if (hungUp || !screenIsOn) { + // power button should turn off screen in addition to hanging up the phone + if ((hungUp && code != KeyEvent.KEYCODE_POWER) || !screenIsOn) { mShouldTurnOffOnKeyUp = false; } else { // only try to turn off the screen if we didn't already hang up -- GitLab From 2eb4796590e068b7089524f3a521cc2ecbe3f124 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Fri, 23 Oct 2009 11:29:52 -0400 Subject: [PATCH 148/458] When phone is ringing, power button should only mute the ringer, not hang up. Fixes my previous fix for bug b/2201585 (Pressing power button when phone ringing should mute ringer) Change-Id: I9460e21245b9719f715818f7ad878b121857d773 Signed-off-by: Mike Lockwood --- .../internal/policy/impl/PhoneWindowManager.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 135dc83e6577..df8b265917e4 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1682,17 +1682,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (code == KeyEvent.KEYCODE_ENDCALL || code == KeyEvent.KEYCODE_POWER) { if (down) { - boolean hungUp = false; + boolean handled = false; // key repeats are generated by the window manager, and we don't see them // here, so unless the driver is doing something it shouldn't be, we know // this is the real press event. ITelephony phoneServ = getPhoneInterface(); if (phoneServ != null) { try { - // power button should hang up only when ringing - // but not after the call has been answered - if (code == KeyEvent.KEYCODE_ENDCALL || phoneServ.isRinging()) { - hungUp = phoneServ.endCall(); + if (code == KeyEvent.KEYCODE_ENDCALL) { + handled = phoneServ.endCall(); + } else if (code == KeyEvent.KEYCODE_POWER && phoneServ.isRinging()) { + // Pressing power during incoming call should silence the ringer + phoneServ.silenceRinger(); + handled = true; } } catch (RemoteException ex) { Log.w(TAG, "ITelephony threw RemoteException" + ex); @@ -1701,7 +1703,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Log.w(TAG, "!!! Unable to find ITelephony interface !!!"); } // power button should turn off screen in addition to hanging up the phone - if ((hungUp && code != KeyEvent.KEYCODE_POWER) || !screenIsOn) { + if ((handled && code != KeyEvent.KEYCODE_POWER) || !screenIsOn) { mShouldTurnOffOnKeyUp = false; } else { // only try to turn off the screen if we didn't already hang up -- GitLab From 89b17225f89ea2092b215a6757ed2d240c24098d Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Tue, 27 Oct 2009 14:54:09 -0700 Subject: [PATCH 149/458] Fix for 2201954: Disable haptic feedback for hard keys while keyguard is showing --- .../com/android/internal/policy/impl/PhoneWindowManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index df8b265917e4..cd06d33f4b14 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -2189,8 +2189,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) { - if (!always && Settings.System.getInt(mContext.getContentResolver(), - Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) { + final boolean hapticsDisabled = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0; + if (!always && (hapticsDisabled || mKeyguardMediator.isShowing())) { return false; } switch (effectId) { -- GitLab From 1b152029cc681eca6fad21d3f9e81c84c334087b Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Wed, 28 Oct 2009 16:08:15 -0700 Subject: [PATCH 150/458] Fix 2201413: Enable login on Passion when there's no SIM --- .../android/internal/policy/impl/KeyguardViewMediator.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index dc243c45f4b0..0fba17b30c86 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -32,6 +32,7 @@ import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; +import android.os.SystemProperties; import android.telephony.TelephonyManager; import android.util.Config; import android.util.EventLog; @@ -469,9 +470,13 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } // if the setup wizard hasn't run yet, don't show + final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", + false); final boolean provisioned = mUpdateMonitor.isDeviceProvisioned(); final IccCard.State state = mUpdateMonitor.getSimState(); - final boolean lockedOrMissing = state.isPinLocked() || (state == IccCard.State.ABSENT); + final boolean lockedOrMissing = state.isPinLocked() + || ((state == IccCard.State.ABSENT) && requireSim); + if (!lockedOrMissing && !provisioned) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned" + " and the sim is not locked or missing"); -- GitLab From bd998018ed028c1922d3cf14aeabe24ff1818761 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Tue, 3 Nov 2009 13:56:39 -0800 Subject: [PATCH 151/458] Fix 2129239: Add an override method for enabling the menu key on signed builds. There are now 3 ways to enable the menu key: - by config file (config_disableMenuKeyInLockScreen) - by 'adb shell setprop ro.monkey=1' (for automated testing on userdebug builds) - by creating file '/data/local/enable_menu_key (for automated testing on signed user builds) Security: this only affects the insecure lock screen (not lock pattern) which is generally enabled. --- .../internal/policy/impl/LockScreen.java | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index a9f35467293e..dda509735971 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -21,6 +21,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.RotarySelector; import android.content.Context; +import android.content.res.Resources; import android.text.format.DateFormat; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -35,6 +36,7 @@ import android.os.SystemProperties; import com.android.internal.telephony.IccCard; import java.util.Date; +import java.io.File; import java.text.SimpleDateFormat; /** @@ -46,8 +48,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM KeyguardUpdateMonitor.SimStateCallback, KeyguardUpdateMonitor.ConfigurationChangeCallback, RotarySelector.OnDialTriggerListener { - static private final boolean DBG = false; - static private final String TAG = "LockScreen"; + private static final boolean DBG = false; + private static final String TAG = "LockScreen"; + private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key"; private Status mStatus = Status.Normal; @@ -83,7 +86,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private java.text.DateFormat mDateFormat; private java.text.DateFormat mTimeFormat; private boolean mCreatedInPortrait; - private boolean mDisableMenuKeyInLockScreen; + private boolean mEnableMenuKeyInLockScreen; /** * The status of this lock screen. @@ -136,6 +139,20 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } } + /** + * 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 + * is prone to false positives. + * + * @return true if the menu key should be enabled + */ + private boolean shouldEnableMenuKey() { + final Resources res = getResources(); + final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen); + final boolean isMonkey = SystemProperties.getBoolean("ro.monkey", false); + final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists(); + return !configDisabled || isMonkey || fileOverride; + } /** * @param context Used to setup the view. @@ -152,9 +169,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mUpdateMonitor = updateMonitor; mCallback = callback; - mDisableMenuKeyInLockScreen = getResources() - .getBoolean(R.bool.config_disableMenuKeyInLockScreen) - && !SystemProperties.getBoolean("ro.monkey", false); + mEnableMenuKeyInLockScreen = shouldEnableMenuKey(); mCreatedInPortrait = updateMonitor.isInPortrait(); @@ -220,7 +235,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU && !mDisableMenuKeyInLockScreen) { + if (keyCode == KeyEvent.KEYCODE_MENU && mEnableMenuKeyInLockScreen) { mCallback.goToUnlockScreen(); } return false; -- GitLab From 09a404081a12a4afbf61b347ec8454e1d702ea1a Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Sun, 8 Nov 2009 00:33:23 -0500 Subject: [PATCH 152/458] Do not apply keyguard's short timeout when the keyguard is hidden by another window. Fixes bug b/2215852 (Music player doesn't grab screen wakelock) Change-Id: I6c402cdb460d216314ad72e37dbcdc7e19518941 Signed-off-by: Mike Lockwood --- .../policy/impl/KeyguardViewMediator.java | 26 ++++++++++++++----- .../policy/impl/PhoneWindowManager.java | 2 ++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 0fba17b30c86..bfa48eec7d64 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -184,6 +184,9 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // answer whether the input should be restricted) private boolean mShowing = false; + // true if the keyguard is hidden by another window + private boolean mHidden = false; + /** * Helps remember whether the screen has turned on since the last time * it turned off due to timeout. see {@link #onScreenTurnedOff(int)} @@ -417,6 +420,16 @@ public class KeyguardViewMediator implements KeyguardViewCallback, return mShowing; } + /** + * Notify us when the keyguard is hidden by another window + */ + public void setHidden(boolean isHidden) { + synchronized (KeyguardViewMediator.this) { + mHidden = isHidden; + adjustUserActivityLocked(); + } + } + /** * Given the state of the keyguard, is the input restricted? * Input is restricted when the keyguard is showing, or when the keyguard @@ -860,12 +873,9 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (DEBUG) Log.d(TAG, "handleShow"); if (!mSystemReady) return; - // while we're showing, we control the wake state, so ask the power - // manager not to honor request for userActivity. - mRealPowerManager.enableUserActivity(false); - mKeyguardViewManager.show(); mShowing = true; + adjustUserActivityLocked(); try { ActivityManagerNative.getDefault().closeSystemDialogs("lock"); } catch (RemoteException e) { @@ -885,14 +895,18 @@ public class KeyguardViewMediator implements KeyguardViewCallback, Log.w(TAG, "attempt to hide the keyguard while waking, ignored"); return; } - // When we go away, tell the poewr manager to honor requests from userActivity. - mRealPowerManager.enableUserActivity(true); mKeyguardViewManager.hide(); mShowing = false; + adjustUserActivityLocked(); } } + private void adjustUserActivityLocked() { + // disable user activity if we are shown and not hidden + mRealPowerManager.enableUserActivity(!mShowing || mHidden); + } + /** * Handle message sent by {@link #wakeWhenReadyLocked(int)} * @param keyCode The key that woke the device. diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index cd06d33f4b14..e57fbe8b544b 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1446,12 +1446,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } else if (mHideLockScreen) { if (mKeyguard.hideLw(false)) { + mKeyguardMediator.setHidden(true); changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; } } else { if (mKeyguard.showLw(false)) { + mKeyguardMediator.setHidden(false); changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; -- GitLab From b17b2fbcef9f02443be5db2cb1626f81c9dd4711 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Mon, 9 Nov 2009 16:01:37 -0500 Subject: [PATCH 153/458] Restore short screen timeout when keyguard is unhidden. This is part of a fix for bug b/2248320 (Lock screen does not time out after 5 seconds, after call-decline) Change-Id: I9ad8cc54fe50d8c9862eec27341fabbd0e871bdd Signed-off-by: Mike Lockwood --- .../internal/policy/impl/KeyguardViewMediator.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index bfa48eec7d64..f5591b213df5 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -424,6 +424,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, * Notify us when the keyguard is hidden by another window */ public void setHidden(boolean isHidden) { + if (DEBUG) Log.d(TAG, "setHidden " + isHidden); synchronized (KeyguardViewMediator.this) { mHidden = isHidden; adjustUserActivityLocked(); @@ -904,7 +905,13 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private void adjustUserActivityLocked() { // disable user activity if we are shown and not hidden - mRealPowerManager.enableUserActivity(!mShowing || mHidden); + if (DEBUG) Log.d(TAG, "adjustUserActivityLocked mShowing: " + mShowing + " mHidden: " + mHidden); + boolean enabled = !mShowing || mHidden; + mRealPowerManager.enableUserActivity(enabled); + if (!enabled && mScreenOn) { + // reinstate our short screen timeout policy + pokeWakelock(); + } } /** -- GitLab From 80080e54ef571a5109563d4bfc4619197961f51a Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Tue, 10 Nov 2009 21:44:58 -0800 Subject: [PATCH 154/458] Fix for 2209086: Initial pass at new SlidingTab widget and integration into LockScreen. Tested: - unlock and mute/unmute Not working: - highlighting on right tab. --- .../internal/policy/impl/LockScreen.java | 72 +++++++++++-------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index dda509735971..b4a318c9438d 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -17,8 +17,9 @@ package com.android.internal.policy.impl; import com.android.internal.R; +import com.android.internal.telephony.IccCard; import com.android.internal.widget.LockPatternUtils; -import com.android.internal.widget.RotarySelector; +import com.android.internal.widget.SlidingTab; import android.content.Context; import android.content.res.Resources; @@ -33,8 +34,6 @@ import android.util.Log; import android.media.AudioManager; import android.os.SystemProperties; -import com.android.internal.telephony.IccCard; - import java.util.Date; import java.io.File; import java.text.SimpleDateFormat; @@ -46,7 +45,7 @@ import java.text.SimpleDateFormat; */ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback, KeyguardUpdateMonitor.ConfigurationChangeCallback, - RotarySelector.OnDialTriggerListener { + SlidingTab.OnTriggerListener { private static final boolean DBG = false; private static final String TAG = "LockScreen"; @@ -59,7 +58,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private final KeyguardScreenCallback mCallback; private TextView mCarrier; - private RotarySelector mRotary; + private SlidingTab mSelector; private TextView mTime; private TextView mDate; private TextView mStatus1; @@ -175,9 +174,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM final LayoutInflater inflater = LayoutInflater.from(context); if (mCreatedInPortrait) { - inflater.inflate(R.layout.keyguard_screen_rotary_unlock, this, true); + inflater.inflate(R.layout.keyguard_screen_tab_unlock, this, true); } else { - inflater.inflate(R.layout.keyguard_screen_rotary_unlock_land, this, true); + inflater.inflate(R.layout.keyguard_screen_tab_unlock_land, this, true); } mCarrier = (TextView) findViewById(R.id.carrier); @@ -189,7 +188,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); mEmergencyCallButton.setText(R.string.lockscreen_emergency_call); mScreenLocked = (TextView) findViewById(R.id.screenLocked); - mRotary = (RotarySelector) findViewById(R.id.rotary); + mSelector = (SlidingTab) findViewById(R.id.tab_selector); + mSelector.setLeftHintText(R.string.lockscreen_unlock_label); + mSelector.setRightHintText(R.string.lockscreen_mute_unmute_label); mEmergencyCallButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mCallback.takeEmergencyCallAction(); @@ -207,15 +208,28 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mSilentMode = mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT; - mRotary.setOnDialTriggerListener(this); - mRotary.setLeftHandleResource(R.drawable.ic_jog_dial_unlock); - mRotary.setRightHandleResource(mSilentMode ? - R.drawable.ic_jog_dial_sound_off : - R.drawable.ic_jog_dial_sound_on); + mSelector.setOnTriggerListener(this); + 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(); resetStatusInfo(updateMonitor); } + private void updateRightTabResources() { + mSelector.setRightTabResources( + mSilentMode ? 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(); @@ -242,24 +256,23 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } /** {@inheritDoc} */ - public void onDialTrigger(View v, int whichHandle) { - if (whichHandle == RotarySelector.OnDialTriggerListener.LEFT_HANDLE) { + public void onTrigger(View v, int whichHandle) { + if (whichHandle == SlidingTab.OnTriggerListener.LEFT_HANDLE) { mCallback.goToUnlockScreen(); - } else if (whichHandle == RotarySelector.OnDialTriggerListener.RIGHT_HANDLE) { + } else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { // toggle silent mode mSilentMode = !mSilentMode; mAudioManager.setRingerMode(mSilentMode ? AudioManager.RINGER_MODE_SILENT : AudioManager.RINGER_MODE_NORMAL); - final int handleIcon = mSilentMode ? - R.drawable.ic_jog_dial_sound_off : - R.drawable.ic_jog_dial_sound_on; - final int toastIcon = mSilentMode ? - R.drawable.ic_lock_ringer_off : - R.drawable.ic_lock_ringer_on; - mRotary.setRightHandleResource(handleIcon); + + 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; toastMessage(mScreenLocked, message, toastIcon); mCallback.pokeWakelock(); } @@ -268,6 +281,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM /** {@inheritDoc} */ public void onGrabbedStateChange(View v, int grabbedState) { // TODO: Update onscreen hint text based on the new state. + mCallback.pokeWakelock(); } /** @@ -468,7 +482,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mRotary.setVisibility(View.VISIBLE); + mSelector.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.GONE); break; case NetworkLocked: @@ -478,7 +492,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mRotary.setVisibility(View.VISIBLE); + mSelector.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.GONE); break; case SimMissing: @@ -488,7 +502,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.INVISIBLE); - mRotary.setVisibility(View.VISIBLE); + mSelector.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.VISIBLE); putEmergencyBelow(R.id.divider); break; @@ -499,7 +513,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mRotary.setVisibility(View.GONE); + mSelector.setVisibility(View.GONE); mEmergencyCallButton.setVisibility(View.VISIBLE); putEmergencyBelow(R.id.screenLocked); break; @@ -509,7 +523,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.INVISIBLE); - mRotary.setVisibility(View.VISIBLE); + mSelector.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.GONE); break; case SimPukLocked: @@ -519,7 +533,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mRotary.setVisibility(View.GONE); + mSelector.setVisibility(View.GONE); mEmergencyCallButton.setVisibility(View.VISIBLE); putEmergencyBelow(R.id.screenLocked); break; -- GitLab From 421db0f0990b2551e5fe3e99147c32128b58516b Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Wed, 11 Nov 2009 18:06:35 -0800 Subject: [PATCH 155/458] Fix 2209086: Update sound states in LockScreen. --- policy/com/android/internal/policy/impl/LockScreen.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index b4a318c9438d..1eb274796efc 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -190,7 +190,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mScreenLocked = (TextView) findViewById(R.id.screenLocked); mSelector = (SlidingTab) findViewById(R.id.tab_selector); mSelector.setLeftHintText(R.string.lockscreen_unlock_label); - mSelector.setRightHintText(R.string.lockscreen_mute_unmute_label); mEmergencyCallButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mCallback.takeEmergencyCallAction(); @@ -228,6 +227,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM : R.drawable.jog_tab_bar_right_sound_off, mSilentMode ? R.drawable.jog_tab_right_sound_on : R.drawable.jog_tab_right_sound_off); + + mSelector.setRightHintText(mSilentMode ? + R.string.lockscreen_sound_on_label : R.string.lockscreen_sound_off_label); } private void resetStatusInfo(KeyguardUpdateMonitor updateMonitor) { -- GitLab From 8633ea9b7ad23e24eeb59bb30ac91db459660dfa Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Wed, 11 Nov 2009 22:23:36 -0800 Subject: [PATCH 156/458] Update LockScreen/UnlockScreen for new UX designs. This change depends upon relevant layout changes in frameworks/base/core/res/res. --- policy/com/android/internal/policy/impl/LockScreen.java | 2 -- policy/com/android/internal/policy/impl/UnlockScreen.java | 6 ------ 2 files changed, 8 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 1eb274796efc..43e155778ba1 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -180,7 +180,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } mCarrier = (TextView) findViewById(R.id.carrier); - mTime = (TextView) findViewById(R.id.time); mDate = (TextView) findViewById(R.id.date); mStatus1 = (TextView) findViewById(R.id.status1); mStatus2 = (TextView) findViewById(R.id.status2); @@ -371,7 +370,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private void refreshTimeAndDateDisplay() { Date now = new Date(); - mTime.setText(mTimeFormat.format(now)); mDate.setText(mDateFormat.format(now)); } diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index a5032b3ae0c5..2843dd4ce4bb 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -72,9 +72,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient private boolean mCreatedInPortrait; private TextView mCarrier; - private TextView mCenterDot; private TextView mDate; - private TextView mTime; // are we showing battery information? private boolean mShowingBatteryInfo = false; @@ -169,11 +167,8 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient } mCarrier = (TextView) findViewById(R.id.carrier); - mCenterDot = (TextView) findViewById(R.id.centerDot); mDate = (TextView) findViewById(R.id.date); - mTime = (TextView) findViewById(R.id.time); - mCenterDot.setText("|"); refreshTimeAndDateDisplay(); mStatus1 = (TextView) findViewById(R.id.status1); @@ -323,7 +318,6 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient private void refreshTimeAndDateDisplay() { Date now = new Date(); - mTime.setText(DateFormat.getTimeFormat(getContext()).format(now)); mDate.setText(DateFormat.getMediumDateFormat(getContext()).format(now)); } -- GitLab From 0469e9b13987ffe67894bde0a3af091580a036ff Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Thu, 12 Nov 2009 18:46:07 -0800 Subject: [PATCH 157/458] eclair snapshot --- .../policy/impl/AccountUnlockScreen.java | 195 +++--- .../internal/policy/impl/GlobalActions.java | 63 +- .../policy/impl/KeyguardScreenCallback.java | 11 +- .../policy/impl/KeyguardUpdateMonitor.java | 17 +- .../policy/impl/KeyguardViewManager.java | 27 +- .../policy/impl/KeyguardViewMediator.java | 151 +++-- .../policy/impl/LockPatternKeyguardView.java | 183 ++--- .../internal/policy/impl/LockScreen.java | 604 +++++++++++------ .../internal/policy/impl/PhoneWindow.java | 368 +++++----- .../policy/impl/PhoneWindowManager.java | 638 ++++++++++++++---- .../internal/policy/impl/PowerDialog.java | 7 +- .../policy/impl/RecentApplicationsDialog.java | 10 +- .../internal/policy/impl/SimUnlockScreen.java | 9 +- .../internal/policy/impl/UnlockScreen.java | 266 ++++++-- 14 files changed, 1715 insertions(+), 834 deletions(-) mode change 100644 => 100755 policy/com/android/internal/policy/impl/PhoneWindowManager.java diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index 65102c67fc8b..7992dd8856a6 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -19,38 +19,39 @@ package com.android.internal.policy.impl; import com.android.internal.R; import com.android.internal.widget.LockPatternUtils; -import android.accounts.AccountsServiceConstants; -import android.accounts.IAccountsService; -import android.content.ComponentName; +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.OperationCanceledException; +import android.accounts.AccountManagerFuture; +import android.accounts.AuthenticatorException; +import android.accounts.AccountManagerCallback; import android.content.Context; import android.content.Intent; -import android.content.ServiceConnection; import android.graphics.Rect; -import android.os.IBinder; -import android.os.RemoteException; import android.text.Editable; import android.text.InputFilter; import android.text.LoginFilter; import android.text.TextWatcher; -import android.text.TextUtils; -import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; +import android.view.WindowManager; import android.widget.Button; import android.widget.EditText; import android.widget.RelativeLayout; import android.widget.TextView; +import android.app.Dialog; +import android.app.ProgressDialog; +import android.os.Bundle; + +import java.io.IOException; /** * When the user forgets their password a bunch of times, we fall back on their * account's login/password to unlock the phone (and reset their lock pattern). - * - *

    This class is useful only on platforms that support the - * IAccountsService. */ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen, - View.OnClickListener, ServiceConnection, TextWatcher { + View.OnClickListener, TextWatcher { private static final String LOCK_PATTERN_PACKAGE = "com.android.settings"; private static final String LOCK_PATTERN_CLASS = "com.android.settings.ChooseLockPattern"; @@ -62,7 +63,6 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree private final KeyguardScreenCallback mCallback; private final LockPatternUtils mLockPatternUtils; - private IAccountsService mAccountsService; private TextView mTopHeader; private TextView mInstructions; @@ -71,15 +71,17 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree private Button mOk; private Button mEmergencyCall; + /** + * Shown while making asynchronous check of password. + */ + private ProgressDialog mCheckingDialog; + /** * AccountUnlockScreen constructor. - * - * @throws IllegalStateException if the IAccountsService is not - * available on the current platform. */ public AccountUnlockScreen(Context context, - KeyguardScreenCallback callback, - LockPatternUtils lockPatternUtils) { + KeyguardScreenCallback callback, + LockPatternUtils lockPatternUtils) { super(context); mCallback = callback; mLockPatternUtils = lockPatternUtils; @@ -88,6 +90,9 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree R.layout.keyguard_screen_glogin_unlock, this, true); mTopHeader = (TextView) findViewById(R.id.topHeader); + mTopHeader.setText(mLockPatternUtils.isPermanentlyLocked() ? + R.string.lockscreen_glogin_too_many_attempts : + R.string.lockscreen_glogin_forgot_pattern); mInstructions = (TextView) findViewById(R.id.instructions); @@ -103,14 +108,6 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree mEmergencyCall = (Button) findViewById(R.id.emergencyCall); mEmergencyCall.setOnClickListener(this); - - Log.v("AccountUnlockScreen", "debug: Connecting to accounts service"); - final boolean connected = mContext.bindService(AccountsServiceConstants.SERVICE_INTENT, - this, Context.BIND_AUTO_CREATE); - if (!connected) { - Log.v("AccountUnlockScreen", "debug: Couldn't connect to accounts service"); - throw new IllegalStateException("couldn't bind to accounts service"); - } } public void afterTextChanged(Editable s) { @@ -150,30 +147,16 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree /** {@inheritDoc} */ public void cleanUp() { - mContext.unbindService(this); + if (mCheckingDialog != null) { + mCheckingDialog.hide(); + } } /** {@inheritDoc} */ public void onClick(View v) { mCallback.pokeWakelock(); if (v == mOk) { - if (checkPassword()) { - // clear out forgotten password - mLockPatternUtils.setPermanentlyLocked(false); - - // launch the 'choose lock pattern' activity so - // the user can pick a new one if they want to - Intent intent = new Intent(); - intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(intent); - - // close the keyguard - mCallback.keyguardDone(true); - } else { - mInstructions.setText(R.string.lockscreen_glogin_invalid_input); - mPassword.setText(""); - } + asyncCheckPassword(); } if (v == mEmergencyCall) { @@ -181,11 +164,37 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree } } + private void onCheckPasswordResult(boolean success) { + if (success) { + // clear out forgotten password + mLockPatternUtils.setPermanentlyLocked(false); + mLockPatternUtils.setLockPatternEnabled(false); + mLockPatternUtils.saveLockPattern(null); + + // launch the 'choose lock pattern' activity so + // the user can pick a new one if they want to + Intent intent = new Intent(); + intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + + // close the keyguard + mCallback.keyguardDone(true); + } else { + mInstructions.setText(R.string.lockscreen_glogin_invalid_input); + mPassword.setText(""); + } + } + @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { - mCallback.goToLockScreen(); + if (mLockPatternUtils.isPermanentlyLocked()) { + mCallback.goToLockScreen(); + } else { + mCallback.forgotPattern(false); + } return true; } return super.dispatchKeyEvent(event); @@ -207,33 +216,25 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree * @return an account name from the database, or null if we can't * find a single best match. */ - private String findIntendedAccount(String username) { - String[] accounts = null; - try { - accounts = mAccountsService.getAccounts(); - } catch (RemoteException e) { - return null; - } - if (accounts == null) { - return null; - } + private Account findIntendedAccount(String username) { + Account[] accounts = AccountManager.get(mContext).getAccounts(); // Try to figure out which account they meant if they // typed only the username (and not the domain), or got // the case wrong. - String bestAccount = null; + Account bestAccount = null; int bestScore = 0; - for (String a: accounts) { + for (Account a: accounts) { int score = 0; - if (username.equals(a)) { + if (username.equals(a.name)) { score = 4; - } else if (username.equalsIgnoreCase(a)) { + } else if (username.equalsIgnoreCase(a.name)) { score = 3; } else if (username.indexOf('@') < 0) { - int i = a.indexOf('@'); + int i = a.name.indexOf('@'); if (i >= 0) { - String aUsername = a.substring(0, i); + String aUsername = a.name.substring(0, i); if (username.equals(aUsername)) { score = 2; } else if (username.equalsIgnoreCase(aUsername)) { @@ -251,28 +252,64 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree return bestAccount; } - private boolean checkPassword() { + private void asyncCheckPassword() { + mCallback.pokeWakelock(AWAKE_POKE_MILLIS); final String login = mLogin.getText().toString(); final String password = mPassword.getText().toString(); - try { - String account = findIntendedAccount(login); - if (account == null) { - return false; - } - return mAccountsService.shouldUnlock(account, password); - } catch (RemoteException e) { - return false; + Account account = findIntendedAccount(login); + if (account == null) { + onCheckPasswordResult(false); + return; } + getProgressDialog().show(); + Bundle options = new Bundle(); + options.putString(AccountManager.KEY_PASSWORD, password); + AccountManager.get(mContext).confirmCredentials(account, options, null /* activity */, + new AccountManagerCallback() { + public void run(AccountManagerFuture future) { + try { + mCallback.pokeWakelock(AWAKE_POKE_MILLIS); + final Bundle result = future.getResult(); + final boolean verified = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT); + // ensure on UI thread + mLogin.post(new Runnable() { + public void run() { + onCheckPasswordResult(verified); + } + }); + } catch (OperationCanceledException e) { + onCheckPasswordResult(false); + } catch (IOException e) { + onCheckPasswordResult(false); + } catch (AuthenticatorException e) { + onCheckPasswordResult(false); + } finally { + mLogin.post(new Runnable() { + public void run() { + getProgressDialog().hide(); + } + }); + } + } + }, null /* handler */); } - /** {@inheritDoc} */ - public void onServiceConnected(ComponentName name, IBinder service) { - Log.v("AccountUnlockScreen", "debug: About to grab as interface"); - mAccountsService = IAccountsService.Stub.asInterface(service); - } - - /** {@inheritDoc} */ - public void onServiceDisconnected(ComponentName name) { - mAccountsService = null; + private Dialog getProgressDialog() { + if (mCheckingDialog == null) { + mCheckingDialog = new ProgressDialog(mContext); + mCheckingDialog.setMessage( + mContext.getString(R.string.lockscreen_glogin_checking_password)); + mCheckingDialog.setIndeterminate(true); + mCheckingDialog.setCancelable(false); + mCheckingDialog.getWindow().setType( + WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_sf_slowBlur)) { + mCheckingDialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + } + } + return mCheckingDialog; } } diff --git a/policy/com/android/internal/policy/impl/GlobalActions.java b/policy/com/android/internal/policy/impl/GlobalActions.java index 377ff7828e75..2f1f024c5d89 100644 --- a/policy/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/com/android/internal/policy/impl/GlobalActions.java @@ -16,6 +16,7 @@ package com.android.internal.policy.impl; +import android.app.Activity; import android.app.AlertDialog; import android.app.StatusBarManager; import android.content.BroadcastReceiver; @@ -26,6 +27,7 @@ import android.content.IntentFilter; import android.media.AudioManager; import android.os.Handler; import android.os.Message; +import android.os.SystemProperties; import android.provider.Settings; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; @@ -40,6 +42,8 @@ import android.widget.ImageView; import android.widget.TextView; import com.android.internal.R; import com.android.internal.app.ShutdownThread; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.TelephonyProperties; import com.google.android.collect.Lists; import java.util.ArrayList; @@ -69,6 +73,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private boolean mKeyguardShowing = false; private boolean mDeviceProvisioned = false; private ToggleAction.State mAirplaneState = ToggleAction.State.Off; + private boolean mIsWaitingForEcmExit = false; /** * @param context everything needs a context :( @@ -81,6 +86,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); context.registerReceiver(mBroadcastReceiver, filter); // get notified of phone state changes @@ -141,20 +147,27 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac R.string.global_actions_airplane_mode_off_status) { void onToggle(boolean on) { - // Change the system setting - Settings.System.putInt( - mContext.getContentResolver(), - Settings.System.AIRPLANE_MODE_ON, - on ? 1 : 0); - Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - intent.putExtra("state", on); - mContext.sendBroadcast(intent); + if (Boolean.parseBoolean( + SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) { + mIsWaitingForEcmExit = true; + // Launch ECM exit dialog + Intent ecmDialogIntent = + new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null); + ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(ecmDialogIntent); + } else { + changeAirplaneModeSystemSetting(on); + } } @Override protected void changeStateFromPress(boolean buttonOn) { - mState = buttonOn ? State.TurningOn : State.TurningOff; - mAirplaneState = mState; + // In ECM mode airplane state cannot be changed + if (!(Boolean.parseBoolean( + SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) { + mState = buttonOn ? State.TurningOn : State.TurningOff; + mAirplaneState = mState; + } } public boolean showDuringKeyguard() { @@ -200,8 +213,11 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac final AlertDialog dialog = ab.create(); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); - dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_sf_slowBlur)) { + dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + } dialog.setOnDismissListener(this); @@ -218,7 +234,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac if (mKeyguardShowing) { mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); } else { - mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); + mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); } } @@ -490,6 +506,14 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) { mHandler.sendEmptyMessage(MESSAGE_DISMISS); } + } else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) { + // Airplane mode can be changed after ECM exits if airplane toggle button + // is pressed during ECM mode + if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) && + mIsWaitingForEcmExit) { + mIsWaitingForEcmExit = false; + changeAirplaneModeSystemSetting(true); + } } } }; @@ -514,4 +538,17 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } } }; + + /** + * Change the airplane mode system setting + */ + private void changeAirplaneModeSystemSetting(boolean on) { + Settings.System.putInt( + mContext.getContentResolver(), + Settings.System.AIRPLANE_MODE_ON, + on ? 1 : 0); + Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.putExtra("state", on); + mContext.sendBroadcast(intent); + } } diff --git a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java index b46b37d04db0..6bb6a45a7e34 100644 --- a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java +++ b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java @@ -28,10 +28,19 @@ public interface KeyguardScreenCallback extends KeyguardViewCallback { void goToLockScreen(); /** - * Transitino to th unlock screen. + * Transition to the unlock screen. */ void goToUnlockScreen(); + /** + * The user reported that they forgot their pattern (or not, when they want to back out of the + * forgot pattern screen). + * + * @param isForgotten True if the user hit the forgot pattern, false if they want to back out + * of the account screen. + */ + void forgotPattern(boolean isForgotten); + /** * @return Whether the keyguard requires some sort of PIN. */ diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index cd21427e1342..58905a10c435 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -35,7 +35,6 @@ import static android.provider.Telephony.Intents.EXTRA_SHOW_SPN; import static android.provider.Telephony.Intents.EXTRA_SPN; import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION; -import com.android.internal.app.ShutdownThread; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.TelephonyIntents; import android.util.Log; @@ -67,6 +66,8 @@ public class KeyguardUpdateMonitor { private boolean mInPortrait; private boolean mKeyboardOpen; + private boolean mKeyguardBypassEnabled; + private boolean mDevicePluggedIn; private boolean mDeviceProvisioned; @@ -163,6 +164,9 @@ public class KeyguardUpdateMonitor { } }; + mKeyguardBypassEnabled = context.getResources().getBoolean( + com.android.internal.R.bool.config_bypass_keyguard_if_slider_open); + mDeviceProvisioned = Settings.Secure.getInt( mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; @@ -295,13 +299,6 @@ public class KeyguardUpdateMonitor { shouldShowBatteryInfo(), pluggedIn, batteryLevel); } } - - // shut down gracefully if our battery is critically low and we are not powered - if (batteryLevel == 0 && - pluggedInStatus != BATTERY_STATUS_CHARGING && - pluggedInStatus != BATTERY_STATUS_UNKNOWN) { - ShutdownThread.shutdown(mContext, false); - } } /** @@ -513,6 +510,10 @@ public class KeyguardUpdateMonitor { return mKeyboardOpen; } + public boolean isKeyguardBypassEnabled() { + return mKeyguardBypassEnabled; + } + public boolean isDevicePluggedIn() { return mDevicePluggedIn; } diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index 297d62f4a4bf..bac2fcada11f 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -48,7 +48,7 @@ public class KeyguardViewManager implements KeyguardWindowController { private WindowManager.LayoutParams mWindowLayoutParams; private boolean mNeedsInput = false; - + private FrameLayout mKeyguardHost; private KeyguardViewBase mKeyguardView; @@ -101,6 +101,8 @@ public class KeyguardViewManager implements KeyguardWindowController { final int stretch = ViewGroup.LayoutParams.FILL_PARENT; int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN + | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER + | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ; if (!mNeedsInput) { @@ -108,7 +110,7 @@ public class KeyguardViewManager implements KeyguardWindowController { } WindowManager.LayoutParams lp = new WindowManager.LayoutParams( stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD, - flags, PixelFormat.OPAQUE); + 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; @@ -152,7 +154,7 @@ public class KeyguardViewManager implements KeyguardWindowController { mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); } } - + /** * Reset the state of the view. */ @@ -195,10 +197,14 @@ public class KeyguardViewManager implements KeyguardWindowController { * * @param keyCode The wake key. */ - public void wakeWhenReadyTq(int keyCode) { + public boolean wakeWhenReadyTq(int keyCode) { if (DEBUG) Log.d(TAG, "wakeWhenReady(" + keyCode + ")"); if (mKeyguardView != null) { mKeyguardView.wakeWhenReadyTq(keyCode); + return true; + } else { + Log.w(TAG, "mKeyguardView is null in wakeWhenReadyTq"); + return false; } } @@ -209,10 +215,19 @@ public class KeyguardViewManager implements KeyguardWindowController { if (DEBUG) Log.d(TAG, "hide()"); if (mKeyguardHost != null) { mKeyguardHost.setVisibility(View.GONE); + // Don't do this right away, so we can let the view continue to animate + // as it goes away. if (mKeyguardView != null) { - mKeyguardHost.removeView(mKeyguardView); - mKeyguardView.cleanUp(); + final KeyguardViewBase lastView = mKeyguardView; mKeyguardView = null; + mKeyguardHost.postDelayed(new Runnable() { + public void run() { + synchronized (KeyguardViewManager.this) { + mKeyguardHost.removeView(lastView); + lastView.cleanUp(); + } + } + }, 500); } } } diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 043f72712690..f5591b213df5 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -19,11 +19,9 @@ package com.android.internal.policy.impl; import com.android.internal.telephony.IccCard; import com.android.internal.widget.LockPatternUtils; +import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.PendingIntent; -import android.app.StatusBarManager; -import static android.app.StatusBarManager.DISABLE_EXPAND; -import static android.app.StatusBarManager.DISABLE_NONE; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -32,7 +30,9 @@ import android.os.Handler; import android.os.LocalPowerManager; import android.os.Message; import android.os.PowerManager; +import android.os.RemoteException; import android.os.SystemClock; +import android.os.SystemProperties; import android.telephony.TelephonyManager; import android.util.Config; import android.util.EventLog; @@ -84,7 +84,7 @@ import android.view.WindowManagerPolicy; * thread of the keyguard. */ public class KeyguardViewMediator implements KeyguardViewCallback, - KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.SimStateCallback { + KeyguardUpdateMonitor.SimStateCallback { private final static boolean DEBUG = false && Config.LOGD; private final static boolean DBG_WAKE = DEBUG || true; @@ -104,6 +104,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private static final int WAKE_WHEN_READY = 8; private static final int KEYGUARD_DONE = 9; private static final int KEYGUARD_DONE_DRAWING = 10; + private static final int KEYGUARD_DONE_AUTHENTICATING = 11; /** * The default amount of time we stay awake (used for all key input) @@ -122,7 +123,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 = 0; + private static final int KEYGUARD_DELAY_MS = 5000; /** * How long we'll wait for the {@link KeyguardViewCallback#keyguardDoneDrawing()} @@ -149,6 +150,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ private PowerManager.WakeLock mWakeLock; + /** + * Used to keep the device awake while to ensure the keyguard finishes opening before + * we sleep. + */ + private PowerManager.WakeLock mShowKeyguardWakeLock; + /** * Does not turn on screen, held while a call to {@link KeyguardViewManager#wakeWhenReadyTq(int)} * is called to make sure the device doesn't sleep before it has a chance to poke @@ -157,11 +164,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ private PowerManager.WakeLock mWakeAndHandOff; - /** - * Used to disable / reenable status bar expansion. - */ - private StatusBarManager mStatusBarManager; - private KeyguardViewManager mKeyguardViewManager; // these are protected by synchronized (this) @@ -182,6 +184,9 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // answer whether the input should be restricted) private boolean mShowing = false; + // true if the keyguard is hidden by another window + private boolean mHidden = false; + /** * Helps remember whether the screen has turned on since the last time * it turned off due to timeout. see {@link #onScreenTurnedOff(int)} @@ -229,6 +234,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "keyguard"); mWakeLock.setReferenceCounted(false); + mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard"); + mShowKeyguardWakeLock.setReferenceCounted(false); mWakeAndHandOff = mPM.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, @@ -245,7 +252,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mUpdateMonitor = new KeyguardUpdateMonitor(context); - mUpdateMonitor.registerConfigurationChangeCallback(this); mUpdateMonitor.registerSimStateCallback(this); mKeyguardViewProperties = @@ -347,14 +353,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (DEBUG) Log.d(TAG, "remembering to reshow, hiding keyguard, " + "disabling status bar expansion"); mNeedToReshowWhenReenabled = true; - setStatusBarExpandable(false); hideLocked(); } else if (enabled && mNeedToReshowWhenReenabled) { // reenabled after previously hidden, reshow if (DEBUG) Log.d(TAG, "previously hidden, reshowing, reenabling " + "status bar expansion"); mNeedToReshowWhenReenabled = false; - setStatusBarExpandable(true); if (mExitSecureCallback != null) { if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting"); @@ -409,15 +413,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } } - - private void setStatusBarExpandable(boolean isExpandable) { - if (mStatusBarManager == null) { - mStatusBarManager = - (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); - } - mStatusBarManager.disable(isExpandable ? DISABLE_NONE : DISABLE_EXPAND); - } - /** * Is the keyguard currently showing? */ @@ -425,6 +420,17 @@ public class KeyguardViewMediator implements KeyguardViewCallback, return mShowing; } + /** + * Notify us when the keyguard is hidden by another window + */ + public void setHidden(boolean isHidden) { + if (DEBUG) Log.d(TAG, "setHidden " + isHidden); + synchronized (KeyguardViewMediator.this) { + mHidden = isHidden; + adjustUserActivityLocked(); + } + } + /** * Given the state of the keyguard, is the input restricted? * Input is restricted when the keyguard is showing, or when the keyguard @@ -434,6 +440,21 @@ public class KeyguardViewMediator implements KeyguardViewCallback, return mShowing || mNeedToReshowWhenReenabled || !mUpdateMonitor.isDeviceProvisioned(); } + /** + * Returns true if the change is resulting in the keyguard beign dismissed, + * meaning the screen can turn on immediately. Otherwise returns false. + */ + public boolean doLidChangeTq(boolean isLidOpen) { + mKeyboardOpen = isLidOpen; + + if (mUpdateMonitor.isKeyguardBypassEnabled() && mKeyboardOpen + && !mKeyguardViewProperties.isSecure() && mKeyguardViewManager.isShowing()) { + if (DEBUG) Log.d(TAG, "bypassing keyguard on sliding open of keyboard with non-secure keyguard"); + mHandler.sendEmptyMessage(KEYGUARD_DONE_AUTHENTICATING); + return true; + } + return false; + } /** * Enable the keyguard if the settings are appropriate. @@ -463,9 +484,13 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } // if the setup wizard hasn't run yet, don't show + final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", + false); final boolean provisioned = mUpdateMonitor.isDeviceProvisioned(); final IccCard.State state = mUpdateMonitor.getSimState(); - final boolean lockedOrMissing = state.isPinLocked() || (state == IccCard.State.ABSENT); + final boolean lockedOrMissing = state.isPinLocked() + || ((state == IccCard.State.ABSENT) && requireSim); + if (!lockedOrMissing && !provisioned) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned" + " and the sim is not locked or missing"); @@ -544,6 +569,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ private void showLocked() { if (DEBUG) Log.d(TAG, "showLocked"); + // ensure we stay awake until we are finished displaying the keyguard + mShowKeyguardWakeLock.acquire(); Message msg = mHandler.obtainMessage(SHOW); mHandler.sendMessage(msg); } @@ -558,26 +585,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mHandler.sendMessage(msg); } - /** - * {@link KeyguardUpdateMonitor} callbacks. - */ - - /** {@inheritDoc} */ - public void onOrientationChange(boolean inPortrait) { - - } - - /** {@inheritDoc} */ - public void onKeyboardChange(boolean isKeyboardOpen) { - mKeyboardOpen = isKeyboardOpen; - - if (mKeyboardOpen && !mKeyguardViewProperties.isSecure() - && mKeyguardViewManager.isShowing()) { - if (DEBUG) Log.d(TAG, "bypassing keyguard on sliding open of keyboard with non-secure keyguard"); - keyguardDone(true); - } - } - /** {@inheritDoc} */ public void onSimStateChanged(IccCard.State simState) { if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState); @@ -615,6 +622,10 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } } + public boolean isSecure() { + return mKeyguardViewProperties.isSecure(); + } + private BroadcastReceiver mBroadCastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -719,10 +730,15 @@ public class KeyguardViewMediator implements KeyguardViewCallback, * @see #handleKeyguardDone */ public void keyguardDone(boolean authenticated) { + keyguardDone(authenticated, true); + } + + public void keyguardDone(boolean authenticated, boolean wakeup) { synchronized (this) { EventLog.writeEvent(70000, 2); if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")"); Message msg = mHandler.obtainMessage(KEYGUARD_DONE); + msg.arg1 = wakeup ? 1 : 0; mHandler.sendMessage(msg); if (authenticated) { @@ -738,7 +754,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // the keyguard when they've released the lock mExternallyEnabled = true; mNeedToReshowWhenReenabled = false; - setStatusBarExpandable(true); } } } @@ -789,10 +804,14 @@ public class KeyguardViewMediator implements KeyguardViewCallback, handleWakeWhenReady(msg.arg1); return; case KEYGUARD_DONE: - handleKeyguardDone(); + handleKeyguardDone(msg.arg1 != 0); return; case KEYGUARD_DONE_DRAWING: handleKeyguardDoneDrawing(); + return; + case KEYGUARD_DONE_AUTHENTICATING: + keyguardDone(true); + return; } } }; @@ -801,10 +820,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, * @see #keyguardDone * @see #KEYGUARD_DONE */ - private void handleKeyguardDone() { + private void handleKeyguardDone(boolean wakeup) { if (DEBUG) Log.d(TAG, "handleKeyguardDone"); handleHide(); - mPM.userActivity(SystemClock.uptimeMillis(), true); + if (wakeup) { + mPM.userActivity(SystemClock.uptimeMillis(), true); + } mWakeLock.release(); mContext.sendBroadcast(mUserPresentIntent); } @@ -853,12 +874,14 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (DEBUG) Log.d(TAG, "handleShow"); if (!mSystemReady) return; - // while we're showing, we control the wake state, so ask the power - // manager not to honor request for userActivity. - mRealPowerManager.enableUserActivity(false); - mKeyguardViewManager.show(); mShowing = true; + adjustUserActivityLocked(); + try { + ActivityManagerNative.getDefault().closeSystemDialogs("lock"); + } catch (RemoteException e) { + } + mShowKeyguardWakeLock.release(); } } @@ -869,11 +892,25 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private void handleHide() { synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleHide"); - // When we go away, tell the poewr manager to honor requests from userActivity. - mRealPowerManager.enableUserActivity(true); + if (mWakeAndHandOff.isHeld()) { + Log.w(TAG, "attempt to hide the keyguard while waking, ignored"); + return; + } mKeyguardViewManager.hide(); mShowing = false; + adjustUserActivityLocked(); + } + } + + private void adjustUserActivityLocked() { + // disable user activity if we are shown and not hidden + if (DEBUG) Log.d(TAG, "adjustUserActivityLocked mShowing: " + mShowing + " mHidden: " + mHidden); + boolean enabled = !mShowing || mHidden; + mRealPowerManager.enableUserActivity(enabled); + if (!enabled && mScreenOn) { + // reinstate our short screen timeout policy + pokeWakelock(); } } @@ -888,7 +925,11 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // this should result in a call to 'poke wakelock' which will set a timeout // on releasing the wakelock - mKeyguardViewManager.wakeWhenReadyTq(keyCode); + if (!mKeyguardViewManager.wakeWhenReadyTq(keyCode)) { + // poke wakelock ourselves if keyguard is no longer active + Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock, so poke it ourselves"); + pokeWakelock(); + } /** * Now that the keyguard is ready and has poked the wake lock, we can @@ -897,7 +938,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mWakeAndHandOff.release(); if (!mWakeLock.isHeld()) { - Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock"); + Log.w(TAG, "mWakeLock not held in mKeyguardViewManager.wakeWhenReadyTq"); } } } diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 6a1c2794a76f..0ebd945600ef 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -16,41 +16,47 @@ package com.android.internal.policy.impl; -import android.accounts.AccountsServiceConstants; -import android.accounts.IAccountsService; +import com.android.internal.R; +import com.android.internal.telephony.IccCard; +import com.android.internal.widget.LockPatternUtils; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.AccountManagerCallback; +import android.accounts.AccountManagerFuture; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; import android.app.AlertDialog; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.ServiceConnection; -import android.os.IBinder; -import android.os.RemoteException; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.PixelFormat; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.os.SystemProperties; -import com.android.internal.telephony.IccCard; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.WindowManager; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.PixelFormat; -import android.graphics.ColorFilter; -import com.android.internal.R; -import com.android.internal.widget.LockPatternUtils; + +import java.io.IOException; /** * The host view for all of the screens of the pattern unlock screen. There are * two {@link Mode}s of operation, lock and unlock. This will show the appropriate - * screen, and listen for callbacks via {@link com.android.internal.policy.impl.KeyguardScreenCallback + * screen, and listen for callbacks via + * {@link com.android.internal.policy.impl.KeyguardScreenCallback} * from the current screen. * - * This view, in turn, communicates back to {@link com.android.internal.policy.impl.KeyguardViewManager} + * This view, in turn, communicates back to + * {@link com.android.internal.policy.impl.KeyguardViewManager} * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate. */ -public class LockPatternKeyguardView extends KeyguardViewBase { +public class LockPatternKeyguardView extends KeyguardViewBase + implements AccountManagerCallback { // intent action for launching emergency dialer activity. static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL"; @@ -60,12 +66,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase { private final KeyguardUpdateMonitor mUpdateMonitor; private final KeyguardWindowController mWindowController; - + private View mLockScreen; private View mUnlockScreen; private boolean mScreenOn = false; - private boolean mHasAccount = false; // assume they don't have an account until we know better + private boolean mEnableFallback = false; // assume no fallback UI until we know better /** @@ -114,10 +120,13 @@ public class LockPatternKeyguardView extends KeyguardViewBase { private Mode mMode = Mode.LockScreen; /** - * Keeps track of what mode the current unlock screen is + * Keeps track of what mode the current unlock screen is (cached from most recent computation in + * {@link #getUnlockMode}). */ private UnlockMode mUnlockScreenMode; + private boolean mForgotPattern; + /** * If true, it means we are in the process of verifying that the user * can get past the lock screen per {@link #verifyUnlock()} @@ -130,11 +139,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase { */ private final LockPatternUtils mLockPatternUtils; - /** - * Used to fetch accounts from GLS. - */ - private ServiceConnection mServiceConnection; - /** * @return Whether we are stuck on the lock screen because the sim is * missing. @@ -145,6 +149,22 @@ public class LockPatternKeyguardView extends KeyguardViewBase { && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT); } + public void run(AccountManagerFuture future) { + // We err on the side of caution. + // In case of error we assume we have a SAML account. + boolean hasSAMLAccount = true; + try { + hasSAMLAccount = future.getResult().length > 0; + } catch (OperationCanceledException e) { + } catch (IOException e) { + } catch (AuthenticatorException e) { + } + mEnableFallback = !hasSAMLAccount; + if (mUnlockScreen instanceof UnlockScreen) { + ((UnlockScreen)mUnlockScreen).setEnableFallback(true); + } + } + /** * @param context Used to inflate, and create views. * @param updateMonitor Knows the state of the world, and passed along to each @@ -158,9 +178,21 @@ public class LockPatternKeyguardView extends KeyguardViewBase { LockPatternUtils lockPatternUtils, KeyguardWindowController controller) { super(context); + + final boolean hasAccount = AccountManager.get(context).getAccounts().length > 0; + if (hasAccount) { + /* If we have a SAML account which requires web login we can not use the + fallback screen UI to ask the user for credentials. + For now we will disable fallback screen in this case. + Ultimately we could consider bringing up a web login from GLS + but need to make sure that it will work in the "locked screen" mode. */ + String[] features = new String[] {"saml"}; + AccountManager.get(context).getAccountsByTypeAndFeatures( + "com.google", features, this, null); + } - asyncCheckForAccount(); - + mEnableFallback = false; + mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); @@ -169,10 +201,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase { mWindowController = controller; mMode = getInitialMode(); - + mKeyguardScreenCallback = new KeyguardScreenCallback() { public void goToLockScreen() { + mForgotPattern = false; if (mIsVerifyUnlockOnly) { // navigating away from unlock screen during verify mode means // we are done and the user failed to authenticate. @@ -197,6 +230,13 @@ public class LockPatternKeyguardView extends KeyguardViewBase { } } + public void forgotPattern(boolean isForgotten) { + if (mEnableFallback) { + mForgotPattern = isForgotten; + updateScreen(Mode.UnlockScreen); + } + } + public boolean isSecure() { return LockPatternKeyguardView.this.isSecure(); } @@ -235,11 +275,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase { public void reportFailedPatternAttempt() { mUpdateMonitor.reportFailedAttempt(); final int failedAttempts = mUpdateMonitor.getFailedAttempts(); - if (mHasAccount && failedAttempts == - (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET + if (mEnableFallback && failedAttempts == + (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { showAlmostAtAccountLoginDialog(); - } else if (mHasAccount + } else if (mEnableFallback && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { mLockPatternUtils.setPermanentlyLocked(true); updateScreen(mMode); @@ -248,9 +288,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase { showTimeoutDialog(); } } - + public boolean doesFallbackUnlockScreenExist() { - return mHasAccount; + return mEnableFallback; } }; @@ -262,9 +302,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase { setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); // wall paper background - final BitmapDrawable drawable = (BitmapDrawable) context.getWallpaper(); - setBackgroundDrawable( - new FastBitmapDrawable(drawable.getBitmap())); + if (false) { + final BitmapDrawable drawable = (BitmapDrawable) context.getWallpaper(); + setBackgroundDrawable( + new FastBitmapDrawable(drawable.getBitmap())); + } // create both the lock and unlock screen so they are quickly available // when the screen turns on @@ -277,45 +319,18 @@ public class LockPatternKeyguardView extends KeyguardViewBase { updateScreen(mMode); } - /** - * Asynchronously checks for at least one account. This will set mHasAccount - * to true if an account is found. - */ - private void asyncCheckForAccount() { - - mServiceConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - try { - IAccountsService accountsService = IAccountsService.Stub.asInterface(service); - String accounts[] = accountsService.getAccounts(); - mHasAccount = (accounts.length > 0); - } catch (RemoteException e) { - // Not much we can do here... - Log.e(TAG, "Gls died while attempting to get accounts: " + e); - } finally { - getContext().unbindService(mServiceConnection); - mServiceConnection = null; - } - } - - public void onServiceDisconnected(ComponentName className) { - // nothing to do here - } - }; - boolean status = getContext().bindService(AccountsServiceConstants.SERVICE_INTENT, - mServiceConnection, Context.BIND_AUTO_CREATE); - if (!status) Log.e(TAG, "Failed to bind to GLS while checking for account"); - } @Override public void reset() { mIsVerifyUnlockOnly = false; + mForgotPattern = false; updateScreen(getInitialMode()); } @Override public void onScreenTurnedOff() { mScreenOn = false; + mForgotPattern = false; if (mMode == Mode.LockScreen) { ((KeyguardScreen) mLockScreen).onPause(); } else { @@ -423,7 +438,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { // do this before changing visibility so focus isn't requested before the input // flag is set mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); - + if (mScreenOn) { if (goneScreen.getVisibility() == View.VISIBLE) { @@ -454,12 +469,14 @@ public class LockPatternKeyguardView extends KeyguardViewBase { View createUnlockScreenFor(UnlockMode unlockMode) { if (unlockMode == UnlockMode.Pattern) { - return new UnlockScreen( + UnlockScreen view = new UnlockScreen( mContext, mLockPatternUtils, mUpdateMonitor, mKeyguardScreenCallback, mUpdateMonitor.getFailedAttempts()); + view.setEnableFallback(mEnableFallback); + return view; } else if (unlockMode == UnlockMode.SimPin) { return new SimUnlockScreen( mContext, @@ -525,7 +542,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { final IccCard.State simState = mUpdateMonitor.getSimState(); if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED)) { return Mode.LockScreen; - } else if (mUpdateMonitor.isKeyboardOpen() && isSecure()) { + } else if (isSecure()) { return Mode.UnlockScreen; } else { return Mode.LockScreen; @@ -540,7 +557,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { if (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED) { return UnlockMode.SimPin; } else { - return mLockPatternUtils.isPermanentlyLocked() ? + return (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) ? UnlockMode.Account: UnlockMode.Pattern; } @@ -558,9 +575,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase { .setNeutralButton(R.string.ok, null) .create(); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - dialog.getWindow().setFlags( - WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_sf_slowBlur)) { + dialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + } dialog.show(); } @@ -578,15 +598,20 @@ public class LockPatternKeyguardView extends KeyguardViewBase { .setNeutralButton(R.string.ok, null) .create(); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - dialog.getWindow().setFlags( - WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_sf_slowBlur)) { + dialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + } dialog.show(); } /** - * Used to put wallpaper on the background of the lock screen. Centers it Horizontally and - * vertically. + * Used to put wallpaper on the background of the lock screen. Centers it + * Horizontally and pins the bottom (assuming that the lock screen is aligned + * with the bottom, so the wallpaper should extend above the top into the + * status bar). */ static private class FastBitmapDrawable extends Drawable { private Bitmap mBitmap; @@ -602,7 +627,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { canvas.drawBitmap( mBitmap, (getBounds().width() - mBitmap.getWidth()) / 2, - (getBounds().height() - mBitmap.getHeight()) / 2, + (getBounds().height() - mBitmap.getHeight()), null); } diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 0495a76b7c0c..dda509735971 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -18,21 +18,26 @@ package com.android.internal.policy.impl; import com.android.internal.R; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.RotarySelector; import android.content.Context; +import android.content.res.Resources; import android.text.format.DateFormat; -import android.text.TextUtils; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; +import android.widget.*; +import android.graphics.drawable.Drawable; +import android.util.Log; +import android.media.AudioManager; +import android.os.SystemProperties; + import com.android.internal.telephony.IccCard; import java.util.Date; +import java.io.File; +import java.text.SimpleDateFormat; /** * The screen within {@link LockPatternKeyguardView} that shows general @@ -40,40 +45,28 @@ import java.util.Date; * past it, as applicable. */ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateMonitor.InfoCallback, - KeyguardUpdateMonitor.SimStateCallback, KeyguardUpdateMonitor.ConfigurationChangeCallback { + KeyguardUpdateMonitor.SimStateCallback, KeyguardUpdateMonitor.ConfigurationChangeCallback, + RotarySelector.OnDialTriggerListener { + + private static final boolean DBG = false; + private static final String TAG = "LockScreen"; + private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key"; + + private Status mStatus = Status.Normal; + private final LockPatternUtils mLockPatternUtils; private final KeyguardUpdateMonitor mUpdateMonitor; private final KeyguardScreenCallback mCallback; - private TextView mHeaderSimOk1; - private TextView mHeaderSimOk2; - - private TextView mHeaderSimBad1; - private TextView mHeaderSimBad2; - + private TextView mCarrier; + private RotarySelector mRotary; private TextView mTime; private TextView mDate; - - private ViewGroup mBatteryInfoGroup; - private ImageView mBatteryInfoIcon; - private TextView mBatteryInfoText; - private View mBatteryInfoSpacer; - - private ViewGroup mNextAlarmGroup; - private TextView mAlarmText; - private View mAlarmSpacer; - - private ViewGroup mScreenLockedMessageGroup; - - private TextView mLockInstructions; - + private TextView mStatus1; + private TextView mStatus2; + private TextView mScreenLocked; private Button mEmergencyCallButton; - /** - * false means sim is missing or PUK'd - */ - private boolean mSimOk = true; - // are we showing battery information? private boolean mShowingBatteryInfo = false; @@ -83,10 +76,83 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // last known battery level private int mBatteryLevel = 100; + private String mNextAlarm = null; + private Drawable mAlarmIcon = null; + private String mCharging = null; + private Drawable mChargingIcon = null; + + private boolean mSilentMode; + private AudioManager mAudioManager; + private java.text.DateFormat mDateFormat; + private java.text.DateFormat mTimeFormat; + private boolean mCreatedInPortrait; + private boolean mEnableMenuKeyInLockScreen; - private View[] mOnlyVisibleWhenSimOk; + /** + * The status of this lock screen. + */ + enum Status { + /** + * Normal case (sim card present, it's not locked) + */ + Normal(true), + + /** + * The sim card is 'network locked'. + */ + NetworkLocked(true), + + /** + * The sim card is missing. + */ + SimMissing(false), + + /** + * The sim card is missing, and this is the device isn't provisioned, so we don't let + * them get past the screen. + */ + SimMissingLocked(false), + + /** + * The sim card is PUK locked, meaning they've entered the wrong sim unlock code too many + * times. + */ + SimPukLocked(false), + + /** + * The sim card is locked. + */ + SimLocked(true); + + private final boolean mShowStatusLines; + + Status(boolean mShowStatusLines) { + this.mShowStatusLines = mShowStatusLines; + } - private View[] mOnlyVisibleWhenSimNotOk; + /** + * @return Whether the status lines (battery level and / or next alarm) are shown while + * in this state. Mostly dictated by whether this is room for them. + */ + public boolean showStatusLines() { + return mShowStatusLines; + } + } + + /** + * 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 + * is prone to false positives. + * + * @return true if the menu key should be enabled + */ + private boolean shouldEnableMenuKey() { + final Resources res = getResources(); + final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen); + final boolean isMonkey = SystemProperties.getBoolean("ro.monkey", false); + final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists(); + return !configDisabled || isMonkey || fileOverride; + } /** * @param context Used to setup the view. @@ -103,262 +169,391 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mUpdateMonitor = updateMonitor; mCallback = callback; - final LayoutInflater inflater = LayoutInflater.from(context); - inflater.inflate(R.layout.keyguard_screen_lock, this, true); + mEnableMenuKeyInLockScreen = shouldEnableMenuKey(); - mSimOk = isSimOk(updateMonitor.getSimState()); - mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo(); - mPluggedIn = updateMonitor.isDevicePluggedIn(); - mBatteryLevel = updateMonitor.getBatteryLevel(); - - mHeaderSimOk1 = (TextView) findViewById(R.id.headerSimOk1); - mHeaderSimOk2 = (TextView) findViewById(R.id.headerSimOk2); + mCreatedInPortrait = updateMonitor.isInPortrait(); - mHeaderSimBad1 = (TextView) findViewById(R.id.headerSimBad1); - mHeaderSimBad2 = (TextView) findViewById(R.id.headerSimBad2); + final LayoutInflater inflater = LayoutInflater.from(context); + if (mCreatedInPortrait) { + inflater.inflate(R.layout.keyguard_screen_rotary_unlock, this, true); + } else { + inflater.inflate(R.layout.keyguard_screen_rotary_unlock_land, this, true); + } + mCarrier = (TextView) findViewById(R.id.carrier); mTime = (TextView) findViewById(R.id.time); mDate = (TextView) findViewById(R.id.date); - - mBatteryInfoGroup = (ViewGroup) findViewById(R.id.batteryInfo); - mBatteryInfoIcon = (ImageView) findViewById(R.id.batteryInfoIcon); - mBatteryInfoText = (TextView) findViewById(R.id.batteryInfoText); - mBatteryInfoSpacer = findViewById(R.id.batteryInfoSpacer); - - mNextAlarmGroup = (ViewGroup) findViewById(R.id.nextAlarmInfo); - mAlarmText = (TextView) findViewById(R.id.nextAlarmText); - mAlarmSpacer = findViewById(R.id.nextAlarmSpacer); - - mScreenLockedMessageGroup = (ViewGroup) findViewById(R.id.screenLockedInfo); - - mLockInstructions = (TextView) findViewById(R.id.lockInstructions); + mStatus1 = (TextView) findViewById(R.id.status1); + mStatus2 = (TextView) findViewById(R.id.status2); mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); - + mEmergencyCallButton.setText(R.string.lockscreen_emergency_call); + mScreenLocked = (TextView) findViewById(R.id.screenLocked); + mRotary = (RotarySelector) findViewById(R.id.rotary); mEmergencyCallButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mCallback.takeEmergencyCallAction(); } }); - mOnlyVisibleWhenSimOk = new View[] { - mHeaderSimOk1, - mHeaderSimOk2, - mBatteryInfoGroup, - mBatteryInfoSpacer, - mNextAlarmGroup, - mAlarmSpacer, - mScreenLockedMessageGroup, - mLockInstructions - }; - - mOnlyVisibleWhenSimNotOk = new View[] { - mHeaderSimBad1, - mHeaderSimBad2, - mEmergencyCallButton - }; - setFocusable(true); setFocusableInTouchMode(true); setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); - refreshBatteryDisplay(); - refreshAlarmDisplay(); - refreshTimeAndDateDisplay(); - refreshUnlockIntructions(); - refreshViewsWRTSimOk(); - refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn()); - updateMonitor.registerInfoCallback(this); updateMonitor.registerSimStateCallback(this); updateMonitor.registerConfigurationChangeCallback(this); + + mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); + mSilentMode = mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT; + + mRotary.setOnDialTriggerListener(this); + mRotary.setLeftHandleResource(R.drawable.ic_jog_dial_unlock); + mRotary.setRightHandleResource(mSilentMode ? + R.drawable.ic_jog_dial_sound_off : + R.drawable.ic_jog_dial_sound_on); + + resetStatusInfo(updateMonitor); } + private void resetStatusInfo(KeyguardUpdateMonitor updateMonitor) { + mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo(); + mPluggedIn = updateMonitor.isDevicePluggedIn(); + mBatteryLevel = updateMonitor.getBatteryLevel(); + + mStatus = getCurrentStatus(updateMonitor.getSimState()); + updateLayout(mStatus); + + refreshBatteryStringAndIcon(); + refreshAlarmDisplay(); + + mTimeFormat = DateFormat.getTimeFormat(getContext()); + mDateFormat = getLockScreenDateFormat(); + refreshTimeAndDateDisplay(); + updateStatusLines(); + } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU) { + if (keyCode == KeyEvent.KEYCODE_MENU && mEnableMenuKeyInLockScreen) { mCallback.goToUnlockScreen(); } return false; } - private void refreshViewsWRTSimOk() { - if (mSimOk) { - for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) { - final View view = mOnlyVisibleWhenSimOk[i]; - if (view == null) throw new RuntimeException("index " + i + " null"); - view.setVisibility(View.VISIBLE); - } - for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) { - final View view = mOnlyVisibleWhenSimNotOk[i]; - view.setVisibility(View.GONE); - } - refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), - mUpdateMonitor.getTelephonySpn()); - refreshAlarmDisplay(); - refreshBatteryDisplay(); - } else { - for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) { - final View view = mOnlyVisibleWhenSimOk[i]; - view.setVisibility(View.GONE); - } - for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) { - final View view = mOnlyVisibleWhenSimNotOk[i]; - view.setVisibility(View.VISIBLE); - } - refreshSimBadInfo(); + /** {@inheritDoc} */ + public void onDialTrigger(View v, int whichHandle) { + if (whichHandle == RotarySelector.OnDialTriggerListener.LEFT_HANDLE) { + mCallback.goToUnlockScreen(); + } else if (whichHandle == RotarySelector.OnDialTriggerListener.RIGHT_HANDLE) { + // toggle silent mode + mSilentMode = !mSilentMode; + mAudioManager.setRingerMode(mSilentMode ? AudioManager.RINGER_MODE_SILENT + : AudioManager.RINGER_MODE_NORMAL); + final int handleIcon = mSilentMode ? + R.drawable.ic_jog_dial_sound_off : + R.drawable.ic_jog_dial_sound_on; + final int toastIcon = mSilentMode ? + R.drawable.ic_lock_ringer_off : + R.drawable.ic_lock_ringer_on; + mRotary.setRightHandleResource(handleIcon); + String message = mSilentMode ? + getContext().getString(R.string.global_action_silent_mode_on_status) : + getContext().getString(R.string.global_action_silent_mode_off_status); + toastMessage(mScreenLocked, message, toastIcon); + mCallback.pokeWakelock(); } } - private void refreshSimBadInfo() { - final IccCard.State simState = mUpdateMonitor.getSimState(); - if (simState == IccCard.State.PUK_REQUIRED) { - mHeaderSimBad1.setText(R.string.lockscreen_sim_puk_locked_message); - mHeaderSimBad2.setText(R.string.lockscreen_sim_puk_locked_instructions); - } else if (simState == IccCard.State.ABSENT) { - mHeaderSimBad1.setText(R.string.lockscreen_missing_sim_message); - mHeaderSimBad2.setVisibility(View.GONE); - //mHeaderSimBad2.setText(R.string.lockscreen_missing_sim_instructions); - } else { - mHeaderSimBad1.setVisibility(View.GONE); - mHeaderSimBad2.setVisibility(View.GONE); - } + /** {@inheritDoc} */ + public void onGrabbedStateChange(View v, int grabbedState) { + // TODO: Update onscreen hint text based on the new state. } - private void refreshUnlockIntructions() { - if (mLockPatternUtils.isLockPatternEnabled() - || mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED - || mUpdateMonitor.getSimState() == IccCard.State.ABSENT) { - mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_enabled); - } else { - mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_disabled); + /** + * Displays a message in a text view and then removes it. + * @param textView The text view. + * @param text The text. + * @param iconResourceId The left hand icon. + */ + private void toastMessage(final TextView textView, final String text, final int iconResourceId) { + if (mPendingR1 != null) { + textView.removeCallbacks(mPendingR1); + mPendingR1 = null; } + if (mPendingR2 != null) { + textView.removeCallbacks(mPendingR2); + mPendingR2 = null; + } + + mPendingR1 = new Runnable() { + public void run() { + textView.setText(text); + textView.setCompoundDrawablesWithIntrinsicBounds(iconResourceId, 0, 0, 0); + textView.setCompoundDrawablePadding(4); + } + }; + textView.postDelayed(mPendingR1, 0); + mPendingR2 = new Runnable() { + public void run() { + textView.setText(""); + textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + } + }; + textView.postDelayed(mPendingR2, 3500); } + private Runnable mPendingR1; + private Runnable mPendingR2; + private void refreshAlarmDisplay() { - final String nextAlarmText = mLockPatternUtils.getNextAlarm(); - - // bug 1685880: if we are in landscape and showing plmn, the information can end up not - // fitting on screen. in this case, the alarm will get cut. - final CharSequence plmn = mUpdateMonitor.getTelephonyPlmn(); - final boolean showingPlmn = plmn != null && !TextUtils.isEmpty(plmn); - final boolean wontFit = !mUpdateMonitor.isInPortrait() && showingPlmn; - if (nextAlarmText != null && mSimOk && !wontFit) { - setAlarmInfoVisible(true); - mAlarmText.setText(nextAlarmText); - } else { - setAlarmInfoVisible(false); + mNextAlarm = mLockPatternUtils.getNextAlarm(); + if (mNextAlarm != null) { + mAlarmIcon = getContext().getResources().getDrawable(R.drawable.ic_lock_idle_alarm); } + updateStatusLines(); } - private void setAlarmInfoVisible(boolean visible) { - final int visibilityFlag = visible ? View.VISIBLE : View.GONE; - mNextAlarmGroup.setVisibility(visibilityFlag); - mAlarmSpacer.setVisibility(visibilityFlag); - } - - + /** {@inheritDoc} */ public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + if (DBG) Log.d(TAG, "onRefreshBatteryInfo(" + showBatteryInfo + ", " + pluggedIn + ")"); mShowingBatteryInfo = showBatteryInfo; mPluggedIn = pluggedIn; mBatteryLevel = batteryLevel; - refreshBatteryDisplay(); + refreshBatteryStringAndIcon(); + updateStatusLines(); } - private void refreshBatteryDisplay() { - if (!mShowingBatteryInfo || !mSimOk) { - mBatteryInfoGroup.setVisibility(View.GONE); - mBatteryInfoSpacer.setVisibility(View.GONE); + private void refreshBatteryStringAndIcon() { + if (!mShowingBatteryInfo) { + mCharging = null; return; } - mBatteryInfoGroup.setVisibility(View.VISIBLE); - mBatteryInfoSpacer.setVisibility(View.VISIBLE); + + if (mChargingIcon == null) { + mChargingIcon = + getContext().getResources().getDrawable(R.drawable.ic_lock_idle_charging); + } if (mPluggedIn) { - mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_charging); if (mBatteryLevel >= 100) { - mBatteryInfoText.setText(R.string.lockscreen_charged); + mCharging = getContext().getString(R.string.lockscreen_charged); } else { - mBatteryInfoText.setText( - getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel)); + mCharging = getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel); } } else { - mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_low_battery); - mBatteryInfoText.setText(R.string.lockscreen_low_battery); + mCharging = getContext().getString(R.string.lockscreen_low_battery); } } + /** {@inheritDoc} */ public void onTimeChanged() { refreshTimeAndDateDisplay(); } private void refreshTimeAndDateDisplay() { Date now = new Date(); - mTime.setText(DateFormat.getTimeFormat(getContext()).format(now)); - mDate.setText(DateFormat.getDateFormat(getContext()).format(now)); + mTime.setText(mTimeFormat.format(now)); + mDate.setText(mDateFormat.format(now)); } - public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { - refreshSimOkHeaders(plmn, spn); - refreshAlarmDisplay(); // in case alarm won't fit anymore + /** + * @return A localized format like "Fri, Sep 18, 2009" + */ + private java.text.DateFormat getLockScreenDateFormat() { + SimpleDateFormat adjusted = null; + try { + // this call gives us the localized order + final SimpleDateFormat dateFormat = (SimpleDateFormat) + java.text.DateFormat.getDateInstance(java.text.DateFormat.FULL); + adjusted = new SimpleDateFormat(dateFormat.toPattern() + .replace("MMMM", "MMM") // we want "Sep", not "September" + .replace("EEEE", "EEE")); // we want "Fri", no "Friday" + } catch (ClassCastException e) { + // in case the library implementation changes and this throws a class cast exception + // or anything else that is funky + Log.e("LockScreen", "couldn't finnagle our custom date format :(", e); + return java.text.DateFormat.getDateInstance(java.text.DateFormat.MEDIUM); + } + return adjusted; } - private void refreshSimOkHeaders(CharSequence plmn, CharSequence spn) { - final IccCard.State simState = mUpdateMonitor.getSimState(); - if (simState == IccCard.State.READY) { - if (plmn != null && !TextUtils.isEmpty(plmn)) { - mHeaderSimOk1.setVisibility(View.VISIBLE); - mHeaderSimOk1.setText(plmn); - } else { - mHeaderSimOk1.setVisibility(View.GONE); - } - - if (spn != null && !TextUtils.isEmpty(spn)) { - mHeaderSimOk2.setVisibility(View.VISIBLE); - mHeaderSimOk2.setText(spn); - } else { - mHeaderSimOk2.setVisibility(View.GONE); - } - } else if (simState == IccCard.State.PIN_REQUIRED) { - mHeaderSimOk1.setVisibility(View.VISIBLE); - mHeaderSimOk1.setText(R.string.lockscreen_sim_locked_message); - mHeaderSimOk2.setVisibility(View.GONE); - } else if (simState == IccCard.State.ABSENT) { - mHeaderSimOk1.setVisibility(View.VISIBLE); - mHeaderSimOk1.setText(R.string.lockscreen_missing_sim_message_short); - mHeaderSimOk2.setVisibility(View.GONE); - } else if (simState == IccCard.State.NETWORK_LOCKED) { - mHeaderSimOk1.setVisibility(View.VISIBLE); - mHeaderSimOk1.setText(R.string.lockscreen_network_locked_message); - mHeaderSimOk2.setVisibility(View.GONE); + 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); } } - public void onSimStateChanged(IccCard.State simState) { - mSimOk = isSimOk(simState); - refreshViewsWRTSimOk(); - refreshUnlockIntructions(); + /** {@inheritDoc} */ + public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + if (DBG) Log.d(TAG, "onRefreshCarrierInfo(" + plmn + ", " + spn + ")"); + updateLayout(mStatus); + } + + private void putEmergencyBelow(int viewId) { + final RelativeLayout.LayoutParams layoutParams = + (RelativeLayout.LayoutParams) mEmergencyCallButton.getLayoutParams(); + layoutParams.addRule(RelativeLayout.BELOW, viewId); + mEmergencyCallButton.setLayoutParams(layoutParams); } /** - * @return Whether the sim state is ok, meaning we don't need to show - * a special screen with the emergency call button and keep them from - * doing anything else. + * Determine the current status of the lock screen given the sim state and other stuff. */ - private boolean isSimOk(IccCard.State simState) { + private Status getCurrentStatus(IccCard.State simState) { boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned() && simState == IccCard.State.ABSENT); - return !(missingAndNotProvisioned || simState == IccCard.State.PUK_REQUIRED); + if (missingAndNotProvisioned) { + return Status.SimMissingLocked; + } + + switch (simState) { + case ABSENT: + return Status.SimMissing; + case NETWORK_LOCKED: + return Status.SimMissingLocked; + case NOT_READY: + return Status.SimMissing; + case PIN_REQUIRED: + return Status.SimLocked; + case PUK_REQUIRED: + return Status.SimPukLocked; + case READY: + return Status.Normal; + case UNKNOWN: + return Status.SimMissing; + } + return Status.SimMissing; } + /** + * Update the layout to match the current status. + */ + private void updateLayout(Status status) { + switch (status) { + case Normal: + // text + mCarrier.setText( + getCarrierString( + mUpdateMonitor.getTelephonyPlmn(), + mUpdateMonitor.getTelephonySpn())); +// mScreenLocked.setText(R.string.lockscreen_screen_locked); + + // layout + mScreenLocked.setVisibility(View.VISIBLE); + mRotary.setVisibility(View.VISIBLE); + mEmergencyCallButton.setVisibility(View.GONE); + break; + case NetworkLocked: + // text + mCarrier.setText(R.string.lockscreen_network_locked_message); + mScreenLocked.setText(R.string.lockscreen_instructions_when_pattern_disabled); + + // layout + mScreenLocked.setVisibility(View.VISIBLE); + mRotary.setVisibility(View.VISIBLE); + mEmergencyCallButton.setVisibility(View.GONE); + break; + case SimMissing: + // text + mCarrier.setText(R.string.lockscreen_missing_sim_message_short); + mScreenLocked.setText(R.string.lockscreen_instructions_when_pattern_disabled); + + // layout + mScreenLocked.setVisibility(View.INVISIBLE); + mRotary.setVisibility(View.VISIBLE); + mEmergencyCallButton.setVisibility(View.VISIBLE); + putEmergencyBelow(R.id.divider); + break; + case SimMissingLocked: + // text + mCarrier.setText(R.string.lockscreen_missing_sim_message_short); + mScreenLocked.setText(R.string.lockscreen_missing_sim_instructions); + + // layout + mScreenLocked.setVisibility(View.VISIBLE); + mRotary.setVisibility(View.GONE); + mEmergencyCallButton.setVisibility(View.VISIBLE); + putEmergencyBelow(R.id.screenLocked); + break; + case SimLocked: + // text + mCarrier.setText(R.string.lockscreen_sim_locked_message); + + // layout + mScreenLocked.setVisibility(View.INVISIBLE); + mRotary.setVisibility(View.VISIBLE); + mEmergencyCallButton.setVisibility(View.GONE); + break; + case SimPukLocked: + // text + mCarrier.setText(R.string.lockscreen_sim_puk_locked_message); + mScreenLocked.setText(R.string.lockscreen_sim_puk_locked_instructions); + + // layout + mScreenLocked.setVisibility(View.VISIBLE); + mRotary.setVisibility(View.GONE); + mEmergencyCallButton.setVisibility(View.VISIBLE); + putEmergencyBelow(R.id.screenLocked); + break; + } + } + + static CharSequence getCarrierString(CharSequence telephonyPlmn, CharSequence telephonySpn) { + if (telephonyPlmn != null && telephonySpn == null) { + return telephonyPlmn; + } else if (telephonyPlmn != null && telephonySpn != null) { + return telephonyPlmn + "\n" + telephonySpn; + } else if (telephonyPlmn == null && telephonySpn != null) { + return telephonySpn; + } else { + return ""; + } + } + + public void onSimStateChanged(IccCard.State simState) { + if (DBG) Log.d(TAG, "onSimStateChanged(" + simState + ")"); + mStatus = getCurrentStatus(simState); + updateLayout(mStatus); + updateStatusLines(); + } + + public void onOrientationChange(boolean inPortrait) { + if (inPortrait != mCreatedInPortrait) { + mCallback.recreateMe(); + } } public void onKeyboardChange(boolean isKeyboardOpen) { - if (isKeyboardOpen) { + if (mUpdateMonitor.isKeyguardBypassEnabled() && isKeyboardOpen) { mCallback.goToUnlockScreen(); } } @@ -376,7 +571,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM /** {@inheritDoc} */ public void onResume() { - + resetStatusInfo(mUpdateMonitor); } /** {@inheritDoc} */ @@ -384,4 +579,3 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mUpdateMonitor.removeCallback(this); } } - diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 6341771ac0f6..6dd5d934b713 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -20,6 +20,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; 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 com.android.internal.view.menu.ContextMenuBuilder; import com.android.internal.view.menu.MenuBuilder; @@ -34,7 +35,6 @@ import android.content.Intent; import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Canvas; -import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -124,6 +124,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * this is 0, there is no key held down. */ private int mPanelChordingKey; + private boolean mPanelMayLongPress; private ImageView mLeftIconView; @@ -155,120 +156,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private TelephonyManager mTelephonyManager = null; - private boolean mSearchKeyDownReceived; - - private boolean mKeycodeCallTimeoutActive = false; - - private boolean mKeycodeCameraTimeoutActive = false; - - static final int MSG_MENU_LONG_PRESS = 1; - static final int MSG_MENU_LONG_PRESS_COMPLETE = 2; - static final int MSG_CALL_LONG_PRESS = 3; - static final int MSG_CALL_LONG_PRESS_COMPLETE = 4; - static final int MSG_CAMERA_LONG_PRESS = 5; - static final int MSG_CAMERA_LONG_PRESS_COMPLETE = 6; - static final int MSG_SEARCH_LONG_PRESS = 7; - static final int MSG_SEARCH_LONG_PRESS_COMPLETE = 8; - - private final Handler mKeycodeMenuTimeoutHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_MENU_LONG_PRESS: { - if (mPanelChordingKey == 0) return; - // Before actually doing the long press, enqueue another - // message and do the processing there. This helps if - // the app isn't being responsive, and finally woke up -- - // if the window manager wasn't told about it processing - // the down key for too long, it would enqueue the key up - // at a time after the timeout of this message. So we go - // through another message, to make sure we process an up - // before continuing. - mKeycodeMenuTimeoutHandler.sendEmptyMessage( - MSG_MENU_LONG_PRESS_COMPLETE); - break; - } - case MSG_CALL_LONG_PRESS: { - if (!mKeycodeCallTimeoutActive) return; - // See above. - mKeycodeMenuTimeoutHandler.sendEmptyMessage( - MSG_CALL_LONG_PRESS_COMPLETE); - break; - } - case MSG_CAMERA_LONG_PRESS: { - if (!mKeycodeCameraTimeoutActive) return; - // See above. - Message newMessage = Message.obtain(msg); - newMessage.what = MSG_CAMERA_LONG_PRESS_COMPLETE; - mKeycodeMenuTimeoutHandler.sendMessage(newMessage); - break; - } - case MSG_SEARCH_LONG_PRESS: { - if (!mSearchKeyDownReceived) return; - // See above. - Message newMessage = Message.obtain(msg); - newMessage.what = MSG_SEARCH_LONG_PRESS_COMPLETE; - mKeycodeMenuTimeoutHandler.sendMessage(newMessage); - break; - } - case MSG_MENU_LONG_PRESS_COMPLETE: { - if (mPanelChordingKey == 0) return; - mPanelChordingKey = 0; - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - InputMethodManager imm = (InputMethodManager) - getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - if (imm != null) { - imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); - } - } break; - case MSG_CALL_LONG_PRESS_COMPLETE: { - if (!mKeycodeCallTimeoutActive) return; - mKeycodeCallTimeoutActive = false; - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - // launch the VoiceDialer - Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - sendCloseSystemWindows(); - getContext().startActivity(intent); - } catch (ActivityNotFoundException e) { - startCallActivity(); - } - } break; - case MSG_CAMERA_LONG_PRESS_COMPLETE: { - if (!mKeycodeCameraTimeoutActive) return; - mKeycodeCameraTimeoutActive = false; - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - sendCloseSystemWindows(); - // Broadcast an intent that the Camera button was longpressed - Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); - intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj); - getContext().sendOrderedBroadcast(intent, null); - } break; - case MSG_SEARCH_LONG_PRESS_COMPLETE: { - if (getKeyguardManager().inKeyguardRestrictedInputMode() || - !mSearchKeyDownReceived) { - mSearchKeyDownReceived = false; - return; - } - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - // launch the search activity - Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - sendCloseSystemWindows(); - getContext().startActivity(intent); - // Only clear this if we successfully start the - // activity; otherwise we will allow the normal short - // press action to be performed. - mSearchKeyDownReceived = false; - } catch (ActivityNotFoundException e) { - } - } break; - } - } - }; - public PhoneWindow(Context context) { super(context); mLayoutInflater = LayoutInflater.from(context); @@ -295,11 +182,9 @@ 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"); } - /* FEATURE_OPENGL disabled for 1.0 if (featureId == FEATURE_OPENGL) { getAttributes().memoryType = WindowManager.LayoutParams.MEMORY_TYPE_GPU; } - */ return super.requestFeature(featureId); } @@ -567,7 +452,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { WindowManager.LayoutParams lp = new WindowManager.LayoutParams( WRAP_CONTENT, WRAP_CONTENT, - st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, + st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG, WindowManager.LayoutParams.FLAG_DITHER | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, st.decorView.mDefaultOpacity); @@ -649,19 +534,35 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * @return Whether the key was handled. */ public final boolean onKeyDownPanel(int featureId, KeyEvent event) { - // The panel key was pushed, so set the chording key - mPanelChordingKey = event.getKeyCode(); - - PanelFeatureState st = getPanelState(featureId, true); - if (!st.isOpen) { - if (getContext().getResources().getConfiguration().keyboard - == Configuration.KEYBOARD_NOKEYS) { - mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); - mKeycodeMenuTimeoutHandler.sendMessageDelayed( - mKeycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS), - ViewConfiguration.getLongPressTimeout()); + final int keyCode = event.getKeyCode(); + + if (event.getRepeatCount() == 0) { + // 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 + == Configuration.KEYBOARD_NOKEYS) { + mPanelMayLongPress = true; + } + 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 + // should be executed... do it! + mPanelChordingKey = 0; + mPanelMayLongPress = false; + InputMethodManager imm = (InputMethodManager) + getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); } - return preparePanel(st, event); + } return false; @@ -676,8 +577,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // The panel key was released, so clear the chording key if (mPanelChordingKey != 0) { mPanelChordingKey = 0; - mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); + mPanelMayLongPress = false; + if (event.isCanceled()) { + return; + } + boolean playSoundEffect = false; PanelFeatureState st = getPanelState(featureId, true); if (st.isOpen || st.isHandled) { @@ -1214,6 +1119,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * @see android.view.KeyEvent */ protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) { + final KeyEvent.DispatcherState dispatcher = + mDecor != null ? mDecor.getKeyDispatcherState() : null; + //Log.i(TAG, "Key down: repeat=" + event.getRepeatCount() + // + " flags=0x" + Integer.toHexString(event.getFlags())); + switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: { @@ -1260,21 +1170,25 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } case KeyEvent.KEYCODE_CAMERA: { - if (getKeyguardManager().inKeyguardRestrictedInputMode()) { + if (getKeyguardManager().inKeyguardRestrictedInputMode() + || dispatcher == null) { break; } - if (event.getRepeatCount() > 0) break; - mKeycodeCameraTimeoutActive = true; - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); - Message message = mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CAMERA_LONG_PRESS); - message.obj = event; - mKeycodeMenuTimeoutHandler.sendMessageDelayed(message, - ViewConfiguration.getLongPressTimeout()); + if (event.getRepeatCount() == 0) { + dispatcher.startTracking(event, this); + } else if (event.isLongPress() && dispatcher.isTracking(event)) { + dispatcher.performedLongPress(event); + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + sendCloseSystemWindows(); + // Broadcast an intent that the Camera button was longpressed + Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, event); + getContext().sendOrderedBroadcast(intent, null); + } return true; } case KeyEvent.KEYCODE_MENU: { - if (event.getRepeatCount() > 0) break; onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event); return true; } @@ -1282,48 +1196,61 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { case KeyEvent.KEYCODE_BACK: { if (event.getRepeatCount() > 0) break; if (featureId < 0) break; - if (featureId == FEATURE_OPTIONS_PANEL) { - PanelFeatureState st = getPanelState(featureId, false); - if (st != null && st.isInExpandedMode) { - // If the user is in an expanded menu and hits back, it - // should go back to the icon menu - reopenMenu(true); - return true; - } - } - closePanel(featureId); + // Currently don't do anything with long press. + dispatcher.startTracking(event, this); return true; } case KeyEvent.KEYCODE_CALL: { - if (getKeyguardManager().inKeyguardRestrictedInputMode()) { + if (getKeyguardManager().inKeyguardRestrictedInputMode() + || dispatcher == null) { break; } - if (event.getRepeatCount() > 0) break; - mKeycodeCallTimeoutActive = true; - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); - mKeycodeMenuTimeoutHandler.sendMessageDelayed( - mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CALL_LONG_PRESS), - ViewConfiguration.getLongPressTimeout()); + if (event.getRepeatCount() == 0) { + dispatcher.startTracking(event, this); + } else if (event.isLongPress() && dispatcher.isTracking(event)) { + dispatcher.performedLongPress(event); + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + // launch the VoiceDialer + Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + sendCloseSystemWindows(); + getContext().startActivity(intent); + } catch (ActivityNotFoundException e) { + startCallActivity(); + } + } return true; } case KeyEvent.KEYCODE_SEARCH: { + if (getKeyguardManager().inKeyguardRestrictedInputMode() + || dispatcher == null) { + break; + } if (event.getRepeatCount() == 0) { - mSearchKeyDownReceived = true; + dispatcher.startTracking(event, this); + } else if (event.isLongPress() && dispatcher.isTracking(event)) { Configuration config = getContext().getResources().getConfiguration(); if (config.keyboard == Configuration.KEYBOARD_NOKEYS - || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { - // If this device does not have a hardware keyboard, - // or that keyboard is hidden, then we can't use the - // search key for chording to perform shortcuts; - // instead, we will let the user long press, - mKeycodeMenuTimeoutHandler.removeMessages(MSG_SEARCH_LONG_PRESS); - mKeycodeMenuTimeoutHandler.sendMessageDelayed( - mKeycodeMenuTimeoutHandler.obtainMessage(MSG_SEARCH_LONG_PRESS), - ViewConfiguration.getLongPressTimeout()); + || config.hardKeyboardHidden + == Configuration.HARDKEYBOARDHIDDEN_YES) { + // launch the search activity + Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + sendCloseSystemWindows(); + getContext().startActivity(intent); + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + // Only clear this if we successfully start the + // activity; otherwise we will allow the normal short + // press action to be performed. + dispatcher.performedLongPress(event); + } catch (ActivityNotFoundException e) { + // Ignore + } } - return true; } break; } @@ -1349,6 +1276,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * @see android.view.KeyEvent */ protected boolean onKeyUp(int featureId, int keyCode, KeyEvent event) { + final KeyEvent.DispatcherState dispatcher = + mDecor != null ? mDecor.getKeyDispatcherState() : null; + if (dispatcher != null) { + dispatcher.handleUpEvent(event); + } + //Log.i(TAG, "Key up: repeat=" + event.getRepeatCount() + // + " flags=0x" + Integer.toHexString(event.getFlags())); + switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: { @@ -1374,6 +1309,24 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return true; } + case KeyEvent.KEYCODE_BACK: { + if (featureId < 0) break; + if (event.isTracking() && !event.isCanceled()) { + if (featureId == FEATURE_OPTIONS_PANEL) { + PanelFeatureState st = getPanelState(featureId, false); + if (st != null && st.isInExpandedMode) { + // If the user is in an expanded menu and hits back, it + // should go back to the icon menu + reopenMenu(true); + return true; + } + } + closePanel(featureId); + return true; + } + break; + } + case KeyEvent.KEYCODE_HEADSETHOOK: case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: case KeyEvent.KEYCODE_MEDIA_STOP: @@ -1391,11 +1344,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (getKeyguardManager().inKeyguardRestrictedInputMode()) { break; } - if (event.getRepeatCount() > 0) break; // Can a key up event repeat? - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); - if (!mKeycodeCameraTimeoutActive) break; - mKeycodeCameraTimeoutActive = false; - // Add short press behavior here if desired + if (event.isTracking() && !event.isCanceled()) { + // Add short press behavior here if desired + } return true; } @@ -1403,11 +1354,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (getKeyguardManager().inKeyguardRestrictedInputMode()) { break; } - if (event.getRepeatCount() > 0) break; - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); - if (!mKeycodeCallTimeoutActive) break; - mKeycodeCallTimeoutActive = false; - startCallActivity(); + if (event.isTracking() && !event.isCanceled()) { + startCallActivity(); + } return true; } @@ -1416,13 +1365,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * Do this in onKeyUp since the Search key is also used for * chording quick launch shortcuts. */ - if (getKeyguardManager().inKeyguardRestrictedInputMode() || - !mSearchKeyDownReceived) { - mSearchKeyDownReceived = false; + if (getKeyguardManager().inKeyguardRestrictedInputMode()) { break; } - mSearchKeyDownReceived = false; - launchDefaultSearch(); + if (event.isTracking() && !event.isCanceled()) { + launchDefaultSearch(); + } return true; } } @@ -1584,9 +1532,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { PanelFeatureState st; for (int i = panels.length - 1; i >= 0; i--) { st = panels[i]; - if ((st != null) && st.isOpen) { - // Clear st.isOpen (openPanel will not open if it's already open) - st.isOpen = false; + // We restore the panel if it was last open; we skip it if it + // now is open, to avoid a race condition if the user immediately + // opens it when we are resuming. + if ((st != null) && !st.isOpen && st.wasLastOpen) { + st.isInExpandedMode = st.wasLastExpanded; openPanel(st, null); } } @@ -1606,8 +1556,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private final Rect mFrameOffsets = new Rect(); - private final Paint mBlackPaint = new Paint(); - private boolean mChanging; private Drawable mMenuBackground; @@ -1617,7 +1565,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public DecorView(Context context, int featureId) { super(context); mFeatureId = featureId; - mBlackPaint.setColor(0xFF000000); } @Override @@ -2009,16 +1956,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); - // no KEYCODE_CALL events active across focus changes - mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS); - mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS); - mKeycodeCallTimeoutActive = false; - mKeycodeCameraTimeoutActive = false; + mPanelMayLongPress = false; // If the user is chording a menu shortcut, release the chord since // this window lost focus - if (!hasWindowFocus && mPanelChordingKey > 0) { + if (!hasWindowFocus && mPanelChordingKey != 0) { closePanel(FEATURE_OPTIONS_PANEL); } @@ -2031,6 +1973,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); + + final Callback cb = getCallback(); + if (cb != null && mFeatureId < 0) { + cb.onAttachedToWindow(); + } if (mFeatureId == -1) { /* @@ -2043,6 +1990,23 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { openPanelsAfterRestore(); } } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + final Callback cb = getCallback(); + if (cb != null && mFeatureId < 0) { + cb.onDetachedFromWindow(); + } + } + + @Override + public void onCloseSystemDialogs(String reason) { + if (mFeatureId >= 0) { + closeAllPanels(); + } + } } protected DecorView generateDecor() { @@ -2097,6 +2061,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags())); } + if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) { + setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags())); + } + WindowManager.LayoutParams params = getAttributes(); if (!hasSoftInputMode()) { @@ -2606,6 +2574,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { boolean refreshDecorView; + boolean wasLastOpen; + + boolean wasLastExpanded; + /** * Contains the state of the menu when told to freeze. */ @@ -2654,8 +2626,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { void onRestoreInstanceState(Parcelable state) { SavedState savedState = (SavedState) state; featureId = savedState.featureId; - isOpen = savedState.isOpen; - isInExpandedMode = savedState.isInExpandedMode; + wasLastOpen = savedState.isOpen; + wasLastExpanded = savedState.isInExpandedMode; frozenMenuState = savedState.menuState; /* diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java old mode 100644 new mode 100755 index 8140b3dbf7ee..e57fbe8b544b --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -20,17 +20,19 @@ import android.app.Activity; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.IStatusBar; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; -import android.content.ContentQueryMap; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Rect; +import android.os.BatteryManager; import android.os.Handler; import android.os.IBinder; import android.os.LocalPowerManager; @@ -67,6 +69,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; +import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; @@ -88,8 +91,12 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; +import android.view.WindowManagerPolicy.WindowState; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; import android.media.IAudioService; import android.media.AudioManager; @@ -108,29 +115,31 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final boolean SHOW_STARTING_ANIMATIONS = true; static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; - static final int APPLICATION_LAYER = 1; - static final int PHONE_LAYER = 2; - static final int SEARCH_BAR_LAYER = 3; - static final int STATUS_BAR_PANEL_LAYER = 4; + // wallpaper is at the bottom, though the window manager may move it. + static final int WALLPAPER_LAYER = 2; + static final int APPLICATION_LAYER = 2; + static final int PHONE_LAYER = 3; + static final int SEARCH_BAR_LAYER = 4; + static final int STATUS_BAR_PANEL_LAYER = 5; // toasts and the plugged-in battery thing - static final int TOAST_LAYER = 5; - static final int STATUS_BAR_LAYER = 6; + static final int TOAST_LAYER = 6; + static final int STATUS_BAR_LAYER = 7; // SIM errors and unlock. Not sure if this really should be in a high layer. - static final int PRIORITY_PHONE_LAYER = 7; + static final int PRIORITY_PHONE_LAYER = 8; // like the ANR / app crashed dialogs - static final int SYSTEM_ALERT_LAYER = 8; + static final int SYSTEM_ALERT_LAYER = 9; // system-level error dialogs - static final int SYSTEM_ERROR_LAYER = 9; + static final int SYSTEM_ERROR_LAYER = 10; // on-screen keyboards and other such input method user interfaces go here. - static final int INPUT_METHOD_LAYER = 10; + static final int INPUT_METHOD_LAYER = 11; // on-screen keyboards and other such input method user interfaces go here. - static final int INPUT_METHOD_DIALOG_LAYER = 11; + static final int INPUT_METHOD_DIALOG_LAYER = 12; // the keyguard; nothing on top of these can take focus, since they are // responsible for power management when displayed. - static final int KEYGUARD_LAYER = 12; - static final int KEYGUARD_DIALOG_LAYER = 13; + static final int KEYGUARD_LAYER = 13; + static final int KEYGUARD_DIALOG_LAYER = 14; // things in here CAN NOT take focus, but are shown on top of everything else. - static final int SYSTEM_OVERLAY_LAYER = 14; + static final int SYSTEM_OVERLAY_LAYER = 15; static final int APPLICATION_MEDIA_SUBLAYER = -2; static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; @@ -146,9 +155,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; - // Vibrator pattern for haptic feedback of a long press. - private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21}; - final Object mLock = new Object(); Context mContext; @@ -156,6 +162,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { LocalPowerManager mPowerManager; Vibrator mVibrator; // Vibrator for giving feedback of orientation changes + // Vibrator pattern for haptic feedback of a long press. + long[] mLongPressVibePattern; + + // Vibrator pattern for haptic feedback of virtual key press. + long[] mVirtualKeyVibePattern; + + // Vibrator pattern for haptic feedback during boot when safe mode is disabled. + long[] mSafeModeDisabledVibePattern; + + // Vibrator pattern for haptic feedback during boot when safe mode is enabled. + long[] mSafeModeEnabledVibePattern; + /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ boolean mEnableShiftMenuBugReports = false; @@ -168,7 +186,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { RecentApplicationsDialog mRecentAppsDialog; Handler mHandler; + final IntentFilter mBatteryStatusFilter = new IntentFilter(); + boolean mLidOpen; + int mPlugged; + boolean mRegisteredBatteryReceiver; + int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + int mLidOpenRotation; + int mCarDockRotation; + int mDeskDockRotation; + int mCarDockKeepsScreenOn; + int mDeskDockKeepsScreenOn; + boolean mCarDockEnablesAccelerometer; + boolean mDeskDockEnablesAccelerometer; + int mLidKeyboardAccessibility; + int mLidNavigationAccessibility; boolean mScreenOn = false; boolean mOrientationSensorEnabled = false; int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -200,9 +232,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowState mTopFullscreenOpaqueWindowState; boolean mForceStatusBar; - boolean mHideKeyguard; + boolean mHideLockScreen; + boolean mDismissKeyguard; boolean mHomePressed; Intent mHomeIntent; + Intent mCarDockIntent; + Intent mDeskDockIntent; boolean mSearchKeyPressed; boolean mConsumeSearchKeyUp; @@ -219,6 +254,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { ShortcutManager mShortcutManager; PowerManager.WakeLock mBroadcastWakeLock; + PowerManager.WakeLock mDockWakeLock; class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler) { @@ -284,7 +320,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void onOrientationChanged(int rotation) { // Send updates based on orientation value - if (true) Log.i(TAG, "onOrientationChanged, rotation changed to " +rotation); + if (localLOGV) Log.v(TAG, "onOrientationChanged, rotation changed to " +rotation); try { mWindowManager.setRotation(rotation, false, mFancyRotationAnimation); @@ -297,14 +333,27 @@ public class PhoneWindowManager implements WindowManagerPolicy { MyOrientationListener mOrientationListener; boolean useSensorForOrientationLp(int appOrientation) { + // The app says use the sensor. if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { return true; } - if (mAccelerometerDefault != 0 && ( - appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || - appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { + // The user preference says we can rotate, and the app is willing to rotate. + if (mAccelerometerDefault != 0 && + (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER + || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { return true; } + // We're in a dock that has a rotation affinity, an the app is willing to rotate. + if ((mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR) + || (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) { + // Note we override the nosensor flag here. + if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER + || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { + return true; + } + } + // Else, don't use the sensor. return false; } @@ -319,6 +368,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // orientation, then we need to turn the sensor or. return true; } + if ((mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR) || + (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) { + // enable accelerometer if we are docked in a dock that enables accelerometer + // orientation management, + return true; + } if (mAccelerometerDefault == 0) { // If the setting for using the sensor by default is enabled, then // we will always leave it on. Note that the user could go to @@ -350,7 +405,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } //Could have been invoked due to screen turning on or off or //change of the currently visible window's orientation - if (localLOGV) Log.i(TAG, "Screen status="+mScreenOn+ + if (localLOGV) Log.v(TAG, "Screen status="+mScreenOn+ ", current orientation="+mCurrentAppOrientation+ ", SensorEnabled="+mOrientationSensorEnabled); boolean disable = true; @@ -360,7 +415,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { //enable listener if not already enabled if (!mOrientationSensorEnabled) { mOrientationListener.enable(); - if(localLOGV) Log.i(TAG, "Enabling listeners"); + if(localLOGV) Log.v(TAG, "Enabling listeners"); mOrientationSensorEnabled = true; } } @@ -368,12 +423,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { //check if sensors need to be disabled if (disable && mOrientationSensorEnabled) { mOrientationListener.disable(); - if(localLOGV) Log.i(TAG, "Disabling listeners"); + if(localLOGV) Log.v(TAG, "Disabling listeners"); mOrientationSensorEnabled = false; } } - Runnable mEndCallLongPress = new Runnable() { + Runnable mPowerLongPress = new Runnable() { public void run() { mShouldTurnOffOnKeyUp = false; performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); @@ -443,10 +498,81 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHomeIntent.addCategory(Intent.CATEGORY_HOME); mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + mCarDockIntent = new Intent(Intent.ACTION_MAIN, null); + mCarDockIntent.addCategory(Intent.CATEGORY_CAR_DOCK); + mCarDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + mDeskDockIntent = new Intent(Intent.ACTION_MAIN, null); + 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"); + mDockWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, + "PhoneWindowManager.mDockWakeLock"); + mDockWakeLock.setReferenceCounted(false); mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); + mLidOpenRotation = readRotation( + com.android.internal.R.integer.config_lidOpenRotation); + mCarDockRotation = readRotation( + com.android.internal.R.integer.config_carDockRotation); + mDeskDockRotation = readRotation( + com.android.internal.R.integer.config_deskDockRotation); + mCarDockKeepsScreenOn = mContext.getResources().getInteger( + com.android.internal.R.integer.config_carDockKeepsScreenOn); + mDeskDockKeepsScreenOn = mContext.getResources().getInteger( + com.android.internal.R.integer.config_deskDockKeepsScreenOn); + mCarDockEnablesAccelerometer = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_carDockEnablesAccelerometer); + mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_deskDockEnablesAccelerometer); + mLidKeyboardAccessibility = mContext.getResources().getInteger( + com.android.internal.R.integer.config_lidKeyboardAccessibility); + mLidNavigationAccessibility = mContext.getResources().getInteger( + com.android.internal.R.integer.config_lidNavigationAccessibility); + // register for battery events + mBatteryStatusFilter.addAction(Intent.ACTION_BATTERY_CHANGED); + mPlugged = 0; + updatePlugged(context.registerReceiver(null, mBatteryStatusFilter)); + // register for dock events + context.registerReceiver(mDockReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT)); + mVibrator = new Vibrator(); + mLongPressVibePattern = getLongIntArray(mContext.getResources(), + com.android.internal.R.array.config_longPressVibePattern); + mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(), + com.android.internal.R.array.config_virtualKeyVibePattern); + mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(), + com.android.internal.R.array.config_safeModeDisabledVibePattern); + mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), + com.android.internal.R.array.config_safeModeEnabledVibePattern); + } + + void updatePlugged(Intent powerIntent) { + if (localLOGV) Log.v(TAG, "New battery status: " + powerIntent.getExtras()); + if (powerIntent != null) { + mPlugged = powerIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); + if (localLOGV) Log.v(TAG, "PLUGGED: " + mPlugged); + } + } + + private int readRotation(int resID) { + try { + int rotation = mContext.getResources().getInteger(resID); + switch (rotation) { + case 0: + return Surface.ROTATION_0; + case 90: + return Surface.ROTATION_90; + case 180: + return Surface.ROTATION_180; + case 270: + return Surface.ROTATION_270; + } + } catch (Resources.NotFoundException e) { + // fall through + } + return -1; } /** {@inheritDoc} */ @@ -465,7 +591,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // monitor/control what they are doing. break; case TYPE_INPUT_METHOD: - // The window manager will check this. + case TYPE_WALLPAPER: + // The window manager will check these. break; case TYPE_PHONE: case TYPE_PRIORITY_PHONE: @@ -499,7 +626,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { void readLidState() { try { - int sw = mWindowManager.getSwitchState(0); + int sw = mWindowManager.getSwitchState(RawInputEvent.SW_LID); if (sw >= 0) { mLidOpen = sw == 0; } @@ -508,17 +635,32 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private int determineHiddenState(boolean lidOpen, + int mode, int hiddenValue, int visibleValue) { + switch (mode) { + case 1: + return lidOpen ? visibleValue : hiddenValue; + case 2: + return lidOpen ? hiddenValue : visibleValue; + } + return visibleValue; + } + /** {@inheritDoc} */ public void adjustConfigurationLw(Configuration config) { readLidState(); final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen; mPowerManager.setKeyboardVisibility(lidOpen); - config.keyboardHidden = (lidOpen || mHasSoftInput) - ? Configuration.KEYBOARDHIDDEN_NO - : Configuration.KEYBOARDHIDDEN_YES; - config.hardKeyboardHidden = lidOpen - ? Configuration.KEYBOARDHIDDEN_NO - : Configuration.KEYBOARDHIDDEN_YES; + config.hardKeyboardHidden = determineHiddenState(lidOpen, + mLidKeyboardAccessibility, Configuration.HARDKEYBOARDHIDDEN_YES, + Configuration.HARDKEYBOARDHIDDEN_NO); + config.navigationHidden = determineHiddenState(lidOpen, + mLidNavigationAccessibility, Configuration.NAVIGATIONHIDDEN_YES, + Configuration.NAVIGATIONHIDDEN_NO); + config.keyboardHidden = (config.hardKeyboardHidden + == Configuration.HARDKEYBOARDHIDDEN_NO || mHasSoftInput) + ? Configuration.KEYBOARDHIDDEN_NO + : Configuration.KEYBOARDHIDDEN_YES; } public boolean isCheekPressedAgainstScreen(MotionEvent ev) { @@ -566,6 +708,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return PRIORITY_PHONE_LAYER; case TYPE_TOAST: return TOAST_LAYER; + case TYPE_WALLPAPER: + return WALLPAPER_LAYER; } Log.e(TAG, "Unknown window type: " + type); return APPLICATION_LAYER; @@ -588,6 +732,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } + public int getMaxWallpaperLayer() { + return STATUS_BAR_LAYER; + } + + public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) { + return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD; + } + + public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) { + return attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR + && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER; + } + /** {@inheritDoc} */ public View addStartingWindow(IBinder appToken, String packageName, int theme, CharSequence nonLocalizedLabel, @@ -756,6 +913,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } + public Animation createForceHideEnterAnimation() { + return AnimationUtils.loadAnimation(mContext, + com.android.internal.R.anim.lock_screen_behind_enter); + } + static ITelephony getPhoneInterface() { return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE)); } @@ -775,7 +937,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, - int repeatCount) { + int repeatCount, int flags) { boolean keyguardOn = keyguardOn(); if (false) { @@ -800,32 +962,36 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (!down) { mHomePressed = false; - // If an incoming call is ringing, HOME is totally disabled. - // (The user is already on the InCallScreen at this point, - // and his ONLY options are to answer or reject the call.) - boolean incomingRinging = false; - try { - ITelephony phoneServ = getPhoneInterface(); - if (phoneServ != null) { - incomingRinging = phoneServ.isRinging(); + if ((flags&KeyEvent.FLAG_CANCELED) == 0) { + // If an incoming call is ringing, HOME is totally disabled. + // (The user is already on the InCallScreen at this point, + // and his ONLY options are to answer or reject the call.) + boolean incomingRinging = false; + try { + ITelephony phoneServ = getPhoneInterface(); + if (phoneServ != null) { + incomingRinging = phoneServ.isRinging(); + } else { + Log.w(TAG, "Unable to find ITelephony interface"); + } + } catch (RemoteException ex) { + Log.w(TAG, "RemoteException from getPhoneInterface()", ex); + } + + if (incomingRinging) { + Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); } else { - Log.w(TAG, "Unable to find ITelephony interface"); + launchHomeFromHotKey(); } - } catch (RemoteException ex) { - Log.w(TAG, "RemoteException from getPhoneInterface()", ex); - } - - if (incomingRinging) { - Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); } else { - launchHomeFromHotKey(); + Log.i(TAG, "Ignoring HOME; event canceled."); } } } return true; } - + // First we always handle the home key here, so applications // can never break it, although if keyguard is on, we do let // it handle it, because that gives us the correct 5 second @@ -942,9 +1108,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { * given the situation with the keyguard. */ void launchHomeFromHotKey() { - if (mKeyguardMediator.isShowing()) { + if (!mHideLockScreen && mKeyguardMediator.isShowing()) { // don't launch home if keyguard showing - } else if (mKeyguardMediator.isInputRestricted()) { + } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) { // when in keyguard restricted mode, must first verify unlock // before launching home mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() { @@ -955,7 +1121,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } catch (RemoteException e) { } sendCloseSystemWindows(); - mContext.startActivity(mHomeIntent); + startDockOrHome(); } } }); @@ -966,7 +1132,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } catch (RemoteException e) { } sendCloseSystemWindows(); - mContext.startActivity(mHomeIntent); + startDockOrHome(); } } @@ -994,7 +1160,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mTopFullscreenOpaqueWindowState = null; mForceStatusBar = false; - mHideKeyguard = false; + mHideLockScreen = false; + mDismissKeyguard = false; // decide where the status bar goes ahead of time if (mStatusBar != null) { @@ -1192,20 +1359,24 @@ public class PhoneWindowManager implements WindowManagerPolicy { win.computeFrameLw(pf, df, cf, vf); - if (win.isVisibleLw()) { + if (mTopFullscreenOpaqueWindowState == null && + win.isVisibleOrBehindKeyguardLw()) { if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { mForceStatusBar = true; - } else if (mTopFullscreenOpaqueWindowState == null - && attrs.type >= FIRST_APPLICATION_WINDOW + } + if (attrs.type >= FIRST_APPLICATION_WINDOW && attrs.type <= LAST_APPLICATION_WINDOW && win.fillsScreenLw(mW, mH, false, false)) { if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win); mTopFullscreenOpaqueWindowState = win; + if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { + if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win); + mHideLockScreen = true; + } } - if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { - // TODO Add a check for the window to be full screen - if (localLOGV) Log.i(TAG, "Setting mHideKeyguard to true by win " + win); - mHideKeyguard = true; + if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) { + if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win); + mDismissKeyguard = true; } } @@ -1229,15 +1400,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ - public boolean finishLayoutLw() { - boolean changed = false; + public int finishLayoutLw() { + int changes = 0; boolean hiding = false; if (mStatusBar != null) { - //Log.i(TAG, "force=" + mForceStatusBar - // + " top=" + mTopFullscreenOpaqueWindowState); + if (localLOGV) Log.i(TAG, "force=" + mForceStatusBar + + " top=" + mTopFullscreenOpaqueWindowState); if (mForceStatusBar) { if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); - changed |= mStatusBar.showLw(true); + if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; } else if (mTopFullscreenOpaqueWindowState != null) { //Log.i(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw() // + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw()); @@ -1248,26 +1419,49 @@ public class PhoneWindowManager implements WindowManagerPolicy { (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; if (hideStatusBar) { if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar"); - changed |= mStatusBar.hideLw(true); + if (mStatusBar.hideLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; hiding = true; } else { if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); - changed |= mStatusBar.showLw(true); + if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; } } } // 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.i(TAG, "finishLayoutLw::mHideKeyguard="+mHideKeyguard); - if (mHideKeyguard) { - changed |= mKeyguard.hideLw(true); + if (localLOGV) Log.v(TAG, "finishLayoutLw::mHideKeyguard="+mHideLockScreen); + if (mDismissKeyguard && !mKeyguardMediator.isSecure()) { + if (mKeyguard.hideLw(false)) { + changes |= FINISH_LAYOUT_REDO_LAYOUT + | FINISH_LAYOUT_REDO_CONFIG + | FINISH_LAYOUT_REDO_WALLPAPER; + } + if (mKeyguardMediator.isShowing()) { + mHandler.post(new Runnable() { + public void run() { + mKeyguardMediator.keyguardDone(false, false); + } + }); + } + } else if (mHideLockScreen) { + if (mKeyguard.hideLw(false)) { + mKeyguardMediator.setHidden(true); + changes |= FINISH_LAYOUT_REDO_LAYOUT + | FINISH_LAYOUT_REDO_CONFIG + | FINISH_LAYOUT_REDO_WALLPAPER; + } } else { - changed |= mKeyguard.showLw(true); + if (mKeyguard.showLw(false)) { + mKeyguardMediator.setHidden(false); + changes |= FINISH_LAYOUT_REDO_LAYOUT + | FINISH_LAYOUT_REDO_CONFIG + | FINISH_LAYOUT_REDO_WALLPAPER; + } } } - if (changed && hiding) { + if (changes != 0 && hiding) { IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar")); if (sbs != null) { try { @@ -1278,7 +1472,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - return changed; + return changes; } /** {@inheritDoc} */ @@ -1299,15 +1493,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { public boolean preprocessInputEventTq(RawInputEvent event) { switch (event.type) { case RawInputEvent.EV_SW: - if (event.keycode == 0) { + if (event.keycode == RawInputEvent.SW_LID) { // lid changed state mLidOpen = event.value == 0; + boolean awakeNow = mKeyguardMediator.doLidChangeTq(mLidOpen); updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); - if (keyguardIsShowingTq()) { + if (awakeNow) { + // If the lid opening and we don't have to keep the + // keyguard up, then we can turn on the screen + // immediately. + mKeyguardMediator.pokeWakelock(); + } else if (keyguardIsShowingTq()) { if (mLidOpen) { - // only do this if it's opening -- closing the device shouldn't turn it - // off, but it also shouldn't turn it on. - mKeyguardMediator.pokeWakelock(); + // If we are opening the lid and not hiding the + // keyguard, then we need to have it turn on the + // screen once it is shown. + mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq( + KeyEvent.KEYCODE_POWER); } } else { // Light up the keyboard if we are sliding up. @@ -1365,27 +1567,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { * @return Whether music is being played right now. */ boolean isMusicActive() { - final IAudioService audio = getAudioInterface(); - if (audio == null) { - Log.w(TAG, "isMusicActive: couldn't get IAudioService reference"); - return false; - } - try { - return audio.isMusicActive(); - } catch (RemoteException e) { - Log.w(TAG, "IAudioService.isMusicActive() threw RemoteException " + e); + final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); + if (am == null) { + Log.w(TAG, "isMusicActive: couldn't get AudioManager reference"); return false; } + return am.isMusicActive(); } /** * Tell the audio service to adjust the volume appropriate to the event. * @param keycode */ - void sendVolToMusic(int keycode) { + void handleVolumeKey(int stream, int keycode) { final IAudioService audio = getAudioInterface(); if (audio == null) { - Log.w(TAG, "sendVolToMusic: couldn't get IAudioService reference"); + Log.w(TAG, "handleVolumeKey: couldn't get IAudioService reference"); return; } try { @@ -1393,8 +1590,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // during the call, but we do it as a precaution for the rare possibility // that the music stops right before we call this mBroadcastWakeLock.acquire(); - audio.adjustStreamVolume( - AudioManager.STREAM_MUSIC, + audio.adjustStreamVolume(stream, keycode == KeyEvent.KEYCODE_VOLUME_UP ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER, @@ -1456,12 +1652,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else if (isMusicActive()) { // when keyguard is showing and screen off, we need // to handle the volume key for music here - sendVolToMusic(event.keycode); + handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode); } } } } } else if (!screenIsOn) { + // If we are in-call with screen off and keyguard is not showing, + // then handle the volume key ourselves. + // This is necessary because the phone app will disable the keyguard + // when the proximity sensor is in use. + if (isInCall() && event.type == RawInputEvent.EV_KEY && + (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN + || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) { + result &= ~ACTION_PASS_TO_USER; + handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode); + } if (isWakeKey) { // a wake key has a sole purpose of waking the device; don't pass // it to the user @@ -1475,33 +1681,41 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean down = event.value != 0; if (type == RawInputEvent.EV_KEY) { - if (code == KeyEvent.KEYCODE_ENDCALL) { + if (code == KeyEvent.KEYCODE_ENDCALL + || code == KeyEvent.KEYCODE_POWER) { if (down) { - boolean hungUp = false; + boolean handled = false; // key repeats are generated by the window manager, and we don't see them // here, so unless the driver is doing something it shouldn't be, we know // this is the real press event. - try { - ITelephony phoneServ = getPhoneInterface(); - if (phoneServ != null) { - hungUp = phoneServ.endCall(); - } else { - Log.w(TAG, "!!! Unable to find ITelephony interface !!!"); + ITelephony phoneServ = getPhoneInterface(); + if (phoneServ != null) { + try { + if (code == KeyEvent.KEYCODE_ENDCALL) { + handled = phoneServ.endCall(); + } else if (code == KeyEvent.KEYCODE_POWER && phoneServ.isRinging()) { + // Pressing power during incoming call should silence the ringer + phoneServ.silenceRinger(); + handled = true; + } + } catch (RemoteException ex) { + Log.w(TAG, "ITelephony threw RemoteException" + ex); } - } catch (RemoteException ex) { - Log.w(TAG, "ITelephony.endCall() threw RemoteException" + ex); + } else { + Log.w(TAG, "!!! Unable to find ITelephony interface !!!"); } - if (hungUp || !screenIsOn) { + // power button should turn off screen in addition to hanging up the phone + if ((handled && code != KeyEvent.KEYCODE_POWER) || !screenIsOn) { mShouldTurnOffOnKeyUp = false; } else { // only try to turn off the screen if we didn't already hang up mShouldTurnOffOnKeyUp = true; - mHandler.postDelayed(mEndCallLongPress, + mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout()); result &= ~ACTION_PASS_TO_USER; } } else { - mHandler.removeCallbacks(mEndCallLongPress); + mHandler.removeCallbacks(mPowerLongPress); if (mShouldTurnOffOnKeyUp) { mShouldTurnOffOnKeyUp = false; boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0; @@ -1620,7 +1834,34 @@ public class PhoneWindowManager implements WindowManagerPolicy { mBroadcastWakeLock.release(); } }; - + + BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + updatePlugged(intent); + updateDockKeepingScreenOn(); + } + }; + + BroadcastReceiver mDockReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, + Intent.EXTRA_DOCK_STATE_UNDOCKED); + boolean watchBattery = mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED; + if (watchBattery != mRegisteredBatteryReceiver) { + mRegisteredBatteryReceiver = watchBattery; + if (watchBattery) { + updatePlugged(mContext.registerReceiver(mBatteryReceiver, + mBatteryStatusFilter)); + } else { + mContext.unregisterReceiver(mBatteryReceiver); + } + } + updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); + updateDockKeepingScreenOn(); + updateOrientationListenerLp(); + } + }; + /** {@inheritDoc} */ public boolean isWakeRelMovementTq(int device, int classes, RawInputEvent event) { @@ -1736,7 +1977,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { // or orientation sensor disabled //or case.unspecified if (mLidOpen) { - return Surface.ROTATION_90; + return mLidOpenRotation; + } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) { + return mCarDockRotation; + } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) { + return mDeskDockRotation; } else { if (useSensorForOrientationLp(orientation)) { // If the user has enabled auto rotation by default, do it. @@ -1751,8 +1996,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { public boolean detectSafeMode() { try { int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU); - mSafeMode = menuState > 0; - Log.i(TAG, "Menu key state: " + menuState + " safeMode=" + mSafeMode); + int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S); + int dpadState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER); + int trackballState = mWindowManager.getScancodeState(RawInputEvent.BTN_MOUSE); + mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0; + performHapticFeedbackLw(null, mSafeMode + ? HapticFeedbackConstants.SAFE_MODE_ENABLED + : HapticFeedbackConstants.SAFE_MODE_DISABLED, true); + if (mSafeMode) { + Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState + + " dpad=" + dpadState + " trackball=" + trackballState + ")"); + } else { + Log.i(TAG, "SAFE MODE not enabled"); + } return mSafeMode; } catch (RemoteException e) { // Doom! (it's also local) @@ -1760,23 +2016,25 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + static long[] getLongIntArray(Resources r, int resid) { + int[] ar = r.getIntArray(resid); + if (ar == null) { + return null; + } + long[] out = new long[ar.length]; + for (int i=0; i= 0) { + rotation = mCarDockRotation; + } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) { + rotation = mDeskDockRotation; } //if lid is closed orientation will be portrait try { @@ -1804,6 +2091,53 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + /** + * Return an Intent to launch the currently active dock as home. Returns + * null if the standard home should be launched. + * @return + */ + Intent createHomeDockIntent() { + if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) { + return null; + } + + Intent intent; + if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) { + intent = mCarDockIntent; + } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { + intent = mDeskDockIntent; + } else { + Log.w(TAG, "Unknown dock state: " + mDockState); + return null; + } + + ActivityInfo ai = intent.resolveActivityInfo( + mContext.getPackageManager(), PackageManager.GET_META_DATA); + if (ai == null) { + return null; + } + + if (ai.metaData != null && ai.metaData.getBoolean(Intent.METADATA_DOCK_HOME)) { + intent = new Intent(intent); + intent.setClassName(ai.packageName, ai.name); + return intent; + } + + return null; + } + + void startDockOrHome() { + Intent dock = createHomeDockIntent(); + if (dock != null) { + try { + mContext.startActivity(dock); + return; + } catch (ActivityNotFoundException e) { + } + } + mContext.startActivity(mHomeIntent); + } + /** * goes to the home screen * @return whether it did anything @@ -1816,13 +2150,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { } catch (RemoteException e) { } sendCloseSystemWindows(); - mContext.startActivity(mHomeIntent); + startDockOrHome(); } else { // This code brings home to the front or, if it is already // at the front, puts the device to sleep. try { ActivityManagerNative.getDefault().stopAppSwitches(); sendCloseSystemWindows(); + Intent dock = createHomeDockIntent(); + if (dock != null) { + int result = ActivityManagerNative.getDefault() + .startActivity(null, dock, + dock.resolveTypeIfNeeded(mContext.getContentResolver()), + null, 0, null, null, 0, true /* onlyIfNeeded*/, false); + if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) { + return false; + } + } int result = ActivityManagerNative.getDefault() .startActivity(null, mHomeIntent, mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()), @@ -1847,23 +2191,45 @@ public class PhoneWindowManager implements WindowManagerPolicy { } public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) { - if (!always && Settings.System.getInt(mContext.getContentResolver(), - Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) { + final boolean hapticsDisabled = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0; + if (!always && (hapticsDisabled || mKeyguardMediator.isShowing())) { return false; } switch (effectId) { case HapticFeedbackConstants.LONG_PRESS: - mVibrator.vibrate(LONG_PRESS_VIBE_PATTERN, -1); + mVibrator.vibrate(mLongPressVibePattern, -1); + return true; + case HapticFeedbackConstants.VIRTUAL_KEY: + mVibrator.vibrate(mVirtualKeyVibePattern, -1); + return true; + case HapticFeedbackConstants.SAFE_MODE_DISABLED: + mVibrator.vibrate(mSafeModeDisabledVibePattern, -1); + return true; + case HapticFeedbackConstants.SAFE_MODE_ENABLED: + mVibrator.vibrate(mSafeModeEnabledVibePattern, -1); return true; } return false; } + public void keyFeedbackFromInput(KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_DOWN + && (event.getFlags()&KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) { + performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false); + } + } + public void screenOnStoppedLw() { if (!mKeyguardMediator.isShowing()) { long curTime = SystemClock.uptimeMillis(); mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); } } + + public boolean allowKeyRepeat() { + // disable key repeat when screen is off + return mScreenOn; + } } diff --git a/policy/com/android/internal/policy/impl/PowerDialog.java b/policy/com/android/internal/policy/impl/PowerDialog.java index f4d4b049b397..de35bd7bd2cf 100644 --- a/policy/com/android/internal/policy/impl/PowerDialog.java +++ b/policy/com/android/internal/policy/impl/PowerDialog.java @@ -70,8 +70,11 @@ public class PowerDialog extends Dialog implements OnClickListener, setContentView(com.android.internal.R.layout.power_dialog); getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); - getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + 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); diff --git a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java index a680cc83b3d6..4c46be5bdfc5 100644 --- a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java +++ b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java @@ -20,7 +20,6 @@ import android.app.ActivityManager; import android.app.Dialog; import android.app.StatusBarManager; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -30,13 +29,10 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.view.View.OnClickListener; -import android.widget.ImageView; import android.widget.TextView; import java.util.List; @@ -59,7 +55,7 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener private int mIconSize; public RecentApplicationsDialog(Context context) { - super(context); + super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications); final Resources resources = context.getResources(); mIconSize = (int) resources.getDimension(android.R.dimen.app_icon_size); @@ -84,8 +80,8 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener Window theWindow = getWindow(); theWindow.requestFeature(Window.FEATURE_NO_TITLE); theWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); - theWindow.setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + theWindow.setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND, + WindowManager.LayoutParams.FLAG_DIM_BEHIND); theWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); theWindow.setTitle("Recents"); diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java index 0f7fe32a8278..3881d116fdfd 100644 --- a/policy/com/android/internal/policy/impl/SimUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/SimUnlockScreen.java @@ -182,9 +182,12 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie mSimUnlockProgressDialog.setCancelable(false); mSimUnlockProgressDialog.getWindow().setType( WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - mSimUnlockProgressDialog.getWindow().setFlags( - WindowManager.LayoutParams.FLAG_BLUR_BEHIND, - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_sf_slowBlur)) { + mSimUnlockProgressDialog.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + } } return mSimUnlockProgressDialog; } diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index 9aedf901d232..a5032b3ae0c5 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -17,30 +17,33 @@ package com.android.internal.policy.impl; import android.content.Context; -import android.content.ServiceConnection; import android.os.CountDownTimer; import android.os.SystemClock; -import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.MotionEvent; import android.widget.Button; -import android.widget.ImageView; import android.widget.TextView; +import android.text.format.DateFormat; +import android.text.TextUtils; import com.android.internal.R; +import com.android.internal.telephony.IccCard; import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient; import com.android.internal.widget.LockPatternUtils; 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 * the user how to unlock their device, or make an emergency call. */ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient - implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback { + implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback, + KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback { private static final String TAG = "UnlockScreen"; @@ -50,6 +53,9 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient // how long we stay awake once the user is ready to enter a pattern private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000; + // how many cells the user has to cross before we poke the wakelock + private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2; + private int mFailedPatternAttemptsSinceLastTimeout = 0; private int mTotalFailedPatternAttempts = 0; private CountDownTimer mCountdownTimer = null; @@ -58,10 +64,35 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient private final KeyguardUpdateMonitor mUpdateMonitor; private final KeyguardScreenCallback mCallback; + /** + * whether there is a fallback option available when the pattern is forgotten. + */ + private boolean mEnableFallback; + private boolean mCreatedInPortrait; - private ImageView mUnlockIcon; - private TextView mUnlockHeader; + private TextView mCarrier; + private TextView mCenterDot; + private TextView mDate; + private TextView mTime; + + // 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 LockPatternView mLockPatternView; private ViewGroup mFooterNormal; @@ -86,9 +117,6 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient private Button mForgotPatternButton; - private ServiceConnection mServiceConnection; - - enum FooterMode { Normal, ForgotLockPattern, @@ -104,6 +132,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient case ForgotLockPattern: mFooterNormal.setVisibility(View.GONE); mFooterForgotPattern.setVisibility(View.VISIBLE); + mForgotPatternButton.setVisibility(View.VISIBLE); break; case VerifyUnlocked: mFooterNormal.setVisibility(View.GONE); @@ -117,12 +146,15 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient * @param updateMonitor Used to lookup state affecting keyguard. * @param callback Used to notify the manager when we're done, etc. * @param totalFailedAttempts The current number of failed attempts. + * @param enableFallback True if a backup unlock option is available when the user has forgotten + * their pattern (e.g they have a google account so we can show them the account based + * backup option). */ UnlockScreen(Context context, - LockPatternUtils lockPatternUtils, - KeyguardUpdateMonitor updateMonitor, - KeyguardScreenCallback callback, - int totalFailedAttempts) { + LockPatternUtils lockPatternUtils, + KeyguardUpdateMonitor updateMonitor, + KeyguardScreenCallback callback, + int totalFailedAttempts) { super(context); mLockPatternUtils = lockPatternUtils; mUpdateMonitor = updateMonitor; @@ -136,12 +168,22 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_landscape, this, true); } - mUnlockIcon = (ImageView) findViewById(R.id.unlockLockIcon); + mCarrier = (TextView) findViewById(R.id.carrier); + mCenterDot = (TextView) findViewById(R.id.centerDot); + mDate = (TextView) findViewById(R.id.date); + mTime = (TextView) findViewById(R.id.time); - mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern); - mUnlockHeader = (TextView) findViewById(R.id.headerText); + mCenterDot.setText("|"); + refreshTimeAndDateDisplay(); - mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); + mStatus1 = (TextView) findViewById(R.id.status1); + mStatusSep = (TextView) findViewById(R.id.statusSep); + mStatus2 = (TextView) findViewById(R.id.status2); + + resetStatusInfo(); + + + mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern); mFooterNormal = (ViewGroup) findViewById(R.id.footerNormal); mFooterForgotPattern = (ViewGroup) findViewById(R.id.footerForgotPattern); @@ -164,8 +206,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mForgotPatternButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { - mLockPatternUtils.setPermanentlyLocked(true); - mCallback.goToUnlockScreen(); + mCallback.forgotPattern(true); } }); @@ -187,19 +228,106 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient updateFooter(FooterMode.Normal); mCreatedInPortrait = updateMonitor.isInPortrait(); + updateMonitor.registerInfoCallback(this); + updateMonitor.registerSimStateCallback(this); updateMonitor.registerConfigurationChangeCallback(this); setFocusableInTouchMode(true); + + // until we get an update... + mCarrier.setText( + LockScreen.getCarrierString( + mUpdateMonitor.getTelephonyPlmn(), + mUpdateMonitor.getTelephonySpn())); } - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - mCallback.goToLockScreen(); - return true; + public void setEnableFallback(boolean state) { + 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); } - return false; } + + private void refreshTimeAndDateDisplay() { + Date now = new Date(); + mTime.setText(DateFormat.getTimeFormat(getContext()).format(now)); + mDate.setText(DateFormat.getMediumDateFormat(getContext()).format(now)); + } + + @Override public boolean dispatchTouchEvent(MotionEvent ev) { // as long as the user is entering a pattern (i.e sending a touch @@ -210,11 +338,40 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient ((SystemClock.elapsedRealtime() - mLastPokeTime) > (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) { mLastPokeTime = SystemClock.elapsedRealtime(); - mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); } return result; } + + // ---------- InfoCallback + + /** {@inheritDoc} */ + public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + mShowingBatteryInfo = showBatteryInfo; + mPluggedIn = pluggedIn; + mBatteryLevel = batteryLevel; + updateStatusLines(); + } + + /** {@inheritDoc} */ + public void onTimeChanged() { + refreshTimeAndDateDisplay(); + } + + /** {@inheritDoc} */ + public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + mCarrier.setText(LockScreen.getCarrierString(plmn, spn)); + } + + // ---------- SimStateCallback + + /** {@inheritDoc} */ + public void onSimStateChanged(IccCard.State simState) { + } + + + + /** {@inheritDoc} */ public void onOrientationChange(boolean inPortrait) { if (inPortrait != mCreatedInPortrait) { @@ -241,8 +398,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient /** {@inheritDoc} */ public void onResume() { // reset header - mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); - mUnlockIcon.setVisibility(View.VISIBLE); + resetStatusInfo(); // reset lock pattern mLockPatternView.enableInput(); @@ -262,10 +418,11 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient // the footer depends on how many total attempts the user has failed if (mCallback.isVerifyUnlockOnly()) { updateFooter(FooterMode.VerifyUnlocked); - } else if (mTotalFailedPatternAttempts < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { - updateFooter(FooterMode.Normal); - } else { + } else if (mEnableFallback && + (mTotalFailedPatternAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { updateFooter(FooterMode.ForgotLockPattern); + } else { + updateFooter(FooterMode.Normal); } } @@ -274,6 +431,15 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mUpdateMonitor.removeCallback(this); } + @Override + public void onWindowFocusChanged(boolean hasWindowFocus) { + super.onWindowFocusChanged(hasWindowFocus); + if (hasWindowFocus) { + // when timeout dialog closes we want to update our state + onResume(); + } + } + private class UnlockPatternListener implements LockPatternView.OnPatternListener { @@ -284,15 +450,25 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient public void onPatternCleared() { } + public void onPatternCellAdded(List pattern) { + // To guard against accidental poking of the wakelock, look for + // the user actually trying to draw a pattern of some minimal length. + if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { + mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); + } + } + public void onPatternDetected(List pattern) { if (mLockPatternUtils.checkPattern(pattern)) { mLockPatternView .setDisplayMode(LockPatternView.DisplayMode.Correct); - mUnlockIcon.setVisibility(View.GONE); - mUnlockHeader.setText(""); + mInstructions = ""; + updateStatusLines(); mCallback.keyguardDone(true); } else { - mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); + if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { + mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); + } mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong); if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { mTotalFailedPatternAttempts++; @@ -304,8 +480,9 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient handleAttemptLockout(deadline); return; } - mUnlockIcon.setVisibility(View.VISIBLE); - mUnlockHeader.setText(R.string.lockscreen_pattern_wrong); + // TODO mUnlockIcon.setVisibility(View.VISIBLE); + mInstructions = getContext().getString(R.string.lockscreen_pattern_wrong); + updateStatusLines(); mLockPatternView.postDelayed( mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS); @@ -322,20 +499,25 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient @Override public void onTick(long millisUntilFinished) { int secondsRemaining = (int) (millisUntilFinished / 1000); - mUnlockHeader.setText(getContext().getString( + mInstructions = getContext().getString( R.string.lockscreen_too_many_failed_attempts_countdown, - secondsRemaining)); + secondsRemaining); + updateStatusLines(); } @Override public void onFinish() { mLockPatternView.setEnabled(true); - mUnlockHeader.setText(R.string.lockscreen_pattern_instructions); - mUnlockIcon.setVisibility(View.VISIBLE); + mInstructions = getContext().getString(R.string.lockscreen_pattern_instructions); + updateStatusLines(); + // TODO mUnlockIcon.setVisibility(View.VISIBLE); mFailedPatternAttemptsSinceLastTimeout = 0; - updateFooter(FooterMode.ForgotLockPattern); + if (mEnableFallback) { + updateFooter(FooterMode.ForgotLockPattern); + } else { + updateFooter(FooterMode.Normal); + } } }.start(); } - } -- GitLab From 6f2da1e57803ad4eebd36232a14d684f8cff5311 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Fri, 13 Nov 2009 14:17:21 -0800 Subject: [PATCH 158/458] Use new date format for lock screen. Fixes http://b/issue?id=2247356 (well, it will once the format is updated to include the full day-of-week). Change-Id: Iaafbc60b7ff3edbfee7208052ecc1575cb8c226c --- .../internal/policy/impl/LockScreen.java | 28 ++----------------- .../internal/policy/impl/UnlockScreen.java | 6 ++-- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 43e155778ba1..72d144766963 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -82,7 +82,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private boolean mSilentMode; private AudioManager mAudioManager; - private java.text.DateFormat mDateFormat; + private String mDateFormatString; private java.text.DateFormat mTimeFormat; private boolean mCreatedInPortrait; private boolean mEnableMenuKeyInLockScreen; @@ -243,7 +243,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM refreshAlarmDisplay(); mTimeFormat = DateFormat.getTimeFormat(getContext()); - mDateFormat = getLockScreenDateFormat(); + mDateFormatString = getContext().getString(R.string.full_wday_month_day_no_year); refreshTimeAndDateDisplay(); updateStatusLines(); } @@ -369,29 +369,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } private void refreshTimeAndDateDisplay() { - Date now = new Date(); - mDate.setText(mDateFormat.format(now)); - } - - /** - * @return A localized format like "Fri, Sep 18, 2009" - */ - private java.text.DateFormat getLockScreenDateFormat() { - SimpleDateFormat adjusted = null; - try { - // this call gives us the localized order - final SimpleDateFormat dateFormat = (SimpleDateFormat) - java.text.DateFormat.getDateInstance(java.text.DateFormat.FULL); - adjusted = new SimpleDateFormat(dateFormat.toPattern() - .replace("MMMM", "MMM") // we want "Sep", not "September" - .replace("EEEE", "EEE")); // we want "Fri", no "Friday" - } catch (ClassCastException e) { - // in case the library implementation changes and this throws a class cast exception - // or anything else that is funky - Log.e("LockScreen", "couldn't finnagle our custom date format :(", e); - return java.text.DateFormat.getDateInstance(java.text.DateFormat.MEDIUM); - } - return adjusted; + mDate.setText(DateFormat.format(mDateFormatString, new Date())); } private void updateStatusLines() { diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index 2843dd4ce4bb..f85b62f341f4 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -71,6 +71,8 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient private boolean mCreatedInPortrait; + private String mDateFormatString; + private TextView mCarrier; private TextView mDate; @@ -169,6 +171,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient 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); @@ -317,8 +320,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient private void refreshTimeAndDateDisplay() { - Date now = new Date(); - mDate.setText(DateFormat.getMediumDateFormat(getContext()).format(now)); + mDate.setText(DateFormat.format(mDateFormatString, new Date())); } -- GitLab From 47e5023eea23957933fe9bc683045c3e3f06f784 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Fri, 13 Nov 2009 18:06:22 -0500 Subject: [PATCH 159/458] Don't trigger user activity in screenOnStoppedLw() if the screen is off. Fixes b/2260437 (device wakes itself back up when camera is last application running) Change-Id: Icdb3d0369df752a3838fa8e58c7a4bb08efe00a6 Signed-off-by: Mike Lockwood --- policy/com/android/internal/policy/impl/PhoneWindowManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index e57fbe8b544b..3f97661c7165 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -2221,7 +2221,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } public void screenOnStoppedLw() { - if (!mKeyguardMediator.isShowing()) { + if (!mKeyguardMediator.isShowing() && mPowerManager.isScreenOn()) { long curTime = SystemClock.uptimeMillis(); mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); } -- GitLab From 16541e4f88bf645408de098d1368cb49dd09e4c3 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Fri, 13 Nov 2009 17:07:50 -0800 Subject: [PATCH 160/458] Fix a race condition determining whether password fallback mode is allowed. The fix is in LockPatternKeyguardView, whose constructor was firing off an asynchronous request to the AccountManager to find out about the specifics of the account on the device. (If it's SAML, we don't have the password in cleartext and therefore can't use it to unlock.) Unfortunately, if the AccountManager responds too quickly, we get the answer (in LPKV.run()) before the UnlockScreen has even been instantiated (later in LPKV's ctor). The fix is to create the unlock screen first and *then* ping the AccountManager for details. Bug: http://b/2216308 Change-Id: Iedc84675c0ab8a001d062d806e2bee7ed1a29758 --- .../policy/impl/KeyguardViewManager.java | 2 +- .../policy/impl/LockPatternKeyguardView.java | 42 +++++++++++++------ .../internal/policy/impl/UnlockScreen.java | 9 ++++ 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index bac2fcada11f..d4dc429d08b0 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -92,7 +92,7 @@ public class KeyguardViewManager implements KeyguardWindowController { * lazily. */ public synchronized void show() { - if (DEBUG) Log.d(TAG, "show()"); + if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView); if (mKeyguardHost == null) { if (DEBUG) Log.d(TAG, "keyguard host is null, creating it..."); diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 0ebd945600ef..00dc92969b0d 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -160,7 +160,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase } catch (AuthenticatorException e) { } mEnableFallback = !hasSAMLAccount; - if (mUnlockScreen instanceof UnlockScreen) { + + if (mUnlockScreen == null) { + Log.w(TAG, "no unlock screen when receiving AccountManager information"); + } else if (mUnlockScreen instanceof UnlockScreen) { ((UnlockScreen)mUnlockScreen).setEnableFallback(true); } } @@ -179,18 +182,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase KeyguardWindowController controller) { super(context); - final boolean hasAccount = AccountManager.get(context).getAccounts().length > 0; - if (hasAccount) { - /* If we have a SAML account which requires web login we can not use the - fallback screen UI to ask the user for credentials. - For now we will disable fallback screen in this case. - Ultimately we could consider bringing up a web login from GLS - but need to make sure that it will work in the "locked screen" mode. */ - String[] features = new String[] {"saml"}; - AccountManager.get(context).getAccountsByTypeAndFeatures( - "com.google", features, this, null); - } - mEnableFallback = false; mRequiresSim = @@ -275,6 +266,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase public void reportFailedPatternAttempt() { mUpdateMonitor.reportFailedAttempt(); final int failedAttempts = mUpdateMonitor.getFailedAttempts(); + if (DEBUG) Log.d(TAG, + "reportFailedPatternAttempt: #" + failedAttempts + + " (enableFallback=" + mEnableFallback + ")"); if (mEnableFallback && failedAttempts == (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { @@ -313,8 +307,28 @@ public class LockPatternKeyguardView extends KeyguardViewBase mLockScreen = createLockScreen(); addView(mLockScreen); final UnlockMode unlockMode = getUnlockMode(); + if (DEBUG) Log.d(TAG, + "LockPatternKeyguardView ctor: about to createUnlockScreenFor; mEnableFallback=" + + mEnableFallback); mUnlockScreen = createUnlockScreenFor(unlockMode); mUnlockScreenMode = unlockMode; + + // Ask the account manager if we have an account that can be used as a + // fallback in case the user forgets his pattern. The response comes + // back in run() below; don't bother asking until you've called + // createUnlockScreenFor(), else the information will go unused. + final boolean hasAccount = AccountManager.get(context).getAccounts().length > 0; + if (hasAccount) { + /* If we have a SAML account which requires web login we can not use the + fallback screen UI to ask the user for credentials. + For now we will disable fallback screen in this case. + Ultimately we could consider bringing up a web login from GLS + but need to make sure that it will work in the "locked screen" mode. */ + String[] features = new String[] {"saml"}; + AccountManager.get(context).getAccountsByTypeAndFeatures( + "com.google", features, this, null); + } + addView(mUnlockScreen); updateScreen(mMode); } @@ -475,6 +489,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase mUpdateMonitor, mKeyguardScreenCallback, mUpdateMonitor.getFailedAttempts()); + if (DEBUG) Log.d(TAG, + "createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback); view.setEnableFallback(mEnableFallback); return view; } else if (unlockMode == UnlockMode.SimPin) { diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index f85b62f341f4..e413d6bed607 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -27,6 +27,7 @@ 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; import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient; @@ -45,6 +46,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback { + private static final boolean DEBUG = false; private static final String TAG = "UnlockScreen"; // how long before we clear the wrong pattern @@ -162,6 +164,12 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mTotalFailedPatternAttempts = totalFailedAttempts; mFailedPatternAttemptsSinceLastTimeout = totalFailedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; + if (DEBUG) Log.d(TAG, + "UnlockScreen() ctor: totalFailedAttempts=" + + totalFailedAttempts + ", mFailedPat...=" + + mFailedPatternAttemptsSinceLastTimeout + ); + if (mUpdateMonitor.isInPortrait()) { LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_portrait, this, true); } else { @@ -239,6 +247,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient } public void setEnableFallback(boolean state) { + if (DEBUG) Log.d(TAG, "setEnableFallback(" + state + ")"); mEnableFallback = state; } -- GitLab From c119f1299b63c224df5e7fa9c197f394eee890ca Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Sat, 14 Nov 2009 02:31:09 -0800 Subject: [PATCH 161/458] Fix 2209086: Fix missing callback that was preventing right tab bar text from updating. --- .../internal/policy/impl/LockScreen.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 72d144766963..a58cfb70191e 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -204,9 +204,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM updateMonitor.registerConfigurationChangeCallback(this); mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); - mSilentMode = mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT; + mSilentMode = isSilentMode(); - mSelector.setOnTriggerListener(this); mSelector.setLeftTabResources( R.drawable.ic_jog_dial_unlock, R.drawable.jog_tab_target_green, @@ -215,9 +214,15 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM updateRightTabResources(); + mSelector.setOnTriggerListener(this); + resetStatusInfo(updateMonitor); } + private boolean isSilentMode() { + return mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT; + } + private void updateRightTabResources() { mSelector.setRightTabResources( mSilentMode ? R.drawable.ic_jog_dial_sound_off : R.drawable.ic_jog_dial_sound_on, @@ -226,9 +231,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM : R.drawable.jog_tab_bar_right_sound_off, mSilentMode ? R.drawable.jog_tab_right_sound_on : R.drawable.jog_tab_right_sound_off); - - mSelector.setRightHintText(mSilentMode ? - R.string.lockscreen_sound_on_label : R.string.lockscreen_sound_off_label); } private void resetStatusInfo(KeyguardUpdateMonitor updateMonitor) { @@ -281,7 +283,11 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM /** {@inheritDoc} */ public void onGrabbedStateChange(View v, int grabbedState) { - // TODO: Update onscreen hint text based on the new state. + 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(); } -- GitLab From 5425930bd11817468cfd5b99c15b58945cdcb360 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Mon, 16 Nov 2009 23:11:42 -0800 Subject: [PATCH 162/458] Fix 2209086: Fix visual glitches in lockscreen. Call new setHoldAfterTrigger() method to enable feature added in https://android-git.corp.google.com/g/#change,33380. --- policy/com/android/internal/policy/impl/LockScreen.java | 1 + 1 file changed, 1 insertion(+) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index a58cfb70191e..67fe0b372611 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -188,6 +188,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mEmergencyCallButton.setText(R.string.lockscreen_emergency_call); mScreenLocked = (TextView) findViewById(R.id.screenLocked); mSelector = (SlidingTab) findViewById(R.id.tab_selector); + mSelector.setHoldAfterTrigger(true, false); mSelector.setLeftHintText(R.string.lockscreen_unlock_label); mEmergencyCallButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { -- GitLab From 9200a3987e3dc147f732e9bce34ab1c5be043f12 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Tue, 17 Nov 2009 20:25:58 -0500 Subject: [PATCH 163/458] Handle KeyguardViewMediator.setHidden() asynchronously to avoid deadlocks. Fixes b/2267046 (Could not shut off alarm; then device reboot) Change-Id: Id8f3e24edc5e1242a39c5d43bd549b5cb05abb36 Signed-off-by: Mike Lockwood --- .../policy/impl/KeyguardViewMediator.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index f5591b213df5..8d60e0ecdd49 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -105,6 +105,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private static final int KEYGUARD_DONE = 9; private static final int KEYGUARD_DONE_DRAWING = 10; private static final int KEYGUARD_DONE_AUTHENTICATING = 11; + private static final int SET_HIDDEN = 12; /** * The default amount of time we stay awake (used for all key input) @@ -425,9 +426,20 @@ public class KeyguardViewMediator implements KeyguardViewCallback, */ public void setHidden(boolean isHidden) { if (DEBUG) Log.d(TAG, "setHidden " + isHidden); + mHandler.removeMessages(SET_HIDDEN); + Message msg = mHandler.obtainMessage(SET_HIDDEN, (isHidden ? 1 : 0), 0); + mHandler.sendMessage(msg); + } + + /** + * Handles SET_HIDDEN message sent by setHidden() + */ + private void handleSetHidden(boolean isHidden) { synchronized (KeyguardViewMediator.this) { - mHidden = isHidden; - adjustUserActivityLocked(); + if (mHidden != isHidden) { + mHidden = isHidden; + adjustUserActivityLocked(); + } } } @@ -812,6 +824,9 @@ public class KeyguardViewMediator implements KeyguardViewCallback, case KEYGUARD_DONE_AUTHENTICATING: keyguardDone(true); return; + case SET_HIDDEN: + handleSetHidden(msg.arg1 != 0); + break; } } }; -- GitLab From a8730f985f4f9105be6690ad2ce10b6ef002645f Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 17 Nov 2009 15:53:36 -0800 Subject: [PATCH 164/458] Fix issue #2249821: Unable to start passion in safe mode Change-Id: I4320b38ce0cda4dca560c07bc0378b507032598a --- .../com/android/internal/policy/impl/PhoneWindowManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 3f97661c7165..470987fc270b 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1997,8 +1997,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { try { int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU); int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S); - int dpadState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER); - int trackballState = mWindowManager.getScancodeState(RawInputEvent.BTN_MOUSE); + int dpadState = mWindowManager.getDPadKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER); + int trackballState = mWindowManager.getTrackballScancodeState(RawInputEvent.BTN_MOUSE); mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0; performHapticFeedbackLw(null, mSafeMode ? HapticFeedbackConstants.SAFE_MODE_ENABLED -- GitLab From 9dc06cc2a800905619470030e0f2528aa239c113 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 17 Nov 2009 18:19:23 -0800 Subject: [PATCH 165/458] Fix issue #2264162 and #2252436: Now playing screens problems when locked. We now treat the case where the lock screen is hidden to be basically the same as it being removed for purposes of event dispatching and other things in the policy. Change-Id: I7386220594ad6e89e1493d643b1f0603663ae72a --- .../internal/policy/impl/KeyguardViewMediator.java | 7 +++++++ .../internal/policy/impl/PhoneWindowManager.java | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 8d60e0ecdd49..6b9db604ee99 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -421,6 +421,13 @@ public class KeyguardViewMediator implements KeyguardViewCallback, return mShowing; } + /** + * Is the keyguard currently showing and not being force hidden? + */ + public boolean isShowingAndNotHidden() { + return mShowing && !mHidden; + } + /** * Notify us when the keyguard is hidden by another window */ diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 470987fc270b..987e280c19dd 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -441,7 +441,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext); } - final boolean keyguardShowing = mKeyguardMediator.isShowing(); + final boolean keyguardShowing = mKeyguardMediator.isShowingAndNotHidden(); mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); if (keyguardShowing) { // since it took two seconds of long press to bring this up, @@ -1108,7 +1108,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * given the situation with the keyguard. */ void launchHomeFromHotKey() { - if (!mHideLockScreen && mKeyguardMediator.isShowing()) { + if (mKeyguardMediator.isShowingAndNotHidden()) { // don't launch home if keyguard showing } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) { // when in keyguard restricted mode, must first verify unlock @@ -1923,7 +1923,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public boolean keyguardIsShowingTq() { - return mKeyguardMediator.isShowing(); + return mKeyguardMediator.isShowingAndNotHidden(); } /** {@inheritDoc} */ @@ -2193,7 +2193,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) { final boolean hapticsDisabled = Settings.System.getInt(mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0; - if (!always && (hapticsDisabled || mKeyguardMediator.isShowing())) { + if (!always && (hapticsDisabled || mKeyguardMediator.isShowingAndNotHidden())) { return false; } switch (effectId) { @@ -2221,7 +2221,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } public void screenOnStoppedLw() { - if (!mKeyguardMediator.isShowing() && mPowerManager.isScreenOn()) { + if (!mKeyguardMediator.isShowingAndNotHidden() && mPowerManager.isScreenOn()) { long curTime = SystemClock.uptimeMillis(); mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); } -- GitLab From 5f892c130a9799067686ac47640f9f70c8916103 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Thu, 19 Nov 2009 23:39:13 -0500 Subject: [PATCH 166/458] When keyguard is active, only allow the status bar to be opened if it is insecure and covered by another window. Fixes b/2215112 (When screen wakes to Playback screen, Notification Bar is active) Change-Id: I43a8574259788d983c30b1a22e5bfc4e95d09bee Signed-off-by: Mike Lockwood --- .../policy/impl/KeyguardViewMediator.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 6b9db604ee99..2e97e14560c1 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -22,6 +22,7 @@ import com.android.internal.widget.LockPatternUtils; import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.PendingIntent; +import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -135,6 +136,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private Context mContext; private AlarmManager mAlarmManager; + private StatusBarManager mStatusBarManager; private boolean mSystemReady; @@ -446,6 +448,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (mHidden != isHidden) { mHidden = isHidden; adjustUserActivityLocked(); + adjustStatusBarLocked(); } } } @@ -899,6 +902,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mKeyguardViewManager.show(); mShowing = true; adjustUserActivityLocked(); + adjustStatusBarLocked(); try { ActivityManagerNative.getDefault().closeSystemDialogs("lock"); } catch (RemoteException e) { @@ -922,6 +926,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mKeyguardViewManager.hide(); mShowing = false; adjustUserActivityLocked(); + adjustStatusBarLocked(); } } @@ -936,6 +941,23 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } } + private void adjustStatusBarLocked() { + if (mStatusBarManager == null) { + mStatusBarManager = (StatusBarManager) + mContext.getSystemService(Context.STATUS_BAR_SERVICE); + } + if (mStatusBarManager == null) { + Log.w(TAG, "Could not get status bar manager"); + } else { + // if the keyguard is shown, allow the status bar to open + // only if the keyguard is insecure and is covered by another window + boolean enable = !mShowing || (mHidden && !isSecure()); + mStatusBarManager.disable(enable ? + StatusBarManager.DISABLE_NONE : + StatusBarManager.DISABLE_EXPAND); + } + } + /** * Handle message sent by {@link #wakeWhenReadyLocked(int)} * @param keyCode The key that woke the device. -- GitLab From b4e2d1c2aaebd6f8bd8ef78fbbc75b0ff359ae49 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Mon, 23 Nov 2009 15:54:10 -0500 Subject: [PATCH 167/458] END_BUTTON_BEHAVIOR setting should affect end call button only (not power button) Fixes b/2212852 ("end button behavior" in spare parts doesn't work) Change-Id: Ia17f37ad82b17f3a0e1ceb1ab7a0211b1d3ad8be Signed-off-by: Mike Lockwood --- .../internal/policy/impl/PhoneWindowManager.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 987e280c19dd..3e669f6f3fc7 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1718,8 +1718,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.removeCallbacks(mPowerLongPress); if (mShouldTurnOffOnKeyUp) { mShouldTurnOffOnKeyUp = false; - boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0; - boolean sleeps = (mEndcallBehavior & ENDCALL_SLEEPS) != 0; + boolean gohome, sleeps; + if (code == KeyEvent.KEYCODE_ENDCALL) { + gohome = (mEndcallBehavior & ENDCALL_HOME) != 0; + sleeps = (mEndcallBehavior & ENDCALL_SLEEPS) != 0; + } else { + gohome = false; + sleeps = true; + } if (keyguardShowing || (sleeps && !gohome) || (gohome && !goHome() && sleeps)) { -- GitLab From 47088bbbef61e3bd8d2930f4a2b72884129b5bd5 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Tue, 24 Nov 2009 00:40:16 -0800 Subject: [PATCH 168/458] Fix 2270597: Add callback to watch ringer state and update lock screen UI when it changes. --- .../policy/impl/KeyguardUpdateMonitor.java | 53 +++++++++++++------ .../internal/policy/impl/LockScreen.java | 12 ++++- .../internal/policy/impl/UnlockScreen.java | 19 ++++--- 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 58905a10c435..3483405fb96a 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -25,6 +25,7 @@ import android.database.ContentObserver; import static android.os.BatteryManager.BATTERY_STATUS_CHARGING; import static android.os.BatteryManager.BATTERY_STATUS_FULL; import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; +import android.media.AudioManager; import android.os.Handler; import android.os.Message; import android.provider.Settings; @@ -69,9 +70,9 @@ public class KeyguardUpdateMonitor { private boolean mKeyguardBypassEnabled; private boolean mDevicePluggedIn; - + private boolean mDeviceProvisioned; - + private int mBatteryLevel; private CharSequence mTelephonyPlmn; @@ -86,7 +87,7 @@ public class KeyguardUpdateMonitor { private ArrayList mInfoCallbacks = Lists.newArrayList(); private ArrayList mSimStateCallbacks = Lists.newArrayList(); private ContentObserver mContentObserver; - + // messages for the handler private static final int MSG_CONFIGURATION_CHANGED = 300; @@ -94,14 +95,15 @@ public class KeyguardUpdateMonitor { private static final int MSG_BATTERY_UPDATE = 302; private static final int MSG_CARRIER_INFO_UPDATE = 303; private static final int MSG_SIM_STATE_CHANGE = 304; + private static final int MSG_RINGER_MODE_CHANGED = 305; /** - * When we receive a - * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, + * When we receive a + * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange}, * we need a single object to pass to the handler. This class helps decode - * the intent and provide a {@link SimCard.State} result. + * the intent and provide a {@link SimCard.State} result. */ private static class SimArgs { @@ -140,7 +142,7 @@ public class KeyguardUpdateMonitor { public KeyguardUpdateMonitor(Context context) { mContext = context; - + mHandler = new Handler() { @Override public void handleMessage(Message msg) { @@ -160,6 +162,9 @@ public class KeyguardUpdateMonitor { case MSG_SIM_STATE_CHANGE: handleSimStateChange((SimArgs) msg.obj); break; + case MSG_RINGER_MODE_CHANGED: + handleRingerModeChange(msg.arg1); + break; } } }; @@ -169,7 +174,7 @@ public class KeyguardUpdateMonitor { mDeviceProvisioned = Settings.Secure.getInt( mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; - + // Since device can't be un-provisioned, we only need to register a content observer // to update mDeviceProvisioned when we are... if (!mDeviceProvisioned) { @@ -177,7 +182,7 @@ public class KeyguardUpdateMonitor { @Override public void onChange(boolean selfChange) { super.onChange(selfChange); - mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), + mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; if (mDeviceProvisioned && mContentObserver != null) { // We don't need the observer anymore... @@ -187,17 +192,17 @@ public class KeyguardUpdateMonitor { if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned); } }; - + mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.DEVICE_PROVISIONED), false, mContentObserver); - + // prevent a race condition between where we check the flag and where we register the // observer by grabbing the value once again... - mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), + mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; } - + mInPortrait = queryInPortrait(); mKeyboardOpen = queryKeyboardOpen(); @@ -217,6 +222,7 @@ public class KeyguardUpdateMonitor { filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); filter.addAction(SPN_STRINGS_UPDATED_ACTION); + filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); context.registerReceiver(new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { @@ -242,15 +248,25 @@ public class KeyguardUpdateMonitor { pluggedInStatus, batteryLevel); mHandler.sendMessage(msg); - } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){ + } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) { mHandler.sendMessage(mHandler.obtainMessage( MSG_SIM_STATE_CHANGE, new SimArgs(intent))); + } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED, + intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0)); } } }, filter); } + protected void handleRingerModeChange(int mode) { + if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")"); + for (int i = 0; i < mInfoCallbacks.size(); i++) { + mInfoCallbacks.get(i).onRingerModeChanged(mode); + } + } + /** * Handle {@link #MSG_CONFIGURATION_CHANGED} */ @@ -443,7 +459,7 @@ public class KeyguardUpdateMonitor { } /** - * Callback for general information releveant to lock screen. + * Callback for general information relevant to lock screen. */ interface InfoCallback { void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel); @@ -455,6 +471,13 @@ public class KeyguardUpdateMonitor { * @param spn The service provider name. May be null if it shouldn't be displayed. */ void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn); + + /** + * Called when the ringer mode changes. + * @param state the current ringer state, as defined in + * {@link AudioManager#RINGER_MODE_CHANGED_ACTION} + */ + void onRingerModeChanged(int state); } /** diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 67fe0b372611..6da03ab441e0 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -36,7 +36,6 @@ import android.os.SystemProperties; import java.util.Date; import java.io.File; -import java.text.SimpleDateFormat; /** * The screen within {@link LockPatternKeyguardView} that shows general @@ -562,7 +561,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM public boolean needsInput() { return false; } - + /** {@inheritDoc} */ public void onPause() { @@ -577,4 +576,13 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM public void cleanUp() { mUpdateMonitor.removeCallback(this); } + + /** {@inheritDoc} */ + public void onRingerModeChanged(int state) { + boolean silent = AudioManager.RINGER_MODE_SILENT == state; + if (silent != mSilentMode) { + mSilentMode = silent; + updateRightTabResources(); + } + } } diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index e413d6bed607..e090ac5e9fd0 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -104,7 +104,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient * Keeps track of the last time we poked the wake lock during dispatching * of the touch event, initalized to something gauranteed to make us * poke it when the user starts drawing the pattern. - * @see #dispatchTouchEvent(android.view.MotionEvent) + * @see #dispatchTouchEvent(android.view.MotionEvent) */ private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS; @@ -167,7 +167,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient if (DEBUG) Log.d(TAG, "UnlockScreen() ctor: totalFailedAttempts=" + totalFailedAttempts + ", mFailedPat...=" - + mFailedPatternAttemptsSinceLastTimeout + + mFailedPatternAttemptsSinceLastTimeout ); if (mUpdateMonitor.isInPortrait()) { @@ -250,7 +250,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient if (DEBUG) Log.d(TAG, "setEnableFallback(" + state + ")"); mEnableFallback = state; } - + private void resetStatusInfo() { mInstructions = null; mShowingBatteryInfo = mUpdateMonitor.shouldShowBatteryInfo(); @@ -368,6 +368,11 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mCarrier.setText(LockScreen.getCarrierString(plmn, spn)); } + /** {@inheritDoc} */ + public void onRingerModeChanged(int state) { + // not currently used + } + // ---------- SimStateCallback /** {@inheritDoc} */ @@ -391,7 +396,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient public boolean needsInput() { return false; } - + /** {@inheritDoc} */ public void onPause() { if (mCountdownTimer != null) { @@ -409,9 +414,9 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mLockPatternView.enableInput(); mLockPatternView.setEnabled(true); mLockPatternView.clearPattern(); - + // show "forgot pattern?" button if we have an alternate authentication method - mForgotPatternButton.setVisibility(mCallback.doesFallbackUnlockScreenExist() + mForgotPatternButton.setVisibility(mCallback.doesFallbackUnlockScreenExist() ? View.VISIBLE : View.INVISIBLE); // if the user is currently locked out, enforce it. @@ -457,7 +462,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient public void onPatternCellAdded(List pattern) { // To guard against accidental poking of the wakelock, look for - // the user actually trying to draw a pattern of some minimal length. + // the user actually trying to draw a pattern of some minimal length. if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); } -- GitLab From f275f0c0f9bd8e5d698baf157eb1e9c787018725 Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Tue, 24 Nov 2009 16:11:13 -0500 Subject: [PATCH 169/458] Bug 2248173 - Tell listeners to ACTION_CLOSE_SYSTEM_DIALOGS that we're doing so because of the home key. --- .../com/android/internal/policy/impl/PhoneWindowManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 987e280c19dd..2143f52dfd1d 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -154,6 +154,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; + static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey"; final Object mLock = new Object(); @@ -1120,7 +1121,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { ActivityManagerNative.getDefault().stopAppSwitches(); } catch (RemoteException e) { } - sendCloseSystemWindows(); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY); startDockOrHome(); } } @@ -1131,7 +1132,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { ActivityManagerNative.getDefault().stopAppSwitches(); } catch (RemoteException e) { } - sendCloseSystemWindows(); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY); startDockOrHome(); } } -- GitLab From c72b15f2ee751e7cb747e0b53ddecc9da69c9e0c Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Sat, 28 Nov 2009 20:58:22 -0500 Subject: [PATCH 170/458] Fix bug 2290852: Screen wakes up in my pocket while listening to music When the screen is off keyguard is open but hidden by another activity make sure that non-waking events like volume key or track ball press do not turn the screen back on. Change-Id: Ie6b191360b903b54388a6f65680ccc3264a51dd8 Signed-off-by: Mike Lockwood --- .../internal/policy/impl/PhoneWindowManager.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 2143f52dfd1d..2f9faae85b2c 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1620,14 +1620,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) { int result = ACTION_PASS_TO_USER; final boolean isWakeKey = isWakeKeyTq(event); - final boolean keyguardShowing = keyguardIsShowingTq(); + // If screen is off then we treat the case where the keyguard is open but hidden + // the same as if it were open and in front. + // This will prevent any keys other than the power button from waking the screen + // when the keyguard is hidden by another activity. + final boolean keyguardActive = (screenIsOn ? + mKeyguardMediator.isShowingAndNotHidden() : + mKeyguardMediator.isShowing()); if (false) { Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode - + " screenIsOn=" + screenIsOn + " keyguardShowing=" + keyguardShowing); + + " screenIsOn=" + screenIsOn + " keyguardActive=" + keyguardActive); } - if (keyguardShowing) { + if (keyguardActive) { if (screenIsOn) { // when the screen is on, always give the event to the keyguard result |= ACTION_PASS_TO_USER; @@ -1721,7 +1727,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mShouldTurnOffOnKeyUp = false; boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0; boolean sleeps = (mEndcallBehavior & ENDCALL_SLEEPS) != 0; - if (keyguardShowing + if (keyguardActive || (sleeps && !gohome) || (gohome && !goHome() && sleeps)) { // they must already be on the keyguad or home screen, -- GitLab From f791330dd15a350003af3304a62010b4e304f157 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Sat, 28 Nov 2009 22:27:10 -0500 Subject: [PATCH 171/458] Remove some unused window manager methods. Change-Id: Idd23ea4adb7328781ea81c45d61392b51dee1374 Signed-off-by: Mike Lockwood --- .../com/android/internal/policy/impl/PhoneWindowManager.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 6f67751241a5..4abd26800724 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1928,8 +1928,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardMediator.verifyUnlock(callback); } - /** {@inheritDoc} */ - public boolean keyguardIsShowingTq() { + private boolean keyguardIsShowingTq() { return mKeyguardMediator.isShowingAndNotHidden(); } -- GitLab From 3e42c35f7a7fd41c8173075f28a275aa04b00d0d Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 2 Dec 2009 01:15:27 -0500 Subject: [PATCH 172/458] Fix problems with KeyguardManager.exitKeyguardSecurely() and the FLAG_SHOW_WHEN_LOCKED window manager flag. Fixes b/2297221 ('Add call' button has no action, if call is answered on lockpattern screen) Change-Id: I6df8f64dedc4d2d8b02f746213c7b1b336d6560e Signed-off-by: Mike Lockwood --- .../policy/impl/KeyguardViewMediator.java | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 6b9db604ee99..17586bed1ece 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -170,7 +170,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // these are protected by synchronized (this) /** - * External apps (like the phone app) can tell us to disable the keygaurd. + * This is set to false if the keyguard is disabled via setKeyguardEnabled(false). */ private boolean mExternallyEnabled = true; @@ -398,15 +398,31 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // don't allow this api when the device isn't provisioned if (DEBUG) Log.d(TAG, "ignoring because device isn't provisioned"); callback.onKeyguardExitResult(false); - } else if (mExternallyEnabled) { - // this only applies when the user has externally disabled the - // keyguard. this is unexpected and means the user is not - // using the api properly. - Log.w(TAG, "verifyUnlock called when not externally disabled"); - callback.onKeyguardExitResult(false); } else if (mExitSecureCallback != null) { // already in progress with someone else callback.onKeyguardExitResult(false); + } else if (mExternallyEnabled) { + if (mHidden) { + if (isSecure()) { + // if the current activity is in front of the keyguard, then + // pretend like we succeeded and we will hit the lock screen + // when the activity is launched. + // HACK ALERT - this is assuming that the callback will be used + // to start a new activity (current usage by Phone app). + callback.onKeyguardExitResult(true); + } else { + // call through to verifyUnlockLocked() so we can bypass + // the insecure keyguard screen. + mExitSecureCallback = callback; + verifyUnlockLocked(); + } + } else { + // this only applies when the user has externally disabled the keyguard + // and no other activities are in front of the keyguard. + // this is unexpected and means the user is not using the api properly. + Log.w(TAG, "verifyUnlock called when not externally disabled"); + callback.onKeyguardExitResult(false); + } } else { mExitSecureCallback = callback; verifyUnlockLocked(); -- GitLab From 99ff0a82907b18ff1d3b2828b4751802951f0085 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 2 Dec 2009 01:37:38 -0500 Subject: [PATCH 173/458] Fix volume keys when in-call and screen is off due to proximity sensor. Fixes bug b/2297262 (Volume keys on passion don't work while in-call and phone is pressed to my ear) Change-Id: I775daa24295482000f87273d1f84dd796fb0f4eb Signed-off-by: Mike Lockwood --- .../android/internal/policy/impl/PhoneWindowManager.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 2f9faae85b2c..feb07178f400 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1651,14 +1651,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode) && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) { + // when keyguard is showing and screen off, we need + // to handle the volume key for calls and music here if (isInCall()) { - // if the keyguard didn't wake the device, we are in call, and - // it is a volume key, turn on the screen so that the user - // can more easily adjust the in call volume. - mKeyguardMediator.pokeWakelock(); + handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode); } else if (isMusicActive()) { - // when keyguard is showing and screen off, we need - // to handle the volume key for music here handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode); } } -- GitLab From 5d258b6b17eb258ca728f27907d0b24697ab72c9 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 2 Dec 2009 13:50:45 -0500 Subject: [PATCH 174/458] Revert "Fix problems with KeyguardManager.exitKeyguardSecurely() and the FLAG_SHOW_WHEN_LOCKED window manager flag." We have a better solution for this in the Phone app. This reverts commit b684251e8f1e85ea9483af2b80bc92f0fd8ded1c. --- .../policy/impl/KeyguardViewMediator.java | 30 +++++-------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 17586bed1ece..6b9db604ee99 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -170,7 +170,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // these are protected by synchronized (this) /** - * This is set to false if the keyguard is disabled via setKeyguardEnabled(false). + * External apps (like the phone app) can tell us to disable the keygaurd. */ private boolean mExternallyEnabled = true; @@ -398,31 +398,15 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // don't allow this api when the device isn't provisioned if (DEBUG) Log.d(TAG, "ignoring because device isn't provisioned"); callback.onKeyguardExitResult(false); + } else if (mExternallyEnabled) { + // this only applies when the user has externally disabled the + // keyguard. this is unexpected and means the user is not + // using the api properly. + Log.w(TAG, "verifyUnlock called when not externally disabled"); + callback.onKeyguardExitResult(false); } else if (mExitSecureCallback != null) { // already in progress with someone else callback.onKeyguardExitResult(false); - } else if (mExternallyEnabled) { - if (mHidden) { - if (isSecure()) { - // if the current activity is in front of the keyguard, then - // pretend like we succeeded and we will hit the lock screen - // when the activity is launched. - // HACK ALERT - this is assuming that the callback will be used - // to start a new activity (current usage by Phone app). - callback.onKeyguardExitResult(true); - } else { - // call through to verifyUnlockLocked() so we can bypass - // the insecure keyguard screen. - mExitSecureCallback = callback; - verifyUnlockLocked(); - } - } else { - // this only applies when the user has externally disabled the keyguard - // and no other activities are in front of the keyguard. - // this is unexpected and means the user is not using the api properly. - Log.w(TAG, "verifyUnlock called when not externally disabled"); - callback.onKeyguardExitResult(false); - } } else { mExitSecureCallback = callback; verifyUnlockLocked(); -- GitLab From ce27776887fb252e08667c16e6945c7fecf33368 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Thu, 3 Dec 2009 08:41:44 -0500 Subject: [PATCH 175/458] Do not show keyguard if screen is turned off by proximity sensor. Fixes bug b/2300622 (Proximity sensor always blows up the lock screen while in call) Change-Id: I85572973c142a72b3bba0bb032e5d2f710b5e36c Signed-off-by: Mike Lockwood --- .../android/internal/policy/impl/KeyguardViewMediator.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 6b9db604ee99..8d711461b11b 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -280,8 +280,9 @@ public class KeyguardViewMediator implements KeyguardViewCallback, /** * Called to let us know the screen was turned off. - * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER} or - * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}. + * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER}, + * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or + * {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}. */ public void onScreenTurnedOff(int why) { synchronized (this) { @@ -312,6 +313,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, 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 { doKeyguard(); } -- GitLab From 15620ce4151f88f70b05219669058f242df8bbab Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Thu, 3 Dec 2009 11:17:09 -0500 Subject: [PATCH 176/458] Tiny code fix required for http://b/2260798 . (We were trying to place the emergency call button beneath a layout object that no longer exists, which is why it was showing up at the top of the screen on top of other things.) Change-Id: I10b8b90f0e5923edf5d672b822ee8da6e28933d2 --- policy/com/android/internal/policy/impl/LockScreen.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 6da03ab441e0..7514cc2c4c82 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -488,7 +488,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mScreenLocked.setVisibility(View.INVISIBLE); mSelector.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.VISIBLE); - putEmergencyBelow(R.id.divider); + putEmergencyBelow(R.id.screenLocked); break; case SimMissingLocked: // text -- GitLab From 6a294ce7a5d56b9e38a388b2667db9f0fb316a45 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 3 Dec 2009 11:37:44 -0800 Subject: [PATCH 177/458] Fix issue #2302336: System dialogs are not being given a layer Define a new dedicated layer for system dialogs and use it. Change-Id: Iaa8b7a48617ae37ea3e83c9f77b1d357f750f5bc --- .../policy/impl/PhoneWindowManager.java | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index feb07178f400..27a42bc62bd7 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -85,6 +85,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE; import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; @@ -94,7 +95,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; -import android.view.WindowManagerPolicy.WindowState; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.media.IAudioService; @@ -121,25 +121,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int PHONE_LAYER = 3; static final int SEARCH_BAR_LAYER = 4; static final int STATUS_BAR_PANEL_LAYER = 5; + static final int SYSTEM_DIALOG_LAYER = 6; // toasts and the plugged-in battery thing - static final int TOAST_LAYER = 6; - static final int STATUS_BAR_LAYER = 7; + static final int TOAST_LAYER = 7; + static final int STATUS_BAR_LAYER = 8; // SIM errors and unlock. Not sure if this really should be in a high layer. - static final int PRIORITY_PHONE_LAYER = 8; + static final int PRIORITY_PHONE_LAYER = 9; // like the ANR / app crashed dialogs - static final int SYSTEM_ALERT_LAYER = 9; + static final int SYSTEM_ALERT_LAYER = 10; // system-level error dialogs - static final int SYSTEM_ERROR_LAYER = 10; + static final int SYSTEM_ERROR_LAYER = 11; // on-screen keyboards and other such input method user interfaces go here. - static final int INPUT_METHOD_LAYER = 11; + static final int INPUT_METHOD_LAYER = 12; // on-screen keyboards and other such input method user interfaces go here. - static final int INPUT_METHOD_DIALOG_LAYER = 12; + static final int INPUT_METHOD_DIALOG_LAYER = 13; // the keyguard; nothing on top of these can take focus, since they are // responsible for power management when displayed. - static final int KEYGUARD_LAYER = 13; - static final int KEYGUARD_DIALOG_LAYER = 14; + static final int KEYGUARD_LAYER = 14; + static final int KEYGUARD_DIALOG_LAYER = 15; // things in here CAN NOT take focus, but are shown on top of everything else. - static final int SYSTEM_OVERLAY_LAYER = 15; + static final int SYSTEM_OVERLAY_LAYER = 16; static final int APPLICATION_MEDIA_SUBLAYER = -2; static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; @@ -687,6 +688,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return STATUS_BAR_LAYER; case TYPE_STATUS_BAR_PANEL: return STATUS_BAR_PANEL_LAYER; + case TYPE_SYSTEM_DIALOG: + return SYSTEM_DIALOG_LAYER; case TYPE_SEARCH_BAR: return SEARCH_BAR_LAYER; case TYPE_PHONE: -- GitLab From e1246932519267fed62e5bf6d59ed7a9a0fc10cd Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Mon, 7 Dec 2009 15:48:05 -0500 Subject: [PATCH 178/458] Move emergency call button to top-right when no SIM. Also allows lockscreen's toasts to restore the previous text in the status TextView, which is necessary for this UI. Also added color to the toasts (another UI ask). In conjunction with change Ifea65fb9. http://b/2260798 --- .../internal/policy/impl/LockScreen.java | 62 ++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 7514cc2c4c82..7ec4a40a8527 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -23,6 +23,7 @@ import com.android.internal.widget.SlidingTab; import android.content.Context; import android.content.res.Resources; +import android.content.res.ColorStateList; import android.text.format.DateFormat; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -274,9 +275,14 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM 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; - toastMessage(mScreenLocked, message, toastIcon); + 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(); } } @@ -292,32 +298,43 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } /** - * Displays a message in a text view and then removes it. + * Displays a message in a text view and then restores the previous text. * @param textView The text view. * @param text The text. + * @param color The color to apply to the text, or 0 if the existing color should be used. * @param iconResourceId The left hand icon. */ - private void toastMessage(final TextView textView, final String text, final int iconResourceId) { + private void toastMessage(final TextView textView, final String text, final int color, final int iconResourceId) { + if (DBG) android.util.Log.d("LockScreen", "toastMessage(text=" + text +", color=" + color + ")"); + if (mPendingR1 != null) { textView.removeCallbacks(mPendingR1); mPendingR1 = null; } if (mPendingR2 != null) { + mPendingR2.run(); // fire immediately, restoring non-toasted appearance textView.removeCallbacks(mPendingR2); mPendingR2 = null; } + final String oldText = textView.getText().toString(); + final ColorStateList oldColors = textView.getTextColors(); + mPendingR1 = new Runnable() { public void run() { textView.setText(text); + if (color != 0) { + textView.setTextColor(color); + } textView.setCompoundDrawablesWithIntrinsicBounds(iconResourceId, 0, 0, 0); - textView.setCompoundDrawablePadding(4); } }; + textView.postDelayed(mPendingR1, 0); mPendingR2 = new Runnable() { public void run() { - textView.setText(""); + textView.setText(oldText); + textView.setTextColor(oldColors); textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); } }; @@ -415,11 +432,11 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM updateLayout(mStatus); } - private void putEmergencyBelow(int viewId) { + private void addRelativeLayoutRule(View view, int rule, int viewId) { final RelativeLayout.LayoutParams layoutParams = - (RelativeLayout.LayoutParams) mEmergencyCallButton.getLayoutParams(); - layoutParams.addRule(RelativeLayout.BELOW, viewId); - mEmergencyCallButton.setLayoutParams(layoutParams); + (RelativeLayout.LayoutParams) view.getLayoutParams(); + layoutParams.addRule(rule, viewId); + view.setLayoutParams(layoutParams); } /** @@ -455,6 +472,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM * Update the layout to match the current status. */ private void updateLayout(Status status) { + // The emergency call button appears where the carrier would + // ordinarily be shown, so if one is VISIBLE the other must be + // INVISIBLE. switch (status) { case Normal: // text @@ -481,25 +501,25 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM break; case SimMissing: // text - mCarrier.setText(R.string.lockscreen_missing_sim_message_short); - mScreenLocked.setText(R.string.lockscreen_instructions_when_pattern_disabled); + mCarrier.setText(""); + mScreenLocked.setText(R.string.lockscreen_missing_sim_message_short); + // previously shown here: lockscreen_instructions_when_pattern_disabled // layout - mScreenLocked.setVisibility(View.INVISIBLE); + mScreenLocked.setVisibility(View.VISIBLE); mSelector.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.VISIBLE); - putEmergencyBelow(R.id.screenLocked); break; case SimMissingLocked: // text - mCarrier.setText(R.string.lockscreen_missing_sim_message_short); - mScreenLocked.setText(R.string.lockscreen_missing_sim_instructions); + mCarrier.setText(""); + mScreenLocked.setText(R.string.lockscreen_missing_sim_message_short); + // previously shown here: lockscreen_missing_sim_instructions // layout mScreenLocked.setVisibility(View.VISIBLE); mSelector.setVisibility(View.GONE); mEmergencyCallButton.setVisibility(View.VISIBLE); - putEmergencyBelow(R.id.screenLocked); break; case SimLocked: // text @@ -512,14 +532,14 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM break; case SimPukLocked: // text - mCarrier.setText(R.string.lockscreen_sim_puk_locked_message); - mScreenLocked.setText(R.string.lockscreen_sim_puk_locked_instructions); + mCarrier.setText(""); + mScreenLocked.setText(R.string.lockscreen_sim_puk_locked_message); + // previously shown here: lockscreen_sim_puk_locked_instructions); // layout mScreenLocked.setVisibility(View.VISIBLE); mSelector.setVisibility(View.GONE); mEmergencyCallButton.setVisibility(View.VISIBLE); - putEmergencyBelow(R.id.screenLocked); break; } } -- GitLab From 75cbfcdf36b520dd14f2b257a9ee496b8152b168 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Tue, 8 Dec 2009 14:05:39 -0500 Subject: [PATCH 179/458] Prevent NPE in recent apps dialog. Bug: 2284111 --- .../internal/policy/impl/RecentApplicationsDialog.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java index 4c46be5bdfc5..c5aafa565ebd 100644 --- a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java +++ b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java @@ -110,8 +110,11 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener if (b == v) { // prepare a launch intent and send it Intent intent = (Intent)b.getTag(); - intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); - getContext().startActivity(intent); + if (intent != null) { + intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); + getContext().startActivity(intent); + } + break; } } dismiss(); -- GitLab From 818ba11cd680de336fb9278b64a21dc2efb7517e Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Fri, 11 Dec 2009 11:12:02 -0800 Subject: [PATCH 180/458] Add replace flag to a few more broadcasts. --- policy/com/android/internal/policy/impl/GlobalActions.java | 1 + .../com/android/internal/policy/impl/KeyguardViewMediator.java | 1 + 2 files changed, 2 insertions(+) diff --git a/policy/com/android/internal/policy/impl/GlobalActions.java b/policy/com/android/internal/policy/impl/GlobalActions.java index 2f1f024c5d89..8b6257f42838 100644 --- a/policy/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/com/android/internal/policy/impl/GlobalActions.java @@ -548,6 +548,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac Settings.System.AIRPLANE_MODE_ON, on ? 1 : 0); Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra("state", on); mContext.sendBroadcast(intent); } diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 99c3b5353cf3..176ba7fcf52f 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -267,6 +267,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mKeyguardViewProperties, mUpdateMonitor); mUserPresentIntent = new Intent(Intent.ACTION_USER_PRESENT); + mUserPresentIntent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); } /** -- GitLab From 0874372554523a02c3a210fca46107fc4b2c6bef Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 21 Dec 2009 12:16:51 -0800 Subject: [PATCH 181/458] Don't perform app transition if app is not currently visible. Tell the window manager if we are not visible due to the lock screen or status bar. --- .../policy/impl/PhoneWindowManager.java | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 1dcec654158b..d692a1d2e70f 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -100,6 +100,8 @@ import android.view.animation.AnimationUtils; import android.media.IAudioService; import android.media.AudioManager; +import java.util.ArrayList; + /** * WindowManagerPolicy implementation for the Android phone UI. This * introduces a new method suffix, Lp, for an internal lock of the @@ -181,6 +183,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mSafeMode; WindowState mStatusBar = null; + final ArrayList mStatusBarPanels = new ArrayList(); WindowState mKeyguard = null; KeyguardViewMediator mKeyguardMediator; GlobalActions mGlobalActions; @@ -881,6 +884,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } mStatusBar = win; break; + case TYPE_STATUS_BAR_PANEL: + mStatusBarPanels.add(win); + break; case TYPE_KEYGUARD: if (mKeyguard != null) { return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; @@ -898,6 +904,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else if (mKeyguard == win) { mKeyguard = null; + } else { + mStatusBarPanels.remove(win); } } @@ -1436,7 +1444,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mKeyguard != null) { if (localLOGV) Log.v(TAG, "finishLayoutLw::mHideKeyguard="+mHideLockScreen); if (mDismissKeyguard && !mKeyguardMediator.isSecure()) { - if (mKeyguard.hideLw(false)) { + if (mKeyguard.hideLw(true)) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; @@ -1449,14 +1457,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { }); } } else if (mHideLockScreen) { - if (mKeyguard.hideLw(false)) { + if (mKeyguard.hideLw(true)) { mKeyguardMediator.setHidden(true); changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; } } else { - if (mKeyguard.showLw(false)) { + if (mKeyguard.showLw(true)) { mKeyguardMediator.setHidden(false); changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG @@ -1493,6 +1501,33 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } + public boolean allowAppAnimationsLw() { + if (mKeyguard != null && mKeyguard.isVisibleLw()) { + // If keyguard is currently visible, no reason to animate + // behind it. + return false; + } + if (mStatusBar != null && mStatusBar.isVisibleLw()) { + Rect rect = new Rect(mStatusBar.getShownFrameLw()); + for (int i=mStatusBarPanels.size()-1; i>=0; i--) { + WindowState w = mStatusBarPanels.get(i); + if (w.isVisibleLw()) { + rect.union(w.getShownFrameLw()); + } + } + final int insetw = mW/10; + final int inseth = mH/10; + if (rect.contains(insetw, inseth, mW-insetw, mH-inseth)) { + // All of the status bar windows put together cover the + // screen, so the app can't be seen. (Note this test doesn't + // work if the rects of these windows are at off offsets or + // sizes, causing gaps in the rect union we have computed.) + return false; + } + } + return true; + } + /** {@inheritDoc} */ public boolean preprocessInputEventTq(RawInputEvent event) { switch (event.type) { @@ -1924,6 +1959,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + /** {@inheritDoc} */ + public boolean isScreenOn() { + return mScreenOn; + } + /** {@inheritDoc} */ public void enableKeyguard(boolean enabled) { mKeyguardMediator.setKeyguardEnabled(enabled); -- GitLab From 18c59475445751e9ed24cacd7cfdbf86a94412fd Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Fri, 18 Dec 2009 19:57:07 -0800 Subject: [PATCH 182/458] Fix 2338170: Fix a bug where adding a SAML account would cause the fallback unlock to break. Adding a SAML account to the system would cause the current test to fail because it expected to have only one account on the system. Instead, ensure that the device has at lease one non-SAML account. Fixed update bug where having a single SAML account still showed the "Forgot pattern" button. Tested: - Wipe device and add pattern lock - Add SAML account, verify "forgot pattern" doesn't appear. - Add GAIA account, verify "forgot pattern" appears. - Wipe device and add pattern lock - Add GAIA account, verify "forgot pattern" appears - Add SAML account, verify "forgot pattern" doesn't go away. --- .../policy/impl/LockPatternKeyguardView.java | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 00dc92969b0d..66c5159d1e2b 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -139,6 +139,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase */ private final LockPatternUtils mLockPatternUtils; + private int mNumAccounts; + /** * @return Whether we are stuck on the lock screen because the sim is * missing. @@ -149,22 +151,22 @@ public class LockPatternKeyguardView extends KeyguardViewBase && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT); } + // Called by AccountManager.getAccountByTypeAndFeatures() below... public void run(AccountManagerFuture future) { - // We err on the side of caution. - // In case of error we assume we have a SAML account. - boolean hasSAMLAccount = true; + int samlAccounts = 0; try { - hasSAMLAccount = future.getResult().length > 0; + samlAccounts = future.getResult().length; } catch (OperationCanceledException e) { } catch (IOException e) { } catch (AuthenticatorException e) { } - mEnableFallback = !hasSAMLAccount; + // At least one of the accounts must be non-SAML to enable the fallback. + mEnableFallback = samlAccounts < mNumAccounts; if (mUnlockScreen == null) { Log.w(TAG, "no unlock screen when receiving AccountManager information"); } else if (mUnlockScreen instanceof UnlockScreen) { - ((UnlockScreen)mUnlockScreen).setEnableFallback(true); + ((UnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback); } } @@ -313,12 +315,19 @@ public class LockPatternKeyguardView extends KeyguardViewBase mUnlockScreen = createUnlockScreenFor(unlockMode); mUnlockScreenMode = unlockMode; + maybeEnableFallback(context); + + addView(mUnlockScreen); + updateScreen(mMode); + } + + private void maybeEnableFallback(Context context) { // Ask the account manager if we have an account that can be used as a // fallback in case the user forgets his pattern. The response comes // back in run() below; don't bother asking until you've called // createUnlockScreenFor(), else the information will go unused. - final boolean hasAccount = AccountManager.get(context).getAccounts().length > 0; - if (hasAccount) { + mNumAccounts = AccountManager.get(context).getAccounts().length; + if (mNumAccounts > 0) { /* If we have a SAML account which requires web login we can not use the fallback screen UI to ask the user for credentials. For now we will disable fallback screen in this case. @@ -328,12 +337,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase AccountManager.get(context).getAccountsByTypeAndFeatures( "com.google", features, this, null); } - - addView(mUnlockScreen); - updateScreen(mMode); } - @Override public void reset() { mIsVerifyUnlockOnly = false; -- GitLab From a3a430e467ad3aacf45935fa63a5d9b2ffd98521 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Mon, 4 Jan 2010 11:57:30 -0800 Subject: [PATCH 183/458] Rename ro.monkey to monkey.running So that Monkey can set it before running and reset it after running. --- policy/com/android/internal/policy/impl/LockScreen.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 7514cc2c4c82..7231026cc386 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -147,7 +147,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private boolean shouldEnableMenuKey() { final Resources res = getResources(); final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen); - final boolean isMonkey = SystemProperties.getBoolean("ro.monkey", false); + final boolean isMonkey = SystemProperties.getBoolean("monkey.running", false); final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists(); return !configDisabled || isMonkey || fileOverride; } -- GitLab From 2e2a3d0a4bb11a481baccad0112f841cd60ed09b Mon Sep 17 00:00:00 2001 From: Johan Redestig Date: Tue, 5 Jan 2010 08:45:33 +0100 Subject: [PATCH 184/458] Added missing media keycode (KEYCODE_MEDIA_REWIND), removed duplicate keycode (KEYCODE_MEDIA_PREVIOUS) --- policy/com/android/internal/policy/impl/PhoneWindowManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index e57fbe8b544b..5a94165b709d 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1608,7 +1608,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { code == KeyEvent.KEYCODE_MEDIA_STOP || code == KeyEvent.KEYCODE_MEDIA_NEXT || code == KeyEvent.KEYCODE_MEDIA_PREVIOUS || - code == KeyEvent.KEYCODE_MEDIA_PREVIOUS || + code == KeyEvent.KEYCODE_MEDIA_REWIND || code == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) { return true; } -- GitLab From bb2e5c91fb5d0e6e04b237343933c09780365887 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Mon, 4 Jan 2010 18:49:49 -0800 Subject: [PATCH 185/458] Still use ro.monkey http://b/issue?id=1681101 --- policy/com/android/internal/policy/impl/LockScreen.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 7231026cc386..7514cc2c4c82 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -147,7 +147,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private boolean shouldEnableMenuKey() { final Resources res = getResources(); final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen); - final boolean isMonkey = SystemProperties.getBoolean("monkey.running", false); + final boolean isMonkey = SystemProperties.getBoolean("ro.monkey", false); final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists(); return !configDisabled || isMonkey || fileOverride; } -- GitLab From cc6828c676c0bfabbcbefa27f4be9183352f5fee Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Fri, 8 Jan 2010 15:06:37 -0800 Subject: [PATCH 186/458] Deprecate fill_parent and introduce match_parent. Bug: #2361749. --- .../internal/policy/impl/KeyguardViewManager.java | 6 +++--- .../android/internal/policy/impl/PhoneWindow.java | 13 +++++-------- .../internal/policy/impl/PhoneWindowManager.java | 4 ++-- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index d4dc429d08b0..ba1d7f530294 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -99,7 +99,7 @@ public class KeyguardViewManager implements KeyguardWindowController { mKeyguardHost = new KeyguardViewHost(mContext, mCallback); - final int stretch = ViewGroup.LayoutParams.FILL_PARENT; + final int stretch = ViewGroup.LayoutParams.MATCH_PARENT; int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING @@ -127,8 +127,8 @@ public class KeyguardViewManager implements KeyguardWindowController { mKeyguardView.setCallback(mCallback); final ViewGroup.LayoutParams lp = new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.FILL_PARENT); + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); mKeyguardHost.addView(mKeyguardView, lp); diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 6dd5d934b713..55772b2ae734 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -15,7 +15,7 @@ package com.android.internal.policy.impl; -import static android.view.ViewGroup.LayoutParams.FILL_PARENT; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; @@ -41,8 +41,6 @@ import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -61,7 +59,6 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewManager; import android.view.VolumePanel; @@ -204,7 +201,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public void setContentView(View view) { - setContentView(view, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT)); + setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); } @Override @@ -424,7 +421,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } int backgroundResId; - if (lp.width == ViewGroup.LayoutParams.FILL_PARENT) { + if (lp.width == ViewGroup.LayoutParams.MATCH_PARENT) { // If the contents is fill parent for the width, set the // corresponding background backgroundResId = st.fullBackground; @@ -1811,7 +1808,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (SWEEP_OPEN_MENU) { if (mMenuBackground == null && mFeatureId < 0 && getAttributes().height - == WindowManager.LayoutParams.FILL_PARENT) { + == WindowManager.LayoutParams.MATCH_PARENT) { mMenuBackground = getContext().getResources().getDrawable( com.android.internal.R.drawable.menu_background); } @@ -2151,7 +2148,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mDecor.startChanging(); View in = mLayoutInflater.inflate(layoutResource, null); - decor.addView(in, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT)); + decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); if (contentParent == null) { diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index d692a1d2e70f..659b2bb3daba 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -805,8 +805,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - win.setLayout(WindowManager.LayoutParams.FILL_PARENT, - WindowManager.LayoutParams.FILL_PARENT); + win.setLayout(WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.MATCH_PARENT); final WindowManager.LayoutParams params = win.getAttributes(); params.token = appToken; -- GitLab From 5e0f7ba8fa8045aab98664b5103d8620e9ac7f06 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Tue, 22 Dec 2009 19:04:23 -0800 Subject: [PATCH 187/458] Fix 2332563: Add password-lock support to lockscreen --- .../policy/impl/LockPatternKeyguardView.java | 68 +++-- .../LockPatternKeyguardViewProperties.java | 7 +- .../policy/impl/PasswordUnlockScreen.java | 260 ++++++++++++++++++ .../internal/policy/impl/SimUnlockScreen.java | 4 +- .../internal/policy/impl/UnlockScreen.java | 1 + 5 files changed, 316 insertions(+), 24 deletions(-) create mode 100644 policy/com/android/internal/policy/impl/PasswordUnlockScreen.java diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 66c5159d1e2b..ccb79023ac28 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -111,7 +111,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase /** * Unlock by entering an account's login and password. */ - Account + Account, + + /** + * Unlock by entering a password or PIN + */ + Password } /** @@ -268,7 +273,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase public void reportFailedPatternAttempt() { mUpdateMonitor.reportFailedAttempt(); final int failedAttempts = mUpdateMonitor.getFailedAttempts(); - if (DEBUG) Log.d(TAG, + if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts + " (enableFallback=" + mEnableFallback + ")"); if (mEnableFallback && failedAttempts == @@ -309,7 +314,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase mLockScreen = createLockScreen(); addView(mLockScreen); final UnlockMode unlockMode = getUnlockMode(); - if (DEBUG) Log.d(TAG, + if (DEBUG) Log.d(TAG, "LockPatternKeyguardView ctor: about to createUnlockScreenFor; mEnableFallback=" + mEnableFallback); mUnlockScreen = createUnlockScreenFor(unlockMode); @@ -434,16 +439,25 @@ public class LockPatternKeyguardView extends KeyguardViewBase private boolean isSecure() { UnlockMode unlockMode = getUnlockMode(); - if (unlockMode == UnlockMode.Pattern) { - return mLockPatternUtils.isLockPatternEnabled(); - } else if (unlockMode == UnlockMode.SimPin) { - return mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED - || mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED; - } else if (unlockMode == UnlockMode.Account) { - return true; - } else { - throw new IllegalStateException("unknown unlock mode " + unlockMode); + boolean secure = false; + switch (unlockMode) { + case Pattern: + secure = mLockPatternUtils.isLockPatternEnabled(); + break; + case SimPin: + secure = mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED + || mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED; + break; + case Account: + secure = true; + break; + case Password: + secure = mLockPatternUtils.isLockPasswordEnabled(); + break; + default: + throw new IllegalStateException("unknown unlock mode " + unlockMode); } + return secure; } private void updateScreen(final Mode mode) { @@ -524,6 +538,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase // "permanently locked" state.) return createUnlockScreenFor(UnlockMode.Pattern); } + } else if (unlockMode == UnlockMode.Password) { + return new PasswordUnlockScreen( + mContext, + mLockPatternUtils, + mUpdateMonitor, + mKeyguardScreenCallback); } else { throw new IllegalArgumentException("unknown unlock mode " + unlockMode); } @@ -575,13 +595,29 @@ public class LockPatternKeyguardView extends KeyguardViewBase */ private UnlockMode getUnlockMode() { final IccCard.State simState = mUpdateMonitor.getSimState(); + UnlockMode currentMode; if (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED) { - return UnlockMode.SimPin; + currentMode = UnlockMode.SimPin; } else { - return (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) ? - UnlockMode.Account: - UnlockMode.Pattern; + final int mode = mLockPatternUtils.getPasswordMode(); + switch (mode) { + case LockPatternUtils.MODE_PIN: + case LockPatternUtils.MODE_PASSWORD: + currentMode = UnlockMode.Password; + break; + case LockPatternUtils.MODE_PATTERN: + // "forgot pattern" button is only available in the pattern mode... + if (mForgotPattern && mLockPatternUtils.isPermanentlyLocked()) { + currentMode = UnlockMode.Account; + } else { + currentMode = UnlockMode.Pattern; + } + break; + default: + throw new IllegalStateException("Unknown unlock mode:" + mode); + } } + return currentMode; } private void showTimeoutDialog() { diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java index 8a62cbd79c4f..ed5a058b8315 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java @@ -50,12 +50,7 @@ public class LockPatternKeyguardViewProperties implements KeyguardViewProperties } public boolean isSecure() { - return isLockPatternSecure() || isSimPinSecure(); - } - - private boolean isLockPatternSecure() { - return mLockPatternUtils.isLockPatternEnabled() && mLockPatternUtils - .savedPatternExists(); + return mLockPatternUtils.isSecure() || isSimPinSecure(); } private boolean isSimPinSecure() { diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java new file mode 100644 index 000000000000..bb1950a940d4 --- /dev/null +++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2010 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 android.content.Context; + +import com.android.internal.telephony.IccCard.State; +import com.android.internal.widget.LockPatternUtils; + +import android.text.Editable; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; +import com.android.internal.R; + +/** + * Displays a dialer-like interface or alphanumeric (latin-1) key entry for the user to enter + * an unlock password + */ +public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener, + KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.InfoCallback { + + private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; + + private final KeyguardUpdateMonitor mUpdateMonitor; + private final KeyguardScreenCallback mCallback; + + private final boolean mCreatedWithKeyboardOpen; + + private TextView mPasswordTextView; + private TextView mOkButton; + private TextView mEmergencyCallButton; + private View mBackSpaceButton; + private TextView mCarrier; + private LockPatternUtils mLockPatternUtils; + private Button mCancelButton; + private int mPasswordAttempts = 0; + private int mMinimumPasswordLength = 4; // TODO: get from policy store + + private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + + public PasswordUnlockScreen(Context context, LockPatternUtils lockPatternUtils, + KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback) { + super(context); + mUpdateMonitor = updateMonitor; + mCallback = callback; + mCreatedWithKeyboardOpen = mUpdateMonitor.isKeyboardOpen(); + + LayoutInflater layoutInflater = LayoutInflater.from(context); + if (mCreatedWithKeyboardOpen) { + layoutInflater.inflate(R.layout.keyguard_screen_password_landscape, this, true); + } else { + layoutInflater.inflate(R.layout.keyguard_screen_password_portrait, this, true); + new TouchInput(); + } + + mPasswordTextView = (TextView) findViewById(R.id.pinDisplay); + mBackSpaceButton = findViewById(R.id.backspace); + mBackSpaceButton.setOnClickListener(this); + + // The cancel button is not used on this screen. + mCancelButton = (Button) findViewById(R.id.cancel); + if (mCancelButton != null) { + mCancelButton.setText(""); + } + + mEmergencyCallButton = (TextView) findViewById(R.id.emergencyCall); + mOkButton = (TextView) findViewById(R.id.ok); + + mPasswordTextView.setFocusable(false); + + mEmergencyCallButton.setOnClickListener(this); + mOkButton.setOnClickListener(this); + + mUpdateMonitor.registerConfigurationChangeCallback(this); + + mLockPatternUtils = lockPatternUtils; + mCarrier = (TextView) findViewById(R.id.carrier); + // until we get an update... + mCarrier.setText(LockScreen.getCarrierString(mUpdateMonitor.getTelephonyPlmn(), + mUpdateMonitor.getTelephonySpn())); + + updateMonitor.registerInfoCallback(this); + updateMonitor.registerConfigurationChangeCallback(this); + + setFocusableInTouchMode(true); + } + + /** {@inheritDoc} */ + public boolean needsInput() { + return true; + } + + /** {@inheritDoc} */ + public void onPause() { + + } + + /** {@inheritDoc} */ + public void onResume() { + // start fresh + mPasswordTextView.setText(""); + } + + /** {@inheritDoc} */ + public void cleanUp() { + mUpdateMonitor.removeCallback(this); + } + + public void onClick(View v) { + if (v == mBackSpaceButton) { + final Editable digits = mPasswordTextView.getEditableText(); + final int len = digits.length(); + if (len > 0) { + digits.delete(len-1, len); + } + } else if (v == mEmergencyCallButton) { + mCallback.takeEmergencyCallAction(); + } else if (v == mOkButton) { + verifyPasswordAndUnlock(); + } + mCallback.pokeWakelock(); + } + + private void verifyPasswordAndUnlock() { + String entry = mPasswordTextView.getText().toString(); + if (mLockPatternUtils.checkPassword(entry)) { + mPasswordAttempts = 0; + mCallback.keyguardDone(true); + } else if (entry.length() >= mMinimumPasswordLength ) { + // to avoid accidental lockout, only count attempts that are long enough to be a + // real password. This may require some tweaking. + mPasswordAttempts++; + } + mPasswordTextView.setText(""); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + return true; + } + + final char match = event.getMatch(DIGITS); + if (match != 0) { + reportDigit(match - '0'); + return true; + } + if (keyCode == KeyEvent.KEYCODE_DEL) { + mPasswordTextView.onKeyDown(keyCode, event); + return true; + } + + if (keyCode == KeyEvent.KEYCODE_ENTER) { + verifyPasswordAndUnlock(); + return true; + } + + return false; + } + + private void reportDigit(int digit) { + mPasswordTextView.append(Integer.toString(digit)); + } + + public void onOrientationChange(boolean inPortrait) { + + } + + public void onKeyboardChange(boolean isKeyboardOpen) { + if (isKeyboardOpen != mCreatedWithKeyboardOpen) { + mCallback.recreateMe(); + } + } + + /** + * Helper class to handle input from touch dialer. Only relevant when + * the keyboard is shut. + */ + private class TouchInput implements View.OnClickListener { + private int mDigitIds[] = { R.id.zero, R.id.one, R.id.two, R.id.three, R.id.four, + R.id.five, R.id.six, R.id.seven, R.id.eight, R.id.nine }; + private TextView mCancelButton; + private TouchInput() { + for (int i = 0; i < mDigitIds.length; i++) { + Button button = (Button) findViewById(mDigitIds[i]); + button.setOnClickListener(this); + button.setText(Integer.toString(i)); + } + mCancelButton = (TextView) findViewById(R.id.cancel); + mCancelButton.setOnClickListener(this); + mOkButton = (TextView) findViewById(R.id.ok); + mOkButton.setOnClickListener(this); + } + + public void onClick(View v) { + if (v == mCancelButton) { + return; + } + if (v == mOkButton) { + verifyPasswordAndUnlock(); + } + + final int digit = checkDigit(v); + if (digit >= 0) { + mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS); + reportDigit(digit); + } + } + + private int checkDigit(View v) { + int digit = -1; + for (int i = 0; i < mDigitIds.length; i++) { + if (v.getId() == mDigitIds[i]) { + digit = i; + break; + } + } + return digit; + } + } + + /** {@inheritDoc} */ + public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + mCarrier.setText(LockScreen.getCarrierString(plmn, spn)); + } + + public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + + } + + public void onRingerModeChanged(int state) { + + } + + public void onTimeChanged() { + + } + + public void onSimStateChanged(State simState) { + + } +} diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java index 3881d116fdfd..8c738a7e7bda 100644 --- a/policy/com/android/internal/policy/impl/SimUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/SimUnlockScreen.java @@ -27,7 +27,6 @@ import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; -import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; import com.android.internal.R; @@ -167,6 +166,7 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie } mCallback.pokeWakelock(); } else if (v == mEmergencyCallButton) { + mCallback.pokeWakelock(); mCallback.takeEmergencyCallAction(); } else if (v == mOkButton) { checkPin(); @@ -219,8 +219,8 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie mHeaderText.setText(R.string.keyguard_password_wrong_pin_code); mPinText.setText(""); mEnteredDigits = 0; - mCallback.pokeWakelock(); } + mCallback.pokeWakelock(); } }.start(); } diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index e090ac5e9fd0..30ab8799a2ad 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -197,6 +197,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient // emergency call buttons final OnClickListener emergencyClick = new OnClickListener() { public void onClick(View v) { + mCallback.pokeWakelock(); mCallback.takeEmergencyCallAction(); } }; -- GitLab From 46883a42e226c50d73de59ceeaa0c1d4811d5857 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 12 Jan 2010 15:19:04 -0800 Subject: [PATCH 188/458] android-2.1_r1 snapshot --- .../policy/impl/KeyguardUpdateMonitor.java | 53 +++++-- .../policy/impl/KeyguardViewManager.java | 2 +- .../policy/impl/KeyguardViewMediator.java | 33 ++++- .../policy/impl/LockPatternKeyguardView.java | 42 ++++-- .../internal/policy/impl/LockScreen.java | 129 +++++++++--------- .../policy/impl/PhoneWindowManager.java | 67 +++++---- .../internal/policy/impl/UnlockScreen.java | 38 ++++-- 7 files changed, 226 insertions(+), 138 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 58905a10c435..3483405fb96a 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -25,6 +25,7 @@ import android.database.ContentObserver; import static android.os.BatteryManager.BATTERY_STATUS_CHARGING; import static android.os.BatteryManager.BATTERY_STATUS_FULL; import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; +import android.media.AudioManager; import android.os.Handler; import android.os.Message; import android.provider.Settings; @@ -69,9 +70,9 @@ public class KeyguardUpdateMonitor { private boolean mKeyguardBypassEnabled; private boolean mDevicePluggedIn; - + private boolean mDeviceProvisioned; - + private int mBatteryLevel; private CharSequence mTelephonyPlmn; @@ -86,7 +87,7 @@ public class KeyguardUpdateMonitor { private ArrayList mInfoCallbacks = Lists.newArrayList(); private ArrayList mSimStateCallbacks = Lists.newArrayList(); private ContentObserver mContentObserver; - + // messages for the handler private static final int MSG_CONFIGURATION_CHANGED = 300; @@ -94,14 +95,15 @@ public class KeyguardUpdateMonitor { private static final int MSG_BATTERY_UPDATE = 302; private static final int MSG_CARRIER_INFO_UPDATE = 303; private static final int MSG_SIM_STATE_CHANGE = 304; + private static final int MSG_RINGER_MODE_CHANGED = 305; /** - * When we receive a - * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, + * When we receive a + * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange}, * we need a single object to pass to the handler. This class helps decode - * the intent and provide a {@link SimCard.State} result. + * the intent and provide a {@link SimCard.State} result. */ private static class SimArgs { @@ -140,7 +142,7 @@ public class KeyguardUpdateMonitor { public KeyguardUpdateMonitor(Context context) { mContext = context; - + mHandler = new Handler() { @Override public void handleMessage(Message msg) { @@ -160,6 +162,9 @@ public class KeyguardUpdateMonitor { case MSG_SIM_STATE_CHANGE: handleSimStateChange((SimArgs) msg.obj); break; + case MSG_RINGER_MODE_CHANGED: + handleRingerModeChange(msg.arg1); + break; } } }; @@ -169,7 +174,7 @@ public class KeyguardUpdateMonitor { mDeviceProvisioned = Settings.Secure.getInt( mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; - + // Since device can't be un-provisioned, we only need to register a content observer // to update mDeviceProvisioned when we are... if (!mDeviceProvisioned) { @@ -177,7 +182,7 @@ public class KeyguardUpdateMonitor { @Override public void onChange(boolean selfChange) { super.onChange(selfChange); - mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), + mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; if (mDeviceProvisioned && mContentObserver != null) { // We don't need the observer anymore... @@ -187,17 +192,17 @@ public class KeyguardUpdateMonitor { if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned); } }; - + mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.DEVICE_PROVISIONED), false, mContentObserver); - + // prevent a race condition between where we check the flag and where we register the // observer by grabbing the value once again... - mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), + mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; } - + mInPortrait = queryInPortrait(); mKeyboardOpen = queryKeyboardOpen(); @@ -217,6 +222,7 @@ public class KeyguardUpdateMonitor { filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); filter.addAction(SPN_STRINGS_UPDATED_ACTION); + filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); context.registerReceiver(new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { @@ -242,15 +248,25 @@ public class KeyguardUpdateMonitor { pluggedInStatus, batteryLevel); mHandler.sendMessage(msg); - } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){ + } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) { mHandler.sendMessage(mHandler.obtainMessage( MSG_SIM_STATE_CHANGE, new SimArgs(intent))); + } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED, + intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0)); } } }, filter); } + protected void handleRingerModeChange(int mode) { + if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")"); + for (int i = 0; i < mInfoCallbacks.size(); i++) { + mInfoCallbacks.get(i).onRingerModeChanged(mode); + } + } + /** * Handle {@link #MSG_CONFIGURATION_CHANGED} */ @@ -443,7 +459,7 @@ public class KeyguardUpdateMonitor { } /** - * Callback for general information releveant to lock screen. + * Callback for general information relevant to lock screen. */ interface InfoCallback { void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel); @@ -455,6 +471,13 @@ public class KeyguardUpdateMonitor { * @param spn The service provider name. May be null if it shouldn't be displayed. */ void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn); + + /** + * Called when the ringer mode changes. + * @param state the current ringer state, as defined in + * {@link AudioManager#RINGER_MODE_CHANGED_ACTION} + */ + void onRingerModeChanged(int state); } /** diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index bac2fcada11f..d4dc429d08b0 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -92,7 +92,7 @@ public class KeyguardViewManager implements KeyguardWindowController { * lazily. */ public synchronized void show() { - if (DEBUG) Log.d(TAG, "show()"); + if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView); if (mKeyguardHost == null) { if (DEBUG) Log.d(TAG, "keyguard host is null, creating it..."); diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index f5591b213df5..8d711461b11b 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -105,6 +105,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private static final int KEYGUARD_DONE = 9; private static final int KEYGUARD_DONE_DRAWING = 10; private static final int KEYGUARD_DONE_AUTHENTICATING = 11; + private static final int SET_HIDDEN = 12; /** * The default amount of time we stay awake (used for all key input) @@ -279,8 +280,9 @@ public class KeyguardViewMediator implements KeyguardViewCallback, /** * Called to let us know the screen was turned off. - * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER} or - * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}. + * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER}, + * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or + * {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}. */ public void onScreenTurnedOff(int why) { synchronized (this) { @@ -311,6 +313,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, 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 { doKeyguard(); } @@ -420,14 +424,32 @@ public class KeyguardViewMediator implements KeyguardViewCallback, return mShowing; } + /** + * Is the keyguard currently showing and not being force hidden? + */ + public boolean isShowingAndNotHidden() { + return mShowing && !mHidden; + } + /** * Notify us when the keyguard is hidden by another window */ public void setHidden(boolean isHidden) { if (DEBUG) Log.d(TAG, "setHidden " + isHidden); + mHandler.removeMessages(SET_HIDDEN); + Message msg = mHandler.obtainMessage(SET_HIDDEN, (isHidden ? 1 : 0), 0); + mHandler.sendMessage(msg); + } + + /** + * Handles SET_HIDDEN message sent by setHidden() + */ + private void handleSetHidden(boolean isHidden) { synchronized (KeyguardViewMediator.this) { - mHidden = isHidden; - adjustUserActivityLocked(); + if (mHidden != isHidden) { + mHidden = isHidden; + adjustUserActivityLocked(); + } } } @@ -812,6 +834,9 @@ public class KeyguardViewMediator implements KeyguardViewCallback, case KEYGUARD_DONE_AUTHENTICATING: keyguardDone(true); return; + case SET_HIDDEN: + handleSetHidden(msg.arg1 != 0); + break; } } }; diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 0ebd945600ef..00dc92969b0d 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -160,7 +160,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase } catch (AuthenticatorException e) { } mEnableFallback = !hasSAMLAccount; - if (mUnlockScreen instanceof UnlockScreen) { + + if (mUnlockScreen == null) { + Log.w(TAG, "no unlock screen when receiving AccountManager information"); + } else if (mUnlockScreen instanceof UnlockScreen) { ((UnlockScreen)mUnlockScreen).setEnableFallback(true); } } @@ -179,18 +182,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase KeyguardWindowController controller) { super(context); - final boolean hasAccount = AccountManager.get(context).getAccounts().length > 0; - if (hasAccount) { - /* If we have a SAML account which requires web login we can not use the - fallback screen UI to ask the user for credentials. - For now we will disable fallback screen in this case. - Ultimately we could consider bringing up a web login from GLS - but need to make sure that it will work in the "locked screen" mode. */ - String[] features = new String[] {"saml"}; - AccountManager.get(context).getAccountsByTypeAndFeatures( - "com.google", features, this, null); - } - mEnableFallback = false; mRequiresSim = @@ -275,6 +266,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase public void reportFailedPatternAttempt() { mUpdateMonitor.reportFailedAttempt(); final int failedAttempts = mUpdateMonitor.getFailedAttempts(); + if (DEBUG) Log.d(TAG, + "reportFailedPatternAttempt: #" + failedAttempts + + " (enableFallback=" + mEnableFallback + ")"); if (mEnableFallback && failedAttempts == (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { @@ -313,8 +307,28 @@ public class LockPatternKeyguardView extends KeyguardViewBase mLockScreen = createLockScreen(); addView(mLockScreen); final UnlockMode unlockMode = getUnlockMode(); + if (DEBUG) Log.d(TAG, + "LockPatternKeyguardView ctor: about to createUnlockScreenFor; mEnableFallback=" + + mEnableFallback); mUnlockScreen = createUnlockScreenFor(unlockMode); mUnlockScreenMode = unlockMode; + + // Ask the account manager if we have an account that can be used as a + // fallback in case the user forgets his pattern. The response comes + // back in run() below; don't bother asking until you've called + // createUnlockScreenFor(), else the information will go unused. + final boolean hasAccount = AccountManager.get(context).getAccounts().length > 0; + if (hasAccount) { + /* If we have a SAML account which requires web login we can not use the + fallback screen UI to ask the user for credentials. + For now we will disable fallback screen in this case. + Ultimately we could consider bringing up a web login from GLS + but need to make sure that it will work in the "locked screen" mode. */ + String[] features = new String[] {"saml"}; + AccountManager.get(context).getAccountsByTypeAndFeatures( + "com.google", features, this, null); + } + addView(mUnlockScreen); updateScreen(mMode); } @@ -475,6 +489,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase mUpdateMonitor, mKeyguardScreenCallback, mUpdateMonitor.getFailedAttempts()); + if (DEBUG) Log.d(TAG, + "createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback); view.setEnableFallback(mEnableFallback); return view; } else if (unlockMode == UnlockMode.SimPin) { diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index dda509735971..7514cc2c4c82 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -17,8 +17,9 @@ package com.android.internal.policy.impl; import com.android.internal.R; +import com.android.internal.telephony.IccCard; import com.android.internal.widget.LockPatternUtils; -import com.android.internal.widget.RotarySelector; +import com.android.internal.widget.SlidingTab; import android.content.Context; import android.content.res.Resources; @@ -33,11 +34,8 @@ import android.util.Log; import android.media.AudioManager; import android.os.SystemProperties; -import com.android.internal.telephony.IccCard; - import java.util.Date; import java.io.File; -import java.text.SimpleDateFormat; /** * The screen within {@link LockPatternKeyguardView} that shows general @@ -46,7 +44,7 @@ import java.text.SimpleDateFormat; */ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback, KeyguardUpdateMonitor.ConfigurationChangeCallback, - RotarySelector.OnDialTriggerListener { + SlidingTab.OnTriggerListener { private static final boolean DBG = false; private static final String TAG = "LockScreen"; @@ -59,7 +57,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private final KeyguardScreenCallback mCallback; private TextView mCarrier; - private RotarySelector mRotary; + private SlidingTab mSelector; private TextView mTime; private TextView mDate; private TextView mStatus1; @@ -83,7 +81,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private boolean mSilentMode; private AudioManager mAudioManager; - private java.text.DateFormat mDateFormat; + private String mDateFormatString; private java.text.DateFormat mTimeFormat; private boolean mCreatedInPortrait; private boolean mEnableMenuKeyInLockScreen; @@ -175,13 +173,12 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM final LayoutInflater inflater = LayoutInflater.from(context); if (mCreatedInPortrait) { - inflater.inflate(R.layout.keyguard_screen_rotary_unlock, this, true); + inflater.inflate(R.layout.keyguard_screen_tab_unlock, this, true); } else { - inflater.inflate(R.layout.keyguard_screen_rotary_unlock_land, this, true); + inflater.inflate(R.layout.keyguard_screen_tab_unlock_land, this, true); } mCarrier = (TextView) findViewById(R.id.carrier); - mTime = (TextView) findViewById(R.id.time); mDate = (TextView) findViewById(R.id.date); mStatus1 = (TextView) findViewById(R.id.status1); mStatus2 = (TextView) findViewById(R.id.status2); @@ -189,7 +186,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); mEmergencyCallButton.setText(R.string.lockscreen_emergency_call); mScreenLocked = (TextView) findViewById(R.id.screenLocked); - mRotary = (RotarySelector) findViewById(R.id.rotary); + mSelector = (SlidingTab) findViewById(R.id.tab_selector); + mSelector.setHoldAfterTrigger(true, false); + mSelector.setLeftHintText(R.string.lockscreen_unlock_label); mEmergencyCallButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mCallback.takeEmergencyCallAction(); @@ -205,17 +204,35 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM updateMonitor.registerConfigurationChangeCallback(this); mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); - mSilentMode = mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT; + mSilentMode = isSilentMode(); - mRotary.setOnDialTriggerListener(this); - mRotary.setLeftHandleResource(R.drawable.ic_jog_dial_unlock); - mRotary.setRightHandleResource(mSilentMode ? - R.drawable.ic_jog_dial_sound_off : - R.drawable.ic_jog_dial_sound_on); + 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); resetStatusInfo(updateMonitor); } + private boolean isSilentMode() { + return mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT; + } + + private void updateRightTabResources() { + mSelector.setRightTabResources( + mSilentMode ? 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(); @@ -228,7 +245,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM refreshAlarmDisplay(); mTimeFormat = DateFormat.getTimeFormat(getContext()); - mDateFormat = getLockScreenDateFormat(); + mDateFormatString = getContext().getString(R.string.full_wday_month_day_no_year); refreshTimeAndDateDisplay(); updateStatusLines(); } @@ -242,24 +259,23 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } /** {@inheritDoc} */ - public void onDialTrigger(View v, int whichHandle) { - if (whichHandle == RotarySelector.OnDialTriggerListener.LEFT_HANDLE) { + public void onTrigger(View v, int whichHandle) { + if (whichHandle == SlidingTab.OnTriggerListener.LEFT_HANDLE) { mCallback.goToUnlockScreen(); - } else if (whichHandle == RotarySelector.OnDialTriggerListener.RIGHT_HANDLE) { + } else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { // toggle silent mode mSilentMode = !mSilentMode; mAudioManager.setRingerMode(mSilentMode ? AudioManager.RINGER_MODE_SILENT : AudioManager.RINGER_MODE_NORMAL); - final int handleIcon = mSilentMode ? - R.drawable.ic_jog_dial_sound_off : - R.drawable.ic_jog_dial_sound_on; - final int toastIcon = mSilentMode ? - R.drawable.ic_lock_ringer_off : - R.drawable.ic_lock_ringer_on; - mRotary.setRightHandleResource(handleIcon); + + 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; toastMessage(mScreenLocked, message, toastIcon); mCallback.pokeWakelock(); } @@ -267,7 +283,12 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM /** {@inheritDoc} */ public void onGrabbedStateChange(View v, int grabbedState) { - // TODO: Update onscreen hint text based on the new state. + 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(); } /** @@ -354,30 +375,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } private void refreshTimeAndDateDisplay() { - Date now = new Date(); - mTime.setText(mTimeFormat.format(now)); - mDate.setText(mDateFormat.format(now)); - } - - /** - * @return A localized format like "Fri, Sep 18, 2009" - */ - private java.text.DateFormat getLockScreenDateFormat() { - SimpleDateFormat adjusted = null; - try { - // this call gives us the localized order - final SimpleDateFormat dateFormat = (SimpleDateFormat) - java.text.DateFormat.getDateInstance(java.text.DateFormat.FULL); - adjusted = new SimpleDateFormat(dateFormat.toPattern() - .replace("MMMM", "MMM") // we want "Sep", not "September" - .replace("EEEE", "EEE")); // we want "Fri", no "Friday" - } catch (ClassCastException e) { - // in case the library implementation changes and this throws a class cast exception - // or anything else that is funky - Log.e("LockScreen", "couldn't finnagle our custom date format :(", e); - return java.text.DateFormat.getDateInstance(java.text.DateFormat.MEDIUM); - } - return adjusted; + mDate.setText(DateFormat.format(mDateFormatString, new Date())); } private void updateStatusLines() { @@ -468,7 +466,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mRotary.setVisibility(View.VISIBLE); + mSelector.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.GONE); break; case NetworkLocked: @@ -478,7 +476,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mRotary.setVisibility(View.VISIBLE); + mSelector.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.GONE); break; case SimMissing: @@ -488,9 +486,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.INVISIBLE); - mRotary.setVisibility(View.VISIBLE); + mSelector.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.VISIBLE); - putEmergencyBelow(R.id.divider); + putEmergencyBelow(R.id.screenLocked); break; case SimMissingLocked: // text @@ -499,7 +497,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mRotary.setVisibility(View.GONE); + mSelector.setVisibility(View.GONE); mEmergencyCallButton.setVisibility(View.VISIBLE); putEmergencyBelow(R.id.screenLocked); break; @@ -509,7 +507,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.INVISIBLE); - mRotary.setVisibility(View.VISIBLE); + mSelector.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.GONE); break; case SimPukLocked: @@ -519,7 +517,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mRotary.setVisibility(View.GONE); + mSelector.setVisibility(View.GONE); mEmergencyCallButton.setVisibility(View.VISIBLE); putEmergencyBelow(R.id.screenLocked); break; @@ -563,7 +561,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM public boolean needsInput() { return false; } - + /** {@inheritDoc} */ public void onPause() { @@ -578,4 +576,13 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM public void cleanUp() { mUpdateMonitor.removeCallback(this); } + + /** {@inheritDoc} */ + public void onRingerModeChanged(int state) { + boolean silent = AudioManager.RINGER_MODE_SILENT == state; + if (silent != mSilentMode) { + mSilentMode = silent; + updateRightTabResources(); + } + } } diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index e57fbe8b544b..27a42bc62bd7 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -85,6 +85,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE; import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; @@ -94,7 +95,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; -import android.view.WindowManagerPolicy.WindowState; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.media.IAudioService; @@ -121,25 +121,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int PHONE_LAYER = 3; static final int SEARCH_BAR_LAYER = 4; static final int STATUS_BAR_PANEL_LAYER = 5; + static final int SYSTEM_DIALOG_LAYER = 6; // toasts and the plugged-in battery thing - static final int TOAST_LAYER = 6; - static final int STATUS_BAR_LAYER = 7; + static final int TOAST_LAYER = 7; + static final int STATUS_BAR_LAYER = 8; // SIM errors and unlock. Not sure if this really should be in a high layer. - static final int PRIORITY_PHONE_LAYER = 8; + static final int PRIORITY_PHONE_LAYER = 9; // like the ANR / app crashed dialogs - static final int SYSTEM_ALERT_LAYER = 9; + static final int SYSTEM_ALERT_LAYER = 10; // system-level error dialogs - static final int SYSTEM_ERROR_LAYER = 10; + static final int SYSTEM_ERROR_LAYER = 11; // on-screen keyboards and other such input method user interfaces go here. - static final int INPUT_METHOD_LAYER = 11; + static final int INPUT_METHOD_LAYER = 12; // on-screen keyboards and other such input method user interfaces go here. - static final int INPUT_METHOD_DIALOG_LAYER = 12; + static final int INPUT_METHOD_DIALOG_LAYER = 13; // the keyguard; nothing on top of these can take focus, since they are // responsible for power management when displayed. - static final int KEYGUARD_LAYER = 13; - static final int KEYGUARD_DIALOG_LAYER = 14; + static final int KEYGUARD_LAYER = 14; + static final int KEYGUARD_DIALOG_LAYER = 15; // things in here CAN NOT take focus, but are shown on top of everything else. - static final int SYSTEM_OVERLAY_LAYER = 15; + static final int SYSTEM_OVERLAY_LAYER = 16; static final int APPLICATION_MEDIA_SUBLAYER = -2; static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; @@ -154,6 +155,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; + static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey"; final Object mLock = new Object(); @@ -441,7 +443,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext); } - final boolean keyguardShowing = mKeyguardMediator.isShowing(); + final boolean keyguardShowing = mKeyguardMediator.isShowingAndNotHidden(); mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); if (keyguardShowing) { // since it took two seconds of long press to bring this up, @@ -686,6 +688,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return STATUS_BAR_LAYER; case TYPE_STATUS_BAR_PANEL: return STATUS_BAR_PANEL_LAYER; + case TYPE_SYSTEM_DIALOG: + return SYSTEM_DIALOG_LAYER; case TYPE_SEARCH_BAR: return SEARCH_BAR_LAYER; case TYPE_PHONE: @@ -1108,7 +1112,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * given the situation with the keyguard. */ void launchHomeFromHotKey() { - if (!mHideLockScreen && mKeyguardMediator.isShowing()) { + if (mKeyguardMediator.isShowingAndNotHidden()) { // don't launch home if keyguard showing } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) { // when in keyguard restricted mode, must first verify unlock @@ -1120,7 +1124,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { ActivityManagerNative.getDefault().stopAppSwitches(); } catch (RemoteException e) { } - sendCloseSystemWindows(); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY); startDockOrHome(); } } @@ -1131,7 +1135,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { ActivityManagerNative.getDefault().stopAppSwitches(); } catch (RemoteException e) { } - sendCloseSystemWindows(); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY); startDockOrHome(); } } @@ -1619,14 +1623,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) { int result = ACTION_PASS_TO_USER; final boolean isWakeKey = isWakeKeyTq(event); - final boolean keyguardShowing = keyguardIsShowingTq(); + // If screen is off then we treat the case where the keyguard is open but hidden + // the same as if it were open and in front. + // This will prevent any keys other than the power button from waking the screen + // when the keyguard is hidden by another activity. + final boolean keyguardActive = (screenIsOn ? + mKeyguardMediator.isShowingAndNotHidden() : + mKeyguardMediator.isShowing()); if (false) { Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode - + " screenIsOn=" + screenIsOn + " keyguardShowing=" + keyguardShowing); + + " screenIsOn=" + screenIsOn + " keyguardActive=" + keyguardActive); } - if (keyguardShowing) { + if (keyguardActive) { if (screenIsOn) { // when the screen is on, always give the event to the keyguard result |= ACTION_PASS_TO_USER; @@ -1644,14 +1654,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode) && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) { + // when keyguard is showing and screen off, we need + // to handle the volume key for calls and music here if (isInCall()) { - // if the keyguard didn't wake the device, we are in call, and - // it is a volume key, turn on the screen so that the user - // can more easily adjust the in call volume. - mKeyguardMediator.pokeWakelock(); + handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode); } else if (isMusicActive()) { - // when keyguard is showing and screen off, we need - // to handle the volume key for music here handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode); } } @@ -1720,7 +1727,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mShouldTurnOffOnKeyUp = false; boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0; boolean sleeps = (mEndcallBehavior & ENDCALL_SLEEPS) != 0; - if (keyguardShowing + if (keyguardActive || (sleeps && !gohome) || (gohome && !goHome() && sleeps)) { // they must already be on the keyguad or home screen, @@ -1923,7 +1930,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public boolean keyguardIsShowingTq() { - return mKeyguardMediator.isShowing(); + return mKeyguardMediator.isShowingAndNotHidden(); } /** {@inheritDoc} */ @@ -1997,8 +2004,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { try { int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU); int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S); - int dpadState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER); - int trackballState = mWindowManager.getScancodeState(RawInputEvent.BTN_MOUSE); + int dpadState = mWindowManager.getDPadKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER); + int trackballState = mWindowManager.getTrackballScancodeState(RawInputEvent.BTN_MOUSE); mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0; performHapticFeedbackLw(null, mSafeMode ? HapticFeedbackConstants.SAFE_MODE_ENABLED @@ -2193,7 +2200,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) { final boolean hapticsDisabled = Settings.System.getInt(mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0; - if (!always && (hapticsDisabled || mKeyguardMediator.isShowing())) { + if (!always && (hapticsDisabled || mKeyguardMediator.isShowingAndNotHidden())) { return false; } switch (effectId) { @@ -2221,7 +2228,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } public void screenOnStoppedLw() { - if (!mKeyguardMediator.isShowing()) { + if (!mKeyguardMediator.isShowingAndNotHidden() && mPowerManager.isScreenOn()) { long curTime = SystemClock.uptimeMillis(); mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); } diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index a5032b3ae0c5..e090ac5e9fd0 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -27,6 +27,7 @@ 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; import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient; @@ -45,6 +46,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback { + private static final boolean DEBUG = false; private static final String TAG = "UnlockScreen"; // how long before we clear the wrong pattern @@ -71,10 +73,10 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient private boolean mCreatedInPortrait; + private String mDateFormatString; + private TextView mCarrier; - private TextView mCenterDot; private TextView mDate; - private TextView mTime; // are we showing battery information? private boolean mShowingBatteryInfo = false; @@ -102,7 +104,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient * Keeps track of the last time we poked the wake lock during dispatching * of the touch event, initalized to something gauranteed to make us * poke it when the user starts drawing the pattern. - * @see #dispatchTouchEvent(android.view.MotionEvent) + * @see #dispatchTouchEvent(android.view.MotionEvent) */ private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS; @@ -162,6 +164,12 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mTotalFailedPatternAttempts = totalFailedAttempts; mFailedPatternAttemptsSinceLastTimeout = totalFailedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; + if (DEBUG) Log.d(TAG, + "UnlockScreen() ctor: totalFailedAttempts=" + + totalFailedAttempts + ", mFailedPat...=" + + mFailedPatternAttemptsSinceLastTimeout + ); + if (mUpdateMonitor.isInPortrait()) { LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_portrait, this, true); } else { @@ -169,11 +177,9 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient } mCarrier = (TextView) findViewById(R.id.carrier); - mCenterDot = (TextView) findViewById(R.id.centerDot); mDate = (TextView) findViewById(R.id.date); - mTime = (TextView) findViewById(R.id.time); - mCenterDot.setText("|"); + mDateFormatString = getContext().getString(R.string.full_wday_month_day_no_year); refreshTimeAndDateDisplay(); mStatus1 = (TextView) findViewById(R.id.status1); @@ -241,9 +247,10 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient } public void setEnableFallback(boolean state) { + if (DEBUG) Log.d(TAG, "setEnableFallback(" + state + ")"); mEnableFallback = state; } - + private void resetStatusInfo() { mInstructions = null; mShowingBatteryInfo = mUpdateMonitor.shouldShowBatteryInfo(); @@ -322,9 +329,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient private void refreshTimeAndDateDisplay() { - Date now = new Date(); - mTime.setText(DateFormat.getTimeFormat(getContext()).format(now)); - mDate.setText(DateFormat.getMediumDateFormat(getContext()).format(now)); + mDate.setText(DateFormat.format(mDateFormatString, new Date())); } @@ -363,6 +368,11 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mCarrier.setText(LockScreen.getCarrierString(plmn, spn)); } + /** {@inheritDoc} */ + public void onRingerModeChanged(int state) { + // not currently used + } + // ---------- SimStateCallback /** {@inheritDoc} */ @@ -386,7 +396,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient public boolean needsInput() { return false; } - + /** {@inheritDoc} */ public void onPause() { if (mCountdownTimer != null) { @@ -404,9 +414,9 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mLockPatternView.enableInput(); mLockPatternView.setEnabled(true); mLockPatternView.clearPattern(); - + // show "forgot pattern?" button if we have an alternate authentication method - mForgotPatternButton.setVisibility(mCallback.doesFallbackUnlockScreenExist() + mForgotPatternButton.setVisibility(mCallback.doesFallbackUnlockScreenExist() ? View.VISIBLE : View.INVISIBLE); // if the user is currently locked out, enforce it. @@ -452,7 +462,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient public void onPatternCellAdded(List pattern) { // To guard against accidental poking of the wakelock, look for - // the user actually trying to draw a pattern of some minimal length. + // the user actually trying to draw a pattern of some minimal length. if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); } -- GitLab From e224cefb3c9cb41b2999732bde78eb119163078d Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 13 Jan 2010 21:11:08 -0800 Subject: [PATCH 189/458] Do not turn off screen immediately after undocking. Change-Id: I1d01d141961d1e26d814a202745ce77678fd4518 BUG: 2356385 Signed-off-by: Mike Lockwood --- policy/com/android/internal/policy/impl/PhoneWindowManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 27a42bc62bd7..27278e01d812 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -511,7 +511,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PhoneWindowManager.mBroadcastWakeLock"); - mDockWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, + mDockWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "PhoneWindowManager.mDockWakeLock"); mDockWakeLock.setReferenceCounted(false); mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); -- GitLab From 066aa99d2d114d46406e00fcc23d193d117395b1 Mon Sep 17 00:00:00 2001 From: Scott Turner Date: Thu, 14 Jan 2010 21:05:17 -0500 Subject: [PATCH 190/458] long modifier was on the wrong argument. --- tools/aidl/aidl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp index fc658f5b54fb..f17f66b31f8e 100644 --- a/tools/aidl/aidl.cpp +++ b/tools/aidl/aidl.cpp @@ -55,7 +55,7 @@ test_document(document_item_type* d) printf("parcelable %s %s;\n", b->package, b->name.data); } else { - printf("UNKNOWN d=0x%08x d->item_type=%ld\n", (long)d, d->item_type); + printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type); } d = d->next; } -- GitLab From 3a1837e9947505edc41d3f422bf0e0d268e349c3 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Fri, 15 Jan 2010 16:39:16 -0800 Subject: [PATCH 191/458] Fix for 2292713: Remove workaround that hides SlidingTab widget while internal state is inconsistent. The previous workaround for this race condition prevented glitches by postponing drawing the SlidingTab until the internal state was consistent. Unfortunately, the InCallScreen seems to trigger this most of the time if the keyboard is open or the last application was in landscape mode. Instead, we'll handle this separately in lockscreen. --- .../policy/impl/LockPatternKeyguardView.java | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 00dc92969b0d..85918fbf43b7 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -29,6 +29,7 @@ import android.accounts.OperationCanceledException; import android.app.AlertDialog; import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorFilter; @@ -40,6 +41,7 @@ import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.View; +import android.view.ViewGroup; import android.view.WindowManager; import java.io.IOException; @@ -139,6 +141,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase */ private final LockPatternUtils mLockPatternUtils; + private boolean mIsPortrait; + /** * @return Whether we are stuck on the lock screen because the sim is * missing. @@ -266,7 +270,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase public void reportFailedPatternAttempt() { mUpdateMonitor.reportFailedAttempt(); final int failedAttempts = mUpdateMonitor.getFailedAttempts(); - if (DEBUG) Log.d(TAG, + if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts + " (enableFallback=" + mEnableFallback + ")"); if (mEnableFallback && failedAttempts == @@ -307,7 +311,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase mLockScreen = createLockScreen(); addView(mLockScreen); final UnlockMode unlockMode = getUnlockMode(); - if (DEBUG) Log.d(TAG, + if (DEBUG) Log.d(TAG, "LockPatternKeyguardView ctor: about to createUnlockScreenFor; mEnableFallback=" + mEnableFallback); mUnlockScreen = createUnlockScreenFor(unlockMode); @@ -334,6 +338,33 @@ public class LockPatternKeyguardView extends KeyguardViewBase } + // TODO: + // This overloaded method was added to workaround a race condition in the framework between + // notification for orientation changed, layout() and switching resources. This code attempts + // to avoid drawing the incorrect layout while things are in transition. The method can just + // be removed once the race condition is fixed. See bugs 2262578 and 2292713. + @Override + protected void dispatchDraw(Canvas canvas) { + final int orientation = getResources().getConfiguration().orientation; + if (mIsPortrait && Configuration.ORIENTATION_PORTRAIT != orientation + || getResources().getBoolean(R.bool.lockscreen_isPortrait) != mIsPortrait) { + // Make sure we redraw once things settle down. + // Log.v(TAG, "dispatchDraw(): not drawing because state is inconsistent"); + postInvalidate(); + + // In order to minimize flashing, draw the first child's background for now. + ViewGroup view = (ViewGroup) (mMode == Mode.LockScreen ? mLockScreen : mUnlockScreen); + if (view != null && view.getChildAt(0) != null) { + Drawable background = view.getChildAt(0).getBackground(); + if (background != null) { + background.draw(canvas); + } + } + return; + } + super.dispatchDraw(canvas); + } + @Override public void reset() { mIsVerifyUnlockOnly = false; @@ -482,6 +513,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase } View createUnlockScreenFor(UnlockMode unlockMode) { + // Capture the orientation this layout was created in. + mIsPortrait = getResources().getBoolean(R.bool.lockscreen_isPortrait); + if (unlockMode == UnlockMode.Pattern) { UnlockScreen view = new UnlockScreen( mContext, -- GitLab From 9c20d0e91bb5c0b7c540ba2f0d6c9b8add979d6f Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Wed, 20 Jan 2010 15:00:23 -0800 Subject: [PATCH 192/458] Fix 2385283: Add DevicePolicyManager calls to LockScreen. --- .../policy/impl/KeyguardViewMediator.java | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 176ba7fcf52f..c3c36b48a983 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -91,7 +91,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private final static String TAG = "KeyguardViewMediator"; - private static final String DELAYED_KEYGUARD_ACTION = + private static final String DELAYED_KEYGUARD_ACTION = "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD"; // used for handler messages @@ -107,7 +107,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private static final int KEYGUARD_DONE_DRAWING = 10; private static final int KEYGUARD_DONE_AUTHENTICATING = 11; private static final int SET_HIDDEN = 12; - + /** * The default amount of time we stay awake (used for all key input) */ @@ -133,13 +133,13 @@ public class KeyguardViewMediator implements KeyguardViewCallback, * that is reenabling the keyguard. */ private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000; - + private Context mContext; private AlarmManager mAlarmManager; private StatusBarManager mStatusBarManager; private boolean mSystemReady; - + /** Low level access to the power manager for enableUserActivity. Having this * requires that we run in the system process. */ LocalPowerManager mRealPowerManager; @@ -234,7 +234,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mRealPowerManager = powerManager; mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mWakeLock = mPM.newWakeLock( - PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, + PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "keyguard"); mWakeLock.setReferenceCounted(false); mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard"); @@ -257,10 +257,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mUpdateMonitor.registerSimStateCallback(this); - mKeyguardViewProperties = - new LockPatternKeyguardViewProperties( - new LockPatternUtils(mContext.getContentResolver()), - mUpdateMonitor); + mKeyguardViewProperties = new LockPatternKeyguardViewProperties( + new LockPatternUtils(mContext), mUpdateMonitor); mKeyguardViewManager = new KeyguardViewManager( context, WindowManagerImpl.getDefault(), this, @@ -297,7 +295,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mExitSecureCallback.onKeyguardExitResult(false); mExitSecureCallback = null; if (!mExternallyEnabled) { - hideLocked(); + hideLocked(); } } else if (mShowing) { notifyScreenOffLocked(); @@ -314,7 +312,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, 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 = " + 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. @@ -508,7 +506,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing"); return; } - + // if the setup wizard hasn't run yet, don't show final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", false); @@ -522,7 +520,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, + " and the sim is not locked or missing"); return; } - + if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen"); showLocked(); } @@ -560,7 +558,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, /** * Send a message to keyguard telling it the screen just turned on. - * @see #onScreenTurnedOn() + * @see #onScreenTurnedOn() * @see #handleNotifyScreenOn */ private void notifyScreenOnLocked() { @@ -603,7 +601,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, /** * Send message to keyguard telling it to hide itself - * @see #handleHide() + * @see #handleHide() */ private void hideLocked() { if (DEBUG) Log.d(TAG, "hideLocked"); @@ -651,7 +649,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, public boolean isSecure() { return mKeyguardViewProperties.isSecure(); } - + private BroadcastReceiver mBroadCastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -692,7 +690,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, * The 'Tq' suffix is per the documentation in {@link WindowManagerPolicy}. * Be sure not to take any action that takes a long time; any significant * action should be posted to a handler. - * + * * @param keyCode The keycode of the key that woke the device * @return Whether we poked the wake lock (and turned the screen on) */ @@ -715,12 +713,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_MUTE: - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - case KeyEvent.KEYCODE_MEDIA_STOP: - case KeyEvent.KEYCODE_MEDIA_NEXT: - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: case KeyEvent.KEYCODE_CAMERA: return false; @@ -753,7 +751,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, /** * {@inheritDoc} * - * @see #handleKeyguardDone + * @see #handleKeyguardDone */ public void keyguardDone(boolean authenticated) { keyguardDone(authenticated, true); @@ -761,14 +759,14 @@ public class KeyguardViewMediator implements KeyguardViewCallback, public void keyguardDone(boolean authenticated, boolean wakeup) { synchronized (this) { - EventLog.writeEvent(70000, 2); + EventLog.writeEvent(70000, 2); if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")"); Message msg = mHandler.obtainMessage(KEYGUARD_DONE); msg.arg1 = wakeup ? 1 : 0; mHandler.sendMessage(msg); if (authenticated) { - mUpdateMonitor.clearFailedAttempts(); + mUpdateMonitor.clearFailedAttempts(); } if (mExitSecureCallback != null) { @@ -902,7 +900,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleShow"); if (!mSystemReady) return; - + mKeyguardViewManager.show(); mShowing = true; adjustUserActivityLocked(); @@ -992,7 +990,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } /** - * Handle message sent by {@link #resetStateLocked()} + * Handle message sent by {@link #resetStateLocked()} * @see #RESET */ private void handleReset() { -- GitLab From e6ec57727e2da14a9027293858d97a84b08768b1 Mon Sep 17 00:00:00 2001 From: Paul Watts Date: Tue, 19 Jan 2010 15:53:11 -0800 Subject: [PATCH 193/458] Include the API level 4 fields in the Parcel. --- location/java/android/location/Address.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/location/java/android/location/Address.java b/location/java/android/location/Address.java index ac275c677c76..b152f48a3e9e 100644 --- a/location/java/android/location/Address.java +++ b/location/java/android/location/Address.java @@ -500,7 +500,10 @@ public class Address implements Parcelable { a.mAdminArea = in.readString(); a.mSubAdminArea = in.readString(); a.mLocality = in.readString(); + a.mSubLocality = in.readString(); a.mThoroughfare = in.readString(); + a.mSubThoroughfare = in.readString(); + a.mPremises = in.readString(); a.mPostalCode = in.readString(); a.mCountryCode = in.readString(); a.mCountryName = in.readString(); @@ -544,7 +547,10 @@ public class Address implements Parcelable { parcel.writeString(mAdminArea); parcel.writeString(mSubAdminArea); parcel.writeString(mLocality); + parcel.writeString(mSubLocality); parcel.writeString(mThoroughfare); + parcel.writeString(mSubThoroughfare); + parcel.writeString(mPremises); parcel.writeString(mPostalCode); parcel.writeString(mCountryCode); parcel.writeString(mCountryName); -- GitLab From f3bfed513ebbe7831a2bb696ccda5703f2bead84 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Thu, 21 Jan 2010 16:38:44 -0500 Subject: [PATCH 194/458] Workaround for a keyguard problem that appeared in the in call screen. While in call, pressing the power key to turn off the screen caused the Home button to no longer work after rewaking the screen due to the KeyguardViewMediator mHidden flag not being set. Change-Id: I322317671b2e5e32de23ed524f6e4808b0334c12 BUG: 2382766 Signed-off-by: Mike Lockwood --- .../com/android/internal/policy/impl/PhoneWindowManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 27278e01d812..7be15e2f0c0d 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1450,18 +1450,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } else if (mHideLockScreen) { if (mKeyguard.hideLw(false)) { - mKeyguardMediator.setHidden(true); changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; } + mKeyguardMediator.setHidden(true); } else { if (mKeyguard.showLw(false)) { - mKeyguardMediator.setHidden(false); changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; } + mKeyguardMediator.setHidden(false); } } -- GitLab From 6e37055b0741c618db1a35a60df5c612237c315c Mon Sep 17 00:00:00 2001 From: John Wang Date: Thu, 21 Jan 2010 17:30:07 -0800 Subject: [PATCH 195/458] Update carrier display in lockscreen. For bug 2352904, lockscreen need clearly show "Emergency Calls Only" status no matter with SIM status. The change is to show both SIM card status and carrier PLMN including "Emergency Calls Only" status. --- .../internal/policy/impl/LockScreen.java | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 7514cc2c4c82..c370f9e8ba1c 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -470,8 +470,12 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mEmergencyCallButton.setVisibility(View.GONE); break; case NetworkLocked: - // text - mCarrier.setText(R.string.lockscreen_network_locked_message); + // 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( + getCarrierString( + mUpdateMonitor.getTelephonyPlmn(), + getContext().getText(R.string.lockscreen_network_locked_message))); mScreenLocked.setText(R.string.lockscreen_instructions_when_pattern_disabled); // layout @@ -481,7 +485,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM break; case SimMissing: // text - mCarrier.setText(R.string.lockscreen_missing_sim_message_short); + mCarrier.setText( + getCarrierString( + mUpdateMonitor.getTelephonyPlmn(), + getContext().getText(R.string.lockscreen_missing_sim_message_short))); mScreenLocked.setText(R.string.lockscreen_instructions_when_pattern_disabled); // layout @@ -492,7 +499,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM break; case SimMissingLocked: // text - mCarrier.setText(R.string.lockscreen_missing_sim_message_short); + mCarrier.setText( + getCarrierString( + mUpdateMonitor.getTelephonyPlmn(), + getContext().getText(R.string.lockscreen_missing_sim_message_short))); mScreenLocked.setText(R.string.lockscreen_missing_sim_instructions); // layout @@ -503,7 +513,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM break; case SimLocked: // text - mCarrier.setText(R.string.lockscreen_sim_locked_message); + mCarrier.setText( + getCarrierString( + mUpdateMonitor.getTelephonyPlmn(), + getContext().getText(R.string.lockscreen_sim_locked_message))); // layout mScreenLocked.setVisibility(View.INVISIBLE); @@ -512,7 +525,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM break; case SimPukLocked: // text - mCarrier.setText(R.string.lockscreen_sim_puk_locked_message); + mCarrier.setText( + getCarrierString( + mUpdateMonitor.getTelephonyPlmn(), + getContext().getText(R.string.lockscreen_sim_puk_locked_message))); mScreenLocked.setText(R.string.lockscreen_sim_puk_locked_instructions); // layout -- GitLab From 5bfb2e0d7c729f6ed9b81200c92f000a24f8b736 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Fri, 22 Jan 2010 19:07:47 -0800 Subject: [PATCH 196/458] Fix 2287263: Change carrier TextView to be 1 line and marquee if text is too long. This is intended as a workaround for the long text lines introduced in https://android-git.corp.google.com/g/#change,38100. Added explicit TextView.setColor() to workaround bug with TextView.setSelected(). --- policy/com/android/internal/policy/impl/LockScreen.java | 6 +++++- policy/com/android/internal/policy/impl/UnlockScreen.java | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index c370f9e8ba1c..08cdd3fbe9f0 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -179,6 +179,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } 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); @@ -544,7 +548,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM if (telephonyPlmn != null && telephonySpn == null) { return telephonyPlmn; } else if (telephonyPlmn != null && telephonySpn != null) { - return telephonyPlmn + "\n" + telephonySpn; + return telephonyPlmn + "|" + telephonySpn; } else if (telephonyPlmn == null && telephonySpn != null) { return telephonySpn; } else { diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index e090ac5e9fd0..32633e1f7d59 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -239,6 +239,10 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient updateMonitor.registerConfigurationChangeCallback(this); setFocusableInTouchMode(true); + // Required to get Marquee to work. + mCarrier.setSelected(true); + mCarrier.setTextColor(0xffffffff); + // until we get an update... mCarrier.setText( LockScreen.getCarrierString( -- GitLab From 6fe0f0e46d7863bd75f6bd23b2fa805df84b5a4d Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Wed, 27 Jan 2010 17:53:18 -0800 Subject: [PATCH 197/458] Fix 2385283,2379269: report unlock attempt success/fail to DevicePolicyManager Reports success/fail for password, pattern and account unlock. Tweak pattern timeout a bit to avoid timeouts. --- .../policy/impl/AccountUnlockScreen.java | 2 ++ .../policy/impl/KeyguardScreenCallback.java | 11 +++++-- .../policy/impl/LockPatternKeyguardView.java | 8 +++++ .../policy/impl/PasswordUnlockScreen.java | 12 ++++--- .../internal/policy/impl/UnlockScreen.java | 32 +++++++++++++------ 5 files changed, 48 insertions(+), 17 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index 7992dd8856a6..26419dda87a2 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -177,12 +177,14 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(intent); + mCallback.reportSuccessfulUnlockAttempt(); // close the keyguard mCallback.keyguardDone(true); } else { mInstructions.setText(R.string.lockscreen_glogin_invalid_input); mPassword.setText(""); + mCallback.reportFailedUnlockAttempt(); } } diff --git a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java index 6bb6a45a7e34..06a5f193b3bb 100644 --- a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java +++ b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java @@ -63,13 +63,18 @@ public interface KeyguardScreenCallback extends KeyguardViewCallback { void takeEmergencyCallAction(); /** - * Report that the user had a failed attempt unlocking via the pattern. + * Report that the user had a failed attempt to unlock with password or pattern. */ - void reportFailedPatternAttempt(); + void reportFailedUnlockAttempt(); + + /** + * Report that the user successfully entered their password or pattern. + */ + void reportSuccessfulUnlockAttempt(); /** * Report whether we there's another way to unlock the device. - * @return true + * @return true */ boolean doesFallbackUnlockScreenExist(); } diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index ccb79023ac28..8f6561af679d 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -293,6 +293,14 @@ public class LockPatternKeyguardView extends KeyguardViewBase public boolean doesFallbackUnlockScreenExist() { return mEnableFallback; } + + public void reportFailedUnlockAttempt() { + mLockPatternUtils.reportFailedPasswordAttempt(); + } + + public void reportSuccessfulUnlockAttempt() { + mLockPatternUtils.reportSuccessfulPasswordAttempt(); + } }; /** diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java index bb1950a940d4..1a250b8aacdd 100644 --- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -51,11 +51,13 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen private TextView mCarrier; private LockPatternUtils mLockPatternUtils; private Button mCancelButton; - private int mPasswordAttempts = 0; - private int mMinimumPasswordLength = 4; // TODO: get from policy store private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + // 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. + private static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3; + public PasswordUnlockScreen(Context context, LockPatternUtils lockPatternUtils, KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback) { super(context); @@ -142,12 +144,12 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen private void verifyPasswordAndUnlock() { String entry = mPasswordTextView.getText().toString(); if (mLockPatternUtils.checkPassword(entry)) { - mPasswordAttempts = 0; mCallback.keyguardDone(true); - } else if (entry.length() >= mMinimumPasswordLength ) { + mCallback.reportSuccessfulUnlockAttempt(); + } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) { // to avoid accidental lockout, only count attempts that are long enough to be a // real password. This may require some tweaking. - mPasswordAttempts++; + mCallback.reportFailedUnlockAttempt(); } mPasswordTextView.setText(""); } diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index 30ab8799a2ad..5e6e54d2ac23 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -52,12 +52,20 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient // how long before we clear the wrong pattern private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000; - // how long we stay awake once the user is ready to enter a pattern + // how long we stay awake after each key beyond MIN_PATTERN_BEFORE_POKE_WAKELOCK private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000; + // how long we stay awake after the user hits the first dot. + private static final int UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS = 2000; + // how many cells the user has to cross before we poke the wakelock private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2; + // This dictates how long a pattern should be before we count it as an attempt. + // This should be long enough to avoid false triggers while the device is in a pocket, + // as this can lead to a wiped device if a {@link DeviceAdmin} is active and has it enabled. + private static final int MIN_PATTERN_BEFORE_REPORT = 3; + private int mFailedPatternAttemptsSinceLastTimeout = 0; private int mTotalFailedPatternAttempts = 0; private CountDownTimer mCountdownTimer = null; @@ -466,6 +474,9 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient // the user actually trying to draw a pattern of some minimal length. if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); + } else { + // Give just a little extra time if they hit one of the first few dots + mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS); } } @@ -476,6 +487,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mInstructions = ""; updateStatusLines(); mCallback.keyguardDone(true); + mCallback.reportSuccessfulUnlockAttempt(); } else { if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); @@ -484,19 +496,21 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { mTotalFailedPatternAttempts++; mFailedPatternAttemptsSinceLastTimeout++; - mCallback.reportFailedPatternAttempt(); } if (mFailedPatternAttemptsSinceLastTimeout >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); handleAttemptLockout(deadline); - return; + } else { + // TODO mUnlockIcon.setVisibility(View.VISIBLE); + mInstructions = getContext().getString(R.string.lockscreen_pattern_wrong); + updateStatusLines(); + mLockPatternView.postDelayed( + mCancelPatternRunnable, + PATTERN_CLEAR_TIMEOUT_MS); + } + if (pattern.size() > MIN_PATTERN_BEFORE_REPORT) { + mCallback.reportFailedUnlockAttempt(); } - // TODO mUnlockIcon.setVisibility(View.VISIBLE); - mInstructions = getContext().getString(R.string.lockscreen_pattern_wrong); - updateStatusLines(); - mLockPatternView.postDelayed( - mCancelPatternRunnable, - PATTERN_CLEAR_TIMEOUT_MS); } } } -- GitLab From b3f615907d8339e5813457dc8076dbfdadfd2800 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Wed, 27 Jan 2010 20:26:42 -0800 Subject: [PATCH 198/458] Fix 2402303: Show pmf3k in front of PIN/Password unlock screens. This came down to a decision; if we want to show other information (owner id, current playing song, etc.) as well as continue to have an easy way to silence the device, we need to have two unlock screens in these cases. We simply don't have enough room on these screens to show anything but the unlock widget and a small bit of text. This change *does not* affect pattern unlock, which will continue to be a single unlock screen. --- .../android/internal/policy/impl/LockPatternKeyguardView.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 1e7d62ec1c4a..a7fc6b66e2c4 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -625,7 +625,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase final IccCard.State simState = mUpdateMonitor.getSimState(); if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED)) { return Mode.LockScreen; - } else if (isSecure()) { + } else if (isSecure() + && mLockPatternUtils.getPasswordMode() == LockPatternUtils.MODE_PATTERN) { return Mode.UnlockScreen; } else { return Mode.LockScreen; -- GitLab From 81d42591f766928fe250a0182e707e864f6e1f54 Mon Sep 17 00:00:00 2001 From: Mike Playle Date: Fri, 29 Jan 2010 09:52:22 +0000 Subject: [PATCH 199/458] Fix glReadPixels() to verify that both x and y are non-negative. --- opengl/libagl/texture.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp index 13d078e2a3d8..89a19b66d555 100644 --- a/opengl/libagl/texture.cpp +++ b/opengl/libagl/texture.cpp @@ -1467,7 +1467,7 @@ void glReadPixels( ogles_error(c, GL_INVALID_VALUE); return; } - if (x<0 || x<0) { + if (x<0 || y<0) { ogles_error(c, GL_INVALID_VALUE); return; } -- GitLab From 28569306e3fb136488cade5ed908a1be66128c2d Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Thu, 28 Jan 2010 11:54:40 -0500 Subject: [PATCH 200/458] Add implementation for ALLOW_LOCK_WHILE_SCREEN_ON flag to PhoneWindowManager This allows the lockscreen to activate after the normal screen timeout while the screen is on. Needed for dock apps, screen savers, etc. Change-Id: I25c3579e4363c2b19d503fdbd45d2ff41cdd11bb Signed-off-by: Mike Lockwood --- .../policy/impl/KeyguardViewMediator.java | 14 +++++ .../policy/impl/PhoneWindowManager.java | 57 ++++++++++++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index c3c36b48a983..85afa81cd637 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -107,6 +107,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private static final int KEYGUARD_DONE_DRAWING = 10; private static final int KEYGUARD_DONE_AUTHENTICATING = 11; private static final int SET_HIDDEN = 12; + private static final int KEYGUARD_TIMEOUT = 13; /** * The default amount of time we stay awake (used for all key input) @@ -455,6 +456,16 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } } + /** + * Used by PhoneWindowManager to enable the keyguard due to a user activity timeout. + * This must be safe to call from any thread and with any window manager locks held. + */ + public void doKeyguardTimeout() { + mHandler.removeMessages(KEYGUARD_TIMEOUT); + Message msg = mHandler.obtainMessage(KEYGUARD_TIMEOUT); + mHandler.sendMessage(msg); + } + /** * Given the state of the keyguard, is the input restricted? * Input is restricted when the keyguard is showing, or when the keyguard @@ -839,6 +850,9 @@ public class KeyguardViewMediator implements KeyguardViewCallback, case SET_HIDDEN: handleSetHidden(msg.arg1 != 0); break; + case KEYGUARD_TIMEOUT: + doKeyguard(); + break; } } }; diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index f0717713bdc9..e9acc2325b57 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -70,6 +70,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; +import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; @@ -246,6 +247,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mSearchKeyPressed; boolean mConsumeSearchKeyUp; + // support for activating the lock screen while the screen is on + boolean mAllowLockscreenWhenOn; + int mLockScreenTimeout; + boolean mLockScreenTimerActive; + static final int ENDCALL_HOME = 0x1; static final int ENDCALL_SLEEPS = 0x2; static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; @@ -272,6 +278,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.System.END_BUTTON_BEHAVIOR), false, this); resolver.registerContentObserver(Settings.System.getUriFor( Settings.System.ACCELEROMETER_ROTATION), false, this); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.SCREEN_OFF_TIMEOUT), false, this); resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.DEFAULT_INPUT_METHOD), false, this); resolver.registerContentObserver(Settings.System.getUriFor( @@ -303,6 +311,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mAccelerometerDefault = accelerometerDefault; updateOrientationListenerLp(); } + // use screen off timeout setting as the timeout for the lockscreen + mLockScreenTimeout = Settings.System.getInt(resolver, + Settings.System.SCREEN_OFF_TIMEOUT, 0); String imId = Settings.Secure.getString(resolver, Settings.Secure.DEFAULT_INPUT_METHOD); boolean hasSoftInput = imId != null && imId.length() > 0; @@ -1173,6 +1184,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mTopFullscreenOpaqueWindowState = null; mForceStatusBar = false; mHideLockScreen = false; + mAllowLockscreenWhenOn = false; mDismissKeyguard = false; // decide where the status bar goes ahead of time @@ -1390,6 +1402,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win); mDismissKeyguard = true; } + if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { + mAllowLockscreenWhenOn = true; + } } // Dock windows carve out the bottom of the screen, so normal windows @@ -1483,7 +1498,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } - + + // update since mAllowLockscreenWhenOn might have changed + updateLockScreenTimeout(); return changes; } @@ -1946,6 +1963,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { synchronized (mLock) { mScreenOn = false; updateOrientationListenerLp(); + updateLockScreenTimeout(); } } @@ -1956,6 +1974,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { synchronized (mLock) { mScreenOn = true; updateOrientationListenerLp(); + updateLockScreenTimeout(); } } @@ -2090,6 +2109,42 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + /** {@inheritDoc} */ + public void userActivity() { + synchronized (mScreenLockTimeout) { + if (mLockScreenTimerActive) { + // reset the timer + mHandler.removeCallbacks(mScreenLockTimeout); + mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout); + } + } + } + + Runnable mScreenLockTimeout = new Runnable() { + public void run() { + synchronized (this) { + if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard"); + mKeyguardMediator.doKeyguardTimeout(); + mLockScreenTimerActive = false; + } + } + }; + + private void updateLockScreenTimeout() { + synchronized (mScreenLockTimeout) { + boolean enable = (mAllowLockscreenWhenOn && mScreenOn && mKeyguardMediator.isSecure()); + if (mLockScreenTimerActive != enable) { + if (enable) { + if (localLOGV) Log.v(TAG, "setting lockscreen timer"); + mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout); + } else { + if (localLOGV) Log.v(TAG, "clearing lockscreen timer"); + mHandler.removeCallbacks(mScreenLockTimeout); + } + mLockScreenTimerActive = enable; + } + } + } /** {@inheritDoc} */ public void enableScreenAfterBoot() { -- GitLab From e5fbe9b9122e68e16f7657989ab4b2cf5ea88958 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Fri, 5 Feb 2010 13:26:28 -0800 Subject: [PATCH 201/458] New "device is locked" status bar icon, part 2. Shown whenever the secure lockscreen is (a) visible, or (b) active but hidden due to a FLAG_SHOW_WHEN_LOCKED Activity. Change-Id: I0e08a952904cc4728621953a42806edf26eb8e46 --- .../policy/impl/KeyguardViewMediator.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 85afa81cd637..b35b3fc3c799 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -28,6 +28,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; +import android.os.IBinder; import android.os.LocalPowerManager; import android.os.Message; import android.os.PowerManager; @@ -138,6 +139,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private Context mContext; private AlarmManager mAlarmManager; private StatusBarManager mStatusBarManager; + private IBinder mSecureLockIcon = null; private boolean mSystemReady; @@ -965,6 +967,19 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (mStatusBarManager == null) { Log.w(TAG, "Could not get status bar manager"); } else { + // Give feedback to user when secure keyguard is active and engaged + if (mShowing && isSecure()) { + if (mSecureLockIcon == null) { + mSecureLockIcon = mStatusBarManager.addIcon("secure", + com.android.internal.R.drawable.stat_sys_secure, 0); + } + } else { + if (mSecureLockIcon != null) { + mStatusBarManager.removeIcon(mSecureLockIcon); + mSecureLockIcon = null; + } + } + // if the keyguard is shown, allow the status bar to open // only if the keyguard is insecure and is covered by another window boolean enable = !mShowing || (mHidden && !isSecure()); -- GitLab From a781d016108d64b2735740d42b5a7c57eb420406 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Fri, 5 Feb 2010 18:59:25 -0800 Subject: [PATCH 202/458] Fix 2402303: Split Keyboard widget from LatinIME into reusable PasswordEntryKeyboardView - Added new PasswordEntryKeyboardView to internal/widgets. Widget supports: - alpha mode with symbols (latin-1 only). - a numeric keyboard - IME emulation that applies keyboard input to arbitrary top-level view widget. - Added new transparent assets to framework resources. - Modified Keyguard and Keyguard layouts to use new PasswordEntryKeyboardView. --- .../policy/impl/PasswordUnlockScreen.java | 165 ++++-------------- 1 file changed, 33 insertions(+), 132 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java index 1a250b8aacdd..400668315b80 100644 --- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -20,22 +20,29 @@ import android.content.Context; import com.android.internal.telephony.IccCard.State; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.PasswordEntryKeyboardView; import android.text.Editable; +import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; +import android.view.inputmethod.EditorInfo; import android.widget.Button; +import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; + import com.android.internal.R; +import com.android.internal.widget.PasswordEntryKeyboardHelper; /** * Displays a dialer-like interface or alphanumeric (latin-1) key entry for the user to enter * an unlock password */ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener, - KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.InfoCallback { + KeyguardUpdateMonitor.ConfigurationChangeCallback, OnEditorActionListener { private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; @@ -44,15 +51,11 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen private final boolean mCreatedWithKeyboardOpen; - private TextView mPasswordTextView; - private TextView mOkButton; + private EditText mPasswordEntry; private TextView mEmergencyCallButton; - private View mBackSpaceButton; - private TextView mCarrier; private LockPatternUtils mLockPatternUtils; - private Button mCancelButton; - - private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + private PasswordEntryKeyboardView mKeyboardView; + private PasswordEntryKeyboardHelper mKeyboardHelper; // 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. @@ -70,44 +73,29 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen layoutInflater.inflate(R.layout.keyguard_screen_password_landscape, this, true); } else { layoutInflater.inflate(R.layout.keyguard_screen_password_portrait, this, true); - new TouchInput(); - } - - mPasswordTextView = (TextView) findViewById(R.id.pinDisplay); - mBackSpaceButton = findViewById(R.id.backspace); - mBackSpaceButton.setOnClickListener(this); - - // The cancel button is not used on this screen. - mCancelButton = (Button) findViewById(R.id.cancel); - if (mCancelButton != null) { - mCancelButton.setText(""); } + boolean isAlpha = lockPatternUtils.getPasswordMode() == LockPatternUtils.MODE_PASSWORD; + mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard); + mPasswordEntry = (EditText) findViewById(R.id.passwordEntry); + mPasswordEntry.setOnEditorActionListener(this); mEmergencyCallButton = (TextView) findViewById(R.id.emergencyCall); - mOkButton = (TextView) findViewById(R.id.ok); - - mPasswordTextView.setFocusable(false); - mEmergencyCallButton.setOnClickListener(this); - mOkButton.setOnClickListener(this); - mUpdateMonitor.registerConfigurationChangeCallback(this); - mLockPatternUtils = lockPatternUtils; - mCarrier = (TextView) findViewById(R.id.carrier); - // until we get an update... - mCarrier.setText(LockScreen.getCarrierString(mUpdateMonitor.getTelephonyPlmn(), - mUpdateMonitor.getTelephonySpn())); - updateMonitor.registerInfoCallback(this); - updateMonitor.registerConfigurationChangeCallback(this); + mKeyboardHelper = new PasswordEntryKeyboardHelper(context, mKeyboardView, this); + mKeyboardHelper.setKeyboardMode(isAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA + : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC); + updateMonitor.registerConfigurationChangeCallback(this); setFocusableInTouchMode(true); + mPasswordEntry.requestFocus(); } /** {@inheritDoc} */ public boolean needsInput() { - return true; + return false; } /** {@inheritDoc} */ @@ -118,7 +106,8 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen /** {@inheritDoc} */ public void onResume() { // start fresh - mPasswordTextView.setText(""); + mPasswordEntry.setText(""); + mPasswordEntry.requestFocus(); } /** {@inheritDoc} */ @@ -127,22 +116,14 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen } public void onClick(View v) { - if (v == mBackSpaceButton) { - final Editable digits = mPasswordTextView.getEditableText(); - final int len = digits.length(); - if (len > 0) { - digits.delete(len-1, len); - } - } else if (v == mEmergencyCallButton) { + if (v == mEmergencyCallButton) { mCallback.takeEmergencyCallAction(); - } else if (v == mOkButton) { - verifyPasswordAndUnlock(); } mCallback.pokeWakelock(); } private void verifyPasswordAndUnlock() { - String entry = mPasswordTextView.getText().toString(); + String entry = mPasswordEntry.getText().toString(); if (mLockPatternUtils.checkPassword(entry)) { mCallback.keyguardDone(true); mCallback.reportSuccessfulUnlockAttempt(); @@ -151,37 +132,15 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen // real password. This may require some tweaking. mCallback.reportFailedUnlockAttempt(); } - mPasswordTextView.setText(""); + mPasswordEntry.setText(""); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - return true; - } - - final char match = event.getMatch(DIGITS); - if (match != 0) { - reportDigit(match - '0'); - return true; - } - if (keyCode == KeyEvent.KEYCODE_DEL) { - mPasswordTextView.onKeyDown(keyCode, event); - return true; - } - - if (keyCode == KeyEvent.KEYCODE_ENTER) { - verifyPasswordAndUnlock(); - return true; - } - + mCallback.pokeWakelock(); return false; } - private void reportDigit(int digit) { - mPasswordTextView.append(Integer.toString(digit)); - } - public void onOrientationChange(boolean inPortrait) { } @@ -192,71 +151,13 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen } } - /** - * Helper class to handle input from touch dialer. Only relevant when - * the keyboard is shut. - */ - private class TouchInput implements View.OnClickListener { - private int mDigitIds[] = { R.id.zero, R.id.one, R.id.two, R.id.three, R.id.four, - R.id.five, R.id.six, R.id.seven, R.id.eight, R.id.nine }; - private TextView mCancelButton; - private TouchInput() { - for (int i = 0; i < mDigitIds.length; i++) { - Button button = (Button) findViewById(mDigitIds[i]); - button.setOnClickListener(this); - button.setText(Integer.toString(i)); - } - mCancelButton = (TextView) findViewById(R.id.cancel); - mCancelButton.setOnClickListener(this); - mOkButton = (TextView) findViewById(R.id.ok); - mOkButton.setOnClickListener(this); - } - - public void onClick(View v) { - if (v == mCancelButton) { - return; - } - if (v == mOkButton) { - verifyPasswordAndUnlock(); - } - - final int digit = checkDigit(v); - if (digit >= 0) { - mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS); - reportDigit(digit); - } - } - - private int checkDigit(View v) { - int digit = -1; - for (int i = 0; i < mDigitIds.length; i++) { - if (v.getId() == mDigitIds[i]) { - digit = i; - break; - } - } - return digit; + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + // Check if this was the result of hitting the enter key + if (actionId == EditorInfo.IME_NULL) { + verifyPasswordAndUnlock(); + return true; } + return false; } - /** {@inheritDoc} */ - public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { - mCarrier.setText(LockScreen.getCarrierString(plmn, spn)); - } - - public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { - - } - - public void onRingerModeChanged(int state) { - - } - - public void onTimeChanged() { - - } - - public void onSimStateChanged(State simState) { - - } } -- GitLab From 9d86fafe634415c1b34662250c376e452790e967 Mon Sep 17 00:00:00 2001 From: Adam Powell Date: Wed, 10 Feb 2010 11:39:57 -0800 Subject: [PATCH 203/458] Added haptic feedback support for scroll barriers --- .../android/internal/policy/impl/PhoneWindowManager.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index e9acc2325b57..d50d96c20a60 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -179,6 +179,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Vibrator pattern for haptic feedback during boot when safe mode is enabled. long[] mSafeModeEnabledVibePattern; + // Vibrator pattern for haptic feedback when the user hits a touch scroll barrier. + long[] mScrollBarrierVibePattern; + /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ boolean mEnableShiftMenuBugReports = false; @@ -562,6 +565,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.array.config_safeModeDisabledVibePattern); mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_safeModeEnabledVibePattern); + mScrollBarrierVibePattern = getLongIntArray(mContext.getResources(), + com.android.internal.R.array.config_scrollBarrierVibePattern); } void updatePlugged(Intent powerIntent) { @@ -2316,6 +2321,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { case HapticFeedbackConstants.SAFE_MODE_ENABLED: mVibrator.vibrate(mSafeModeEnabledVibePattern, -1); return true; + case HapticFeedbackConstants.SCROLL_BARRIER: + mVibrator.vibrate(mScrollBarrierVibePattern, -1); + return true; } return false; } -- GitLab From 148e73eaed1fc0c12cdf84f0eb20a24624397a11 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Thu, 11 Feb 2010 15:39:45 -0800 Subject: [PATCH 204/458] Fix 2431663: Ensure password field retains focus in PasswordUnlockScreen. --- .../internal/policy/impl/PasswordUnlockScreen.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java index 400668315b80..560a00059f69 100644 --- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -17,18 +17,15 @@ package com.android.internal.policy.impl; import android.content.Context; +import android.graphics.Rect; -import com.android.internal.telephony.IccCard.State; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.PasswordEntryKeyboardView; -import android.text.Editable; -import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.inputmethod.EditorInfo; -import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; @@ -89,10 +86,15 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC); updateMonitor.registerConfigurationChangeCallback(this); - setFocusableInTouchMode(true); mPasswordEntry.requestFocus(); } + @Override + protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { + // send focus to the password field + return mPasswordEntry.requestFocus(direction, previouslyFocusedRect); + } + /** {@inheritDoc} */ public boolean needsInput() { return false; -- GitLab From d2e6a33cb1b6213bde5a1d62c7c415e954317ef9 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Fri, 12 Feb 2010 12:12:06 -0800 Subject: [PATCH 205/458] Change EndCallBehavior while in UTS test mode. When in UTS test mode this reverts the behavior of the end key as it was in cupcake. When not in UTS test mode the behavior is as before the change. The UTS test mode is enabled when presist.sys.uts-test-mode is 1. Bug: 2402366 Change-Id: I81359f3870a1e4da513f76c32aecdb7dfdf3bacf --- .../policy/impl/PhoneWindowManager.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 7be15e2f0c0d..7970987c6dd8 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -2162,16 +2162,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { // This code brings home to the front or, if it is already // at the front, puts the device to sleep. try { - ActivityManagerNative.getDefault().stopAppSwitches(); - sendCloseSystemWindows(); - Intent dock = createHomeDockIntent(); - if (dock != null) { - int result = ActivityManagerNative.getDefault() - .startActivity(null, dock, - dock.resolveTypeIfNeeded(mContext.getContentResolver()), - null, 0, null, null, 0, true /* onlyIfNeeded*/, false); - if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) { - return false; + if (SystemProperties.getInt("persist.sys.uts-test-mode", 0) == 1) { + /// Roll back EndcallBehavior as the cupcake design to pass P1 lab entry. + Log.d(TAG, "UTS-TEST-MODE"); + } else { + ActivityManagerNative.getDefault().stopAppSwitches(); + sendCloseSystemWindows(); + Intent dock = createHomeDockIntent(); + if (dock != null) { + int result = ActivityManagerNative.getDefault() + .startActivity(null, dock, + dock.resolveTypeIfNeeded(mContext.getContentResolver()), + null, 0, null, null, 0, true /* onlyIfNeeded*/, false); + if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) { + return false; + } } } int result = ActivityManagerNative.getDefault() -- GitLab From c777e071d1f2a1e4118f47e7f34af16fda03a504 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Fri, 12 Feb 2010 13:07:59 -0800 Subject: [PATCH 206/458] Add pointer location to window manager. --- .../policy/impl/PhoneWindowManager.java | 131 +++++++++++++----- 1 file changed, 99 insertions(+), 32 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index d50d96c20a60..99a8f484a1b9 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -31,6 +31,7 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; +import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.BatteryManager; import android.os.Handler; @@ -44,6 +45,7 @@ import android.os.SystemProperties; import android.os.Vibrator; import android.provider.Settings; +import com.android.common.ui.PointerLocationView; import com.android.internal.policy.PolicyManager; import com.android.internal.telephony.ITelephony; import android.util.Config; @@ -197,6 +199,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { final IntentFilter mBatteryStatusFilter = new IntentFilter(); + boolean mSystemReady; boolean mLidOpen; int mPlugged; boolean mRegisteredBatteryReceiver; @@ -217,6 +220,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mAccelerometerDefault = DEFAULT_ACCELEROMETER_ROTATION; boolean mHasSoftInput = false; + int mPointerLocationMode = 0; + PointerLocationView mPointerLocationView = null; + // The current size of the screen. int mW, mH; // During layout, the current screen borders with all outer decoration @@ -283,15 +289,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.System.ACCELEROMETER_ROTATION), false, this); resolver.registerContentObserver(Settings.System.getUriFor( Settings.System.SCREEN_OFF_TIMEOUT), false, this); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.POINTER_LOCATION), false, this); resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.DEFAULT_INPUT_METHOD), false, this); resolver.registerContentObserver(Settings.System.getUriFor( "fancy_rotation_anim"), false, this); - update(); + updateSettings(); } @Override public void onChange(boolean selfChange) { - update(); + updateSettings(); try { mWindowManager.setRotation(USE_LAST_ROTATION, false, mFancyRotationAnimation); @@ -299,36 +307,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Ignore } } - - public void update() { - ContentResolver resolver = mContext.getContentResolver(); - boolean updateRotation = false; - synchronized (mLock) { - mEndcallBehavior = Settings.System.getInt(resolver, - Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); - mFancyRotationAnimation = Settings.System.getInt(resolver, - "fancy_rotation_anim", 0) != 0 ? 0x80 : 0; - int accelerometerDefault = Settings.System.getInt(resolver, - Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); - if (mAccelerometerDefault != accelerometerDefault) { - mAccelerometerDefault = accelerometerDefault; - updateOrientationListenerLp(); - } - // use screen off timeout setting as the timeout for the lockscreen - mLockScreenTimeout = Settings.System.getInt(resolver, - Settings.System.SCREEN_OFF_TIMEOUT, 0); - String imId = Settings.Secure.getString(resolver, - Settings.Secure.DEFAULT_INPUT_METHOD); - boolean hasSoftInput = imId != null && imId.length() > 0; - if (mHasSoftInput != hasSoftInput) { - mHasSoftInput = hasSoftInput; - updateRotation = true; - } - } - if (updateRotation) { - updateRotation(0); - } - } } class MyOrientationListener extends WindowOrientationListener { @@ -569,6 +547,75 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.array.config_scrollBarrierVibePattern); } + public void updateSettings() { + ContentResolver resolver = mContext.getContentResolver(); + boolean updateRotation = false; + View addView = null; + View removeView = null; + synchronized (mLock) { + mEndcallBehavior = Settings.System.getInt(resolver, + Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); + mFancyRotationAnimation = Settings.System.getInt(resolver, + "fancy_rotation_anim", 0) != 0 ? 0x80 : 0; + int accelerometerDefault = Settings.System.getInt(resolver, + Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); + if (mAccelerometerDefault != accelerometerDefault) { + mAccelerometerDefault = accelerometerDefault; + updateOrientationListenerLp(); + } + if (mSystemReady) { + int pointerLocation = Settings.System.getInt(resolver, + Settings.System.POINTER_LOCATION, 0); + if (mPointerLocationMode != pointerLocation) { + mPointerLocationMode = pointerLocation; + if (pointerLocation != 0) { + if (mPointerLocationView == null) { + mPointerLocationView = new PointerLocationView(mContext); + mPointerLocationView.setPrintCoords(false); + addView = mPointerLocationView; + } + } else { + removeView = mPointerLocationView; + mPointerLocationView = null; + } + } + } + // use screen off timeout setting as the timeout for the lockscreen + mLockScreenTimeout = Settings.System.getInt(resolver, + Settings.System.SCREEN_OFF_TIMEOUT, 0); + String imId = Settings.Secure.getString(resolver, + Settings.Secure.DEFAULT_INPUT_METHOD); + boolean hasSoftInput = imId != null && imId.length() > 0; + if (mHasSoftInput != hasSoftInput) { + mHasSoftInput = hasSoftInput; + updateRotation = true; + } + } + if (updateRotation) { + updateRotation(0); + } + if (addView != null) { + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.MATCH_PARENT); + lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; + lp.flags = + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; + lp.format = PixelFormat.TRANSLUCENT; + lp.setTitle("PointerLocation"); + WindowManagerImpl wm = (WindowManagerImpl) + mContext.getSystemService(Context.WINDOW_SERVICE); + wm.addView(addView, lp); + } + if (removeView != null) { + WindowManagerImpl wm = (WindowManagerImpl) + mContext.getSystemService(Context.WINDOW_SERVICE); + wm.removeView(removeView); + } + } + void updatePlugged(Intent powerIntent) { if (localLOGV) Log.v(TAG, "New battery status: " + powerIntent.getExtras()); if (powerIntent != null) { @@ -697,6 +744,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } + public void dispatchedPointerEventLw(MotionEvent ev, int targetX, int targetY) { + if (mPointerLocationView == null) { + return; + } + synchronized (mLock) { + if (mPointerLocationView == null) { + return; + } + ev.offsetLocation(targetX, targetY); + mPointerLocationView.addTouchEvent(ev); + ev.offsetLocation(-targetX, -targetY); + } + } + /** {@inheritDoc} */ public int windowTypeToLayerLw(int type) { if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) { @@ -2111,6 +2172,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { android.os.SystemProperties.set("dev.bootcomplete", "1"); synchronized (mLock) { updateOrientationListenerLp(); + mSystemReady = true; + mHandler.post(new Runnable() { + public void run() { + updateSettings(); + } + }); } } -- GitLab From db783bdff33bbfcf825ec27d1b1af1fe7b3045e3 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Thu, 11 Feb 2010 15:27:37 -0500 Subject: [PATCH 207/458] Support for lockscreen/keyguard sound effects. See sibling change to frameworks/base (including basic lockscreen sounds). Change-Id: I62bb16b90c47353a3ca4a531e7f7d5b446486dde --- .../policy/impl/KeyguardViewMediator.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index b35b3fc3c799..c8e8cd47de08 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -24,9 +24,13 @@ import android.app.AlarmManager; import android.app.PendingIntent; import android.app.StatusBarManager; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; import android.os.Handler; import android.os.IBinder; import android.os.LocalPowerManager; @@ -35,6 +39,7 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; +import android.provider.Settings; import android.telephony.TelephonyManager; import android.util.Config; import android.util.EventLog; @@ -908,6 +913,30 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } } + private void playSounds(boolean locked) { + // User feedback for keyguard. + final ContentResolver cr = mContext.getContentResolver(); + if (Settings.System.getInt(cr, Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1) == 1) + { + final String whichSound = locked + ? Settings.System.LOCK_SOUND + : Settings.System.UNLOCK_SOUND; + final String soundPath = Settings.System.getString(cr, whichSound); + if (soundPath != null) { + final Uri soundUri = Uri.parse("file://" + soundPath); + if (soundUri != null) { + final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); + if (sfx != null) sfx.play(); + else Log.d(TAG, "playSounds: failed to load ringtone from uri: " + soundUri); + } else { + Log.d(TAG, "playSounds: could not parse Uri: " + soundPath); + } + } else { + Log.d(TAG, "playSounds: whichSound = " + whichSound + "; soundPath was null"); + } + } + } + /** * Handle message sent by {@link #showLocked}. * @see #SHOW @@ -917,6 +946,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (DEBUG) Log.d(TAG, "handleShow"); if (!mSystemReady) return; + playSounds(true); + mKeyguardViewManager.show(); mShowing = true; adjustUserActivityLocked(); @@ -941,6 +972,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, return; } + playSounds(false); + mKeyguardViewManager.hide(); mShowing = false; adjustUserActivityLocked(); -- GitLab From c33cb7117e64b93609ceb60d911bad6add09aa09 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Wed, 10 Feb 2010 15:21:49 -0800 Subject: [PATCH 208/458] Add a new KEYBOARD_TAP haptic feedback type for very short, low-latency vibration. The minimum value varies from device to device, so this is useful for defining the shortest and most efficient vibration. The VibratorService creates a Thread when playing back vibration patterns, so this allows you to avoid thread creation and associated scheduling delays by specifying a one-shot duration in the config file. --- .../policy/impl/PhoneWindowManager.java | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 99a8f484a1b9..c879eceefd04 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -175,6 +175,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Vibrator pattern for haptic feedback of virtual key press. long[] mVirtualKeyVibePattern; + // Vibrator pattern for a short vibration. + long[] mKeyboardTapVibePattern; + // Vibrator pattern for haptic feedback during boot when safe mode is disabled. long[] mSafeModeDisabledVibePattern; @@ -539,6 +542,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.array.config_longPressVibePattern); mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_virtualKeyVibePattern); + mKeyboardTapVibePattern = getLongIntArray(mContext.getResources(), + com.android.internal.R.array.config_keyboardTapVibePattern); mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_safeModeDisabledVibePattern); mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), @@ -2368,31 +2373,44 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } - + public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) { final boolean hapticsDisabled = Settings.System.getInt(mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0; if (!always && (hapticsDisabled || mKeyguardMediator.isShowingAndNotHidden())) { return false; } + long[] pattern = null; switch (effectId) { case HapticFeedbackConstants.LONG_PRESS: - mVibrator.vibrate(mLongPressVibePattern, -1); - return true; + pattern = mLongPressVibePattern; + break; case HapticFeedbackConstants.VIRTUAL_KEY: - mVibrator.vibrate(mVirtualKeyVibePattern, -1); - return true; + pattern = mVirtualKeyVibePattern; + break; + case HapticFeedbackConstants.KEYBOARD_TAP: + pattern = mKeyboardTapVibePattern; + break; case HapticFeedbackConstants.SAFE_MODE_DISABLED: - mVibrator.vibrate(mSafeModeDisabledVibePattern, -1); - return true; + pattern = mSafeModeDisabledVibePattern; + break; case HapticFeedbackConstants.SAFE_MODE_ENABLED: - mVibrator.vibrate(mSafeModeEnabledVibePattern, -1); - return true; + pattern = mSafeModeEnabledVibePattern; + break; case HapticFeedbackConstants.SCROLL_BARRIER: - mVibrator.vibrate(mScrollBarrierVibePattern, -1); - return true; + pattern = mScrollBarrierVibePattern; + break; + default: + return false; } - return false; + if (pattern.length == 1) { + // One-shot vibration + mVibrator.vibrate(pattern[0]); + } else { + // Pattern vibration + mVibrator.vibrate(pattern, -1); + } + return true; } public void keyFeedbackFromInput(KeyEvent event) { -- GitLab From 42b432d84cd3bf860a03a10e9191738e05f2eadd Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Fri, 12 Feb 2010 18:56:03 -0800 Subject: [PATCH 209/458] Partial Fix for 2416967: Fix potential memory leak in PasswordUnlockScreen. PasswordUnlockScreen was previously registering for multiple callbacks which *sometimes* caused a memory leak because a reference stuck around in the callback list. I wasn't able to track down the cause, but it looks like an interaction between switching between various lockscreen modes and ordering of CONFIGURATION_CHANGED events. I found one instance where the callback was being registered twice (fixed). However, I'm still able to reproduce the bug but far less frequently. As a workaround, I've added code to prevent adding additional callbacks and added logging to detect when a callback is already registered. Also fixed an instance where we'd recreate the password unlock screen in LockPatternKeyguardView.updateScreen() so it should be quite a bit faster switching orientations now. Renamed UnlockScreen.java to PatternUnlockScreen.java for consistency. --- .../policy/impl/KeyguardUpdateMonitor.java | 18 +++++++++++++++--- .../policy/impl/LockPatternKeyguardView.java | 10 ++++------ .../policy/impl/PasswordUnlockScreen.java | 16 ++++++++-------- ...ockScreen.java => PatternUnlockScreen.java} | 4 ++-- 4 files changed, 29 insertions(+), 19 deletions(-) rename policy/com/android/internal/policy/impl/{UnlockScreen.java => PatternUnlockScreen.java} (99%) diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 3483405fb96a..9729edabce89 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -492,7 +492,11 @@ public class KeyguardUpdateMonitor { * @param callback The callback. */ public void registerConfigurationChangeCallback(ConfigurationChangeCallback callback) { - mConfigurationChangeCallbacks.add(callback); + if (!mConfigurationChangeCallbacks.contains(callback)) { + mConfigurationChangeCallbacks.add(callback); + } else { + Log.e(TAG, "Object tried to add another CONFIG callback", new Exception("Whoops")); + } } /** @@ -501,7 +505,11 @@ public class KeyguardUpdateMonitor { * @param callback The callback. */ public void registerInfoCallback(InfoCallback callback) { - mInfoCallbacks.add(callback); + if (!mInfoCallbacks.contains(callback)) { + mInfoCallbacks.add(callback); + } else { + Log.e(TAG, "Object tried to add another INFO callback", new Exception("Whoops")); + } } /** @@ -509,7 +517,11 @@ public class KeyguardUpdateMonitor { * @param callback The callback. */ public void registerSimStateCallback(SimStateCallback callback) { - mSimStateCallbacks.add(callback); + if (!mSimStateCallbacks.contains(callback)) { + mSimStateCallbacks.add(callback); + } else { + Log.e(TAG, "Object tried to add another SIM callback", new Exception("Whoops")); + } } public IccCard.State getSimState() { diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index a7fc6b66e2c4..cdac278be6cc 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -173,8 +173,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase if (mUnlockScreen == null) { Log.w(TAG, "no unlock screen when receiving AccountManager information"); - } else if (mUnlockScreen instanceof UnlockScreen) { - ((UnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback); + } else if (mUnlockScreen instanceof PatternUnlockScreen) { + ((PatternUnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback); } } @@ -411,7 +411,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase } } - private void recreateScreens() { if (mLockScreen.getVisibility() == View.VISIBLE) { ((KeyguardScreen) mLockScreen).onPause(); @@ -504,8 +503,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase mMode = mode; final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen; - final View visibleScreen = (mode == Mode.LockScreen) - ? mLockScreen : getUnlockScreenForCurrentUnlockMode(); + final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen; // do this before changing visibility so focus isn't requested before the input // flag is set @@ -544,7 +542,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase mIsPortrait = getResources().getBoolean(R.bool.lockscreen_isPortrait); if (unlockMode == UnlockMode.Pattern) { - UnlockScreen view = new UnlockScreen( + PatternUnlockScreen view = new PatternUnlockScreen( mContext, mLockPatternUtils, mUpdateMonitor, diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java index 560a00059f69..9094ed68a3db 100644 --- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -53,6 +53,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen private LockPatternUtils mLockPatternUtils; private PasswordEntryKeyboardView mKeyboardView; private PasswordEntryKeyboardHelper mKeyboardHelper; + private boolean mIsInPortrait; // To avoid accidental lockout due to events while the device in in the pocket, ignore // any passwords with length less than or equal to this length. @@ -66,10 +67,10 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mCreatedWithKeyboardOpen = mUpdateMonitor.isKeyboardOpen(); LayoutInflater layoutInflater = LayoutInflater.from(context); - if (mCreatedWithKeyboardOpen) { - layoutInflater.inflate(R.layout.keyguard_screen_password_landscape, this, true); - } else { + if (mUpdateMonitor.isInPortrait()) { layoutInflater.inflate(R.layout.keyguard_screen_password_portrait, this, true); + } else { + layoutInflater.inflate(R.layout.keyguard_screen_password_landscape, this, true); } boolean isAlpha = lockPatternUtils.getPasswordMode() == LockPatternUtils.MODE_PASSWORD; @@ -85,7 +86,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mKeyboardHelper.setKeyboardMode(isAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC); - updateMonitor.registerConfigurationChangeCallback(this); + mKeyboardView.setVisibility(mCreatedWithKeyboardOpen ? View.INVISIBLE : View.VISIBLE); mPasswordEntry.requestFocus(); } @@ -144,13 +145,12 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen } public void onOrientationChange(boolean inPortrait) { - + mCallback.recreateMe(); } public void onKeyboardChange(boolean isKeyboardOpen) { - if (isKeyboardOpen != mCreatedWithKeyboardOpen) { - mCallback.recreateMe(); - } + // Don't show the soft keyboard when the real keyboard is open + mKeyboardView.setVisibility(isKeyboardOpen ? View.INVISIBLE : View.VISIBLE); } public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/PatternUnlockScreen.java similarity index 99% rename from policy/com/android/internal/policy/impl/UnlockScreen.java rename to policy/com/android/internal/policy/impl/PatternUnlockScreen.java index f2a2c95c8625..2e3aa84b49f3 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PatternUnlockScreen.java @@ -42,7 +42,7 @@ import java.util.Date; * This is the screen that shows the 9 circle unlock widget and instructs * the user how to unlock their device, or make an emergency call. */ -class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient +class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback { @@ -160,7 +160,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient * their pattern (e.g they have a google account so we can show them the account based * backup option). */ - UnlockScreen(Context context, + PatternUnlockScreen(Context context, LockPatternUtils lockPatternUtils, KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback, -- GitLab From f129859ee83fb1cce8a0549e216d57b5ddd602be Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Thu, 18 Feb 2010 11:42:36 -0500 Subject: [PATCH 210/458] Suppress screen lock sound effect on first boot. Bug: 2453032 --- .../android/internal/policy/impl/KeyguardViewMediator.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index c8e8cd47de08..f82d1a906487 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -147,6 +147,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private IBinder mSecureLockIcon = null; private boolean mSystemReady; + private boolean mFirstShow = true; /** Low level access to the power manager for enableUserActivity. Having this * requires that we run in the system process. */ @@ -946,7 +947,11 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (DEBUG) Log.d(TAG, "handleShow"); if (!mSystemReady) return; - playSounds(true); + if (mFirstShow) { + mFirstShow = false; + } else { + playSounds(true); + } mKeyguardViewManager.show(); mShowing = true; -- GitLab From 966b126ea7f24ae16c6a2aa683072bfd2cae8158 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Thu, 18 Feb 2010 19:55:29 -0800 Subject: [PATCH 211/458] Fix 2448345: Fix tactile feedback bug in password/PIN and pattern unlock. --- .../android/internal/policy/impl/PasswordUnlockScreen.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java index 9094ed68a3db..841c2e4d7d58 100644 --- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -53,7 +53,6 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen private LockPatternUtils mLockPatternUtils; private PasswordEntryKeyboardView mKeyboardView; private PasswordEntryKeyboardHelper mKeyboardHelper; - private boolean mIsInPortrait; // To avoid accidental lockout due to events while the device in in the pocket, ignore // any passwords with length less than or equal to this length. @@ -88,6 +87,9 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mKeyboardView.setVisibility(mCreatedWithKeyboardOpen ? View.INVISIBLE : View.VISIBLE); mPasswordEntry.requestFocus(); + + mKeyboardHelper.setVibratePattern(mLockPatternUtils.isTactileFeedbackEnabled() ? + com.android.internal.R.array.config_virtualKeyVibePattern : 0); } @Override -- GitLab From f123ec8f7d449b2e079ea8d5d7e431ff83235f56 Mon Sep 17 00:00:00 2001 From: Magnus Landqvist Date: Fri, 19 Feb 2010 12:06:59 +0100 Subject: [PATCH 212/458] Build software AGL library with correct get_tls() macro for ARMv7 based platforms This prevents crashes on snapdragon processors. --- opengl/libagl/Android.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk index 983784554d30..518be8b5322e 100644 --- a/opengl/libagl/Android.mk +++ b/opengl/libagl/Android.mk @@ -37,6 +37,10 @@ ifeq ($(TARGET_ARCH),arm) LOCAL_CFLAGS += -fstrict-aliasing endif +ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true) + LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER +endif + ifneq ($(TARGET_SIMULATOR),true) # we need to access the private Bionic header LOCAL_C_INCLUDES += bionic/libc/private -- GitLab From f2d8e74c0230f53acdc6f94652961e4adb0e134a Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Mon, 22 Feb 2010 13:09:48 -0500 Subject: [PATCH 213/458] Suppress unlock noises while in-call. Bug: 2458106 --- .../policy/impl/KeyguardViewMediator.java | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index f82d1a906487..1a2898fda939 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -225,6 +225,9 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private boolean mScreenOn = false; + // last known state of the cellular connection + private String mPhoneState = TelephonyManager.EXTRA_STATE_IDLE; + /** * we send this intent when the keyguard is dismissed. */ @@ -683,19 +686,21 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (mDelayedShowingSequence == sequence) { doKeyguard(); } - } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action) - && TelephonyManager.EXTRA_STATE_IDLE.equals(intent.getStringExtra( - TelephonyManager.EXTRA_STATE)) // call ending - && !mScreenOn // screen off - && mExternallyEnabled) { // not disabled by any app - - // note: this is a way to gracefully reenable the keyguard when the call - // ends and the screen is off without always reenabling the keyguard - // each time the screen turns off while in call (and having an occasional ugly - // flicker while turning back on the screen and disabling the keyguard again). - if (DEBUG) Log.d(TAG, "screen is off and call ended, let's make sure the " - + "keyguard is showing"); - doKeyguard(); + } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { + mPhoneState = intent.getStringExtra(TelephonyManager.EXTRA_STATE); + + if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState) // call ending + && !mScreenOn // screen off + && mExternallyEnabled) { // not disabled by any app + + // note: this is a way to gracefully reenable the keyguard when the call + // ends and the screen is off without always reenabling the keyguard + // each time the screen turns off while in call (and having an occasional ugly + // flicker while turning back on the screen and disabling the keyguard again). + if (DEBUG) Log.d(TAG, "screen is off and call ended, let's make sure the " + + "keyguard is showing"); + doKeyguard(); + } } } }; @@ -977,7 +982,11 @@ public class KeyguardViewMediator implements KeyguardViewCallback, return; } - playSounds(false); + // only play "unlock" noises if not on a call (since the incall UI + // disables the keyguard) + if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) { + playSounds(false); + } mKeyguardViewManager.hide(); mShowing = false; -- GitLab From aec967acabfdc8eb6311ee787c6ed5a3b7fa4203 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Sat, 20 Feb 2010 01:05:22 -0500 Subject: [PATCH 214/458] Move lockscreen sound effects to the system stream. Bug: 2458106, 2451532 Change-Id: I01869e3fd461dc24aa3157bf38aba9d2967526ec --- .../internal/policy/impl/KeyguardViewMediator.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 1a2898fda939..526dcbc66d1c 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -28,6 +28,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; @@ -932,8 +933,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, final Uri soundUri = Uri.parse("file://" + soundPath); if (soundUri != null) { final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); - if (sfx != null) sfx.play(); - else Log.d(TAG, "playSounds: failed to load ringtone from uri: " + soundUri); + if (sfx != null) { + sfx.setStreamType(AudioManager.STREAM_SYSTEM); + sfx.play(); + } else { + Log.d(TAG, "playSounds: failed to load ringtone from uri: " + soundUri); + } } else { Log.d(TAG, "playSounds: could not parse Uri: " + soundPath); } -- GitLab From 0c33ed2992b2eb484c229fd3322df14d97c10caa Mon Sep 17 00:00:00 2001 From: Devin Taylor Date: Tue, 23 Feb 2010 13:26:46 -0600 Subject: [PATCH 215/458] Fix Memory Leak When Switching Input Methods Fixes a memory leak when input methods are switched. Uses a variety of methods to avoid holding a reference to the InputMethodService which created the binders, which was leaking those InputMethodServices. See http://code.google.com/p/android/issues/detail?id=6661 for reproduction steps. --- .../IInputMethodSessionWrapper.java | 15 ++++-- .../IInputMethodWrapper.java | 52 ++++++++++++------- .../internal/view/IInputMethodSession.aidl | 2 + .../server/InputMethodManagerService.java | 14 +++++ 4 files changed, 62 insertions(+), 21 deletions(-) diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java index 6cf90d673579..7ee35c070c17 100644 --- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java @@ -31,9 +31,10 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub private static final int DO_UPDATE_CURSOR = 95; private static final int DO_APP_PRIVATE_COMMAND = 100; private static final int DO_TOGGLE_SOFT_INPUT = 105; - - final HandlerCaller mCaller; - final InputMethodSession mInputMethodSession; + private static final int DO_FINISH_SESSION = 110; + + HandlerCaller mCaller; + InputMethodSession mInputMethodSession; // NOTE: we should have a cache of these. static class InputMethodEventCallbackWrapper implements InputMethodSession.EventCallback { @@ -111,6 +112,10 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub mInputMethodSession.toggleSoftInput(msg.arg1, msg.arg2); return; } + case DO_FINISH_SESSION: { + mInputMethodSession = null; + return; + } } Log.w(TAG, "Unhandled message code: " + msg.what); } @@ -158,4 +163,8 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub public void toggleSoftInput(int showFlags, int hideFlags) { mCaller.executeOrSendMessage(mCaller.obtainMessageII(DO_TOGGLE_SOFT_INPUT, showFlags, hideFlags)); } + + public void finishSession() { + mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_SESSION)); + } } diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java index 20a05a5aea42..74ce71ab7da7 100644 --- a/core/java/android/inputmethodservice/IInputMethodWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java @@ -23,6 +23,7 @@ import android.view.inputmethod.InputMethodSession; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.lang.ref.WeakReference; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -48,9 +49,9 @@ class IInputMethodWrapper extends IInputMethod.Stub private static final int DO_SHOW_SOFT_INPUT = 60; private static final int DO_HIDE_SOFT_INPUT = 70; - final AbstractInputMethodService mTarget; + final WeakReference mTarget; final HandlerCaller mCaller; - final InputMethod mInputMethod; + final WeakReference mInputMethod; static class Notifier { boolean notified; @@ -80,21 +81,32 @@ class IInputMethodWrapper extends IInputMethod.Stub public IInputMethodWrapper(AbstractInputMethodService context, InputMethod inputMethod) { - mTarget = context; - mCaller = new HandlerCaller(context, this); - mInputMethod = inputMethod; + mTarget = new WeakReference(context); + mCaller = new HandlerCaller(context.getApplicationContext(), this); + mInputMethod = new WeakReference(inputMethod); } public InputMethod getInternalInputMethod() { - return mInputMethod; + return mInputMethod.get(); } public void executeMessage(Message msg) { + InputMethod inputMethod = mInputMethod.get(); + // Need a valid reference to the inputMethod for everything except a dump. + if (inputMethod == null && msg.what != DO_DUMP) { + Log.w(TAG, "Input method reference was null, ignoring message: " + msg.what); + return; + } + switch (msg.what) { case DO_DUMP: { + AbstractInputMethodService target = mTarget.get(); + if (target == null) { + return; + } HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj; try { - mTarget.dump((FileDescriptor)args.arg1, + target.dump((FileDescriptor)args.arg1, (PrintWriter)args.arg2, (String[])args.arg3); } catch (RuntimeException e) { ((PrintWriter)args.arg2).println("Exception: " + e); @@ -106,22 +118,22 @@ class IInputMethodWrapper extends IInputMethod.Stub } case DO_ATTACH_TOKEN: { - mInputMethod.attachToken((IBinder)msg.obj); + inputMethod.attachToken((IBinder)msg.obj); return; } case DO_SET_INPUT_CONTEXT: { - mInputMethod.bindInput((InputBinding)msg.obj); + inputMethod.bindInput((InputBinding)msg.obj); return; } case DO_UNSET_INPUT_CONTEXT: - mInputMethod.unbindInput(); + inputMethod.unbindInput(); return; case DO_START_INPUT: { HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj; IInputContext inputContext = (IInputContext)args.arg1; InputConnection ic = inputContext != null ? new InputConnectionWrapper(inputContext) : null; - mInputMethod.startInput(ic, (EditorInfo)args.arg2); + inputMethod.startInput(ic, (EditorInfo)args.arg2); return; } case DO_RESTART_INPUT: { @@ -129,33 +141,37 @@ class IInputMethodWrapper extends IInputMethod.Stub IInputContext inputContext = (IInputContext)args.arg1; InputConnection ic = inputContext != null ? new InputConnectionWrapper(inputContext) : null; - mInputMethod.restartInput(ic, (EditorInfo)args.arg2); + inputMethod.restartInput(ic, (EditorInfo)args.arg2); return; } case DO_CREATE_SESSION: { - mInputMethod.createSession(new InputMethodSessionCallbackWrapper( + inputMethod.createSession(new InputMethodSessionCallbackWrapper( mCaller.mContext, (IInputMethodCallback)msg.obj)); return; } case DO_SET_SESSION_ENABLED: - mInputMethod.setSessionEnabled((InputMethodSession)msg.obj, + inputMethod.setSessionEnabled((InputMethodSession)msg.obj, msg.arg1 != 0); return; case DO_REVOKE_SESSION: - mInputMethod.revokeSession((InputMethodSession)msg.obj); + inputMethod.revokeSession((InputMethodSession)msg.obj); return; case DO_SHOW_SOFT_INPUT: - mInputMethod.showSoftInput(msg.arg1, (ResultReceiver)msg.obj); + inputMethod.showSoftInput(msg.arg1, (ResultReceiver)msg.obj); return; case DO_HIDE_SOFT_INPUT: - mInputMethod.hideSoftInput(msg.arg1, (ResultReceiver)msg.obj); + inputMethod.hideSoftInput(msg.arg1, (ResultReceiver)msg.obj); return; } Log.w(TAG, "Unhandled message code: " + msg.what); } @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { - if (mTarget.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + AbstractInputMethodService target = mTarget.get(); + if (target == null) { + return; + } + if (target.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { fout.println("Permission Denial: can't dump InputMethodManager from from pid=" diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl index a05ff14bcccd..338dcaa7db96 100644 --- a/core/java/com/android/internal/view/IInputMethodSession.aidl +++ b/core/java/com/android/internal/view/IInputMethodSession.aidl @@ -48,4 +48,6 @@ oneway interface IInputMethodSession { void appPrivateCommand(String action, in Bundle data); void toggleSoftInput(int showFlags, int hideFlags); + + void finishSession(); } diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index e2e0ba9cc0b9..afcba4764d06 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -855,12 +855,26 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + private void finishSession(SessionState sessionState) { + if (sessionState != null && sessionState.session != null) { + try { + sessionState.session.finishSession(); + } catch (RemoteException e) { + Log.w(TAG, "Session failed to close due to remote exception", e); + } + } + } + void clearCurMethodLocked() { if (mCurMethod != null) { for (ClientState cs : mClients.values()) { cs.sessionRequested = false; + finishSession(cs.curSession); cs.curSession = null; } + + finishSession(mEnabledSession); + mEnabledSession = null; mCurMethod = null; } mStatusBar.setIconVisibility(mInputMethodIcon, false); -- GitLab From 746c4c44645e022ee9b49acbb4a1bde3c95a7a45 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 24 Feb 2010 20:03:34 -0800 Subject: [PATCH 216/458] Update to reflect android-common no longer in framework. --- policy/Android.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/policy/Android.mk b/policy/Android.mk index 29f62b872306..c56f3538cd90 100644 --- a/policy/Android.mk +++ b/policy/Android.mk @@ -6,6 +6,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ $(call all-subdir-java-files) + +LOCAL_STATIC_JAVA_LIBRARIES += android-common LOCAL_MODULE := android.policy_phone LOCAL_UNINSTALLABLE_MODULE := true -- GitLab From c23024d32779b170dde32a50fbdd945ce521b874 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Wed, 24 Feb 2010 15:37:00 -0800 Subject: [PATCH 217/458] Fix 2336057: Provide a way for the user to return to a call from LockScreen. This makes the "Emergency call" button dual-purpose. If there's a call in progress, the button will show "Return to call" and take them back to the call. --- .../policy/impl/AccountUnlockScreen.java | 25 +++++++++- .../policy/impl/KeyguardUpdateMonitor.java | 25 ++++++++++ .../policy/impl/LockPatternKeyguardView.java | 47 +++++++------------ .../internal/policy/impl/LockScreen.java | 10 ++++ .../policy/impl/PasswordUnlockScreen.java | 34 ++++++++++++-- .../policy/impl/PatternUnlockScreen.java | 29 +++++++++--- .../internal/policy/impl/SimUnlockScreen.java | 40 +++++++++++++--- 7 files changed, 161 insertions(+), 49 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index 26419dda87a2..1aaef8392472 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -28,6 +28,7 @@ import android.accounts.AccountManagerCallback; import android.content.Context; import android.content.Intent; import android.graphics.Rect; +import android.telephony.TelephonyManager; import android.text.Editable; import android.text.InputFilter; import android.text.LoginFilter; @@ -51,7 +52,7 @@ import java.io.IOException; * account's login/password to unlock the phone (and reset their lock pattern). */ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen, - View.OnClickListener, TextWatcher { + KeyguardUpdateMonitor.InfoCallback,View.OnClickListener, TextWatcher { private static final String LOCK_PATTERN_PACKAGE = "com.android.settings"; private static final String LOCK_PATTERN_CLASS = "com.android.settings.ChooseLockPattern"; @@ -108,6 +109,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree mEmergencyCall = (Button) findViewById(R.id.emergencyCall); mEmergencyCall.setOnClickListener(this); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCall); } public void afterTextChanged(Editable s) { @@ -143,6 +145,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree mLogin.setText(""); mPassword.setText(""); mLogin.requestFocus(); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCall); } /** {@inheritDoc} */ @@ -314,4 +317,24 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree } return mCheckingDialog; } + + public void onPhoneStateChanged(String newState) { + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCall); + } + + public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + + } + + public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + + } + + public void onRingerModeChanged(int state) { + + } + + public void onTimeChanged() { + + } } diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 9729edabce89..b7187a48a8ef 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -38,6 +38,8 @@ import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.TelephonyIntents; + +import android.telephony.TelephonyManager; import android.util.Log; import com.android.internal.R; import com.google.android.collect.Lists; @@ -96,6 +98,7 @@ public class KeyguardUpdateMonitor { private static final int MSG_CARRIER_INFO_UPDATE = 303; private static final int MSG_SIM_STATE_CHANGE = 304; private static final int MSG_RINGER_MODE_CHANGED = 305; + private static final int MSG_PHONE_STATE_CHANGED = 306; /** @@ -165,6 +168,9 @@ public class KeyguardUpdateMonitor { case MSG_RINGER_MODE_CHANGED: handleRingerModeChange(msg.arg1); break; + case MSG_PHONE_STATE_CHANGED: + handlePhoneStateChanged((String)msg.obj); + break; } } }; @@ -221,6 +227,7 @@ public class KeyguardUpdateMonitor { filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); filter.addAction(SPN_STRINGS_UPDATED_ACTION); filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); context.registerReceiver(new BroadcastReceiver() { @@ -255,11 +262,21 @@ public class KeyguardUpdateMonitor { } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) { mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED, intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0)); + } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { + String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); + mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state)); } } }, filter); } + protected void handlePhoneStateChanged(String newState) { + if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")"); + for (int i = 0; i < mInfoCallbacks.size(); i++) { + mInfoCallbacks.get(i).onPhoneStateChanged(newState); + } + } + protected void handleRingerModeChange(int mode) { if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")"); for (int i = 0; i < mInfoCallbacks.size(); i++) { @@ -478,6 +495,14 @@ public class KeyguardUpdateMonitor { * {@link AudioManager#RINGER_MODE_CHANGED_ACTION} */ void onRingerModeChanged(int state); + + /** + * Called when the phone state changes. String will be one of: + * {@link TelephonyManager#EXTRA_STATE_IDLE} + * {@link TelephonyManager@EXTRA_STATE_RINGING} + * {@link TelephonyManager#EXTRA_STATE_OFFHOOK + */ + void onPhoneStateChanged(String newState); } /** diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index cdac278be6cc..48abe63819f3 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -37,6 +37,7 @@ import android.graphics.PixelFormat; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.SystemProperties; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; @@ -60,6 +61,9 @@ import java.io.IOException; public class LockPatternKeyguardView extends KeyguardViewBase implements AccountManagerCallback { + // time after launching EmergencyDialer before the screen goes blank. + private static final int EMERGENCY_CALL_TIMEOUT = 10000; + // intent action for launching emergency dialer activity. static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL"; @@ -251,10 +255,16 @@ public class LockPatternKeyguardView extends KeyguardViewBase } public void takeEmergencyCallAction() { - Intent intent = new Intent(ACTION_EMERGENCY_DIAL); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - getContext().startActivity(intent); + pokeWakelock(EMERGENCY_CALL_TIMEOUT); + if (TelephonyManager.getDefault().getCallState() + == TelephonyManager.CALL_STATE_OFFHOOK) { + mLockPatternUtils.resumeCall(); + } else { + Intent intent = new Intent(ACTION_EMERGENCY_DIAL); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + getContext().startActivity(intent); + } } public void pokeWakelock() { @@ -556,7 +566,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase return new SimUnlockScreen( mContext, mUpdateMonitor, - mKeyguardScreenCallback); + mKeyguardScreenCallback, + mLockPatternUtils); } else if (unlockMode == UnlockMode.Account) { try { return new AccountUnlockScreen( @@ -589,32 +600,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase } } - private View getUnlockScreenForCurrentUnlockMode() { - final UnlockMode unlockMode = getUnlockMode(); - - // if a screen exists for the correct mode, we're done - if (unlockMode == mUnlockScreenMode) { - return mUnlockScreen; - } - - // remember the mode - mUnlockScreenMode = unlockMode; - - // unlock mode has changed and we have an existing old unlock screen - // to clean up - if (mScreenOn && (mUnlockScreen.getVisibility() == View.VISIBLE)) { - ((KeyguardScreen) mUnlockScreen).onPause(); - } - ((KeyguardScreen) mUnlockScreen).cleanUp(); - removeViewInLayout(mUnlockScreen); - - // create the new one - mUnlockScreen = createUnlockScreenFor(unlockMode); - mUnlockScreen.setVisibility(View.INVISIBLE); - addView(mUnlockScreen); - return mUnlockScreen; - } - /** * Given the current state of things, what should be the initial mode of * the lock screen (lock or unlock). diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index ba6b3b31756a..772481637202 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -18,12 +18,15 @@ package com.android.internal.policy.impl; import com.android.internal.R; import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.Phone.State; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.SlidingTab; import android.content.Context; import android.content.res.Resources; import android.content.res.ColorStateList; +import android.telephony.TelephonyManager; import android.text.format.DateFormat; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -190,6 +193,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); mEmergencyCallButton.setText(R.string.lockscreen_emergency_call); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); mScreenLocked = (TextView) findViewById(R.id.screenLocked); mSelector = (SlidingTab) findViewById(R.id.tab_selector); mSelector.setHoldAfterTrigger(true, false); @@ -248,6 +252,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM refreshBatteryStringAndIcon(); refreshAlarmDisplay(); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); mTimeFormat = DateFormat.getTimeFormat(getContext()); mDateFormatString = getContext().getString(R.string.full_wday_month_day_no_year); @@ -610,6 +615,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM /** {@inheritDoc} */ public void onResume() { resetStatusInfo(mUpdateMonitor); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); } /** {@inheritDoc} */ @@ -625,4 +631,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM updateRightTabResources(); } } + + public void onPhoneStateChanged(String newState) { + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); + } } diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java index 841c2e4d7d58..a721c470e272 100644 --- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -22,10 +22,12 @@ import android.graphics.Rect; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.PasswordEntryKeyboardView; +import android.telephony.TelephonyManager; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.inputmethod.EditorInfo; +import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; @@ -39,7 +41,8 @@ import com.android.internal.widget.PasswordEntryKeyboardHelper; * an unlock password */ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener, - KeyguardUpdateMonitor.ConfigurationChangeCallback, OnEditorActionListener { + KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.InfoCallback, + OnEditorActionListener { private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; @@ -49,7 +52,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen private final boolean mCreatedWithKeyboardOpen; private EditText mPasswordEntry; - private TextView mEmergencyCallButton; + private Button mEmergencyCallButton; private LockPatternUtils mLockPatternUtils; private PasswordEntryKeyboardView mKeyboardView; private PasswordEntryKeyboardHelper mKeyboardHelper; @@ -64,6 +67,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mUpdateMonitor = updateMonitor; mCallback = callback; mCreatedWithKeyboardOpen = mUpdateMonitor.isKeyboardOpen(); + mLockPatternUtils = lockPatternUtils; LayoutInflater layoutInflater = LayoutInflater.from(context); if (mUpdateMonitor.isInPortrait()) { @@ -76,10 +80,10 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard); mPasswordEntry = (EditText) findViewById(R.id.passwordEntry); mPasswordEntry.setOnEditorActionListener(this); - mEmergencyCallButton = (TextView) findViewById(R.id.emergencyCall); + mEmergencyCallButton = (Button) findViewById(R.id.emergencyCall); mEmergencyCallButton.setOnClickListener(this); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); mUpdateMonitor.registerConfigurationChangeCallback(this); - mLockPatternUtils = lockPatternUtils; mKeyboardHelper = new PasswordEntryKeyboardHelper(context, mKeyboardView, this); mKeyboardHelper.setKeyboardMode(isAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA @@ -90,6 +94,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mKeyboardHelper.setVibratePattern(mLockPatternUtils.isTactileFeedbackEnabled() ? com.android.internal.R.array.config_virtualKeyVibePattern : 0); + } @Override @@ -113,6 +118,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen // start fresh mPasswordEntry.setText(""); mPasswordEntry.requestFocus(); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); } /** {@inheritDoc} */ @@ -164,4 +170,24 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen return false; } + public void onPhoneStateChanged(String newState) { + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); + } + + public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + + } + + public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + + } + + public void onRingerModeChanged(int state) { + + } + + public void onTimeChanged() { + + } + } diff --git a/policy/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/com/android/internal/policy/impl/PatternUnlockScreen.java index 2e3aa84b49f3..30fb8b8fb80a 100644 --- a/policy/com/android/internal/policy/impl/PatternUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PatternUnlockScreen.java @@ -25,6 +25,7 @@ import android.view.ViewGroup; import android.view.MotionEvent; import android.widget.Button; import android.widget.TextView; +import android.telephony.TelephonyManager; import android.text.format.DateFormat; import android.text.TextUtils; import android.util.Log; @@ -126,6 +127,8 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient }; private Button mForgotPatternButton; + private Button mEmergencyAlone; + private Button mEmergencyTogether; enum FooterMode { Normal, @@ -205,16 +208,17 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient // emergency call buttons final OnClickListener emergencyClick = new OnClickListener() { public void onClick(View v) { - mCallback.pokeWakelock(); mCallback.takeEmergencyCallAction(); } }; - Button emergencyAlone = (Button) findViewById(R.id.emergencyCallAlone); - emergencyAlone.setFocusable(false); // touch only! - emergencyAlone.setOnClickListener(emergencyClick); - Button emergencyTogether = (Button) findViewById(R.id.emergencyCallTogether); - emergencyTogether.setFocusable(false); - emergencyTogether.setOnClickListener(emergencyClick); + + mEmergencyAlone = (Button) findViewById(R.id.emergencyCallAlone); + mEmergencyAlone.setFocusable(false); // touch only! + mEmergencyAlone.setOnClickListener(emergencyClick); + mEmergencyTogether = (Button) findViewById(R.id.emergencyCallTogether); + mEmergencyTogether.setFocusable(false); + mEmergencyTogether.setOnClickListener(emergencyClick); + refreshEmergencyButtonText(); mForgotPatternButton = (Button) findViewById(R.id.forgotPattern); mForgotPatternButton.setText(R.string.lockscreen_forgot_pattern_button_text); @@ -259,6 +263,11 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient mUpdateMonitor.getTelephonySpn())); } + private void refreshEmergencyButtonText() { + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyAlone); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyTogether); + } + public void setEnableFallback(boolean state) { if (DEBUG) Log.d(TAG, "setEnableFallback(" + state + ")"); mEnableFallback = state; @@ -447,6 +456,8 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient } else { updateFooter(FooterMode.Normal); } + + refreshEmergencyButtonText(); } /** {@inheritDoc} */ @@ -549,4 +560,8 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient } }.start(); } + + public void onPhoneStateChanged(String newState) { + refreshEmergencyButtonText(); + } } diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java index 8c738a7e7bda..d5da274d5fb8 100644 --- a/policy/com/android/internal/policy/impl/SimUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/SimUnlockScreen.java @@ -22,11 +22,14 @@ import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; import com.android.internal.telephony.ITelephony; +import com.android.internal.widget.LockPatternUtils; + import android.text.Editable; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; +import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import com.android.internal.R; @@ -35,7 +38,7 @@ import com.android.internal.R; * Displays a dialer like interface to unlock the SIM PIN. */ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener, - KeyguardUpdateMonitor.ConfigurationChangeCallback { + KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.InfoCallback { private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; @@ -48,7 +51,7 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie private TextView mPinText; private TextView mOkButton; - private TextView mEmergencyCallButton; + private Button mEmergencyCallButton; private View mBackSpaceButton; @@ -57,14 +60,17 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie private ProgressDialog mSimUnlockProgressDialog = null; + private LockPatternUtils mLockPatternUtils; + private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; public SimUnlockScreen(Context context, KeyguardUpdateMonitor updateMonitor, - KeyguardScreenCallback callback) { + KeyguardScreenCallback callback, LockPatternUtils lockpatternutils) { super(context); mUpdateMonitor = updateMonitor; mCallback = callback; mCreatedWithKeyboardOpen = mUpdateMonitor.isKeyboardOpen(); + mLockPatternUtils = lockpatternutils; if (mCreatedWithKeyboardOpen) { LayoutInflater.from(context).inflate(R.layout.keyguard_screen_sim_pin_landscape, this, true); @@ -78,7 +84,8 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie mBackSpaceButton = findViewById(R.id.backspace); mBackSpaceButton.setOnClickListener(this); - mEmergencyCallButton = (TextView) findViewById(R.id.emergencyCall); + mEmergencyCallButton = (Button) findViewById(R.id.emergencyCall); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); mOkButton = (TextView) findViewById(R.id.ok); mHeaderText.setText(R.string.keyguard_password_enter_pin_code); @@ -95,7 +102,7 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie public boolean needsInput() { return true; } - + /** {@inheritDoc} */ public void onPause() { @@ -110,6 +117,8 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie // erase the SIM unlock code, including orientation changes. mPinText.setText(""); mEnteredDigits = 0; + + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); } /** {@inheritDoc} */ @@ -166,7 +175,6 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie } mCallback.pokeWakelock(); } else if (v == mEmergencyCallButton) { - mCallback.pokeWakelock(); mCallback.takeEmergencyCallAction(); } else if (v == mOkButton) { checkPin(); @@ -366,4 +374,24 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie return digit; } } + + public void onPhoneStateChanged(String newState) { + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); + } + + public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + + } + + public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + + } + + public void onRingerModeChanged(int state) { + + } + + public void onTimeChanged() { + + } } -- GitLab From c8f7c0ec193bac368007f7cdf58616ac3e82708a Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Wed, 24 Feb 2010 15:37:00 -0800 Subject: [PATCH 218/458] Fix 2336057: Provide a way for the user to return to a call from LockScreen. This makes the "Emergency call" button dual-purpose. If there's a call in progress, the button will show "Return to call" and take them back to the call. --- .../policy/impl/AccountUnlockScreen.java | 25 +++++++++- .../policy/impl/KeyguardUpdateMonitor.java | 25 ++++++++++ .../policy/impl/LockPatternKeyguardView.java | 47 +++++++------------ .../internal/policy/impl/LockScreen.java | 10 ++++ .../policy/impl/PasswordUnlockScreen.java | 34 ++++++++++++-- .../policy/impl/PatternUnlockScreen.java | 29 +++++++++--- .../internal/policy/impl/SimUnlockScreen.java | 40 +++++++++++++--- 7 files changed, 161 insertions(+), 49 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index 26419dda87a2..1aaef8392472 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -28,6 +28,7 @@ import android.accounts.AccountManagerCallback; import android.content.Context; import android.content.Intent; import android.graphics.Rect; +import android.telephony.TelephonyManager; import android.text.Editable; import android.text.InputFilter; import android.text.LoginFilter; @@ -51,7 +52,7 @@ import java.io.IOException; * account's login/password to unlock the phone (and reset their lock pattern). */ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen, - View.OnClickListener, TextWatcher { + KeyguardUpdateMonitor.InfoCallback,View.OnClickListener, TextWatcher { private static final String LOCK_PATTERN_PACKAGE = "com.android.settings"; private static final String LOCK_PATTERN_CLASS = "com.android.settings.ChooseLockPattern"; @@ -108,6 +109,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree mEmergencyCall = (Button) findViewById(R.id.emergencyCall); mEmergencyCall.setOnClickListener(this); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCall); } public void afterTextChanged(Editable s) { @@ -143,6 +145,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree mLogin.setText(""); mPassword.setText(""); mLogin.requestFocus(); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCall); } /** {@inheritDoc} */ @@ -314,4 +317,24 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree } return mCheckingDialog; } + + public void onPhoneStateChanged(String newState) { + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCall); + } + + public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + + } + + public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + + } + + public void onRingerModeChanged(int state) { + + } + + public void onTimeChanged() { + + } } diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 9729edabce89..b7187a48a8ef 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -38,6 +38,8 @@ import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.TelephonyIntents; + +import android.telephony.TelephonyManager; import android.util.Log; import com.android.internal.R; import com.google.android.collect.Lists; @@ -96,6 +98,7 @@ public class KeyguardUpdateMonitor { private static final int MSG_CARRIER_INFO_UPDATE = 303; private static final int MSG_SIM_STATE_CHANGE = 304; private static final int MSG_RINGER_MODE_CHANGED = 305; + private static final int MSG_PHONE_STATE_CHANGED = 306; /** @@ -165,6 +168,9 @@ public class KeyguardUpdateMonitor { case MSG_RINGER_MODE_CHANGED: handleRingerModeChange(msg.arg1); break; + case MSG_PHONE_STATE_CHANGED: + handlePhoneStateChanged((String)msg.obj); + break; } } }; @@ -221,6 +227,7 @@ public class KeyguardUpdateMonitor { filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); filter.addAction(SPN_STRINGS_UPDATED_ACTION); filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); context.registerReceiver(new BroadcastReceiver() { @@ -255,11 +262,21 @@ public class KeyguardUpdateMonitor { } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) { mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED, intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0)); + } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { + String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); + mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state)); } } }, filter); } + protected void handlePhoneStateChanged(String newState) { + if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")"); + for (int i = 0; i < mInfoCallbacks.size(); i++) { + mInfoCallbacks.get(i).onPhoneStateChanged(newState); + } + } + protected void handleRingerModeChange(int mode) { if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")"); for (int i = 0; i < mInfoCallbacks.size(); i++) { @@ -478,6 +495,14 @@ public class KeyguardUpdateMonitor { * {@link AudioManager#RINGER_MODE_CHANGED_ACTION} */ void onRingerModeChanged(int state); + + /** + * Called when the phone state changes. String will be one of: + * {@link TelephonyManager#EXTRA_STATE_IDLE} + * {@link TelephonyManager@EXTRA_STATE_RINGING} + * {@link TelephonyManager#EXTRA_STATE_OFFHOOK + */ + void onPhoneStateChanged(String newState); } /** diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index cdac278be6cc..48abe63819f3 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -37,6 +37,7 @@ import android.graphics.PixelFormat; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.SystemProperties; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; @@ -60,6 +61,9 @@ import java.io.IOException; public class LockPatternKeyguardView extends KeyguardViewBase implements AccountManagerCallback { + // time after launching EmergencyDialer before the screen goes blank. + private static final int EMERGENCY_CALL_TIMEOUT = 10000; + // intent action for launching emergency dialer activity. static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL"; @@ -251,10 +255,16 @@ public class LockPatternKeyguardView extends KeyguardViewBase } public void takeEmergencyCallAction() { - Intent intent = new Intent(ACTION_EMERGENCY_DIAL); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - getContext().startActivity(intent); + pokeWakelock(EMERGENCY_CALL_TIMEOUT); + if (TelephonyManager.getDefault().getCallState() + == TelephonyManager.CALL_STATE_OFFHOOK) { + mLockPatternUtils.resumeCall(); + } else { + Intent intent = new Intent(ACTION_EMERGENCY_DIAL); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + getContext().startActivity(intent); + } } public void pokeWakelock() { @@ -556,7 +566,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase return new SimUnlockScreen( mContext, mUpdateMonitor, - mKeyguardScreenCallback); + mKeyguardScreenCallback, + mLockPatternUtils); } else if (unlockMode == UnlockMode.Account) { try { return new AccountUnlockScreen( @@ -589,32 +600,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase } } - private View getUnlockScreenForCurrentUnlockMode() { - final UnlockMode unlockMode = getUnlockMode(); - - // if a screen exists for the correct mode, we're done - if (unlockMode == mUnlockScreenMode) { - return mUnlockScreen; - } - - // remember the mode - mUnlockScreenMode = unlockMode; - - // unlock mode has changed and we have an existing old unlock screen - // to clean up - if (mScreenOn && (mUnlockScreen.getVisibility() == View.VISIBLE)) { - ((KeyguardScreen) mUnlockScreen).onPause(); - } - ((KeyguardScreen) mUnlockScreen).cleanUp(); - removeViewInLayout(mUnlockScreen); - - // create the new one - mUnlockScreen = createUnlockScreenFor(unlockMode); - mUnlockScreen.setVisibility(View.INVISIBLE); - addView(mUnlockScreen); - return mUnlockScreen; - } - /** * Given the current state of things, what should be the initial mode of * the lock screen (lock or unlock). diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index ba6b3b31756a..772481637202 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -18,12 +18,15 @@ package com.android.internal.policy.impl; import com.android.internal.R; import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.Phone.State; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.SlidingTab; import android.content.Context; import android.content.res.Resources; import android.content.res.ColorStateList; +import android.telephony.TelephonyManager; import android.text.format.DateFormat; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -190,6 +193,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); mEmergencyCallButton.setText(R.string.lockscreen_emergency_call); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); mScreenLocked = (TextView) findViewById(R.id.screenLocked); mSelector = (SlidingTab) findViewById(R.id.tab_selector); mSelector.setHoldAfterTrigger(true, false); @@ -248,6 +252,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM refreshBatteryStringAndIcon(); refreshAlarmDisplay(); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); mTimeFormat = DateFormat.getTimeFormat(getContext()); mDateFormatString = getContext().getString(R.string.full_wday_month_day_no_year); @@ -610,6 +615,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM /** {@inheritDoc} */ public void onResume() { resetStatusInfo(mUpdateMonitor); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); } /** {@inheritDoc} */ @@ -625,4 +631,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM updateRightTabResources(); } } + + public void onPhoneStateChanged(String newState) { + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); + } } diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java index 841c2e4d7d58..a721c470e272 100644 --- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -22,10 +22,12 @@ import android.graphics.Rect; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.PasswordEntryKeyboardView; +import android.telephony.TelephonyManager; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.inputmethod.EditorInfo; +import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; @@ -39,7 +41,8 @@ import com.android.internal.widget.PasswordEntryKeyboardHelper; * an unlock password */ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener, - KeyguardUpdateMonitor.ConfigurationChangeCallback, OnEditorActionListener { + KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.InfoCallback, + OnEditorActionListener { private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; @@ -49,7 +52,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen private final boolean mCreatedWithKeyboardOpen; private EditText mPasswordEntry; - private TextView mEmergencyCallButton; + private Button mEmergencyCallButton; private LockPatternUtils mLockPatternUtils; private PasswordEntryKeyboardView mKeyboardView; private PasswordEntryKeyboardHelper mKeyboardHelper; @@ -64,6 +67,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mUpdateMonitor = updateMonitor; mCallback = callback; mCreatedWithKeyboardOpen = mUpdateMonitor.isKeyboardOpen(); + mLockPatternUtils = lockPatternUtils; LayoutInflater layoutInflater = LayoutInflater.from(context); if (mUpdateMonitor.isInPortrait()) { @@ -76,10 +80,10 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard); mPasswordEntry = (EditText) findViewById(R.id.passwordEntry); mPasswordEntry.setOnEditorActionListener(this); - mEmergencyCallButton = (TextView) findViewById(R.id.emergencyCall); + mEmergencyCallButton = (Button) findViewById(R.id.emergencyCall); mEmergencyCallButton.setOnClickListener(this); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); mUpdateMonitor.registerConfigurationChangeCallback(this); - mLockPatternUtils = lockPatternUtils; mKeyboardHelper = new PasswordEntryKeyboardHelper(context, mKeyboardView, this); mKeyboardHelper.setKeyboardMode(isAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA @@ -90,6 +94,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mKeyboardHelper.setVibratePattern(mLockPatternUtils.isTactileFeedbackEnabled() ? com.android.internal.R.array.config_virtualKeyVibePattern : 0); + } @Override @@ -113,6 +118,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen // start fresh mPasswordEntry.setText(""); mPasswordEntry.requestFocus(); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); } /** {@inheritDoc} */ @@ -164,4 +170,24 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen return false; } + public void onPhoneStateChanged(String newState) { + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); + } + + public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + + } + + public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + + } + + public void onRingerModeChanged(int state) { + + } + + public void onTimeChanged() { + + } + } diff --git a/policy/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/com/android/internal/policy/impl/PatternUnlockScreen.java index 2e3aa84b49f3..30fb8b8fb80a 100644 --- a/policy/com/android/internal/policy/impl/PatternUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PatternUnlockScreen.java @@ -25,6 +25,7 @@ import android.view.ViewGroup; import android.view.MotionEvent; import android.widget.Button; import android.widget.TextView; +import android.telephony.TelephonyManager; import android.text.format.DateFormat; import android.text.TextUtils; import android.util.Log; @@ -126,6 +127,8 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient }; private Button mForgotPatternButton; + private Button mEmergencyAlone; + private Button mEmergencyTogether; enum FooterMode { Normal, @@ -205,16 +208,17 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient // emergency call buttons final OnClickListener emergencyClick = new OnClickListener() { public void onClick(View v) { - mCallback.pokeWakelock(); mCallback.takeEmergencyCallAction(); } }; - Button emergencyAlone = (Button) findViewById(R.id.emergencyCallAlone); - emergencyAlone.setFocusable(false); // touch only! - emergencyAlone.setOnClickListener(emergencyClick); - Button emergencyTogether = (Button) findViewById(R.id.emergencyCallTogether); - emergencyTogether.setFocusable(false); - emergencyTogether.setOnClickListener(emergencyClick); + + mEmergencyAlone = (Button) findViewById(R.id.emergencyCallAlone); + mEmergencyAlone.setFocusable(false); // touch only! + mEmergencyAlone.setOnClickListener(emergencyClick); + mEmergencyTogether = (Button) findViewById(R.id.emergencyCallTogether); + mEmergencyTogether.setFocusable(false); + mEmergencyTogether.setOnClickListener(emergencyClick); + refreshEmergencyButtonText(); mForgotPatternButton = (Button) findViewById(R.id.forgotPattern); mForgotPatternButton.setText(R.string.lockscreen_forgot_pattern_button_text); @@ -259,6 +263,11 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient mUpdateMonitor.getTelephonySpn())); } + private void refreshEmergencyButtonText() { + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyAlone); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyTogether); + } + public void setEnableFallback(boolean state) { if (DEBUG) Log.d(TAG, "setEnableFallback(" + state + ")"); mEnableFallback = state; @@ -447,6 +456,8 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient } else { updateFooter(FooterMode.Normal); } + + refreshEmergencyButtonText(); } /** {@inheritDoc} */ @@ -549,4 +560,8 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient } }.start(); } + + public void onPhoneStateChanged(String newState) { + refreshEmergencyButtonText(); + } } diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java index 8c738a7e7bda..d5da274d5fb8 100644 --- a/policy/com/android/internal/policy/impl/SimUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/SimUnlockScreen.java @@ -22,11 +22,14 @@ import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; import com.android.internal.telephony.ITelephony; +import com.android.internal.widget.LockPatternUtils; + import android.text.Editable; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; +import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import com.android.internal.R; @@ -35,7 +38,7 @@ import com.android.internal.R; * Displays a dialer like interface to unlock the SIM PIN. */ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener, - KeyguardUpdateMonitor.ConfigurationChangeCallback { + KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.InfoCallback { private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; @@ -48,7 +51,7 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie private TextView mPinText; private TextView mOkButton; - private TextView mEmergencyCallButton; + private Button mEmergencyCallButton; private View mBackSpaceButton; @@ -57,14 +60,17 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie private ProgressDialog mSimUnlockProgressDialog = null; + private LockPatternUtils mLockPatternUtils; + private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; public SimUnlockScreen(Context context, KeyguardUpdateMonitor updateMonitor, - KeyguardScreenCallback callback) { + KeyguardScreenCallback callback, LockPatternUtils lockpatternutils) { super(context); mUpdateMonitor = updateMonitor; mCallback = callback; mCreatedWithKeyboardOpen = mUpdateMonitor.isKeyboardOpen(); + mLockPatternUtils = lockpatternutils; if (mCreatedWithKeyboardOpen) { LayoutInflater.from(context).inflate(R.layout.keyguard_screen_sim_pin_landscape, this, true); @@ -78,7 +84,8 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie mBackSpaceButton = findViewById(R.id.backspace); mBackSpaceButton.setOnClickListener(this); - mEmergencyCallButton = (TextView) findViewById(R.id.emergencyCall); + mEmergencyCallButton = (Button) findViewById(R.id.emergencyCall); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); mOkButton = (TextView) findViewById(R.id.ok); mHeaderText.setText(R.string.keyguard_password_enter_pin_code); @@ -95,7 +102,7 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie public boolean needsInput() { return true; } - + /** {@inheritDoc} */ public void onPause() { @@ -110,6 +117,8 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie // erase the SIM unlock code, including orientation changes. mPinText.setText(""); mEnteredDigits = 0; + + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); } /** {@inheritDoc} */ @@ -166,7 +175,6 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie } mCallback.pokeWakelock(); } else if (v == mEmergencyCallButton) { - mCallback.pokeWakelock(); mCallback.takeEmergencyCallAction(); } else if (v == mOkButton) { checkPin(); @@ -366,4 +374,24 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie return digit; } } + + public void onPhoneStateChanged(String newState) { + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); + } + + public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + + } + + public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + + } + + public void onRingerModeChanged(int state) { + + } + + public void onTimeChanged() { + + } } -- GitLab From 0d9f798e9f76b13b07ac3dee3ff90b5530f53145 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Thu, 25 Feb 2010 19:56:06 -0800 Subject: [PATCH 219/458] Fix 2468960: Make sure unlock screen gets updated when SIM state changes. Added code to let us lazily re-create the unlock screen when the SIM status changes. This fixes a bug where we sometimes show the Pattern/Password unlock instead of the SIM PIN unlock due to an ordering issue with recent changes to the telephony layer SIM update logic. It now correctly re-evaluates the SIM state and updates the UI accordingly. --- .../policy/impl/LockPatternKeyguardView.java | 63 ++++++++++++++++--- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 48abe63819f3..e4f28e9b3d09 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -122,7 +122,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase /** * Unlock by entering a password or PIN */ - Password + Password, + + /** + * Unknown (uninitialized) value + */ + Unknown } /** @@ -153,6 +158,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase private int mNumAccounts; private boolean mIsPortrait; + private UnlockMode mCurrentUnlockMode = UnlockMode.Unknown; + /** * @return Whether we are stuck on the lock screen because the sim is * missing. @@ -421,7 +428,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase } } - private void recreateScreens() { + private void recreateLockScreen() { if (mLockScreen.getVisibility() == View.VISIBLE) { ((KeyguardScreen) mLockScreen).onPause(); } @@ -431,7 +438,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase mLockScreen = createLockScreen(); mLockScreen.setVisibility(View.INVISIBLE); addView(mLockScreen); + } + private void recreateUnlockScreen() { if (mUnlockScreen.getVisibility() == View.VISIBLE) { ((KeyguardScreen) mUnlockScreen).onPause(); } @@ -443,11 +452,14 @@ public class LockPatternKeyguardView extends KeyguardViewBase mUnlockScreen.setVisibility(View.INVISIBLE); mUnlockScreenMode = unlockMode; addView(mUnlockScreen); + } + private void recreateScreens() { + recreateLockScreen(); + recreateUnlockScreen(); updateScreen(mMode); } - @Override public void wakeWhenReadyTq(int keyCode) { if (DEBUG) Log.d(TAG, "onWakeKey"); @@ -512,6 +524,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase mMode = mode; + // Re-create the unlock screen if necessary. This is primarily required to properly handle + // SIM state changes. This typically happens when this method is called by reset() + if (mode == Mode.UnlockScreen && mCurrentUnlockMode != getUnlockMode()) { + recreateUnlockScreen(); + } + final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen; final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen; @@ -551,6 +569,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase // Capture the orientation this layout was created in. mIsPortrait = getResources().getBoolean(R.bool.lockscreen_isPortrait); + View unlockView = null; if (unlockMode == UnlockMode.Pattern) { PatternUnlockScreen view = new PatternUnlockScreen( mContext, @@ -561,16 +580,16 @@ public class LockPatternKeyguardView extends KeyguardViewBase if (DEBUG) Log.d(TAG, "createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback); view.setEnableFallback(mEnableFallback); - return view; + unlockView = view; } else if (unlockMode == UnlockMode.SimPin) { - return new SimUnlockScreen( + unlockView = new SimUnlockScreen( mContext, mUpdateMonitor, mKeyguardScreenCallback, mLockPatternUtils); } else if (unlockMode == UnlockMode.Account) { try { - return new AccountUnlockScreen( + unlockView = new AccountUnlockScreen( mContext, mKeyguardScreenCallback, mLockPatternUtils); @@ -587,10 +606,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase // regular pattern unlock UI, regardless of the value of // mUnlockScreenMode or whether or not we're in the // "permanently locked" state.) - return createUnlockScreenFor(UnlockMode.Pattern); + unlockView = createUnlockScreenFor(UnlockMode.Pattern); } } else if (unlockMode == UnlockMode.Password) { - return new PasswordUnlockScreen( + unlockView = new PasswordUnlockScreen( mContext, mLockPatternUtils, mUpdateMonitor, @@ -598,6 +617,34 @@ public class LockPatternKeyguardView extends KeyguardViewBase } else { throw new IllegalArgumentException("unknown unlock mode " + unlockMode); } + mCurrentUnlockMode = unlockMode; + return unlockView; + } + + private View getUnlockScreenForCurrentUnlockMode() { + final UnlockMode unlockMode = getUnlockMode(); + + // if a screen exists for the correct mode, we're done + if (unlockMode == mUnlockScreenMode) { + return mUnlockScreen; + } + + // remember the mode + mUnlockScreenMode = unlockMode; + + // unlock mode has changed and we have an existing old unlock screen + // to clean up + if (mScreenOn && (mUnlockScreen.getVisibility() == View.VISIBLE)) { + ((KeyguardScreen) mUnlockScreen).onPause(); + } + ((KeyguardScreen) mUnlockScreen).cleanUp(); + removeViewInLayout(mUnlockScreen); + + // create the new one + mUnlockScreen = createUnlockScreenFor(unlockMode); + mUnlockScreen.setVisibility(View.INVISIBLE); + addView(mUnlockScreen); + return mUnlockScreen; } /** -- GitLab From cdb70af791446f050c3275bd048fe4c630d7e9ea Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Mon, 1 Mar 2010 16:51:43 -0800 Subject: [PATCH 220/458] Fix 2447470: always update the battery status when it's below the threshold. Previously, the battery percentage was only shown when the battery level transitioned below the LOW_BATTERY_THRESHOLD (20%). This change makes it so it gets updated whenever we get a battery status update where the level is below LOW_BATTERY_THRESHOLD. Note: this only applies to the pattern unlock screen. --- .../internal/policy/impl/KeyguardUpdateMonitor.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index b7187a48a8ef..b7bb18416779 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -385,14 +385,8 @@ public class KeyguardUpdateMonitor { } if (!pluggedIn) { - // not plugged in and going below threshold - if (batteryLevel < LOW_BATTERY_THRESHOLD - && mBatteryLevel >= LOW_BATTERY_THRESHOLD) { - return true; - } - // not plugged in and going above threshold (sounds impossible, but, meh...) - if (mBatteryLevel < LOW_BATTERY_THRESHOLD - && batteryLevel >= LOW_BATTERY_THRESHOLD) { + // not plugged in and below threshold + if (batteryLevel < LOW_BATTERY_THRESHOLD && batteryLevel != mBatteryLevel) { return true; } } -- GitLab From 82d6c68b396323789e52c407b18ee4a7eab11a24 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Fri, 26 Feb 2010 15:16:54 -0500 Subject: [PATCH 221/458] Support refined vibrate/silent behavior. See change I14cf91b0 for explanation and required framework support. Bug: 2457183 Change-Id: I09ad7d697ff17c24fc41744ed70add214d132bd3 --- .../internal/policy/impl/GlobalActions.java | 39 +++++++++++++++---- .../internal/policy/impl/LockScreen.java | 32 +++++++++++---- 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/policy/com/android/internal/policy/impl/GlobalActions.java b/policy/com/android/internal/policy/impl/GlobalActions.java index 8b6257f42838..b10bda212554 100644 --- a/policy/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/com/android/internal/policy/impl/GlobalActions.java @@ -117,7 +117,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac * @return A new dialog. */ private AlertDialog createDialog() { - mSilentModeToggle = new ToggleAction( R.drawable.ic_lock_silent_mode, R.drawable.ic_lock_silent_mode_off, @@ -125,9 +124,23 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac R.string.global_action_silent_mode_on_status, R.string.global_action_silent_mode_off_status) { + void willCreate() { + // XXX: FIXME: switch to ic_lock_vibrate_mode when available + mEnabledIconResId = (Settings.System.getInt(mContext.getContentResolver(), + Settings.System.VIBRATE_IN_SILENT, 1) == 1) + ? R.drawable.ic_lock_silent_mode + : R.drawable.ic_lock_silent_mode; + } + void onToggle(boolean on) { - mAudioManager.setRingerMode(on ? AudioManager.RINGER_MODE_SILENT - : AudioManager.RINGER_MODE_NORMAL); + if (on) { + mAudioManager.setRingerMode((Settings.System.getInt(mContext.getContentResolver(), + Settings.System.VIBRATE_IN_SILENT, 1) == 1) + ? AudioManager.RINGER_MODE_VIBRATE + : AudioManager.RINGER_MODE_SILENT); + } else { + mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); + } } public boolean showDuringKeyguard() { @@ -412,11 +425,11 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac protected State mState = State.Off; // prefs - private final int mEnabledIconResId; - private final int mDisabledIconResid; - private final int mMessageResId; - private final int mEnabledStatusMessageResId; - private final int mDisabledStatusMessageResId; + protected int mEnabledIconResId; + protected int mDisabledIconResid; + protected int mMessageResId; + protected int mEnabledStatusMessageResId; + protected int mDisabledStatusMessageResId; /** * @param enabledIconResId The icon for when this action is on. @@ -437,8 +450,18 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mDisabledStatusMessageResId = disabledStatusMessageResId; } + /** + * Override to make changes to resource IDs just before creating the + * View. + */ + void willCreate() { + + } + public View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { + willCreate(); + View v = (convertView != null) ? convertView : inflater.inflate(R diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 772481637202..22a43367e90c 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -37,6 +37,7 @@ import android.graphics.drawable.Drawable; import android.util.Log; import android.media.AudioManager; import android.os.SystemProperties; +import android.provider.Settings; import java.util.Date; import java.io.File; @@ -229,17 +230,23 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } private boolean isSilentMode() { - return mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT; + return mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; } private void updateRightTabResources() { + boolean vibe = mSilentMode + && (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE); + mSelector.setRightTabResources( - mSilentMode ? 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 ? ( 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, + : R.drawable.jog_tab_bar_right_sound_off, mSilentMode ? R.drawable.jog_tab_right_sound_on - : R.drawable.jog_tab_right_sound_off); + : R.drawable.jog_tab_right_sound_off); } private void resetStatusInfo(KeyguardUpdateMonitor updateMonitor) { @@ -275,8 +282,17 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { // toggle silent mode mSilentMode = !mSilentMode; - mAudioManager.setRingerMode(mSilentMode ? AudioManager.RINGER_MODE_SILENT - : AudioManager.RINGER_MODE_NORMAL); + 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(); @@ -625,7 +641,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM /** {@inheritDoc} */ public void onRingerModeChanged(int state) { - boolean silent = AudioManager.RINGER_MODE_SILENT == state; + boolean silent = AudioManager.RINGER_MODE_NORMAL != state; if (silent != mSilentMode) { mSilentMode = silent; updateRightTabResources(); -- GitLab From 6019c9d9ca785f83fa9c163e177639381a8beeda Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 1 Mar 2010 21:43:11 -0800 Subject: [PATCH 222/458] Pointer location in framework, no longer need to link common. --- policy/Android.mk | 2 -- .../com/android/internal/policy/impl/PhoneWindowManager.java | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/policy/Android.mk b/policy/Android.mk index c56f3538cd90..f42cbac781ac 100644 --- a/policy/Android.mk +++ b/policy/Android.mk @@ -7,8 +7,6 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ $(call all-subdir-java-files) -LOCAL_STATIC_JAVA_LIBRARIES += android-common - LOCAL_MODULE := android.policy_phone LOCAL_UNINSTALLABLE_MODULE := true diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index ba5ea74ff567..97c71ff8bd67 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -45,9 +45,10 @@ import android.os.SystemProperties; import android.os.Vibrator; import android.provider.Settings; -import com.android.common.ui.PointerLocationView; import com.android.internal.policy.PolicyManager; import com.android.internal.telephony.ITelephony; +import com.android.internal.widget.PointerLocationView; + import android.util.Config; import android.util.EventLog; import android.util.Log; -- GitLab From 8b9dda28c9850b4a68b6958b8d4f751dd64157ad Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Tue, 2 Mar 2010 17:24:48 -0800 Subject: [PATCH 223/458] Fix 2481917: allows keyboards with overlapping qwerty/numeric keys to work w/o requiring hitting the key. Some devices have a qwerty layout without separate numeric keys. This makes PIN entry painful. The workaround is to set an explicit numeric key listener when in numeric mode. --- .../internal/policy/impl/PasswordUnlockScreen.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java index a721c470e272..c52ef53c742f 100644 --- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -23,6 +23,8 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.PasswordEntryKeyboardView; import android.telephony.TelephonyManager; +import android.text.method.DigitsKeyListener; +import android.text.method.TextKeyListener; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -92,6 +94,14 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mKeyboardView.setVisibility(mCreatedWithKeyboardOpen ? View.INVISIBLE : View.VISIBLE); mPasswordEntry.requestFocus(); + // This allows keyboards with overlapping qwerty/numeric keys to choose just the + // numeric keys. + if (isAlpha) { + mPasswordEntry.setKeyListener(TextKeyListener.getInstance()); + } else { + mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance()); + } + mKeyboardHelper.setVibratePattern(mLockPatternUtils.isTactileFeedbackEnabled() ? com.android.internal.R.array.config_virtualKeyVibePattern : 0); -- GitLab From c20115c500ca2ca95b52b3163774e79fc8cc2040 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 2 Mar 2010 23:32:01 -0800 Subject: [PATCH 224/458] Fix issue #2445481: onNewIntent is called twice if SEARCH button is "long-pressed" --- policy/com/android/internal/policy/impl/PhoneWindow.java | 1 + 1 file changed, 1 insertion(+) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 55772b2ae734..4e630df3115f 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -1244,6 +1244,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // activity; otherwise we will allow the normal short // press action to be performed. dispatcher.performedLongPress(event); + return true; } catch (ActivityNotFoundException e) { // Ignore } -- GitLab From 0340b4299282bcbddd29b26751186431cc4af17b Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Thu, 4 Mar 2010 13:24:17 -0800 Subject: [PATCH 225/458] Fix 2420689: Fix bug that prevents pattern unlock from showing lockout dialog. This fixes the problem where the lockout dialog wasn't showing. It also fixes a problem where the "forgot pattern" button would stop working. --- .../policy/impl/LockPatternKeyguardView.java | 16 +++------------- .../policy/impl/PatternUnlockScreen.java | 9 +-------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index e4f28e9b3d09..8bda7601dbdf 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -290,7 +290,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase // irrelevant to keyguard screen, they shouldn't be calling this } - public void reportFailedPatternAttempt() { + public void reportFailedUnlockAttempt() { mUpdateMonitor.reportFailedAttempt(); final int failedAttempts = mUpdateMonitor.getFailedAttempts(); if (DEBUG) Log.d(TAG, @@ -308,16 +308,13 @@ public class LockPatternKeyguardView extends KeyguardViewBase == 0) { showTimeoutDialog(); } + mLockPatternUtils.reportFailedPasswordAttempt(); } public boolean doesFallbackUnlockScreenExist() { return mEnableFallback; } - public void reportFailedUnlockAttempt() { - mLockPatternUtils.reportFailedPasswordAttempt(); - } - public void reportSuccessfulUnlockAttempt() { mLockPatternUtils.reportSuccessfulPasswordAttempt(); } @@ -330,13 +327,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase setFocusableInTouchMode(true); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); - // wall paper background - if (false) { - final BitmapDrawable drawable = (BitmapDrawable) context.getWallpaper(); - setBackgroundDrawable( - new FastBitmapDrawable(drawable.getBitmap())); - } - // create both the lock and unlock screen so they are quickly available // when the screen turns on mLockScreen = createLockScreen(); @@ -680,7 +670,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase break; case LockPatternUtils.MODE_PATTERN: // "forgot pattern" button is only available in the pattern mode... - if (mForgotPattern && mLockPatternUtils.isPermanentlyLocked()) { + if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) { currentMode = UnlockMode.Account; } else { currentMode = UnlockMode.Pattern; diff --git a/policy/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/com/android/internal/policy/impl/PatternUnlockScreen.java index 30fb8b8fb80a..d09b358f1ab8 100644 --- a/policy/com/android/internal/policy/impl/PatternUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PatternUnlockScreen.java @@ -62,11 +62,6 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient // how many cells the user has to cross before we poke the wakelock private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2; - // This dictates how long a pattern should be before we count it as an attempt. - // This should be long enough to avoid false triggers while the device is in a pocket, - // as this can lead to a wiped device if a {@link DeviceAdmin} is active and has it enabled. - private static final int MIN_PATTERN_BEFORE_REPORT = 3; - private int mFailedPatternAttemptsSinceLastTimeout = 0; private int mTotalFailedPatternAttempts = 0; private CountDownTimer mCountdownTimer = null; @@ -511,6 +506,7 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { mTotalFailedPatternAttempts++; mFailedPatternAttemptsSinceLastTimeout++; + mCallback.reportFailedUnlockAttempt(); } if (mFailedPatternAttemptsSinceLastTimeout >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); @@ -523,9 +519,6 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS); } - if (pattern.size() > MIN_PATTERN_BEFORE_REPORT) { - mCallback.reportFailedUnlockAttempt(); - } } } } -- GitLab From b0fbe297c50df5dcfb81721fd6079dd7125f88e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20=C3=96stergren?= Date: Fri, 5 Mar 2010 09:44:15 +0100 Subject: [PATCH 226/458] Updated RGB LED test cases The test cases for turning on the RGB LED with persistent light was corrected. The color for blinking was updated to blue. And finally an option for turning off the lights was added. --- .../statusbartest/NotificationTestList.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java index f2ddd0fd55c0..4fd7e650264c 100644 --- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java +++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java @@ -165,6 +165,8 @@ public class NotificationTestList extends TestActivity Notification n = new Notification(); n.flags |= Notification.FLAG_SHOW_LIGHTS; n.ledARGB = 0xff0000ff; + n.ledOnMS = 1; + n.ledOffMS = 0; mNM.notify(1, n); } }, @@ -175,6 +177,8 @@ public class NotificationTestList extends TestActivity Notification n = new Notification(); n.flags |= Notification.FLAG_SHOW_LIGHTS; n.ledARGB = 0xffff0000; + n.ledOnMS = 1; + n.ledOffMS = 0; mNM.notify(1, n); } }, @@ -185,6 +189,20 @@ public class NotificationTestList extends TestActivity Notification n = new Notification(); n.flags |= Notification.FLAG_SHOW_LIGHTS; n.ledARGB = 0xffffff00; + n.ledOnMS = 1; + n.ledOffMS = 0; + mNM.notify(1, n); + } + }, + + new Test("Lights off") { + public void run() + { + Notification n = new Notification(); + n.flags |= Notification.FLAG_SHOW_LIGHTS; + n.ledARGB = 0x00000000; + n.ledOnMS = 0; + n.ledOffMS = 0; mNM.notify(1, n); } }, @@ -194,7 +212,7 @@ public class NotificationTestList extends TestActivity { Notification n = new Notification(); n.flags |= Notification.FLAG_SHOW_LIGHTS; - n.ledARGB = 0xffffff00; + n.ledARGB = 0xff0000ff; n.ledOnMS = 1300; n.ledOffMS = 1300; mNM.notify(1, n); @@ -206,7 +224,7 @@ public class NotificationTestList extends TestActivity { Notification n = new Notification(); n.flags |= Notification.FLAG_SHOW_LIGHTS; - n.ledARGB = 0xffffff00; + n.ledARGB = 0xff0000ff; n.ledOnMS = 300; n.ledOffMS = 300; mNM.notify(1, n); -- GitLab From 055ea248a40897dcf9bc09241135f4003e69a562 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Fri, 5 Mar 2010 09:34:52 -0500 Subject: [PATCH 227/458] Use new vibrate icon in power menu. Change-Id: I54725ae73bac731a2078a9c61d75d77c0cbb3680 --- policy/com/android/internal/policy/impl/GlobalActions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/GlobalActions.java b/policy/com/android/internal/policy/impl/GlobalActions.java index b10bda212554..1f06dcc4c6f2 100644 --- a/policy/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/com/android/internal/policy/impl/GlobalActions.java @@ -128,7 +128,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac // XXX: FIXME: switch to ic_lock_vibrate_mode when available mEnabledIconResId = (Settings.System.getInt(mContext.getContentResolver(), Settings.System.VIBRATE_IN_SILENT, 1) == 1) - ? R.drawable.ic_lock_silent_mode + ? R.drawable.ic_lock_silent_mode_vibrate : R.drawable.ic_lock_silent_mode; } -- GitLab From 78968395ddf75a4033ec5b97b0ab90660d7e32cc Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 4 Mar 2010 20:47:56 -0800 Subject: [PATCH 228/458] Update to use new dock broadcasts. --- .../policy/impl/PhoneWindowManager.java | 67 ++++++++++--------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 97c71ff8bd67..9e96c0d5cf98 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -20,6 +20,8 @@ import android.app.Activity; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.IStatusBar; +import android.app.IUiModeManager; +import android.app.UiModeManager; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -207,7 +209,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mLidOpen; int mPlugged; boolean mRegisteredBatteryReceiver; - int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + int mUiMode = Configuration.UI_MODE_TYPE_NORMAL; int mLidOpenRotation; int mCarDockRotation; int mDeskDockRotation; @@ -345,8 +347,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return true; } // We're in a dock that has a rotation affinity, an the app is willing to rotate. - if ((mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR) - || (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) { + if ((mCarDockEnablesAccelerometer && mUiMode == Configuration.UI_MODE_TYPE_CAR) + || (mDeskDockEnablesAccelerometer && mUiMode == Configuration.UI_MODE_TYPE_DESK)) { // Note we override the nosensor flag here. if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED @@ -369,8 +371,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // orientation, then we need to turn the sensor or. return true; } - if ((mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR) || - (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) { + if ((mCarDockEnablesAccelerometer && mUiMode == Configuration.UI_MODE_TYPE_CAR) || + (mDeskDockEnablesAccelerometer && mUiMode == Configuration.UI_MODE_TYPE_DESK)) { // enable accelerometer if we are docked in a dock that enables accelerometer // orientation management, return true; @@ -537,7 +539,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { mPlugged = 0; updatePlugged(context.registerReceiver(null, mBatteryStatusFilter)); // register for dock events - context.registerReceiver(mDockReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT)); + IntentFilter filter = new IntentFilter(); + filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE); + filter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE); + filter.addAction(UiModeManager.ACTION_ENTER_DESK_MODE); + filter.addAction(UiModeManager.ACTION_EXIT_DESK_MODE); + context.registerReceiver(mDockReceiver, filter); mVibrator = new Vibrator(); mLongPressVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_longPressVibePattern); @@ -1981,17 +1988,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { BroadcastReceiver mDockReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { - mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, - Intent.EXTRA_DOCK_STATE_UNDOCKED); - boolean watchBattery = mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED; - if (watchBattery != mRegisteredBatteryReceiver) { - mRegisteredBatteryReceiver = watchBattery; - if (watchBattery) { - updatePlugged(mContext.registerReceiver(mBatteryReceiver, - mBatteryStatusFilter)); - } else { - mContext.unregisterReceiver(mBatteryReceiver); + try { + IUiModeManager uiModeService = IUiModeManager.Stub.asInterface( + ServiceManager.getService(Context.UI_MODE_SERVICE)); + mUiMode = uiModeService.getCurrentModeType(); + boolean watchBattery = mUiMode != Configuration.UI_MODE_TYPE_UNDEFINED + && mUiMode != Configuration.UI_MODE_TYPE_NORMAL; + if (watchBattery != mRegisteredBatteryReceiver) { + mRegisteredBatteryReceiver = watchBattery; + if (watchBattery) { + updatePlugged(mContext.registerReceiver(mBatteryReceiver, + mBatteryStatusFilter)); + } else { + mContext.unregisterReceiver(mBatteryReceiver); + } } + } catch (RemoteException e) { } updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); updateDockKeepingScreenOn(); @@ -2121,9 +2133,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { //or case.unspecified if (mLidOpen) { return mLidOpenRotation; - } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) { + } else if (mUiMode == Configuration.UI_MODE_TYPE_CAR && mCarDockRotation >= 0) { return mCarDockRotation; - } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) { + } else if (mUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskDockRotation >= 0) { return mDeskDockRotation; } else { if (useSensorForOrientationLp(orientation)) { @@ -2232,17 +2244,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { void updateDockKeepingScreenOn() { if (mPlugged != 0) { - if (localLOGV) Log.v(TAG, "Update: mDockState=" + mDockState + if (localLOGV) Log.v(TAG, "Update: mUiMode=" + mUiMode + " mPlugged=" + mPlugged + " mCarDockKeepsScreenOn" + mCarDockKeepsScreenOn + " mDeskDockKeepsScreenOn" + mDeskDockKeepsScreenOn); - if (mDockState == Intent.EXTRA_DOCK_STATE_CAR + if (mUiMode == Configuration.UI_MODE_TYPE_CAR && (mPlugged&mCarDockKeepsScreenOn) != 0) { if (!mDockWakeLock.isHeld()) { mDockWakeLock.acquire(); } return; - } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK + } else if (mUiMode == Configuration.UI_MODE_TYPE_DESK && (mPlugged&mDeskDockKeepsScreenOn) != 0) { if (!mDockWakeLock.isHeld()) { mDockWakeLock.acquire(); @@ -2261,9 +2273,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { int rotation = Surface.ROTATION_0; if (mLidOpen) { rotation = mLidOpenRotation; - } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) { + } else if (mUiMode == Configuration.UI_MODE_TYPE_CAR && mCarDockRotation >= 0) { rotation = mCarDockRotation; - } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) { + } else if (mUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskDockRotation >= 0) { rotation = mDeskDockRotation; } //if lid is closed orientation will be portrait @@ -2282,17 +2294,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { * @return */ Intent createHomeDockIntent() { - if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) { - return null; - } - Intent intent; - if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) { + if (mUiMode == Configuration.UI_MODE_TYPE_CAR) { intent = mCarDockIntent; - } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { + } else if (mUiMode == Configuration.UI_MODE_TYPE_DESK) { intent = mDeskDockIntent; } else { - Log.w(TAG, "Unknown dock state: " + mDockState); return null; } -- GitLab From b101d99ee5af50f0e57c39aec3f2376859795e32 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Fri, 5 Mar 2010 15:46:24 -0500 Subject: [PATCH 229/458] Move dock wakelock code to UiModeManagerService. Change-Id: Ide758a9e68002b13ba2d61bd9e9701d449edb65b Signed-off-by: Mike Lockwood --- .../policy/impl/PhoneWindowManager.java | 72 ------------------- 1 file changed, 72 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 9e96c0d5cf98..95fac9e51564 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -35,7 +35,6 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.PixelFormat; import android.graphics.Rect; -import android.os.BatteryManager; import android.os.Handler; import android.os.IBinder; import android.os.LocalPowerManager; @@ -202,19 +201,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mShouldTurnOffOnKeyUp; RecentApplicationsDialog mRecentAppsDialog; Handler mHandler; - - final IntentFilter mBatteryStatusFilter = new IntentFilter(); boolean mSystemReady; boolean mLidOpen; - int mPlugged; - boolean mRegisteredBatteryReceiver; int mUiMode = Configuration.UI_MODE_TYPE_NORMAL; int mLidOpenRotation; int mCarDockRotation; int mDeskDockRotation; - int mCarDockKeepsScreenOn; - int mDeskDockKeepsScreenOn; boolean mCarDockEnablesAccelerometer; boolean mDeskDockEnablesAccelerometer; int mLidKeyboardAccessibility; @@ -280,7 +273,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { ShortcutManager mShortcutManager; PowerManager.WakeLock mBroadcastWakeLock; - PowerManager.WakeLock mDockWakeLock; class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler) { @@ -512,9 +504,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PhoneWindowManager.mBroadcastWakeLock"); - mDockWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, - "PhoneWindowManager.mDockWakeLock"); - mDockWakeLock.setReferenceCounted(false); mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); mLidOpenRotation = readRotation( com.android.internal.R.integer.config_lidOpenRotation); @@ -522,10 +511,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.integer.config_carDockRotation); mDeskDockRotation = readRotation( com.android.internal.R.integer.config_deskDockRotation); - mCarDockKeepsScreenOn = mContext.getResources().getInteger( - com.android.internal.R.integer.config_carDockKeepsScreenOn); - mDeskDockKeepsScreenOn = mContext.getResources().getInteger( - com.android.internal.R.integer.config_deskDockKeepsScreenOn); mCarDockEnablesAccelerometer = mContext.getResources().getBoolean( com.android.internal.R.bool.config_carDockEnablesAccelerometer); mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean( @@ -534,10 +519,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.integer.config_lidKeyboardAccessibility); mLidNavigationAccessibility = mContext.getResources().getInteger( com.android.internal.R.integer.config_lidNavigationAccessibility); - // register for battery events - mBatteryStatusFilter.addAction(Intent.ACTION_BATTERY_CHANGED); - mPlugged = 0; - updatePlugged(context.registerReceiver(null, mBatteryStatusFilter)); // register for dock events IntentFilter filter = new IntentFilter(); filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE); @@ -629,14 +610,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - void updatePlugged(Intent powerIntent) { - if (localLOGV) Log.v(TAG, "New battery status: " + powerIntent.getExtras()); - if (powerIntent != null) { - mPlugged = powerIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); - if (localLOGV) Log.v(TAG, "PLUGGED: " + mPlugged); - } - } - private int readRotation(int resID) { try { int rotation = mContext.getResources().getInteger(resID); @@ -1979,34 +1952,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; - BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - updatePlugged(intent); - updateDockKeepingScreenOn(); - } - }; - BroadcastReceiver mDockReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { try { IUiModeManager uiModeService = IUiModeManager.Stub.asInterface( ServiceManager.getService(Context.UI_MODE_SERVICE)); mUiMode = uiModeService.getCurrentModeType(); - boolean watchBattery = mUiMode != Configuration.UI_MODE_TYPE_UNDEFINED - && mUiMode != Configuration.UI_MODE_TYPE_NORMAL; - if (watchBattery != mRegisteredBatteryReceiver) { - mRegisteredBatteryReceiver = watchBattery; - if (watchBattery) { - updatePlugged(mContext.registerReceiver(mBatteryReceiver, - mBatteryStatusFilter)); - } else { - mContext.unregisterReceiver(mBatteryReceiver); - } - } } catch (RemoteException e) { } updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); - updateDockKeepingScreenOn(); updateOrientationListenerLp(); } }; @@ -2241,32 +2195,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { readLidState(); updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); } - - void updateDockKeepingScreenOn() { - if (mPlugged != 0) { - if (localLOGV) Log.v(TAG, "Update: mUiMode=" + mUiMode - + " mPlugged=" + mPlugged - + " mCarDockKeepsScreenOn" + mCarDockKeepsScreenOn - + " mDeskDockKeepsScreenOn" + mDeskDockKeepsScreenOn); - if (mUiMode == Configuration.UI_MODE_TYPE_CAR - && (mPlugged&mCarDockKeepsScreenOn) != 0) { - if (!mDockWakeLock.isHeld()) { - mDockWakeLock.acquire(); - } - return; - } else if (mUiMode == Configuration.UI_MODE_TYPE_DESK - && (mPlugged&mDeskDockKeepsScreenOn) != 0) { - if (!mDockWakeLock.isHeld()) { - mDockWakeLock.acquire(); - } - return; - } - } - - if (mDockWakeLock.isHeld()) { - mDockWakeLock.release(); - } - } void updateRotation(int animFlags) { mPowerManager.setKeyboardVisibility(mLidOpen); -- GitLab From c8830d5c55a92a7e2490f1d11d44c475641deda3 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Mon, 8 Mar 2010 18:04:51 -0800 Subject: [PATCH 230/458] Add an empty CleanSpec.mk Change-Id: I29594c5f5438d6b7c586887e25ef84ffaf64faff -- GitLab From 5f3063e37072274b8019c38d4f581c18dcae6a87 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 10 Mar 2010 16:01:58 -0800 Subject: [PATCH 231/458] Update for new layout flow. Now does lock screen and status bar management in the animation pass, to better match actual changes on screen. Change-Id: I9a68fcfa1968dfa71961bc164a6fda15b2cd7d47 --- .../policy/impl/PhoneWindowManager.java | 111 +++++++++--------- 1 file changed, 56 insertions(+), 55 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 95fac9e51564..06997019b821 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1233,12 +1233,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mDockBottom = mContentBottom = mCurBottom = displayHeight; mDockLayer = 0x10000000; - mTopFullscreenOpaqueWindowState = null; - mForceStatusBar = false; - mHideLockScreen = false; - mAllowLockscreenWhenOn = false; - mDismissKeyguard = false; - // decide where the status bar goes ahead of time if (mStatusBar != null) { final Rect pf = mTmpParentFrame; @@ -1435,30 +1429,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { win.computeFrameLw(pf, df, cf, vf); - if (mTopFullscreenOpaqueWindowState == null && - win.isVisibleOrBehindKeyguardLw()) { - if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { - mForceStatusBar = true; - } - if (attrs.type >= FIRST_APPLICATION_WINDOW - && attrs.type <= LAST_APPLICATION_WINDOW - && win.fillsScreenLw(mW, mH, false, false)) { - if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win); - mTopFullscreenOpaqueWindowState = win; - if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { - if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win); - mHideLockScreen = true; - } - } - if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) { - if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win); - mDismissKeyguard = true; - } - if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { - mAllowLockscreenWhenOn = true; - } - } - // Dock windows carve out the bottom of the screen, so normal windows // can't appear underneath them. if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) { @@ -1480,7 +1450,51 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public int finishLayoutLw() { + return 0; + } + + /** {@inheritDoc} */ + public void beginAnimationLw(int displayWidth, int displayHeight) { + mTopFullscreenOpaqueWindowState = null; + mForceStatusBar = false; + + mHideLockScreen = false; + mAllowLockscreenWhenOn = false; + mDismissKeyguard = false; + } + + /** {@inheritDoc} */ + public void animatingWindowLw(WindowState win, + WindowManager.LayoutParams attrs) { + if (mTopFullscreenOpaqueWindowState == null && + win.isVisibleOrBehindKeyguardLw()) { + if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { + mForceStatusBar = true; + } + if (attrs.type >= FIRST_APPLICATION_WINDOW + && attrs.type <= LAST_APPLICATION_WINDOW + && win.fillsScreenLw(mW, mH, false, false)) { + if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win); + mTopFullscreenOpaqueWindowState = win; + if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { + if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win); + mHideLockScreen = true; + } + if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) { + if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win); + mDismissKeyguard = true; + } + if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { + mAllowLockscreenWhenOn = true; + } + } + } + } + + /** {@inheritDoc} */ + public int finishAnimationLw() { int changes = 0; + boolean hiding = false; if (mStatusBar != null) { if (localLOGV) Log.i(TAG, "force=" + mForceStatusBar @@ -1506,6 +1520,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } + + if (changes != 0 && hiding) { + IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar")); + if (sbs != null) { + try { + // Make sure the window shade is hidden. + sbs.deactivate(); + } catch (RemoteException e) { + } + } + } + // Hide the key guard if a visible window explicitly specifies that it wants to be displayed // when the screen is locked if (mKeyguard != null) { @@ -1540,36 +1566,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - if (changes != 0 && hiding) { - IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar")); - if (sbs != null) { - try { - // Make sure the window shade is hidden. - sbs.deactivate(); - } catch (RemoteException e) { - } - } - } - // update since mAllowLockscreenWhenOn might have changed updateLockScreenTimeout(); return changes; } - /** {@inheritDoc} */ - public void beginAnimationLw(int displayWidth, int displayHeight) { - } - - /** {@inheritDoc} */ - public void animatingWindowLw(WindowState win, - WindowManager.LayoutParams attrs) { - } - - /** {@inheritDoc} */ - public boolean finishAnimationLw() { - return false; - } - public boolean allowAppAnimationsLw() { if (mKeyguard != null && mKeyguard.isVisibleLw()) { // If keyguard is currently visible, no reason to animate -- GitLab From baf8d0929210763ad570a46157c8055a16fb89c3 Mon Sep 17 00:00:00 2001 From: David Brown Date: Mon, 8 Mar 2010 21:52:59 -0800 Subject: [PATCH 232/458] Accessibility: optionally allow Power key to end the current call. This is part 2 of the fix for bug 2364220 "Accessibility improvements for ending calls". This change updates the POWER key logic in interceptKeyTq() to check the value of Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR, which allows the user to specify that the Power button should hang up while in-call, instead of just turning off the screen. Bug: 2364220 Change-Id: If6d8e3155f7d60142ab6fd61f0a9db7f0b0d95ab --- .../policy/impl/PhoneWindowManager.java | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 06997019b821..f750f23d7cbc 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -260,11 +260,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mLockScreenTimeout; boolean mLockScreenTimerActive; - static final int ENDCALL_HOME = 0x1; - static final int ENDCALL_SLEEPS = 0x2; - static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; + // Behavior of ENDCALL Button. (See Settings.System.END_BUTTON_BEHAVIOR.) int mEndcallBehavior; - + + // Behavior of POWER button while in-call and screen on. + // (See Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR.) + int mIncallPowerBehavior; + int mLandscapeRotation = -1; int mPortraitRotation = -1; @@ -278,11 +280,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { SettingsObserver(Handler handler) { super(handler); } - + void observe() { ContentResolver resolver = mContext.getContentResolver(); resolver.registerContentObserver(Settings.System.getUriFor( Settings.System.END_BUTTON_BEHAVIOR), false, this); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this); resolver.registerContentObserver(Settings.System.getUriFor( Settings.System.ACCELEROMETER_ROTATION), false, this); resolver.registerContentObserver(Settings.System.getUriFor( @@ -548,7 +552,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { View removeView = null; synchronized (mLock) { mEndcallBehavior = Settings.System.getInt(resolver, - Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); + Settings.System.END_BUTTON_BEHAVIOR, + Settings.System.END_BUTTON_BEHAVIOR_DEFAULT); + mIncallPowerBehavior = Settings.Secure.getInt(resolver, + Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR, + Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT); mFancyRotationAnimation = Settings.System.getInt(resolver, "fancy_rotation_anim", 0) != 0 ? 0x80 : 0; int accelerometerDefault = Settings.System.getInt(resolver, @@ -1797,6 +1805,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { || code == KeyEvent.KEYCODE_POWER) { if (down) { boolean handled = false; + boolean hungUp = false; // key repeats are generated by the window manager, and we don't see them // here, so unless the driver is doing something it shouldn't be, we know // this is the real press event. @@ -1804,11 +1813,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (phoneServ != null) { try { if (code == KeyEvent.KEYCODE_ENDCALL) { - handled = phoneServ.endCall(); - } else if (code == KeyEvent.KEYCODE_POWER && phoneServ.isRinging()) { - // Pressing power during incoming call should silence the ringer - phoneServ.silenceRinger(); - handled = true; + handled = hungUp = phoneServ.endCall(); + } else if (code == KeyEvent.KEYCODE_POWER) { + if (phoneServ.isRinging()) { + // Pressing Power while there's a ringing incoming + // call should silence the ringer. + phoneServ.silenceRinger(); + handled = true; + } else if (phoneServ.isOffhook() && + ((mIncallPowerBehavior + & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) + != 0)) { + // Otherwise, if "Power button ends call" is enabled, + // the Power button will hang up any current active call. + handled = hungUp = phoneServ.endCall(); + } } } catch (RemoteException ex) { Log.w(TAG, "ITelephony threw RemoteException" + ex); @@ -1816,8 +1835,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else { Log.w(TAG, "!!! Unable to find ITelephony interface !!!"); } - // power button should turn off screen in addition to hanging up the phone - if ((handled && code != KeyEvent.KEYCODE_POWER) || !screenIsOn) { + + if (!screenIsOn + || (handled && code != KeyEvent.KEYCODE_POWER) + || (handled && hungUp && code == KeyEvent.KEYCODE_POWER)) { mShouldTurnOffOnKeyUp = false; } else { // only try to turn off the screen if we didn't already hang up @@ -1832,8 +1853,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { mShouldTurnOffOnKeyUp = false; boolean gohome, sleeps; if (code == KeyEvent.KEYCODE_ENDCALL) { - gohome = (mEndcallBehavior & ENDCALL_HOME) != 0; - sleeps = (mEndcallBehavior & ENDCALL_SLEEPS) != 0; + gohome = (mEndcallBehavior + & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0; + sleeps = (mEndcallBehavior + & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0; } else { gohome = false; sleeps = true; @@ -2374,4 +2397,3 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mScreenOn; } } - -- GitLab From 5475906f53e2d79807548932dfabbf9945143740 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Thu, 11 Mar 2010 15:46:29 -0800 Subject: [PATCH 233/458] Fix 2428368: Fix most of the lockscreen orientation refresh bugs This change removes the legacy notification of orientation and configuration changed events from KeyguardUpdateMonitor and moves them into the individual activities. This was necessary to guarantee order of events. In addition, to minimize discrepencies due to notification lag, Keyguard screens (LockScreen, PatternUnlock, etc.) are now responsible for handling onConfigurationChanged() notification and forwarding them to LockPatternKeyguardView by a call to recreateMe() with the new configuration. This also removes the hack that used to prevent drawing while the configuration was in flux. Change-Id: I6b72e8c06cebb2c5c83e2debeb478e89b6f6f386 --- .../policy/impl/AccountUnlockScreen.java | 7 +- .../policy/impl/KeyguardScreenCallback.java | 4 +- .../policy/impl/KeyguardUpdateMonitor.java | 88 +------------------ .../policy/impl/LockPatternKeyguardView.java | 66 ++++---------- .../internal/policy/impl/LockScreen.java | 67 +++++++------- .../policy/impl/PasswordUnlockScreen.java | 38 ++++---- .../policy/impl/PatternUnlockScreen.java | 36 ++++---- .../internal/policy/impl/SimUnlockScreen.java | 44 ++++++---- 8 files changed, 129 insertions(+), 221 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index 1aaef8392472..53793deb6565 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -27,6 +27,7 @@ import android.accounts.AuthenticatorException; import android.accounts.AccountManagerCallback; import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; import android.graphics.Rect; import android.telephony.TelephonyManager; import android.text.Editable; @@ -79,10 +80,10 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree /** * AccountUnlockScreen constructor. + * @param configuration */ - public AccountUnlockScreen(Context context, - KeyguardScreenCallback callback, - LockPatternUtils lockPatternUtils) { + public AccountUnlockScreen(Context context,Configuration configuration, + KeyguardScreenCallback callback, LockPatternUtils lockPatternUtils) { super(context); mCallback = callback; mLockPatternUtils = lockPatternUtils; diff --git a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java index 06a5f193b3bb..a84360340c91 100644 --- a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java +++ b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java @@ -16,6 +16,8 @@ package com.android.internal.policy.impl; +import android.content.res.Configuration; + /** * Within a keyguard, there may be several screens that need a callback * to the host keyguard view. @@ -55,7 +57,7 @@ public interface KeyguardScreenCallback extends KeyguardViewCallback { /** * Stay on me, but recreate me (so I can use a different layout). */ - void recreateMe(); + void recreateMe(Configuration config); /** * Take action to send an emergency call. diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index b7bb18416779..b225e56b3b72 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -28,6 +28,7 @@ import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; import android.media.AudioManager; import android.os.Handler; import android.os.Message; +import android.os.SystemClock; import android.provider.Settings; import android.provider.Telephony; import static android.provider.Telephony.Intents.EXTRA_PLMN; @@ -66,8 +67,6 @@ public class KeyguardUpdateMonitor { private final Context mContext; private IccCard.State mSimState = IccCard.State.READY; - private boolean mInPortrait; - private boolean mKeyboardOpen; private boolean mKeyguardBypassEnabled; @@ -84,15 +83,11 @@ public class KeyguardUpdateMonitor { private Handler mHandler; - private ArrayList mConfigurationChangeCallbacks - = Lists.newArrayList(); private ArrayList mInfoCallbacks = Lists.newArrayList(); private ArrayList mSimStateCallbacks = Lists.newArrayList(); private ContentObserver mContentObserver; - // messages for the handler - private static final int MSG_CONFIGURATION_CHANGED = 300; private static final int MSG_TIME_UPDATE = 301; private static final int MSG_BATTERY_UPDATE = 302; private static final int MSG_CARRIER_INFO_UPDATE = 303; @@ -150,9 +145,6 @@ public class KeyguardUpdateMonitor { @Override public void handleMessage(Message msg) { switch (msg.what) { - case MSG_CONFIGURATION_CHANGED: - handleConfigurationChange(); - break; case MSG_TIME_UPDATE: handleTimeUpdate(); break; @@ -209,9 +201,6 @@ public class KeyguardUpdateMonitor { Settings.Secure.DEVICE_PROVISIONED, 0) != 0; } - mInPortrait = queryInPortrait(); - mKeyboardOpen = queryKeyboardOpen(); - // take a guess to start mSimState = IccCard.State.READY; mDevicePluggedIn = true; @@ -221,7 +210,6 @@ public class KeyguardUpdateMonitor { // setup receiver final IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(Intent.ACTION_TIME_TICK); filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_BATTERY_CHANGED); @@ -236,9 +224,7 @@ public class KeyguardUpdateMonitor { final String action = intent.getAction(); if (DEBUG) Log.d(TAG, "received broadcast " + action); - if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_CONFIGURATION_CHANGED)); - } else if (Intent.ACTION_TIME_TICK.equals(action) + if (Intent.ACTION_TIME_TICK.equals(action) || Intent.ACTION_TIME_CHANGED.equals(action) || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) { mHandler.sendMessage(mHandler.obtainMessage(MSG_TIME_UPDATE)); @@ -284,29 +270,6 @@ public class KeyguardUpdateMonitor { } } - /** - * Handle {@link #MSG_CONFIGURATION_CHANGED} - */ - private void handleConfigurationChange() { - if (DEBUG) Log.d(TAG, "handleConfigurationChange"); - - final boolean inPortrait = queryInPortrait(); - if (mInPortrait != inPortrait) { - mInPortrait = inPortrait; - for (int i = 0; i < mConfigurationChangeCallbacks.size(); i++) { - mConfigurationChangeCallbacks.get(i).onOrientationChange(inPortrait); - } - } - - final boolean keyboardOpen = queryKeyboardOpen(); - if (mKeyboardOpen != keyboardOpen) { - mKeyboardOpen = keyboardOpen; - for (int i = 0; i < mConfigurationChangeCallbacks.size(); i++) { - mConfigurationChangeCallbacks.get(i).onKeyboardChange(keyboardOpen); - } - } - } - /** * Handle {@link #MSG_TIME_UPDATE} */ @@ -393,23 +356,6 @@ public class KeyguardUpdateMonitor { return false; } - /** - * What is the current orientation? - */ - boolean queryInPortrait() { - final Configuration configuration = mContext.getResources().getConfiguration(); - return configuration.orientation == Configuration.ORIENTATION_PORTRAIT; - } - - /** - * Is the (hard) keyboard currently open? - */ - boolean queryKeyboardOpen() { - final Configuration configuration = mContext.getResources().getConfiguration(); - - return configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO; - } - /** * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION} * @return The string to use for the plmn, or null if it should not be shown. @@ -455,20 +401,10 @@ public class KeyguardUpdateMonitor { * {@link InfoCallback} or {@link SimStateCallback} */ public void removeCallback(Object observer) { - mConfigurationChangeCallbacks.remove(observer); mInfoCallbacks.remove(observer); mSimStateCallbacks.remove(observer); } - /** - * Callback for configuration changes. - */ - interface ConfigurationChangeCallback { - void onOrientationChange(boolean inPortrait); - - void onKeyboardChange(boolean isKeyboardOpen); - } - /** * Callback for general information relevant to lock screen. */ @@ -506,18 +442,6 @@ public class KeyguardUpdateMonitor { void onSimStateChanged(IccCard.State simState); } - /** - * Register to receive notifications about configuration changes. - * @param callback The callback. - */ - public void registerConfigurationChangeCallback(ConfigurationChangeCallback callback) { - if (!mConfigurationChangeCallbacks.contains(callback)) { - mConfigurationChangeCallbacks.add(callback); - } else { - Log.e(TAG, "Object tried to add another CONFIG callback", new Exception("Whoops")); - } - } - /** * Register to receive notifications about general keyguard information * (see {@link InfoCallback}. @@ -556,14 +480,6 @@ public class KeyguardUpdateMonitor { mSimState = IccCard.State.READY; } - public boolean isInPortrait() { - return mInPortrait; - } - - public boolean isKeyboardOpen() { - return mKeyboardOpen; - } - public boolean isKeyguardBypassEnabled() { return mKeyguardBypassEnabled; } diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 8bda7601dbdf..8ec1e74c5436 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -34,15 +34,14 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.os.SystemClock; import android.os.SystemProperties; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.View; -import android.view.ViewGroup; import android.view.WindowManager; import java.io.IOException; @@ -79,7 +78,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase private boolean mScreenOn = false; private boolean mEnableFallback = false; // assume no fallback UI until we know better - /** * The current {@link KeyguardScreen} will use this to communicate back to us. */ @@ -156,10 +154,14 @@ public class LockPatternKeyguardView extends KeyguardViewBase private final LockPatternUtils mLockPatternUtils; private int mNumAccounts; - private boolean mIsPortrait; private UnlockMode mCurrentUnlockMode = UnlockMode.Unknown; + /** + * The current configuration. + */ + private Configuration mConfiguration; + /** * @return Whether we are stuck on the lock screen because the sim is * missing. @@ -203,6 +205,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase KeyguardWindowController controller) { super(context); + mConfiguration = context.getResources().getConfiguration(); mEnableFallback = false; mRequiresSim = @@ -257,7 +260,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase return mIsVerifyUnlockOnly; } - public void recreateMe() { + public void recreateMe(Configuration config) { + mConfiguration = config; recreateScreens(); } @@ -370,23 +374,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase // be removed once the race condition is fixed. See bugs 2262578 and 2292713. @Override protected void dispatchDraw(Canvas canvas) { - final int orientation = getResources().getConfiguration().orientation; - if (mIsPortrait && Configuration.ORIENTATION_PORTRAIT != orientation - || getResources().getBoolean(R.bool.lockscreen_isPortrait) != mIsPortrait) { - // Make sure we redraw once things settle down. - // Log.v(TAG, "dispatchDraw(): not drawing because state is inconsistent"); - postInvalidate(); - - // In order to minimize flashing, draw the first child's background for now. - ViewGroup view = (ViewGroup) (mMode == Mode.LockScreen ? mLockScreen : mUnlockScreen); - if (view != null && view.getChildAt(0) != null) { - Drawable background = view.getChildAt(0).getBackground(); - if (background != null) { - background.draw(canvas); - } - } - return; - } + if (DEBUG) Log.v(TAG, "*** dispatchDraw() time: " + SystemClock.elapsedRealtime()); super.dispatchDraw(canvas); } @@ -550,19 +538,18 @@ public class LockPatternKeyguardView extends KeyguardViewBase View createLockScreen() { return new LockScreen( mContext, + mConfiguration, mLockPatternUtils, mUpdateMonitor, mKeyguardScreenCallback); } View createUnlockScreenFor(UnlockMode unlockMode) { - // Capture the orientation this layout was created in. - mIsPortrait = getResources().getBoolean(R.bool.lockscreen_isPortrait); - View unlockView = null; if (unlockMode == UnlockMode.Pattern) { PatternUnlockScreen view = new PatternUnlockScreen( mContext, + mConfiguration, mLockPatternUtils, mUpdateMonitor, mKeyguardScreenCallback, @@ -574,6 +561,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase } else if (unlockMode == UnlockMode.SimPin) { unlockView = new SimUnlockScreen( mContext, + mConfiguration, mUpdateMonitor, mKeyguardScreenCallback, mLockPatternUtils); @@ -581,6 +569,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase try { unlockView = new AccountUnlockScreen( mContext, + mConfiguration, mKeyguardScreenCallback, mLockPatternUtils); } catch (IllegalStateException e) { @@ -601,6 +590,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase } else if (unlockMode == UnlockMode.Password) { unlockView = new PasswordUnlockScreen( mContext, + mConfiguration, mLockPatternUtils, mUpdateMonitor, mKeyguardScreenCallback); @@ -611,32 +601,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase return unlockView; } - private View getUnlockScreenForCurrentUnlockMode() { - final UnlockMode unlockMode = getUnlockMode(); - - // if a screen exists for the correct mode, we're done - if (unlockMode == mUnlockScreenMode) { - return mUnlockScreen; - } - - // remember the mode - mUnlockScreenMode = unlockMode; - - // unlock mode has changed and we have an existing old unlock screen - // to clean up - if (mScreenOn && (mUnlockScreen.getVisibility() == View.VISIBLE)) { - ((KeyguardScreen) mUnlockScreen).onPause(); - } - ((KeyguardScreen) mUnlockScreen).cleanUp(); - removeViewInLayout(mUnlockScreen); - - // create the new one - mUnlockScreen = createUnlockScreenFor(unlockMode); - mUnlockScreen.setVisibility(View.INVISIBLE); - addView(mUnlockScreen); - return mUnlockScreen; - } - /** * Given the current state of things, what should be the initial mode of * the lock screen (lock or unlock). diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index 22a43367e90c..ae1367a075a6 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -18,15 +18,13 @@ package com.android.internal.policy.impl; import com.android.internal.R; import com.android.internal.telephony.IccCard; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.Phone.State; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.SlidingTab; import android.content.Context; +import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.ColorStateList; -import android.telephony.TelephonyManager; import android.text.format.DateFormat; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -36,6 +34,7 @@ import android.widget.*; import android.graphics.drawable.Drawable; import android.util.Log; import android.media.AudioManager; +import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; @@ -48,8 +47,7 @@ import java.io.File; * past it, as applicable. */ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateMonitor.InfoCallback, - KeyguardUpdateMonitor.SimStateCallback, KeyguardUpdateMonitor.ConfigurationChangeCallback, - SlidingTab.OnTriggerListener { + KeyguardUpdateMonitor.SimStateCallback, SlidingTab.OnTriggerListener { private static final boolean DBG = false; private static final String TAG = "LockScreen"; @@ -70,6 +68,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private TextView mScreenLocked; private Button mEmergencyCallButton; + // current configuration state of keyboard and display + private int mKeyboardHidden; + private int mCreationOrientation; + // are we showing battery information? private boolean mShowingBatteryInfo = false; @@ -88,7 +90,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private AudioManager mAudioManager; private String mDateFormatString; private java.text.DateFormat mTimeFormat; - private boolean mCreatedInPortrait; private boolean mEnableMenuKeyInLockScreen; /** @@ -159,12 +160,13 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM /** * @param context Used to setup the view. + * @param configuration The current configuration. Used to use when selecting layout, etc. * @param lockPatternUtils Used to know the state of the lock pattern settings. * @param updateMonitor Used to register for updates on various keyguard related * state, and query the initial state at setup. * @param callback Used to communicate back to the host keyguard view. */ - LockScreen(Context context, LockPatternUtils lockPatternUtils, + LockScreen(Context context, Configuration configuration, LockPatternUtils lockPatternUtils, KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback) { super(context); @@ -174,10 +176,13 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mEnableMenuKeyInLockScreen = shouldEnableMenuKey(); - mCreatedInPortrait = updateMonitor.isInPortrait(); + mCreationOrientation = configuration.orientation; + + mKeyboardHidden = configuration.hardKeyboardHidden; final LayoutInflater inflater = LayoutInflater.from(context); - if (mCreatedInPortrait) { + if (DBG) Log.v(TAG, "Creation orientation = " + mCreationOrientation); + if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) { inflater.inflate(R.layout.keyguard_screen_tab_unlock, this, true); } else { inflater.inflate(R.layout.keyguard_screen_tab_unlock_land, this, true); @@ -211,7 +216,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM updateMonitor.registerInfoCallback(this); updateMonitor.registerSimStateCallback(this); - updateMonitor.registerConfigurationChangeCallback(this); mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mSilentMode = isSilentMode(); @@ -234,14 +238,14 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } private void updateRightTabResources() { - boolean vibe = mSilentMode + 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_off ) : R.drawable.ic_jog_dial_sound_on, - mSilentMode ? R.drawable.jog_tab_target_yellow + 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, @@ -288,7 +292,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM Settings.System.VIBRATE_IN_SILENT, 1) == 1); mAudioManager.setRingerMode(vibe - ? AudioManager.RINGER_MODE_VIBRATE + ? AudioManager.RINGER_MODE_VIBRATE : AudioManager.RINGER_MODE_SILENT); } else { mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); @@ -368,7 +372,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private Runnable mPendingR1; private Runnable mPendingR2; - private void refreshAlarmDisplay() { mNextAlarm = mLockPatternUtils.getNextAlarm(); if (mNextAlarm != null) { @@ -457,13 +460,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM updateLayout(mStatus); } - private void addRelativeLayoutRule(View view, int rule, int viewId) { - final RelativeLayout.LayoutParams layoutParams = - (RelativeLayout.LayoutParams) view.getLayoutParams(); - layoutParams.addRule(rule, viewId); - view.setLayoutParams(layoutParams); - } - /** * Determine the current status of the lock screen given the sim state and other stuff. */ @@ -604,20 +600,27 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM updateStatusLines(); } - - public void onOrientationChange(boolean inPortrait) { - if (inPortrait != mCreatedInPortrait) { - mCallback.recreateMe(); + /** {@inheritDoc} */ + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (DBG) { + Log.v(TAG, "onConfigurationChanged() time " + SystemClock.elapsedRealtime()); + if (getResources().getConfiguration().orientation != newConfig.orientation) { + Log.e(TAG, "mismatchConfig: ", new Exception("stack trace:")); + } } - } - - public void onKeyboardChange(boolean isKeyboardOpen) { - if (mUpdateMonitor.isKeyguardBypassEnabled() && isKeyboardOpen) { - mCallback.goToUnlockScreen(); + if (newConfig.orientation != mCreationOrientation) { + mCallback.recreateMe(newConfig); + } else if (newConfig.hardKeyboardHidden != mKeyboardHidden) { + mKeyboardHidden = newConfig.hardKeyboardHidden; + final boolean isKeyboardOpen = mKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO; + if (mUpdateMonitor.isKeyguardBypassEnabled() && isKeyboardOpen) { + mCallback.goToUnlockScreen(); + } } } - /** {@inheritDoc} */ public boolean needsInput() { return false; diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java index c52ef53c742f..0bbab3e4793d 100644 --- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -17,6 +17,7 @@ package com.android.internal.policy.impl; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Rect; import com.android.internal.widget.LockPatternUtils; @@ -42,37 +43,38 @@ import com.android.internal.widget.PasswordEntryKeyboardHelper; * Displays a dialer-like interface or alphanumeric (latin-1) key entry for the user to enter * an unlock password */ -public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener, - KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.InfoCallback, - OnEditorActionListener { - - private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; +public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen, + View.OnClickListener, KeyguardUpdateMonitor.InfoCallback, OnEditorActionListener { private final KeyguardUpdateMonitor mUpdateMonitor; private final KeyguardScreenCallback mCallback; - private final boolean mCreatedWithKeyboardOpen; - private EditText mPasswordEntry; private Button mEmergencyCallButton; private LockPatternUtils mLockPatternUtils; private PasswordEntryKeyboardView mKeyboardView; private PasswordEntryKeyboardHelper mKeyboardHelper; + private int mCreationOrientation; + private int mKeyboardHidden; + // 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. private static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3; - public PasswordUnlockScreen(Context context, LockPatternUtils lockPatternUtils, - KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback) { + public PasswordUnlockScreen(Context context, Configuration configuration, + LockPatternUtils lockPatternUtils, KeyguardUpdateMonitor updateMonitor, + KeyguardScreenCallback callback) { super(context); + + mKeyboardHidden = configuration.hardKeyboardHidden; + mCreationOrientation = configuration.orientation; mUpdateMonitor = updateMonitor; mCallback = callback; - mCreatedWithKeyboardOpen = mUpdateMonitor.isKeyboardOpen(); mLockPatternUtils = lockPatternUtils; LayoutInflater layoutInflater = LayoutInflater.from(context); - if (mUpdateMonitor.isInPortrait()) { + if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) { layoutInflater.inflate(R.layout.keyguard_screen_password_portrait, this, true); } else { layoutInflater.inflate(R.layout.keyguard_screen_password_landscape, this, true); @@ -85,13 +87,13 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mEmergencyCallButton = (Button) findViewById(R.id.emergencyCall); mEmergencyCallButton.setOnClickListener(this); mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); - mUpdateMonitor.registerConfigurationChangeCallback(this); mKeyboardHelper = new PasswordEntryKeyboardHelper(context, mKeyboardView, this); mKeyboardHelper.setKeyboardMode(isAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC); - mKeyboardView.setVisibility(mCreatedWithKeyboardOpen ? View.INVISIBLE : View.VISIBLE); + mKeyboardView.setVisibility(mKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO + ? View.INVISIBLE : View.VISIBLE); mPasswordEntry.requestFocus(); // This allows keyboards with overlapping qwerty/numeric keys to choose just the @@ -104,7 +106,6 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mKeyboardHelper.setVibratePattern(mLockPatternUtils.isTactileFeedbackEnabled() ? com.android.internal.R.array.config_virtualKeyVibePattern : 0); - } @Override @@ -162,8 +163,13 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen return false; } - public void onOrientationChange(boolean inPortrait) { - mCallback.recreateMe(); + /** {@inheritDoc} */ + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (newConfig.orientation != mCreationOrientation) { + mCallback.recreateMe(newConfig); + } } public void onKeyboardChange(boolean isKeyboardOpen) { diff --git a/policy/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/com/android/internal/policy/impl/PatternUnlockScreen.java index d09b358f1ab8..a93b4629d784 100644 --- a/policy/com/android/internal/policy/impl/PatternUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PatternUnlockScreen.java @@ -17,6 +17,7 @@ package com.android.internal.policy.impl; import android.content.Context; +import android.content.res.Configuration; import android.os.CountDownTimer; import android.os.SystemClock; import android.view.LayoutInflater; @@ -25,7 +26,6 @@ import android.view.ViewGroup; import android.view.MotionEvent; import android.widget.Button; import android.widget.TextView; -import android.telephony.TelephonyManager; import android.text.format.DateFormat; import android.text.TextUtils; import android.util.Log; @@ -44,8 +44,8 @@ import java.util.Date; * the user how to unlock their device, or make an emergency call. */ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient - implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback, - KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback { + implements KeyguardScreen, KeyguardUpdateMonitor.InfoCallback, + KeyguardUpdateMonitor.SimStateCallback { private static final boolean DEBUG = false; private static final String TAG = "UnlockScreen"; @@ -75,8 +75,6 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient */ private boolean mEnableFallback; - private boolean mCreatedInPortrait; - private String mDateFormatString; private TextView mCarrier; @@ -124,6 +122,7 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient private Button mForgotPatternButton; private Button mEmergencyAlone; private Button mEmergencyTogether; + private int mCreationOrientation; enum FooterMode { Normal, @@ -150,6 +149,7 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient /** * @param context The context. + * @param configuration * @param lockPatternUtils Used to lookup lock pattern settings. * @param updateMonitor Used to lookup state affecting keyguard. * @param callback Used to notify the manager when we're done, etc. @@ -159,7 +159,7 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient * backup option). */ PatternUnlockScreen(Context context, - LockPatternUtils lockPatternUtils, + Configuration configuration, LockPatternUtils lockPatternUtils, KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback, int totalFailedAttempts) { @@ -168,7 +168,8 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient mUpdateMonitor = updateMonitor; mCallback = callback; mTotalFailedPatternAttempts = totalFailedAttempts; - mFailedPatternAttemptsSinceLastTimeout = totalFailedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; + mFailedPatternAttemptsSinceLastTimeout = + totalFailedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; if (DEBUG) Log.d(TAG, "UnlockScreen() ctor: totalFailedAttempts=" @@ -176,10 +177,13 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient + mFailedPatternAttemptsSinceLastTimeout ); - if (mUpdateMonitor.isInPortrait()) { - LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_portrait, this, true); + mCreationOrientation = configuration.orientation; + + LayoutInflater inflater = LayoutInflater.from(context); + if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) { + inflater.inflate(R.layout.keyguard_screen_unlock_portrait, this, true); } else { - LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_landscape, this, true); + inflater.inflate(R.layout.keyguard_screen_unlock_landscape, this, true); } mCarrier = (TextView) findViewById(R.id.carrier); @@ -241,10 +245,8 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient // assume normal footer mode for now updateFooter(FooterMode.Normal); - mCreatedInPortrait = updateMonitor.isInPortrait(); updateMonitor.registerInfoCallback(this); updateMonitor.registerSimStateCallback(this); - updateMonitor.registerConfigurationChangeCallback(this); setFocusableInTouchMode(true); // Required to get Marquee to work. @@ -397,12 +399,12 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient } - - /** {@inheritDoc} */ - public void onOrientationChange(boolean inPortrait) { - if (inPortrait != mCreatedInPortrait) { - mCallback.recreateMe(); + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (newConfig.orientation != mCreationOrientation) { + mCallback.recreateMe(newConfig); } } diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java index d5da274d5fb8..d92b961da22a 100644 --- a/policy/com/android/internal/policy/impl/SimUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/SimUnlockScreen.java @@ -19,8 +19,10 @@ package com.android.internal.policy.impl; import android.app.Dialog; import android.app.ProgressDialog; import android.content.Context; +import android.content.res.Configuration; import android.os.RemoteException; import android.os.ServiceManager; + import com.android.internal.telephony.ITelephony; import com.android.internal.widget.LockPatternUtils; @@ -38,15 +40,13 @@ import com.android.internal.R; * Displays a dialer like interface to unlock the SIM PIN. */ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener, - KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.InfoCallback { + KeyguardUpdateMonitor.InfoCallback { private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; private final KeyguardUpdateMonitor mUpdateMonitor; private final KeyguardScreenCallback mCallback; - private final boolean mCreatedWithKeyboardOpen; - private TextView mHeaderText; private TextView mPinText; @@ -62,20 +62,28 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie private LockPatternUtils mLockPatternUtils; + private int mCreationOrientation; + + private int mKeyboardHidden; + private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; - public SimUnlockScreen(Context context, KeyguardUpdateMonitor updateMonitor, - KeyguardScreenCallback callback, LockPatternUtils lockpatternutils) { + public SimUnlockScreen(Context context, Configuration configuration, + KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback, + LockPatternUtils lockpatternutils) { super(context); mUpdateMonitor = updateMonitor; mCallback = callback; - mCreatedWithKeyboardOpen = mUpdateMonitor.isKeyboardOpen(); + + mCreationOrientation = configuration.orientation; + mKeyboardHidden = configuration.hardKeyboardHidden; mLockPatternUtils = lockpatternutils; - if (mCreatedWithKeyboardOpen) { - LayoutInflater.from(context).inflate(R.layout.keyguard_screen_sim_pin_landscape, this, true); + LayoutInflater inflater = LayoutInflater.from(context); + if (mKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) { + inflater.inflate(R.layout.keyguard_screen_sim_pin_landscape, this, true); } else { - LayoutInflater.from(context).inflate(R.layout.keyguard_screen_sim_pin_portrait, this, true); + inflater.inflate(R.layout.keyguard_screen_sim_pin_portrait, this, true); new TouchInput(); } @@ -94,7 +102,6 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie mEmergencyCallButton.setOnClickListener(this); mOkButton.setOnClickListener(this); - mUpdateMonitor.registerConfigurationChangeCallback(this); setFocusableInTouchMode(true); } @@ -272,11 +279,18 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie mEnteredPin[mEnteredDigits++] = digit; } - public void onOrientationChange(boolean inPortrait) {} - - public void onKeyboardChange(boolean isKeyboardOpen) { - if (isKeyboardOpen != mCreatedWithKeyboardOpen) { - mCallback.recreateMe(); + /** {@inheritDoc} */ + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (newConfig.orientation != mCreationOrientation) { + mCallback.recreateMe(newConfig); + } else if (newConfig.hardKeyboardHidden != mKeyboardHidden) { + mKeyboardHidden = newConfig.hardKeyboardHidden; + final boolean isKeyboardOpen = mKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO; + if (mUpdateMonitor.isKeyguardBypassEnabled() && isKeyboardOpen) { + mCallback.goToUnlockScreen(); + } } } -- GitLab From 687a3274f054ec2c48e70c56d8fcb508f2f82363 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Sat, 13 Mar 2010 15:44:47 -0500 Subject: [PATCH 234/458] Remove the secure lock icon from the status bar. Added in I0e08a952904cc4728621953a42806edf26eb8e46, but takes up too much room. An undocumented system setting, "show_status_bar_lock", can be set to 1 (e.g. in Spare Parts) to bring this back. Bug: 2511090 Change-Id: I8869ac18c303a786eeb7f1a0c4ae08529b45d59c --- .../policy/impl/KeyguardViewMediator.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 526dcbc66d1c..862e328b5b7f 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -145,6 +145,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private Context mContext; private AlarmManager mAlarmManager; private StatusBarManager mStatusBarManager; + private boolean mShowLockIcon = false; private IBinder mSecureLockIcon = null; private boolean mSystemReady; @@ -279,6 +280,9 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mUserPresentIntent = new Intent(Intent.ACTION_USER_PRESENT); mUserPresentIntent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + + final ContentResolver cr = mContext.getContentResolver(); + mShowLockIcon = (Settings.System.getInt(cr, "show_status_bar_lock", 0) == 1); } /** @@ -1019,16 +1023,18 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (mStatusBarManager == null) { Log.w(TAG, "Could not get status bar manager"); } else { - // Give feedback to user when secure keyguard is active and engaged - if (mShowing && isSecure()) { - if (mSecureLockIcon == null) { - mSecureLockIcon = mStatusBarManager.addIcon("secure", - com.android.internal.R.drawable.stat_sys_secure, 0); - } - } else { - if (mSecureLockIcon != null) { - mStatusBarManager.removeIcon(mSecureLockIcon); - mSecureLockIcon = null; + if (mShowLockIcon) { + // Give feedback to user when secure keyguard is active and engaged + if (mShowing && isSecure()) { + if (mSecureLockIcon == null) { + mSecureLockIcon = mStatusBarManager.addIcon("secure", + com.android.internal.R.drawable.stat_sys_secure, 0); + } + } else { + if (mSecureLockIcon != null) { + mStatusBarManager.removeIcon(mSecureLockIcon); + mSecureLockIcon = null; + } } } -- GitLab From 0060a9b544e0a64ba2a7cd6f0025b6600e08f372 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Mon, 15 Mar 2010 23:09:57 -0400 Subject: [PATCH 235/458] Suppress lock sound effect on screen timeout. Bug: 2512130 (without regressing http://b/2453032) Change-Id: I79c90e6f59b95c3096808ad5ee9845369a2e50ce --- .../policy/impl/KeyguardViewMediator.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 862e328b5b7f..c255041df36a 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -149,7 +149,11 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private IBinder mSecureLockIcon = null; private boolean mSystemReady; - private boolean mFirstShow = true; + + // Whether the next call to playSounds() should be skipped. Defaults to + // true because the first lock (on boot) should be silent. + private boolean mSuppressNextLockSound = true; + /** Low level access to the power manager for enableUserActivity. Having this * requires that we run in the system process. */ @@ -689,6 +693,10 @@ public class KeyguardViewMediator implements KeyguardViewCallback, + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence); if (mDelayedShowingSequence == sequence) { + // Don't play lockscreen SFX if the screen went off due to + // timeout. + mSuppressNextLockSound = true; + doKeyguard(); } } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { @@ -926,6 +934,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private void playSounds(boolean locked) { // User feedback for keyguard. + + if (mSuppressNextLockSound) { + mSuppressNextLockSound = false; + return; + } + final ContentResolver cr = mContext.getContentResolver(); if (Settings.System.getInt(cr, Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1) == 1) { @@ -961,11 +975,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (DEBUG) Log.d(TAG, "handleShow"); if (!mSystemReady) return; - if (mFirstShow) { - mFirstShow = false; - } else { - playSounds(true); - } + playSounds(true); mKeyguardViewManager.show(); mShowing = true; -- GitLab From f1818ffd82ad288f52e81dae8eccc44db10c6564 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Wed, 17 Mar 2010 19:14:18 -0700 Subject: [PATCH 236/458] Fix 2520598: Disable password entry in keyguard while in lockout The password unlock wasn't abiding by the 30s lockout rule. This change adds the necessary logic and countdown timer to disable text entry while in lockout mode. After 30s, text entry is re-enabled until the next lockout count is reached. Change-Id: I4d860565cad91cb88c36615b40d1837a5d97fe21 --- .../policy/impl/LockPatternKeyguardView.java | 6 ++- .../policy/impl/PasswordUnlockScreen.java | 43 +++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 8ec1e74c5436..3deee6f79560 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -300,11 +300,13 @@ public class LockPatternKeyguardView extends KeyguardViewBase if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts + " (enableFallback=" + mEnableFallback + ")"); - if (mEnableFallback && failedAttempts == + final boolean usingLockPattern = mLockPatternUtils.getPasswordMode() + == LockPatternUtils.MODE_PATTERN; + if (usingLockPattern && mEnableFallback && failedAttempts == (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { showAlmostAtAccountLoginDialog(); - } else if (mEnableFallback + } else if (usingLockPattern && mEnableFallback && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { mLockPatternUtils.setPermanentlyLocked(true); updateScreen(mMode); diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java index 0bbab3e4793d..e08fe4f18e18 100644 --- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -20,9 +20,12 @@ import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; +import com.android.internal.policy.impl.PatternUnlockScreen.FooterMode; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.PasswordEntryKeyboardView; +import android.os.CountDownTimer; +import android.os.SystemClock; import android.telephony.TelephonyManager; import android.text.method.DigitsKeyListener; import android.text.method.TextKeyListener; @@ -57,6 +60,8 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen private int mCreationOrientation; private int mKeyboardHidden; + private CountDownTimer mCountdownTimer; + private TextView mTitle; // 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. @@ -87,6 +92,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen 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 @@ -130,6 +136,12 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mPasswordEntry.setText(""); mPasswordEntry.requestFocus(); mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); + + // if the user is currently locked out, enforce it. + long deadline = mLockPatternUtils.getLockoutAttemptDeadline(); + if (deadline != 0) { + handleAttemptLockout(deadline); + } } /** {@inheritDoc} */ @@ -153,10 +165,41 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen // to avoid accidental lockout, only count attempts that are long enough to be a // real password. This may require some tweaking. mCallback.reportFailedUnlockAttempt(); + if (0 == (mUpdateMonitor.getFailedAttempts() + % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { + long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); + handleAttemptLockout(deadline); + } } mPasswordEntry.setText(""); } + // Prevent user from using the PIN/Password entry until scheduled deadline. + private void handleAttemptLockout(long elapsedRealtimeDeadline) { + mPasswordEntry.setEnabled(false); + mKeyboardView.setEnabled(false); + long elapsedRealtime = SystemClock.elapsedRealtime(); + mCountdownTimer = new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) { + + @Override + public void onTick(long millisUntilFinished) { + int secondsRemaining = (int) (millisUntilFinished / 1000); + String instructions = getContext().getString( + R.string.lockscreen_too_many_failed_attempts_countdown, + secondsRemaining); + mTitle.setText(instructions); + } + + @Override + public void onFinish() { + mPasswordEntry.setEnabled(true); + mTitle.setText(R.string.keyguard_password_enter_password_code); + mKeyboardView.setEnabled(true); + } + }.start(); + } + + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { mCallback.pokeWakelock(); -- GitLab From 75787398fa5db9add16f3d3bc298198ed2c6671f Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 18 Mar 2010 01:04:37 -0700 Subject: [PATCH 237/458] Policy part of fixing issue #2519590: Lock screen stuck in landscape mode Change-Id: Id7f3a7102a86f4fecb7f7ef40b1275b75e27dac4 --- .../policy/impl/LockPatternKeyguardView.java | 17 ++++++-- .../internal/policy/impl/LockScreen.java | 41 ++++++++++++++----- .../policy/impl/PasswordUnlockScreen.java | 8 ++++ .../policy/impl/PatternUnlockScreen.java | 18 ++++++++ .../internal/policy/impl/SimUnlockScreen.java | 20 +++++++-- 5 files changed, 86 insertions(+), 18 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 3deee6f79560..da51ad052f7e 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -60,6 +60,8 @@ import java.io.IOException; public class LockPatternKeyguardView extends KeyguardViewBase implements AccountManagerCallback { + static final boolean DEBUG_CONFIGURATION = false; + // time after launching EmergencyDialer before the screen goes blank. private static final int EMERGENCY_CALL_TIMEOUT = 10000; @@ -413,7 +415,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase ((KeyguardScreen) mLockScreen).onPause(); } ((KeyguardScreen) mLockScreen).cleanUp(); - removeViewInLayout(mLockScreen); + removeView(mLockScreen); mLockScreen = createLockScreen(); mLockScreen.setVisibility(View.INVISIBLE); @@ -425,7 +427,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase ((KeyguardScreen) mUnlockScreen).onPause(); } ((KeyguardScreen) mUnlockScreen).cleanUp(); - removeViewInLayout(mUnlockScreen); + removeView(mUnlockScreen); final UnlockMode unlockMode = getUnlockMode(); mUnlockScreen = createUnlockScreenFor(unlockMode); @@ -502,6 +504,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase private void updateScreen(final Mode mode) { + if (DEBUG_CONFIGURATION) Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode + + " last mode=" + mMode, new RuntimeException()); + mMode = mode; // Re-create the unlock screen if necessary. This is primarily required to properly handle @@ -517,7 +522,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase // flag is set mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); - + if (DEBUG_CONFIGURATION) { + Log.v(TAG, "Gone=" + goneScreen); + Log.v(TAG, "Visible=" + visibleScreen); + } + if (mScreenOn) { if (goneScreen.getVisibility() == View.VISIBLE) { ((KeyguardScreen) goneScreen).onPause(); @@ -529,7 +538,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase goneScreen.setVisibility(View.GONE); visibleScreen.setVisibility(View.VISIBLE); - + requestLayout(); if (!visibleScreen.requestFocus()) { throw new IllegalStateException("keyguard screen must be able to take " diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index ae1367a075a6..baed9ebcea32 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -180,6 +180,12 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mKeyboardHidden = configuration.hardKeyboardHidden; + if (LockPatternKeyguardView.DEBUG_CONFIGURATION) { + Log.v(TAG, "***** CREATING LOCK SCREEN", new RuntimeException()); + Log.v(TAG, "Cur orient=" + mCreationOrientation + + " res orient=" + context.getResources().getConfiguration().orientation); + } + final LayoutInflater inflater = LayoutInflater.from(context); if (DBG) Log.v(TAG, "Creation orientation = " + mCreationOrientation); if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) { @@ -600,16 +606,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM updateStatusLines(); } - /** {@inheritDoc} */ - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - if (DBG) { - Log.v(TAG, "onConfigurationChanged() time " + SystemClock.elapsedRealtime()); - if (getResources().getConfiguration().orientation != newConfig.orientation) { - Log.e(TAG, "mismatchConfig: ", new Exception("stack trace:")); - } - } + void updateConfiguration() { + Configuration newConfig = getResources().getConfiguration(); if (newConfig.orientation != mCreationOrientation) { mCallback.recreateMe(newConfig); } else if (newConfig.hardKeyboardHidden != mKeyboardHidden) { @@ -620,6 +618,29 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } } } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (LockPatternKeyguardView.DEBUG_CONFIGURATION) { + Log.v(TAG, "***** LOCK ATTACHED TO WINDOW"); + Log.v(TAG, "Cur orient=" + mCreationOrientation + + ", new config=" + getResources().getConfiguration()); + } + updateConfiguration(); + } + + /** {@inheritDoc} */ + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (LockPatternKeyguardView.DEBUG_CONFIGURATION) { + Log.w(TAG, "***** LOCK CONFIG CHANGING", new RuntimeException()); + Log.v(TAG, "Cur orient=" + mCreationOrientation + + ", new config=" + newConfig); + } + updateConfiguration(); + } /** {@inheritDoc} */ public boolean needsInput() { diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java index e08fe4f18e18..07eaf9369f92 100644 --- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -206,6 +206,14 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen return false; } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (getResources().getConfiguration().orientation != mCreationOrientation) { + mCallback.recreateMe(getResources().getConfiguration()); + } + } + /** {@inheritDoc} */ @Override protected void onConfigurationChanged(Configuration newConfig) { diff --git a/policy/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/com/android/internal/policy/impl/PatternUnlockScreen.java index a93b4629d784..418e24392279 100644 --- a/policy/com/android/internal/policy/impl/PatternUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PatternUnlockScreen.java @@ -398,11 +398,29 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient public void onSimStateChanged(IccCard.State simState) { } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (LockPatternKeyguardView.DEBUG_CONFIGURATION) { + Log.v(TAG, "***** PATTERN ATTACHED TO WINDOW"); + Log.v(TAG, "Cur orient=" + mCreationOrientation + + ", new config=" + getResources().getConfiguration()); + } + if (getResources().getConfiguration().orientation != mCreationOrientation) { + mCallback.recreateMe(getResources().getConfiguration()); + } + } + /** {@inheritDoc} */ @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); + if (LockPatternKeyguardView.DEBUG_CONFIGURATION) { + Log.v(TAG, "***** PATTERN CONFIGURATION CHANGED"); + Log.v(TAG, "Cur orient=" + mCreationOrientation + + ", new config=" + getResources().getConfiguration()); + } if (newConfig.orientation != mCreationOrientation) { mCallback.recreateMe(newConfig); } diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java index d92b961da22a..5518e11ab639 100644 --- a/policy/com/android/internal/policy/impl/SimUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/SimUnlockScreen.java @@ -279,10 +279,8 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie mEnteredPin[mEnteredDigits++] = digit; } - /** {@inheritDoc} */ - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); + void updateConfiguration() { + Configuration newConfig = getResources().getConfiguration(); if (newConfig.orientation != mCreationOrientation) { mCallback.recreateMe(newConfig); } else if (newConfig.hardKeyboardHidden != mKeyboardHidden) { @@ -292,6 +290,20 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie mCallback.goToUnlockScreen(); } } + + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + updateConfiguration(); + } + + /** {@inheritDoc} */ + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + updateConfiguration(); } /** -- GitLab From ebcc51d39c340f6fdafa828bb0fe715ffaa8658d Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Fri, 19 Mar 2010 23:18:02 +0900 Subject: [PATCH 238/458] Accept media files by file extension in case insensitive manner. Change-Id: I8e246010c96802ae87960797607fc8f8f2ab6031 --- media/libmediaplayerservice/MediaPlayerService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index df673a4dbb85..49032e7a6554 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -682,7 +682,7 @@ player_type getPlayerType(const char* url) int len = strlen(FILE_EXTS[i].extension); int start = lenURL - len; if (start > 0) { - if (!strncmp(url + start, FILE_EXTS[i].extension, len)) { + if (!strncasecmp(url + start, FILE_EXTS[i].extension, len)) { return FILE_EXTS[i].playertype; } } -- GitLab From cf59a0b72d3fa6bfe21b3c4cab317ef06496961e Mon Sep 17 00:00:00 2001 From: Dirk Balfanz Date: Wed, 17 Mar 2010 21:07:56 -0700 Subject: [PATCH 239/458] Instead of asking whether accounts are SAML accounts to figure out whether they can be used for screen unlocking, we ask directly whether they support confirmCredentials(). Change-Id: Ib83c89133b67661e2eb0827baecc32910b386f63 --- .../policy/impl/LockPatternKeyguardView.java | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index da51ad052f7e..169368c3e87f 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -35,6 +35,7 @@ import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.os.SystemClock; import android.os.SystemProperties; import android.telephony.TelephonyManager; @@ -57,8 +58,7 @@ import java.io.IOException; * {@link com.android.internal.policy.impl.KeyguardViewManager} * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate. */ -public class LockPatternKeyguardView extends KeyguardViewBase - implements AccountManagerCallback { +public class LockPatternKeyguardView extends KeyguardViewBase { static final boolean DEBUG_CONFIGURATION = false; @@ -155,8 +155,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase */ private final LockPatternUtils mLockPatternUtils; - private int mNumAccounts; - private UnlockMode mCurrentUnlockMode = UnlockMode.Unknown; /** @@ -174,25 +172,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT); } - // Called by AccountManager.getAccountByTypeAndFeatures() below... - public void run(AccountManagerFuture future) { - int samlAccounts = 0; - try { - samlAccounts = future.getResult().length; - } catch (OperationCanceledException e) { - } catch (IOException e) { - } catch (AuthenticatorException e) { - } - // At least one of the accounts must be non-SAML to enable the fallback. - mEnableFallback = samlAccounts < mNumAccounts; - - if (mUnlockScreen == null) { - Log.w(TAG, "no unlock screen when receiving AccountManager information"); - } else if (mUnlockScreen instanceof PatternUnlockScreen) { - ((PatternUnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback); - } - } - /** * @param context Used to inflate, and create views. * @param updateMonitor Knows the state of the world, and passed along to each @@ -357,16 +336,40 @@ public class LockPatternKeyguardView extends KeyguardViewBase // fallback in case the user forgets his pattern. The response comes // back in run() below; don't bother asking until you've called // createUnlockScreenFor(), else the information will go unused. - mNumAccounts = AccountManager.get(context).getAccounts().length; - if (mNumAccounts > 0) { - /* If we have a SAML account which requires web login we can not use the - fallback screen UI to ask the user for credentials. - For now we will disable fallback screen in this case. - Ultimately we could consider bringing up a web login from GLS - but need to make sure that it will work in the "locked screen" mode. */ - String[] features = new String[] {"saml"}; - AccountManager.get(context).getAccountsByTypeAndFeatures( - "com.google", features, this, null); + Account[] accounts = AccountManager.get(context).getAccounts(); + mEnableFallback = false; + + for (Account account : accounts) { + // See whether this account can be used to unlock the screen. + try { + // Passing null for action makes sure the confirmCredentials intent is not actually + // executed - we're just checking whether it's supported. + AccountManager.get(context) + .confirmCredentials(account, null, null, null, null) + .getResult(); + mEnableFallback = true; + break; + + } catch (OperationCanceledException e) { + Log.w(TAG, "couldn't talk to AccountManager", e); + + } catch (AuthenticatorException e) { + if (e.getCause() instanceof UnsupportedOperationException) { + // This is expected for accounts that don't support confirmCredentials + continue; + } else { + Log.w(TAG, "couldn't talk to AccountManager", e); + } + + } catch (IOException e) { + Log.w(TAG, "couldn't talk to AccountManager", e); + } + } + + if (mUnlockScreen == null) { + Log.w(TAG, "no unlock screen when trying to enable fallback"); + } else if (mUnlockScreen instanceof PatternUnlockScreen) { + ((PatternUnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback); } } -- GitLab From bfd25cacf81982f7fd9caba9b3d4f558131469fe Mon Sep 17 00:00:00 2001 From: Mike LeBeau Date: Mon, 22 Mar 2010 17:40:35 -0700 Subject: [PATCH 240/458] Tell SearchManager to stopSearch on long-press of search. Also, do the long-press haptic feedback first, to avoid any slowdown in the responsiveness of that. Fixes http://b/2526697 Change-Id: I607063b67bdde92303ee112663b76d6e4e9a369b --- .../internal/policy/impl/PhoneWindow.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 4e630df3115f..c6a528d11d9d 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -29,6 +29,7 @@ import com.android.internal.view.menu.MenuView; import com.android.internal.view.menu.SubMenuBuilder; import android.app.KeyguardManager; +import android.app.SearchManager; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; @@ -150,6 +151,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private long mVolumeKeyUpTime; private KeyguardManager mKeyguardManager = null; + + private SearchManager mSearchManager = null; private TelephonyManager mTelephonyManager = null; @@ -1237,9 +1240,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { + mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); sendCloseSystemWindows(); + getSearchManager().stopSearch(); getContext().startActivity(intent); - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); // Only clear this if we successfully start the // activity; otherwise we will allow the normal short // press action to be performed. @@ -1266,6 +1270,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } return mKeyguardManager; } + + /** + * @return A handle to the search manager. + */ + private SearchManager getSearchManager() { + if (mSearchManager == null) { + mSearchManager = (SearchManager) getContext().getSystemService(Context.SEARCH_SERVICE); + } + return mSearchManager; + } /** * A key was released and not handled by anything else in the window. -- GitLab From 3779dd12b09d1e38b9b27be99acbac3509e480d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Bia=C5=82ka?= Date: Wed, 24 Mar 2010 10:20:52 +0100 Subject: [PATCH 241/458] Fix reporting of window visibility in WindowManagerService. WindowManagerService (WMS) can wrongly report windows visibility due to wrong handling of "starting windows". "Starting windows" are special temporary windows that are displayed while the application is starting. Sometimes "starting windows" are considered when checking visibility what leads to not reported or wrongly reported visibility status. If visibility is not reported correctly some internal flows are not executed and WMS internal state can be wrong. --- services/java/com/android/server/WindowManagerService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 24caf1fbb28d..d209cfaa1982 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -8520,7 +8520,8 @@ public class WindowManagerService extends IWindowManager.Stub final int N = allAppWindows.size(); for (int i=0; i Date: Mon, 30 Nov 2009 17:30:21 +0900 Subject: [PATCH 242/458] gl_code : add end of line. Signed-off-by: Jae-Hyung Ahn --- opengl/tests/gl_jni/jni/gl_code.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/opengl/tests/gl_jni/jni/gl_code.cpp b/opengl/tests/gl_jni/jni/gl_code.cpp index 33b25ab6c775..f031c79cd33e 100644 --- a/opengl/tests/gl_jni/jni/gl_code.cpp +++ b/opengl/tests/gl_jni/jni/gl_code.cpp @@ -180,4 +180,5 @@ JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobjec JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * env, jobject obj) { background = 1.0f - background; -} \ No newline at end of file +} + -- GitLab From 00f4d986c6eb4bc16f2d2661ead2cdae33e82ff3 Mon Sep 17 00:00:00 2001 From: Adam Powell Date: Wed, 24 Mar 2010 11:17:03 -0700 Subject: [PATCH 243/458] Fix bug 2386867 - Phone DecorViews FOCUS_AFTER_DESCENDANTS Change-Id: Iade2c2d8ea575fc452897dbfd3d8454b5b7972ed --- policy/com/android/internal/policy/impl/PhoneWindow.java | 1 + 1 file changed, 1 insertion(+) diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index c6a528d11d9d..5592b6d5337e 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -2213,6 +2213,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private void installDecor() { if (mDecor == null) { mDecor = generateDecor(); + mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); mDecor.setIsRootNamespace(true); } if (mContentParent == null) { -- GitLab From cd8aed8c503ee37fa36b7d14744c9d0271faf12d Mon Sep 17 00:00:00 2001 From: Fred Quintana Date: Thu, 25 Mar 2010 14:50:20 -0700 Subject: [PATCH 244/458] change the account unlock enabling logic use async calls rather than blocking calls limit the account unlocks to google accounts Change-Id: If412a7557716503f7d122ec3ff31375f47b624b9 http://b/issue?id=2544496 --- .../policy/impl/AccountUnlockScreen.java | 2 +- .../policy/impl/LockPatternKeyguardView.java | 86 +++++++++++-------- 2 files changed, 52 insertions(+), 36 deletions(-) diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index 53793deb6565..9921069025bf 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -223,7 +223,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree * find a single best match. */ private Account findIntendedAccount(String username) { - Account[] accounts = AccountManager.get(mContext).getAccounts(); + Account[] accounts = AccountManager.get(mContext).getAccountsByType("com.google"); // Try to figure out which account they meant if they // typed only the username (and not the domain), or got diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 169368c3e87f..4005ae64caef 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -61,7 +61,7 @@ import java.io.IOException; public class LockPatternKeyguardView extends KeyguardViewBase { static final boolean DEBUG_CONFIGURATION = false; - + // time after launching EmergencyDialer before the screen goes blank. private static final int EMERGENCY_CALL_TIMEOUT = 10000; @@ -331,46 +331,62 @@ public class LockPatternKeyguardView extends KeyguardViewBase { updateScreen(mMode); } - private void maybeEnableFallback(Context context) { - // Ask the account manager if we have an account that can be used as a - // fallback in case the user forgets his pattern. The response comes - // back in run() below; don't bother asking until you've called - // createUnlockScreenFor(), else the information will go unused. - Account[] accounts = AccountManager.get(context).getAccounts(); - mEnableFallback = false; - - for (Account account : accounts) { - // See whether this account can be used to unlock the screen. - try { - // Passing null for action makes sure the confirmCredentials intent is not actually - // executed - we're just checking whether it's supported. - AccountManager.get(context) - .confirmCredentials(account, null, null, null, null) - .getResult(); - mEnableFallback = true; - break; + private class AccountAnalyzer implements AccountManagerCallback { + private final AccountManager mAccountManager; + private final Account[] mAccounts; + private int mAccountIndex; - } catch (OperationCanceledException e) { - Log.w(TAG, "couldn't talk to AccountManager", e); + private AccountAnalyzer(AccountManager accountManager) { + mAccountManager = accountManager; + mAccounts = accountManager.getAccountsByType("com.google"); + } - } catch (AuthenticatorException e) { - if (e.getCause() instanceof UnsupportedOperationException) { - // This is expected for accounts that don't support confirmCredentials - continue; - } else { - Log.w(TAG, "couldn't talk to AccountManager", e); + private void next() { + // if we are ready to enable the fallback or if we depleted the list of accounts + // then finish and get out + if (mEnableFallback || mAccountIndex >= mAccounts.length) { + if (mUnlockScreen == null) { + Log.w(TAG, "no unlock screen when trying to enable fallback"); + } else if (mUnlockScreen instanceof PatternUnlockScreen) { + ((PatternUnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback); } + return; + } + + // lookup the confirmCredentials intent for the current account + mAccountManager.confirmCredentials(mAccounts[mAccountIndex], null, null, this, null); + } + + public void start() { + mEnableFallback = false; + mAccountIndex = 0; + next(); + } + public void run(AccountManagerFuture future) { + try { + Bundle result = future.getResult(); + if (result.getParcelable(AccountManager.KEY_INTENT) != null) { + mEnableFallback = true; + } + } catch (OperationCanceledException e) { + // just skip the account if we are unable to query it } catch (IOException e) { - Log.w(TAG, "couldn't talk to AccountManager", e); + // just skip the account if we are unable to query it + } catch (AuthenticatorException e) { + // just skip the account if we are unable to query it + } finally { + mAccountIndex++; + next(); } } + } - if (mUnlockScreen == null) { - Log.w(TAG, "no unlock screen when trying to enable fallback"); - } else if (mUnlockScreen instanceof PatternUnlockScreen) { - ((PatternUnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback); - } + private void maybeEnableFallback(Context context) { + // Ask the account manager if we have an account that can be used as a + // fallback in case the user forgets his pattern. + AccountAnalyzer accountAnalyzer = new AccountAnalyzer(AccountManager.get(context)); + accountAnalyzer.start(); } @@ -509,7 +525,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { if (DEBUG_CONFIGURATION) Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode + " last mode=" + mMode, new RuntimeException()); - + mMode = mode; // Re-create the unlock screen if necessary. This is primarily required to properly handle @@ -529,7 +545,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { Log.v(TAG, "Gone=" + goneScreen); Log.v(TAG, "Visible=" + visibleScreen); } - + if (mScreenOn) { if (goneScreen.getVisibility() == View.VISIBLE) { ((KeyguardScreen) goneScreen).onPause(); -- GitLab From f7c5d0e46ced3ec3edb6f656acd82900b9ac988c Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Thu, 25 Mar 2010 18:37:48 -0700 Subject: [PATCH 245/458] Fix 2535700: Add support for enforcing password quality Change-Id: I945eea1a3869f48d636ed0c1172063f7bc57e889 --- .../policy/impl/LockPatternKeyguardView.java | 18 ++++++++++-------- .../policy/impl/PasswordUnlockScreen.java | 6 +++++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 4005ae64caef..5a32dc850502 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -27,6 +27,7 @@ import android.accounts.AccountManagerFuture; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.app.AlertDialog; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; @@ -281,8 +282,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts + " (enableFallback=" + mEnableFallback + ")"); - final boolean usingLockPattern = mLockPatternUtils.getPasswordMode() - == LockPatternUtils.MODE_PATTERN; + final boolean usingLockPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality() + == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; if (usingLockPattern && mEnableFallback && failedAttempts == (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { @@ -639,8 +640,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { final IccCard.State simState = mUpdateMonitor.getSimState(); if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED)) { return Mode.LockScreen; - } else if (isSecure() - && mLockPatternUtils.getPasswordMode() == LockPatternUtils.MODE_PATTERN) { + } else if (isSecure()) { return Mode.UnlockScreen; } else { return Mode.LockScreen; @@ -656,13 +656,15 @@ public class LockPatternKeyguardView extends KeyguardViewBase { if (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED) { currentMode = UnlockMode.SimPin; } else { - final int mode = mLockPatternUtils.getPasswordMode(); + final int mode = mLockPatternUtils.getKeyguardStoredPasswordQuality(); switch (mode) { - case LockPatternUtils.MODE_PIN: - case LockPatternUtils.MODE_PASSWORD: + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: + case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: + case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: currentMode = UnlockMode.Password; break; - case LockPatternUtils.MODE_PATTERN: + case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: + case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED: // "forgot pattern" button is only available in the pattern mode... if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) { currentMode = UnlockMode.Account; diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java index 07eaf9369f92..a0e4f93c8c09 100644 --- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -16,6 +16,7 @@ package com.android.internal.policy.impl; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; @@ -85,7 +86,10 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen layoutInflater.inflate(R.layout.keyguard_screen_password_landscape, this, true); } - boolean isAlpha = lockPatternUtils.getPasswordMode() == LockPatternUtils.MODE_PASSWORD; + final int quality = lockPatternUtils.getKeyguardStoredPasswordQuality(); + final boolean isAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == quality + || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == quality; + mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard); mPasswordEntry = (EditText) findViewById(R.id.passwordEntry); mPasswordEntry.setOnEditorActionListener(this); -- GitLab From c16889dc0034daaf50b2307c4de6c16c4964f30c Mon Sep 17 00:00:00 2001 From: Naveen Kalla Date: Wed, 24 Mar 2010 06:46:14 -0700 Subject: [PATCH 246/458] Type Zero Sms should not be displayed/stored/notified. Type Zero messages indicated by TP_PID field set to value 0x40, should not be displayed/stored/notified. They should only be acknowledged. --- .../android/internal/telephony/gsm/GsmSMSDispatcher.java | 7 +++++++ .../com/android/internal/telephony/gsm/SmsMessage.java | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java index 6ae316d0f08e..d7205169f7af 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java @@ -94,6 +94,13 @@ final class GsmSMSDispatcher extends SMSDispatcher { SmsMessage sms = (SmsMessage) smsb; boolean handled = false; + if (sms.isTypeZero()) { + // As per 3GPP TS 23.040 9.2.3.9, Type Zero messages should not be + // Displayed/Stored/Notified. They should only be acknowledged. + Log.d(TAG, "Received short message type 0, Dont display or store it. Send Ack"); + return Intents.RESULT_SMS_HANDLED; + } + // Special case the message waiting indicator messages if (sms.isMWISetMessage()) { mGsmPhone.updateMessageWaitingIndicator(true); diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java index d627bafbafe9..12c6b8897b76 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java @@ -110,6 +110,14 @@ public class SmsMessage extends SmsMessageBase{ } } + /** + * 3GPP TS 23.040 9.2.3.9 specifies that Type Zero messages are indicated + * by TP_PID field set to value 0x40 + */ + public boolean isTypeZero() { + return (protocolIdentifier == 0x40); + } + /** * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the * +CMT unsolicited response (PDU mode, of course) -- GitLab From 8082d5d9ebe29d8cb9755a64e05f4cf89b1cea5c Mon Sep 17 00:00:00 2001 From: Devin Taylor Date: Thu, 18 Mar 2010 15:35:11 -0500 Subject: [PATCH 247/458] Fix last character of password field being visible after rotation This is a fix for http://code.google.com/p/android/issues/detail?id=907. Note that that issue was declined without comment, but the bug (while incredibly minor) does exist. This can be seen on the facebook app, as well as many third party apps. Change-Id: I8f1449c47228f5f757a5baf389656e51c817b150 --- .../method/PasswordTransformationMethod.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/core/java/android/text/method/PasswordTransformationMethod.java b/core/java/android/text/method/PasswordTransformationMethod.java index fad4f64ffe1e..b769b76832ed 100644 --- a/core/java/android/text/method/PasswordTransformationMethod.java +++ b/core/java/android/text/method/PasswordTransformationMethod.java @@ -51,6 +51,8 @@ implements TransformationMethod, TextWatcher sp.removeSpan(vr[i]); } + removeVisibleSpans(sp); + sp.setSpan(new ViewReference(view), 0, 0, Spannable.SPAN_POINT_POINT); } @@ -100,10 +102,7 @@ implements TransformationMethod, TextWatcher int pref = TextKeyListener.getInstance().getPrefs(v.getContext()); if ((pref & TextKeyListener.SHOW_PASSWORD) != 0) { if (count > 0) { - Visible[] old = sp.getSpans(0, sp.length(), Visible.class); - for (int i = 0; i < old.length; i++) { - sp.removeSpan(old[i]); - } + removeVisibleSpans(sp); if (count == 1) { sp.setSpan(new Visible(sp, this), start, start + count, @@ -125,14 +124,18 @@ implements TransformationMethod, TextWatcher if (sourceText instanceof Spannable) { Spannable sp = (Spannable) sourceText; - Visible[] old = sp.getSpans(0, sp.length(), Visible.class); - for (int i = 0; i < old.length; i++) { - sp.removeSpan(old[i]); - } + removeVisibleSpans(sp); } } } + private static void removeVisibleSpans(Spannable sp) { + Visible[] old = sp.getSpans(0, sp.length(), Visible.class); + for (int i = 0; i < old.length; i++) { + sp.removeSpan(old[i]); + } + } + private static class PasswordCharSequence implements CharSequence, GetChars { -- GitLab From d323995d316b94512119b98cf444c62bdfde9a0e Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Wed, 17 Mar 2010 21:52:35 -0400 Subject: [PATCH 248/458] Redesigned keyguard layout in the no-SIM case. DO NOT MERGE The emergency call button has been removed (since the user can disable the keyguard, open the phone app, and enter the emergency number there). This change also restores a number of the informational & help messages that were previously removed from the lock screen. Bug: 2421380 Change-Id: I4dda16be5d54c1e0ab4e26914c63d1f5b922cfe8 --- .../internal/policy/impl/LockScreen.java | 57 +++++++------------ 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index baed9ebcea32..381b9132b525 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -66,7 +66,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private TextView mStatus1; private TextView mStatus2; private TextView mScreenLocked; - private Button mEmergencyCallButton; + private TextView mEmergencyCallText; // current configuration state of keyboard and display private int mKeyboardHidden; @@ -203,18 +203,12 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mStatus1 = (TextView) findViewById(R.id.status1); mStatus2 = (TextView) findViewById(R.id.status2); - mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); - mEmergencyCallButton.setText(R.string.lockscreen_emergency_call); - mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); mScreenLocked = (TextView) findViewById(R.id.screenLocked); mSelector = (SlidingTab) findViewById(R.id.tab_selector); mSelector.setHoldAfterTrigger(true, false); mSelector.setLeftHintText(R.string.lockscreen_unlock_label); - mEmergencyCallButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - mCallback.takeEmergencyCallAction(); - } - }); + + mEmergencyCallText = (TextView) findViewById(R.id.emergencyCallText); setFocusable(true); setFocusableInTouchMode(true); @@ -269,7 +263,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM refreshBatteryStringAndIcon(); refreshAlarmDisplay(); - mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); mTimeFormat = DateFormat.getTimeFormat(getContext()); mDateFormatString = getContext().getString(R.string.full_wday_month_day_no_year); @@ -340,8 +333,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM * @param iconResourceId The left hand icon. */ private void toastMessage(final TextView textView, final String text, final int color, final int iconResourceId) { - if (DBG) android.util.Log.d("LockScreen", "toastMessage(text=" + text +", color=" + color + ")"); - if (mPendingR1 != null) { textView.removeCallbacks(mPendingR1); mPendingR1 = null; @@ -499,9 +490,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM * Update the layout to match the current status. */ private void updateLayout(Status status) { - // The emergency call button appears where the carrier would - // ordinarily be shown, so if one is VISIBLE the other must be - // INVISIBLE. + // The emergency call button no longer appears on this screen. + if (DBG) Log.d(TAG, "updateLayout: status=" + status); switch (status) { case Normal: // text @@ -509,12 +499,13 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM getCarrierString( mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn())); -// mScreenLocked.setText(R.string.lockscreen_screen_locked); + // unnecessary clutter + //mScreenLocked.setText(R.string.lockscreen_screen_locked); // layout - mScreenLocked.setVisibility(View.VISIBLE); + mScreenLocked.setVisibility(View.INVISIBLE); mSelector.setVisibility(View.VISIBLE); - mEmergencyCallButton.setVisibility(View.GONE); + mEmergencyCallText.setVisibility(View.GONE); break; case NetworkLocked: // The carrier string shows both sim card status (i.e. No Sim Card) and @@ -528,35 +519,30 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); mSelector.setVisibility(View.VISIBLE); - mEmergencyCallButton.setVisibility(View.GONE); + mEmergencyCallText.setVisibility(View.GONE); break; case SimMissing: // text - mCarrier.setText(""); - mScreenLocked.setText( - getCarrierString( - mUpdateMonitor.getTelephonyPlmn(), - getContext().getText(R.string.lockscreen_missing_sim_message_short))); - // previously shown here: lockscreen_instructions_when_pattern_disabled + mCarrier.setText(R.string.lockscreen_missing_sim_message_short); + mScreenLocked.setText(R.string.lockscreen_missing_sim_instructions); // layout mScreenLocked.setVisibility(View.VISIBLE); mSelector.setVisibility(View.VISIBLE); - mEmergencyCallButton.setVisibility(View.VISIBLE); + mEmergencyCallText.setVisibility(View.VISIBLE); break; case SimMissingLocked: // text - mCarrier.setText(""); - mScreenLocked.setText( + mCarrier.setText( getCarrierString( mUpdateMonitor.getTelephonyPlmn(), getContext().getText(R.string.lockscreen_missing_sim_message_short))); - // previously shown here: lockscreen_missing_sim_instructions + mScreenLocked.setText(R.string.lockscreen_missing_sim_instructions); // layout mScreenLocked.setVisibility(View.VISIBLE); mSelector.setVisibility(View.GONE); - mEmergencyCallButton.setVisibility(View.VISIBLE); + mEmergencyCallText.setVisibility(View.VISIBLE); break; case SimLocked: // text @@ -568,21 +554,20 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.INVISIBLE); mSelector.setVisibility(View.VISIBLE); - mEmergencyCallButton.setVisibility(View.GONE); + mEmergencyCallText.setVisibility(View.GONE); break; case SimPukLocked: // text - mCarrier.setText(""); - mScreenLocked.setText( + mCarrier.setText( getCarrierString( mUpdateMonitor.getTelephonyPlmn(), getContext().getText(R.string.lockscreen_sim_puk_locked_message))); - // previously shown here: lockscreen_sim_puk_locked_instructions); + mScreenLocked.setText(R.string.lockscreen_sim_puk_locked_instructions); // layout mScreenLocked.setVisibility(View.VISIBLE); mSelector.setVisibility(View.GONE); - mEmergencyCallButton.setVisibility(View.VISIBLE); + mEmergencyCallText.setVisibility(View.VISIBLE); break; } } @@ -655,7 +640,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM /** {@inheritDoc} */ public void onResume() { resetStatusInfo(mUpdateMonitor); - mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); } /** {@inheritDoc} */ @@ -673,6 +657,5 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } public void onPhoneStateChanged(String newState) { - mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); } } -- GitLab From 69f789a12888b3a3a1711fcc8ce2489cdfd1437f Mon Sep 17 00:00:00 2001 From: Tatsuo Nagamatsu Date: Sun, 28 Mar 2010 14:23:51 +0900 Subject: [PATCH 249/458] CursorToBulkCursorAdapter.close must call mCursor.close instead of mCursor.deactivate. This prevent us to call Cursor.close on cross process ContentProvider and may cause a database leak problem. Change-Id: I126457c1b709e853727f460095b518b0420aa34f --- core/java/android/database/CursorToBulkCursorAdaptor.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java index 19ad946b91a3..05f801481ad7 100644 --- a/core/java/android/database/CursorToBulkCursorAdaptor.java +++ b/core/java/android/database/CursorToBulkCursorAdaptor.java @@ -143,8 +143,7 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative public void close() { maybeUnregisterObserverProxy(); - mCursor.deactivate(); - + mCursor.close(); } public int requery(IContentObserver observer, CursorWindow window) { -- GitLab From 5f3445dc609fb3dd64b023c1ba9c1ee3ba95b868 Mon Sep 17 00:00:00 2001 From: David Hoover Date: Sun, 28 Mar 2010 08:48:55 -0700 Subject: [PATCH 250/458] Fix typos in comment. Change-Id: Ia2a9ea0802bcc5773bb4fd52d7e07f9492242bfd --- graphics/java/android/graphics/Color.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java index 5cefaa3b72c6..a50693d2f130 100644 --- a/graphics/java/android/graphics/Color.java +++ b/graphics/java/android/graphics/Color.java @@ -30,7 +30,8 @@ import java.util.Locale; * (green << 8) | blue. Each component ranges between 0..255 with 0 * meaning no contribution for that component, and 255 meaning 100% * contribution. Thus opaque-black would be 0xFF000000 (100% opaque but - * no contributes from red, gree, blue, and opaque-white would be 0xFFFFFFFF + * no contributions from red, green, or blue), and opaque-white would be + * 0xFFFFFFFF */ public class Color { public static final int BLACK = 0xFF000000; -- GitLab From 14f190e1252006711044ebb3cafa1345e2852d30 Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Thu, 25 Mar 2010 09:45:53 -0400 Subject: [PATCH 251/458] Put the wifi status icon in the right place. This fixes the inconsistency where all network-related icons appear on the right side of the volume/vibrate icon except for the wifi icon, which appears on the left. Thanks to Kevin Purdy @ Lifehacker for kicking my OCD in :) --- core/res/res/values/arrays.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml index 66f0e820cb38..e801ba868242 100644 --- a/core/res/res/values/arrays.xml +++ b/core/res/res/values/arrays.xml @@ -113,11 +113,11 @@ phone_evdo_signal data_connection cdma_eri + wifi tty volume mute speakerphone - wifi tty bluetooth gps -- GitLab From 9d0f6dfdc1ac0b9374acf51572f273e9c9bbc9f9 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Mon, 29 Mar 2010 12:55:09 -0700 Subject: [PATCH 252/458] Fix build Change-Id: I8c68731786ab648dc916b09333b67acb26f81594 --- services/java/com/android/server/InputMethodManagerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index e82996247835..5bf66e4d1282 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -895,7 +895,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub try { sessionState.session.finishSession(); } catch (RemoteException e) { - Log.w(TAG, "Session failed to close due to remote exception", e); + Slog.w(TAG, "Session failed to close due to remote exception", e); } } } -- GitLab From 8154cd3bbce98e2b3850d47a7d0826e93860506b Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Mon, 29 Mar 2010 14:41:15 -0700 Subject: [PATCH 253/458] Remove scroll barrier constant. Bug #2553595 Change-Id: Ie3bb31930b57ed1a658b79632786dfef9435ccf3 --- .../internal/policy/impl/PhoneWindowManager.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index f750f23d7cbc..cfdce5a14583 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -185,10 +185,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Vibrator pattern for haptic feedback during boot when safe mode is enabled. long[] mSafeModeEnabledVibePattern; - - // Vibrator pattern for haptic feedback when the user hits a touch scroll barrier. - long[] mScrollBarrierVibePattern; - + /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ boolean mEnableShiftMenuBugReports = false; @@ -541,8 +538,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.array.config_safeModeDisabledVibePattern); mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_safeModeEnabledVibePattern); - mScrollBarrierVibePattern = getLongIntArray(mContext.getResources(), - com.android.internal.R.array.config_scrollBarrierVibePattern); } public void updateSettings() { @@ -2362,9 +2357,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { case HapticFeedbackConstants.SAFE_MODE_ENABLED: pattern = mSafeModeEnabledVibePattern; break; - case HapticFeedbackConstants.SCROLL_BARRIER: - pattern = mScrollBarrierVibePattern; - break; default: return false; } -- GitLab From 466d77617ace8380ab8c52ede20790755d8ff092 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Mon, 29 Mar 2010 19:31:26 -0700 Subject: [PATCH 254/458] Fix 2555028: Restore showing tab unlock before PIN & password entry. This fixes a bug introduced in change 46594 that prevents showing the tab unlock screen before PIN & password entry. Change-Id: Ibd603921f6a22b603652c4751fa0f2f7d9129bb2 --- .../internal/policy/impl/LockPatternKeyguardView.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 5a32dc850502..c1b14c43772d 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -640,10 +640,15 @@ public class LockPatternKeyguardView extends KeyguardViewBase { final IccCard.State simState = mUpdateMonitor.getSimState(); if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED)) { return Mode.LockScreen; - } else if (isSecure()) { - return Mode.UnlockScreen; } else { - return Mode.LockScreen; + // Show LockScreen first for any screen other than Pattern unlock. + final boolean usingLockPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality() + == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; + if (isSecure() && usingLockPattern) { + return Mode.UnlockScreen; + } else { + return Mode.LockScreen; + } } } -- GitLab From a749f869747b763600fcfaa67a934f404f262d39 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Wed, 31 Mar 2010 00:43:36 -0700 Subject: [PATCH 255/458] Fix a previous bad merge. Change-Id: I12e577873389d6200f8add252867e63dee2d2c3c --- services/java/com/android/server/PackageManagerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index a1a703f5b7d3..c3eaf107c834 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -7637,7 +7637,7 @@ class PackageManagerService extends IPackageManager.Stub { this.pkgFlags = pkgFlags & ( ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_FORWARD_LOCK | - ApplicationInfo.FLAG_EXTERNAL_STORAGE |; + ApplicationInfo.FLAG_EXTERNAL_STORAGE | ApplicationInfo.FLAG_NEVER_ENCRYPT); } } -- GitLab From 6f63dd5dc8ae38f866e297883435dd1fd3a5cdfd Mon Sep 17 00:00:00 2001 From: San Mehat Date: Mon, 29 Mar 2010 15:01:44 -0700 Subject: [PATCH 256/458] framework: Hide StorageManager for froyo - do not merge Change-Id: I9a871e49cc9e1accb28c7e4b76bb0796eaf26d7b --- api/current.xml | 234 ------------------ .../os/storage/StorageEventListener.java | 1 + .../android/os/storage/StorageManager.java | 2 + .../android/os/storage/StorageResultCode.java | 2 + 4 files changed, 5 insertions(+), 234 deletions(-) diff --git a/api/current.xml b/api/current.xml index 23d13bdea1b6..6477fc475600 100644 --- a/api/current.xml +++ b/api/current.xml @@ -120539,240 +120539,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Date: Wed, 27 May 2009 15:52:50 +0800 Subject: [PATCH 257/458] Add keycodes PageUp and PageDown This is useful for applications like web browser. Change-Id: Ie9262d5b75de87ecd0971407a7c3ce9aa6e4998e --- api/current.xml | 24 +++++++++++++++++++++++- core/java/android/view/KeyEvent.java | 4 +++- core/res/res/values/attrs.xml | 2 ++ include/ui/KeycodeLabels.h | 6 +++++- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/api/current.xml b/api/current.xml index 83d2bc74d186..3b65d958e118 100644 --- a/api/current.xml +++ b/api/current.xml @@ -153221,6 +153221,28 @@ visibility="public" > + + + + - + diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index d4f978756f4d..14e015977b81 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -120,6 +120,8 @@ public class KeyEvent implements Parcelable { public static final int KEYCODE_MEDIA_REWIND = 89; public static final int KEYCODE_MEDIA_FAST_FORWARD = 90; public static final int KEYCODE_MUTE = 91; + public static final int KEYCODE_PAGE_UP = 92; + public static final int KEYCODE_PAGE_DOWN = 93; // NOTE: If you add a new keycode here you must also add it to: // isSystem() @@ -135,7 +137,7 @@ public class KeyEvent implements Parcelable { // those new codes. This is intended to maintain a consistent // set of key code definitions across all Android devices. - private static final int LAST_KEYCODE = KEYCODE_MUTE; + private static final int LAST_KEYCODE = KEYCODE_PAGE_DOWN; /** * @deprecated There are now more than MAX_KEYCODE keycodes. diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 68661ae46d51..91256f1d0581 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -912,6 +912,8 @@ + + diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h index 571e47b22d86..749155ebab89 100644 --- a/include/ui/KeycodeLabels.h +++ b/include/ui/KeycodeLabels.h @@ -114,6 +114,8 @@ static const KeycodeLabel KEYCODES[] = { { "MEDIA_REWIND", 89 }, { "MEDIA_FAST_FORWARD", 90 }, { "MUTE", 91 }, + { "PAGE_UP", 92 }, + { "PAGE_DOWN", 93 }, // NOTE: If you add a new keycode here you must also add it to: // (enum KeyCode, in this file) @@ -218,7 +220,9 @@ typedef enum KeyCode { kKeyCodePreviousSong = 88, kKeyCodeRewind = 89, kKeyCodeForward = 90, - kKeyCodeMute = 91 + kKeyCodeMute = 91, + kKeyCodePageUp = 92, + kKeyCodePageDown = 93 } KeyCode; static const KeycodeLabel FLAGS[] = { -- GitLab From 79e642e8ed75033eacc461633a8f4cd5157d25df Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 17 Mar 2010 23:19:25 -0400 Subject: [PATCH 258/458] Call LocationManager.sendNiResponse() instead of calling directly to GpsLocationProvider Change-Id: I6a5b47abb0519f5228d29bc3340bb2490564803e Signed-off-by: Mike Lockwood --- .../internal/app/NetInitiatedActivity.java | 1 - .../internal/location/GpsLocationProvider.java | 2 +- .../internal/location/GpsNetInitiatedHandler.java | 15 +++++---------- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java index 24818a84a130..03b0957dc694 100755 --- a/core/java/com/android/internal/app/NetInitiatedActivity.java +++ b/core/java/com/android/internal/app/NetInitiatedActivity.java @@ -30,7 +30,6 @@ import android.os.ServiceManager; import android.widget.Toast; import android.util.Log; import android.location.LocationManager; -import com.android.internal.location.GpsLocationProvider; import com.android.internal.location.GpsNetInitiatedHandler; /** diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java index 15d692c46263..e3124821e0bc 100755 --- a/location/java/com/android/internal/location/GpsLocationProvider.java +++ b/location/java/com/android/internal/location/GpsLocationProvider.java @@ -348,7 +348,7 @@ public class GpsLocationProvider implements LocationProviderInterface { public GpsLocationProvider(Context context, ILocationManager locationManager) { mContext = context; mLocationManager = locationManager; - mNIHandler = new GpsNetInitiatedHandler(context, this); + mNIHandler = new GpsNetInitiatedHandler(context); mLocation.setExtras(mLocationExtras); diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index a5466d1be03d..2a6618b9c828 100755 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -23,6 +23,7 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.location.LocationManager; import android.os.Bundle; import android.os.RemoteException; import android.util.Log; @@ -81,7 +82,7 @@ public class GpsNetInitiatedHandler { private final Context mContext; // parent gps location provider - private final GpsLocationProvider mGpsLocationProvider; + private final LocationManager mLocationManager; // configuration of notificaiton behavior private boolean mPlaySounds = false; @@ -122,9 +123,9 @@ public class GpsNetInitiatedHandler { */ private Notification mNiNotification; - public GpsNetInitiatedHandler(Context context, GpsLocationProvider gpsLocationProvider) { + public GpsNetInitiatedHandler(Context context) { mContext = context; - mGpsLocationProvider = gpsLocationProvider; + mLocationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE); } // Handles NI events from HAL @@ -157,13 +158,7 @@ public class GpsNetInitiatedHandler { !notif.needNotify && !notif.needVerify || notif.privacyOverride) { - try { - mGpsLocationProvider.getNetInitiatedListener().sendNiResponse(notif.notificationId, GPS_NI_RESPONSE_ACCEPT); - } - catch (RemoteException e) - { - Log.e(TAG, e.getMessage()); - } + mLocationManager.sendNiResponse(notif.notificationId, GPS_NI_RESPONSE_ACCEPT); } ////////////////////////////////////////////////////////////////////////// -- GitLab From 5b53244a4e6c81b5346cde22fabbbefe5b472cf7 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 17 Mar 2010 23:28:36 -0400 Subject: [PATCH 259/458] GpsNetInitiatedHandler: whitespace cleanup Signed-off-by: Mike Lockwood --- .../location/GpsNetInitiatedHandler.java | 508 +++++++++--------- 1 file changed, 254 insertions(+), 254 deletions(-) diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index 2a6618b9c828..2cf9c2bf6353 100755 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -94,25 +94,25 @@ public class GpsNetInitiatedHandler { public static class GpsNiNotification { - int notificationId; - int niType; - boolean needNotify; - boolean needVerify; - boolean privacyOverride; - int timeout; - int defaultResponse; - String requestorId; - String text; - int requestorIdEncoding; - int textEncoding; - Bundle extras; + int notificationId; + int niType; + boolean needNotify; + boolean needVerify; + boolean privacyOverride; + int timeout; + int defaultResponse; + String requestorId; + String text; + int requestorIdEncoding; + int textEncoding; + Bundle extras; }; public static class GpsNiResponse { - /* User reponse, one of the values in GpsUserResponseType */ - int userResponse; - /* Optional extra data to pass with the user response */ - Bundle extras; + /* User reponse, one of the values in GpsUserResponseType */ + int userResponse; + /* Optional extra data to pass with the user response */ + Bundle extras; }; /** @@ -124,56 +124,56 @@ public class GpsNetInitiatedHandler { private Notification mNiNotification; public GpsNetInitiatedHandler(Context context) { - mContext = context; - mLocationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE); + mContext = context; + mLocationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE); } // Handles NI events from HAL public void handleNiNotification(GpsNiNotification notif) { - if (DEBUG) Log.d(TAG, "handleNiNotification" + " notificationId: " + notif.notificationId - + " requestorId: " + notif.requestorId + " text: " + notif.text); - - // Notify and verify with immediate pop-up - if (notif.needNotify && notif.needVerify && mPopupImmediately) - { - // Popup the dialog box now - openNiDialog(notif); - } - - // Notify only, or delayed pop-up (change mPopupImmediately to FALSE) - if (notif.needNotify && !notif.needVerify || - notif.needNotify && notif.needVerify && !mPopupImmediately) - { - // Show the notification - - // if mPopupImmediately == FALSE and needVerify == TRUE, a dialog will be opened - // when the user opens the notification message - - setNiNotification(notif); - } - - // ACCEPT cases: 1. Notify, no verify; 2. no notify, no verify; 3. privacy override. - if ( notif.needNotify && !notif.needVerify || - !notif.needNotify && !notif.needVerify || - notif.privacyOverride) - { - mLocationManager.sendNiResponse(notif.notificationId, GPS_NI_RESPONSE_ACCEPT); - } - - ////////////////////////////////////////////////////////////////////////// - // A note about timeout - // According to the protocol, in the need_notify and need_verify case, - // a default response should be sent when time out. - // - // In some GPS hardware, the GPS driver (under HAL) can handle the timeout case - // and this class GpsNetInitiatedHandler does not need to do anything. - // - // However, the UI should at least close the dialog when timeout. Further, - // for more general handling, timeout response should be added to the Handler here. - // + if (DEBUG) Log.d(TAG, "handleNiNotification" + " notificationId: " + notif.notificationId + + " requestorId: " + notif.requestorId + " text: " + notif.text); + + // Notify and verify with immediate pop-up + if (notif.needNotify && notif.needVerify && mPopupImmediately) + { + // Popup the dialog box now + openNiDialog(notif); + } + + // Notify only, or delayed pop-up (change mPopupImmediately to FALSE) + if (notif.needNotify && !notif.needVerify || + notif.needNotify && notif.needVerify && !mPopupImmediately) + { + // Show the notification + + // if mPopupImmediately == FALSE and needVerify == TRUE, a dialog will be opened + // when the user opens the notification message + + setNiNotification(notif); + } + + // ACCEPT cases: 1. Notify, no verify; 2. no notify, no verify; 3. privacy override. + if ( notif.needNotify && !notif.needVerify || + !notif.needNotify && !notif.needVerify || + notif.privacyOverride) + { + mLocationManager.sendNiResponse(notif.notificationId, GPS_NI_RESPONSE_ACCEPT); + } + + ////////////////////////////////////////////////////////////////////////// + // A note about timeout + // According to the protocol, in the need_notify and need_verify case, + // a default response should be sent when time out. + // + // In some GPS hardware, the GPS driver (under HAL) can handle the timeout case + // and this class GpsNetInitiatedHandler does not need to do anything. + // + // However, the UI should at least close the dialog when timeout. Further, + // for more general handling, timeout response should be added to the Handler here. + // } - + // Sets the NI notification. private synchronized void setNiNotification(GpsNiNotification notif) { NotificationManager notificationManager = (NotificationManager) mContext @@ -181,272 +181,272 @@ public class GpsNetInitiatedHandler { if (notificationManager == null) { return; } - - String title = getNotifTitle(notif); - String message = getNotifMessage(notif); - + + String title = getNotifTitle(notif); + String message = getNotifMessage(notif); + if (DEBUG) Log.d(TAG, "setNiNotification, notifyId: " + notif.notificationId + - ", title: " + title + - ", message: " + message); - - // Construct Notification - if (mNiNotification == null) { - mNiNotification = new Notification(); - mNiNotification.icon = com.android.internal.R.drawable.stat_sys_gps_on; /* Change notification icon here */ - mNiNotification.when = 0; + ", title: " + title + + ", message: " + message); + + // Construct Notification + if (mNiNotification == null) { + mNiNotification = new Notification(); + mNiNotification.icon = com.android.internal.R.drawable.stat_sys_gps_on; /* Change notification icon here */ + mNiNotification.when = 0; } - + if (mPlaySounds) { - mNiNotification.defaults |= Notification.DEFAULT_SOUND; + mNiNotification.defaults |= Notification.DEFAULT_SOUND; } else { - mNiNotification.defaults &= ~Notification.DEFAULT_SOUND; + mNiNotification.defaults &= ~Notification.DEFAULT_SOUND; } - + mNiNotification.flags = Notification.FLAG_ONGOING_EVENT; mNiNotification.tickerText = getNotifTicker(notif); - + // if not to popup dialog immediately, pending intent will open the dialog - Intent intent = !mPopupImmediately ? getDlgIntent(notif) : new Intent(); + Intent intent = !mPopupImmediately ? getDlgIntent(notif) : new Intent(); PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0); mNiNotification.setLatestEventInfo(mContext, title, message, pi); - + if (visible) { notificationManager.notify(notif.notificationId, mNiNotification); } else { notificationManager.cancel(notif.notificationId); } } - + // Opens the notification dialog and waits for user input - private void openNiDialog(GpsNiNotification notif) + private void openNiDialog(GpsNiNotification notif) { - Intent intent = getDlgIntent(notif); - - if (DEBUG) Log.d(TAG, "openNiDialog, notifyId: " + notif.notificationId + - ", requestorId: " + notif.requestorId + - ", text: " + notif.text); + Intent intent = getDlgIntent(notif); - mContext.startActivity(intent); + if (DEBUG) Log.d(TAG, "openNiDialog, notifyId: " + notif.notificationId + + ", requestorId: " + notif.requestorId + + ", text: " + notif.text); + + mContext.startActivity(intent); } - + // Construct the intent for bringing up the dialog activity, which shows the // notification and takes user input private Intent getDlgIntent(GpsNiNotification notif) { - Intent intent = new Intent(); - String title = getDialogTitle(notif); - String message = getDialogMessage(notif); - - // directly bring up the NI activity - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setClass(mContext, com.android.internal.app.NetInitiatedActivity.class); - - // put data in the intent - intent.putExtra(NI_INTENT_KEY_NOTIF_ID, notif.notificationId); - intent.putExtra(NI_INTENT_KEY_TITLE, title); - intent.putExtra(NI_INTENT_KEY_MESSAGE, message); - intent.putExtra(NI_INTENT_KEY_TIMEOUT, notif.timeout); - intent.putExtra(NI_INTENT_KEY_DEFAULT_RESPONSE, notif.defaultResponse); - - if (DEBUG) Log.d(TAG, "generateIntent, title: " + title + ", message: " + message + - ", timeout: " + notif.timeout); - - return intent; + Intent intent = new Intent(); + String title = getDialogTitle(notif); + String message = getDialogMessage(notif); + + // directly bring up the NI activity + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setClass(mContext, com.android.internal.app.NetInitiatedActivity.class); + + // put data in the intent + intent.putExtra(NI_INTENT_KEY_NOTIF_ID, notif.notificationId); + intent.putExtra(NI_INTENT_KEY_TITLE, title); + intent.putExtra(NI_INTENT_KEY_MESSAGE, message); + intent.putExtra(NI_INTENT_KEY_TIMEOUT, notif.timeout); + intent.putExtra(NI_INTENT_KEY_DEFAULT_RESPONSE, notif.defaultResponse); + + if (DEBUG) Log.d(TAG, "generateIntent, title: " + title + ", message: " + message + + ", timeout: " + notif.timeout); + + return intent; } - + // Converts a string (or Hex string) to a char array static byte[] stringToByteArray(String original, boolean isHex) { - int length = isHex ? original.length() / 2 : original.length(); - byte[] output = new byte[length]; - int i; - - if (isHex) - { - for (i = 0; i < length; i++) - { - output[i] = (byte) Integer.parseInt(original.substring(i*2, i*2+2), 16); - } - } - else { - for (i = 0; i < length; i++) - { - output[i] = (byte) original.charAt(i); - } - } - - return output; + int length = isHex ? original.length() / 2 : original.length(); + byte[] output = new byte[length]; + int i; + + if (isHex) + { + for (i = 0; i < length; i++) + { + output[i] = (byte) Integer.parseInt(original.substring(i*2, i*2+2), 16); + } + } + else { + for (i = 0; i < length; i++) + { + output[i] = (byte) original.charAt(i); + } + } + + return output; } - + /** * Unpacks an byte array containing 7-bit packed characters into a String. - * + * * @param input a 7-bit packed char array * @return the unpacked String */ static String decodeGSMPackedString(byte[] input) { - final char CHAR_CR = 0x0D; - int nStridx = 0; - int nPckidx = 0; - int num_bytes = input.length; - int cPrev = 0; - int cCurr = 0; - byte nShift; - byte nextChar; - byte[] stringBuf = new byte[input.length * 2]; - String result = ""; - - while(nPckidx < num_bytes) - { - nShift = (byte) (nStridx & 0x07); - cCurr = input[nPckidx++]; - if (cCurr < 0) cCurr += 256; - - /* A 7-bit character can be split at the most between two bytes of packed - ** data. - */ - nextChar = (byte) (( (cCurr << nShift) | (cPrev >> (8-nShift)) ) & 0x7F); - stringBuf[nStridx++] = nextChar; - - /* Special case where the whole of the next 7-bit character fits inside - ** the current byte of packed data. - */ - if(nShift == 6) - { - /* If the next 7-bit character is a CR (0x0D) and it is the last - ** character, then it indicates a padding character. Drop it. - */ - if (nPckidx == num_bytes || (cCurr >> 1) == CHAR_CR) - { - break; - } - - nextChar = (byte) (cCurr >> 1); - stringBuf[nStridx++] = nextChar; - } - - cPrev = cCurr; - } - - try{ - result = new String(stringBuf, 0, nStridx, "US-ASCII"); - } - catch (UnsupportedEncodingException e) - { - Log.e(TAG, e.getMessage()); - } - - return result; + final char CHAR_CR = 0x0D; + int nStridx = 0; + int nPckidx = 0; + int num_bytes = input.length; + int cPrev = 0; + int cCurr = 0; + byte nShift; + byte nextChar; + byte[] stringBuf = new byte[input.length * 2]; + String result = ""; + + while(nPckidx < num_bytes) + { + nShift = (byte) (nStridx & 0x07); + cCurr = input[nPckidx++]; + if (cCurr < 0) cCurr += 256; + + /* A 7-bit character can be split at the most between two bytes of packed + ** data. + */ + nextChar = (byte) (( (cCurr << nShift) | (cPrev >> (8-nShift)) ) & 0x7F); + stringBuf[nStridx++] = nextChar; + + /* Special case where the whole of the next 7-bit character fits inside + ** the current byte of packed data. + */ + if(nShift == 6) + { + /* If the next 7-bit character is a CR (0x0D) and it is the last + ** character, then it indicates a padding character. Drop it. + */ + if (nPckidx == num_bytes || (cCurr >> 1) == CHAR_CR) + { + break; + } + + nextChar = (byte) (cCurr >> 1); + stringBuf[nStridx++] = nextChar; + } + + cPrev = cCurr; + } + + try { + result = new String(stringBuf, 0, nStridx, "US-ASCII"); + } + catch (UnsupportedEncodingException e) + { + Log.e(TAG, e.getMessage()); + } + + return result; } - + static String decodeUTF8String(byte[] input) { - String decoded = ""; - try { - decoded = new String(input, "UTF-8"); - } - catch (UnsupportedEncodingException e) - { - Log.e(TAG, e.getMessage()); - } - return decoded; + String decoded = ""; + try { + decoded = new String(input, "UTF-8"); + } + catch (UnsupportedEncodingException e) + { + Log.e(TAG, e.getMessage()); + } + return decoded; } - + static String decodeUCS2String(byte[] input) { - String decoded = ""; - try { - decoded = new String(input, "UTF-16"); - } - catch (UnsupportedEncodingException e) - { - Log.e(TAG, e.getMessage()); - } - return decoded; + String decoded = ""; + try { + decoded = new String(input, "UTF-16"); + } + catch (UnsupportedEncodingException e) + { + Log.e(TAG, e.getMessage()); + } + return decoded; } - + /** Decode NI string - * + * * @param original The text string to be decoded * @param isHex Specifies whether the content of the string has been encoded as a Hex string. Encoding - * a string as Hex can allow zeros inside the coded text. + * a string as Hex can allow zeros inside the coded text. * @param coding Specifies the coding scheme of the string, such as GSM, UTF8, UCS2, etc. This coding scheme - * needs to match those used passed to HAL from the native GPS driver. Decoding is done according + * needs to match those used passed to HAL from the native GPS driver. Decoding is done according * to the coding , after a Hex string is decoded. Generally, if the - * notification strings don't need further decoding, coding encoding can be + * notification strings don't need further decoding, coding encoding can be * set to -1, and isHex can be false. * @return the decoded string */ static private String decodeString(String original, boolean isHex, int coding) { - String decoded = original; - byte[] input = stringToByteArray(original, isHex); - - switch (coding) { - case GPS_ENC_NONE: - decoded = original; - break; - - case GPS_ENC_SUPL_GSM_DEFAULT: - decoded = decodeGSMPackedString(input); - break; - - case GPS_ENC_SUPL_UTF8: - decoded = decodeUTF8String(input); - break; - - case GPS_ENC_SUPL_UCS2: - decoded = decodeUCS2String(input); - break; - - case GPS_ENC_UNKNOWN: - decoded = original; - break; - - default: - Log.e(TAG, "Unknown encoding " + coding + " for NI text " + original); - break; - } - return decoded; + String decoded = original; + byte[] input = stringToByteArray(original, isHex); + + switch (coding) { + case GPS_ENC_NONE: + decoded = original; + break; + + case GPS_ENC_SUPL_GSM_DEFAULT: + decoded = decodeGSMPackedString(input); + break; + + case GPS_ENC_SUPL_UTF8: + decoded = decodeUTF8String(input); + break; + + case GPS_ENC_SUPL_UCS2: + decoded = decodeUCS2String(input); + break; + + case GPS_ENC_UNKNOWN: + decoded = original; + break; + + default: + Log.e(TAG, "Unknown encoding " + coding + " for NI text " + original); + break; + } + return decoded; } - + // change this to configure notification display static private String getNotifTicker(GpsNiNotification notif) { - String ticker = String.format("Position request! ReqId: [%s] ClientName: [%s]", - decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding), - decodeString(notif.text, mIsHexInput, notif.textEncoding)); - return ticker; + String ticker = String.format("Position request! ReqId: [%s] ClientName: [%s]", + decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding), + decodeString(notif.text, mIsHexInput, notif.textEncoding)); + return ticker; } - + // change this to configure notification display static private String getNotifTitle(GpsNiNotification notif) { - String title = String.format("Position Request"); - return title; + String title = String.format("Position Request"); + return title; } - + // change this to configure notification display static private String getNotifMessage(GpsNiNotification notif) { - String message = String.format( - "NI Request received from [%s] for client [%s]!", - decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding), - decodeString(notif.text, mIsHexInput, notif.textEncoding)); - return message; + String message = String.format( + "NI Request received from [%s] for client [%s]!", + decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding), + decodeString(notif.text, mIsHexInput, notif.textEncoding)); + return message; } - + // change this to configure dialog display (for verification) static public String getDialogTitle(GpsNiNotification notif) { - return getNotifTitle(notif); + return getNotifTitle(notif); } - + // change this to configure dialog display (for verification) static private String getDialogMessage(GpsNiNotification notif) { - return getNotifMessage(notif); + return getNotifMessage(notif); } - + } -- GitLab From 00b74270c9f136a8727c5f6cda0997a3a905f385 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Fri, 26 Mar 2010 10:41:48 -0400 Subject: [PATCH 260/458] Move files internal to LocationManagerService from framework.jar to services.jar Change-Id: Iebbfc49b8300ab59730733efdf489ec87ea45a25 Signed-off-by: Mike Lockwood --- core/jni/Android.mk | 1 - core/jni/AndroidRuntime.cpp | 2 - .../android/location/LocationManager.java | 31 +++++++++++++ .../location/GpsNetInitiatedHandler.java | 24 +++++----- preloaded-classes | 2 - .../server/LocationManagerService.java | 35 +++++++------- .../server}/location/GeocoderProxy.java | 2 +- .../server}/location/GpsLocationProvider.java | 46 +++---------------- .../server}/location/GpsXtraDownloader.java | 16 +++---- .../location/LocationProviderInterface.java | 2 +- .../location/LocationProviderProxy.java | 5 +- .../server}/location/MockProvider.java | 3 +- .../server}/location/PassiveProvider.java | 3 +- .../server/status/StatusBarPolicy.java | 16 +++---- services/jni/Android.mk | 1 + ...id_server_location_GpsLocationProvider.cpp | 4 +- services/jni/onload.cpp | 2 + 17 files changed, 95 insertions(+), 100 deletions(-) rename {location/java/com/android/internal => services/java/com/android/server}/location/GeocoderProxy.java (98%) rename {location/java/com/android/internal => services/java/com/android/server}/location/GpsLocationProvider.java (97%) rename {location/java/com/android/internal => services/java/com/android/server}/location/GpsXtraDownloader.java (99%) rename {location/java/android => services/java/com/android/server}/location/LocationProviderInterface.java (97%) rename {location/java/com/android/internal => services/java/com/android/server}/location/LocationProviderProxy.java (99%) rename {location/java/com/android/internal => services/java/com/android/server}/location/MockProvider.java (98%) rename {location/java/com/android/internal => services/java/com/android/server}/location/PassiveProvider.java (97%) rename core/jni/android_location_GpsLocationProvider.cpp => services/jni/com_android_server_location_GpsLocationProvider.cpp (99%) diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 85d1a6f17dff..6d1a4148acf8 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -121,7 +121,6 @@ LOCAL_SRC_FILES:= \ android_server_BluetoothA2dpService.cpp \ android_message_digest_sha1.cpp \ android_ddm_DdmHandleNativeHeap.cpp \ - android_location_GpsLocationProvider.cpp \ com_android_internal_os_ZygoteInit.cpp \ com_android_internal_graphics_NativeUtils.cpp \ android_backup_BackupDataInput.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 7f8e8548c15f..c9e5bdcecccf 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -154,7 +154,6 @@ extern int register_android_server_BluetoothEventLoop(JNIEnv *env); extern int register_android_server_BluetoothA2dpService(JNIEnv* env); extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env); extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env); -extern int register_android_location_GpsLocationProvider(JNIEnv* env); extern int register_android_backup_BackupDataInput(JNIEnv *env); extern int register_android_backup_BackupDataOutput(JNIEnv *env); extern int register_android_backup_FileBackupHelperBase(JNIEnv *env); @@ -1267,7 +1266,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_server_BluetoothA2dpService), REG_JNI(register_android_message_digest_sha1), REG_JNI(register_android_ddm_DdmHandleNativeHeap), - REG_JNI(register_android_location_GpsLocationProvider), REG_JNI(register_android_backup_BackupDataInput), REG_JNI(register_android_backup_BackupDataOutput), REG_JNI(register_android_backup_FileBackupHelperBase), diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 9e4a16b241e6..28bc59982e34 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -117,6 +117,37 @@ public class LocationManager { */ public static final String KEY_LOCATION_CHANGED = "location"; + /** + * Broadcast intent action indicating that the GPS has either been + * enabled or disabled. An intent extra provides this state as a boolean, + * where {@code true} means enabled. + * @see #EXTRA_GPS_ENABLED + * + * {@hide} + */ + public static final String GPS_ENABLED_CHANGE_ACTION = + "android.location.GPS_ENABLED_CHANGE"; + + /** + * Broadcast intent action indicating that the GPS has either started or + * stopped receiving GPS fixes. An intent extra provides this state as a + * boolean, where {@code true} means that the GPS is actively receiving fixes. + * @see #EXTRA_GPS_ENABLED + * + * {@hide} + */ + public static final String GPS_FIX_CHANGE_ACTION = + "android.location.GPS_FIX_CHANGE"; + + /** + * The lookup key for a boolean that indicates whether GPS is enabled or + * disabled. {@code true} means GPS is enabled. Retrieve it with + * {@link android.content.Intent#getBooleanExtra(String,boolean)}. + * + * {@hide} + */ + public static final String EXTRA_GPS_ENABLED = "enabled"; + // Map from LocationListeners to their associated ListenerTransport objects private HashMap mListeners = new HashMap(); diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index 2cf9c2bf6353..d3a71b372730 100755 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -94,18 +94,18 @@ public class GpsNetInitiatedHandler { public static class GpsNiNotification { - int notificationId; - int niType; - boolean needNotify; - boolean needVerify; - boolean privacyOverride; - int timeout; - int defaultResponse; - String requestorId; - String text; - int requestorIdEncoding; - int textEncoding; - Bundle extras; + public int notificationId; + public int niType; + public boolean needNotify; + public boolean needVerify; + public boolean privacyOverride; + public int timeout; + public int defaultResponse; + public String requestorId; + public String text; + public int requestorIdEncoding; + public int textEncoding; + public Bundle extras; }; public static class GpsNiResponse { diff --git a/preloaded-classes b/preloaded-classes index 54c73039ba5f..5d2fd687d380 100644 --- a/preloaded-classes +++ b/preloaded-classes @@ -269,7 +269,6 @@ android.location.ILocationManager$Stub android.location.ILocationManager$Stub$Proxy android.location.Location android.location.LocationManager -android.location.LocationProviderInterface android.media.AudioFormat android.media.AudioManager android.media.AudioRecord @@ -633,7 +632,6 @@ com.android.internal.appwidget.IAppWidgetService$Stub com.android.internal.content.SyncStateContentProviderHelper com.android.internal.graphics.NativeUtils com.android.internal.location.DummyLocationProvider -com.android.internal.location.GpsLocationProvider com.android.internal.logging.AndroidHandler com.android.internal.os.AndroidPrintStream com.android.internal.os.BinderInternal diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index ef570568596b..f9c1a93c7f34 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -16,17 +16,6 @@ package com.android.server; -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Observable; -import java.util.Observer; -import java.util.Set; - import android.app.Activity; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -50,7 +39,6 @@ import android.location.INetInitiatedListener; import android.location.Location; import android.location.LocationManager; import android.location.LocationProvider; -import android.location.LocationProviderInterface; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; @@ -68,12 +56,25 @@ import android.util.Log; import android.util.Slog; import android.util.PrintWriterPrinter; -import com.android.internal.location.GeocoderProxy; -import com.android.internal.location.GpsLocationProvider; import com.android.internal.location.GpsNetInitiatedHandler; -import com.android.internal.location.LocationProviderProxy; -import com.android.internal.location.MockProvider; -import com.android.internal.location.PassiveProvider; + +import com.android.server.location.GeocoderProxy; +import com.android.server.location.GpsLocationProvider; +import com.android.server.location.LocationProviderInterface; +import com.android.server.location.LocationProviderProxy; +import com.android.server.location.MockProvider; +import com.android.server.location.PassiveProvider; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Observable; +import java.util.Observer; +import java.util.Set; /** * The service class that manages LocationProviders and issues location diff --git a/location/java/com/android/internal/location/GeocoderProxy.java b/services/java/com/android/server/location/GeocoderProxy.java similarity index 98% rename from location/java/com/android/internal/location/GeocoderProxy.java rename to services/java/com/android/server/location/GeocoderProxy.java index b06297baffc1..3c05da25eaf2 100644 --- a/location/java/com/android/internal/location/GeocoderProxy.java +++ b/services/java/com/android/server/location/GeocoderProxy.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.location; +package com.android.server.location; import android.content.ComponentName; import android.content.Context; diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java similarity index 97% rename from location/java/com/android/internal/location/GpsLocationProvider.java rename to services/java/com/android/server/location/GpsLocationProvider.java index e3124821e0bc..daa198f090e0 100755 --- a/location/java/com/android/internal/location/GpsLocationProvider.java +++ b/services/java/com/android/server/location/GpsLocationProvider.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.location; +package com.android.server.location; import android.app.AlarmManager; import android.app.PendingIntent; @@ -30,7 +30,6 @@ import android.location.INetInitiatedListener; import android.location.Location; import android.location.LocationManager; import android.location.LocationProvider; -import android.location.LocationProviderInterface; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.SntpClient; @@ -77,37 +76,6 @@ public class GpsLocationProvider implements LocationProviderInterface { private static final boolean DEBUG = false; private static final boolean VERBOSE = false; - /** - * Broadcast intent action indicating that the GPS has either been - * enabled or disabled. An intent extra provides this state as a boolean, - * where {@code true} means enabled. - * @see #EXTRA_ENABLED - * - * {@hide} - */ - public static final String GPS_ENABLED_CHANGE_ACTION = - "android.location.GPS_ENABLED_CHANGE"; - - /** - * Broadcast intent action indicating that the GPS has either started or - * stopped receiving GPS fixes. An intent extra provides this state as a - * boolean, where {@code true} means that the GPS is actively receiving fixes. - * @see #EXTRA_ENABLED - * - * {@hide} - */ - public static final String GPS_FIX_CHANGE_ACTION = - "android.location.GPS_FIX_CHANGE"; - - /** - * The lookup key for a boolean that indicates whether GPS is enabled or - * disabled. {@code true} means GPS is enabled. Retrieve it with - * {@link android.content.Intent#getBooleanExtra(String,boolean)}. - * - * {@hide} - */ - public static final String EXTRA_ENABLED = "enabled"; - // these need to match GpsPositionMode enum in gps.h private static final int GPS_POSITION_MODE_STANDALONE = 0; private static final int GPS_POSITION_MODE_MS_BASED = 1; @@ -1031,8 +999,8 @@ public class GpsLocationProvider implements LocationProviderInterface { } // send an intent to notify that the GPS is receiving fixes. - Intent intent = new Intent(GPS_FIX_CHANGE_ACTION); - intent.putExtra(EXTRA_ENABLED, true); + Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); + intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true); mContext.sendBroadcast(intent); updateStatus(LocationProvider.AVAILABLE, mSvCount); } @@ -1108,8 +1076,8 @@ public class GpsLocationProvider implements LocationProviderInterface { } // send an intent to notify that the GPS has been enabled or disabled. - Intent intent = new Intent(GPS_ENABLED_CHANGE_ACTION); - intent.putExtra(EXTRA_ENABLED, mNavigating); + Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION); + intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating); mContext.sendBroadcast(intent); } @@ -1165,8 +1133,8 @@ public class GpsLocationProvider implements LocationProviderInterface { if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 && System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT * 1000) { // send an intent to notify that the GPS is no longer receiving fixes. - Intent intent = new Intent(GPS_FIX_CHANGE_ACTION); - intent.putExtra(EXTRA_ENABLED, false); + Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); + intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false); mContext.sendBroadcast(intent); updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount); } diff --git a/location/java/com/android/internal/location/GpsXtraDownloader.java b/services/java/com/android/server/location/GpsXtraDownloader.java similarity index 99% rename from location/java/com/android/internal/location/GpsXtraDownloader.java rename to services/java/com/android/server/location/GpsXtraDownloader.java index 978bda2193ae..bc9698090b5e 100644 --- a/location/java/com/android/internal/location/GpsXtraDownloader.java +++ b/services/java/com/android/server/location/GpsXtraDownloader.java @@ -14,7 +14,13 @@ * limitations under the License. */ -package com.android.internal.location; +package com.android.server.location; + +import android.content.Context; +import android.net.Proxy; +import android.net.http.AndroidHttpClient; +import android.util.Config; +import android.util.Log; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; @@ -30,14 +36,6 @@ import java.io.IOException; import java.util.Properties; import java.util.Random; -import android.content.Context; -import android.net.Proxy; -import android.net.http.AndroidHttpClient; -import android.util.Config; -import android.util.Log; - - - /** * A class for downloading GPS XTRA data. * diff --git a/location/java/android/location/LocationProviderInterface.java b/services/java/com/android/server/location/LocationProviderInterface.java similarity index 97% rename from location/java/android/location/LocationProviderInterface.java rename to services/java/com/android/server/location/LocationProviderInterface.java index 5ffe15c359b2..a472143ff527 100644 --- a/location/java/android/location/LocationProviderInterface.java +++ b/services/java/com/android/server/location/LocationProviderInterface.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.location; +package com.android.server.location; import android.location.Location; import android.net.NetworkInfo; diff --git a/location/java/com/android/internal/location/LocationProviderProxy.java b/services/java/com/android/server/location/LocationProviderProxy.java similarity index 99% rename from location/java/com/android/internal/location/LocationProviderProxy.java rename to services/java/com/android/server/location/LocationProviderProxy.java index 31ec09a4503b..3e118f98c1be 100644 --- a/location/java/com/android/internal/location/LocationProviderProxy.java +++ b/services/java/com/android/server/location/LocationProviderProxy.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.location; +package com.android.server.location; import android.content.ComponentName; import android.content.Context; @@ -22,7 +22,6 @@ import android.content.Intent; import android.content.ServiceConnection; import android.location.ILocationProvider; import android.location.Location; -import android.location.LocationProviderInterface; import android.net.NetworkInfo; import android.os.Bundle; import android.os.Handler; @@ -31,6 +30,8 @@ import android.os.RemoteException; import android.os.SystemClock; import android.util.Log; +import com.android.internal.location.DummyLocationProvider; + /** * A class for proxying location providers implemented as services. * diff --git a/location/java/com/android/internal/location/MockProvider.java b/services/java/com/android/server/location/MockProvider.java similarity index 98% rename from location/java/com/android/internal/location/MockProvider.java rename to services/java/com/android/server/location/MockProvider.java index d912740f2e02..e3f334696e43 100644 --- a/location/java/com/android/internal/location/MockProvider.java +++ b/services/java/com/android/server/location/MockProvider.java @@ -14,12 +14,11 @@ * limitations under the License. */ -package com.android.internal.location; +package com.android.server.location; import android.location.ILocationManager; import android.location.Location; import android.location.LocationProvider; -import android.location.LocationProviderInterface; import android.net.NetworkInfo; import android.os.Bundle; import android.os.RemoteException; diff --git a/location/java/com/android/internal/location/PassiveProvider.java b/services/java/com/android/server/location/PassiveProvider.java similarity index 97% rename from location/java/com/android/internal/location/PassiveProvider.java rename to services/java/com/android/server/location/PassiveProvider.java index ab909371d5b6..5ed1558698dc 100644 --- a/location/java/com/android/internal/location/PassiveProvider.java +++ b/services/java/com/android/server/location/PassiveProvider.java @@ -14,13 +14,12 @@ * limitations under the License. */ -package com.android.internal.location; +package com.android.server.location; import android.location.ILocationManager; import android.location.Location; import android.location.LocationManager; import android.location.LocationProvider; -import android.location.LocationProviderInterface; import android.net.NetworkInfo; import android.os.Bundle; import android.os.RemoteException; diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java index 55840e272144..efb1a06aae67 100644 --- a/services/java/com/android/server/status/StatusBarPolicy.java +++ b/services/java/com/android/server/status/StatusBarPolicy.java @@ -30,6 +30,7 @@ import android.content.IntentFilter; import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; +import android.location.LocationManager; import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; @@ -62,7 +63,6 @@ import android.widget.TextView; import com.android.internal.R; import com.android.internal.app.IBatteryStats; -import com.android.internal.location.GpsLocationProvider; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.cdma.EriInfo; @@ -387,8 +387,8 @@ public class StatusBarPolicy { action.equals(WifiManager.RSSI_CHANGED_ACTION)) { updateWifi(intent); } - else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) || - action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION)) { + else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) || + action.equals(LocationManager.GPS_FIX_CHANGE_ACTION)) { updateGps(intent); } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) || @@ -533,8 +533,8 @@ public class StatusBarPolicy { filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); filter.addAction(WifiManager.RSSI_CHANGED_ACTION); - filter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION); - filter.addAction(GpsLocationProvider.GPS_FIX_CHANGE_ACTION); + filter.addAction(LocationManager.GPS_ENABLED_CHANGE_ACTION); + filter.addAction(LocationManager.GPS_FIX_CHANGE_ACTION); filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION); mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); @@ -1286,13 +1286,13 @@ public class StatusBarPolicy { private final void updateGps(Intent intent) { final String action = intent.getAction(); - final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false); + final boolean enabled = intent.getBooleanExtra(LocationManager.EXTRA_GPS_ENABLED, false); - if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) { + if (action.equals(LocationManager.GPS_FIX_CHANGE_ACTION) && enabled) { // GPS is getting fixes mService.updateIcon(mGpsIcon, mGpsFixIconData, null); mService.setIconVisibility(mGpsIcon, true); - } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) { + } else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) && !enabled) { // GPS is off mService.setIconVisibility(mGpsIcon, false); } else { diff --git a/services/jni/Android.mk b/services/jni/Android.mk index 9d2760e167c8..b90e327ea6e3 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -9,6 +9,7 @@ LOCAL_SRC_FILES:= \ com_android_server_SensorService.cpp \ com_android_server_SystemServer.cpp \ com_android_server_VibratorService.cpp \ + com_android_server_location_GpsLocationProvider.cpp \ onload.cpp LOCAL_C_INCLUDES += \ diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp similarity index 99% rename from core/jni/android_location_GpsLocationProvider.cpp rename to services/jni/com_android_server_location_GpsLocationProvider.cpp index a3be309a504f..003f109d6266 100755 --- a/core/jni/android_location_GpsLocationProvider.cpp +++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp @@ -523,9 +523,9 @@ static JNINativeMethod sMethods[] = { {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state}, }; -int register_android_location_GpsLocationProvider(JNIEnv* env) +int register_android_server_location_GpsLocationProvider(JNIEnv* env) { - return jniRegisterNativeMethods(env, "com/android/internal/location/GpsLocationProvider", sMethods, NELEM(sMethods)); + return jniRegisterNativeMethods(env, "com/android/server/location/GpsLocationProvider", sMethods, NELEM(sMethods)); } } /* namespace android */ diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp index c16fdb809a7a..d11e7e1b6b82 100644 --- a/services/jni/onload.cpp +++ b/services/jni/onload.cpp @@ -11,6 +11,7 @@ int register_android_server_LightsService(JNIEnv* env); int register_android_server_SensorService(JNIEnv* env); int register_android_server_VibratorService(JNIEnv* env); int register_android_server_SystemServer(JNIEnv* env); +int register_android_server_location_GpsLocationProvider(JNIEnv* env); }; using namespace android; @@ -33,6 +34,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) register_android_server_SensorService(env); register_android_server_VibratorService(env); register_android_server_SystemServer(env); + register_android_server_location_GpsLocationProvider(env); return JNI_VERSION_1_4; } -- GitLab From b7ff4574b5a8273b0ff43ca7f490ba5ceec42912 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Mon, 5 Apr 2010 15:24:34 -0400 Subject: [PATCH 261/458] Switch from hardware_legacy to new HAL GPS interface. Change-Id: I19b299fbcbd44d711a64ece98955d095eb9ffa2b Signed-off-by: Mike Lockwood --- ...id_server_location_GpsLocationProvider.cpp | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp index 003f109d6266..7a74fd4532ff 100755 --- a/services/jni/com_android_server_location_GpsLocationProvider.cpp +++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp @@ -20,8 +20,8 @@ #include "JNIHelp.h" #include "jni.h" -#include "hardware_legacy/gps.h" -#include "hardware_legacy/gps_ni.h" +#include "hardware/hardware.h" +#include "hardware/gps.h" #include "utils/Log.h" #include "utils/misc.h" @@ -204,16 +204,34 @@ static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V"); } +static const GpsInterface* get_gps_interface() { + int err; + hw_module_t* module; + const GpsInterface* interface = NULL; + + err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); + if (err == 0) { + hw_device_t* device; + err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device); + if (err == 0) { + gps_device_t* gps_device = (gps_device_t *)device; + interface = gps_device->get_gps_interface(gps_device); + } + } + + return interface; +} + static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) { if (!sGpsInterface) - sGpsInterface = gps_get_interface(); + sGpsInterface = get_gps_interface(); return (sGpsInterface != NULL); } static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj) { if (!sGpsInterface) - sGpsInterface = gps_get_interface(); + sGpsInterface = get_gps_interface(); if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) return false; -- GitLab From e58d1c4e4a03a41c9b8eee6b79304fbf85998d7d Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Mon, 5 Apr 2010 16:15:37 -0500 Subject: [PATCH 262/458] Redo the look of the recent apps switcher. Change-Id: Icb523e2f5949c2b502aa8003aa14b7ac98a616f2 --- .../internal/policy/impl/IconUtilities.java | 192 ++++++++++++++++++ .../impl/RecentApplicationsBackground.java | 152 ++++++++++++++ .../policy/impl/RecentApplicationsDialog.java | 89 ++++---- 3 files changed, 387 insertions(+), 46 deletions(-) create mode 100644 policy/com/android/internal/policy/impl/IconUtilities.java create mode 100644 policy/com/android/internal/policy/impl/RecentApplicationsBackground.java diff --git a/policy/com/android/internal/policy/impl/IconUtilities.java b/policy/com/android/internal/policy/impl/IconUtilities.java new file mode 100644 index 000000000000..99055cf73158 --- /dev/null +++ b/policy/com/android/internal/policy/impl/IconUtilities.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2008 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 android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.PaintDrawable; +import android.graphics.drawable.StateListDrawable; +import android.graphics.Bitmap; +import android.graphics.BlurMaskFilter; +import android.graphics.Canvas; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.Paint; +import android.graphics.PaintFlagsDrawFilter; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.TableMaskFilter; +import android.graphics.Typeface; +import android.text.Layout.Alignment; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.util.DisplayMetrics; +import android.util.Log; +import android.content.res.Resources; +import android.content.Context; + +/** + * Various utilities shared amongst the Launcher's classes. + */ +final class IconUtilities { + private static final String TAG = "IconUtilities"; + + private static final int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff }; + + private int mIconWidth = -1; + private int mIconHeight = -1; + private int mIconTextureWidth = -1; + private int mIconTextureHeight = -1; + + private final Paint mPaint = new Paint(); + private final Paint mBlurPaint = new Paint(); + private final Paint mGlowColorPressedPaint = new Paint(); + private final Paint mGlowColorFocusedPaint = new Paint(); + private final Rect mOldBounds = new Rect(); + private final Canvas mCanvas = new Canvas(); + private final DisplayMetrics mDisplayMetrics; + + private int mColorIndex = 0; + + public IconUtilities(Context context) { + final Resources resources = context.getResources(); + DisplayMetrics metrics = mDisplayMetrics = resources.getDisplayMetrics(); + final float density = metrics.density; + final float blurPx = 5 * density; + + mIconWidth = mIconHeight = (int) resources.getDimension(android.R.dimen.app_icon_size); + mIconTextureWidth = mIconTextureHeight = mIconWidth + (int)(blurPx*2); + + mBlurPaint.setMaskFilter(new BlurMaskFilter(blurPx, BlurMaskFilter.Blur.NORMAL)); + mGlowColorPressedPaint.setColor(0xffffc300); + mGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30)); + mGlowColorFocusedPaint.setColor(0xffff8e00); + mGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30)); + + ColorMatrix cm = new ColorMatrix(); + cm.setSaturation(0.2f); + + mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG, + Paint.FILTER_BITMAP_FLAG)); + } + + public Drawable createIconDrawable(Drawable src) { + Bitmap scaled = createIconBitmap(src); + + StateListDrawable result = new StateListDrawable(); + + result.addState(new int[] { android.R.attr.state_focused }, + new BitmapDrawable(createSelectedBitmap(scaled, false))); + result.addState(new int[] { android.R.attr.state_pressed }, + new BitmapDrawable(createSelectedBitmap(scaled, true))); + result.addState(new int[0], new BitmapDrawable(scaled)); + + result.setBounds(0, 0, mIconTextureWidth, mIconTextureHeight); + return result; + } + + /** + * Returns a bitmap suitable for the all apps view. The bitmap will be a power + * of two sized ARGB_8888 bitmap that can be used as a gl texture. + */ + private Bitmap createIconBitmap(Drawable icon) { + int width = mIconWidth; + int height = mIconHeight; + + if (icon instanceof PaintDrawable) { + PaintDrawable painter = (PaintDrawable) icon; + painter.setIntrinsicWidth(width); + painter.setIntrinsicHeight(height); + } else if (icon instanceof BitmapDrawable) { + // Ensure the bitmap has a density. + BitmapDrawable bitmapDrawable = (BitmapDrawable) icon; + Bitmap bitmap = bitmapDrawable.getBitmap(); + if (bitmap.getDensity() == Bitmap.DENSITY_NONE) { + bitmapDrawable.setTargetDensity(mDisplayMetrics); + } + } + int sourceWidth = icon.getIntrinsicWidth(); + int sourceHeight = icon.getIntrinsicHeight(); + + if (sourceWidth > 0 && sourceWidth > 0) { + // There are intrinsic sizes. + if (width < sourceWidth || height < sourceHeight) { + // It's too big, scale it down. + final float ratio = (float) sourceWidth / sourceHeight; + if (sourceWidth > sourceHeight) { + height = (int) (width / ratio); + } else if (sourceHeight > sourceWidth) { + width = (int) (height * ratio); + } + } else if (sourceWidth < width && sourceHeight < height) { + // It's small, use the size they gave us. + width = sourceWidth; + height = sourceHeight; + } + } + + // no intrinsic size --> use default size + int textureWidth = mIconTextureWidth; + int textureHeight = mIconTextureHeight; + + final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight, + Bitmap.Config.ARGB_8888); + final Canvas canvas = mCanvas; + canvas.setBitmap(bitmap); + + final int left = (textureWidth-width) / 2; + final int top = (textureHeight-height) / 2; + + if (false) { + // draw a big box for the icon for debugging + canvas.drawColor(sColors[mColorIndex]); + if (++mColorIndex >= sColors.length) mColorIndex = 0; + Paint debugPaint = new Paint(); + debugPaint.setColor(0xffcccc00); + canvas.drawRect(left, top, left+width, top+height, debugPaint); + } + + mOldBounds.set(icon.getBounds()); + icon.setBounds(left, top, left+width, top+height); + icon.draw(canvas); + icon.setBounds(mOldBounds); + + return bitmap; + } + + private Bitmap createSelectedBitmap(Bitmap src, boolean pressed) { + final Bitmap result = Bitmap.createBitmap(mIconTextureWidth, mIconTextureHeight, + Bitmap.Config.ARGB_8888); + final Canvas dest = new Canvas(result); + + dest.drawColor(0, PorterDuff.Mode.CLEAR); + + int[] xy = new int[2]; + Bitmap mask = src.extractAlpha(mBlurPaint, xy); + + dest.drawBitmap(mask, xy[0], xy[1], + pressed ? mGlowColorPressedPaint : mGlowColorFocusedPaint); + + mask.recycle(); + + dest.drawBitmap(src, 0, 0, mPaint); + + return result; + } +} diff --git a/policy/com/android/internal/policy/impl/RecentApplicationsBackground.java b/policy/com/android/internal/policy/impl/RecentApplicationsBackground.java new file mode 100644 index 000000000000..7c99e87928b8 --- /dev/null +++ b/policy/com/android/internal/policy/impl/RecentApplicationsBackground.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2010 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 android.content.Context; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Gravity; +import android.view.View; +import android.widget.LinearLayout; + +/** + * A vertical linear layout. However, instead of drawing the background + * behnd the items, it draws the background outside the items based on the + * padding. If there isn't enough room to draw both, it clips the background + * instead of the contents. + */ +public class RecentApplicationsBackground extends LinearLayout { + private static final String TAG = "RecentApplicationsBackground"; + + private boolean mBackgroundSizeChanged; + private Drawable mBackground; + private Rect mTmp0 = new Rect(); + private Rect mTmp1 = new Rect(); + + public RecentApplicationsBackground(Context context) { + this(context, null); + init(); + } + + public RecentApplicationsBackground(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + mBackground = getBackground(); + setBackgroundDrawable(null); + setPadding(0, 0, 0, 0); + setGravity(Gravity.CENTER); + } + + @Override + protected boolean setFrame(int left, int top, int right, int bottom) { + setWillNotDraw(false); + if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { + mBackgroundSizeChanged = true; + } + return super.setFrame(left, top, right, bottom); + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return who == mBackground || super.verifyDrawable(who); + } + + @Override + protected void drawableStateChanged() { + Drawable d = mBackground; + if (d != null && d.isStateful()) { + d.setState(getDrawableState()); + } + super.drawableStateChanged(); + } + + @Override + public void draw(Canvas canvas) { + final Drawable background = mBackground; + if (background != null) { + if (mBackgroundSizeChanged) { + mBackgroundSizeChanged = false; + Rect chld = mTmp0; + Rect bkg = mTmp1; + mBackground.getPadding(bkg); + getChildBounds(chld); + // This doesn't clamp to this view's bounds, which is what we want, + // so that the drawing is clipped. + final int top = chld.top - bkg.top; + final int bottom = chld.bottom + bkg.bottom; + // The background here is a gradient that wants to + // extend the full width of the screen (whatever that + // may be). + int left, right; + if (false) { + // This limits the width of the drawable. + left = chld.left - bkg.left; + right = chld.right + bkg.right; + } else { + // This expands it to full width. + left = 0; + right = getRight(); + } + background.setBounds(left, top, right, bottom); + } + } + mBackground.draw(canvas); + + if (false) { + android.graphics.Paint p = new android.graphics.Paint(); + p.setColor(0x88ffff00); + canvas.drawRect(background.getBounds(), p); + } + canvas.drawARGB((int)(0.75*0xff), 0, 0, 0); + + super.draw(canvas); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mBackground.setCallback(this); + setWillNotDraw(false); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mBackground.setCallback(null); + } + + private void getChildBounds(Rect r) { + r.left = r.top = Integer.MAX_VALUE; + r.bottom = r.right = Integer.MIN_VALUE; + final int N = getChildCount(); + for (int i=0; i, we'll use a simple index instead. - int button = 0; + int index = 0; int numTasks = recentTasks.size(); - for (int i = 0; i < numTasks && (button < NUM_BUTTONS); ++i) { + for (int i = 0; i < numTasks && (index < NUM_BUTTONS); ++i) { final ActivityManager.RecentTaskInfo info = recentTasks.get(i); // for debug purposes only, disallow first result to create empty lists @@ -204,39 +211,29 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener if (resolveInfo != null) { final ActivityInfo activityInfo = resolveInfo.activityInfo; final String title = activityInfo.loadLabel(pm).toString(); - final Drawable icon = activityInfo.loadIcon(pm); + Drawable icon = activityInfo.loadIcon(pm); if (title != null && title.length() > 0 && icon != null) { - final View b = mButtons[button]; - setButtonAppearance(b, title, icon); - b.setTag(intent); - b.setVisibility(View.VISIBLE); - b.setPressed(false); - b.clearFocus(); - ++button; + final TextView tv = mIcons[index]; + tv.setText(title); + icon = iconUtilities.createIconDrawable(icon); + tv.setCompoundDrawables(null, icon, null, null); + tv.setTag(intent); + tv.setVisibility(View.VISIBLE); + tv.setPressed(false); + tv.clearFocus(); + ++index; } } } // handle the case of "no icons to show" - mNoAppsText.setVisibility((button == 0) ? View.VISIBLE : View.GONE); + mNoAppsText.setVisibility((index == 0) ? View.VISIBLE : View.GONE); // hide the rest - for ( ; button < NUM_BUTTONS; ++button) { - mButtons[button].setVisibility(View.GONE); - } - } - - /** - * Adjust appearance of each icon-button - */ - private void setButtonAppearance(View theButton, final String theTitle, final Drawable icon) { - TextView tv = (TextView) theButton; - tv.setText(theTitle); - if (icon != null) { - icon.setBounds(0, 0, mIconSize, mIconSize); + for (; index < NUM_BUTTONS; ++index) { + mIcons[index].setVisibility(View.GONE); } - tv.setCompoundDrawables(null, icon, null, null); } /** -- GitLab From 59962ce3b0d8b7efec2840accca8fb7a6066f2bd Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 5 Apr 2010 18:01:24 -0700 Subject: [PATCH 263/458] Make pixels prettier. Change-Id: If3b0774b70cbe943894c15ffa1da111ad887010f --- libs/surfaceflinger/SurfaceFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp index 0722fda55eaf..8a197e256f61 100644 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ b/libs/surfaceflinger/SurfaceFlinger.cpp @@ -1298,7 +1298,7 @@ sp SurfaceFlinger::createNormalSurfaceLocked( format = PIXEL_FORMAT_RGBA_8888; break; case PIXEL_FORMAT_OPAQUE: - format = PIXEL_FORMAT_RGB_565; + format = PIXEL_FORMAT_RGBX_8888; break; } -- GitLab From 6e251d7d669b04a1601134d1d00412891bd9c186 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Tue, 6 Apr 2010 15:43:25 -0700 Subject: [PATCH 264/458] de-activate makefile Change-Id: I6def51dea7aab002f7dbbe1e2573f52a2caa94fe --- policy/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/Android.mk b/policy/Android.mk index f42cbac781ac..0e9d86da455d 100644 --- a/policy/Android.mk +++ b/policy/Android.mk @@ -10,4 +10,4 @@ LOCAL_SRC_FILES := \ LOCAL_MODULE := android.policy_phone LOCAL_UNINSTALLABLE_MODULE := true -include $(BUILD_JAVA_LIBRARY) +#include $(BUILD_JAVA_LIBRARY) -- GitLab From a5c51373d478ea33ffddab13ca8a722c297802ef Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Tue, 6 Apr 2010 20:21:30 -0500 Subject: [PATCH 265/458] Finish moving the policies out of frameworks/policies/base and into frameworks/base. Change-Id: Id3a0c06202b0f6f2206acf490c8655d340ee0556 --- CleanSpec.mk | 2 ++ policy/Android.mk | 5 ++--- tests/framework-tests/src/Android.mk | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CleanSpec.mk b/CleanSpec.mk index 707404ba3981..6455103a9163 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -51,6 +51,8 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/app) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/content) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/FrameworkTest_intermediates/) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android.policy*) +$(call add-clean-step, rm -rf $(TARGET_OUT_JAVA_LIBRARIES)/android.policy.jar) # ************************************************ diff --git a/policy/Android.mk b/policy/Android.mk index 0e9d86da455d..a887142601bd 100644 --- a/policy/Android.mk +++ b/policy/Android.mk @@ -7,7 +7,6 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ $(call all-subdir-java-files) -LOCAL_MODULE := android.policy_phone -LOCAL_UNINSTALLABLE_MODULE := true +LOCAL_MODULE := android.policy -#include $(BUILD_JAVA_LIBRARY) +include $(BUILD_JAVA_LIBRARY) diff --git a/tests/framework-tests/src/Android.mk b/tests/framework-tests/src/Android.mk index 54e33a4ce191..f537b52cffdb 100644 --- a/tests/framework-tests/src/Android.mk +++ b/tests/framework-tests/src/Android.mk @@ -5,6 +5,6 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_MODULE := framework-tests -LOCAL_JAVA_LIBRARIES := android.policy_phone android.test.runner +LOCAL_JAVA_LIBRARIES := android.policy android.test.runner include $(BUILD_JAVA_LIBRARY) -- GitLab From d0964b3fdf546cdd00a319072353818ed8d56f08 Mon Sep 17 00:00:00 2001 From: Matt Fischer Date: Mon, 22 Feb 2010 17:40:46 -0600 Subject: [PATCH 266/458] Only hold a weak pointer on SurfaceComposerClients Each process maintains an array of active SurfaceComposerClient objects, so that they can be reused as new surfaces are parceled across. When a SurfaceComposerClient is disposed, it will remove itself from this list. However, because the list maintains a strong reference on the object, a reference cycle is created, and the client is never deleted. This patch changes the list to maintain weak pointers on the clients instead. Change-Id: I93dc8155fe28b4e350366a3400cdf22a8c77cdd3 --- libs/ui/SurfaceComposerClient.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/ui/SurfaceComposerClient.cpp b/libs/ui/SurfaceComposerClient.cpp index eda84eff04f4..764e6442a484 100644 --- a/libs/ui/SurfaceComposerClient.cpp +++ b/libs/ui/SurfaceComposerClient.cpp @@ -56,7 +56,7 @@ namespace android { // Must not be holding SurfaceComposerClient::mLock when acquiring gLock here. static Mutex gLock; static sp gSurfaceManager; -static DefaultKeyedVector< sp, sp > gActiveConnections; +static DefaultKeyedVector< sp, wp > gActiveConnections; static SortedVector > gOpenTransactions; static sp gServerCblkMemory; static volatile surface_flinger_cblk_t* gServerCblk; @@ -193,7 +193,7 @@ SurfaceComposerClient::clientForConnection(const sp& conn) { // scope for lock Mutex::Autolock _l(gLock); - client = gActiveConnections.valueFor(conn); + client = gActiveConnections.valueFor(conn).promote(); } if (client == 0) { @@ -361,8 +361,8 @@ void SurfaceComposerClient::openGlobalTransaction() const size_t N = gActiveConnections.size(); VERBOSE("openGlobalTransaction (%ld clients)", N); for (size_t i=0; i client(gActiveConnections.valueAt(i)); - if (gOpenTransactions.indexOf(client) < 0) { + sp client(gActiveConnections.valueAt(i).promote()); + if (client != 0 && gOpenTransactions.indexOf(client) < 0) { if (client->openTransaction() == NO_ERROR) { if (gOpenTransactions.add(client) < 0) { // Ooops! -- GitLab From db3647ff4f1266e505e8d6406ba697b48d609a97 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 8 Apr 2010 18:34:07 -0700 Subject: [PATCH 267/458] fix [2420565] Surface.lockCanvas() updates the dirty region too often There was a bug where we were we could be reallocating buffers for no reason. Change-Id: Ieb8a81a289da9339ab7faf987cd3a73428943c1a --- libs/surfaceflinger_client/Surface.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index 5dd75c32135f..3c7a4d2f3431 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -495,9 +495,12 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer) // below we make sure we AT LEAST have the usage flags we want const uint32_t usage(getUsage()); const sp& backBuffer(mBuffers[bufIdx]); + + // Always call needNewBuffer(), since it clears the needed buffers flags + bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx); if (backBuffer == 0 || ((uint32_t(backBuffer->usage) & usage) != usage) || - mSharedBufferClient->needNewBuffer(bufIdx)) + needNewBuffer) { err = getBufferLocked(bufIdx, usage); LOGE_IF(err, "getBufferLocked(%ld, %08x) failed (%s)", @@ -717,25 +720,25 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) Region scratch(bounds); Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch); + const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion)); if (mNeedFullUpdate) { - // reset newDirtyRegion to bounds when a buffer is reallocated - // it would be better if this information was associated with - // the buffer and made available to outside of Surface. - // This will do for now though. mNeedFullUpdate = false; - newDirtyRegion.set(bounds); - } else { - newDirtyRegion.andSelf(bounds); + Region uninitialized(bounds); + uninitialized.subtractSelf(copyback | newDirtyRegion); + // reset newDirtyRegion to bounds when a buffer is reallocated + // and we have nothing to copy back to it + if (!uninitialized.isEmpty()) + newDirtyRegion.set(bounds); } + newDirtyRegion.andSelf(bounds); const sp& frontBuffer(mPostedBuffer); - if (frontBuffer !=0 && + if (frontBuffer != 0 && backBuffer->width == frontBuffer->width && backBuffer->height == frontBuffer->height && !(mFlags & ISurfaceComposer::eDestroyBackbuffer)) { - const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion)); - if (!copyback.isEmpty() && frontBuffer!=0) { + if (!copyback.isEmpty()) { // copy front to back copyBlt(backBuffer, frontBuffer, copyback); } -- GitLab From ab88ea9503e0d84d739e6f232ebe740a5b8959a8 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Mon, 5 Apr 2010 13:25:12 -0700 Subject: [PATCH 268/458] Remove legacy NO_OPENCORE code bypass from MediaPlayerService. Change-Id: I72db73c91673e0d7f1090e3b033ae915337dc16e --- media/libmediaplayerservice/MediaPlayerService.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 594e01049157..fed4f9533664 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -228,14 +228,10 @@ MediaPlayerService::~MediaPlayerService() sp MediaPlayerService::createMediaRecorder(pid_t pid) { -#ifndef NO_OPENCORE sp recorder = new MediaRecorderClient(this, pid); wp w = recorder; Mutex::Autolock lock(mLock); mMediaRecorderClients.add(w); -#else - sp recorder = NULL; -#endif LOGV("Create new media recorder client from pid %d", pid); return recorder; } -- GitLab From 71c27d991ad9f07cc7e28545bf6cd2b133668cd5 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Fri, 19 Mar 2010 11:43:15 -0700 Subject: [PATCH 269/458] Various fixes to enable recording on passion and nexus1. Change-Id: I75a461c9882e2449082ad754ee7b231c1ceec039 --- cmds/stagefright/record.cpp | 11 +- media/libstagefright/CameraSource.cpp | 7 - media/libstagefright/MPEG4Writer.cpp | 225 +++++++++++++++---- media/libstagefright/OMXCodec.cpp | 14 +- media/libstagefright/omx/OMXNodeInstance.cpp | 6 + 5 files changed, 211 insertions(+), 52 deletions(-) diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp index 845c85471f92..5a87f4ca2a6e 100644 --- a/cmds/stagefright/record.cpp +++ b/cmds/stagefright/record.cpp @@ -147,7 +147,7 @@ int main(int argc, char **argv) { OMXClient client; CHECK_EQ(client.connect(), OK); -#if 1 +#if 0 sp source = createSource(argv[1]); if (source == NULL) { @@ -165,14 +165,15 @@ int main(int argc, char **argv) { success = success && meta->findInt32(kKeyHeight, &height); CHECK(success); #else - int width = 800; + int width = 720; int height = 480; sp decoder = new DummySource(width, height); #endif sp enc_meta = new MetaData; // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); + // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); + enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); enc_meta->setInt32(kKeyWidth, width); enc_meta->setInt32(kKeyHeight, height); @@ -213,6 +214,8 @@ int main(int argc, char **argv) { #if 0 CameraSource *source = CameraSource::Create(); + source->start(); + printf("source = %p\n", source); for (int i = 0; i < 100; ++i) { @@ -227,6 +230,8 @@ int main(int argc, char **argv) { buffer = NULL; } + source->stop(); + delete source; source = NULL; #endif diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index 075b1e344480..f57ddc1f48a9 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -142,13 +142,6 @@ CameraSource::CameraSource(const sp &camera) mFirstFrameTimeUs(0), mNumFrames(0), mStarted(false) { - char value[PROPERTY_VALUE_MAX]; - if (property_get("ro.hardware", value, NULL) && !strcmp(value, "sholes")) { - // The hardware encoder(s) do not support yuv420, but only YCbYCr, - // fortunately the camera also supports this, so we needn't transcode. - mCamera->setParameters(String8("preview-format=yuv422i-yuyv")); - } - String8 s = mCamera->getParameters(); printf("params: \"%s\"\n", s.string()); diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 2cf0ddf7b69f..e0e2b939d90f 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -65,10 +66,15 @@ private: static void *ThreadWrapper(void *me); void threadEntry(); + status_t makeAVCCodecSpecificData( + const uint8_t *data, size_t size); + Track(const Track &); Track &operator=(const Track &); }; +#define USE_NALLEN_FOUR 1 + MPEG4Writer::MPEG4Writer(const char *filename) : mFile(fopen(filename, "wb")), mOffset(0), @@ -213,23 +219,55 @@ off_t MPEG4Writer::addSample(MediaBuffer *buffer) { return old_offset; } +static void StripStartcode(MediaBuffer *buffer) { + if (buffer->range_length() < 4) { + return; + } + + const uint8_t *ptr = + (const uint8_t *)buffer->data() + buffer->range_offset(); + + if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { + buffer->set_range( + buffer->range_offset() + 4, buffer->range_length() - 4); + } +} + off_t MPEG4Writer::addLengthPrefixedSample(MediaBuffer *buffer) { Mutex::Autolock autoLock(mLock); + StripStartcode(buffer); + off_t old_offset = mOffset; size_t length = buffer->range_length(); + +#if USE_NALLEN_FOUR + uint8_t x = length >> 24; + fwrite(&x, 1, 1, mFile); + x = (length >> 16) & 0xff; + fwrite(&x, 1, 1, mFile); + x = (length >> 8) & 0xff; + fwrite(&x, 1, 1, mFile); + x = length & 0xff; + fwrite(&x, 1, 1, mFile); +#else CHECK(length < 65536); uint8_t x = length >> 8; fwrite(&x, 1, 1, mFile); x = length & 0xff; fwrite(&x, 1, 1, mFile); +#endif fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 1, length, mFile); +#if USE_NALLEN_FOUR + mOffset += length + 4; +#else mOffset += length + 2; +#endif return old_offset; } @@ -380,6 +418,60 @@ void *MPEG4Writer::Track::ThreadWrapper(void *me) { return NULL; } +status_t MPEG4Writer::Track::makeAVCCodecSpecificData( + const uint8_t *data, size_t size) { + if (mCodecSpecificData != NULL) { + return ERROR_MALFORMED; + } + + if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) { + // Must start with a start-code. + return ERROR_MALFORMED; + } + + size_t picParamOffset = 4; + while (picParamOffset + 3 < size + && memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) { + ++picParamOffset; + } + + if (picParamOffset + 3 >= size) { + // Could not find start-code for pictureParameterSet. + return ERROR_MALFORMED; + } + + size_t seqParamSetLength = picParamOffset - 4; + size_t picParamSetLength = size - picParamOffset - 4; + + mCodecSpecificDataSize = + 6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2; + + mCodecSpecificData = malloc(mCodecSpecificDataSize); + uint8_t *header = (uint8_t *)mCodecSpecificData; + header[0] = 1; + header[1] = 0x42; // profile + header[2] = 0x80; + header[3] = 0x1e; // level + +#if USE_NALLEN_FOUR + header[4] = 0xfc | 3; // length size == 4 bytes +#else + header[4] = 0xfc | 1; // length size == 2 bytes +#endif + + header[5] = 0xe0 | 1; + header[6] = seqParamSetLength >> 8; + header[7] = seqParamSetLength & 0xff; + memcpy(&header[8], &data[4], seqParamSetLength); + header += 8 + seqParamSetLength; + header[0] = 1; + header[1] = picParamSetLength >> 8; + header[2] = picParamSetLength & 0xff; + memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength); + + return OK; +} + void MPEG4Writer::Track::threadEntry() { sp meta = mSource->getFormat(); const char *mime; @@ -399,54 +491,40 @@ void MPEG4Writer::Track::threadEntry() { ++count; - if (is_avc && count < 3) { - size_t size = buffer->range_length(); - - switch (count) { - case 1: - { - CHECK_EQ(mCodecSpecificData, NULL); - mCodecSpecificData = malloc(size + 8); - uint8_t *header = (uint8_t *)mCodecSpecificData; - header[0] = 1; - header[1] = 0x42; // profile - header[2] = 0x80; - header[3] = 0x1e; // level - header[4] = 0xfc | 3; - header[5] = 0xe0 | 1; - header[6] = size >> 8; - header[7] = size & 0xff; - memcpy(&header[8], - (const uint8_t *)buffer->data() + buffer->range_offset(), - size); - - mCodecSpecificDataSize = size + 8; + int32_t isCodecConfig; + if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) + && isCodecConfig) { + if (is_avc) { + status_t err = makeAVCCodecSpecificData( + (const uint8_t *)buffer->data() + + buffer->range_offset(), + buffer->range_length()); + + if (err != OK) { + LOGE("failed to parse avc codec specific data."); break; } - - case 2: - { - size_t offset = mCodecSpecificDataSize; - mCodecSpecificDataSize += size + 3; - mCodecSpecificData = realloc(mCodecSpecificData, mCodecSpecificDataSize); - uint8_t *header = (uint8_t *)mCodecSpecificData; - header[offset] = 1; - header[offset + 1] = size >> 8; - header[offset + 2] = size & 0xff; - memcpy(&header[offset + 3], - (const uint8_t *)buffer->data() + buffer->range_offset(), - size); + } else if (is_mpeg4) { + if (mCodecSpecificData != NULL) { break; } + + mCodecSpecificDataSize = buffer->range_length(); + mCodecSpecificData = malloc(mCodecSpecificDataSize); + memcpy(mCodecSpecificData, + (const uint8_t *)buffer->data() + + buffer->range_offset(), + buffer->range_length()); } buffer->release(); buffer = NULL; continue; - } + } else if (count == 1 && is_mpeg4 && mCodecSpecificData == NULL) { + // The TI mpeg4 encoder does not properly set the + // codec-specific-data flag. - if (mCodecSpecificData == NULL && is_mpeg4) { const uint8_t *data = (const uint8_t *)buffer->data() + buffer->range_offset(); @@ -474,13 +552,70 @@ void MPEG4Writer::Track::threadEntry() { memcpy(mCodecSpecificData, data, offset); buffer->set_range(buffer->range_offset() + offset, size - offset); + + if (size == offset) { + buffer->release(); + buffer = NULL; + + continue; + } + } else if (is_avc && count < 3) { + // The TI video encoder does not flag codec specific data + // as such and also splits up SPS and PPS across two buffers. + + const uint8_t *data = + (const uint8_t *)buffer->data() + buffer->range_offset(); + + size_t size = buffer->range_length(); + + CHECK(count == 2 || mCodecSpecificData == NULL); + + size_t offset = mCodecSpecificDataSize; + mCodecSpecificDataSize += size + 4; + mCodecSpecificData = + realloc(mCodecSpecificData, mCodecSpecificDataSize); + + memcpy((uint8_t *)mCodecSpecificData + offset, + "\x00\x00\x00\x01", 4); + + memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size); + + buffer->release(); + buffer = NULL; + + if (count == 2) { + void *tmp = mCodecSpecificData; + size = mCodecSpecificDataSize; + mCodecSpecificData = NULL; + mCodecSpecificDataSize = 0; + + status_t err = makeAVCCodecSpecificData( + (const uint8_t *)tmp, size); + + free(tmp); + tmp = NULL; + + if (err != OK) { + LOGE("failed to parse avc codec specific data."); + break; + } + } + + continue; } off_t offset = is_avc ? mOwner->addLengthPrefixedSample(buffer) : mOwner->addSample(buffer); SampleInfo info; - info.size = is_avc ? buffer->range_length() + 2 : buffer->range_length(); + info.size = is_avc +#if USE_NALLEN_FOUR + ? buffer->range_length() + 4 +#else + ? buffer->range_length() + 2 +#endif + : buffer->range_length(); + info.offset = offset; int64_t timestampUs; @@ -733,19 +868,29 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { mOwner->beginBox("stts"); mOwner->writeInt32(0); // version=0, flags=0 - mOwner->writeInt32(mSampleInfos.size() - 1); + mOwner->writeInt32(mSampleInfos.size()); List::iterator it = mSampleInfos.begin(); int64_t last = (*it).timestamp; + int64_t lastDuration = 1; + ++it; while (it != mSampleInfos.end()) { mOwner->writeInt32(1); - mOwner->writeInt32((*it).timestamp - last); + lastDuration = (*it).timestamp - last; + mOwner->writeInt32(lastDuration); last = (*it).timestamp; ++it; } + + // We don't really know how long the last frame lasts, since + // there is no frame time after it, just repeat the previous + // frame's duration. + mOwner->writeInt32(1); + mOwner->writeInt32(lastDuration); + mOwner->endBox(); // stts mOwner->beginBox("stsz"); diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 603708806557..41ce239797d8 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -137,6 +137,7 @@ static const CodecInfo kEncoderInfo[] = { { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" }, + { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" }, }; @@ -679,6 +680,7 @@ static size_t getFrameSize( case OMX_COLOR_FormatCbYCrY: return width * height * 2; + case OMX_COLOR_FormatYUV420Planar: case OMX_COLOR_FormatYUV420SemiPlanar: return (width * height * 3) / 2; @@ -706,7 +708,7 @@ void OMXCodec::setVideoInputFormat( OMX_COLOR_FORMATTYPE colorFormat = OMX_COLOR_FormatYUV420SemiPlanar; if (!strcasecmp("OMX.TI.Video.encoder", mComponentName)) { - colorFormat = OMX_COLOR_FormatYCbYCr; + colorFormat = OMX_COLOR_FormatYUV420Planar; } CHECK_EQ(setVideoPortFormatType( @@ -764,6 +766,14 @@ void OMXCodec::setVideoInputFormat( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); CHECK_EQ(err, OK); + err = mOMX->getParameter( + mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); + CHECK_EQ(err, OK); + + err = mOMX->setParameter( + mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); + CHECK_EQ(err, OK); + switch (compressionFormat) { case OMX_VIDEO_CodingMPEG4: { @@ -911,7 +921,7 @@ status_t OMXCodec::setupAVCEncoderParameters() { CHECK_EQ(err, OK); bitrateType.eControlRate = OMX_Video_ControlRateVariable; - bitrateType.nTargetBitrate = 1000000; + bitrateType.nTargetBitrate = 3000000; err = mOMX->setParameter( mNode, OMX_IndexParamVideoBitrate, diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index c1a010c2cbbf..5db516e9c727 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -264,6 +264,8 @@ status_t OMXNodeInstance::useBuffer( return UNKNOWN_ERROR; } + CHECK_EQ(header->pAppPrivate, buffer_meta); + *buffer = header; addActiveBuffer(portIndex, *buffer); @@ -294,6 +296,8 @@ status_t OMXNodeInstance::allocateBuffer( return UNKNOWN_ERROR; } + CHECK_EQ(header->pAppPrivate, buffer_meta); + *buffer = header; *buffer_data = header->pBuffer; @@ -325,6 +329,8 @@ status_t OMXNodeInstance::allocateBufferWithBackup( return UNKNOWN_ERROR; } + CHECK_EQ(header->pAppPrivate, buffer_meta); + *buffer = header; addActiveBuffer(portIndex, *buffer); -- GitLab From e2018ca9ff9234876bb5ba63d2f51b72396c5fca Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Tue, 23 Mar 2010 14:33:02 -0700 Subject: [PATCH 270/458] Remove unnecessary lock from AMRWriter. Change-Id: Ia02966d936dd8cbb31e92051578a3fa816885710 --- include/media/stagefright/AMRWriter.h | 4 +--- media/libstagefright/AMRWriter.cpp | 26 +++++--------------------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/include/media/stagefright/AMRWriter.h b/include/media/stagefright/AMRWriter.h index 372909a0bfbb..34f3c4a9777b 100644 --- a/include/media/stagefright/AMRWriter.h +++ b/include/media/stagefright/AMRWriter.h @@ -42,14 +42,12 @@ protected: virtual ~AMRWriter(); private: - Mutex mLock; - FILE *mFile; status_t mInitCheck; sp mSource; bool mStarted; volatile bool mDone; - bool mReachedEOS; + volatile bool mReachedEOS; pthread_t mThread; static void *ThreadWrapper(void *); diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp index bf4424b23e21..73ea56d2b612 100644 --- a/media/libstagefright/AMRWriter.cpp +++ b/media/libstagefright/AMRWriter.cpp @@ -53,8 +53,6 @@ status_t AMRWriter::initCheck() const { } status_t AMRWriter::addSource(const sp &source) { - Mutex::Autolock autoLock(mLock); - if (mInitCheck != OK) { return mInitCheck; } @@ -95,8 +93,6 @@ status_t AMRWriter::addSource(const sp &source) { } status_t AMRWriter::start() { - Mutex::Autolock autoLock(mLock); - if (mInitCheck != OK) { return mInitCheck; } @@ -127,16 +123,12 @@ status_t AMRWriter::start() { } void AMRWriter::stop() { - { - Mutex::Autolock autoLock(mLock); - - if (!mStarted) { - return; - } - - mDone = true; + if (!mStarted) { + return; } + mDone = true; + void *dummy; pthread_join(mThread, &dummy); @@ -153,13 +145,7 @@ void *AMRWriter::ThreadWrapper(void *me) { } void AMRWriter::threadFunc() { - for (;;) { - Mutex::Autolock autoLock(mLock); - - if (mDone) { - break; - } - + while (!mDone) { MediaBuffer *buffer; status_t err = mSource->read(&buffer); @@ -184,12 +170,10 @@ void AMRWriter::threadFunc() { buffer = NULL; } - Mutex::Autolock autoLock(mLock); mReachedEOS = true; } bool AMRWriter::reachedEOS() { - Mutex::Autolock autoLock(mLock); return mReachedEOS; } -- GitLab From f4e5baa1e9ba464de8c1cd8cfeda29c95f3fe81f Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Fri, 9 Apr 2010 14:25:46 -0700 Subject: [PATCH 271/458] I accidentally broken passion encoding while working around problems with the sholes encoder. Change-Id: Id91b837ed17083cb21efb08e1c1ab9cc3ff3fa8f --- media/libstagefright/MPEG4Writer.cpp | 66 ++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index e0e2b939d90f..5ff2abe54f30 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -60,6 +60,7 @@ private: void *mCodecSpecificData; size_t mCodecSpecificDataSize; + bool mGotAllCodecSpecificData; bool mReachedEOS; @@ -358,6 +359,7 @@ MPEG4Writer::Track::Track( mMaxTimeStampUs(0), mCodecSpecificData(NULL), mCodecSpecificDataSize(0), + mGotAllCodecSpecificData(false), mReachedEOS(false) { } @@ -418,14 +420,58 @@ void *MPEG4Writer::Track::ThreadWrapper(void *me) { return NULL; } +#include +static void hexdump(const void *_data, size_t size) { + const uint8_t *data = (const uint8_t *)_data; + size_t offset = 0; + while (offset < size) { + printf("0x%04x ", offset); + + size_t n = size - offset; + if (n > 16) { + n = 16; + } + + for (size_t i = 0; i < 16; ++i) { + if (i == 8) { + printf(" "); + } + + if (offset + i < size) { + printf("%02x ", data[offset + i]); + } else { + printf(" "); + } + } + + printf(" "); + + for (size_t i = 0; i < n; ++i) { + if (isprint(data[offset + i])) { + printf("%c", data[offset + i]); + } else { + printf("."); + } + } + + printf("\n"); + + offset += 16; + } +} + + status_t MPEG4Writer::Track::makeAVCCodecSpecificData( const uint8_t *data, size_t size) { + // hexdump(data, size); + if (mCodecSpecificData != NULL) { + LOGE("Already have codec specific data"); return ERROR_MALFORMED; } if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) { - // Must start with a start-code. + LOGE("Must start with a start code"); return ERROR_MALFORMED; } @@ -436,7 +482,7 @@ status_t MPEG4Writer::Track::makeAVCCodecSpecificData( } if (picParamOffset + 3 >= size) { - // Could not find start-code for pictureParameterSet. + LOGE("Could not find start-code for pictureParameterSet"); return ERROR_MALFORMED; } @@ -494,6 +540,8 @@ void MPEG4Writer::Track::threadEntry() { int32_t isCodecConfig; if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) && isCodecConfig) { + CHECK(!mGotAllCodecSpecificData); + if (is_avc) { status_t err = makeAVCCodecSpecificData( (const uint8_t *)buffer->data() @@ -505,10 +553,6 @@ void MPEG4Writer::Track::threadEntry() { break; } } else if (is_mpeg4) { - if (mCodecSpecificData != NULL) { - break; - } - mCodecSpecificDataSize = buffer->range_length(); mCodecSpecificData = malloc(mCodecSpecificDataSize); memcpy(mCodecSpecificData, @@ -520,8 +564,10 @@ void MPEG4Writer::Track::threadEntry() { buffer->release(); buffer = NULL; + mGotAllCodecSpecificData = true; continue; - } else if (count == 1 && is_mpeg4 && mCodecSpecificData == NULL) { + } else if (!mGotAllCodecSpecificData && + count == 1 && is_mpeg4 && mCodecSpecificData == NULL) { // The TI mpeg4 encoder does not properly set the // codec-specific-data flag. @@ -559,7 +605,9 @@ void MPEG4Writer::Track::threadEntry() { continue; } - } else if (is_avc && count < 3) { + + mGotAllCodecSpecificData = true; + } else if (!mGotAllCodecSpecificData && is_avc && count < 3) { // The TI video encoder does not flag codec specific data // as such and also splits up SPS and PPS across two buffers. @@ -599,6 +647,8 @@ void MPEG4Writer::Track::threadEntry() { LOGE("failed to parse avc codec specific data."); break; } + + mGotAllCodecSpecificData = true; } continue; -- GitLab From e547835c5210c2ae022c7429e7a75ac17290bf40 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 9 Apr 2010 13:37:34 -0700 Subject: [PATCH 272/458] small cleanup. gEGLImpl should have been static also added a ctor to initialized it in case we use it ont he stack one day. Change-Id: I2736b9bce3d8ba3b74fd029de4c18cca2cdbbf60 --- opengl/libs/EGL/egl.cpp | 2 +- opengl/libs/egl_impl.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 89b3e1f2abca..e6cf7924431f 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -239,7 +239,7 @@ struct tls_t // ---------------------------------------------------------------------------- -egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS]; +static egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS]; static egl_display_t gDisplay[NUM_DISPLAYS]; static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_key_t gEGLThreadLocalStorageKey = -1; diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h index 1fba209f7707..c8f529ac0569 100644 --- a/opengl/libs/egl_impl.h +++ b/opengl/libs/egl_impl.h @@ -31,6 +31,7 @@ namespace android { struct egl_connection_t { + inline egl_connection_t() : dso(0) { } void * dso; gl_hooks_t * hooks[2]; EGLint major; -- GitLab From c6dd77d04a94b7fa0659a099e5b85b70f5f2ea9f Mon Sep 17 00:00:00 2001 From: Naveen Kalla Date: Wed, 7 Apr 2010 17:54:33 -0700 Subject: [PATCH 273/458] telephony: Fix CID when CID is unknown Unknown CID is indicated as 0xFFFFFFFF by ril. When telephony receives that value, set CID to UNKNOWN. --- .../java/android/telephony/NeighboringCellInfo.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/telephony/java/android/telephony/NeighboringCellInfo.java b/telephony/java/android/telephony/NeighboringCellInfo.java index ad7dfc9e2858..2f7666d118bc 100644 --- a/telephony/java/android/telephony/NeighboringCellInfo.java +++ b/telephony/java/android/telephony/NeighboringCellInfo.java @@ -133,8 +133,11 @@ public class NeighboringCellInfo implements Parcelable case NETWORK_TYPE_GPRS: case NETWORK_TYPE_EDGE: mNetworkType = radioType; - mLac = Integer.valueOf(location.substring(0, 4), 16); - mCid = Integer.valueOf(location.substring(4), 16); + // check if 0xFFFFFFFF for UNKNOWN_CID + if (!location.equalsIgnoreCase("FFFFFFFF")) { + mCid = Integer.valueOf(location.substring(4), 16); + mLac = Integer.valueOf(location.substring(0, 4), 16); + } break; case NETWORK_TYPE_UMTS: case NETWORK_TYPE_HSDPA: @@ -293,4 +296,4 @@ public class NeighboringCellInfo implements Parcelable return new NeighboringCellInfo[size]; } }; -} \ No newline at end of file +} -- GitLab From 8b138323d54e36fd66b22a634494648e20c53373 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 12 Apr 2010 16:22:15 -0700 Subject: [PATCH 274/458] don't hardcode "mSurface" throughout our source code this is used in a few places to get access to the android.view.Surface native surface. use a macro instead. Also rename the field to mNativeSurface. Change-Id: I1c6dea14abd6b8b1392c7f97b304115999355094 --- core/java/android/view/Surface.java | 10 +++++----- core/jni/android_hardware_Camera.cpp | 2 +- core/jni/android_view_Surface.cpp | 3 ++- core/jni/com_google_android_gles_jni_EGLImpl.cpp | 2 +- graphics/jni/android_renderscript_RenderScript.cpp | 2 +- include/surfaceflinger/Surface.h | 2 ++ media/jni/android_media_MediaPlayer.cpp | 2 +- media/jni/android_media_MediaRecorder.cpp | 2 +- media/libmedia/IOMX.cpp | 2 +- 9 files changed, 15 insertions(+), 12 deletions(-) diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 255e31795837..cde20e454b10 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -139,14 +139,14 @@ public class Surface implements Parcelable { */ public static final int FLAGS_ORIENTATION_ANIMATION_DISABLE = 0x000000001; - @SuppressWarnings("unused") - private int mSurface; @SuppressWarnings("unused") private int mSurfaceControl; @SuppressWarnings("unused") private int mSaveCount; @SuppressWarnings("unused") private Canvas mCanvas; + @SuppressWarnings("unused") + private int mNativeSurface; // The display metrics used to provide the pseudo canvas size for applications // running in compatibility mode. This is set to null for non compatibility mode. @@ -420,13 +420,13 @@ public class Surface implements Parcelable { /* no user serviceable parts here ... */ @Override protected void finalize() throws Throwable { - if (mSurface != 0 || mSurfaceControl != 0) { + if (mNativeSurface != 0 || mSurfaceControl != 0) { if (DEBUG_RELEASE) { Log.w(LOG_TAG, "Surface.finalize() has work. You should have called release() (" - + mSurface + ", " + mSurfaceControl + ")", mCreationStack); + + mNativeSurface + ", " + mSurfaceControl + ")", mCreationStack); } else { Log.w(LOG_TAG, "Surface.finalize() has work. You should have called release() (" - + mSurface + ", " + mSurfaceControl + ")"); + + mNativeSurface + ", " + mSurfaceControl + ")"); } } release(); diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index b85466b5925d..6c27841108bf 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -659,7 +659,7 @@ int register_android_hardware_Camera(JNIEnv *env) { field fields_to_find[] = { { "android/hardware/Camera", "mNativeContext", "I", &fields.context }, - { "android/view/Surface", "mSurface", "I", &fields.surface } + { "android/view/Surface", ANDROID_VIEW_SURFACE_JNI_ID, "I", &fields.surface } }; if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0) diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index ed26cbe44082..817f0c5ea562 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -19,6 +19,7 @@ #include "android_util_Binder.h" #include +#include #include #include @@ -670,7 +671,7 @@ static JNINativeMethod gSurfaceMethods[] = { void nativeClassInit(JNIEnv* env, jclass clazz) { - so.surface = env->GetFieldID(clazz, "mSurface", "I"); + so.surface = env->GetFieldID(clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I"); so.surfaceControl = env->GetFieldID(clazz, "mSurfaceControl", "I"); so.saveCount = env->GetFieldID(clazz, "mSaveCount", "I"); so.canvas = env->GetFieldID(clazz, "mCanvas", "Landroid/graphics/Canvas;"); diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp index 6a8c4b9281cc..01a15047091a 100644 --- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp @@ -96,7 +96,7 @@ static void nativeClassInit(JNIEnv *_env, jclass eglImplClass) gConfig_EGLConfigFieldID = _env->GetFieldID(gConfig_class, "mEGLConfig", "I"); jclass surface_class = _env->FindClass("android/view/Surface"); - gSurface_SurfaceFieldID = _env->GetFieldID(surface_class, "mSurface", "I"); + gSurface_SurfaceFieldID = _env->GetFieldID(surface_class, ANDROID_VIEW_SURFACE_JNI_ID, "I"); jclass bitmap_class = _env->FindClass("android/graphics/Bitmap"); gBitmap_NativeBitmapFieldID = _env->GetFieldID(bitmap_class, "mNativeBitmap", "I"); diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp index d8e03936aa7b..45cc72e7e41b 100644 --- a/graphics/jni/android_renderscript_RenderScript.cpp +++ b/graphics/jni/android_renderscript_RenderScript.cpp @@ -185,7 +185,7 @@ nContextSetSurface(JNIEnv *_env, jobject _this, jint width, jint height, jobject } else { jclass surface_class = _env->FindClass("android/view/Surface"); - jfieldID surfaceFieldID = _env->GetFieldID(surface_class, "mSurface", "I"); + jfieldID surfaceFieldID = _env->GetFieldID(surface_class, ANDROID_VIEW_SURFACE_JNI_ID, "I"); window = (Surface*)_env->GetIntField(wnd, surfaceFieldID); } diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h index 0279d84b64fe..4c8d0235f6a3 100644 --- a/include/surfaceflinger/Surface.h +++ b/include/surfaceflinger/Surface.h @@ -30,6 +30,8 @@ #include #include +#define ANDROID_VIEW_SURFACE_JNI_ID "mNativeSurface" + namespace android { // --------------------------------------------------------------------------- diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 8ed37301156e..60ff26493487 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -636,7 +636,7 @@ android_media_MediaPlayer_native_init(JNIEnv *env) return; } - fields.surface_native = env->GetFieldID(surface, "mSurface", "I"); + fields.surface_native = env->GetFieldID(surface, ANDROID_VIEW_SURFACE_JNI_ID, "I"); if (fields.surface_native == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Can't find Surface.mSurface"); return; diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index 00af3a286836..8cf2e51dcc72 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -403,7 +403,7 @@ android_media_MediaRecorder_native_init(JNIEnv *env) return; } - fields.surface_native = env->GetFieldID(surface, "mSurface", "I"); + fields.surface_native = env->GetFieldID(surface, ANDROID_VIEW_SURFACE_JNI_ID, "I"); if (fields.surface_native == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Can't find Surface.mSurface"); return; diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index 01b67374ab01..f3804b8cfd49 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -57,7 +57,7 @@ sp IOMX::createRendererFromJavaSurface( return NULL; } - jfieldID surfaceID = env->GetFieldID(surfaceClass, "mSurface", "I"); + jfieldID surfaceID = env->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I"); if (surfaceID == NULL) { LOGE("Can't find Surface.mSurface"); return NULL; -- GitLab From e82ca2dec0469714650b9e3d23a554d4ba9dab9f Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Tue, 13 Apr 2010 14:41:27 -0400 Subject: [PATCH 275/458] Manually integrating froyo lockscreen fixes: I6872c3ad135bc34348adafa76e08a3878f1b506f "Add emergency call button to PUK'd lockscreen." Bug: 2568732 I5ad8745443fc97225af9efb938e4640cfc29b5d7 "Restore text field used by sliding tab to give ringer mode feedback." Bug: 2587358 Change-Id: Ide3ad839aaf029930c0bf7ba4b9f6587efbd811d --- .../internal/policy/impl/LockScreen.java | 63 ++++++++++--------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index baed9ebcea32..a5ef1fab389f 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -66,6 +66,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private TextView mStatus1; private TextView mStatus2; private TextView mScreenLocked; + private TextView mEmergencyCallText; private Button mEmergencyCallButton; // current configuration state of keyboard and display @@ -185,7 +186,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM Log.v(TAG, "Cur orient=" + mCreationOrientation + " res orient=" + context.getResources().getConfiguration().orientation); } - + final LayoutInflater inflater = LayoutInflater.from(context); if (DBG) Log.v(TAG, "Creation orientation = " + mCreationOrientation); if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) { @@ -203,19 +204,23 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mStatus1 = (TextView) findViewById(R.id.status1); mStatus2 = (TextView) findViewById(R.id.status2); - mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); - mEmergencyCallButton.setText(R.string.lockscreen_emergency_call); - mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); 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); + mEmergencyCallButton.setText(R.string.lockscreen_emergency_call); + + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); mEmergencyCallButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mCallback.takeEmergencyCallAction(); } }); + setFocusable(true); setFocusableInTouchMode(true); setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); @@ -269,7 +274,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM refreshBatteryStringAndIcon(); refreshAlarmDisplay(); - mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); mTimeFormat = DateFormat.getTimeFormat(getContext()); mDateFormatString = getContext().getString(R.string.full_wday_month_day_no_year); @@ -340,8 +344,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM * @param iconResourceId The left hand icon. */ private void toastMessage(final TextView textView, final String text, final int color, final int iconResourceId) { - if (DBG) android.util.Log.d("LockScreen", "toastMessage(text=" + text +", color=" + color + ")"); - if (mPendingR1 != null) { textView.removeCallbacks(mPendingR1); mPendingR1 = null; @@ -499,9 +501,11 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM * Update the layout to match the current status. */ private void updateLayout(Status status) { - // The emergency call button appears where the carrier would - // ordinarily be shown, so if one is VISIBLE the other must be - // INVISIBLE. + // The emergency call button no longer appears on this screen. + if (DBG) Log.d(TAG, "updateLayout: status=" + status); + + mEmergencyCallButton.setVisibility(View.GONE); // in almost all cases + switch (status) { case Normal: // text @@ -509,12 +513,14 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM getCarrierString( mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn())); -// mScreenLocked.setText(R.string.lockscreen_screen_locked); + + // Empty now, but used for sliding tab feedback + mScreenLocked.setText(""); // layout mScreenLocked.setVisibility(View.VISIBLE); mSelector.setVisibility(View.VISIBLE); - mEmergencyCallButton.setVisibility(View.GONE); + mEmergencyCallText.setVisibility(View.GONE); break; case NetworkLocked: // The carrier string shows both sim card status (i.e. No Sim Card) and @@ -528,34 +534,31 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); mSelector.setVisibility(View.VISIBLE); - mEmergencyCallButton.setVisibility(View.GONE); + mEmergencyCallText.setVisibility(View.GONE); break; case SimMissing: // text - mCarrier.setText(""); - mScreenLocked.setText( - getCarrierString( - mUpdateMonitor.getTelephonyPlmn(), - getContext().getText(R.string.lockscreen_missing_sim_message_short))); - // previously shown here: lockscreen_instructions_when_pattern_disabled + mCarrier.setText(R.string.lockscreen_missing_sim_message_short); + mScreenLocked.setText(R.string.lockscreen_missing_sim_instructions); // layout mScreenLocked.setVisibility(View.VISIBLE); mSelector.setVisibility(View.VISIBLE); - mEmergencyCallButton.setVisibility(View.VISIBLE); + mEmergencyCallText.setVisibility(View.VISIBLE); + // do not need to show the e-call button; user may unlock break; case SimMissingLocked: // text - mCarrier.setText(""); - mScreenLocked.setText( + mCarrier.setText( getCarrierString( mUpdateMonitor.getTelephonyPlmn(), getContext().getText(R.string.lockscreen_missing_sim_message_short))); - // previously shown here: lockscreen_missing_sim_instructions + mScreenLocked.setText(R.string.lockscreen_missing_sim_instructions); // layout mScreenLocked.setVisibility(View.VISIBLE); - mSelector.setVisibility(View.GONE); + mSelector.setVisibility(View.GONE); // cannot unlock + mEmergencyCallText.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.VISIBLE); break; case SimLocked: @@ -568,20 +571,20 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.INVISIBLE); mSelector.setVisibility(View.VISIBLE); - mEmergencyCallButton.setVisibility(View.GONE); + mEmergencyCallText.setVisibility(View.GONE); break; case SimPukLocked: // text - mCarrier.setText(""); - mScreenLocked.setText( + mCarrier.setText( getCarrierString( mUpdateMonitor.getTelephonyPlmn(), getContext().getText(R.string.lockscreen_sim_puk_locked_message))); - // previously shown here: lockscreen_sim_puk_locked_instructions); + mScreenLocked.setText(R.string.lockscreen_sim_puk_locked_instructions); // layout mScreenLocked.setVisibility(View.VISIBLE); - mSelector.setVisibility(View.GONE); + mSelector.setVisibility(View.GONE); // cannot unlock + mEmergencyCallText.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.VISIBLE); break; } @@ -618,7 +621,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } } } - + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); -- GitLab From e9c0a6d73711ace2ed53f90862ef06f3d0ed6afe Mon Sep 17 00:00:00 2001 From: Naveen Kalla Date: Wed, 17 Mar 2010 09:17:56 -0700 Subject: [PATCH 276/458] Telephony: Add PUK MMI code support for CDMA RUIM phones Add support to unlock RUIM using PUK. PUK is entered using MMI codes. --- .../internal/telephony/cdma/CDMAPhone.java | 45 ++- .../internal/telephony/cdma/CdmaMmiCode.java | 296 ++++++++++++++++++ 2 files changed, 338 insertions(+), 3 deletions(-) create mode 100644 telephony/java/com/android/internal/telephony/cdma/CdmaMmiCode.java diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java index 3548cad95cb6..f94ec4b0476a 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java @@ -67,6 +67,7 @@ import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OP import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY; +import java.util.ArrayList; import java.util.List; @@ -101,6 +102,7 @@ public class CDMAPhone extends PhoneBase { RuimFileHandler mRuimFileHandler; RuimRecords mRuimRecords; RuimCard mRuimCard; + ArrayList mPendingMmis = new ArrayList(); RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager; RuimSmsInterfaceManager mRuimSmsInterfaceManager; PhoneSubInfo mSubInfo; @@ -223,6 +225,8 @@ public class CDMAPhone extends PhoneBase { mSST.unregisterForNetworkAttach(this); //EVENT_REGISTERED_TO_NETWORK mCM.unSetOnSuppServiceNotification(this); + mPendingMmis.clear(); + //Force all referenced classes to unregister their former registered events mCT.dispose(); mDataConnection.dispose(); @@ -365,8 +369,7 @@ public class CDMAPhone extends PhoneBase { public List getPendingMmiCodes() { - Log.e(LOG_TAG, "method getPendingMmiCodes is NOT supported in CDMA!"); - return null; + return mPendingMmis; } public void registerForSuppServiceNotification( @@ -383,6 +386,15 @@ public class CDMAPhone extends PhoneBase { return false; } + boolean isInCall() { + CdmaCall.State foregroundCallState = getForegroundCall().getState(); + CdmaCall.State backgroundCallState = getBackgroundCall().getState(); + CdmaCall.State ringingCallState = getRingingCall().getState(); + + return (foregroundCallState.isAlive() || backgroundCallState.isAlive() || ringingCallState + .isAlive()); + } + public void setNetworkSelectionModeAutomatic(Message response) { Log.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!"); @@ -482,7 +494,18 @@ public class CDMAPhone extends PhoneBase { } public boolean handlePinMmi(String dialString) { - Log.e(LOG_TAG, "method handlePinMmi is NOT supported in CDMA!"); + CdmaMmiCode mmi = CdmaMmiCode.newFromDialString(dialString, this); + + if (mmi == null) { + Log.e(LOG_TAG, "Mmi is NULL!"); + return false; + } else if (mmi.isPukCommand()) { + mPendingMmis.add(mmi); + mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); + mmi.processCode(); + return true; + } + Log.e(LOG_TAG, "Unrecognized mmi!"); return false; } @@ -494,6 +517,22 @@ public class CDMAPhone extends PhoneBase { (mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming()); } + /** + * Removes the given MMI from the pending list and notifies registrants that + * it is complete. + * + * @param mmi MMI that is done + */ + void onMMIDone(CdmaMmiCode mmi) { + /* + * Only notify complete if it's on the pending list. Otherwise, it's + * already been handled (eg, previously canceled). + */ + if (mPendingMmis.remove(mmi)) { + mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); + } + } + public void setLine1Number(String alphaTag, String number, Message onComplete) { Log.e(LOG_TAG, "setLine1Number: not possible in CDMA"); } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaMmiCode.java b/telephony/java/com/android/internal/telephony/cdma/CdmaMmiCode.java new file mode 100644 index 000000000000..8dd8c2e6c679 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaMmiCode.java @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2006 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.telephony.cdma; + +import android.content.Context; + +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.MmiCode; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +/** + * This class can handle Puk code Mmi + * + * {@hide} + * + */ +public final class CdmaMmiCode extends Handler implements MmiCode { + static final String LOG_TAG = "CDMA_MMI"; + + // Constants + + // From TS 22.030 6.5.2 + static final String ACTION_REGISTER = "**"; + + // Supp Service codes from TS 22.030 Annex B + static final String SC_PUK = "05"; + + // Event Constant + + static final int EVENT_SET_COMPLETE = 1; + + // Instance Variables + + CDMAPhone phone; + Context context; + + String action; // ACTION_REGISTER + String sc; // Service Code + String sia, sib, sic; // Service Info a,b,c + String poundString; // Entire MMI string up to and including # + String dialingNumber; + String pwd; // For password registration + + State state = State.PENDING; + CharSequence message; + + // Class Variables + + static Pattern sPatternSuppService = Pattern.compile( + "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)"); +/* 1 2 3 4 5 6 7 8 9 10 11 12 + + 1 = Full string up to and including # + 2 = action + 3 = service code + 5 = SIA + 7 = SIB + 9 = SIC + 10 = dialing number +*/ + + static final int MATCH_GROUP_POUND_STRING = 1; + static final int MATCH_GROUP_ACTION = 2; + static final int MATCH_GROUP_SERVICE_CODE = 3; + static final int MATCH_GROUP_SIA = 5; + static final int MATCH_GROUP_SIB = 7; + static final int MATCH_GROUP_SIC = 9; + static final int MATCH_GROUP_PWD_CONFIRM = 11; + static final int MATCH_GROUP_DIALING_NUMBER = 12; + + + // Public Class methods + + /** + * Check if provided string contains Mmi code in it and create corresponding + * Mmi if it does + */ + + public static CdmaMmiCode + newFromDialString(String dialString, CDMAPhone phone) { + Matcher m; + CdmaMmiCode ret = null; + + m = sPatternSuppService.matcher(dialString); + + // Is this formatted like a standard supplementary service code? + if (m.matches()) { + ret = new CdmaMmiCode(phone); + ret.poundString = makeEmptyNull(m.group(MATCH_GROUP_POUND_STRING)); + ret.action = makeEmptyNull(m.group(MATCH_GROUP_ACTION)); + ret.sc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE)); + ret.sia = makeEmptyNull(m.group(MATCH_GROUP_SIA)); + ret.sib = makeEmptyNull(m.group(MATCH_GROUP_SIB)); + ret.sic = makeEmptyNull(m.group(MATCH_GROUP_SIC)); + ret.pwd = makeEmptyNull(m.group(MATCH_GROUP_PWD_CONFIRM)); + ret.dialingNumber = makeEmptyNull(m.group(MATCH_GROUP_DIALING_NUMBER)); + + } + + return ret; + } + + // Private Class methods + + /** make empty strings be null. + * Regexp returns empty strings for empty groups + */ + private static String + makeEmptyNull (String s) { + if (s != null && s.length() == 0) return null; + + return s; + } + + // Constructor + + CdmaMmiCode (CDMAPhone phone) { + super(phone.getHandler().getLooper()); + this.phone = phone; + this.context = phone.getContext(); + } + + // MmiCode implementation + + public State + getState() { + return state; + } + + public CharSequence + getMessage() { + return message; + } + + // inherited javadoc suffices + public void + cancel() { + // Complete or failed cannot be cancelled + if (state == State.COMPLETE || state == State.FAILED) { + return; + } + + state = State.CANCELLED; + phone.onMMIDone (this); + } + + public boolean isCancelable() { + return false; + } + + // Instance Methods + + /** + * @return true if the Service Code is PIN/PIN2/PUK/PUK2-related + */ + boolean isPukCommand() { + return sc != null && sc.equals(SC_PUK); + } + + boolean isRegister() { + return action != null && action.equals(ACTION_REGISTER); + } + + public boolean isUssdRequest() { + Log.w(LOG_TAG, "isUssdRequest is not implemented in CdmaMmiCode"); + return false; + } + + /** Process a MMI PUK code */ + void + processCode () { + try { + if (isPukCommand()) { + // sia = old PUK + // sib = new PIN + // sic = new PIN + String oldPinOrPuk = sia; + String newPin = sib; + int pinLen = newPin.length(); + if (isRegister()) { + if (!newPin.equals(sic)) { + // password mismatch; return error + handlePasswordError(com.android.internal.R.string.mismatchPin); + } else if (pinLen < 4 || pinLen > 8 ) { + // invalid length + handlePasswordError(com.android.internal.R.string.invalidPin); + } else { + phone.mCM.supplyIccPuk(oldPinOrPuk, newPin, + obtainMessage(EVENT_SET_COMPLETE, this)); + } + } else { + throw new RuntimeException ("Invalid or Unsupported MMI Code"); + } + } else { + throw new RuntimeException ("Invalid or Unsupported MMI Code"); + } + } catch (RuntimeException exc) { + state = State.FAILED; + message = context.getText(com.android.internal.R.string.mmiError); + phone.onMMIDone(this); + } + } + + private void handlePasswordError(int res) { + state = State.FAILED; + StringBuilder sb = new StringBuilder(getScString()); + sb.append("\n"); + sb.append(context.getText(res)); + message = sb; + phone.onMMIDone(this); + } + + public void + handleMessage (Message msg) { + AsyncResult ar; + + if (msg.what == EVENT_SET_COMPLETE) { + ar = (AsyncResult) (msg.obj); + onSetComplete(ar); + } else { + Log.e(LOG_TAG, "Unexpected reply"); + } + } + // Private instance methods + + private CharSequence getScString() { + if (sc != null) { + if (isPukCommand()) { + return context.getText(com.android.internal.R.string.PinMmi); + } + } + + return ""; + } + + private void + onSetComplete(AsyncResult ar){ + StringBuilder sb = new StringBuilder(getScString()); + sb.append("\n"); + + if (ar.exception != null) { + state = State.FAILED; + if (ar.exception instanceof CommandException) { + CommandException.Error err = ((CommandException)(ar.exception)).getCommandError(); + if (err == CommandException.Error.PASSWORD_INCORRECT) { + if (isPukCommand()) { + sb.append(context.getText( + com.android.internal.R.string.badPuk)); + } else { + sb.append(context.getText( + com.android.internal.R.string.passwordIncorrect)); + } + } else { + sb.append(context.getText( + com.android.internal.R.string.mmiError)); + } + } else { + sb.append(context.getText( + com.android.internal.R.string.mmiError)); + } + } else if (isRegister()) { + state = State.COMPLETE; + sb.append(context.getText( + com.android.internal.R.string.serviceRegistered)); + } else { + state = State.FAILED; + sb.append(context.getText( + com.android.internal.R.string.mmiError)); + } + + message = sb; + phone.onMMIDone(this); + } + +} -- GitLab From 31a17033dcb3551e2964aa6b89041ad9b0317015 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Wed, 14 Apr 2010 10:40:28 -0700 Subject: [PATCH 277/458] fix unintentional drift Change-Id: I0bbf3d3f95296a41d71558d8de1ed2ed021f21cf --- media/libstagefright/AwesomePlayer.cpp | 6 ++-- .../codecs/aacdec/AACDecoder.cpp | 31 ++++++++++++------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index b22025abfd27..b14a03ce9e08 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -444,6 +444,8 @@ void AwesomePlayer::onBufferingUpdate() { notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0); postBufferingEvent_l(); + } else { + LOGE("Not sending buffering status because duration is unknown."); } } @@ -552,8 +554,6 @@ status_t AwesomePlayer::play_l() { seekAudioIfNecessary_l(); } - postBufferingEvent_l(); - if (mFlags & AT_EOS) { // Legacy behaviour, if a stream finishes playing and then // is started again, we play from the start... @@ -1230,6 +1230,8 @@ void AwesomePlayer::onPrepareAsyncEvent() { mFlags |= PREPARED; mAsyncPrepareEvent = NULL; mPreparedCondition.broadcast(); + + postBufferingEvent_l(); } status_t AwesomePlayer::suspend() { diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp index 2ed8ef139ba1..ae23691db9e3 100644 --- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp +++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp @@ -203,25 +203,32 @@ status_t AACDecoder::read( Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf); + size_t numOutBytes = + mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels; + if (decoderErr != MP4AUDEC_SUCCESS) { - LOGE("AAC decoder returned error %d", decoderErr); + LOGW("AAC decoder returned error %d, substituting silence", decoderErr); - buffer->release(); - buffer = NULL; + memset(buffer->data(), 0, numOutBytes); - return ERROR_MALFORMED; + // Discard input buffer. + mInputBuffer->release(); + mInputBuffer = NULL; + + // fall through } - buffer->set_range( - 0, mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels); + buffer->set_range(0, numOutBytes); - mInputBuffer->set_range( - mInputBuffer->range_offset() + mConfig->inputBufferUsedLength, - mInputBuffer->range_length() - mConfig->inputBufferUsedLength); + if (mInputBuffer != NULL) { + mInputBuffer->set_range( + mInputBuffer->range_offset() + mConfig->inputBufferUsedLength, + mInputBuffer->range_length() - mConfig->inputBufferUsedLength); - if (mInputBuffer->range_length() == 0) { - mInputBuffer->release(); - mInputBuffer = NULL; + if (mInputBuffer->range_length() == 0) { + mInputBuffer->release(); + mInputBuffer = NULL; + } } buffer->meta_data()->setInt64( -- GitLab From aa9b5b81718c4e2a94e491cc8e1a78af0fa68d4c Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Wed, 14 Apr 2010 15:03:42 -0400 Subject: [PATCH 278/458] Missing resources for lock screen. The manual integration (kraken change Ide3ad839) of froyo change I6872c3ad skipped these. Change-Id: I11102c4ac988cbcd91eb38b7d60e493079dd715e --- .../res/layout/keyguard_screen_tab_unlock.xml | 24 ++++++++++--------- .../keyguard_screen_tab_unlock_land.xml | 20 +++++++++------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml index c4b28c644cf1..79ca6174cc7d 100644 --- a/core/res/res/layout/keyguard_screen_tab_unlock.xml +++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml @@ -41,20 +41,21 @@ android:ellipsize="marquee" android:gravity="right|bottom" android:textAppearance="?android:attr/textAppearanceMedium" + android:textSize="22sp" /> - -