Merge change I9c242127 into eclair
* changes:
PowerManagerService: Animate LCD backlight changes due to autobrightness support.
diff --git a/api/current.xml b/api/current.xml
index 8f83e39..47dc08a 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -99410,6 +99410,17 @@
visibility="public"
>
</field>
+<field name="ECLAIR_MR1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="Bundle"
extends="java.lang.Object"
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index e59a987..0f7ef22 100755
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -191,6 +191,7 @@
private int mLastCodeX;
private int mLastCodeY;
private int mCurrentKey = NOT_A_KEY;
+ private int mDownKey = NOT_A_KEY;
private long mLastKeyTime;
private long mCurrentKeyTime;
private int[] mKeyIndices = new int[12];
@@ -202,6 +203,10 @@
private boolean mAbortKey;
private Key mInvalidatedKey;
private Rect mClipRegion = new Rect(0, 0, 0, 0);
+ private boolean mPossiblePoly;
+ private SwipeTracker mSwipeTracker = new SwipeTracker();
+ private int mSwipeThreshold;
+ private boolean mDisambiguateSwipe;
// Variables for dealing with multiple pointers
private int mOldPointerCount = 1;
@@ -351,7 +356,10 @@
mPadding = new Rect(0, 0, 0, 0);
mMiniKeyboardCache = new HashMap<Key,View>();
mKeyBackground.getPadding(mPadding);
-
+
+ mSwipeThreshold = (int) (500 * getResources().getDisplayMetrics().density);
+ mDisambiguateSwipe = getResources().getBoolean(
+ com.android.internal.R.bool.config_swipeDisambiguation);
resetMultiTap();
initGestureDetector();
}
@@ -361,22 +369,49 @@
@Override
public boolean onFling(MotionEvent me1, MotionEvent me2,
float velocityX, float velocityY) {
+ if (mPossiblePoly) return false;
final float absX = Math.abs(velocityX);
final float absY = Math.abs(velocityY);
- if (velocityX > 500 && absY < absX) {
- swipeRight();
- return true;
- } else if (velocityX < -500 && absY < absX) {
- swipeLeft();
- return true;
- } else if (velocityY < -500 && absX < absY) {
- swipeUp();
- return true;
- } else if (velocityY > 500 && absX < 200) {
- swipeDown();
- return true;
- } else if (absX > 800 || absY > 800) {
- return true;
+ float deltaX = me2.getX() - me1.getX();
+ float deltaY = me2.getY() - me1.getY();
+ int travelX = getWidth() / 2; // Half the keyboard width
+ int travelY = getHeight() / 2; // Half the keyboard height
+ mSwipeTracker.computeCurrentVelocity(1000);
+ final float endingVelocityX = mSwipeTracker.getXVelocity();
+ final float endingVelocityY = mSwipeTracker.getYVelocity();
+ boolean sendDownKey = false;
+ if (velocityX > mSwipeThreshold && absY < absX && deltaX > travelX) {
+ if (mDisambiguateSwipe && endingVelocityX < velocityX / 4) {
+ sendDownKey = true;
+ } else {
+ swipeRight();
+ return true;
+ }
+ } else if (velocityX < -mSwipeThreshold && absY < absX && deltaX < -travelX) {
+ if (mDisambiguateSwipe && endingVelocityX > velocityX / 4) {
+ sendDownKey = true;
+ } else {
+ swipeLeft();
+ return true;
+ }
+ } else if (velocityY < -mSwipeThreshold && absX < absY && deltaY < -travelY) {
+ if (mDisambiguateSwipe && endingVelocityY > velocityY / 4) {
+ sendDownKey = true;
+ } else {
+ swipeUp();
+ return true;
+ }
+ } else if (velocityY > mSwipeThreshold && absX < absY / 2 && deltaY > travelY) {
+ if (mDisambiguateSwipe && endingVelocityY < velocityY / 4) {
+ sendDownKey = true;
+ } else {
+ swipeDown();
+ return true;
+ }
+ }
+
+ if (sendDownKey) {
+ detectAndSendKey(mDownKey, mStartX, mStartY, me1.getEventTime());
}
return false;
}
@@ -743,8 +778,7 @@
return primaryIndex;
}
- private void detectAndSendKey(int x, int y, long eventTime) {
- int index = mCurrentKey;
+ private void detectAndSendKey(int index, int x, int y, long eventTime) {
if (index != NOT_A_KEY && index < mKeys.length) {
final Key key = mKeys[index];
if (key.text != null) {
@@ -1026,51 +1060,64 @@
return false;
}
+ private long mOldEventTime;
+ private boolean mUsedVelocity;
+
@Override
public boolean onTouchEvent(MotionEvent me) {
// Convert multi-pointer up/down events to single up/down events to
// deal with the typical multi-pointer behavior of two-thumb typing
- int pointerCount = me.getPointerCount();
+ final int pointerCount = me.getPointerCount();
+ final int action = me.getAction();
boolean result = false;
+ final long now = me.getEventTime();
+
if (pointerCount != mOldPointerCount) {
- long now = me.getEventTime();
if (pointerCount == 1) {
// Send a down event for the latest pointer
MotionEvent down = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
me.getX(), me.getY(), me.getMetaState());
- result = onModifiedTouchEvent(down);
+ result = onModifiedTouchEvent(down, false);
down.recycle();
// If it's an up action, then deliver the up as well.
- if (me.getAction() == MotionEvent.ACTION_UP) {
- result = onModifiedTouchEvent(me);
+ if (action == MotionEvent.ACTION_UP) {
+ result = onModifiedTouchEvent(me, true);
}
} else {
// Send an up event for the last pointer
MotionEvent up = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP,
mOldPointerX, mOldPointerY, me.getMetaState());
- result = onModifiedTouchEvent(up);
+ result = onModifiedTouchEvent(up, true);
up.recycle();
}
} else {
if (pointerCount == 1) {
+ result = onModifiedTouchEvent(me, false);
mOldPointerX = me.getX();
mOldPointerY = me.getY();
- result = onModifiedTouchEvent(me);
} else {
// Don't do anything when 2 pointers are down and moving.
result = true;
}
}
mOldPointerCount = pointerCount;
+
return result;
}
- private boolean onModifiedTouchEvent(MotionEvent me) {
+ private boolean onModifiedTouchEvent(MotionEvent me, boolean possiblePoly) {
int touchX = (int) me.getX() - mPaddingLeft;
int touchY = (int) me.getY() + mVerticalCorrection - mPaddingTop;
- int action = me.getAction();
- long eventTime = me.getEventTime();
+ final int action = me.getAction();
+ final long eventTime = me.getEventTime();
+ mOldEventTime = eventTime;
int keyIndex = getKeyIndices(touchX, touchY, null);
+ mPossiblePoly = possiblePoly;
+
+ // Track the last few movements to look for spurious swipes.
+ if (action == MotionEvent.ACTION_DOWN) mSwipeTracker.clear();
+ mSwipeTracker.addMovement(me);
+
if (mGestureDetector.onTouchEvent(me)) {
showPreview(NOT_A_KEY);
mHandler.removeMessages(MSG_REPEAT);
@@ -1095,6 +1142,7 @@
mCurrentKeyTime = 0;
mLastKey = NOT_A_KEY;
mCurrentKey = keyIndex;
+ mDownKey = keyIndex;
mDownTime = me.getEventTime();
mLastMoveTime = mDownTime;
checkMultiTap(eventTime, keyIndex);
@@ -1167,11 +1215,17 @@
Arrays.fill(mKeyIndices, NOT_A_KEY);
// If we're not on a repeating key (which sends on a DOWN event)
if (mRepeatKeyIndex == NOT_A_KEY && !mMiniKeyboardOnScreen && !mAbortKey) {
- detectAndSendKey(touchX, touchY, eventTime);
+ detectAndSendKey(mCurrentKey, touchX, touchY, eventTime);
}
invalidateKey(keyIndex);
mRepeatKeyIndex = NOT_A_KEY;
break;
+ case MotionEvent.ACTION_CANCEL:
+ removeMessages();
+ mAbortKey = true;
+ showPreview(NOT_A_KEY);
+ invalidateKey(mCurrentKey);
+ break;
}
mLastX = touchX;
mLastY = touchY;
@@ -1180,7 +1234,7 @@
private boolean repeatKey() {
Key key = mKeys[mRepeatKeyIndex];
- detectAndSendKey(key.x, key.y, mLastTapTime);
+ detectAndSendKey(mCurrentKey, key.x, key.y, mLastTapTime);
return true;
}
@@ -1265,4 +1319,114 @@
resetMultiTap();
}
}
+
+ private static class SwipeTracker {
+
+ static final int NUM_PAST = 4;
+ static final int LONGEST_PAST_TIME = 200;
+
+ final float mPastX[] = new float[NUM_PAST];
+ final float mPastY[] = new float[NUM_PAST];
+ final long mPastTime[] = new long[NUM_PAST];
+
+ float mYVelocity;
+ float mXVelocity;
+
+ public void clear() {
+ mPastTime[0] = 0;
+ }
+
+ public void addMovement(MotionEvent ev) {
+ long time = ev.getEventTime();
+ final int N = ev.getHistorySize();
+ for (int i=0; i<N; i++) {
+ addPoint(ev.getHistoricalX(i), ev.getHistoricalY(i),
+ ev.getHistoricalEventTime(i));
+ }
+ addPoint(ev.getX(), ev.getY(), time);
+ }
+
+ private void addPoint(float x, float y, long time) {
+ int drop = -1;
+ int i;
+ final long[] pastTime = mPastTime;
+ for (i=0; i<NUM_PAST; i++) {
+ if (pastTime[i] == 0) {
+ break;
+ } else if (pastTime[i] < time-LONGEST_PAST_TIME) {
+ drop = i;
+ }
+ }
+ if (i == NUM_PAST && drop < 0) {
+ drop = 0;
+ }
+ if (drop == i) drop--;
+ final float[] pastX = mPastX;
+ final float[] pastY = mPastY;
+ if (drop >= 0) {
+ final int start = drop+1;
+ final int count = NUM_PAST-drop-1;
+ System.arraycopy(pastX, start, pastX, 0, count);
+ System.arraycopy(pastY, start, pastY, 0, count);
+ System.arraycopy(pastTime, start, pastTime, 0, count);
+ i -= (drop+1);
+ }
+ pastX[i] = x;
+ pastY[i] = y;
+ pastTime[i] = time;
+ i++;
+ if (i < NUM_PAST) {
+ pastTime[i] = 0;
+ }
+ }
+
+ public void computeCurrentVelocity(int units) {
+ computeCurrentVelocity(units, Float.MAX_VALUE);
+ }
+
+ public void computeCurrentVelocity(int units, float maxVelocity) {
+ final float[] pastX = mPastX;
+ final float[] pastY = mPastY;
+ final long[] pastTime = mPastTime;
+
+ final float oldestX = pastX[0];
+ final float oldestY = pastY[0];
+ final long oldestTime = pastTime[0];
+ float accumX = 0;
+ float accumY = 0;
+ int N=0;
+ while (N < NUM_PAST) {
+ if (pastTime[N] == 0) {
+ break;
+ }
+ N++;
+ }
+
+ for (int i=1; i < N; i++) {
+ final int dur = (int)(pastTime[i] - oldestTime);
+ if (dur == 0) continue;
+ float dist = pastX[i] - oldestX;
+ float vel = (dist/dur) * units; // pixels/frame.
+ if (accumX == 0) accumX = vel;
+ else accumX = (accumX + vel) * .5f;
+
+ dist = pastY[i] - oldestY;
+ vel = (dist/dur) * units; // pixels/frame.
+ if (accumY == 0) accumY = vel;
+ else accumY = (accumY + vel) * .5f;
+ }
+ mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity)
+ : Math.min(accumX, maxVelocity);
+ mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity)
+ : Math.min(accumY, maxVelocity);
+ }
+
+ public float getXVelocity() {
+ return mXVelocity;
+ }
+
+ public float getYVelocity() {
+ return mYVelocity;
+ }
+ }
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 0f8bc08..d4aaba3 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -103,16 +103,19 @@
* October 2008: The original, first, version of Android. Yay!
*/
public static final int BASE = 1;
+
/**
* February 2009: First Android update, officially called 1.1.
*/
public static final int BASE_1_1 = 2;
+
/**
* May 2009: Android 1.5.
*/
public static final int CUPCAKE = 3;
+
/**
- * Current work on "Donut" development branch.
+ * September 2009: Android 1.6.
*
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
@@ -133,8 +136,9 @@
* </ul>
*/
public static final int DONUT = 4;
+
/**
- * Current work on "Eclair" development branch.
+ * November 2009: Android 2.0
*
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
@@ -152,6 +156,11 @@
* </ul>
*/
public static final int ECLAIR = 5;
+
+ /**
+ * Current work on Eclair MR1.
+ */
+ public static final int ECLAIR_MR1 = 6;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 86685fb..a5a4852 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1643,8 +1643,6 @@
final DrawFilter mZoomFilter =
new PaintFlagsDrawFilter(ZOOM_BITS, Paint.LINEAR_TEXT_FLAG);
- final DrawFilter mScrollFilter =
- new PaintFlagsDrawFilter(SCROLL_BITS, 0);
/* package */ void drawContentPicture(Canvas canvas, int color,
boolean animatingZoom,
@@ -1653,7 +1651,7 @@
if (animatingZoom) {
df = mZoomFilter;
} else if (animatingScroll) {
- df = mScrollFilter;
+ df = null;
}
canvas.setDrawFilter(df);
boolean tookTooLong = nativeDrawContent(canvas, color);
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 057e10a..bd6e7b4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -204,4 +204,7 @@
This must be overridden in platform specific overlays -->
<integer-array name="config_autoBrightnessKeyboardBacklightValues">
</integer-array>
+
+ <!-- Enables swipe versus poly-finger touch disambiguation in the KeyboardView -->
+ <bool name="config_swipeDisambiguation">true</bool>
</resources>
diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java
index 35f0409..e1e09b9 100644
--- a/media/java/android/media/AsyncPlayer.java
+++ b/media/java/android/media/AsyncPlayer.java
@@ -19,10 +19,12 @@
import android.content.Context;
import android.net.Uri;
import android.os.PowerManager;
+import android.os.SystemClock;
import android.util.Log;
import java.io.IOException;
import java.lang.IllegalStateException;
+import java.util.LinkedList;
/**
* Plays a series of audio URIs, but does all the hard work on another thread
@@ -31,14 +33,15 @@
public class AsyncPlayer {
private static final int PLAY = 1;
private static final int STOP = 2;
+ private static final boolean mDebug = false;
private static final class Command {
- Command next;
int code;
Context context;
Uri uri;
boolean looping;
int stream;
+ long requestTime;
public String toString() {
return "{ code=" + code + " looping=" + looping + " stream=" + stream
@@ -46,6 +49,36 @@
}
}
+ private LinkedList<Command> mCmdQueue = new LinkedList();
+
+ private void startSound(Command cmd) {
+ // Preparing can be slow, so if there is something else
+ // is playing, let it continue until we're done, so there
+ // is less of a glitch.
+ try {
+ if (mDebug) Log.d(mTag, "Starting playback");
+ MediaPlayer player = new MediaPlayer();
+ player.setAudioStreamType(cmd.stream);
+ player.setDataSource(cmd.context, cmd.uri);
+ player.setLooping(cmd.looping);
+ player.prepare();
+ player.start();
+ if (mPlayer != null) {
+ mPlayer.release();
+ }
+ mPlayer = player;
+ long delay = SystemClock.uptimeMillis() - cmd.requestTime;
+ if (delay > 1000) {
+ Log.w(mTag, "Notification sound delayed by " + delay + "msecs");
+ }
+ }
+ catch (IOException e) {
+ Log.w(mTag, "error loading sound for " + cmd.uri, e);
+ } catch (IllegalStateException e) {
+ Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e);
+ }
+ }
+
private final class Thread extends java.lang.Thread {
Thread() {
super("AsyncPlayer-" + mTag);
@@ -55,41 +88,23 @@
while (true) {
Command cmd = null;
- synchronized (mLock) {
- if (mHead != null) {
- cmd = mHead;
- mHead = cmd.next;
- if (mTail == cmd) {
- mTail = null;
- }
- }
+ synchronized (mCmdQueue) {
+ if (mDebug) Log.d(mTag, "RemoveFirst");
+ cmd = mCmdQueue.removeFirst();
}
switch (cmd.code) {
case PLAY:
- try {
- // Preparing can be slow, so if there is something else
- // is playing, let it continue until we're done, so there
- // is less of a glitch.
- MediaPlayer player = new MediaPlayer();
- player.setAudioStreamType(cmd.stream);
- player.setDataSource(cmd.context, cmd.uri);
- player.setLooping(cmd.looping);
- player.prepare();
- player.start();
- if (mPlayer != null) {
- mPlayer.release();
- }
- mPlayer = player;
- }
- catch (IOException e) {
- Log.w(mTag, "error loading sound for " + cmd.uri, e);
- } catch (IllegalStateException e) {
- Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e);
- }
+ if (mDebug) Log.d(mTag, "PLAY");
+ startSound(cmd);
break;
case STOP:
+ if (mDebug) Log.d(mTag, "STOP");
if (mPlayer != null) {
+ long delay = SystemClock.uptimeMillis() - cmd.requestTime;
+ if (delay > 1000) {
+ Log.w(mTag, "Notification stop delayed by " + delay + "msecs");
+ }
mPlayer.stop();
mPlayer.release();
mPlayer = null;
@@ -99,8 +114,8 @@
break;
}
- synchronized (mLock) {
- if (mHead == null) {
+ synchronized (mCmdQueue) {
+ if (mCmdQueue.size() == 0) {
// nothing left to do, quit
// doing this check after we're done prevents the case where they
// added it during the operation from spawning two threads and
@@ -115,11 +130,8 @@
}
private String mTag;
- private Command mHead;
- private Command mTail;
private Thread mThread;
private MediaPlayer mPlayer;
- private Object mLock = new Object();
private PowerManager.WakeLock mWakeLock;
// The current state according to the caller. Reality lags behind
@@ -154,12 +166,13 @@
*/
public void play(Context context, Uri uri, boolean looping, int stream) {
Command cmd = new Command();
+ cmd.requestTime = SystemClock.uptimeMillis();
cmd.code = PLAY;
cmd.context = context;
cmd.uri = uri;
cmd.looping = looping;
cmd.stream = stream;
- synchronized (mLock) {
+ synchronized (mCmdQueue) {
enqueueLocked(cmd);
mState = PLAY;
}
@@ -170,11 +183,12 @@
* at this point. Calling this multiple times has no ill effects.
*/
public void stop() {
- synchronized (mLock) {
+ synchronized (mCmdQueue) {
// This check allows stop to be called multiple times without starting
// a thread that ends up doing nothing.
if (mState != STOP) {
Command cmd = new Command();
+ cmd.requestTime = SystemClock.uptimeMillis();
cmd.code = STOP;
enqueueLocked(cmd);
mState = STOP;
@@ -183,12 +197,7 @@
}
private void enqueueLocked(Command cmd) {
- if (mTail == null) {
- mHead = cmd;
- } else {
- mTail.next = cmd;
- }
- mTail = cmd;
+ mCmdQueue.add(cmd);
if (mThread == null) {
acquireWakeLock();
mThread = new Thread();
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index c695dd7..a4cf4f5 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -81,7 +81,7 @@
private boolean mPendingRestartRadio = false;
private static final int TIME_DELAYED_TO_RESTART_RADIO =
- SystemProperties.getInt("ro.cdma.timetoradiorestart", 20000);
+ SystemProperties.getInt("ro.cdma.timetoradiorestart", 60000);
/**
* Pool size of CdmaDataConnection objects.