Merge "Fix issue #6579824: Email crash observed after updating..." into jb-dev
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 291e75e..8543848 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -16,24 +16,19 @@
package android.accounts;
import android.app.Activity;
-import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
-import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
+
import com.android.internal.R;
import java.io.IOException;
@@ -106,10 +101,16 @@
private static final String KEY_INSTANCE_STATE_PENDING_REQUEST = "pendingRequest";
private static final String KEY_INSTANCE_STATE_EXISTING_ACCOUNTS = "existingAccounts";
+ private static final String KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME = "selectedAccountName";
+ private static final String KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT = "selectedAddAccount";
- private ArrayList<AccountInfo> mAccountInfos;
+ private static final int SELECTED_ITEM_NONE = -1;
+
+ private ArrayList<Account> mAccounts;
private int mPendingRequest = REQUEST_NULL;
private Parcelable[] mExistingAccounts = null;
+ private int mSelectedItemIndex;
+ private Button mOkButton;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -119,30 +120,38 @@
+ savedInstanceState + ")");
}
- if (savedInstanceState != null) {
- mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
- mExistingAccounts =
- savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS);
- } else {
- mPendingRequest = REQUEST_NULL;
- mExistingAccounts = null;
- }
-
// save some items we use frequently
final AccountManager accountManager = AccountManager.get(this);
final Intent intent = getIntent();
- // override the description text if supplied
- final String descriptionOverride =
- intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
- if (!TextUtils.isEmpty(descriptionOverride)) {
- ((TextView)findViewById(R.id.description)).setText(descriptionOverride);
+ String selectedAccountName = null;
+ boolean selectedAddNewAccount = false;
+
+ if (savedInstanceState != null) {
+ mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
+ mExistingAccounts =
+ savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS);
+
+ // Makes sure that any user selection is preserved across orientation changes.
+ selectedAccountName = savedInstanceState.getString(
+ KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME);
+
+ selectedAddNewAccount = savedInstanceState.getBoolean(
+ KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
+ } else {
+ mPendingRequest = REQUEST_NULL;
+ mExistingAccounts = null;
+ // If the selected account as specified in the intent matches one in the list we will
+ // show is as pre-selected.
+ Account selectedAccount = (Account) intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
+ if (selectedAccount != null) {
+ selectedAccountName = selectedAccount.name;
+ }
}
- // If the selected account matches one in the list we will place a
- // checkmark next to it.
- final Account selectedAccount =
- (Account)intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "selected account name is " + selectedAccountName);
+ }
// build an efficiently queryable map of account types to authenticator descriptions
final HashMap<String, AuthenticatorDescription> typeToAuthDescription =
@@ -192,7 +201,8 @@
// accounts that don't match the allowable types, if provided, or that don't match the
// allowable accounts, if provided.
final Account[] accounts = accountManager.getAccounts();
- mAccountInfos = new ArrayList<AccountInfo>(accounts.length);
+ mAccounts = new ArrayList<Account>(accounts.length);
+ mSelectedItemIndex = SELECTED_ITEM_NONE;
for (Account account : accounts) {
if (setOfAllowableAccounts != null
&& !setOfAllowableAccounts.contains(account)) {
@@ -202,15 +212,16 @@
&& !setOfRelevantAccountTypes.contains(account.type)) {
continue;
}
- mAccountInfos.add(new AccountInfo(account,
- getDrawableForType(typeToAuthDescription, account.type),
- account.equals(selectedAccount)));
+ if (account.name.equals(selectedAccountName)) {
+ mSelectedItemIndex = mAccounts.size();
+ }
+ mAccounts.add(account);
}
if (mPendingRequest == REQUEST_NULL) {
- // If there are no relevant accounts and only one relevant account typoe go directly to
+ // If there are no relevant accounts and only one relevant account type go directly to
// add account. Otherwise let the user choose.
- if (mAccountInfos.isEmpty()) {
+ if (mAccounts.isEmpty()) {
if (setOfRelevantAccountTypes.size() == 1) {
runAddAccountForAuthenticator(setOfRelevantAccountTypes.iterator().next());
} else {
@@ -221,36 +232,71 @@
// if there is only one allowable account return it
if (!intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false)
- && mAccountInfos.size() == 1) {
- Account account = mAccountInfos.get(0).account;
+ && mAccounts.size() == 1) {
+ Account account = mAccounts.get(0);
setResultAndFinish(account.name, account.type);
return;
}
}
+ // Cannot set content view until we know that mPendingRequest is not null, otherwise
+ // would cause screen flicker.
setContentView(R.layout.choose_type_and_account);
- // there is more than one allowable account. initialize the list adapter to allow
- // the user to select an account.
+ // Override the description text if supplied
+ final String descriptionOverride =
+ intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
+ TextView descriptionView = (TextView) findViewById(R.id.description);
+ if (!TextUtils.isEmpty(descriptionOverride)) {
+ descriptionView.setText(descriptionOverride);
+ } else {
+ descriptionView.setVisibility(View.GONE);
+ }
+
+ // List of options includes all accounts found together with "Add new account" as the
+ // last item in the list.
+ String[] listItems = new String[mAccounts.size() + 1];
+ for (int i = 0; i < mAccounts.size(); i++) {
+ listItems[i] = mAccounts.get(i).name;
+ }
+ listItems[mAccounts.size()] = getResources().getString(
+ R.string.add_account_button_label);
+
ListView list = (ListView) findViewById(android.R.id.list);
- list.setAdapter(new AccountArrayAdapter(this,
- android.R.layout.simple_list_item_1, mAccountInfos));
+ list.setAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_single_choice, listItems));
list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ list.setItemsCanFocus(false);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
- onListItemClick((ListView)parent, v, position, id);
+ mSelectedItemIndex = position;
+ mOkButton.setEnabled(true);
}
});
- // set the listener for the addAccount button
- Button addAccountButton = (Button) findViewById(R.id.addAccount);
- addAccountButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(final View v) {
- startChooseAccountTypeActivity();
+ // If "Add account" option was previously selected by user, preserve it across
+ // orientation changes.
+ if (selectedAddNewAccount) {
+ mSelectedItemIndex = mAccounts.size();
+ }
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "mSelectedItemIndex is " + mSelectedItemIndex);
+ }
+
+ ViewGroup buttonBar = (ViewGroup) findViewById(R.id.button_bar);
+ if (buttonBar != null) {
+ mOkButton = (Button) buttonBar.findViewById(android.R.id.button2);
+ if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
+ // If caller specified a selectedAccount, then display that as selected and enable
+ // the "OK" button by default.
+ list.setSelection(mSelectedItemIndex);
+ mOkButton.setEnabled(true);
+ } else {
+ // Otherwise "OK" button is disabled since nothing is pre-selected.
+ mOkButton.setEnabled(false);
}
- });
+ }
}
@Override
@@ -268,6 +314,28 @@
if (mPendingRequest == REQUEST_ADD_ACCOUNT) {
outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts);
}
+ if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
+ if (mSelectedItemIndex == mAccounts.size()) {
+ outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, true);
+ } else {
+ outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
+ outState.putString(KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME,
+ mAccounts.get(mSelectedItemIndex).name);
+ }
+ }
+ }
+
+ public void onCancelButtonClicked(View view) {
+ onBackPressed();
+ }
+
+ public void onOkButtonClicked(View view) {
+ if (mSelectedItemIndex == mAccounts.size()) {
+ // Selected "Add New Account" option
+ startChooseAccountTypeActivity();
+ } else if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
+ onAccountSelected(mAccounts.get(mSelectedItemIndex));
+ }
}
// Called when the choose account type activity (for adding an account) returns.
@@ -287,9 +355,9 @@
mPendingRequest = REQUEST_NULL;
if (resultCode == RESULT_CANCELED) {
- // if cancelling out of addAccount and the original state caused us to skip this,
+ // if canceling out of addAccount and the original state caused us to skip this,
// finish this activity
- if (mAccountInfos.isEmpty()) {
+ if (mAccounts.isEmpty()) {
setResult(Activity.RESULT_CANCELED);
finish();
}
@@ -360,6 +428,7 @@
options, null /* activity */, this /* callback */, null /* Handler */);
}
+ @Override
public void run(final AccountManagerFuture<Bundle> accountManagerFuture) {
try {
final Bundle accountManagerResult = accountManagerFuture.getResult();
@@ -385,34 +454,9 @@
finish();
}
- private Drawable getDrawableForType(
- final HashMap<String, AuthenticatorDescription> typeToAuthDescription,
- String accountType) {
- Drawable icon = null;
- if (typeToAuthDescription.containsKey(accountType)) {
- try {
- AuthenticatorDescription desc = typeToAuthDescription.get(accountType);
- Context authContext = createPackageContext(desc.packageName, 0);
- icon = authContext.getResources().getDrawable(desc.iconId);
- } catch (PackageManager.NameNotFoundException e) {
- // Nothing we can do much here, just log
- if (Log.isLoggable(TAG, Log.WARN)) {
- Log.w(TAG, "No icon name for account type " + accountType);
- }
- } catch (Resources.NotFoundException e) {
- // Nothing we can do much here, just log
- if (Log.isLoggable(TAG, Log.WARN)) {
- Log.w(TAG, "No icon resource for account type " + accountType);
- }
- }
- }
- return icon;
- }
-
- protected void onListItemClick(ListView l, View v, int position, long id) {
- AccountInfo accountInfo = mAccountInfos.get(position);
- Log.d(TAG, "selected account " + accountInfo.account);
- setResultAndFinish(accountInfo.account.name, accountInfo.account.type);
+ private void onAccountSelected(Account account) {
+ Log.d(TAG, "selected account " + account);
+ setResultAndFinish(account.name, account.type);
}
private void setResultAndFinish(final String accountName, final String accountType) {
@@ -444,58 +488,4 @@
startActivityForResult(intent, REQUEST_CHOOSE_TYPE);
mPendingRequest = REQUEST_CHOOSE_TYPE;
}
-
- private static class AccountInfo {
- final Account account;
- final Drawable drawable;
- private final boolean checked;
-
- AccountInfo(Account account, Drawable drawable, boolean checked) {
- this.account = account;
- this.drawable = drawable;
- this.checked = checked;
- }
- }
-
- private static class ViewHolder {
- ImageView icon;
- TextView text;
- ImageView checkmark;
- }
-
- private static class AccountArrayAdapter extends ArrayAdapter<AccountInfo> {
- private LayoutInflater mLayoutInflater;
- private ArrayList<AccountInfo> mInfos;
-
- public AccountArrayAdapter(Context context, int textViewResourceId,
- ArrayList<AccountInfo> infos) {
- super(context, textViewResourceId, infos);
- mInfos = infos;
- mLayoutInflater = (LayoutInflater) context.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- ViewHolder holder;
-
- if (convertView == null) {
- convertView = mLayoutInflater.inflate(R.layout.choose_selected_account_row, null);
- holder = new ViewHolder();
- holder.text = (TextView) convertView.findViewById(R.id.account_row_text);
- holder.icon = (ImageView) convertView.findViewById(R.id.account_row_icon);
- holder.checkmark = (ImageView) convertView.findViewById(R.id.account_row_checkmark);
- convertView.setTag(holder);
- } else {
- holder = (ViewHolder) convertView.getTag();
- }
-
- holder.text.setText(mInfos.get(position).account.name);
- holder.icon.setImageDrawable(mInfos.get(position).drawable);
- final int displayCheckmark =
- mInfos.get(position).checked ? View.VISIBLE : View.INVISIBLE;
- holder.checkmark.setVisibility(displayCheckmark);
- return convertView;
- }
- }
}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 89068e7..035a7c6 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1059,6 +1059,7 @@
}
native_takePicture(msgType);
+ mFaceDetectionRunning = false;
}
/**
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 33dea6c..46153e7 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1892,6 +1892,13 @@
* {@link KeyEvent#FLAG_KEEP_TOUCH_MODE KeyEvent.FLAG_KEEP_TOUCH_MODE}, so
* that they don't impact the current touch mode of the UI.
*
+ * <p>Note that it's discouraged to send such key events in normal operation;
+ * this is mainly for use with {@link android.text.InputType#TYPE_NULL} type
+ * text fields, or for non-rich input methods. A reasonably capable software
+ * input method should use the
+ * {@link android.view.inputmethod.InputConnection#commitText} family of methods
+ * to send text to an application, rather than sending key events.</p>
+ *
* @param keyEventCode The raw key code to send, as defined by
* {@link KeyEvent}.
*/
@@ -1949,7 +1956,11 @@
* {@link InputConnection#commitText InputConnection.commitText()} with
* the character; some, however, may be handled different. In particular,
* the enter character ('\n') will either be delivered as an action code
- * or a raw key event, as appropriate.
+ * or a raw key event, as appropriate. Consider this as a convenience
+ * method for IMEs that do not have a full implementation of actions; a
+ * fully complying IME will decide of the right action for each event and
+ * will likely never call this method except maybe to handle events coming
+ * from an actual hardware keyboard.
*
* @param charCode The UTF-16 character code to send.
*/
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 7e29dc7..4fede32 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -28,6 +28,10 @@
* Provides a basic foundation for entering and editing text.
* Subclasses should override {@link #onKeyDown} and {@link #onKeyUp} to insert
* characters as keys are pressed.
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public abstract class BaseKeyListener extends MetaKeyKeyListener
implements KeyListener {
diff --git a/core/java/android/text/method/DateKeyListener.java b/core/java/android/text/method/DateKeyListener.java
index 7c11434..e6f63d1 100644
--- a/core/java/android/text/method/DateKeyListener.java
+++ b/core/java/android/text/method/DateKeyListener.java
@@ -21,6 +21,10 @@
/**
* For entering dates in a text field.
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class DateKeyListener extends NumberKeyListener
{
diff --git a/core/java/android/text/method/DateTimeKeyListener.java b/core/java/android/text/method/DateTimeKeyListener.java
index f8ebc40..523e986 100644
--- a/core/java/android/text/method/DateTimeKeyListener.java
+++ b/core/java/android/text/method/DateTimeKeyListener.java
@@ -21,6 +21,10 @@
/**
* For entering dates and times in the same text field.
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class DateTimeKeyListener extends NumberKeyListener
{
diff --git a/core/java/android/text/method/DialerKeyListener.java b/core/java/android/text/method/DialerKeyListener.java
index 07127b7..ce51fae 100644
--- a/core/java/android/text/method/DialerKeyListener.java
+++ b/core/java/android/text/method/DialerKeyListener.java
@@ -23,6 +23,10 @@
/**
* For dialing-only text entry
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class DialerKeyListener extends NumberKeyListener
{
diff --git a/core/java/android/text/method/DigitsKeyListener.java b/core/java/android/text/method/DigitsKeyListener.java
index f0f072c..3d9daed 100644
--- a/core/java/android/text/method/DigitsKeyListener.java
+++ b/core/java/android/text/method/DigitsKeyListener.java
@@ -24,6 +24,10 @@
/**
* For digits-only text entry
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class DigitsKeyListener extends NumberKeyListener
{
diff --git a/core/java/android/text/method/KeyListener.java b/core/java/android/text/method/KeyListener.java
index 318149a..bb79ecd 100644
--- a/core/java/android/text/method/KeyListener.java
+++ b/core/java/android/text/method/KeyListener.java
@@ -27,6 +27,12 @@
* {@link android.view.inputmethod.InputMethod}; it should only be used
* for cases where an application has its own on-screen keypad and also wants
* to process hard keyboard events to match it.
+ * <p></p>
+ * Key presses on soft input methods are not required to trigger the methods
+ * in this listener, and are in fact discouraged to do so. The default
+ * android keyboard will not trigger these for any key to any application
+ * targetting Jelly Bean or later, and will only deliver it for some
+ * key presses to applications targetting Ice Cream Sandwich or earlier.
*/
public interface KeyListener {
/**
diff --git a/core/java/android/text/method/MultiTapKeyListener.java b/core/java/android/text/method/MultiTapKeyListener.java
index 2a739fa..95ac0a1 100644
--- a/core/java/android/text/method/MultiTapKeyListener.java
+++ b/core/java/android/text/method/MultiTapKeyListener.java
@@ -28,6 +28,10 @@
* This is the standard key listener for alphabetic input on 12-key
* keyboards. You should generally not need to instantiate this yourself;
* TextKeyListener will do it for you.
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class MultiTapKeyListener extends BaseKeyListener
implements SpanWatcher {
diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java
index 1e72309..5d4c732 100644
--- a/core/java/android/text/method/NumberKeyListener.java
+++ b/core/java/android/text/method/NumberKeyListener.java
@@ -27,6 +27,10 @@
/**
* For numeric text entry
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public abstract class NumberKeyListener extends BaseKeyListener
implements InputFilter
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 4c82b81..c5261f3 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -27,6 +27,10 @@
* This is the standard key listener for alphabetic input on qwerty
* keyboards. You should generally not need to instantiate this yourself;
* TextKeyListener will do it for you.
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class QwertyKeyListener extends BaseKeyListener {
private static QwertyKeyListener[] sInstance =
diff --git a/core/java/android/text/method/TextKeyListener.java b/core/java/android/text/method/TextKeyListener.java
index 8312fe1..994f3d7 100644
--- a/core/java/android/text/method/TextKeyListener.java
+++ b/core/java/android/text/method/TextKeyListener.java
@@ -33,6 +33,10 @@
/**
* This is the key listener for typing normal text. It delegates to
* other key listeners appropriate to the current keyboard and language.
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class TextKeyListener extends BaseKeyListener implements SpanWatcher {
private static TextKeyListener[] sInstance =
diff --git a/core/java/android/text/method/TimeKeyListener.java b/core/java/android/text/method/TimeKeyListener.java
index 3fbfd8c..c5bfd5c 100644
--- a/core/java/android/text/method/TimeKeyListener.java
+++ b/core/java/android/text/method/TimeKeyListener.java
@@ -21,6 +21,10 @@
/**
* For entering times in a text field.
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class TimeKeyListener extends NumberKeyListener
{
diff --git a/core/java/android/view/AccessibilityIterators.java b/core/java/android/view/AccessibilityIterators.java
index cd54f24..2a7dc18 100644
--- a/core/java/android/view/AccessibilityIterators.java
+++ b/core/java/android/view/AccessibilityIterators.java
@@ -47,7 +47,6 @@
* @hide
*/
public static abstract class AbstractTextSegmentIterator implements TextSegmentIterator {
- protected static final int DONE = -1;
protected String mText;
@@ -104,20 +103,20 @@
if (offset >= textLegth) {
return null;
}
- int start = -1;
- if (offset < 0) {
- offset = 0;
- if (mImpl.isBoundary(offset)) {
- start = offset;
+ int start = offset;
+ if (start < 0) {
+ start = 0;
+ }
+ while (!mImpl.isBoundary(start)) {
+ start = mImpl.following(start);
+ if (start == BreakIterator.DONE) {
+ return null;
}
}
- if (start < 0) {
- start = mImpl.following(offset);
- }
- if (start < 0) {
+ final int end = mImpl.following(start);
+ if (end == BreakIterator.DONE) {
return null;
}
- final int end = mImpl.following(start);
return getRange(start, end);
}
@@ -130,20 +129,20 @@
if (offset <= 0) {
return null;
}
- int end = -1;
- if (offset > mText.length()) {
- offset = mText.length();
- if (mImpl.isBoundary(offset)) {
- end = offset;
+ int end = offset;
+ if (end > textLegth) {
+ end = textLegth;
+ }
+ while (!mImpl.isBoundary(end)) {
+ end = mImpl.preceding(end);
+ if (end == BreakIterator.DONE) {
+ return null;
}
}
- if (end < 0) {
- end = mImpl.preceding(offset);
- }
- if (end < 0) {
+ final int start = mImpl.preceding(end);
+ if (start == BreakIterator.DONE) {
return null;
}
- final int start = mImpl.preceding(end);
return getRange(start, end);
}
@@ -195,25 +194,20 @@
if (offset >= mText.length()) {
return null;
}
- int start = -1;
- if (offset < 0) {
- offset = 0;
- if (mImpl.isBoundary(offset) && isLetterOrDigit(offset)) {
- start = offset;
- }
- }
+ int start = offset;
if (start < 0) {
- while ((offset = mImpl.following(offset)) != DONE) {
- if (isLetterOrDigit(offset)) {
- start = offset;
- break;
- }
- }
+ start = 0;
}
- if (start < 0) {
- return null;
+ while (!isLetterOrDigit(start) && !isStartBoundary(start)) {
+ start = mImpl.following(start);
+ if (start == BreakIterator.DONE) {
+ return null;
+ }
}
final int end = mImpl.following(start);
+ if (end == BreakIterator.DONE || !isEndBoundary(end)) {
+ return null;
+ }
return getRange(start, end);
}
@@ -226,28 +220,33 @@
if (offset <= 0) {
return null;
}
- int end = -1;
- if (offset > mText.length()) {
- offset = mText.length();
- if (mImpl.isBoundary(offset) && offset > 0 && isLetterOrDigit(offset - 1)) {
- end = offset;
- }
+ int end = offset;
+ if (end > textLegth) {
+ end = textLegth;
}
- if (end < 0) {
- while ((offset = mImpl.preceding(offset)) != DONE) {
- if (offset > 0 && isLetterOrDigit(offset - 1)) {
- end = offset;
- break;
- }
+ while (end > 0 && !isLetterOrDigit(end - 1) && !isEndBoundary(end)) {
+ end = mImpl.preceding(end);
+ if (end == BreakIterator.DONE) {
+ return null;
}
}
- if (end < 0) {
- return null;
- }
final int start = mImpl.preceding(end);
+ if (start == BreakIterator.DONE || !isStartBoundary(start)) {
+ return null;
+ }
return getRange(start, end);
}
+ private boolean isStartBoundary(int index) {
+ return isLetterOrDigit(index)
+ && (index == 0 || !isLetterOrDigit(index - 1));
+ }
+
+ private boolean isEndBoundary(int index) {
+ return (index > 0 && isLetterOrDigit(index - 1))
+ && (index == mText.length() || !isLetterOrDigit(index));
+ }
+
private boolean isLetterOrDigit(int index) {
if (index >= 0 && index < mText.length()) {
final int codePoint = mText.codePointAt(index);
@@ -276,31 +275,19 @@
if (offset >= textLength) {
return null;
}
- int start = -1;
- if (offset < 0) {
- start = 0;
- } else {
- for (int i = offset + 1; i < textLength; i++) {
- if (mText.charAt(i) == '\n') {
- start = i;
- break;
- }
- }
- }
+ int start = offset;
if (start < 0) {
- return null;
+ start = 0;
}
- while (start < textLength && mText.charAt(start) == '\n') {
+ while (start < textLength && mText.charAt(start) == '\n'
+ && !isStartBoundary(start)) {
start++;
}
- int end = start;
- for (int i = end + 1; i < textLength; i++) {
- end = i;
- if (mText.charAt(i) == '\n') {
- break;
- }
+ if (start >= textLength) {
+ return null;
}
- while (end < textLength && mText.charAt(end) == '\n') {
+ int end = start + 1;
+ while (end < textLength && !isEndBoundary(end)) {
end++;
}
return getRange(start, end);
@@ -315,38 +302,31 @@
if (offset <= 0) {
return null;
}
- int end = -1;
- if (offset > mText.length()) {
- end = mText.length();
- } else {
- if (offset > 0 && mText.charAt(offset - 1) == '\n') {
- offset--;
- }
- for (int i = offset - 1; i >= 0; i--) {
- if (i > 0 && mText.charAt(i - 1) == '\n') {
- end = i;
- break;
- }
- }
+ int end = offset;
+ if (end > textLength) {
+ end = textLength;
+ }
+ while(end > 0 && mText.charAt(end - 1) == '\n' && !isEndBoundary(end)) {
+ end--;
}
if (end <= 0) {
return null;
}
- int start = end;
- while (start > 0 && mText.charAt(start - 1) == '\n') {
+ int start = end - 1;
+ while (start > 0 && !isStartBoundary(start)) {
start--;
}
- if (start == 0 && mText.charAt(start) == '\n') {
- return null;
- }
- for (int i = start - 1; i >= 0; i--) {
- start = i;
- if (start > 0 && mText.charAt(i - 1) == '\n') {
- break;
- }
- }
- start = Math.max(0, start);
return getRange(start, end);
}
+
+ private boolean isStartBoundary(int index) {
+ return (mText.charAt(index) != '\n'
+ && (index == 0 || mText.charAt(index - 1) == '\n'));
+ }
+
+ private boolean isEndBoundary(int index) {
+ return (index > 0 && mText.charAt(index - 1) != '\n'
+ && (index == mText.length() || mText.charAt(index) == '\n'));
+ }
}
}
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index ace7aa8..1080229 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -52,6 +52,19 @@
* to characters. Be aware that there may be multiple key input devices active
* at the same time and each will have its own key character map.
* </p><p>
+ * As soft input methods can use multiple and inventive ways of inputting text,
+ * there is no guarantee that any key press on a soft keyboard will generate a key
+ * event: this is left to the IME's discretion, and in fact sending such events is
+ * discouraged. You should never rely on receiving KeyEvents for any key on a soft
+ * input method. In particular, the default software keyboard will never send any
+ * key event to any application targetting Jelly Bean or later, and will only send
+ * events for some presses of the delete and return keys to applications targetting
+ * Ice Cream Sandwich or earlier. Be aware that other software input methods may
+ * never send key events regardless of the version. Consider using editor actions
+ * like {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE} if you need
+ * specific interaction with the software keyboard, as it gives more visibility to
+ * the user as to how your application will react to key presses.
+ * </p><p>
* When interacting with an IME, the framework may deliver key events
* with the special action {@link #ACTION_MULTIPLE} that either specifies
* that single repeated key code or a sequence of characters to insert.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6421068..9613149 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -204,12 +204,12 @@
* <tr>
* <td rowspan="4">Event processing</td>
* <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td>
- * <td>Called when a new key event occurs.
+ * <td>Called when a new hardware key event occurs.
* </td>
* </tr>
* <tr>
* <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td>
- * <td>Called when a key up event occurs.
+ * <td>Called when a hardware key up event occurs.
* </td>
* </tr>
* <tr>
@@ -1596,7 +1596,7 @@
/**
* @hide
*/
- private int mAccessibilityCursorPosition = -1;
+ private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED;
/**
* The view's tag.
@@ -2535,6 +2535,11 @@
public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004;
/**
+ * The undefined cursor position.
+ */
+ private static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1;
+
+ /**
* Indicates that the screen has changed state and is now off.
*
* @see #onScreenStateChanged(int)
@@ -4150,7 +4155,9 @@
}
/**
- * Register a callback to be invoked when a key is pressed in this view.
+ * Register a callback to be invoked when a hardware key is pressed in this view.
+ * Key presses in software input methods will generally not trigger the methods of
+ * this listener.
* @param l the key listener to attach to this view
*/
public void setOnKeyListener(OnKeyListener l) {
@@ -6273,7 +6280,7 @@
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
notifyAccessibilityStateChanged();
// Clear the text navigation state.
- setAccessibilityCursorPosition(-1);
+ setAccessibilityCursorPosition(ACCESSIBILITY_CURSOR_POSITION_UNDEFINED);
}
// Clear the global reference of accessibility focus if this
// view or any of its descendants had accessibility focus.
@@ -6323,6 +6330,7 @@
void clearAccessibilityFocusNoCallbacks() {
if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) {
mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED;
+ setAccessibilityCursorPosition(ACCESSIBILITY_CURSOR_POSITION_UNDEFINED);
invalidate();
}
}
@@ -6819,12 +6827,11 @@
final int current = getAccessibilityCursorPosition();
final int[] range = iterator.following(current);
if (range == null) {
- setAccessibilityCursorPosition(-1);
return false;
}
final int start = range[0];
final int end = range[1];
- setAccessibilityCursorPosition(start);
+ setAccessibilityCursorPosition(end);
sendViewTextTraversedAtGranularityEvent(
AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
granularity, start, end);
@@ -6840,16 +6847,26 @@
if (iterator == null) {
return false;
}
- final int selectionStart = getAccessibilityCursorPosition();
- final int current = selectionStart >= 0 ? selectionStart : text.length() + 1;
+ int current = getAccessibilityCursorPosition();
+ if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) {
+ current = text.length();
+ } else if (granularity == AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER) {
+ // When traversing by character we always put the cursor after the character
+ // to ease edit and have to compensate before asking the for previous segment.
+ current--;
+ }
final int[] range = iterator.preceding(current);
if (range == null) {
- setAccessibilityCursorPosition(-1);
return false;
}
final int start = range[0];
final int end = range[1];
- setAccessibilityCursorPosition(end);
+ // Always put the cursor after the character to ease edit.
+ if (granularity == AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER) {
+ setAccessibilityCursorPosition(end);
+ } else {
+ setAccessibilityCursorPosition(start);
+ }
sendViewTextTraversedAtGranularityEvent(
AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
granularity, start, end);
@@ -7527,6 +7544,10 @@
* when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER}
* is released, if the view is enabled and clickable.
*
+ * <p>Key presses in software keyboards will generally NOT trigger this listener,
+ * although some may elect to do so in some situations. Do not rely on this to
+ * catch software key presses.
+ *
* @param keyCode A key code that represents the button pressed, from
* {@link android.view.KeyEvent}.
* @param event The KeyEvent object that defines the button action.
@@ -7558,6 +7579,9 @@
* Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
* KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
* the event).
+ * <p>Key presses in software keyboards will generally NOT trigger this listener,
+ * although some may elect to do so in some situations. Do not rely on this to
+ * catch software key presses.
*/
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
return false;
@@ -7568,6 +7592,9 @@
* KeyEvent.Callback.onKeyUp()}: perform clicking of the view
* when {@link KeyEvent#KEYCODE_DPAD_CENTER} or
* {@link KeyEvent#KEYCODE_ENTER} is released.
+ * <p>Key presses in software keyboards will generally NOT trigger this listener,
+ * although some may elect to do so in some situations. Do not rely on this to
+ * catch software key presses.
*
* @param keyCode A key code that represents the button pressed, from
* {@link android.view.KeyEvent}.
@@ -7602,6 +7629,9 @@
* Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent)
* KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle
* the event).
+ * <p>Key presses in software keyboards will generally NOT trigger this listener,
+ * although some may elect to do so in some situations. Do not rely on this to
+ * catch software key presses.
*
* @param keyCode A key code that represents the button pressed, from
* {@link android.view.KeyEvent}.
@@ -8161,6 +8191,7 @@
private void removeSendViewScrolledAccessibilityEventCallback() {
if (mSendViewScrolledAccessibilityEvent != null) {
removeCallbacks(mSendViewScrolledAccessibilityEvent);
+ mSendViewScrolledAccessibilityEvent.mIsPending = false;
}
}
@@ -16898,14 +16929,20 @@
}
/**
- * Interface definition for a callback to be invoked when a key event is
- * dispatched to this view. The callback will be invoked before the key
- * event is given to the view.
+ * Interface definition for a callback to be invoked when a hardware key event is
+ * dispatched to this view. The callback will be invoked before the key event is
+ * given to the view. This is only useful for hardware keyboards; a software input
+ * method has no obligation to trigger this listener.
*/
public interface OnKeyListener {
/**
- * Called when a key is dispatched to a view. This allows listeners to
+ * Called when a hardware key is dispatched to a view. This allows listeners to
* get a chance to respond before the target view.
+ * <p>Key presses in software keyboards will generally NOT trigger this method,
+ * although some may elect to do so in some situations. Do not assume a
+ * software input method has to be key-based; even if it is, it may use key presses
+ * in a different way than you expect, so there is no way to reliably catch soft
+ * input key presses.
*
* @param v The view the key has been dispatched to.
* @param keyCode The code for the physical key that was pressed
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 3563d4d..76c6d19 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -283,7 +283,7 @@
/**
* Tell the editor that you are done with a batch edit previously
- * initiated with {@link #endBatchEdit}.
+ * initiated with {@link #beginBatchEdit}.
*/
public boolean endBatchEdit();
@@ -307,7 +307,11 @@
* {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD} on all
* key event objects you give to this API; the flag will not be set
* for you.
- *
+ *
+ * <p>Note that it's discouraged to send such key events in normal operation;
+ * this is mainly for use with {@link android.text.InputType#TYPE_NULL} type
+ * text fields. Use the {@link #commitText} family of methods to send text
+ * to the application instead.
* @param event The key event.
*
* @return Returns true on success, false if the input connection is no longer
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index fc59e6e..161e8fb 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -217,7 +217,7 @@
public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
boolean allowImplicitlySelectedSubtype) {
try {
- // Passing null as a locale for ICS
+ // Passing null as a locale until we support multiple enabled spell checker subtypes.
return sService.getCurrentSpellCheckerSubtype(null, allowImplicitlySelectedSubtype);
} catch (RemoteException e) {
Log.e(TAG, "Error in getCurrentSpellCheckerSubtype: " + e);
diff --git a/core/java/android/webkit/AutoCompletePopup.java b/core/java/android/webkit/AutoCompletePopup.java
index 87e878b..c624ce4 100644
--- a/core/java/android/webkit/AutoCompletePopup.java
+++ b/core/java/android/webkit/AutoCompletePopup.java
@@ -181,8 +181,11 @@
// There is no autofill profile setup yet and the user has
// elected to try and set one up. Call through to the
// embedder to action that.
- mWebView.getWebChromeClient().setupAutoFill(
+ WebChromeClient webChromeClient = mWebView.getWebChromeClient();
+ if (webChromeClient != null) {
+ webChromeClient.setupAutoFill(
mHandler.obtainMessage(AUTOFILL_FORM));
+ }
}
} else {
Object selectedItem;
diff --git a/core/java/android/webkit/WebViewInputDispatcher.java b/core/java/android/webkit/WebViewInputDispatcher.java
index d8065e9..f64547f 100644
--- a/core/java/android/webkit/WebViewInputDispatcher.java
+++ b/core/java/android/webkit/WebViewInputDispatcher.java
@@ -661,6 +661,7 @@
// Web kit has decided to consume the event!
if (d.mEventType == EVENT_TYPE_TOUCH) {
enqueueUiCancelTouchEventIfNeededLocked();
+ unscheduleLongPressLocked();
}
} else {
// Web kit is being friendly. Pass the event to the UI.
diff --git a/core/java/android/widget/AccessibilityIterators.java b/core/java/android/widget/AccessibilityIterators.java
index e800e8d..a3d58a4 100644
--- a/core/java/android/widget/AccessibilityIterators.java
+++ b/core/java/android/widget/AccessibilityIterators.java
@@ -56,16 +56,18 @@
if (offset >= mText.length()) {
return null;
}
- int nextLine = -1;
+ int nextLine;
if (offset < 0) {
nextLine = mLayout.getLineForOffset(0);
} else {
final int currentLine = mLayout.getLineForOffset(offset);
- if (currentLine < mLayout.getLineCount() - 1) {
+ if (getLineEdgeIndex(currentLine, DIRECTION_START) == offset) {
+ nextLine = currentLine;
+ } else {
nextLine = currentLine + 1;
}
}
- if (nextLine < 0) {
+ if (nextLine >= mLayout.getLineCount()) {
return null;
}
final int start = getLineEdgeIndex(nextLine, DIRECTION_START);
@@ -82,12 +84,14 @@
if (offset <= 0) {
return null;
}
- int previousLine = -1;
+ int previousLine;
if (offset > mText.length()) {
previousLine = mLayout.getLineForOffset(mText.length());
} else {
- final int currentLine = mLayout.getLineForOffset(offset - 1);
- if (currentLine > 0) {
+ final int currentLine = mLayout.getLineForOffset(offset);
+ if (getLineEdgeIndex(currentLine, DIRECTION_END) + 1 == offset) {
+ previousLine = currentLine;
+ } else {
previousLine = currentLine - 1;
}
}
@@ -141,29 +145,18 @@
return null;
}
- final int currentLine = mLayout.getLineForOffset(offset);
+ final int start = Math.max(0, offset);
+
+ final int currentLine = mLayout.getLineForOffset(start);
final int currentLineTop = mLayout.getLineTop(currentLine);
final int pageHeight = mTempRect.height() - mView.getTotalPaddingTop()
- mView.getTotalPaddingBottom();
+ final int nextPageStartY = currentLineTop + pageHeight;
+ final int lastLineTop = mLayout.getLineTop(mLayout.getLineCount() - 1);
+ final int currentPageEndLine = (nextPageStartY < lastLineTop)
+ ? mLayout.getLineForVertical(nextPageStartY) - 1 : mLayout.getLineCount() - 1;
- final int nextPageStartLine;
- final int nextPageEndLine;
- if (offset < 0) {
- nextPageStartLine = currentLine;
- final int nextPageEndY = currentLineTop + pageHeight;
- nextPageEndLine = mLayout.getLineForVertical(nextPageEndY);
- } else {
- final int nextPageStartY = currentLineTop + pageHeight;
- nextPageStartLine = mLayout.getLineForVertical(nextPageStartY) + 1;
- if (mLayout.getLineTop(nextPageStartLine) <= nextPageStartY) {
- return null;
- }
- final int nextPageEndY = nextPageStartY + pageHeight;
- nextPageEndLine = mLayout.getLineForVertical(nextPageEndY);
- }
-
- final int start = getLineEdgeIndex(nextPageStartLine, DIRECTION_START);
- final int end = getLineEdgeIndex(nextPageEndLine, DIRECTION_END) + 1;
+ final int end = getLineEdgeIndex(currentPageEndLine, DIRECTION_END) + 1;
return getRange(start, end);
}
@@ -181,37 +174,17 @@
return null;
}
- final int currentLine = mLayout.getLineForOffset(offset);
+ final int end = Math.min(mText.length(), offset);
+
+ final int currentLine = mLayout.getLineForOffset(end);
final int currentLineTop = mLayout.getLineTop(currentLine);
final int pageHeight = mTempRect.height() - mView.getTotalPaddingTop()
- mView.getTotalPaddingBottom();
+ final int previousPageEndY = currentLineTop - pageHeight;
+ final int currentPageStartLine = (previousPageEndY > 0) ?
+ mLayout.getLineForVertical(previousPageEndY) + 1 : 0;
- final int previousPageStartLine;
- final int previousPageEndLine;
- if (offset > mText.length()) {
- final int prevousPageStartY = mLayout.getHeight() - pageHeight;
- if (prevousPageStartY < 0) {
- return null;
- }
- previousPageStartLine = mLayout.getLineForVertical(prevousPageStartY);
- previousPageEndLine = mLayout.getLineCount() - 1;
- } else {
- final int prevousPageStartY;
- if (offset == mText.length()) {
- prevousPageStartY = mLayout.getHeight() - 2 * pageHeight;
- } else {
- prevousPageStartY = currentLineTop - 2 * pageHeight;
- }
- if (prevousPageStartY < 0) {
- return null;
- }
- previousPageStartLine = mLayout.getLineForVertical(prevousPageStartY);
- final int previousPageEndY = prevousPageStartY + pageHeight;
- previousPageEndLine = mLayout.getLineForVertical(previousPageEndY) - 1;
- }
-
- final int start = getLineEdgeIndex(previousPageStartLine, DIRECTION_START);
- final int end = getLineEdgeIndex(previousPageEndLine, DIRECTION_END) + 1;
+ final int start = getLineEdgeIndex(currentPageStartLine, DIRECTION_START);
return getRange(start, end);
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index bd19f00..3e2d43a 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8376,10 +8376,12 @@
@Override
public int getAccessibilityCursorPosition() {
if (TextUtils.isEmpty(getContentDescription())) {
- return getSelectionEnd();
- } else {
- return super.getAccessibilityCursorPosition();
+ final int selectionEnd = getSelectionEnd();
+ if (selectionEnd >= 0) {
+ return selectionEnd;
+ }
}
+ return super.getAccessibilityCursorPosition();
}
/**
@@ -8391,7 +8393,7 @@
return;
}
if (TextUtils.isEmpty(getContentDescription())) {
- if (index >= 0) {
+ if (index >= 0 && index <= mText.length()) {
Selection.setSelection((Spannable) mText, index);
} else {
Selection.removeSelection((Spannable) mText);
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index f9ef3c5..a22395b 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -519,6 +519,10 @@
// Inform listener of any active targets. Typically only one will be active.
deactivateHandle(RETURN_TO_HOME_DURATION, RETURN_TO_HOME_DELAY, 0.0f, mResetListener);
dispatchTriggerEvent(activeTarget);
+ if (!mAlwaysTrackFinger) {
+ // Force ring and targets to finish animation to final expanded state
+ mTargetAnimations.stop();
+ }
} else {
// Animate handle back to the center based on current state.
deactivateHandle(HIDE_ANIMATION_DURATION, HIDE_ANIMATION_DELAY, 1.0f,
@@ -542,7 +546,6 @@
mTargetDrawables.get(i).setAlpha(0.0f);
}
}
- mOuterRing.setAlpha(0.0f);
}
private void hideTargets(boolean animate, boolean expanded) {
@@ -809,7 +812,6 @@
switchToState(STATE_START, eventX, eventY);
if (!trySwitchToFirstTouchState(eventX, eventY)) {
mDragging = false;
- mTargetAnimations.cancel();
ping();
}
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e3082ea..155e59c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1983,7 +1983,7 @@
<activity android:name="android.accounts.ChooseTypeAndAccountActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@android:style/Theme.Holo.DialogWhenLarge.NoActionBar"
+ android:theme="@android:style/Theme.Holo.Dialog"
android:label="@string/choose_account_label"
android:process=":ui">
</activity>
diff --git a/core/res/res/layout/choose_selected_account_row.xml b/core/res/res/layout/choose_selected_account_row.xml
deleted file mode 100644
index d88750d..0000000
--- a/core/res/res/layout/choose_selected_account_row.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright (C) 2011 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.
- */
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:paddingLeft="0dip"
- android:paddingRight="0dip"
- android:orientation="horizontal" >
-
- <ImageView android:id="@+id/account_row_icon"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:paddingRight="8dip" />
-
- <TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/account_row_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:gravity="center_vertical"
- android:minHeight="?android:attr/listPreferredItemHeight" />
-
- <ImageView android:id="@+id/account_row_checkmark"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="right"
- android:layout_weight="2"
- android:paddingRight="8dip"
- android:src="@drawable/ic_checkmark_holo_light" />
-
-</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/choose_type_and_account.xml b/core/res/res/layout/choose_type_and_account.xml
index d7068b7bf..9d1d284 100644
--- a/core/res/res/layout/choose_type_and_account.xml
+++ b/core/res/res/layout/choose_type_and_account.xml
@@ -20,53 +20,52 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
- android:paddingLeft="16dip"
- android:paddingRight="16dip">
+ android:orientation="vertical">
- <TextView android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_gravity="left"
- android:text="@string/choose_account_label"
- android:paddingTop="16dip"
- android:paddingBottom="16dip"
- android:textColor="@android:color/holo_blue_light"
- />
-
- <View android:layout_height="3dip"
- android:layout_width="match_parent"
- android:background="#323232"/>
-
+ <!-- Customizable description text -->
<TextView android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_gravity="left|center_vertical"
- android:text="@string/choose_account_text"
android:paddingTop="16dip"
android:paddingBottom="16dip"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
/>
+ <!-- List of accounts, with "Add new account" as the last item -->
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawSelectorOnTop="false"
android:layout_weight="1"
- android:scrollbarAlwaysDrawVerticalTrack="true" />
+ android:scrollbarAlwaysDrawVerticalTrack="true"
+ android:choiceMode="singleChoice" />
+ <!-- Horizontal divider line -->
<View android:layout_height="1dip"
android:layout_width="match_parent"
android:background="?android:attr/dividerHorizontal" />
- <Button android:id="@+id/addAccount"
- style="?android:attr/buttonBarButtonStyle"
+ <!-- Alert dialog style buttons along the bottom. -->
+ <LinearLayout android:id="@+id/button_bar"
+ style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="2dip"
- android:layout_marginRight="2dip"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@string/add_account_button_label"
- />
+ android:measureWithLargestChild="true">
+ <Button android:id="@android:id/button1"
+ style="?android:attr/buttonBarButtonStyle"
+ android:layout_width="wrap_content" android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@android:string/no"
+ android:onClick="onCancelButtonClicked" />
+ <Button android:id="@android:id/button2"
+ style="?android:attr/buttonBarButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@android:string/yes"
+ android:onClick="onOkButtonClicked" />
+ </LinearLayout>
</LinearLayout>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4cfbff5..a70394f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -28,7 +28,6 @@
this.
-->
<java-symbol type="id" name="account_name" />
- <java-symbol type="id" name="account_row_checkmark" />
<java-symbol type="id" name="account_row_icon" />
<java-symbol type="id" name="account_row_text" />
<java-symbol type="id" name="account_type" />
@@ -41,7 +40,6 @@
<java-symbol type="id" name="action_menu_presenter" />
<java-symbol type="id" name="action_mode_close_button" />
<java-symbol type="id" name="activity_chooser_view_content" />
- <java-symbol type="id" name="addAccount" />
<java-symbol type="id" name="albumart" />
<java-symbol type="id" name="alertTitle" />
<java-symbol type="id" name="allow_button" />
@@ -301,6 +299,7 @@
<java-symbol type="dimen" name="notification_title_text_size" />
<java-symbol type="dimen" name="notification_subtext_size" />
+ <java-symbol type="string" name="add_account_button_label" />
<java-symbol type="string" name="addToDictionary" />
<java-symbol type="string" name="action_bar_home_description" />
<java-symbol type="string" name="action_bar_up_description" />
@@ -1027,7 +1026,6 @@
<java-symbol type="layout" name="choose_account" />
<java-symbol type="layout" name="choose_account_row" />
<java-symbol type="layout" name="choose_account_type" />
- <java-symbol type="layout" name="choose_selected_account_row" />
<java-symbol type="layout" name="choose_type_and_account" />
<java-symbol type="layout" name="grant_credentials_permission" />
<java-symbol type="layout" name="number_picker" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5929439..65457b3 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3382,9 +3382,8 @@
<string name="choose_account_label">Choose an account</string>
<string name="add_account_label">"Add an account"</string>
- <string name="choose_account_text">"Which account do you want to use?"</string>
- <!-- Button label to add an account [CHAR LIMIT=20] -->
+ <!-- List item to add an account [CHAR LIMIT=20] -->
<string name="add_account_button_label">Add account</string>
<!-- NumberPicker - accessibility support -->
diff --git a/docs/html/guide/topics/ui/index.jd b/docs/html/guide/topics/ui/index.jd
index 45c9ac9..be07249 100644
--- a/docs/html/guide/topics/ui/index.jd
+++ b/docs/html/guide/topics/ui/index.jd
@@ -148,7 +148,7 @@
On<em><something></em>Listener, each with a callback method called <code>On<em><something></em>()</code>.
For example, {@link android.view.View.OnClickListener} (for handling "clicks" on a View),
{@link android.view.View.OnTouchListener} (for handling touch screen events in a View), and
-{@link android.view.View.OnKeyListener} (for handling device key presses within a View). So if you want your View
+{@link android.view.View.OnKeyListener} if you want to handle hardware key presses within a View. So if you want your View
to be notified when it is "clicked" (such as when a button is selected), implement OnClickListener and define
its <code>onClick()</code> callback method (where you perform the action upon click), and register it
to the View with <code>{@link android.view.View#setOnClickListener(View.OnClickListener) setOnClickListener()}</code>.
@@ -158,7 +158,7 @@
that occur within it. Example events you can handle include when the
screen is touched (<code>{@link android.view.View#onTouchEvent(MotionEvent) onTouchEvent()}</code>), when
the trackball is moved (<code>{@link android.view.View#onTrackballEvent(MotionEvent) onTrackballEvent()}</code>),
-or when a key on the device is pressed (<code>{@link android.view.View#onKeyDown(int, KeyEvent)
+or when a <em>hardware</em> key on the device is pressed (<code>{@link android.view.View#onKeyDown(int, KeyEvent)
onKeyDown()}</code>). This allows you to define the default behavior for each event inside your custom View and determine
whether the event should be passed on to some other child View. Again, these are callbacks to the View class,
so your only chance to define them is when you
diff --git a/docs/html/guide/topics/ui/ui-events.jd b/docs/html/guide/topics/ui/ui-events.jd
index 93bad43..707d4b1 100644
--- a/docs/html/guide/topics/ui/ui-events.jd
+++ b/docs/html/guide/topics/ui/ui-events.jd
@@ -64,7 +64,7 @@
This is called when the user navigates onto or away from the item, using the navigation-keys or trackball.</dd>
<dt><code>onKey()</code></dt>
<dd>From {@link android.view.View.OnKeyListener}.
- This is called when the user is focused on the item and presses or releases a key on the device.</dd>
+ This is called when the user is focused on the item and presses or releases a hardware key on the device.</dd>
<dt><code>onTouch()</code></dt>
<dd>From {@link android.view.View.OnTouchListener}.
This is called when the user performs an action qualified as a touch event, including a press, a release,
@@ -143,13 +143,23 @@
within the event, such as a finger gesture, or the eventual up action event.</li>
</ul>
-<p>Remember that key events are always delivered to the View currently in focus. They are dispatched starting from the top
+<p>Remember that hardware key events are always delivered to the View currently in focus. They are dispatched starting from the top
of the View hierarchy, and then down, until they reach the appropriate destination. If your View (or a child of your View)
currently has focus, then you can see the event travel through the <code>{@link android.view.View#dispatchKeyEvent(KeyEvent)
dispatchKeyEvent()}</code> method. As an alternative to capturing key events through your View, you can also receive
all of the events inside your Activity with <code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code>
and <code>{@link android.app.Activity#onKeyUp(int,KeyEvent) onKeyUp()}</code>.</p>
+<p>Also, when thinking about text input for your application, remember that many devices only have software input
+methods. Such methods are not required to be key-based; some may use voice input, handwriting, and so on. Even if
+an input method presents a keyboard-like interface, it will generally <strong>not</strong> trigger the
+<code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code> family of events. You should never
+build a UI that requires specific key presses to be controlled unless you want to limit your application to devices
+with a hardware keyboard. In particular, do not rely on these methods to validate input when the user presses the
+return key; instead, use actions like {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE} to signal the
+input method how your application expects to react, so it may change its UI in a meaningful way. Avoid assumptions
+about how a software input method should work and just trust it to supply already formatted text to your application.</p>
+
<p class="note"><strong>Note:</strong> Android will call event handlers first and then the appropriate default
handlers from the class definition second. As such, returning <em>true</em> from these event listeners will stop
the propagation of the event to other event listeners and will also block the callback to the
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
index b0c1c35..41ec120 100755
--- a/media/jni/mediaeditor/VideoEditorMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorMain.cpp
@@ -2623,16 +2623,21 @@
M4OSA_Char* tmpString =
(M4OSA_Char *)videoEditJava_getString(&initialized, pEnv, tempPath,
NULL, M4OSA_NULL);
+ M4OSA_UInt32 length = strlen((const char *)tmpString);
+ // Malloc additional 2 bytes for beginning and tail separator.
+ M4OSA_UInt32 pathLength = length + 2;
+
pContext->initParams.pTempPath = (M4OSA_Char *)
- M4OSA_32bitAlignedMalloc(strlen((const char *)tmpString) + 1, 0x0,
- (M4OSA_Char *)"tempPath");
+ M4OSA_32bitAlignedMalloc(pathLength, 0x0, (M4OSA_Char *)"tempPath");
+
//initialize the first char. so that strcat works.
M4OSA_Char *ptmpChar = (M4OSA_Char*)pContext->initParams.pTempPath;
ptmpChar[0] = 0x00;
strncat((char *)pContext->initParams.pTempPath, (const char *)tmpString,
- (size_t)strlen((const char *)tmpString));
+ length);
strncat((char *)pContext->initParams.pTempPath, (const char *)"/", (size_t)1);
free(tmpString);
+ tmpString = NULL;
pContext->mIsUpdateOverlay = false;
pContext->mOverlayFileName = NULL;
pContext->decoders = NULL;
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 2786013..26dba67 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -57,7 +57,13 @@
<!-- Show rotation lock button in phone-style notification panel. -->
<bool name="config_showRotationLock">true</bool>
+ <!-- Amount of time to hold off before showing the search panel when the user presses home -->
+ <integer name="config_show_search_delay">200</integer>
+
<!-- Vibration duration for MultiWaveView used in SearchPanelView -->
- <integer translatable="false" name="config_vibration_duration">20</integer>
+ <integer translatable="false" name="config_vibration_duration">0</integer>
+
+ <!-- Vibration duration for MultiWaveView used in SearchPanelView -->
+ <integer translatable="false" name="config_search_panel_view_vibration_duration">20</integer>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
index 060d08e..af88a06 100644
--- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
@@ -16,9 +16,7 @@
package com.android.systemui;
-import android.animation.Animator;
import android.animation.LayoutTransition;
-import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.SearchManager;
import android.content.ActivityNotFoundException;
@@ -26,6 +24,9 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Vibrator;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Slog;
import android.view.MotionEvent;
@@ -34,12 +35,12 @@
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.widget.FrameLayout;
-
import com.android.internal.widget.multiwaveview.MultiWaveView;
import com.android.internal.widget.multiwaveview.MultiWaveView.OnTriggerListener;
import com.android.systemui.R;
import com.android.systemui.recent.StatusBarTouchProxy;
import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.tablet.StatusBarPanel;
import com.android.systemui.statusbar.tablet.TabletStatusBar;
@@ -49,7 +50,7 @@
private static final int SEARCH_PANEL_HOLD_DURATION = 500;
static final String TAG = "SearchPanelView";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
- private Context mContext;
+ private final Context mContext;
private BaseStatusBar mBar;
private StatusBarTouchProxy mStatusBarTouchProxy;
@@ -77,7 +78,7 @@
Intent intent = getAssistIntent();
return intent == null ? false
: mContext.getPackageManager().queryIntentActivities(intent,
- PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
+ PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
}
private Intent getAssistIntent() {
@@ -106,9 +107,10 @@
private void startAssistActivity() {
// Close Recent Apps if needed
- mBar.animateCollapse();
+ mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL);
// Launch Assist
Intent intent = getAssistIntent();
+ if (intent == null) return;
try {
ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
R.anim.search_launch_enter, R.anim.search_launch_exit);
@@ -142,13 +144,14 @@
case com.android.internal.R.drawable.ic_lockscreen_search:
mWaitingForLaunch = true;
startAssistActivity();
+ vibrate();
postDelayed(new Runnable() {
public void run() {
mWaitingForLaunch = false;
mBar.hideSearchPanel();
}
}, SEARCH_PANEL_HOLD_DURATION);
- break;
+ break;
}
}
@@ -160,7 +163,7 @@
protected void onFinishInflate() {
super.onFinishInflate();
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mSearchTargetsContainer = (ViewGroup) findViewById(R.id.search_panel_container);
+ mSearchTargetsContainer = findViewById(R.id.search_panel_container);
mStatusBarTouchProxy = (StatusBarTouchProxy) findViewById(R.id.status_bar_touch_proxy);
// TODO: fetch views
mMultiWaveView = (MultiWaveView) findViewById(R.id.multi_wave_view);
@@ -186,7 +189,7 @@
}
}
- private OnPreDrawListener mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
+ private final OnPreDrawListener mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
getViewTreeObserver().removeOnPreDrawListener(this);
mMultiWaveView.resumeAnimations();
@@ -194,10 +197,20 @@
}
};
+ private void vibrate() {
+ Context context = getContext();
+ if (Settings.System.getInt(context.getContentResolver(),
+ Settings.System.HAPTIC_FEEDBACK_ENABLED, 1) != 0) {
+ Resources res = context.getResources();
+ Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
+ vibrator.vibrate(res.getInteger(R.integer.config_search_panel_view_vibration_duration));
+ }
+ }
+
public void show(final boolean show, boolean animate) {
if (!show) {
final LayoutTransition transitioner = animate ? createLayoutTransitioner() : null;
- ((ViewGroup)mSearchTargetsContainer).setLayoutTransition(transitioner);
+ ((ViewGroup) mSearchTargetsContainer).setLayoutTransition(transitioner);
}
mShowing = show;
if (show) {
@@ -207,6 +220,7 @@
// right before we are drawn
mMultiWaveView.suspendAnimations();
getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
+ vibrate();
}
setFocusable(true);
setFocusableInTouchMode(true);
@@ -219,7 +233,7 @@
public void hide(boolean animate) {
if (mBar != null) {
// This will indirectly cause show(false, ...) to get called
- mBar.animateCollapse();
+ mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
} else {
setVisibility(View.INVISIBLE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 39d686f..89bf3b6 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -58,6 +58,7 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.tablet.StatusBarPanel;
import com.android.systemui.statusbar.tablet.TabletStatusBar;
@@ -368,7 +369,7 @@
}
if (mBar != null) {
// This will indirectly cause show(false, ...) to get called
- mBar.animateCollapse();
+ mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
}
}
@@ -822,7 +823,7 @@
if (viewHolder != null) {
final TaskDescription ad = viewHolder.taskDescription;
startApplicationDetailsActivity(ad.packageName);
- mBar.animateCollapse();
+ mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
} else {
throw new IllegalStateException("Oops, no tag on view " + selectedView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index a352748..f088e0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -253,7 +253,7 @@
mContext.startActivity(intent);
}
- protected View.OnLongClickListener getNotificationLongClicker() {
+ protected View.OnLongClickListener getNotificationLongClicker() {
return new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
@@ -268,7 +268,7 @@
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.notification_inspect_item) {
startApplicationDetailsActivity(packageNameF);
- animateCollapse();
+ animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
} else {
return false;
}
@@ -618,7 +618,7 @@
}
// close the shade if it was open
- animateCollapse();
+ animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
visibilityChanged(false);
// If this click was on the intruder alert, hide that instead
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 4209354..a00d95a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -66,6 +66,13 @@
private static final int MSG_SET_NAVIGATION_ICON_HINTS = 14 << MSG_SHIFT;
+ public static final int FLAG_EXCLUDE_NONE = 0;
+ public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
+ public static final int FLAG_EXCLUDE_RECENTS_PANEL = 1 << 1;
+ public static final int FLAG_EXCLUDE_NOTIFICATION_PANEL = 1 << 2;
+ public static final int FLAG_EXCLUDE_INPUT_METHODS_PANEL = 1 << 3;
+ public static final int FLAG_EXCLUDE_COMPAT_MODE_PANEL = 1 << 4;
+
private StatusBarIconList mList;
private Callbacks mCallbacks;
private Handler mHandler = new H();
@@ -88,7 +95,7 @@
public void removeNotification(IBinder key);
public void disable(int state);
public void animateExpand();
- public void animateCollapse();
+ public void animateCollapse(int flags);
public void setSystemUiVisibility(int vis, int mask);
public void topAppWindowChanged(boolean visible);
public void setImeWindowStatus(IBinder token, int vis, int backDisposition);
@@ -161,9 +168,13 @@
}
public void animateCollapse() {
+ animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
+ }
+
+ public void animateCollapse(int flags) {
synchronized (mList) {
mHandler.removeMessages(MSG_SET_VISIBILITY);
- mHandler.obtainMessage(MSG_SET_VISIBILITY, OP_COLLAPSE, 0, null).sendToTarget();
+ mHandler.obtainMessage(MSG_SET_VISIBILITY, OP_COLLAPSE, flags, null).sendToTarget();
}
}
@@ -277,7 +288,7 @@
if (msg.arg1 == OP_EXPAND) {
mCallbacks.animateExpand();
} else {
- mCallbacks.animateCollapse();
+ mCallbacks.animateCollapse(msg.arg2);
}
break;
case MSG_SET_SYSTEMUI_VISIBILITY:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 344411b..3a50560 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -76,6 +76,7 @@
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.RotationToggle;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarIconView;
@@ -529,16 +530,29 @@
}
};
+ private int mShowSearchHoldoff = 0;
+ private Runnable mShowSearchPanel = new Runnable() {
+ public void run() {
+ showSearchPanel();
+ }
+ };
+
View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- if (!shouldDisableNavbarGestures()) {
- showSearchPanel();
- }
- break;
- }
- return false;
+ case MotionEvent.ACTION_DOWN:
+ if (!shouldDisableNavbarGestures()) {
+ mHandler.removeCallbacks(mShowSearchPanel);
+ mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff);
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mHandler.removeCallbacks(mShowSearchPanel);
+ break;
+ }
+ return false;
}
};
@@ -733,6 +747,8 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
updateRecentsPanel();
+ mShowSearchHoldoff = mContext.getResources().getInteger(
+ R.integer.config_show_search_delay);
}
private void loadNotificationShade() {
@@ -1057,29 +1073,33 @@
}
public void animateCollapse() {
- animateCollapse(false);
+ animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
}
- public void animateCollapse(boolean excludeRecents) {
- animateCollapse(excludeRecents, 1.0f);
+ public void animateCollapse(int flags) {
+ animateCollapse(flags, 1.0f);
}
- public void animateCollapse(boolean excludeRecents, float velocityMultiplier) {
+ public void animateCollapse(int flags, float velocityMultiplier) {
if (SPEW) {
Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
+ " mExpandedVisible=" + mExpandedVisible
+ " mExpanded=" + mExpanded
+ " mAnimating=" + mAnimating
+ " mAnimY=" + mAnimY
- + " mAnimVel=" + mAnimVel);
+ + " mAnimVel=" + mAnimVel
+ + " flags=" + flags);
}
- if (!excludeRecents) {
+ if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
}
- mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
- mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
+
+ if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) {
+ mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
+ mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
+ }
if (!mExpandedVisible) {
return;
@@ -1941,7 +1961,7 @@
}
}
if (snapshot.isEmpty()) {
- animateCollapse(false);
+ animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
return;
}
new Thread(new Runnable() {
@@ -1989,7 +2009,7 @@
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
- animateCollapse(false);
+ animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
}
}, totalDelay + 225);
}
@@ -2016,14 +2036,14 @@
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
|| Intent.ACTION_SCREEN_OFF.equals(action)) {
- boolean excludeRecents = false;
+ int flags = CommandQueue.FLAG_EXCLUDE_NONE;
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
String reason = intent.getStringExtra("reason");
- if (reason != null) {
- excludeRecents = reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS);
+ if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
+ flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
}
}
- animateCollapse(excludeRecents);
+ animateCollapse(flags);
}
else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
updateResources();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index c0ac50e..8df9b85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -67,6 +67,7 @@
import com.android.systemui.recent.RecentTasksLoader;
import com.android.systemui.recent.RecentsPanelView;
import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DoNotDisturb;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.SignalClusterView;
@@ -186,16 +187,30 @@
private int mNavigationIconHints = 0;
+ private int mShowSearchHoldoff = 0;
+
public Context getContext() { return mContext; }
+ private Runnable mShowSearchPanel = new Runnable() {
+ public void run() {
+ showSearchPanel();
+ }
+ };
+
private View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (!shouldDisableNavbarGestures()) {
- showSearchPanel();
+ mHandler.removeCallbacks(mShowSearchPanel);
+ mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff);
}
break;
+
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mHandler.removeCallbacks(mShowSearchPanel);
+ break;
}
return false;
}
@@ -387,6 +402,8 @@
WindowManagerImpl.getDefault().updateViewLayout(mNotificationPanel,
mNotificationPanelParams);
mRecentsPanel.updateValuesFromResources();
+ mShowSearchHoldoff = mContext.getResources().getInteger(
+ R.integer.config_show_search_delay);
}
protected void loadDimens() {
@@ -1001,22 +1018,31 @@
}
public void animateCollapse() {
- animateCollapse(false);
+ animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
}
- private void animateCollapse(boolean excludeRecents) {
- mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PANEL);
- mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PANEL);
- if (!excludeRecents) {
+ public void animateCollapse(int flags) {
+ if ((flags & CommandQueue.FLAG_EXCLUDE_NOTIFICATION_PANEL) == 0) {
+ mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PANEL);
+ mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PANEL);
+ }
+ if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
}
- mHandler.removeMessages(MSG_CLOSE_INPUT_METHODS_PANEL);
- mHandler.sendEmptyMessage(MSG_CLOSE_INPUT_METHODS_PANEL);
- mHandler.removeMessages(MSG_CLOSE_COMPAT_MODE_PANEL);
- mHandler.sendEmptyMessage(MSG_CLOSE_COMPAT_MODE_PANEL);
- mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
- mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
+ if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) {
+ mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
+ mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
+ }
+ if ((flags & CommandQueue.FLAG_EXCLUDE_INPUT_METHODS_PANEL) == 0) {
+ mHandler.removeMessages(MSG_CLOSE_INPUT_METHODS_PANEL);
+ mHandler.sendEmptyMessage(MSG_CLOSE_INPUT_METHODS_PANEL);
+ }
+ if ((flags & CommandQueue.FLAG_EXCLUDE_COMPAT_MODE_PANEL) == 0) {
+ mHandler.removeMessages(MSG_CLOSE_COMPAT_MODE_PANEL);
+ mHandler.sendEmptyMessage(MSG_CLOSE_COMPAT_MODE_PANEL);
+ }
+
}
@Override // CommandQueue
@@ -1594,11 +1620,11 @@
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
|| Intent.ACTION_SCREEN_OFF.equals(action)) {
- boolean excludeRecents = false;
+ int flags = CommandQueue.FLAG_EXCLUDE_NONE;
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
String reason = intent.getStringExtra("reason");
- if (reason != null) {
- excludeRecents = reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS);
+ if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
+ flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
}
}
if (Intent.ACTION_SCREEN_OFF.equals(action)) {
@@ -1607,9 +1633,9 @@
// TODO: hide other things, like the notification tray,
// with no animation as well
mRecentsPanel.show(false, false);
- excludeRecents = true;
+ flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
}
- animateCollapse(excludeRecents);
+ animateCollapse(flags);
}
}
};
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index c7b336f..c74dd00 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -198,7 +198,7 @@
}
// TODO: Respect allowImplicitlySelectedSubtype
- // TODO: Save SpellCheckerSubtype by supported languages.
+ // TODO: Save SpellCheckerSubtype by supported languages by looking at "locale".
@Override
public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
String locale, boolean allowImplicitlySelectedSubtype) {
@@ -250,10 +250,10 @@
for (int i = 0; i < sci.getSubtypeCount(); ++i) {
final SpellCheckerSubtype scs = sci.getSubtypeAt(i);
if (hashCode == 0) {
- if (candidateLocale.equals(locale)) {
+ final String scsLocale = scs.getLocale();
+ if (candidateLocale.equals(scsLocale)) {
return scs;
} else if (candidate == null) {
- final String scsLocale = scs.getLocale();
if (candidateLocale.length() >= 2 && scsLocale.length() >= 2
&& candidateLocale.startsWith(scsLocale)) {
// Fall back to the applicable language
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 4b4a89d..3a767c2 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -19,9 +19,8 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
import android.os.UserId;
+import android.util.Slog;
import java.io.PrintWriter;
@@ -69,6 +68,8 @@
_intent.setSourceBounds(null);
}
}
+ if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
+ "Setting Intent of " + this + " to " + _intent);
intent = _intent;
realActivity = _intent != null ? _intent.getComponent() : null;
origActivity = null;
@@ -80,6 +81,8 @@
targetIntent.setComponent(targetComponent);
targetIntent.setSelector(null);
targetIntent.setSourceBounds(null);
+ if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
+ "Setting Intent of " + this + " to target " + targetIntent);
intent = targetIntent;
realActivity = targetComponent;
origActivity = _intent.getComponent();
@@ -103,9 +106,10 @@
}
void dump(PrintWriter pw, String prefix) {
- if (numActivities != 0 || rootWasReset) {
+ if (numActivities != 0 || rootWasReset || userId != 0) {
pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
- pw.print(" rootWasReset="); pw.println(rootWasReset);
+ pw.print(" rootWasReset="); pw.print(rootWasReset);
+ pw.print(" userId="); pw.println(userId);
}
if (affinity != null) {
pw.print(prefix); pw.print("affinity="); pw.println(affinity);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index d3b667f..04ec820 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -225,9 +225,10 @@
{
ALOGD("nuSensorService thread starting...");
- const size_t numEventMax = 16 * (1 + mVirtualSensorList.size());
- sensors_event_t buffer[numEventMax];
- sensors_event_t scratch[numEventMax];
+ const size_t numEventMax = 16;
+ const size_t minBufferSize = numEventMax * mVirtualSensorList.size();
+ sensors_event_t buffer[minBufferSize];
+ sensors_event_t scratch[minBufferSize];
SensorDevice& device(SensorDevice::getInstance());
const size_t vcount = mVirtualSensorList.size();
@@ -255,10 +256,17 @@
fusion.process(event[i]);
}
}
- for (size_t i=0 ; i<size_t(count) ; i++) {
+ for (size_t i=0 ; i<size_t(count) && k<minBufferSize ; i++) {
for (size_t j=0 ; j<activeVirtualSensorCount ; j++) {
+ if (count + k >= minBufferSize) {
+ ALOGE("buffer too small to hold all events: "
+ "count=%u, k=%u, size=%u",
+ count, k, minBufferSize);
+ break;
+ }
sensors_event_t out;
- if (virtualSensors.valueAt(j)->process(&out, event[i])) {
+ SensorInterface* si = virtualSensors.valueAt(j);
+ if (si->process(&out, event[i])) {
buffer[count + k] = out;
k++;
}