Merge change 24887 into eclair
* changes:
Fix http://b/issue?id=2098873 (drawing glitch in SeekBar).
diff --git a/api/current.xml b/api/current.xml
index f8cf61f..38490f3 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -16089,6 +16089,17 @@
visibility="public"
>
</method>
+<method name="onBackPressed"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onChildTitleChanged"
return="void"
abstract="false"
@@ -16318,6 +16329,21 @@
<parameter name="event" type="android.view.KeyEvent">
</parameter>
</method>
+<method name="onKeyLongPress"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
<method name="onKeyMultiple"
return="boolean"
abstract="false"
@@ -20085,6 +20111,17 @@
visibility="public"
>
</method>
+<method name="onBackPressed"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onContentChanged"
return="void"
abstract="false"
@@ -20219,6 +20256,21 @@
<parameter name="event" type="android.view.KeyEvent">
</parameter>
</method>
+<method name="onKeyLongPress"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
<method name="onKeyMultiple"
return="boolean"
abstract="false"
@@ -24714,6 +24766,17 @@
visibility="public"
>
</method>
+<method name="getFastDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getInstance"
return="android.app.WallpaperManager"
abstract="false"
@@ -24738,6 +24801,17 @@
visibility="public"
>
</method>
+<method name="peekFastDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="setBitmap"
return="void"
abstract="false"
@@ -63330,7 +63404,7 @@
type="android.graphics.drawable.BitmapDrawable"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="filepath" type="java.lang.String">
@@ -63343,6 +63417,30 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
+<parameter name="filepath" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="BitmapDrawable"
+ type="android.graphics.drawable.BitmapDrawable"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="is" type="java.io.InputStream">
+</parameter>
+</constructor>
+<constructor name="BitmapDrawable"
+ type="android.graphics.drawable.BitmapDrawable"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
<parameter name="is" type="java.io.InputStream">
</parameter>
</constructor>
@@ -64521,6 +64619,19 @@
visibility="public"
>
</method>
+<method name="newDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
+</method>
</class>
<class name="DrawableContainer"
extends="android.graphics.drawable.Drawable"
@@ -69511,6 +69622,17 @@
visibility="public"
>
</constructor>
+<method name="getKeyDispatcherState"
+ return="android.view.KeyEvent.DispatcherState"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onBind"
return="android.os.IBinder"
abstract="false"
@@ -70256,6 +70378,21 @@
<parameter name="event" type="android.view.KeyEvent">
</parameter>
</method>
+<method name="onKeyLongPress"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
<method name="onKeyMultiple"
return="boolean"
abstract="false"
@@ -101558,6 +101695,17 @@
visibility="protected"
>
</method>
+<method name="quit"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
</class>
<interface name="IBinder"
abstract="true"
@@ -144753,7 +144901,7 @@
type="android.view.KeyEvent"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="origEvent" type="android.view.KeyEvent">
@@ -144810,6 +144958,25 @@
<parameter name="newRepeat" type="int">
</parameter>
</method>
+<method name="changeTimeRepeat"
+ return="android.view.KeyEvent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+<parameter name="eventTime" type="long">
+</parameter>
+<parameter name="newRepeat" type="int">
+</parameter>
+<parameter name="newFlags" type="int">
+</parameter>
+</method>
<method name="describeContents"
return="int"
abstract="false"
@@ -144828,11 +144995,28 @@
synchronized="false"
static="false"
final="true"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="receiver" type="android.view.KeyEvent.Callback">
+</parameter>
+</method>
+<method name="dispatch"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
deprecated="not deprecated"
visibility="public"
>
<parameter name="receiver" type="android.view.KeyEvent.Callback">
</parameter>
+<parameter name="state" type="android.view.KeyEvent.DispatcherState">
+</parameter>
+<parameter name="target" type="java.lang.Object">
+</parameter>
</method>
<method name="getAction"
return="int"
@@ -145079,6 +145263,17 @@
visibility="public"
>
</method>
+<method name="isLongPress"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isModifierKey"
return="boolean"
abstract="false"
@@ -145136,6 +145331,28 @@
visibility="public"
>
</method>
+<method name="isTracking"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="startTracking"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="writeToParcel"
return="void"
abstract="false"
@@ -145205,6 +145422,17 @@
visibility="public"
>
</field>
+<field name="FLAG_CANCELED_LONG_PRESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="256"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_EDITOR_ACTION"
type="int"
transient="false"
@@ -145238,6 +145466,17 @@
visibility="public"
>
</field>
+<field name="FLAG_LONG_PRESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="128"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_SOFT_KEYBOARD"
type="int"
transient="false"
@@ -145249,6 +145488,17 @@
visibility="public"
>
</field>
+<field name="FLAG_TRACKING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="512"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_VIRTUAL_HARD_KEY"
type="int"
transient="false"
@@ -146394,6 +146644,21 @@
<parameter name="event" type="android.view.KeyEvent">
</parameter>
</method>
+<method name="onKeyLongPress"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
<method name="onKeyMultiple"
return="boolean"
abstract="true"
@@ -146427,6 +146692,101 @@
</parameter>
</method>
</interface>
+<class name="KeyEvent.DispatcherState"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="KeyEvent.DispatcherState"
+ type="android.view.KeyEvent.DispatcherState"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="handleUpEvent"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
+<method name="isTracking"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
+<method name="performedLongPress"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
+<method name="reset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="reset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="target" type="java.lang.Object">
+</parameter>
+</method>
+<method name="startTracking"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+<parameter name="target" type="java.lang.Object">
+</parameter>
+</method>
+</class>
<class name="LayoutInflater"
extends="java.lang.Object"
abstract="true"
@@ -150801,6 +151161,17 @@
visibility="public"
>
</method>
+<method name="getKeyDispatcherState"
+ return="android.view.KeyEvent.DispatcherState"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getLayoutParams"
return="android.view.ViewGroup.LayoutParams"
abstract="false"
@@ -151927,6 +152298,21 @@
<parameter name="event" type="android.view.KeyEvent">
</parameter>
</method>
+<method name="onKeyLongPress"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
<method name="onKeyMultiple"
return="boolean"
abstract="false"
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 8cfb758..6abed93 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -1398,9 +1398,8 @@
}
if (!imsi.equals(storedImsi) && !TextUtils.isEmpty(storedImsi)) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "wiping all passwords and authtokens");
- }
+ Log.w(TAG, "wiping all passwords and authtokens because IMSI changed ("
+ + "stored=" + storedImsi + ", current=" + imsi + ")");
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
db.beginTransaction();
try {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8c10091..be243a5 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1752,8 +1752,9 @@
*
* <p>If the focused view didn't want this event, this method is called.
*
- * <p>The default implementation handles KEYCODE_BACK to stop the activity
- * and go back, and other default key handling if configured with {@link #setDefaultKeyMode}.
+ * <p>The default implementation sets up state to call
+ * {@link #onKeyLongPress}, and does other default key handling
+ * if configured with {@link #setDefaultKeyMode}.
*
* @return Return <code>true</code> to prevent this event from being propagated
* further, or <code>false</code> to indicate that you have not handled
@@ -1762,16 +1763,19 @@
* @see android.view.KeyEvent
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
- finish();
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ event.startTracking();
return true;
}
if (mDefaultKeyMode == DEFAULT_KEYS_DISABLE) {
return false;
} else if (mDefaultKeyMode == DEFAULT_KEYS_SHORTCUT) {
- return getWindow().performPanelShortcut(Window.FEATURE_OPTIONS_PANEL,
- keyCode, event, Menu.FLAG_ALWAYS_PERFORM_CLOSE);
+ if (getWindow().performPanelShortcut(Window.FEATURE_OPTIONS_PANEL,
+ keyCode, event, Menu.FLAG_ALWAYS_PERFORM_CLOSE)) {
+ return true;
+ }
+ return false;
} else {
// Common code for DEFAULT_KEYS_DIALER & DEFAULT_KEYS_SEARCH_*
boolean clearSpannable = false;
@@ -1780,8 +1784,8 @@
clearSpannable = true;
handled = false;
} else {
- handled = TextKeyListener.getInstance().onKeyDown(null, mDefaultKeySsb,
- keyCode, event);
+ handled = TextKeyListener.getInstance().onKeyDown(
+ null, mDefaultKeySsb, keyCode, event);
if (handled && mDefaultKeySsb.length() > 0) {
// something useable has been typed - dispatch it now.
@@ -1813,11 +1817,23 @@
}
/**
+ * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
+ * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
+ * the event).
+ */
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ /**
* Called when a key was released and not handled by any of the views
* inside of the activity. So, for example, key presses while the cursor
* is inside a TextView will not trigger the event (unless it is a navigation
* to another object) because TextView handles its own key presses.
*
+ * <p>The default implementation handles KEYCODE_BACK to stop the activity
+ * and go back.
+ *
* @return Return <code>true</code> to prevent this event from being propagated
* further, or <code>false</code> to indicate that you have not handled
* this event and it should continue to be propagated.
@@ -1825,6 +1841,11 @@
* @see KeyEvent
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
+ && !event.isCanceled()) {
+ onBackPressed();
+ return true;
+ }
return false;
}
@@ -1838,6 +1859,15 @@
}
/**
+ * Called when the activity has detected the user's press of the back
+ * key. The default implementation simply finishes the current activity,
+ * but you can override this to do whatever you want.
+ */
+ public void onBackPressed() {
+ finish();
+ }
+
+ /**
* Called when a touch screen event was not handled by any of the views
* under it. This is most useful to process touch events that happen
* outside of your window bounds, where there is no view to receive it.
@@ -1909,9 +1939,10 @@
/**
* Called when the current {@link Window} of the activity gains or loses
* focus. This is the best indicator of whether this activity is visible
- * to the user.
+ * to the user. The default implementation clears the key tracking
+ * state, so should always be called.
*
- * <p>Note that this provides information what global focus state, which
+ * <p>Note that this provides information about global focus state, which
* is managed independently of activity lifecycles. As such, while focus
* changes will generally have some relation to lifecycle changes (an
* activity that is stopped will not generally get window focus), you
@@ -1988,7 +2019,8 @@
if (getWindow().superDispatchKeyEvent(event)) {
return true;
}
- return event.dispatch(this);
+ return event.dispatch(this, mDecor != null
+ ? mDecor.getKeyDispatcherState() : null, this);
}
/**
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 1b96af9..58e8b32 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -481,17 +481,15 @@
*
* <p>If the focused view didn't want this event, this method is called.
*
- * <p>The default implementation handles KEYCODE_BACK to close the
- * dialog.
+ * <p>The default implementation consumed the KEYCODE_BACK to later
+ * handle it in {@link #onKeyUp}.
*
* @see #onKeyUp
* @see android.view.KeyEvent
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
- if (mCancelable) {
- cancel();
- }
+ event.startTracking();
return true;
}
@@ -499,12 +497,29 @@
}
/**
+ * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
+ * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
+ * the event).
+ */
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ /**
* A key was released.
*
+ * <p>The default implementation handles KEYCODE_BACK to close the
+ * dialog.
+ *
* @see #onKeyDown
* @see KeyEvent
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
+ && !event.isCanceled()) {
+ onBackPressed();
+ return true;
+ }
return false;
}
@@ -518,6 +533,17 @@
}
/**
+ * Called when the dialog has detected the user's press of the back
+ * key. The default implementation simply cancels the dialog (only if
+ * it is cancelable), but you can override this to do whatever you want.
+ */
+ public void onBackPressed() {
+ if (mCancelable) {
+ cancel();
+ }
+ }
+
+ /**
* Called when a touch screen event was not handled by any of the views
* under it. This is most useful to process touch events that happen outside
* of your window bounds, where there is no view to receive it.
@@ -599,7 +625,8 @@
if (mWindow.superDispatchKeyEvent(event)) {
return true;
}
- return event.dispatch(this);
+ return event.dispatch(this, mDecor != null
+ ? mDecor.getKeyDispatcherState() : null, this);
}
/**
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index f474f06..62dc9b2 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -745,11 +745,9 @@
return true;
}
- if (keyCode == KeyEvent.KEYCODE_SEARCH && event.getRepeatCount() < 1) {
- // If the search key is pressed, toggle between global and in-app search. If we are
- // currently doing global search and there is no in-app search context to toggle to,
- // just don't do anything.
- return toggleGlobalSearch();
+ if (keyCode == KeyEvent.KEYCODE_SEARCH) {
+ // Consume search key for later use.
+ return true;
}
// if it's an action specified by the searchable activity, launch the
@@ -763,6 +761,29 @@
return false;
}
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (DBG) Log.d(LOG_TAG, "onKeyUp(" + keyCode + "," + event + ")");
+ if (mSearchable == null) {
+ return false;
+ }
+
+ // handle back key to go back to previous searchable, etc.
+ if (handleBackKey(keyCode, event)) {
+ return true;
+ }
+
+ if (keyCode == KeyEvent.KEYCODE_SEARCH && event.isTracking()
+ && !event.isCanceled()) {
+ // If the search key is pressed, toggle between global and in-app search. If we are
+ // currently doing global search and there is no in-app search context to toggle to,
+ // just don't do anything.
+ return toggleGlobalSearch();
+ }
+
+ return false;
+ }
+
/**
* Callback to watch the textedit field for empty/non-empty
*/
@@ -1137,6 +1158,11 @@
String action = mGlobalSearchMode ? Intent.ACTION_WEB_SEARCH : Intent.ACTION_SEARCH;
Intent intent = createIntent(action, null, null, query, null,
actionKey, actionMsg);
+ // Allow GlobalSearch to log and create shortcut for searches launched by
+ // the search button, enter key or an action key.
+ if (mGlobalSearchMode) {
+ mSuggestionsAdapter.reportSearch(query);
+ }
launchIntent(intent);
}
@@ -1495,21 +1521,24 @@
*
* @return <code>true</code> if there was a previous component that we could go back to.
*/
- private boolean backToPreviousComponent() {
+ private boolean backToPreviousComponent(boolean doIt) {
ComponentName previous = popPreviousComponent();
if (previous == null) {
return false;
}
- if (!show(previous, mAppSearchData, false)) {
- Log.w(LOG_TAG, "Failed to switch to source " + previous);
- return false;
- }
- // must touch text to trigger suggestions
- // TODO: should this be the text as it was when the user left
- // the source that we are now going back to?
- String query = mSearchAutoComplete.getText().toString();
- setUserQuery(query);
+ if (doIt) {
+ if (!show(previous, mAppSearchData, false)) {
+ Log.w(LOG_TAG, "Failed to switch to source " + previous);
+ return false;
+ }
+
+ // must touch text to trigger suggestions
+ // TODO: should this be the text as it was when the user left
+ // the source that we are now going back to?
+ String query = mSearchAutoComplete.getText().toString();
+ setUserQuery(query);
+ }
return true;
}
@@ -1655,6 +1684,7 @@
public static class SearchAutoComplete extends AutoCompleteTextView {
private int mThreshold;
+ private int mLastKeyDown;
private SearchDialog mSearchDialog;
public SearchAutoComplete(Context context) {
@@ -1735,27 +1765,44 @@
*/
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+ mLastKeyDown = keyCode;
if (mSearchDialog.mSearchable == null) {
return false;
}
- if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
- if (mSearchDialog.backToPreviousComponent()) {
- return true;
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN
+ && event.getRepeatCount() == 0) {
+ // We releae the back key, might we want to do
+ // something before the IME?
+ if (mSearchDialog.backToPreviousComponent(false)) {
+ return true;
+ }
+ if (isInputMethodNotNeeded() ||
+ (isEmpty() && getDropDownChildCount() >= getAdapterCount())) {
+ return true;
+ }
+ mLastKeyDown = 0;
+ return false; // will dismiss soft keyboard if necessary
+ } else if (event.getAction() == KeyEvent.ACTION_UP
+ && mLastKeyDown == keyCode && !event.isCanceled()) {
+ if (mSearchDialog.backToPreviousComponent(true)) {
+ return true;
+ }
+ // If the drop-down obscures the keyboard, the user wouldn't see anything
+ // happening when pressing back, so we dismiss the entire dialog instead.
+ //
+ // also: if there is no text entered, we also want to dismiss the whole dialog,
+ // not just the soft keyboard. the exception to this is if there are shortcuts
+ // that aren't displayed (e.g are being obscured by the soft keyboard); in that
+ // case we want to dismiss the soft keyboard so the user can see the rest of the
+ // shortcuts.
+ if (isInputMethodNotNeeded() ||
+ (isEmpty() && getDropDownChildCount() >= getAdapterCount())) {
+ mSearchDialog.cancel();
+ return true;
+ }
+ return false; // will dismiss soft keyboard if necessary
}
- // If the drop-down obscures the keyboard, the user wouldn't see anything
- // happening when pressing back, so we dismiss the entire dialog instead.
- //
- // also: if there is no text entered, we also want to dismiss the whole dialog,
- // not just the soft keyboard. the exception to this is if there are shortcuts
- // that aren't displayed (e.g are being obscured by the soft keyboard); in that
- // case we want to dismiss the soft keyboard so the user can see the rest of the
- // shortcuts.
- if (isInputMethodNotNeeded() ||
- (isEmpty() && getDropDownChildCount() >= getAdapterCount())) {
- mSearchDialog.cancel();
- return true;
- }
- return false; // will dismiss soft keyboard if necessary
}
return false;
}
@@ -1767,11 +1814,18 @@
}
protected boolean handleBackKey(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
- if (backToPreviousComponent()) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ // Consume the event, to get an up at which point we execute.
return true;
}
- cancel();
+ if (event.getAction() == KeyEvent.ACTION_UP && event.isTracking()
+ && !event.isCanceled()) {
+ if (backToPreviousComponent(true)) {
+ return true;
+ }
+ cancel();
+ }
return true;
}
return false;
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 267d86a..3a14f6f 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1350,6 +1350,14 @@
* When the threshold received in {@link #POST_REFRESH_RECEIVE_DISPLAY_NOTIFY} is displayed.
*/
public final static int THRESH_HIT = 3;
+
+ /**
+ * When a search is started without using a suggestion.
+ */
+ public final static int SEARCH = 4;
+ public final static String SEARCH_SEND_MAX_DISPLAY_POS
+ = "DialogCursorProtocol.SEARCH.sendDisplayPosition";
+ public final static String SEARCH_SEND_QUERY = "DialogCursorProtocol.SEARCH.query";
}
/**
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 90f8c50..8f7e8ca 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -290,7 +290,7 @@
*/
void callCursorOnClick(Cursor cursor, int position) {
if (!mGlobalSearchMode) return;
- final Bundle request = new Bundle(1);
+ final Bundle request = new Bundle(3);
request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.CLICK);
request.putInt(DialogCursorProtocol.CLICK_SEND_POSITION, position);
request.putInt(DialogCursorProtocol.CLICK_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
@@ -301,6 +301,23 @@
}
/**
+ * Tell the cursor that a search was started without using a suggestion.
+ *
+ * @param query The search query.
+ */
+ void reportSearch(String query) {
+ if (!mGlobalSearchMode) return;
+ Cursor cursor = getCursor();
+ if (cursor == null) return;
+ final Bundle request = new Bundle(3);
+ request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.SEARCH);
+ request.putString(DialogCursorProtocol.SEARCH_SEND_QUERY, query);
+ request.putInt(DialogCursorProtocol.SEARCH_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
+ // the response is always empty
+ cursor.respond(request);
+ }
+
+ /**
* Tags the view with cached child view look-ups.
*/
@Override
@@ -378,7 +395,7 @@
Drawable.ConstantState cachedBg = mBackgroundsCache.get(backgroundColor);
if (cachedBg != null) {
if (DBG) Log.d(LOG_TAG, "Background cache hit for color " + backgroundColor);
- return cachedBg.newDrawable();
+ return cachedBg.newDrawable(mProviderContext.getResources());
}
if (DBG) Log.d(LOG_TAG, "Creating new background for color " + backgroundColor);
ColorDrawable transparent = new ColorDrawable(0);
@@ -555,7 +572,7 @@
Drawable.ConstantState cached = mOutsideDrawablesCache.get(drawableId);
if (cached != null) {
if (DBG) Log.d(LOG_TAG, "Found icon in cache: " + drawableId);
- return cached.newDrawable();
+ return cached.newDrawable(mProviderContext.getResources());
}
Drawable drawable = null;
@@ -646,7 +663,7 @@
// Using containsKey() since we also store null values.
if (mOutsideDrawablesCache.containsKey(componentIconKey)) {
Drawable.ConstantState cached = mOutsideDrawablesCache.get(componentIconKey);
- return cached == null ? null : cached.newDrawable();
+ return cached == null ? null : cached.newDrawable(mProviderContext.getResources());
}
// Then try the activity or application icon
Drawable drawable = getActivityIcon(component);
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index da40c8a..38cac87 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -22,7 +22,9 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
+import android.graphics.ColorFilter;
import android.graphics.Paint;
+import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -56,9 +58,96 @@
private final Context mContext;
+ /**
+ * Special drawable that draws a wallpaper as fast as possible. Assumes
+ * no scaling or placement off (0,0) of the wallpaper (this should be done
+ * at the time the bitmap is loaded).
+ */
+ static class FastBitmapDrawable extends Drawable {
+ private final Bitmap mBitmap;
+ private final int mWidth;
+ private final int mHeight;
+ private int mDrawLeft;
+ private int mDrawTop;
+
+ private FastBitmapDrawable(Bitmap bitmap) {
+ mBitmap = bitmap;
+ mWidth = bitmap.getWidth();
+ mHeight = bitmap.getHeight();
+ setBounds(0, 0, mWidth, mHeight);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ canvas.drawBitmap(mBitmap, mDrawLeft, mDrawTop, null);
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.OPAQUE;
+ }
+
+ @Override
+ public void setBounds(int left, int top, int right, int bottom) {
+ mDrawLeft = left + (right-left - mWidth) / 2;
+ mDrawTop = top + (bottom-top - mHeight) / 2;
+ }
+
+ @Override
+ public void setBounds(Rect bounds) {
+ // TODO Auto-generated method stub
+ super.setBounds(bounds);
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ throw new UnsupportedOperationException(
+ "Not supported with this drawable");
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ throw new UnsupportedOperationException(
+ "Not supported with this drawable");
+ }
+
+ @Override
+ public void setDither(boolean dither) {
+ throw new UnsupportedOperationException(
+ "Not supported with this drawable");
+ }
+
+ @Override
+ public void setFilterBitmap(boolean filter) {
+ throw new UnsupportedOperationException(
+ "Not supported with this drawable");
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mHeight;
+ }
+
+ @Override
+ public int getMinimumWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getMinimumHeight() {
+ return mHeight;
+ }
+ }
+
static class Globals extends IWallpaperManagerCallback.Stub {
private IWallpaperManager mService;
private Bitmap mWallpaper;
+ private Bitmap mDefaultWallpaper;
private static final int MSG_CLEAR_WALLPAPER = 1;
@@ -74,6 +163,7 @@
case MSG_CLEAR_WALLPAPER:
synchronized (this) {
mWallpaper = null;
+ mDefaultWallpaper = null;
}
break;
}
@@ -90,12 +180,19 @@
mHandler.sendEmptyMessage(MSG_CLEAR_WALLPAPER);
}
- public Bitmap peekWallpaperBitmap(Context context) {
+ public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
synchronized (this) {
if (mWallpaper != null) {
return mWallpaper;
}
+ if (mDefaultWallpaper != null) {
+ return mDefaultWallpaper;
+ }
mWallpaper = getCurrentWallpaperLocked(context);
+ if (mWallpaper == null && returnDefault) {
+ mDefaultWallpaper = getDefaultWallpaperLocked(context);
+ return mDefaultWallpaper;
+ }
return mWallpaper;
}
}
@@ -134,48 +231,48 @@
fd.close();
} catch (IOException e) {
}
- if (bm == null) {
+
+ return generateBitmap(context, bm, width, height);
+ }
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
+ private Bitmap getDefaultWallpaperLocked(Context context) {
+ try {
+ InputStream is = context.getResources().openRawResource(
+ com.android.internal.R.drawable.default_wallpaper);
+ if (is != null) {
+ int width = mService.getWidthHint();
+ int height = mService.getHeightHint();
+
+ if (width <= 0 || height <= 0) {
+ // Degenerate case: no size requested, just load
+ // bitmap as-is.
+ Bitmap bm = BitmapFactory.decodeStream(is, null, null);
+ try {
+ is.close();
+ } catch (IOException e) {
+ }
+ if (bm != null) {
+ bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+ }
return bm;
}
- bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
- // This is the final bitmap we want to return.
- Bitmap newbm = Bitmap.createBitmap(width, height,
- bm.getConfig());
- newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
- Canvas c = new Canvas(newbm);
- c.setDensity(DisplayMetrics.DENSITY_DEVICE);
- Rect targetRect = new Rect();
- targetRect.left = targetRect.top = 0;
- targetRect.right = bm.getWidth();
- targetRect.bottom = bm.getHeight();
-
- int deltaw = width - targetRect.right;
- int deltah = height - targetRect.bottom;
-
- if (deltaw > 0 || deltah > 0) {
- // We need to scale up so it covers the entire
- // area.
- float scale = 1.0f;
- if (deltaw > deltah) {
- scale = width / (float)targetRect.right;
- } else {
- scale = height / (float)targetRect.bottom;
- }
- targetRect.right = (int)(targetRect.right*scale);
- targetRect.bottom = (int)(targetRect.bottom*scale);
- deltaw = width - targetRect.right;
- deltah = height - targetRect.bottom;
+ // Load the bitmap with full color depth, to preserve
+ // quality for later processing.
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inDither = false;
+ options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ Bitmap bm = BitmapFactory.decodeStream(is, null, options);
+ try {
+ is.close();
+ } catch (IOException e) {
}
- targetRect.offset(deltaw/2, deltah/2);
- Paint paint = new Paint();
- paint.setFilterBitmap(true);
- paint.setDither(true);
- c.drawBitmap(bm, null, targetRect, paint);
-
- bm.recycle();
- return newbm;
+ return generateBitmap(context, bm, width, height);
}
} catch (RemoteException e) {
}
@@ -219,9 +316,13 @@
* @return Returns a Drawable object that will draw the wallpaper.
*/
public Drawable getDrawable() {
- Drawable dr = peekDrawable();
- return dr != null ? dr : Resources.getSystem().getDrawable(
- com.android.internal.R.drawable.default_wallpaper);
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);
+ if (bm != null) {
+ Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
+ dr.setDither(false);
+ return dr;
+ }
+ return null;
}
/**
@@ -234,8 +335,51 @@
* null pointer if these is none.
*/
public Drawable peekDrawable() {
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext);
- return bm != null ? new BitmapDrawable(mContext.getResources(), bm) : null;
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
+ if (bm != null) {
+ Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
+ dr.setDither(false);
+ return dr;
+ }
+ return null;
+ }
+
+ /**
+ * Like {@link #peekFastDrawable}, but always returns a valid Drawable. If
+ * no wallpaper is set, the system default wallpaper is returned.
+ *
+ * @return Returns a Drawable object that will draw the wallpaper.
+ */
+ public Drawable getFastDrawable() {
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);
+ if (bm != null) {
+ Drawable dr = new FastBitmapDrawable(bm);
+ return dr;
+ }
+ return null;
+ }
+
+ /**
+ * Like {@link #peekDrawable()}, but the returned Drawable has a number
+ * of limitations to reduce its overhead as much as possible: it will
+ * never scale the wallpaper (only centering it if the requested bounds
+ * do match the bitmap bounds, which should not be typical), doesn't
+ * allow setting an alpha, color filter, or other attributes, etc. The
+ * bounds of the returned drawable will be initialized to the same bounds
+ * as the wallpaper, so normally you will not need to touch it. The
+ * drawable also assumes that it will be used in a context running in
+ * the same density as the screen (not in density compatibility mode).
+ *
+ * @return Returns an optimized Drawable object that will draw the
+ * wallpaper or a null pointer if these is none.
+ */
+ public Drawable peekFastDrawable() {
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
+ if (bm != null) {
+ Drawable dr = new FastBitmapDrawable(bm);
+ return dr;
+ }
+ return null;
}
/**
@@ -429,8 +573,10 @@
*/
public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
try {
+ //Log.v(TAG, "Sending new wallpaper offsets from app...");
ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
windowToken, xOffset, yOffset);
+ //Log.v(TAG, "...app returning after sending offsets!");
} catch (RemoteException e) {
// Ignore.
}
@@ -466,4 +612,51 @@
public void clear() throws IOException {
setResource(com.android.internal.R.drawable.default_wallpaper);
}
+
+ static Bitmap generateBitmap(Context context, Bitmap bm, int width, int height) {
+ if (bm == null) {
+ return bm;
+ }
+ bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+
+ // This is the final bitmap we want to return.
+ // XXX We should get the pixel depth from the system (to match the
+ // physical display depth), when there is a way.
+ Bitmap newbm = Bitmap.createBitmap(width, height,
+ Bitmap.Config.RGB_565);
+ newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+ Canvas c = new Canvas(newbm);
+ c.setDensity(DisplayMetrics.DENSITY_DEVICE);
+ Rect targetRect = new Rect();
+ targetRect.left = targetRect.top = 0;
+ targetRect.right = bm.getWidth();
+ targetRect.bottom = bm.getHeight();
+
+ int deltaw = width - targetRect.right;
+ int deltah = height - targetRect.bottom;
+
+ if (deltaw > 0 || deltah > 0) {
+ // We need to scale up so it covers the entire
+ // area.
+ float scale = 1.0f;
+ if (deltaw > deltah) {
+ scale = width / (float)targetRect.right;
+ } else {
+ scale = height / (float)targetRect.bottom;
+ }
+ targetRect.right = (int)(targetRect.right*scale);
+ targetRect.bottom = (int)(targetRect.bottom*scale);
+ deltaw = width - targetRect.right;
+ deltah = height - targetRect.bottom;
+ }
+
+ targetRect.offset(deltaw/2, deltah/2);
+ Paint paint = new Paint();
+ paint.setFilterBitmap(true);
+ paint.setDither(true);
+ c.drawBitmap(bm, null, targetRect, paint);
+
+ bm.recycle();
+ return newbm;
+ }
}
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 6d27bc7..1e590f0 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -87,13 +87,37 @@
private static final long MILLIS_IN_4WEEKS = MILLIS_IN_WEEK * 4;
/** Delay a sync due to local changes this long. In milliseconds */
- private static final long LOCAL_SYNC_DELAY = 30 * 1000; // 30 seconds
+ private static final long LOCAL_SYNC_DELAY;
/**
* If a sync takes longer than this and the sync queue is not empty then we will
* cancel it and add it back to the end of the sync queue. In milliseconds.
*/
- private static final long MAX_TIME_PER_SYNC = 5 * 60 * 1000; // 5 minutes
+ private static final long MAX_TIME_PER_SYNC;
+
+ static {
+ String localSyncDelayString = SystemProperties.get("sync.local_sync_delay");
+ long localSyncDelay = 30 * 1000; // 30 seconds
+ if (localSyncDelayString != null) {
+ try {
+ localSyncDelay = Long.parseLong(localSyncDelayString);
+ } catch (NumberFormatException nfe) {
+ // ignore, use default
+ }
+ }
+ LOCAL_SYNC_DELAY = localSyncDelay;
+
+ String maxTimePerSyncString = SystemProperties.get("sync.max_time_per_sync");
+ long maxTimePerSync = 5 * 60 * 1000; // 5 minutes
+ if (maxTimePerSyncString != null) {
+ try {
+ maxTimePerSync = Long.parseLong(maxTimePerSyncString);
+ } catch (NumberFormatException nfe) {
+ // ignore, use default
+ }
+ }
+ MAX_TIME_PER_SYNC = maxTimePerSync;
+ }
private static final long SYNC_NOTIFICATION_DELAY = 30 * 1000; // 30 seconds
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ba5c9ed..3796201 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -22,8 +22,6 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import android.content.pm.ApplicationInfo;
-import android.graphics.BitmapFactory;
import android.graphics.Movie;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ColorDrawable;
@@ -1664,7 +1662,7 @@
Drawable.ConstantState cs = sPreloadedDrawables.get(key);
if (cs != null) {
- dr = cs.newDrawable();
+ dr = cs.newDrawable(this);
} else {
if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
@@ -1699,7 +1697,7 @@
} else {
try {
InputStream is = mAssets.openNonAsset(
- value.assetCookie, file, AssetManager.ACCESS_BUFFER);
+ value.assetCookie, file, AssetManager.ACCESS_STREAMING);
// System.out.println("Opened file " + file + ": " + is);
dr = Drawable.createFromResourceStream(this, value, is,
file, null);
@@ -1745,7 +1743,7 @@
//Log.i(TAG, "Returning cached drawable @ #" +
// Integer.toHexString(((Integer)key).intValue())
// + " in " + this + ": " + entry);
- return entry.newDrawable();
+ return entry.newDrawable(this);
}
else { // our entry has been purged
mDrawableCache.delete(key);
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index eedcc35..3619653 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -45,6 +45,9 @@
implements KeyEvent.Callback {
private InputMethod mInputMethod;
+ final KeyEvent.DispatcherState mDispatcherState
+ = new KeyEvent.DispatcherState();
+
/**
* Base class for derived classes to implement their {@link InputMethod}
* interface. This takes care of basic maintenance of the input method,
@@ -129,7 +132,8 @@
* callbacks on the service, and tell the client when this is done.
*/
public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) {
- boolean handled = event.dispatch(AbstractInputMethodService.this);
+ boolean handled = event.dispatch(AbstractInputMethodService.this,
+ mDispatcherState, this);
if (callback != null) {
callback.finishedEvent(seq, handled);
}
@@ -148,6 +152,16 @@
}
/**
+ * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState}
+ * for used for processing events from the target application.
+ * Normally you will not need to use this directly, but
+ * just use the standard high-level event callbacks like {@link #onKeyDown}.
+ */
+ public KeyEvent.DispatcherState getKeyDispatcherState() {
+ return mDispatcherState;
+ }
+
+ /**
* Called by the framework during initialization, when the InputMethod
* interface for this service needs to be created.
*/
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 1f640ea..5499bba 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -554,7 +554,7 @@
mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
mInflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
- mWindow = new SoftInputWindow(this, mTheme);
+ mWindow = new SoftInputWindow(this, mTheme, mDispatcherState);
initViews();
mWindow.getWindow().setLayout(FILL_PARENT, WRAP_CONTENT);
}
@@ -1557,6 +1557,28 @@
mImm.showSoftInputFromInputMethod(mToken, flags);
}
+ private boolean handleBack(boolean doIt) {
+ if (mShowInputRequested) {
+ // If the soft input area is shown, back closes it and we
+ // consume the back key.
+ if (doIt) requestHideSelf(0);
+ return true;
+ } else if (mWindowVisible) {
+ if (mCandidatesVisibility == View.VISIBLE) {
+ // If we are showing candidates even if no input area, then
+ // hide them.
+ if (doIt) setCandidatesViewShown(false);
+ } else {
+ // If we have the window visible for some other reason --
+ // most likely to show candidates -- then just get rid
+ // of it. This really shouldn't happen, but just in case...
+ if (doIt) hideWindow();
+ }
+ return true;
+ }
+ return false;
+ }
+
/**
* Override this to intercept key down events before they are processed by the
* application. If you return true, the application will not itself
@@ -1564,38 +1586,33 @@
* will occur as if the IME had not seen the event at all.
*
* <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
- * KeyEvent.KEYCODE_BACK} to hide the current IME UI if it is shown. In
- * additional, in fullscreen mode only, it will consume DPAD movement
+ * KeyEvent.KEYCODE_BACK} if the IME is currently shown, to
+ * possibly hide it when the key goes up (if not canceled or long pressed). In
+ * addition, in fullscreen mode only, it will consume DPAD movement
* events to move the cursor in the extracted text view, not allowing
* them to perform navigation in the underlying application.
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
- && event.getRepeatCount() == 0) {
- if (mShowInputRequested) {
- // If the soft input area is shown, back closes it and we
- // consume the back key.
- requestHideSelf(0);
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ if (handleBack(false)) {
+ event.startTracking();
return true;
- } else if (mWindowVisible) {
- if (mCandidatesVisibility == View.VISIBLE) {
- // If we are showing candidates even if no input area, then
- // hide them.
- setCandidatesViewShown(false);
- return true;
- } else {
- // If we have the window visible for some other reason --
- // most likely to show candidates -- then just get rid
- // of it. This really shouldn't happen, but just in case...
- hideWindow();
- return true;
- }
}
+ return false;
}
return doMovementKey(keyCode, event, MOVEMENT_DOWN);
}
/**
+ * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
+ * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
+ * the event).
+ */
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ /**
* Override this to intercept special key multiple events before they are
* processed by the
* application. If you return true, the application will not itself
@@ -1617,12 +1634,18 @@
* process the event. If you return true, the normal application processing
* will occur as if the IME had not seen the event at all.
*
- * <p>The default implementation always returns false, except when
- * in fullscreen mode, where it will consume DPAD movement
+ * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
+ * KeyEvent.KEYCODE_BACK} to hide the current IME UI if it is shown. In
+ * addition, in fullscreen mode only, it will consume DPAD movement
* events to move the cursor in the extracted text view, not allowing
* them to perform navigation in the underlying application.
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.isTracking()
+ && !event.isCanceled()) {
+ return handleBack(true);
+ }
+
return doMovementKey(keyCode, event, MOVEMENT_UP);
}
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index d91ace6..6a54846 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -21,6 +21,7 @@
import android.content.pm.ActivityInfo;
import android.os.IBinder;
import android.view.Gravity;
+import android.view.KeyEvent;
import android.view.WindowManager;
/**
@@ -30,7 +31,8 @@
* always visible.
*/
class SoftInputWindow extends Dialog {
-
+ final KeyEvent.DispatcherState mDispatcherState;
+
public void setToken(IBinder token) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.token = token;
@@ -49,11 +51,19 @@
* using styles. This theme is applied on top of the current theme in
* <var>context</var>. If 0, the default dialog theme will be used.
*/
- public SoftInputWindow(Context context, int theme) {
+ public SoftInputWindow(Context context, int theme,
+ KeyEvent.DispatcherState dispatcherState) {
super(context, theme);
+ mDispatcherState = dispatcherState;
initDockWindow();
}
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ mDispatcherState.reset();
+ }
+
/**
* Get the size of the DockWindow.
*
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
index 0ce86db..65301e4 100644
--- a/core/java/android/os/HandlerThread.java
+++ b/core/java/android/os/HandlerThread.java
@@ -64,7 +64,7 @@
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
- * has been started, this method will blocked until the looper has been initialized.
+ * has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
@@ -85,6 +85,21 @@
}
/**
+ * Ask the currently running looper to quit. If the thread has not
+ * been started or has finished (that is if {@link #getLooper} returns
+ * null), then false is returned. Otherwise the looper is asked to
+ * quit and true is returned.
+ */
+ public boolean quit() {
+ Looper looper = getLooper();
+ if (looper != null) {
+ looper.quit();
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 6ce0f5f..78e2c27 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -399,7 +399,7 @@
// Electronics, Flaircomm Electronics, Jatty Electronics, Delphi,
// Clarion, Novero, Denso (Lexus, Toyota), Johnson Controls (Acura),
// Continental Automotive, Harman/Becker
- private final ArrayList<String> mAutoPairingBlacklisted =
+ private final ArrayList<String> mAutoPairingAddressBlacklist =
new ArrayList<String>(Arrays.asList(
"00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", "00:21:4F",
"00:23:06", "00:24:33", "00:A0:79", "00:0E:6D", "00:13:E0", "00:21:E8",
@@ -408,6 +408,12 @@
"00:0A:30", "00:1E:AE", "00:1C:D7"
));
+ // List of names of Bluetooth devices for which auto pairing should be
+ // disabled.
+ private final ArrayList<String> mAutoPairingNameBlacklist =
+ new ArrayList<String>(Arrays.asList(
+ "Motorola IHF1000", "i.TechBlueBAND", "X5 Stereo v1.3"));
+
public synchronized void loadBondState() {
if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) {
return;
@@ -460,9 +466,16 @@
}
public boolean isAutoPairingBlacklisted(String address) {
- for (String blacklistAddress : mAutoPairingBlacklisted) {
+ for (String blacklistAddress : mAutoPairingAddressBlacklist) {
if (address.startsWith(blacklistAddress)) return true;
}
+
+ String name = getRemoteName(address);
+ if (name != null) {
+ for (String blacklistName : mAutoPairingNameBlacklist) {
+ if (name.equals(blacklistName)) return true;
+ }
+ }
return false;
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index e5659d5..cd5cf10 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -28,9 +28,11 @@
import android.content.IntentFilter;
import android.graphics.Rect;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
+import android.util.LogPrinter;
import android.view.Gravity;
import android.view.IWindowSession;
import android.view.MotionEvent;
@@ -74,6 +76,8 @@
private static final int MSG_WINDOW_RESIZED = 10030;
private static final int MSG_TOUCH_EVENT = 10040;
+ private Looper mCallbackLooper;
+
/**
* The actual implementation of a wallpaper. A wallpaper service may
* have multiple instances running (for example as a real wallpaper
@@ -120,6 +124,7 @@
boolean mOffsetMessageEnqueued;
float mPendingXOffset;
float mPendingYOffset;
+ boolean mPendingSync;
MotionEvent mPendingMove;
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -212,10 +217,14 @@
}
@Override
- public void dispatchWallpaperOffsets(float x, float y) {
+ public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
synchronized (mLock) {
+ if (DEBUG) Log.v(TAG, "Dispatch wallpaper offsets: " + x + ", " + y);
mPendingXOffset = x;
mPendingYOffset = y;
+ if (sync) {
+ mPendingSync = true;
+ }
if (!mOffsetMessageEnqueued) {
mOffsetMessageEnqueued = true;
Message msg = mCaller.obtainMessage(MSG_WALLPAPER_OFFSETS);
@@ -551,9 +560,12 @@
float xOffset;
float yOffset;
+ boolean sync;
synchronized (mLock) {
xOffset = mPendingXOffset;
yOffset = mPendingYOffset;
+ sync = mPendingSync;
+ mPendingSync = false;
mOffsetMessageEnqueued = false;
}
if (DEBUG) Log.v(TAG, "Offsets change in " + this
@@ -563,6 +575,14 @@
final int availh = mIWallpaperEngine.mReqHeight-mCurHeight;
final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0;
onOffsetsChanged(xOffset, yOffset, xPixels, yPixels);
+
+ if (sync) {
+ try {
+ if (DEBUG) Log.v(TAG, "Reporting offsets change complete");
+ mSession.wallpaperOffsetsComplete(mWindow.asBinder());
+ } catch (RemoteException e) {
+ }
+ }
}
void detach() {
@@ -622,7 +642,13 @@
IWallpaperEngineWrapper(WallpaperService context,
IWallpaperConnection conn, IBinder windowToken,
int windowType, boolean isPreview, int reqWidth, int reqHeight) {
- mCaller = new HandlerCaller(context, this);
+ if (DEBUG && mCallbackLooper != null) {
+ mCallbackLooper.setMessageLogging(new LogPrinter(Log.VERBOSE, TAG));
+ }
+ mCaller = new HandlerCaller(context,
+ mCallbackLooper != null
+ ? mCallbackLooper : context.getMainLooper(),
+ this);
mConnection = conn;
mWindowToken = windowToken;
mWindowType = windowType;
@@ -736,5 +762,18 @@
return new IWallpaperServiceWrapper(this);
}
+ /**
+ * This allows subclasses to change the thread that most callbacks
+ * occur on. Currently hidden because it is mostly needed for the
+ * image wallpaper (which runs in the system process and doesn't want
+ * to get stuck running on that seriously in use main thread). Not
+ * exposed right now because the semantics of this are not totally
+ * well defined and some callbacks can still happen on the main thread).
+ * @hide
+ */
+ public void setCallbackLooper(Looper looper) {
+ mCallbackLooper = looper;
+ }
+
public abstract Engine onCreateEngine();
}
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index d61e888..ce25c47 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -208,7 +208,7 @@
if ((mask & WEB_URLS) != 0) {
gatherLinks(links, text, Regex.WEB_URL_PATTERN,
- new String[] { "http://", "https://" },
+ new String[] { "http://", "https://", "rtsp://" },
sUrlMatchFilter, null);
}
diff --git a/core/java/android/text/util/Regex.java b/core/java/android/text/util/Regex.java
index a349b82..a6844a4 100644
--- a/core/java/android/text/util/Regex.java
+++ b/core/java/android/text/util/Regex.java
@@ -65,7 +65,7 @@
*/
public static final Pattern WEB_URL_PATTERN
= Pattern.compile(
- "((?:(http|https|Http|Https):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+ "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+ "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+ "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
+ "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+" // named host
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index ebc5f7b..b7953af 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -60,5 +60,5 @@
/**
* Called for wallpaper windows when their offsets change.
*/
- void dispatchWallpaperOffsets(float x, float y);
+ void dispatchWallpaperOffsets(float x, float y, boolean sync);
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 4d662d2..9b8b6d4 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -114,4 +114,6 @@
* larger than the screen, set the offset within the screen.
*/
void setWallpaperPosition(IBinder windowToken, float x, float y);
+
+ void wallpaperOffsetsComplete(IBinder window);
}
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index f9b16fc..daa4b29 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -18,6 +18,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.SparseIntArray;
import android.view.KeyCharacterMap;
import android.view.KeyCharacterMap.KeyData;
@@ -277,6 +278,32 @@
public static final int FLAG_VIRTUAL_HARD_KEY = 0x40;
/**
+ * This flag is set for the first key repeat that occurs after the
+ * long press timeout.
+ */
+ public static final int FLAG_LONG_PRESS = 0x80;
+
+ /**
+ * Set when a key event has {@link #FLAG_CANCELED} set because a long
+ * press action was executed while it was down.
+ */
+ public static final int FLAG_CANCELED_LONG_PRESS = 0x100;
+
+ /**
+ * Set for {@link #ACTION_UP} when this event's key code is still being
+ * tracked from its initial down. That is, somebody requested that tracking
+ * started on the key down and a long press has not caused
+ * the tracking to be canceled.
+ */
+ public static final int FLAG_TRACKING = 0x200;
+
+ /**
+ * Private control to determine when an app is tracking a key sequence.
+ * @hide
+ */
+ public static final int FLAG_START_TRACKING = 0x40000000;
+
+ /**
* Returns the maximum keycode.
*/
public static int getMaxKeyCode() {
@@ -305,7 +332,11 @@
public interface Callback {
/**
- * Called when a key down event has occurred.
+ * Called when a key down event has occurred. If you return true,
+ * you can first call {@link KeyEvent#startTracking()
+ * KeyEvent.startTracking()} to have the framework track the event
+ * through its {@link #onKeyUp(int, KeyEvent)} and also call your
+ * {@link #onKeyLongPress(int, KeyEvent)} if it occurs.
*
* @param keyCode The value in event.getKeyCode().
* @param event Description of the key event.
@@ -316,6 +347,22 @@
boolean onKeyDown(int keyCode, KeyEvent event);
/**
+ * Called when a long press has occurred. If you return true,
+ * the final key up will have {@link KeyEvent#FLAG_CANCELED} and
+ * {@link KeyEvent#FLAG_CANCELED_LONG_PRESS} set. Note that in
+ * order to receive this callback, someone in the event change
+ * <em>must</em> return true from {@link #onKeyDown} <em>and</em>
+ * call {@link KeyEvent#startTracking()} on the event.
+ *
+ * @param keyCode The value in event.getKeyCode().
+ * @param event Description of the key event.
+ *
+ * @return If you handled the event, return true. If you want to allow
+ * the event to be handled by the next receiver, return false.
+ */
+ boolean onKeyLongPress(int keyCode, KeyEvent event);
+
+ /**
* Called when a key up event has occurred.
*
* @param keyCode The value in event.getKeyCode().
@@ -500,11 +547,15 @@
/**
* Copy an existing key event, modifying its time and repeat count.
*
+ * @deprecated Use {@link #changeTimeRepeat(KeyEvent, long, int)}
+ * instead.
+ *
* @param origEvent The existing event to be copied.
* @param eventTime The new event time
* (in {@link android.os.SystemClock#uptimeMillis}) of the event.
* @param newRepeat The new repeat count of the event.
*/
+ @Deprecated
public KeyEvent(KeyEvent origEvent, long eventTime, int newRepeat) {
mDownTime = origEvent.mDownTime;
mEventTime = eventTime;
@@ -533,6 +584,26 @@
}
/**
+ * Create a new key event that is the same as the given one, but whose
+ * event time and repeat count are replaced with the given value.
+ *
+ * @param event The existing event to be copied. This is not modified.
+ * @param eventTime The new event time
+ * (in {@link android.os.SystemClock#uptimeMillis}) of the event.
+ * @param newRepeat The new repeat count of the event.
+ * @param newFlags New flags for the event, replacing the entire value
+ * in the original event.
+ */
+ public static KeyEvent changeTimeRepeat(KeyEvent event, long eventTime,
+ int newRepeat, int newFlags) {
+ KeyEvent ret = new KeyEvent(event);
+ ret.mEventTime = eventTime;
+ ret.mRepeatCount = newRepeat;
+ ret.mFlags = newFlags;
+ return ret;
+ }
+
+ /**
* Copy an existing key event, modifying its action.
*
* @param origEvent The existing event to be copied.
@@ -721,6 +792,34 @@
}
/**
+ * Call this during {@link Callback#onKeyDown} to have the system track
+ * the key through its final up (possibly including a long press). Note
+ * that only one key can be tracked at a time -- if another key down
+ * event is received while a previous one is being tracked, tracking is
+ * stopped on the previous event.
+ */
+ public final void startTracking() {
+ mFlags |= FLAG_START_TRACKING;
+ }
+
+ /**
+ * For {@link #ACTION_UP} events, indicates that the event is still being
+ * tracked from its initial down event as per
+ * {@link #FLAG_TRACKING}.
+ */
+ public final boolean isTracking() {
+ return (mFlags&FLAG_TRACKING) != 0;
+ }
+
+ /**
+ * For {@link #ACTION_DOWN} events, indicates that the event has been
+ * canceled as per {@link #FLAG_LONG_PRESS}.
+ */
+ public final boolean isLongPress() {
+ return (mFlags&FLAG_LONG_PRESS) != 0;
+ }
+
+ /**
* Retrieve the key code of the key event. This is the physical key that
* was pressed, <em>not</em> the Unicode character.
*
@@ -906,19 +1005,49 @@
}
/**
+ * @deprecated Use {@link #dispatch(Callback, DispatcherState, Object)} instead.
+ */
+ @Deprecated
+ public final boolean dispatch(Callback receiver) {
+ return dispatch(receiver, null, null);
+ }
+
+ /**
* Deliver this key event to a {@link Callback} interface. If this is
* an ACTION_MULTIPLE event and it is not handled, then an attempt will
* be made to deliver a single normal event.
*
* @param receiver The Callback that will be given the event.
+ * @param state State information retained across events.
+ * @param target The target of the dispatch, for use in tracking.
*
* @return The return value from the Callback method that was called.
*/
- public final boolean dispatch(Callback receiver) {
+ public final boolean dispatch(Callback receiver, DispatcherState state,
+ Object target) {
switch (mAction) {
- case ACTION_DOWN:
- return receiver.onKeyDown(mKeyCode, this);
+ case ACTION_DOWN: {
+ mFlags &= ~FLAG_START_TRACKING;
+ boolean res = receiver.onKeyDown(mKeyCode, this);
+ if (state != null) {
+ if (res && mRepeatCount == 0 && (mFlags&FLAG_START_TRACKING) != 0) {
+ state.startTracking(this, target);
+ } else if (isLongPress() && state.isTracking(this)) {
+ try {
+ if (receiver.onKeyLongPress(mKeyCode, this)) {
+ state.performedLongPress(this);
+ res = true;
+ }
+ } catch (AbstractMethodError e) {
+ }
+ }
+ }
+ return res;
+ }
case ACTION_UP:
+ if (state != null) {
+ state.handleUpEvent(this);
+ }
return receiver.onKeyUp(mKeyCode, this);
case ACTION_MULTIPLE:
final int count = mRepeatCount;
@@ -938,10 +1067,97 @@
mRepeatCount = count;
return handled;
}
+ return false;
}
return false;
}
+ /**
+ * Use with {@link KeyEvent#dispatch(Callback, DispatcherState, Object)}
+ * for more advanced key dispatching, such as long presses.
+ */
+ public static class DispatcherState {
+ int mDownKeyCode;
+ Object mDownTarget;
+ SparseIntArray mActiveLongPresses = new SparseIntArray();
+
+ /**
+ * Reset back to initial state.
+ */
+ public void reset() {
+ mDownKeyCode = 0;
+ mDownTarget = null;
+ mActiveLongPresses.clear();
+ }
+
+ /**
+ * Stop any tracking associated with this target.
+ */
+ public void reset(Object target) {
+ if (mDownTarget == target) {
+ mDownKeyCode = 0;
+ mDownTarget = null;
+ }
+ }
+
+ /**
+ * Start tracking the key code associated with the given event. This
+ * can only be called on a key down. It will allow you to see any
+ * long press associated with the key, and will result in
+ * {@link KeyEvent#isTracking} return true on the long press and up
+ * events.
+ *
+ * <p>This is only needed if you are directly dispatching events, rather
+ * than handling them in {@link Callback#onKeyDown}.
+ */
+ public void startTracking(KeyEvent event, Object target) {
+ if (event.getAction() != ACTION_DOWN) {
+ throw new IllegalArgumentException(
+ "Can only start tracking on a down event");
+ }
+ mDownKeyCode = event.getKeyCode();
+ mDownTarget = target;
+ }
+
+ /**
+ * Return true if the key event is for a key code that is currently
+ * being tracked by the dispatcher.
+ */
+ public boolean isTracking(KeyEvent event) {
+ return mDownKeyCode == event.getKeyCode();
+ }
+
+ /**
+ * Keep track of the given event's key code as having performed an
+ * action with a long press, so no action should occur on the up.
+ * <p>This is only needed if you are directly dispatching events, rather
+ * than handling them in {@link Callback#onKeyLongPress}.
+ */
+ public void performedLongPress(KeyEvent event) {
+ mActiveLongPresses.put(event.getKeyCode(), 1);
+ }
+
+ /**
+ * Handle key up event to stop tracking. This resets the dispatcher state,
+ * and updates the key event state based on it.
+ * <p>This is only needed if you are directly dispatching events, rather
+ * than handling them in {@link Callback#onKeyUp}.
+ */
+ public void handleUpEvent(KeyEvent event) {
+ final int keyCode = event.getKeyCode();
+ int index = mActiveLongPresses.indexOfKey(keyCode);
+ if (index >= 0) {
+ event.mFlags |= FLAG_CANCELED | FLAG_CANCELED_LONG_PRESS;
+ mActiveLongPresses.removeAt(index);
+ }
+ if (mDownKeyCode == keyCode) {
+ event.mFlags |= FLAG_TRACKING;
+ mDownKeyCode = 0;
+ mDownTarget = null;
+ }
+ }
+ }
+
public String toString() {
return "KeyEvent{action=" + mAction + " code=" + mKeyCode
+ " repeat=" + mRepeatCount
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f63c2f1..6ff0fc8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2600,6 +2600,10 @@
if (mOnFocusChangeListener != null) {
mOnFocusChangeListener.onFocusChange(this, gainFocus);
}
+
+ if (mAttachInfo != null) {
+ mAttachInfo.mKeyDispatchState.reset(this);
+ }
}
/**
@@ -3609,6 +3613,16 @@
}
/**
+ * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState}
+ * for this view's window. Returns null if the view is not currently attached
+ * to the window. Normally you will not need to use this directly, but
+ * just use the standard high-level event callbacks like {@link #onKeyDown}.
+ */
+ public KeyEvent.DispatcherState getKeyDispatcherState() {
+ return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null;
+ }
+
+ /**
* Dispatch a key event before it is processed by any input method
* associated with the view hierarchy. This can be used to intercept
* key events in special situations before the IME consumes them; a
@@ -3645,7 +3659,8 @@
return true;
}
- return event.dispatch(this);
+ return event.dispatch(this, mAttachInfo != null
+ ? mAttachInfo.mKeyDispatchState : null, this);
}
/**
@@ -3910,6 +3925,15 @@
}
/**
+ * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
+ * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
+ * the event).
+ */
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ /**
* Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent)
* KeyEvent.Callback.onKeyMultiple()}: perform clicking of the view
* when {@link KeyEvent#KEYCODE_DPAD_CENTER} or
@@ -6042,12 +6066,11 @@
int height = mBottom - mTop;
final AttachInfo attachInfo = mAttachInfo;
- final float scale = attachInfo.mApplicationScale;
+ final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f;
width = (int) ((width * scale) + 0.5f);
height = (int) ((height * scale) + 0.5f);
- Bitmap bitmap = Bitmap.createBitmap(width > 0 ? width : 1,
- height > 0 ? height : 1, quality);
+ Bitmap bitmap = Bitmap.createBitmap(width > 0 ? width : 1, height > 0 ? height : 1, quality);
if (bitmap == null) {
throw new OutOfMemoryError();
}
@@ -8573,6 +8596,9 @@
*/
final ArrayList<View> mScrollContainers = new ArrayList<View>();
+ final KeyEvent.DispatcherState mKeyDispatchState
+ = new KeyEvent.DispatcherState();
+
/**
* Indicates whether the view's window currently has the focus.
*/
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index b61465a..c6937a3 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1812,6 +1812,7 @@
if (hasWindowFocus && imm != null && mLastWasImTarget) {
imm.startGettingWindowFocus(mView);
}
+ mAttachInfo.mKeyDispatchState.reset();
mView.dispatchWindowFocusChanged(hasWindowFocus);
}
@@ -2868,7 +2869,13 @@
}
}
- public void dispatchWallpaperOffsets(float x, float y) {
+ public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
+ if (sync) {
+ try {
+ sWindowSession.wallpaperOffsetsComplete(asBinder());
+ } catch (RemoteException e) {
+ }
+ }
}
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 8446475..2329e21 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -458,8 +458,7 @@
private static final int SWITCH_TO_LONGPRESS = 4;
private static final int RELEASE_SINGLE_TAP = 5;
private static final int REQUEST_FORM_DATA = 6;
- private static final int SWITCH_TO_CLICK = 7;
- private static final int RESUME_WEBCORE_UPDATE = 8;
+ private static final int RESUME_WEBCORE_UPDATE = 7;
//! arg1=x, arg2=y
static final int SCROLL_TO_MSG_ID = 10;
@@ -1395,6 +1394,7 @@
* Reload the current url.
*/
public void reload() {
+ clearTextEntry();
switchOutDrawHistory();
mWebViewCore.sendMessage(EventHub.RELOAD);
}
@@ -2049,12 +2049,9 @@
protected int computeHorizontalScrollRange() {
if (mDrawHistory) {
return mHistoryWidth;
- } else if (mLastWidthSent == mContentWidth) {
- // special case to avoid rounding error. Otherwise we may get a
- // faked scrollbar sometimes.
- return getViewWidth();
} else {
- return contentToViewDimension(mContentWidth);
+ // to avoid rounding error caused unnecessary scrollbar, use floor
+ return (int) Math.floor(mContentWidth * mActualScale);
}
}
@@ -2066,18 +2063,8 @@
if (mDrawHistory) {
return mHistoryHeight;
} else {
- int height;
- // special case to avoid rounding error. Otherwise we may get a
- // faked scrollbar sometimes.
- if (mLastHeightSent == mContentHeight) {
- height = getViewHeight();
- } else {
- height = contentToViewDimension(mContentHeight);
- }
- if (mFindIsUp) {
- height += FIND_HEIGHT;
- }
- return height;
+ // to avoid rounding error caused unnecessary scrollbar, use floor
+ return (int) Math.floor(mContentHeight * mActualScale);
}
}
@@ -3677,16 +3664,27 @@
if (mShiftIsPressed) {
return false;
}
- if (getSettings().supportZoom()
- && mTouchMode == TOUCH_DOUBLECLICK_MODE) {
- zoomScrollOut();
- } else {
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(SWITCH_TO_CLICK), TAP_TIMEOUT);
- if (DebugFlags.WEB_VIEW) {
- Log.v(LOGTAG, "TOUCH_DOUBLECLICK_MODE");
- }
- mTouchMode = TOUCH_DOUBLECLICK_MODE;
+
+ // perform the single click
+ Rect visibleRect = sendOurVisibleRect();
+ // Note that sendOurVisibleRect calls viewToContent, so the
+ // coordinates should be in content coordinates.
+ if (!nativeCursorIntersects(visibleRect)) {
+ return false;
+ }
+ nativeSetFollowedLink(true);
+ nativeUpdatePluginReceivesEvents();
+ WebViewCore.CursorData data = cursorData();
+ mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data);
+ playSoundEffect(SoundEffectConstants.CLICK);
+ boolean isTextInput = nativeCursorIsTextInput();
+ if (isTextInput || !mCallbackProxy.uiOverrideUrlLoading(
+ nativeCursorText())) {
+ mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame,
+ nativeCursorNodePointer());
+ }
+ if (isTextInput) {
+ rebuildWebTextView();
}
return true;
}
@@ -4334,7 +4332,6 @@
return true;
}
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mPrivateHandler.removeMessages(SWITCH_TO_CLICK);
mTrackballDown = true;
if (mNativeClass == 0) {
return false;
@@ -4582,9 +4579,8 @@
}
private int computeMaxScrollY() {
- int maxContentH = contentToViewDimension(mContentHeight)
- + getTitleHeight();
- return Math.max(maxContentH - getHeight(), 0);
+ int maxContentH = computeVerticalScrollRange() + getTitleHeight();
+ return Math.max(maxContentH - getHeight(), getTitleHeight());
}
public void flingScroll(int vx, int vy) {
@@ -4890,6 +4886,9 @@
}
int x = viewToContentX((int) event.getX() + mWebTextView.getLeft());
int y = viewToContentY((int) event.getY() + mWebTextView.getTop());
+ // In case the soft keyboard has been dismissed, bring it back up.
+ InputMethodManager.getInstance(getContext()).showSoftInput(mWebTextView,
+ 0);
nativeTextInputMotionUp(x, y);
}
@@ -5023,8 +5022,8 @@
int measuredWidth = widthSize;
// Grab the content size from WebViewCore.
- int contentHeight = Math.round(mContentHeight * mActualScale);
- int contentWidth = Math.round(mContentWidth * mActualScale);
+ int contentHeight = contentToViewDimension(mContentHeight);
+ int contentWidth = contentToViewDimension(mContentWidth);
// Log.d(LOGTAG, "------- measure " + heightMode);
@@ -5198,32 +5197,6 @@
}
break;
}
- case SWITCH_TO_CLICK:
- // The user clicked with the trackball, and did not click a
- // second time, so perform the action of a trackball single
- // click
- mTouchMode = TOUCH_DONE_MODE;
- Rect visibleRect = sendOurVisibleRect();
- // Note that sendOurVisibleRect calls viewToContent, so the
- // coordinates should be in content coordinates.
- if (!nativeCursorIntersects(visibleRect)) {
- break;
- }
- nativeSetFollowedLink(true);
- nativeUpdatePluginReceivesEvents();
- WebViewCore.CursorData data = cursorData();
- mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data);
- playSoundEffect(SoundEffectConstants.CLICK);
- boolean isTextInput = nativeCursorIsTextInput();
- if (isTextInput || !mCallbackProxy.uiOverrideUrlLoading(
- nativeCursorText())) {
- mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame,
- nativeCursorNodePointer());
- }
- if (isTextInput) {
- rebuildWebTextView();
- }
- break;
case SCROLL_BY_MSG_ID:
setContentScrollBy(msg.arg1, msg.arg2, (Boolean) msg.obj);
break;
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index 4e76254..6e10811 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -39,7 +39,7 @@
// log tag
protected static final String LOGTAG = "webviewdatabase";
- private static final int DATABASE_VERSION = 9;
+ private static final int DATABASE_VERSION = 10;
// 2 -> 3 Modified Cache table to allow cache of redirects
// 3 -> 4 Added Oma-Downloads table
// 4 -> 5 Modified Cache table to support persistent contentLength
@@ -48,6 +48,7 @@
// 6 -> 7 Change cache localPath from int to String
// 7 -> 8 Move cache to its own db
// 8 -> 9 Store both scheme and host when storing passwords
+ // 9 -> 10 Update httpauth table UNIQUE
private static final int CACHE_DATABASE_VERSION = 3;
// 1 -> 2 Add expires String
// 2 -> 3 Add content-disposition
@@ -256,6 +257,20 @@
+ DATABASE_VERSION + ", which will destroy old data");
}
boolean justPasswords = 8 == oldVersion && 9 == DATABASE_VERSION;
+ boolean justAuth = 9 == oldVersion && 10 == DATABASE_VERSION;
+ if (justAuth) {
+ mDatabase.execSQL("DROP TABLE IF EXISTS "
+ + mTableNames[TABLE_HTTPAUTH_ID]);
+ mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_HTTPAUTH_ID]
+ + " (" + ID_COL + " INTEGER PRIMARY KEY, "
+ + HTTPAUTH_HOST_COL + " TEXT, " + HTTPAUTH_REALM_COL
+ + " TEXT, " + HTTPAUTH_USERNAME_COL + " TEXT, "
+ + HTTPAUTH_PASSWORD_COL + " TEXT," + " UNIQUE ("
+ + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL
+ + ") ON CONFLICT REPLACE);");
+ return;
+ }
+
if (!justPasswords) {
mDatabase.execSQL("DROP TABLE IF EXISTS "
+ mTableNames[TABLE_COOKIES_ID]);
@@ -302,8 +317,8 @@
+ HTTPAUTH_HOST_COL + " TEXT, " + HTTPAUTH_REALM_COL
+ " TEXT, " + HTTPAUTH_USERNAME_COL + " TEXT, "
+ HTTPAUTH_PASSWORD_COL + " TEXT," + " UNIQUE ("
- + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL + ", "
- + HTTPAUTH_USERNAME_COL + ") ON CONFLICT REPLACE);");
+ + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL
+ + ") ON CONFLICT REPLACE);");
}
// passwords
mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_PASSWORD_ID]
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 2f292d5..bed2a7a 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2945,10 +2945,14 @@
okToSend = false;
break;
case KeyEvent.KEYCODE_BACK:
- if (mFiltered && mPopup != null && mPopup.isShowing() &&
- event.getAction() == KeyEvent.ACTION_DOWN) {
- handled = true;
- mTextFilter.setText("");
+ if (mFiltered && mPopup != null && mPopup.isShowing()) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ handled = true;
+ } else if (event.getAction() == KeyEvent.ACTION_UP
+ && event.isTracking() && !event.isCanceled()) {
+ handled = true;
+ mTextFilter.setText("");
+ }
}
okToSend = false;
break;
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index d821a7d..7891d3c 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -132,6 +132,8 @@
private AutoCompleteTextView.PassThroughClickListener mPassThroughClickListener;
+ private int mDownKeyCode;
+
public AutoCompleteTextView(Context context) {
this(context, null);
}
@@ -603,12 +605,19 @@
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN
+ && event.getRepeatCount() == 0) {
+ mDownKeyCode = keyCode;
+ }
if (isPopupShowing()) {
// special case for the back key, we do not even try to send it
// to the drop down list but instead, consume it immediately
if (keyCode == KeyEvent.KEYCODE_BACK && !mDropDownAlwaysVisible) {
- dismissDropDown();
- return true;
+ if (event.getAction() == KeyEvent.ACTION_UP
+ && mDownKeyCode == keyCode && !event.isCanceled()) {
+ dismissDropDown();
+ return true;
+ }
}
}
return super.onKeyPreIme(keyCode, event);
@@ -1017,6 +1026,7 @@
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
+ mDownKeyCode = 0;
performValidation();
if (!hasWindowFocus && !mDropDownAlwaysVisible) {
dismissDropDown();
@@ -1026,6 +1036,7 @@
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
+ mDownKeyCode = 0;
performValidation();
if (!focused && !mDropDownAlwaysVisible) {
dismissDropDown();
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index e7b303a..f34823c 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -23,7 +23,6 @@
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.util.Config;
import android.util.Log;
import android.view.GestureDetector;
import android.view.Gravity;
@@ -36,8 +35,6 @@
import android.view.SoundEffectConstants;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.animation.Transformation;
-import android.widget.AbsSpinner;
-import android.widget.Scroller;
/**
* A view that shows items in a center-locked, horizontally scrolling list.
@@ -59,7 +56,7 @@
private static final String TAG = "Gallery";
- private static final boolean localLOGV = Config.LOGV;
+ private static final boolean localLOGV = false;
/**
* Duration in milliseconds from the start of a scroll during which we're
@@ -514,6 +511,7 @@
// We haven't been callbacking during the fling, so do it now
super.selectionChanged();
}
+ invalidate();
}
@Override
@@ -534,12 +532,9 @@
int galleryCenter = getCenterOfGallery();
- if (selView != null) {
-
- // Common case where the current selected position is correct
- if (selView.getLeft() <= galleryCenter && selView.getRight() >= galleryCenter) {
- return;
- }
+ // Common case where the current selected position is correct
+ if (selView.getLeft() <= galleryCenter && selView.getRight() >= galleryCenter) {
+ return;
}
// TODO better search
@@ -627,7 +622,6 @@
View sel = makeAndAddView(mSelectedPosition, 0, 0, true);
// Put the selected child in the center
- Gallery.LayoutParams lp = (Gallery.LayoutParams) sel.getLayoutParams();
int selectedOffset = childrenLeft + (childrenWidth / 2) - (sel.getWidth() / 2);
sel.offsetLeftAndRight(selectedOffset);
@@ -733,9 +727,6 @@
child = mRecycler.get(position);
if (child != null) {
// Can reuse an existing view
- Gallery.LayoutParams lp = (Gallery.LayoutParams)
- child.getLayoutParams();
-
int childLeft = child.getLeft();
// Remember left and right edges of where views have been placed
@@ -798,7 +789,7 @@
int childRight;
// Position vertically based on gravity setting
- int childTop = calculateTop(child, lp, true);
+ int childTop = calculateTop(child, true);
int childBottom = childTop + child.getMeasuredHeight();
int width = child.getMeasuredWidth();
@@ -817,11 +808,9 @@
* Figure out vertical placement based on mGravity
*
* @param child Child to place
- * @param lp LayoutParams for this view (just so we don't keep looking them
- * up)
* @return Where the top of the child should be
*/
- private int calculateTop(View child, Gallery.LayoutParams lp, boolean duringLayout) {
+ private int calculateTop(View child, boolean duringLayout) {
int myHeight = duringLayout ? mMeasuredHeight : getHeight();
int childHeight = duringLayout ? child.getMeasuredHeight() : child.getHeight();
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index 5825024..35b9251 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -57,6 +57,13 @@
mCallback = callback;
}
+ public HandlerCaller(Context context, Looper looper, Callback callback) {
+ mContext = context;
+ mMainLooper = looper;
+ mH = new MyHandler(mMainLooper);
+ mCallback = callback;
+ }
+
public SomeArgs obtainArgs() {
synchronized (mH) {
SomeArgs args = mArgsPool;
diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
index 5357469..0bc70de 100644
--- a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -20,6 +20,8 @@
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.HandlerThread;
+import android.os.Process;
import android.service.wallpaper.WallpaperService;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
@@ -33,20 +35,29 @@
*/
public class ImageWallpaper extends WallpaperService {
WallpaperManager mWallpaperManager;
+ private HandlerThread mThread;
@Override
public void onCreate() {
super.onCreate();
mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
+ mThread = new HandlerThread("Wallpaper", Process.THREAD_PRIORITY_FOREGROUND);
+ mThread.start();
+ setCallbackLooper(mThread.getLooper());
}
public Engine onCreateEngine() {
return new DrawableEngine();
}
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mThread.quit();
+ }
+
class DrawableEngine extends Engine {
private final Object mLock = new Object();
- private final Rect mBounds = new Rect();
private WallpaperObserver mReceiver;
Drawable mBackground;
float mXOffset;
@@ -56,6 +67,9 @@
public void onReceive(Context context, Intent intent) {
updateWallpaper();
drawFrame();
+ // Assume we are the only one using the wallpaper in this
+ // process, and force a GC now to release the old wallpaper.
+ System.gc();
}
}
@@ -67,7 +81,6 @@
registerReceiver(mReceiver, filter);
updateWallpaper();
surfaceHolder.setSizeFromLayout();
- //setTouchEventsEnabled(true);
}
@Override
@@ -137,11 +150,7 @@
void updateWallpaper() {
synchronized (mLock) {
- mBackground = mWallpaperManager.getDrawable();
- mBounds.left = mBounds.top = 0;
- mBounds.right = mBackground.getIntrinsicWidth();
- mBounds.bottom = mBackground.getIntrinsicHeight();
- mBackground.setBounds(mBounds);
+ mBackground = mWallpaperManager.getFastDrawable();
}
}
}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index f4f6297..b8d19ac 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -90,6 +90,12 @@
public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
}
- public void dispatchWallpaperOffsets(float x, float y) {
+ public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
+ if (sync) {
+ try {
+ mSession.wallpaperOffsetsComplete(asBinder());
+ } catch (RemoteException e) {
+ }
+ }
}
}
diff --git a/core/java/com/android/internal/view/menu/IconMenuView.java b/core/java/com/android/internal/view/menu/IconMenuView.java
index b81c2b3..bba2ee2 100644
--- a/core/java/com/android/internal/view/menu/IconMenuView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuView.java
@@ -282,7 +282,9 @@
itemView.setIconMenuView(this);
// Apply the background to the item view
- itemView.setBackgroundDrawable(mItemBackground.getConstantState().newDrawable());
+ itemView.setBackgroundDrawable(
+ mItemBackground.getConstantState().newDrawable(
+ getContext().getResources()));
// This class is the invoker for all its item views
itemView.setItemInvoker(this);
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 7748aba..5b6c7ea 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -32,6 +32,7 @@
#include <sys/errno.h>
#include <sys/resource.h>
#include <sys/types.h>
+#include <cutils/sched_policy.h>
#include <dirent.h>
#include <fcntl.h>
#include <grp.h>
@@ -186,58 +187,6 @@
return -1;
}
-static int add_pid_to_cgroup(int pid, const char *grp_name)
-{
- int fd;
- char path[255];
- char text[64];
-
- sprintf(path, "/dev/cpuctl/%s/tasks", grp_name);
-
- if ((fd = open(path, O_WRONLY)) < 0)
- return -1;
-
- sprintf(text, "%d", pid);
- if (write(fd, text, strlen(text)) < 0) {
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-void setSchedPolicy(JNIEnv* env, jobject clazz, int pid, SchedPolicy policy)
-{
- static int __sys_supports_schedgroups = -1;
-
- if (__sys_supports_schedgroups < 0) {
- if (!access("/dev/cpuctl/tasks", F_OK)) {
- __sys_supports_schedgroups = 1;
- } else {
- __sys_supports_schedgroups = 0;
- }
- }
-
- if (__sys_supports_schedgroups) {
- const char *grp = NULL;
-
- if (policy == SP_BACKGROUND) {
- grp = "bg_non_interactive";
- }
-
- if (add_pid_to_cgroup(pid, grp)) {
- if (errno != ESRCH && errno != ENOENT)
- signalExceptionForGroupError(env, clazz, errno);
- }
- } else {
- struct sched_param param;
-
- param.sched_priority = 0;
- sched_setscheduler(pid, (policy == SP_BACKGROUND) ? 5 : 0, ¶m);
- }
-}
-
void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
{
if (grp > ANDROID_TGROUP_MAX || grp < 0) {
@@ -245,9 +194,10 @@
return;
}
- setSchedPolicy(env, clazz, pid,
- (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
- SP_BACKGROUND : SP_FOREGROUND);
+ if (set_sched_policy(pid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+ SP_BACKGROUND : SP_FOREGROUND)) {
+ signalExceptionForGroupError(env, clazz, errno);
+ }
}
void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
@@ -291,9 +241,10 @@
continue;
}
- setSchedPolicy(env, clazz, t_pid,
- (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
- SP_BACKGROUND : SP_FOREGROUND);
+ if (set_sched_policy(t_pid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+ SP_BACKGROUND : SP_FOREGROUND)) {
+ signalExceptionForGroupError(env, clazz, errno);
+ }
}
closedir(d);
}
@@ -301,10 +252,16 @@
void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
jint pid, jint pri)
{
+ int rc = 0;
+
if (pri >= ANDROID_PRIORITY_BACKGROUND) {
- setSchedPolicy(env, clazz, pid, SP_BACKGROUND);
+ rc = set_sched_policy(pid, SP_BACKGROUND);
} else if (getpriority(PRIO_PROCESS, pid) >= ANDROID_PRIORITY_BACKGROUND) {
- setSchedPolicy(env, clazz, pid, SP_FOREGROUND);
+ rc = set_sched_policy(pid, SP_FOREGROUND);
+ }
+
+ if (rc) {
+ signalExceptionForGroupError(env, clazz, errno);
}
if (setpriority(PRIO_PROCESS, pid, pri) < 0) {
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index ac96f20..58206d4 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -45,11 +45,11 @@
private boolean mRunning;
public AnimatedRotateDrawable() {
- this(null);
+ this(null, null);
}
- private AnimatedRotateDrawable(AnimatedRotateState rotateState) {
- mState = new AnimatedRotateState(rotateState, this);
+ private AnimatedRotateDrawable(AnimatedRotateState rotateState, Resources res) {
+ mState = new AnimatedRotateState(rotateState, this, res);
init();
}
@@ -296,9 +296,14 @@
private boolean mCanConstantState;
private boolean mCheckedConstantState;
- public AnimatedRotateState(AnimatedRotateState source, AnimatedRotateDrawable owner) {
+ public AnimatedRotateState(AnimatedRotateState source, AnimatedRotateDrawable owner,
+ Resources res) {
if (source != null) {
- mDrawable = source.mDrawable.getConstantState().newDrawable();
+ if (res != null) {
+ mDrawable = source.mDrawable.getConstantState().newDrawable(res);
+ } else {
+ mDrawable = source.mDrawable.getConstantState().newDrawable();
+ }
mDrawable.setCallback(owner);
mPivotXRel = source.mPivotXRel;
mPivotX = source.mPivotX;
@@ -312,7 +317,12 @@
@Override
public Drawable newDrawable() {
- return new AnimatedRotateDrawable(this);
+ return new AnimatedRotateDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new AnimatedRotateDrawable(this, res);
}
@Override
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 68718c9..fdc4c92 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -77,7 +77,7 @@
private boolean mMutated;
public AnimationDrawable() {
- this(null);
+ this(null, null);
}
@Override
@@ -297,8 +297,9 @@
private int[] mDurations;
private boolean mOneShot;
- AnimationState(AnimationState orig, AnimationDrawable owner) {
- super(orig, owner);
+ AnimationState(AnimationState orig, AnimationDrawable owner,
+ Resources res) {
+ super(orig, owner, res);
if (orig != null) {
mDurations = orig.mDurations;
@@ -311,7 +312,12 @@
@Override
public Drawable newDrawable() {
- return new AnimationDrawable(this);
+ return new AnimationDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new AnimationDrawable(this, res);
}
public void addFrame(Drawable dr, int dur) {
@@ -330,8 +336,8 @@
}
}
- private AnimationDrawable(AnimationState state) {
- AnimationState as = new AnimationState(state, this);
+ private AnimationDrawable(AnimationState state, Resources res) {
+ AnimationState as = new AnimationState(state, this, res);
mAnimationState = as;
setConstantState(as);
if (state != null) {
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 30cef67..e82f297 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -60,15 +60,15 @@
Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
private BitmapState mBitmapState;
private Bitmap mBitmap;
+ private int mTargetDensity;
+
private final Rect mDstRect = new Rect(); // Gravity.apply() sets this
private boolean mApplyGravity;
private boolean mRebuildShader;
private boolean mMutated;
- private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
-
- // These are scaled to match the target density.
+ // These are scaled to match the target density.
private int mBitmapWidth;
private int mBitmapHeight;
@@ -88,10 +88,7 @@
*/
public BitmapDrawable(Resources res) {
mBitmapState = new BitmapState((Bitmap) null);
- if (res != null) {
- setTargetDensity(res.getDisplayMetrics());
- mBitmapState.mTargetDensity = mTargetDensity;
- }
+ mBitmapState.mTargetDensity = mTargetDensity;
}
/**
@@ -101,7 +98,7 @@
*/
@Deprecated
public BitmapDrawable(Bitmap bitmap) {
- this(new BitmapState(bitmap));
+ this(new BitmapState(bitmap), null);
}
/**
@@ -109,22 +106,51 @@
* the display metrics of the resources.
*/
public BitmapDrawable(Resources res, Bitmap bitmap) {
- this(new BitmapState(bitmap));
- if (res != null) {
- setTargetDensity(res.getDisplayMetrics());
- mBitmapState.mTargetDensity = mTargetDensity;
- }
+ this(new BitmapState(bitmap), res);
+ mBitmapState.mTargetDensity = mTargetDensity;
}
+ /**
+ * Create a drawable by opening a given file path and decoding the bitmap.
+ * @deprecated Use {@link #BitmapDrawable(Resources, String)} to ensure
+ * that the drawable has correctly set its target density.
+ */
public BitmapDrawable(String filepath) {
- this(new BitmapState(BitmapFactory.decodeFile(filepath)));
+ this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
if (mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
}
}
+ /**
+ * Create a drawable by opening a given file path and decoding the bitmap.
+ */
+ public BitmapDrawable(Resources res, String filepath) {
+ this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
+ mBitmapState.mTargetDensity = mTargetDensity;
+ if (mBitmap == null) {
+ android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+ }
+ }
+
+ /**
+ * Create a drawable by decoding a bitmap from the given input stream.
+ * @deprecated Use {@link #BitmapDrawable(Resources, java.io.InputStream)} to ensure
+ * that the drawable has correctly set its target density.
+ */
public BitmapDrawable(java.io.InputStream is) {
- this(new BitmapState(BitmapFactory.decodeStream(is)));
+ this(new BitmapState(BitmapFactory.decodeStream(is)), null);
+ if (mBitmap == null) {
+ android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+ }
+ }
+
+ /**
+ * Create a drawable by decoding a bitmap from the given input stream.
+ */
+ public BitmapDrawable(Resources res, java.io.InputStream is) {
+ this(new BitmapState(BitmapFactory.decodeStream(is)), null);
+ mBitmapState.mTargetDensity = mTargetDensity;
if (mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
}
@@ -425,7 +451,12 @@
@Override
public Drawable newDrawable() {
- return new BitmapDrawable(this);
+ return new BitmapDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new BitmapDrawable(this, res);
}
@Override
@@ -434,9 +465,15 @@
}
}
- private BitmapDrawable(BitmapState state) {
+ private BitmapDrawable(BitmapState state, Resources res) {
mBitmapState = state;
- mTargetDensity = state.mTargetDensity;
+ if (res != null) {
+ mTargetDensity = res.getDisplayMetrics().densityDpi;
+ } else if (state != null) {
+ mTargetDensity = state.mTargetDensity;
+ } else {
+ mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+ }
setBitmap(state.mBitmap);
}
}
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 95d4dd0..c387a9b 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -48,14 +48,14 @@
public static final int VERTICAL = 2;
ClipDrawable() {
- this(null);
+ this(null, null);
}
/**
* @param orientation Bitwise-or of {@link #HORIZONTAL} and/or {@link #VERTICAL}
*/
public ClipDrawable(Drawable drawable, int gravity, int orientation) {
- this(null);
+ this(null, null);
mClipState.mDrawable = drawable;
mClipState.mGravity = gravity;
@@ -241,9 +241,13 @@
private boolean mCheckedConstantState;
private boolean mCanConstantState;
- ClipState(ClipState orig, ClipDrawable owner) {
+ ClipState(ClipState orig, ClipDrawable owner, Resources res) {
if (orig != null) {
- mDrawable = orig.mDrawable.getConstantState().newDrawable();
+ if (res != null) {
+ mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
+ } else {
+ mDrawable = orig.mDrawable.getConstantState().newDrawable();
+ }
mDrawable.setCallback(owner);
mOrientation = orig.mOrientation;
mGravity = orig.mGravity;
@@ -253,7 +257,12 @@
@Override
public Drawable newDrawable() {
- return new ClipDrawable(this);
+ return new ClipDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new ClipDrawable(this, res);
}
@Override
@@ -271,8 +280,8 @@
}
}
- private ClipDrawable(ClipState state) {
- mClipState = new ClipState(state, this);
+ private ClipDrawable(ClipState state, Resources res) {
+ mClipState = new ClipState(state, this, res);
}
}
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 226cc04..604c602 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -146,6 +146,11 @@
}
@Override
+ public Drawable newDrawable(Resources res) {
+ return new ColorDrawable(this);
+ }
+
+ @Override
public int getChangingConfigurations() {
return mChangingConfigurations;
}
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 21b5e39..6a7b2d1 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -822,7 +822,26 @@
}
public static abstract class ConstantState {
+ /**
+ * Create a new drawable without supplying resources the caller
+ * is running in. Note that using this means the density-dependent
+ * drawables (like bitmaps) will not be able to update their target
+ * density correctly.
+ */
public abstract Drawable newDrawable();
+ /**
+ * Create a new Drawable instance from its constant state. This
+ * must be implemented for drawables that change based on the target
+ * density of their caller (that is depending on whether it is
+ * in compatibility mode).
+ */
+ public Drawable newDrawable(Resources res) {
+ return newDrawable();
+ }
+ /**
+ * Return a bit mask of configuration changes that will impact
+ * this drawable (and thus require completely reloading it).
+ */
public abstract int getChangingConfigurations();
}
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index af1a289..3266f1e 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -16,6 +16,7 @@
package android.graphics.drawable;
+import android.content.res.Resources;
import android.graphics.*;
public class DrawableContainer extends Drawable implements Drawable.Callback {
@@ -285,7 +286,8 @@
boolean mPaddingChecked = false;
- DrawableContainerState(DrawableContainerState orig, DrawableContainer owner) {
+ DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
+ Resources res) {
mOwner = owner;
if (orig != null) {
@@ -299,7 +301,11 @@
final int N = mNumChildren;
for (int i=0; i<N; i++) {
- mDrawables[i] = origDr[i].getConstantState().newDrawable();
+ if (res != null) {
+ mDrawables[i] = origDr[i].getConstantState().newDrawable(res);
+ } else {
+ mDrawables[i] = origDr[i].getConstantState().newDrawable();
+ }
mDrawables[i].setCallback(owner);
}
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index a7a8708..ddbbaf1 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -917,6 +917,11 @@
}
@Override
+ public Drawable newDrawable(Resources res) {
+ return new GradientDrawable(this);
+ }
+
+ @Override
public int getChangingConfigurations() {
return mChangingConfigurations;
}
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 6047726..4fa9d44 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -49,7 +49,7 @@
private boolean mMutated;
/*package*/ InsetDrawable() {
- this(null);
+ this(null, null);
}
public InsetDrawable(Drawable drawable, int inset) {
@@ -58,7 +58,7 @@
public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,
int insetRight, int insetBottom) {
- this(null);
+ this(null, null);
mInsetState.mDrawable = drawable;
mInsetState.mInsetLeft = insetLeft;
@@ -263,9 +263,13 @@
boolean mCheckedConstantState;
boolean mCanConstantState;
- InsetState(InsetState orig, InsetDrawable owner) {
+ InsetState(InsetState orig, InsetDrawable owner, Resources res) {
if (orig != null) {
- mDrawable = orig.mDrawable.getConstantState().newDrawable();
+ if (res != null) {
+ mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
+ } else {
+ mDrawable = orig.mDrawable.getConstantState().newDrawable();
+ }
mDrawable.setCallback(owner);
mInsetLeft = orig.mInsetLeft;
mInsetTop = orig.mInsetTop;
@@ -277,7 +281,12 @@
@Override
public Drawable newDrawable() {
- return new InsetDrawable(this);
+ return new InsetDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new InsetDrawable(this, res);
}
@Override
@@ -295,8 +304,8 @@
}
}
- private InsetDrawable(InsetState state) {
- mInsetState = new InsetState(state, this);
+ private InsetDrawable(InsetState state, Resources res) {
+ mInsetState = new InsetState(state, this, res);
}
}
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index c777205..389fd40 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -70,7 +70,7 @@
* @param state The constant drawable state.
*/
LayerDrawable(Drawable[] layers, LayerState state) {
- this(state);
+ this(state, null);
int length = layers.length;
ChildDrawable[] r = new ChildDrawable[length];
@@ -87,19 +87,19 @@
}
LayerDrawable() {
- this((LayerState) null);
+ this((LayerState) null, null);
}
- LayerDrawable(LayerState state) {
- LayerState as = createConstantState(state);
+ LayerDrawable(LayerState state, Resources res) {
+ LayerState as = createConstantState(state, res);
mLayerState = as;
if (as.mNum > 0) {
ensurePadding();
}
}
- LayerState createConstantState(LayerState state) {
- return new LayerState(state, this);
+ LayerState createConstantState(LayerState state, Resources res) {
+ return new LayerState(state, this, res);
}
@Override
@@ -563,7 +563,7 @@
private boolean mCheckedConstantState;
private boolean mCanConstantState;
- LayerState(LayerState orig, LayerDrawable owner) {
+ LayerState(LayerState orig, LayerDrawable owner, Resources res) {
if (orig != null) {
final ChildDrawable[] origChildDrawable = orig.mChildren;
final int N = orig.mNum;
@@ -577,7 +577,11 @@
for (int i = 0; i < N; i++) {
final ChildDrawable r = mChildren[i] = new ChildDrawable();
final ChildDrawable or = origChildDrawable[i];
- r.mDrawable = or.mDrawable.getConstantState().newDrawable();
+ if (res != null) {
+ r.mDrawable = or.mDrawable.getConstantState().newDrawable(res);
+ } else {
+ r.mDrawable = or.mDrawable.getConstantState().newDrawable();
+ }
r.mDrawable.setCallback(owner);
r.mInsetL = or.mInsetL;
r.mInsetT = or.mInsetT;
@@ -599,7 +603,12 @@
@Override
public Drawable newDrawable() {
- return new LayerDrawable(this);
+ return new LayerDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new LayerDrawable(this, res);
}
@Override
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
index 7ae649f..ae8f224 100644
--- a/graphics/java/android/graphics/drawable/LevelListDrawable.java
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -57,7 +57,7 @@
private boolean mMutated;
public LevelListDrawable() {
- this(null);
+ this(null, null);
}
public void addLevel(int low, int high, Drawable drawable) {
@@ -154,8 +154,8 @@
private int[] mLows;
private int[] mHighs;
- LevelListState(LevelListState orig, LevelListDrawable owner) {
- super(orig, owner);
+ LevelListState(LevelListState orig, LevelListDrawable owner, Resources res) {
+ super(orig, owner, res);
if (orig != null) {
mLows = orig.mLows;
@@ -186,7 +186,12 @@
@Override
public Drawable newDrawable() {
- return new LevelListDrawable(this);
+ return new LevelListDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new LevelListDrawable(this, res);
}
@Override
@@ -201,8 +206,8 @@
}
}
- private LevelListDrawable(LevelListState state) {
- LevelListState as = new LevelListState(state, this);
+ private LevelListDrawable(LevelListState state, Resources res) {
+ LevelListState as = new LevelListState(state, this, res);
mLevelListState = as;
setConstantState(as);
onLevelChange(getLevel());
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 997efb8..803e7b1 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -61,7 +61,7 @@
*/
@Deprecated
public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
- this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding));
+ this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null);
}
/**
@@ -70,11 +70,8 @@
*/
public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
Rect padding, String srcName) {
- this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding));
- if (res != null) {
- setTargetDensity(res.getDisplayMetrics());
- mNinePatchState.mTargetDensity = mTargetDensity;
- }
+ this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
+ mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
@@ -84,7 +81,7 @@
*/
@Deprecated
public NinePatchDrawable(NinePatch patch) {
- this(new NinePatchState(patch, null));
+ this(new NinePatchState(patch, null), null);
}
/**
@@ -92,18 +89,16 @@
* based on the display metrics of the resources.
*/
public NinePatchDrawable(Resources res, NinePatch patch) {
- this(new NinePatchState(patch, null));
- if (res != null) {
- setTargetDensity(res.getDisplayMetrics());
- mNinePatchState.mTargetDensity = mTargetDensity;
- }
+ this(new NinePatchState(patch, null), res);
+ mNinePatchState.mTargetDensity = mTargetDensity;
}
- private void setNinePatchState(NinePatchState state) {
+ private void setNinePatchState(NinePatchState state, Resources res) {
mNinePatchState = state;
mNinePatch = state.mNinePatch;
mPadding = state.mPadding;
- mTargetDensity = state.mTargetDensity;
+ mTargetDensity = res != null ? res.getDisplayMetrics().densityDpi
+ : state.mTargetDensity;
if (DEFAULT_DITHER != state.mDither) {
// avoid calling the setter unless we need to, since it does a
// lazy allocation of a paint
@@ -258,7 +253,8 @@
}
setNinePatchState(new NinePatchState(
- new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"), padding, dither));
+ new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"),
+ padding, dither), r);
mNinePatchState.mTargetDensity = mTargetDensity;
a.recycle();
@@ -357,7 +353,12 @@
@Override
public Drawable newDrawable() {
- return new NinePatchDrawable(this);
+ return new NinePatchDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new NinePatchDrawable(this, res);
}
@Override
@@ -366,8 +367,7 @@
}
}
- private NinePatchDrawable(NinePatchState state) {
- setNinePatchState(state);
+ private NinePatchDrawable(NinePatchState state, Resources res) {
+ setNinePatchState(state, res);
}
}
-
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index cb16cb7..c4a7822 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -54,7 +54,7 @@
* <p>Create a new rotating drawable with an empty state.</p>
*/
public RotateDrawable() {
- this(null);
+ this(null, null);
}
/**
@@ -64,8 +64,8 @@
*
* @param rotateState the state for this drawable
*/
- private RotateDrawable(RotateState rotateState) {
- mState = new RotateState(rotateState, this);
+ private RotateDrawable(RotateState rotateState, Resources res) {
+ mState = new RotateState(rotateState, this, res);
}
public void draw(Canvas canvas) {
@@ -291,9 +291,13 @@
private boolean mCanConstantState;
private boolean mCheckedConstantState;
- public RotateState(RotateState source, RotateDrawable owner) {
+ public RotateState(RotateState source, RotateDrawable owner, Resources res) {
if (source != null) {
- mDrawable = source.mDrawable.getConstantState().newDrawable();
+ if (res != null) {
+ mDrawable = source.mDrawable.getConstantState().newDrawable(res);
+ } else {
+ mDrawable = source.mDrawable.getConstantState().newDrawable();
+ }
mDrawable.setCallback(owner);
mPivotXRel = source.mPivotXRel;
mPivotX = source.mPivotX;
@@ -307,7 +311,12 @@
@Override
public Drawable newDrawable() {
- return new RotateDrawable(this);
+ return new RotateDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new RotateDrawable(this, res);
}
@Override
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index 7125ab1..275e36f 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -47,11 +47,11 @@
private final Rect mTmpRect = new Rect();
ScaleDrawable() {
- this(null);
+ this(null, null);
}
public ScaleDrawable(Drawable drawable, int gravity, float scaleWidth, float scaleHeight) {
- this(null);
+ this(null, null);
mScaleState.mDrawable = drawable;
mScaleState.mGravity = gravity;
@@ -260,9 +260,13 @@
private boolean mCheckedConstantState;
private boolean mCanConstantState;
- ScaleState(ScaleState orig, ScaleDrawable owner) {
+ ScaleState(ScaleState orig, ScaleDrawable owner, Resources res) {
if (orig != null) {
- mDrawable = orig.mDrawable.getConstantState().newDrawable();
+ if (res != null) {
+ mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
+ } else {
+ mDrawable = orig.mDrawable.getConstantState().newDrawable();
+ }
mDrawable.setCallback(owner);
mScaleWidth = orig.mScaleWidth;
mScaleHeight = orig.mScaleHeight;
@@ -273,7 +277,12 @@
@Override
public Drawable newDrawable() {
- return new ScaleDrawable(this);
+ return new ScaleDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new ScaleDrawable(this, res);
}
@Override
@@ -291,8 +300,8 @@
}
}
- private ScaleDrawable(ScaleState state) {
- mScaleState = new ScaleState(state, this);
+ private ScaleDrawable(ScaleState state, Resources res) {
+ mScaleState = new ScaleState(state, this, res);
}
}
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 6677a35..c699a82 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -396,6 +396,11 @@
}
@Override
+ public Drawable newDrawable(Resources res) {
+ return new ShapeDrawable(this);
+ }
+
+ @Override
public int getChangingConfigurations() {
return mChangingConfigurations;
}
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 59cb226..b1d588e 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -65,7 +65,7 @@
private boolean mMutated;
public StateListDrawable() {
- this(null);
+ this(null, null);
}
/**
@@ -248,8 +248,8 @@
static final class StateListState extends DrawableContainerState {
private int[][] mStateSets;
- StateListState(StateListState orig, StateListDrawable owner) {
- super(orig, owner);
+ StateListState(StateListState orig, StateListDrawable owner, Resources res) {
+ super(orig, owner, res);
if (orig != null) {
mStateSets = orig.mStateSets;
@@ -277,7 +277,12 @@
@Override
public Drawable newDrawable() {
- return new StateListDrawable(this);
+ return new StateListDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new StateListDrawable(this, res);
}
@Override
@@ -289,8 +294,8 @@
}
}
- private StateListDrawable(StateListState state) {
- StateListState as = new StateListState(state, this);
+ private StateListDrawable(StateListState state, Resources res) {
+ StateListState as = new StateListState(state, this, res);
mStateListState = as;
setConstantState(as);
onStateChange(getState());
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index 358f889..97b45d8 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -16,6 +16,7 @@
package android.graphics.drawable;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.os.SystemClock;
@@ -72,7 +73,7 @@
* 2 layers are required for this drawable to work properly.
*/
public TransitionDrawable(Drawable[] layers) {
- this(new TransitionState(null, null), layers);
+ this(new TransitionState(null, null, null), layers);
}
/**
@@ -82,11 +83,11 @@
* @see #TransitionDrawable(Drawable[])
*/
TransitionDrawable() {
- this(new TransitionState(null, null));
+ this(new TransitionState(null, null, null), (Resources)null);
}
- private TransitionDrawable(TransitionState state) {
- super(state);
+ private TransitionDrawable(TransitionState state, Resources res) {
+ super(state, res);
}
private TransitionDrawable(TransitionState state, Drawable[] layers) {
@@ -94,8 +95,8 @@
}
@Override
- LayerState createConstantState(LayerState state) {
- return new TransitionState((TransitionState) state, this);
+ LayerState createConstantState(LayerState state, Resources res) {
+ return new TransitionState((TransitionState) state, this, res);
}
/**
@@ -229,13 +230,19 @@
}
static class TransitionState extends LayerState {
- TransitionState(TransitionState orig, TransitionDrawable owner) {
- super(orig, owner);
+ TransitionState(TransitionState orig, TransitionDrawable owner,
+ Resources res) {
+ super(orig, owner, res);
}
@Override
public Drawable newDrawable() {
- return new TransitionDrawable(this);
+ return new TransitionDrawable(this, (Resources)null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new TransitionDrawable(this, res);
}
@Override
diff --git a/include/private/ui/SharedBufferStack.h b/include/private/ui/SharedBufferStack.h
index 6181f55..8b0f154 100644
--- a/include/private/ui/SharedBufferStack.h
+++ b/include/private/ui/SharedBufferStack.h
@@ -228,6 +228,8 @@
friend struct Condition;
friend struct DequeueCondition;
friend struct LockCondition;
+
+ int32_t computeTail() const;
struct QueueUpdate : public UpdateBase {
inline QueueUpdate(SharedBufferBase* sbb);
diff --git a/include/utils/threads.h b/include/utils/threads.h
index f5304f7..0fc533f 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -90,11 +90,6 @@
ANDROID_TGROUP_MAX = ANDROID_TGROUP_FG_BOOST,
};
-typedef enum {
- SP_BACKGROUND = 0,
- SP_FOREGROUND = 1,
-} SchedPolicy;
-
// Create and run a new thread.
extern int androidCreateThread(android_thread_func_t, void *);
diff --git a/libs/rs/java/Fountain/res/raw/fountain.c b/libs/rs/java/Fountain/res/raw/fountain.c
index 36516c2..57e10cf 100644
--- a/libs/rs/java/Fountain/res/raw/fountain.c
+++ b/libs/rs/java/Fountain/res/raw/fountain.c
@@ -20,20 +20,21 @@
char r = Control->r * 255.f;
char g = Control->g * 255.f;
char b = Control->b * 255.f;
- char a = 0xf0;
+ struct point_s * np = &p[newPart];
while (rate--) {
- vec2Rand((float *)(p + newPart), rMax);
- p[newPart].x = x;
- p[newPart].y = y;
- p[newPart].r = r;
- p[newPart].g = g;
- p[newPart].b = b;
- p[newPart].a = a;
+ vec2Rand((float *)np, rMax);
+ np->x = x;
+ np->y = y;
+ np->r = r;
+ np->g = g;
+ np->b = b;
+ np->a = 0xf0;
newPart++;
if (newPart >= count) {
newPart = 0;
}
+ np++;
}
}
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 8685f99..a352431 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -1524,13 +1524,24 @@
result.append( l->lcblk->dump(" ") );
sp<const Buffer> buf0(l->getBuffer(0));
sp<const Buffer> buf1(l->getBuffer(1));
+ uint32_t w0=0, h0=0, s0=0;
+ uint32_t w1=0, h1=0, s1=0;
+ if (buf0 != 0) {
+ w0 = buf0->getWidth();
+ h0 = buf0->getHeight();
+ s0 = buf0->getStride();
+ }
+ if (buf1 != 0) {
+ w1 = buf1->getWidth();
+ h1 = buf1->getHeight();
+ s1 = buf1->getStride();
+ }
snprintf(buffer, SIZE,
" "
"format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
" freezeLock=%p\n",
l->pixelFormat(),
- buf0->getWidth(), buf0->getHeight(), buf0->getStride(),
- buf1->getWidth(), buf1->getHeight(), buf1->getStride(),
+ w0, h0, s0, w1, h1, s1,
l->getFreezeLock().get());
result.append(buffer);
buffer[0] = 0;
diff --git a/libs/ui/SharedBufferStack.cpp b/libs/ui/SharedBufferStack.cpp
index 436d793..7789a3f 100644
--- a/libs/ui/SharedBufferStack.cpp
+++ b/libs/ui/SharedBufferStack.cpp
@@ -246,19 +246,26 @@
int surface, int num)
: SharedBufferBase(sharedClient, surface, num), tail(0)
{
+ tail = computeTail();
+}
+
+int32_t SharedBufferClient::computeTail() const
+{
SharedBufferStack& stack( *mSharedStack );
- int32_t avail;
- int32_t head;
// we need to make sure we read available and head coherently,
// w.r.t RetireUpdate.
+ int32_t newTail;
+ int32_t avail;
+ int32_t head;
do {
avail = stack.available;
head = stack.head;
} while (stack.available != avail);
- tail = head - avail + 1;
- if (tail < 0) {
- tail += num;
+ newTail = head - avail + 1;
+ if (newTail < 0) {
+ newTail += mNumBuffers;
}
+ return newTail;
}
ssize_t SharedBufferClient::dequeue()
@@ -296,6 +303,9 @@
{
UndoDequeueUpdate update(this);
status_t err = updateCondition( update );
+ if (err == NO_ERROR) {
+ tail = computeTail();
+ }
return err;
}
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index a964d17..22c2f39 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -232,6 +232,16 @@
quirks |= kRequiresAllocateBufferOnOutputPorts;
}
+ if (!strncmp(componentName, "OMX.TI.", 7)) {
+ // Apparently I must not use OMX_UseBuffer on either input or
+ // output ports on any of the TI components or quote:
+ // "(I) may have unexpected problem (sic) which can be timing related
+ // and hard to reproduce."
+
+ quirks |= kRequiresAllocateBufferOnInputPorts;
+ quirks |= kRequiresAllocateBufferOnOutputPorts;
+ }
+
sp<OMXCodec> codec = new OMXCodec(
omx, node, quirks, createEncoder, mime, componentName,
source);
@@ -840,8 +850,8 @@
mNode, portIndex, mem, &buffer);
} else if (portIndex == kPortIndexOutput
&& (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
- err = mOMX->allocate_buffer(
- mNode, portIndex, def.nBufferSize, &buffer);
+ err = mOMX->allocate_buffer_with_backup(
+ mNode, portIndex, mem, &buffer);
} else {
err = mOMX->use_buffer(mNode, portIndex, mem, &buffer);
}
@@ -1256,6 +1266,8 @@
CHECK_EQ(info->mOwnedByComponent, false);
+ CODEC_LOGV("freeing buffer %p on port %ld", info->mBuffer, portIndex);
+
status_t err =
mOMX->free_buffer(mNode, portIndex, info->mBuffer);
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 244e136..d9f4c9c 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -981,6 +981,29 @@
}
}
+ /**
+ * Return true if the queue has an up event pending that corresponds
+ * to the same key as the given key event.
+ */
+ boolean hasKeyUpEvent(KeyEvent origEvent) {
+ synchronized (mFirst) {
+ final int keyCode = origEvent.getKeyCode();
+ QueuedEvent cur = mLast.prev;
+ while (cur.prev != null) {
+ if (cur.classType == RawInputEvent.CLASS_KEYBOARD) {
+ KeyEvent ke = (KeyEvent)cur.event;
+ if (ke.getAction() == KeyEvent.ACTION_UP
+ && ke.getKeyCode() == keyCode) {
+ return true;
+ }
+ }
+ cur = cur.prev;
+ }
+ }
+
+ return false;
+ }
+
void recycleEvent(QueuedEvent ev) {
synchronized (mFirst) {
//Log.i(TAG, "Recycle event: " + ev);
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 38df47b..ba65f01 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -63,7 +63,7 @@
import java.util.Observer;
class PowerManagerService extends IPowerManager.Stub
- implements LocalPowerManager,Watchdog.Monitor, SensorEventListener {
+ implements LocalPowerManager, Watchdog.Monitor, SensorEventListener {
private static final String TAG = "PowerManagerService";
static final String PARTIAL_NAME = "PowerManagerService";
@@ -1848,7 +1848,17 @@
}
public void setKeyboardVisibility(boolean visible) {
- mKeyboardVisible = visible;
+ synchronized (mLocks) {
+ if (mSpew) {
+ Log.d(TAG, "setKeyboardVisibility: " + visible);
+ }
+ mKeyboardVisible = visible;
+ // don't signal user activity when closing keyboard if the screen is off.
+ // otherwise, we want to make sure the backlights are adjusted.
+ if (visible || (mPowerState & SCREEN_ON_BIT) != 0) {
+ userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);
+ }
+ }
}
/**
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index b0e4038..8e85a6a 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -99,6 +99,7 @@
import android.view.Surface;
import android.view.SurfaceSession;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
@@ -151,9 +152,6 @@
static final int LOG_WM_NO_SURFACE_MEMORY = 31000;
- /** How long to wait for first key repeat, in milliseconds */
- static final int KEY_REPEAT_FIRST_DELAY = 750;
-
/** How long to wait for subsequent key repeats, in milliseconds */
static final int KEY_REPEAT_DELAY = 50;
@@ -418,6 +416,17 @@
int mWallpaperAnimLayerAdjustment;
float mLastWallpaperX;
float mLastWallpaperY;
+ // Lock for waiting for the wallpaper.
+ final Object mWaitingOnWallpaperLock = new Object();
+ // This is set when we are waiting for a wallpaper to tell us it is done
+ // changing its scroll position.
+ WindowState mWaitingOnWallpaper;
+ // The last time we had a timeout when waiting for a wallpaper.
+ long mLastWallpaperTimeoutTime;
+ // We give a wallpaper up to 150ms to finish scrolling.
+ static final long WALLPAPER_TIMEOUT = 150;
+ // Time we wait after a timeout before trying to wait again.
+ static final long WALLPAPER_TIMEOUT_RECOVERY = 10000;
AppWindowToken mFocusedApp = null;
@@ -1427,7 +1436,7 @@
WindowState wallpaper = token.windows.get(curWallpaperIndex);
if (visible) {
- updateWallpaperOffsetLocked(wallpaper, dw, dh);
+ updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
}
// First, make sure the client has the current visibility
@@ -1498,7 +1507,8 @@
}
}
- boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh) {
+ boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh,
+ boolean sync) {
boolean changed = false;
boolean rawChanged = false;
if (mLastWallpaperX >= 0) {
@@ -1536,8 +1546,37 @@
if (DEBUG_WALLPAPER) Log.v(TAG, "Report new wp offset "
+ wallpaperWin + " x=" + wallpaperWin.mWallpaperX
+ " y=" + wallpaperWin.mWallpaperY);
+ if (sync) {
+ synchronized (mWaitingOnWallpaperLock) {
+ mWaitingOnWallpaper = wallpaperWin;
+ }
+ }
wallpaperWin.mClient.dispatchWallpaperOffsets(
- wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY);
+ wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY, sync);
+ if (sync) {
+ synchronized (mWaitingOnWallpaperLock) {
+ if (mWaitingOnWallpaper != null) {
+ long start = SystemClock.uptimeMillis();
+ if ((mLastWallpaperTimeoutTime+WALLPAPER_TIMEOUT_RECOVERY)
+ < start) {
+ try {
+ if (DEBUG_WALLPAPER) Log.v(TAG,
+ "Waiting for offset complete...");
+ mWaitingOnWallpaperLock.wait(WALLPAPER_TIMEOUT);
+ } catch (InterruptedException e) {
+ }
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Offset complete!");
+ if ((start+WALLPAPER_TIMEOUT)
+ < SystemClock.uptimeMillis()) {
+ Log.i(TAG, "Timeout waiting for wallpaper to offset: "
+ + wallpaperWin);
+ mLastWallpaperTimeoutTime = start;
+ }
+ }
+ mWaitingOnWallpaper = null;
+ }
+ }
+ }
} catch (RemoteException e) {
}
}
@@ -1545,7 +1584,17 @@
return changed;
}
- boolean updateWallpaperOffsetLocked() {
+ void wallpaperOffsetsComplete(IBinder window) {
+ synchronized (mWaitingOnWallpaperLock) {
+ if (mWaitingOnWallpaper != null &&
+ mWaitingOnWallpaper.mClient.asBinder() == window) {
+ mWaitingOnWallpaper = null;
+ mWaitingOnWallpaperLock.notifyAll();
+ }
+ }
+ }
+
+ boolean updateWallpaperOffsetLocked(boolean sync) {
final int dw = mDisplay.getWidth();
final int dh = mDisplay.getHeight();
@@ -1563,9 +1612,11 @@
while (curWallpaperIndex > 0) {
curWallpaperIndex--;
WindowState wallpaper = token.windows.get(curWallpaperIndex);
- if (updateWallpaperOffsetLocked(wallpaper, dw, dh)) {
+ if (updateWallpaperOffsetLocked(wallpaper, dw, dh, sync)) {
wallpaper.computeShownFrameLocked();
changed = true;
+ // We only want to be synchronous with one wallpaper.
+ sync = false;
}
}
}
@@ -1595,7 +1646,7 @@
curWallpaperIndex--;
WindowState wallpaper = token.windows.get(curWallpaperIndex);
if (visible) {
- updateWallpaperOffsetLocked(wallpaper, dw, dh);
+ updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
}
if (wallpaper.mWallpaperVisible != visible) {
@@ -1782,8 +1833,10 @@
imMayMove = false;
} else {
addWindowToListInOrderLocked(win, true);
- if (attrs.type == TYPE_WALLPAPER ||
- (attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+ if (attrs.type == TYPE_WALLPAPER) {
+ mLastWallpaperTimeoutTime = 0;
+ adjustWallpaperWindowsLocked();
+ } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
adjustWallpaperWindowsLocked();
}
}
@@ -1992,8 +2045,10 @@
}
}
- if (win.mAttrs.type == TYPE_WALLPAPER ||
- (win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+ if (win.mAttrs.type == TYPE_WALLPAPER) {
+ mLastWallpaperTimeoutTime = 0;
+ adjustWallpaperWindowsLocked();
+ } else if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
adjustWallpaperWindowsLocked();
}
@@ -2070,7 +2125,7 @@
window.mWallpaperY = y;
if (mWallpaperTarget == window) {
- if (updateWallpaperOffsetLocked()) {
+ if (updateWallpaperOffsetLocked(true)) {
performLayoutAndPlaceSurfacesLocked();
}
}
@@ -2258,7 +2313,7 @@
performLayoutAndPlaceSurfacesLocked();
if (displayed && win.mIsWallpaper) {
updateWallpaperOffsetLocked(win, mDisplay.getWidth(),
- mDisplay.getHeight());
+ mDisplay.getHeight(), false);
}
if (win.mAppToken != null) {
win.mAppToken.updateReportedVisibilityLocked();
@@ -4843,6 +4898,16 @@
return INJECT_SUCCEEDED;
}
+ // Okay we have finished waiting for the last event to be processed.
+ // First off, if this is a repeat event, check to see if there is
+ // a corresponding up event in the queue. If there is, we will
+ // just drop the repeat, because it makes no sense to repeat after
+ // the user has released a key. (This is especially important for
+ // long presses.)
+ if (event.getRepeatCount() > 0 && mQueue.hasKeyUpEvent(event)) {
+ return INJECT_SUCCEEDED;
+ }
+
WindowState focus = (WindowState)focusObj;
if (DEBUG_INPUT) Log.v(
@@ -5961,6 +6026,7 @@
// Last keydown time for auto-repeating keys
long lastKeyTime = SystemClock.uptimeMillis();
long nextKeyTime = lastKeyTime+LONG_WAIT;
+ long downTime = 0;
// How many successive repeats we generated
int keyRepeatCount = 0;
@@ -6031,15 +6097,17 @@
KeyEvent ke = (KeyEvent)ev.event;
if (ke.isDown()) {
lastKey = ke;
+ downTime = curTime;
keyRepeatCount = 0;
lastKeyTime = curTime;
nextKeyTime = lastKeyTime
- + KEY_REPEAT_FIRST_DELAY;
+ + ViewConfiguration.getLongPressTimeout();
if (DEBUG_INPUT) Log.v(
TAG, "Received key down: first repeat @ "
+ nextKeyTime);
} else {
lastKey = null;
+ downTime = 0;
// Arbitrary long timeout.
lastKeyTime = curTime;
nextKeyTime = curTime + LONG_WAIT;
@@ -6087,7 +6155,19 @@
if (DEBUG_INPUT) Log.v(
TAG, "Key repeat: count=" + keyRepeatCount
+ ", next @ " + nextKeyTime);
- dispatchKey(KeyEvent.changeTimeRepeat(lastKey, curTime, keyRepeatCount), 0, 0);
+ KeyEvent newEvent;
+ if (downTime != 0 && (downTime
+ + ViewConfiguration.getLongPressTimeout())
+ <= curTime) {
+ newEvent = KeyEvent.changeTimeRepeat(lastKey,
+ curTime, keyRepeatCount,
+ lastKey.getFlags() | KeyEvent.FLAG_LONG_PRESS);
+ downTime = 0;
+ } else {
+ newEvent = KeyEvent.changeTimeRepeat(lastKey,
+ curTime, keyRepeatCount);
+ }
+ dispatchKey(newEvent, 0, 0);
} else {
curTime = SystemClock.uptimeMillis();
@@ -6303,6 +6383,10 @@
}
}
+ public void wallpaperOffsetsComplete(IBinder window) {
+ WindowManagerService.this.wallpaperOffsetsComplete(window);
+ }
+
void windowAddedLocked() {
if (mSurfaceSession == null) {
if (localLOGV) Log.v(
@@ -6698,7 +6782,7 @@
if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) {
updateWallpaperOffsetLocked(this, mDisplay.getWidth(),
- mDisplay.getHeight());
+ mDisplay.getHeight(), false);
}
if (localLOGV) {
diff --git a/telephony/java/com/android/internal/telephony/IccProvider.java b/telephony/java/com/android/internal/telephony/IccProvider.java
index ffcfe6f..8b54ca8 100644
--- a/telephony/java/com/android/internal/telephony/IccProvider.java
+++ b/telephony/java/com/android/internal/telephony/IccProvider.java
@@ -181,7 +181,7 @@
return null;
}
- StringBuilder buf = new StringBuilder("content://im/");
+ StringBuilder buf = new StringBuilder("content://icc/");
switch (match) {
case ADN:
buf.append("adn/");
diff --git a/tests/DumpRenderTree/assets/run_layout_tests.py b/tests/DumpRenderTree/assets/run_layout_tests.py
index c3e6b5b..c3627bb 100755
--- a/tests/DumpRenderTree/assets/run_layout_tests.py
+++ b/tests/DumpRenderTree/assets/run_layout_tests.py
@@ -197,7 +197,17 @@
logging.error("DumpRenderTree crashed, output:\n" + adb_output)
shell_cmd_str = adb_cmd + " shell cat /sdcard/android/running_test.txt"
- crashed_test = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE).communicate()[0]
+ crashed_test = ""
+ while not crashed_test:
+ (crashed_test, err) = subprocess.Popen(
+ shell_cmd_str, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).communicate()
+ crashed_test = crashed_test.strip()
+ if not crashed_test:
+ logging.error('Cannot get crashed test name, device offline?')
+ logging.error('stderr: ' + err)
+ logging.error('retrying in 10s...')
+ time.sleep(10)
logging.info(crashed_test + " CRASHED");
crashed_tests.append(crashed_test);
diff --git a/tests/DumpRenderTree/assets/run_page_cycler.py b/tests/DumpRenderTree/assets/run_page_cycler.py
index 2325047..4a68d72 100755
--- a/tests/DumpRenderTree/assets/run_page_cycler.py
+++ b/tests/DumpRenderTree/assets/run_page_cycler.py
@@ -59,8 +59,18 @@
run_load_test_cmd = run_load_test_cmd_prefix + " -e class com.android.dumprendertree.LoadTestsAutoTest#runPageCyclerTest -e path \"" + path + "\" -e timeout " + timeout_ms + run_load_test_cmd_postfix
(adb_output, adb_error) = subprocess.Popen(run_load_test_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
- if adb_output.find('INSTRUMENTATION_FAILED') != -1 or \
- adb_output.find('Process crashed.') != -1:
+ fail_flag = False
+ for line in adb_output.splitlines():
+ line = line.strip()
+ if line.find('INSTRUMENTATION_CODE') == 0:
+ if not line[22:] == '-1':
+ fail_flag = True
+ break
+ if (line.find('INSTRUMENTATION_FAILED') != -1 or
+ line.find('Process crashed.') != -1):
+ fail_flag = True
+ break
+ if fail_flag:
logging.error("Error happened : " + adb_output)
sys.exit(1)
@@ -80,7 +90,6 @@
shell_cmd_str = adb_cmd + " pull " + result_file + " " + results_dir
adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
logging.info(adb_output)
-
logging.info("Results are stored under: " + results_dir + "/load_test_result.txt\n")
if '__main__' == __name__:
diff --git a/tests/DumpRenderTree/assets/run_reliability_tests.py b/tests/DumpRenderTree/assets/run_reliability_tests.py
index 23f93df..59ac4a3 100755
--- a/tests/DumpRenderTree/assets/run_reliability_tests.py
+++ b/tests/DumpRenderTree/assets/run_reliability_tests.py
@@ -195,8 +195,18 @@
while not DumpRenderTreeFinished(adb_cmd):
logging.error("DumpRenderTree exited before all URLs are visited.")
shell_cmd_str = adb_cmd + " shell cat " + TEST_STATUS_FILE
- crashed_test = subprocess.Popen(shell_cmd_str, shell=True,
- stdout=subprocess.PIPE).communicate()[0]
+ crashed_test = ""
+ while not crashed_test:
+ (crashed_test, err) = subprocess.Popen(
+ shell_cmd_str, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).communicate()
+ crashed_test = crashed_test.strip()
+ if not crashed_test:
+ logging.error('Cannot get crashed test name, device offline?')
+ logging.error('stderr: ' + err)
+ logging.error('retrying in 10s...')
+ time.sleep(10)
+
logging.info(crashed_test + " CRASHED")
crashed_tests.append(crashed_test)
Bugreport(crashed_test, bugreport_dir, adb_cmd)
diff --git a/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java b/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java
index c562650..4dbcfdc 100644
--- a/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java
+++ b/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java
@@ -88,7 +88,7 @@
* @param projectCallback The {@link IProjectCallback} object to get information from
* the project.
* @param logger the object responsible for displaying warning/errors to the user.
- * @return an {@link ILayoutResult} object that contains the result of the layout.
+ * @return a new {@link ILayoutResult} object that contains the result of the layout.
* @since 4
*/
ILayoutResult computeLayout(IXmlPullParser layoutDescription,
@@ -123,7 +123,7 @@
* @param projectCallback The {@link IProjectCallback} object to get information from
* the project.
* @param logger the object responsible for displaying warning/errors to the user.
- * @return an {@link ILayoutResult} object that contains the result of the layout.
+ * @return a new {@link ILayoutResult} object that contains the result of the layout.
* @since 3
*/
@Deprecated
@@ -155,7 +155,7 @@
* @param projectCallback The {@link IProjectCallback} object to get information from
* the project.
* @param logger the object responsible for displaying warning/errors to the user.
- * @return an {@link ILayoutResult} object that contains the result of the layout.
+ * @return a new {@link ILayoutResult} object that contains the result of the layout.
* @deprecated Use {@link #computeLayout(IXmlPullParser, Object, int, int, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}
* @since 2
*/
@@ -187,7 +187,7 @@
* @param projectCallback The {@link IProjectCallback} object to get information from
* the project.
* @param logger the object responsible for displaying warning/errors to the user.
- * @return an {@link ILayoutResult} object that contains the result of the layout.
+ * @return a new {@link ILayoutResult} object that contains the result of the layout.
* @deprecated Use {@link #computeLayout(IXmlPullParser, Object, int, int, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}
* @since 1
*/
@@ -205,7 +205,7 @@
* until this method is called.
* <p/>The cache is not configuration dependent and should only be cleared when a
* resource changes (at this time only bitmaps and 9 patches go into the cache).
- * @param objectKey the key for the project.
+ * @param projectKey the key for the project.
* @since 1
*/
void clearCaches(Object projectKey);
diff --git a/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutResult.java b/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutResult.java
index 5a06349..2d8a210 100644
--- a/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutResult.java
+++ b/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutResult.java
@@ -23,13 +23,17 @@
* {@link ILayoutLibBridge#computeLayout(IXmlPullParser, int, int, String, java.util.Map, java.util.Map, java.util.Map, IFontLoader, ILayoutLibLog, ICustomViewLoader)}
*/
public interface ILayoutResult {
- /** Sucess return code */
+ /**
+ * Success return code
+ */
final static int SUCCESS = 0;
- /** Error return code.
- * <p/>See {@link #getErrorMessage()}
- */
+
+ /**
+ * Error return code, in which case an error message is guaranteed to be defined.
+ * @See {@link #getErrorMessage()}
+ */
final static int ERROR = 1;
-
+
/**
* Returns the result code.
* @see #SUCCESS
@@ -62,18 +66,18 @@
* Returns the list of children views.
*/
ILayoutViewInfo[] getChildren();
-
+
/**
* Returns the key associated with the node.
* @see IXmlPullParser#getViewKey()
*/
Object getViewKey();
-
+
/**
* Returns the name of the view.
*/
String getName();
-
+
/**
* Returns the left of the view bounds.
*/
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 55fe4ac..0888fd8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -1051,15 +1051,22 @@
// pass for now.
}
+ @SuppressWarnings("unused")
public void setInsets(IWindow window, int touchable, Rect contentInsets,
Rect visibleInsets) {
// pass for now.
}
+ @SuppressWarnings("unused")
public void setWallpaperPosition(IBinder window, float x, float y) {
// pass for now.
}
+ @SuppressWarnings("unused")
+ public void wallpaperOffsetsComplete(IBinder window) {
+ // pass for now.
+ }
+
public IBinder asBinder() {
// pass for now.
return null;
@@ -1114,7 +1121,7 @@
}
@SuppressWarnings("unused")
- public void dispatchWallpaperOffsets(float x, float y) {
+ public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
// pass for now.
}