summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/java/android/app/ApplicationContext.java19
-rw-r--r--core/java/android/content/Context.java13
-rwxr-xr-xcore/java/android/inputmethodservice/KeyboardView.java222
-rw-r--r--core/java/android/os/DropBox.aidl (renamed from core/java/android/os/DropBoxEntry.aidl)2
-rw-r--r--core/java/android/os/DropBox.java276
-rw-r--r--core/java/android/os/DropBoxEntry.java163
-rw-r--r--core/java/android/os/IDropBox.aidl92
-rw-r--r--core/java/android/provider/Telephony.java2
-rw-r--r--core/java/android/webkit/WebTextView.java114
-rw-r--r--core/java/android/webkit/WebView.java137
-rw-r--r--core/java/android/webkit/WebViewCore.java16
-rw-r--r--core/java/com/android/internal/os/IDropBoxService.aidl42
-rw-r--r--core/jni/android/graphics/Canvas.cpp42
-rw-r--r--core/jni/android/graphics/Graphics.cpp10
-rw-r--r--core/jni/android/graphics/GraphicsJNI.h13
-rw-r--r--core/res/res/values/config.xml3
16 files changed, 725 insertions, 441 deletions
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index f48f150..305ee6a 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -70,6 +70,7 @@ import android.net.wifi.IWifiManager;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Bundle;
+import android.os.DropBox;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
@@ -93,6 +94,8 @@ import android.view.inputmethod.InputMethodManager;
import android.accounts.AccountManager;
import android.accounts.IAccountManager;
+import com.android.internal.os.IDropBoxService;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -182,6 +185,7 @@ class ApplicationContext extends Context {
private ClipboardManager mClipboardManager = null;
private boolean mRestricted;
private AccountManager mAccountManager; // protected by mSync
+ private DropBox mDropBox = null;
private final Object mSync = new Object();
@@ -896,6 +900,8 @@ class ApplicationContext extends Context {
return getClipboardManager();
} else if (WALLPAPER_SERVICE.equals(name)) {
return getWallpaperManager();
+ } else if (DROPBOX_SERVICE.equals(name)) {
+ return getDropBox();
}
return null;
@@ -1045,7 +1051,7 @@ class ApplicationContext extends Context {
}
return mVibrator;
}
-
+
private AudioManager getAudioManager()
{
if (mAudioManager == null) {
@@ -1054,6 +1060,17 @@ class ApplicationContext extends Context {
return mAudioManager;
}
+ private DropBox getDropBox() {
+ synchronized (mSync) {
+ if (mDropBox == null) {
+ IBinder b = ServiceManager.getService(DROPBOX_SERVICE);
+ IDropBoxService service = IDropBoxService.Stub.asInterface(b);
+ mDropBox = new DropBox(service);
+ }
+ }
+ return mDropBox;
+ }
+
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 8f1c671..b4ab408 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1309,7 +1309,7 @@ public abstract class Context {
* @see #getSystemService
*/
public static final String APPWIDGET_SERVICE = "appwidget";
-
+
/**
* Use with {@link #getSystemService} to retrieve an
* {@blink android.backup.IBackupManager IBackupManager} for communicating
@@ -1319,7 +1319,16 @@ public abstract class Context {
* @see #getSystemService
*/
public static final String BACKUP_SERVICE = "backup";
-
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@blink android.os.DropBox DropBox} instance for recording
+ * diagnostic logs.
+ * @hide
+ * @see #getSystemService
+ */
+ public static final String DROPBOX_SERVICE = "dropbox";
+
/**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
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 @@ public class KeyboardView extends View implements View.OnClickListener {
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 @@ public class KeyboardView extends View implements View.OnClickListener {
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 @@ public class KeyboardView extends View implements View.OnClickListener {
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 @@ public class KeyboardView extends View implements View.OnClickListener {
@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 @@ public class KeyboardView extends View implements View.OnClickListener {
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 @@ public class KeyboardView extends View implements View.OnClickListener {
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 @@ public class KeyboardView extends View implements View.OnClickListener {
mCurrentKeyTime = 0;
mLastKey = NOT_A_KEY;
mCurrentKey = keyIndex;
+ mDownKey = keyIndex;
mDownTime = me.getEventTime();
mLastMoveTime = mDownTime;
checkMultiTap(eventTime, keyIndex);
@@ -1167,11 +1215,17 @@ public class KeyboardView extends View implements View.OnClickListener {
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 @@ public class KeyboardView extends View implements View.OnClickListener {
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 @@ public class KeyboardView extends View implements View.OnClickListener {
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/DropBoxEntry.aidl b/core/java/android/os/DropBox.aidl
index 225eee1..77abd22 100644
--- a/core/java/android/os/DropBoxEntry.aidl
+++ b/core/java/android/os/DropBox.aidl
@@ -16,4 +16,4 @@
package android.os;
-parcelable DropBoxEntry;
+parcelable DropBox.Entry;
diff --git a/core/java/android/os/DropBox.java b/core/java/android/os/DropBox.java
new file mode 100644
index 0000000..0551dc1
--- /dev/null
+++ b/core/java/android/os/DropBox.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.util.Log;
+
+import com.android.internal.os.IDropBoxService;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * Enqueues chunks of data (from various sources -- application crashes, kernel
+ * log records, etc.). The queue is size bounded and will drop old data if the
+ * enqueued data exceeds the maximum size. You can think of this as a
+ * persistent, system-wide, blob-oriented "logcat".
+ *
+ * <p>You can obtain an instance of this class by calling
+ * {@link android.content.Context#getSystemService}
+ * with {@link android.content.Context#DROPBOX_SERVICE}.
+ *
+ * <p>DropBox entries are not sent anywhere directly, but other system services
+ * and debugging tools may scan and upload entries for processing.
+ *
+ * {@pending}
+ */
+public class DropBox {
+ private static final String TAG = "DropBox";
+ private final IDropBoxService mService;
+
+ /** Flag value: Entry's content was deleted to save space. */
+ public static final int IS_EMPTY = 1;
+
+ /** Flag value: Content is human-readable UTF-8 text (can be combined with IS_GZIPPED). */
+ public static final int IS_TEXT = 2;
+
+ /** Flag value: Content can be decompressed with {@link GZIPOutputStream}. */
+ public static final int IS_GZIPPED = 4;
+
+ /**
+ * A single entry retrieved from the drop box.
+ * This may include a reference to a stream, so you must call
+ * {@link #close()} when you are done using it.
+ */
+ public static class Entry implements Parcelable {
+ private final String mTag;
+ private final long mTimeMillis;
+
+ private final byte[] mData;
+ private final ParcelFileDescriptor mFileDescriptor;
+ private final int mFlags;
+
+ /** Create a new empty Entry with no contents. */
+ public Entry(String tag, long millis) {
+ this(tag, millis, (Object) null, IS_EMPTY);
+ }
+
+ /** Create a new Entry with plain text contents. */
+ public Entry(String tag, long millis, String text) {
+ this(tag, millis, (Object) text.getBytes(), IS_TEXT);
+ }
+
+ /**
+ * Create a new Entry with byte array contents.
+ * The data array must not be modified after creating this entry.
+ */
+ public Entry(String tag, long millis, byte[] data, int flags) {
+ this(tag, millis, (Object) data, flags);
+ }
+
+ /**
+ * Create a new Entry with streaming data contents.
+ * Takes ownership of the ParcelFileDescriptor.
+ */
+ public Entry(String tag, long millis, ParcelFileDescriptor data, int flags) {
+ this(tag, millis, (Object) data, flags);
+ }
+
+ /**
+ * Create a new Entry with the contents read from a file.
+ * The file will be read when the entry's contents are requested.
+ */
+ public Entry(String tag, long millis, File data, int flags) throws IOException {
+ this(tag, millis, (Object) ParcelFileDescriptor.open(
+ data, ParcelFileDescriptor.MODE_READ_ONLY), flags);
+ }
+
+ /** Internal constructor for CREATOR.createFromParcel(). */
+ private Entry(String tag, long millis, Object value, int flags) {
+ if (tag == null) throw new NullPointerException();
+ if (((flags & IS_EMPTY) != 0) != (value == null)) throw new IllegalArgumentException();
+
+ mTag = tag;
+ mTimeMillis = millis;
+ mFlags = flags;
+
+ if (value == null) {
+ mData = null;
+ mFileDescriptor = null;
+ } else if (value instanceof byte[]) {
+ mData = (byte[]) value;
+ mFileDescriptor = null;
+ } else if (value instanceof ParcelFileDescriptor) {
+ mData = null;
+ mFileDescriptor = (ParcelFileDescriptor) value;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /** Close the input stream associated with this entry. */
+ public void close() {
+ try { if (mFileDescriptor != null) mFileDescriptor.close(); } catch (IOException e) { }
+ }
+
+ /** @return the tag originally attached to the entry. */
+ public String getTag() { return mTag; }
+
+ /** @return time when the entry was originally created. */
+ public long getTimeMillis() { return mTimeMillis; }
+
+ /** @return flags describing the content returned by @{link #getInputStream()}. */
+ public int getFlags() { return mFlags & ~IS_GZIPPED; } // getInputStream() decompresses.
+
+ /**
+ * @param maxBytes of string to return (will truncate at this length).
+ * @return the uncompressed text contents of the entry, null if the entry is not text.
+ */
+ public String getText(int maxBytes) {
+ if ((mFlags & IS_TEXT) == 0) return null;
+ if (mData != null) return new String(mData, 0, Math.min(maxBytes, mData.length));
+
+ InputStream is = null;
+ try {
+ is = getInputStream();
+ byte[] buf = new byte[maxBytes];
+ return new String(buf, 0, Math.max(0, is.read(buf)));
+ } catch (IOException e) {
+ return null;
+ } finally {
+ try { if (is != null) is.close(); } catch (IOException e) {}
+ }
+ }
+
+ /** @return the uncompressed contents of the entry, or null if the contents were lost */
+ public InputStream getInputStream() throws IOException {
+ InputStream is;
+ if (mData != null) {
+ is = new ByteArrayInputStream(mData);
+ } else if (mFileDescriptor != null) {
+ is = new ParcelFileDescriptor.AutoCloseInputStream(mFileDescriptor);
+ } else {
+ return null;
+ }
+ return (mFlags & IS_GZIPPED) != 0 ? new GZIPInputStream(is) : is;
+ }
+
+ public static final Parcelable.Creator<Entry> CREATOR = new Parcelable.Creator() {
+ public Entry[] newArray(int size) { return new Entry[size]; }
+ public Entry createFromParcel(Parcel in) {
+ return new Entry(
+ in.readString(), in.readLong(), in.readValue(null), in.readInt());
+ }
+ };
+
+ public int describeContents() {
+ return mFileDescriptor != null ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mTag);
+ out.writeLong(mTimeMillis);
+ if (mFileDescriptor != null) {
+ out.writeValue(mFileDescriptor);
+ } else {
+ out.writeValue(mData);
+ }
+ out.writeInt(mFlags);
+ }
+ }
+
+ /** {@hide} */
+ public DropBox(IDropBoxService service) { mService = service; }
+
+ /**
+ * Create a dummy instance for testing. All methods will fail unless
+ * overridden with an appropriate mock implementation. To obtain a
+ * functional instance, use {@link android.content.Context#getSystemService}.
+ */
+ protected DropBox() { mService = null; }
+
+ /**
+ * Stores human-readable text. The data may be discarded eventually (or even
+ * immediately) if space is limited, or ignored entirely if the tag has been
+ * blocked (see {@link #isTagEnabled}).
+ *
+ * @param tag describing the type of entry being stored
+ * @param data value to store
+ */
+ public void addText(String tag, String data) {
+ try { mService.add(new Entry(tag, 0, data)); } catch (RemoteException e) {}
+ }
+
+ /**
+ * Stores binary data, which may be ignored or discarded as with {@link #addText}.
+ *
+ * @param tag describing the type of entry being stored
+ * @param data value to store
+ * @param flags describing the data
+ */
+ public void addData(String tag, byte[] data, int flags) {
+ if (data == null) throw new NullPointerException();
+ try { mService.add(new Entry(tag, 0, data, flags)); } catch (RemoteException e) {}
+ }
+
+ /**
+ * Stores data read from a file descriptor. The data may be ignored or
+ * discarded as with {@link #addText}. You must close your
+ * ParcelFileDescriptor object after calling this method!
+ *
+ * @param tag describing the type of entry being stored
+ * @param fd file descriptor to read from
+ * @param flags describing the data
+ */
+ public void addFile(String tag, ParcelFileDescriptor fd, int flags) {
+ if (fd == null) throw new NullPointerException();
+ try { mService.add(new Entry(tag, 0, fd, flags)); } catch (RemoteException e) {}
+ }
+
+ /**
+ * Checks any blacklists (set in system settings) to see whether a certain
+ * tag is allowed. Entries with disabled tags will be dropped immediately,
+ * so you can save the work of actually constructing and sending the data.
+ *
+ * @param tag that would be used in {@link #addText} or {@link #addFile}
+ * @return whether events with that tag would be accepted
+ */
+ public boolean isTagEnabled(String tag) {
+ try { return mService.isTagEnabled(tag); } catch (RemoteException e) { return false; }
+ }
+
+ /**
+ * Gets the next entry from the drop box *after* the specified time.
+ * Requires android.permission.READ_LOGS. You must always call
+ * {@link Entry#close()} on the return value!
+ *
+ * @param tag of entry to look for, null for all tags
+ * @param msec time of the last entry seen
+ * @return the next entry, or null if there are no more entries
+ */
+ public Entry getNextEntry(String tag, long msec) {
+ try { return mService.getNextEntry(tag, msec); } catch (RemoteException e) { return null; }
+ }
+
+ // TODO: It may be useful to have some sort of notification mechanism
+ // when data is added to the dropbox, for demand-driven readers --
+ // for now readers need to poll the dropbox to find new data.
+}
diff --git a/core/java/android/os/DropBoxEntry.java b/core/java/android/os/DropBoxEntry.java
deleted file mode 100644
index e3816a8..0000000
--- a/core/java/android/os/DropBoxEntry.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.zip.GZIPInputStream;
-
-/**
- * A single entry retrieved from an {@link IDropBox} implementation.
- * This may include a reference to a stream, so you must call
- * {@link #close()} when you are done using it.
- *
- * {@pending}
- */
-public class DropBoxEntry implements Parcelable {
- private final String mTag;
- private final long mTimeMillis;
-
- private final String mText;
- private final ParcelFileDescriptor mFileDescriptor;
- private final int mFlags;
-
- /** Flag value: Entry's content was deleted to save space. */
- public static final int IS_EMPTY = 1;
-
- /** Flag value: Content is human-readable UTF-8 text (possibly compressed). */
- public static final int IS_TEXT = 2;
-
- /** Flag value: Content can been decompressed with {@link GZIPOutputStream}. */
- public static final int IS_GZIPPED = 4;
-
- /** Create a new DropBoxEntry with the specified contents. */
- public DropBoxEntry(String tag, long timeMillis, String text) {
- if (tag == null || text == null) throw new NullPointerException();
- mTag = tag;
- mTimeMillis = timeMillis;
- mText = text;
- mFileDescriptor = null;
- mFlags = IS_TEXT;
- }
-
- /** Create a new DropBoxEntry with the specified contents. */
- public DropBoxEntry(String tag, long millis, File data, int flags) throws IOException {
- if (tag == null) throw new NullPointerException();
- if (((flags & IS_EMPTY) != 0) != (data == null)) throw new IllegalArgumentException();
-
- mTag = tag;
- mTimeMillis = millis;
- mText = null;
- mFlags = flags;
- mFileDescriptor = data == null ? null :
- ParcelFileDescriptor.open(data, ParcelFileDescriptor.MODE_READ_ONLY);
- }
-
- /** Internal constructor for CREATOR.createFromParcel(). */
- private DropBoxEntry(String tag, long millis, Object value, int flags) {
- if (tag == null) throw new NullPointerException();
- if (((flags & IS_EMPTY) != 0) != (value == null)) throw new IllegalArgumentException();
-
- mTag = tag;
- mTimeMillis = millis;
- mFlags = flags;
-
- if (value == null) {
- mText = null;
- mFileDescriptor = null;
- } else if (value instanceof String) {
- if ((flags & IS_TEXT) == 0) throw new IllegalArgumentException();
- mText = (String) value;
- mFileDescriptor = null;
- } else if (value instanceof ParcelFileDescriptor) {
- mText = null;
- mFileDescriptor = (ParcelFileDescriptor) value;
- } else {
- throw new IllegalArgumentException();
- }
- }
-
- /** Close the input stream associated with this entry. */
- public synchronized void close() {
- try { if (mFileDescriptor != null) mFileDescriptor.close(); } catch (IOException e) { }
- }
-
- /** @return the tag originally attached to the entry. */
- public String getTag() { return mTag; }
-
- /** @return time when the entry was originally created. */
- public long getTimeMillis() { return mTimeMillis; }
-
- /** @return flags describing the content returned by @{link #getInputStream()}. */
- public int getFlags() { return mFlags & ~IS_GZIPPED; } // getInputStream() decompresses.
-
- /**
- * @param maxLength of string to return (will truncate at this length).
- * @return the uncompressed text contents of the entry, null if the entry is not text.
- */
- public String getText(int maxLength) {
- if (mText != null) return mText.substring(0, Math.min(maxLength, mText.length()));
- if ((mFlags & IS_TEXT) == 0) return null;
-
- try {
- InputStream stream = getInputStream();
- if (stream == null) return null;
- char[] buf = new char[maxLength];
- InputStreamReader reader = new InputStreamReader(stream);
- return new String(buf, 0, Math.max(0, reader.read(buf)));
- } catch (IOException e) {
- return null;
- }
- }
-
- /** @return the uncompressed contents of the entry, or null if the contents were lost */
- public InputStream getInputStream() throws IOException {
- if (mText != null) return new ByteArrayInputStream(mText.getBytes("UTF8"));
- if (mFileDescriptor == null) return null;
- InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(mFileDescriptor);
- return (mFlags & IS_GZIPPED) != 0 ? new GZIPInputStream(is) : is;
- }
-
- public static final Parcelable.Creator<DropBoxEntry> CREATOR = new Parcelable.Creator() {
- public DropBoxEntry[] newArray(int size) { return new DropBoxEntry[size]; }
- public DropBoxEntry createFromParcel(Parcel in) {
- return new DropBoxEntry(
- in.readString(), in.readLong(), in.readValue(null), in.readInt());
- }
- };
-
- public int describeContents() {
- return mFileDescriptor != null ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(mTag);
- out.writeLong(mTimeMillis);
- if (mFileDescriptor != null) {
- out.writeValue(mFileDescriptor);
- } else {
- out.writeValue(mText);
- }
- out.writeInt(mFlags);
- }
-}
diff --git a/core/java/android/os/IDropBox.aidl b/core/java/android/os/IDropBox.aidl
deleted file mode 100644
index 26294b6..0000000
--- a/core/java/android/os/IDropBox.aidl
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import android.os.DropBoxEntry;
-import android.os.ParcelFileDescriptor;
-
-/**
- * Enqueues chunks of data (from various sources -- application crashes, kernel
- * log records, etc.). The queue is size bounded and will drop old data if the
- * enqueued data exceeds the maximum size.
- *
- * <p>This interface is implemented by a system service you can access:
- *
- * <pre>IDropBox.Stub.asInterface(ServiceManager.getService("dropbox"));</pre>
- *
- * <p>Other system services and debugging tools may scan the drop box to upload
- * entries for processing.
- *
- * {@pending}
- */
-interface IDropBox {
- /**
- * Stores human-readable text. The data may be discarded eventually (or even
- * immediately) if space is limited, or ignored entirely if the tag has been
- * blocked (see {@link #isTagEnabled}).
- *
- * @param tag describing the type of entry being stored
- * @param data value to store
- */
- void addText(String tag, String data);
-
- /**
- * Stores binary data. The data may be ignored or discarded as with
- * {@link #addText}.
- *
- * @param tag describing the type of entry being stored
- * @param data value to store
- * @param flags describing the data, defined in {@link DropBoxEntry}
- */
- void addData(String tag, in byte[] data, int flags);
-
- /**
- * Stores data read from a file descriptor. The data may be ignored or
- * discarded as with {@link #addText}. You must close your
- * ParcelFileDescriptor object after calling this method!
- *
- * @param tag describing the type of entry being stored
- * @param data file descriptor to read from
- * @param flags describing the data, defined in {@link DropBoxEntry}
- */
- void addFile(String tag, in ParcelFileDescriptor data, int flags);
-
- /**
- * Checks any blacklists (set in system settings) to see whether a certain
- * tag is allowed. Entries with disabled tags will be dropped immediately,
- * so you can save the work of actually constructing and sending the data.
- *
- * @param tag that would be used in {@link #addText} or {@link #addFile}
- * @return whether events with that tag would be accepted
- */
- boolean isTagEnabled(String tag);
-
- /**
- * Gets the next entry from the drop box *after* the specified time.
- * Requires android.permission.READ_LOGS. You must always call
- * {@link DropBoxEntry#close()} on the return value!
- *
- * @param tag of entry to look for, null for all tags
- * @param millis time of the last entry seen
- * @return the next entry, or null if there are no more entries
- */
- DropBoxEntry getNextEntry(String tag, long millis);
-
- // TODO: It may be useful to have some sort of notification mechanism
- // when data is added to the dropbox, for demand-driven readers --
- // for now readers need to poll the dropbox to find new data.
-}
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 042c75e..d8c5a53 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1669,6 +1669,8 @@ public final class Telephony {
public static final String NUMERIC = "numeric";
+ public static final String AUTH_TYPE = "authtype";
+
public static final String TYPE = "type";
public static final String CURRENT = "current";
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 4fafb65..71b1f9f 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -84,14 +84,24 @@ import java.util.ArrayList;
// True if the most recent drag event has caused either the TextView to
// scroll or the web page to scroll. Gets reset after a touch down.
private boolean mScrolled;
- // Gets set to true when the the IME jumps to the next textfield. When this
- // happens, the next time the user hits a key it is okay for the focus
- // pointer to not match the WebTextView's node pointer
+ // Gets set to true any time the WebTextView has focus, but the navigation
+ // cache does not yet know that the focus has been changed. This happens
+ // if the user presses "Next", if the user moves the cursor to a textfield
+ // and starts typing or clicks the trackball/center key, and when the user
+ // touches a textfield.
boolean mOkayForFocusNotToMatch;
- boolean mResendKeyDown;
// Whether or not a selection change was generated from webkit. If it was,
// we do not need to pass the selection back to webkit.
private boolean mFromWebKit;
+ // Whether or not a selection change was generated from the WebTextView
+ // gaining focus. If it is, we do not want to pass it to webkit. This
+ // selection comes from the MovementMethod, but we behave differently. If
+ // WebTextView gained focus from a touch, webkit will determine the
+ // selection.
+ private boolean mFromFocusChange;
+ // Whether or not a selection change was generated from setInputType. We
+ // do not want to pass this change to webkit.
+ private boolean mFromSetInputType;
private boolean mGotTouchDown;
private boolean mInSetTextAndKeepSelection;
// Array to store the final character added in onTextChanged, so that its
@@ -137,22 +147,23 @@ import java.util.ArrayList;
isArrowKey = true;
break;
}
- if (!isArrowKey && !mOkayForFocusNotToMatch && !mResendKeyDown
- && mWebView.nativeFocusNodePointer() != mNodePointer) {
- if (mWebView.nativeFocusNodePointer() != 0) {
+
+ if (down) {
+ if (mOkayForFocusNotToMatch) {
+ if (mWebView.nativeFocusNodePointer() == mNodePointer) {
+ mOkayForFocusNotToMatch = false;
+ }
+ } else if (mWebView.nativeFocusNodePointer() != mNodePointer
+ && !isArrowKey) {
mWebView.nativeClearCursor();
+ // Do not call remove() here, which hides the soft keyboard. If
+ // the soft keyboard is being displayed, the user will still want
+ // it there.
+ mWebView.removeView(this);
+ mWebView.requestFocus();
+ return mWebView.dispatchKeyEvent(event);
}
- // Do not call remove() here, which hides the soft keyboard. If
- // the soft keyboard is being displayed, the user will still want
- // it there.
- mWebView.removeView(this);
- mWebView.requestFocus();
- return mWebView.dispatchKeyEvent(event);
- }
- // After a jump to next textfield and the first key press, the cursor
- // and focus will once again match, so reset this value.
- mOkayForFocusNotToMatch = false;
- mResendKeyDown = false;
+ }
Spannable text = (Spannable) getText();
int oldLength = text.length();
// Normally the delete key's dom events are sent via onTextChanged.
@@ -306,15 +317,19 @@ import java.util.ArrayList;
public void onEditorAction(int actionCode) {
switch (actionCode) {
case EditorInfo.IME_ACTION_NEXT:
+ // Since the cursor will no longer be in the same place as the
+ // focus, set the focus controller back to inactive
+ mWebView.setFocusControllerInactive();
mWebView.nativeMoveCursorToNextTextInput();
+ mOkayForFocusNotToMatch = true;
+ // Pass the click to set the focus to the textfield which will now
+ // have the cursor.
+ mWebView.centerKeyPressOnTextField();
// Preemptively rebuild the WebTextView, so that the action will
// be set properly.
mWebView.rebuildWebTextView();
- // Since the cursor will no longer be in the same place as the
- // focus, set the focus controller back to inactive
- mWebView.setFocusControllerInactive();
+ setDefaultSelection();
mWebView.invalidate();
- mOkayForFocusNotToMatch = true;
break;
case EditorInfo.IME_ACTION_DONE:
super.onEditorAction(actionCode);
@@ -334,6 +349,14 @@ import java.util.ArrayList;
}
@Override
+ protected void onFocusChanged(boolean focused, int direction,
+ Rect previouslyFocusedRect) {
+ mFromFocusChange = true;
+ super.onFocusChanged(focused, direction, previouslyFocusedRect);
+ mFromFocusChange = false;
+ }
+
+ @Override
protected void onSelectionChanged(int selStart, int selEnd) {
// This code is copied from TextView.onDraw(). That code does not get
// executed, however, because the WebTextView does not draw, allowing
@@ -345,7 +368,8 @@ import java.util.ArrayList;
int candEnd = EditableInputConnection.getComposingSpanEnd(sp);
imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
}
- if (!mFromWebKit && mWebView != null) {
+ if (!mFromWebKit && !mFromFocusChange && !mFromSetInputType
+ && mWebView != null) {
if (DebugFlags.WEB_TEXT_VIEW) {
Log.v(LOGTAG, "onSelectionChanged selStart=" + selStart
+ " selEnd=" + selEnd);
@@ -594,6 +618,17 @@ import java.util.ArrayList;
}
/**
+ * Sets the selection when the user clicks on a textfield or textarea with
+ * the trackball or center key, or starts typing into it without clicking on
+ * it.
+ */
+ /* package */ void setDefaultSelection() {
+ Spannable text = (Spannable) getText();
+ int selection = mSingle ? text.length() : 0;
+ Selection. setSelection(text, selection, selection);
+ }
+
+ /**
* Determine whether to use the system-wide password disguising method,
* or to use none.
* @param inPassword True if the textfield is a password field.
@@ -663,6 +698,13 @@ import java.util.ArrayList;
setTextColor(Color.BLACK);
}
+ @Override
+ public void setInputType(int type) {
+ mFromSetInputType = true;
+ super.setInputType(type);
+ mFromSetInputType = false;
+ }
+
/* package */ void setMaxLength(int maxLength) {
mMaxLength = maxLength;
if (-1 == maxLength) {
@@ -764,32 +806,6 @@ import java.util.ArrayList;
}
/**
- * Set the text for this WebTextView, and set the selection to (start, end)
- * @param text Text to go into this WebTextView.
- * @param start Beginning of the selection.
- * @param end End of the selection.
- */
- /* package */ void setText(CharSequence text, int start, int end) {
- mPreChange = text.toString();
- setText(text);
- Spannable span = (Spannable) getText();
- int length = span.length();
- if (end > length) {
- end = length;
- }
- if (start < 0) {
- start = 0;
- } else if (start > length) {
- start = length;
- }
- if (DebugFlags.WEB_TEXT_VIEW) {
- Log.v(LOGTAG, "setText start=" + start
- + " end=" + end);
- }
- Selection.setSelection(span, start, end);
- }
-
- /**
* Set the text to the new string, but use the old selection, making sure
* to keep it within the new string.
* @param text The new text to place in the textfield.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index fabaf8c..304c927 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2971,11 +2971,12 @@ public class WebView extends AbsoluteLayout
if (mNativeClass == 0) return;
if (mShiftIsPressed && !animateZoom) {
- if (mTouchSelection) {
+ if (mTouchSelection || mExtendSelection) {
nativeDrawSelectionRegion(canvas);
- } else {
- nativeDrawSelection(canvas, mInvActualScale, getTitleHeight(),
- mSelectX, mSelectY, mExtendSelection);
+ }
+ if (!mTouchSelection) {
+ nativeDrawSelectionPointer(canvas, mInvActualScale, mSelectX,
+ mSelectY - getTitleHeight(), mExtendSelection);
}
} else if (drawCursorRing) {
if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
@@ -3094,6 +3095,16 @@ public class WebView extends AbsoluteLayout
imm.hideSoftInputFromWindow(this.getWindowToken(), 0);
}
+ /**
+ * Only for calling from JNI. Allows a click on an unfocused textfield to
+ * put the textfield in focus.
+ */
+ private void setOkayNotToMatch() {
+ if (inEditingMode()) {
+ mWebTextView.mOkayForFocusNotToMatch = true;
+ }
+ }
+
/*
* This method checks the current focus and cursor and potentially rebuilds
* mWebTextView to have the appropriate properties, such as password,
@@ -3149,6 +3160,7 @@ public class WebView extends AbsoluteLayout
&& nativeTextGeneration() == mTextGeneration) {
mWebTextView.setTextAndKeepSelection(text);
} else {
+ // FIXME: Determine whether this is necessary.
Selection.setSelection(spannable, start, end);
}
} else {
@@ -3181,34 +3193,12 @@ public class WebView extends AbsoluteLayout
mWebTextView.setSingleLine(isTextField);
mWebTextView.setInPassword(nativeFocusCandidateIsPassword());
if (null == text) {
- mWebTextView.setText("", 0, 0);
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "rebuildWebTextView null == text");
}
- } else {
- // Change to true to enable the old style behavior, where
- // entering a textfield/textarea always set the selection to the
- // whole field. This was desirable for the case where the user
- // intends to scroll past the field using the trackball.
- // However, it causes a problem when replying to emails - the
- // user expects the cursor to be at the beginning of the
- // textarea. Testing out a new behavior, where textfields set
- // selection at the end, and textareas at the beginning.
- if (false) {
- mWebTextView.setText(text, 0, text.length());
- } else if (isTextField) {
- int length = text.length();
- mWebTextView.setText(text, length, length);
- if (DebugFlags.WEB_VIEW) {
- Log.v(LOGTAG, "rebuildWebTextView length=" + length);
- }
- } else {
- mWebTextView.setText(text, 0, 0);
- if (DebugFlags.WEB_VIEW) {
- Log.v(LOGTAG, "rebuildWebTextView !isTextField");
- }
- }
+ text = "";
}
+ mWebTextView.setTextAndKeepSelection(text);
mWebTextView.requestFocus();
}
}
@@ -3275,18 +3265,8 @@ public class WebView extends AbsoluteLayout
if (mShiftIsPressed == false && nativeCursorWantsKeyEvents() == false
&& (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
|| keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)) {
- mExtendSelection = false;
- mShiftIsPressed = true;
- if (nativeHasCursorNode()) {
- Rect rect = nativeCursorNodeBounds();
- mSelectX = contentToViewX(rect.left);
- mSelectY = contentToViewY(rect.top);
- } else {
- mSelectX = mScrollX + (int) mLastTouchX;
- mSelectY = mScrollY + (int) mLastTouchY;
- }
- nativeHideCursor();
- }
+ setUpSelectXY();
+ }
if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
&& keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
@@ -3364,10 +3344,7 @@ public class WebView extends AbsoluteLayout
}
}
- if (nativeFocusCandidateIsPlugin()) {
- nativeUpdatePluginReceivesEvents();
- invalidate();
- } else if (nativeCursorIsTextInput()) {
+ if (nativeCursorIsTextInput()) {
// This message will put the node in focus, for the DOM's notion
// of focus, and make the focuscontroller active
mWebViewCore.sendMessage(EventHub.CLICK, nativeCursorFramePointer(),
@@ -3377,15 +3354,16 @@ public class WebView extends AbsoluteLayout
rebuildWebTextView();
// Now we need to pass the event to it
if (inEditingMode()) {
- mWebTextView.mResendKeyDown = true;
- return mWebTextView.onKeyDown(keyCode, event);
+ mWebTextView.setDefaultSelection();
+ mWebTextView.mOkayForFocusNotToMatch = true;
+ return mWebTextView.dispatchKeyEvent(event);
}
} else if (nativeHasFocusNode()) {
// In this case, the cursor is not on a text input, but the focus
// might be. Check it, and if so, hand over to the WebTextView.
rebuildWebTextView();
if (inEditingMode()) {
- return mWebTextView.onKeyDown(keyCode, event);
+ return mWebTextView.dispatchKeyEvent(event);
}
}
@@ -3454,6 +3432,7 @@ public class WebView extends AbsoluteLayout
commitCopy();
} else {
mExtendSelection = true;
+ invalidate(); // draw the i-beam instead of the arrow
}
return true; // discard press if copy in progress
}
@@ -3465,13 +3444,16 @@ public class WebView extends AbsoluteLayout
if (!nativeCursorIntersects(visibleRect)) {
return false;
}
- nativeUpdatePluginReceivesEvents();
WebViewCore.CursorData data = cursorData();
mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data);
playSoundEffect(SoundEffectConstants.CLICK);
if (nativeCursorIsTextInput()) {
rebuildWebTextView();
centerKeyPressOnTextField();
+ if (inEditingMode()) {
+ mWebTextView.setDefaultSelection();
+ mWebTextView.mOkayForFocusNotToMatch = true;
+ }
return true;
}
nativeSetFollowedLink(true);
@@ -3494,14 +3476,29 @@ public class WebView extends AbsoluteLayout
return false;
}
+ private void setUpSelectXY() {
+ mExtendSelection = false;
+ mShiftIsPressed = true;
+ if (nativeHasCursorNode()) {
+ Rect rect = nativeCursorNodeBounds();
+ mSelectX = contentToViewX(rect.left);
+ mSelectY = contentToViewY(rect.top);
+ } else if (mLastTouchY > getVisibleTitleHeight()) {
+ mSelectX = mScrollX + (int) mLastTouchX;
+ mSelectY = mScrollY + (int) mLastTouchY;
+ } else {
+ mSelectX = mScrollX + getViewWidth() / 2;
+ mSelectY = mScrollY + getViewHeightWithTitle() / 2;
+ }
+ nativeHideCursor();
+ }
+
/**
* @hide
*/
public void emulateShiftHeld() {
if (0 == mNativeClass) return; // client isn't initialized
- mExtendSelection = false;
- mShiftIsPressed = true;
- nativeHideCursor();
+ setUpSelectXY();
}
private boolean commitCopy() {
@@ -3519,6 +3516,7 @@ public class WebView extends AbsoluteLayout
mExtendSelection = false;
}
mShiftIsPressed = false;
+ invalidate(); // remove selection region and pointer
if (mTouchMode == TOUCH_SELECT_MODE) {
mTouchMode = TOUCH_INIT_MODE;
}
@@ -3813,6 +3811,7 @@ public class WebView extends AbsoluteLayout
nativeMoveSelection(viewToContentX(mSelectX),
viewToContentY(mSelectY), false);
mTouchSelection = mExtendSelection = true;
+ invalidate(); // draw the i-beam instead of the arrow
} else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
if (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare) {
@@ -4195,6 +4194,7 @@ public class WebView extends AbsoluteLayout
commitCopy();
} else {
mExtendSelection = true;
+ invalidate(); // draw the i-beam instead of the arrow
}
return true; // discard press if copy in progress
}
@@ -4783,19 +4783,6 @@ public class WebView extends AbsoluteLayout
mCallbackProxy.uiOverrideUrlLoading(url);
}
- // called by JNI
- private void sendPluginState(int state) {
- WebViewCore.PluginStateData psd = new WebViewCore.PluginStateData();
- psd.mFrame = nativeFocusCandidateFramePointer();
- psd.mNode = nativeFocusCandidatePointer();
- if (DebugFlags.WEB_VIEW) {
- Log.v(LOGTAG, "sendPluginState frame=" + psd.mFrame
- + " node=" + psd.mNode);
- }
- psd.mState = state;
- mWebViewCore.sendMessage(EventHub.PLUGIN_STATE, psd);
- }
-
@Override
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
boolean result = false;
@@ -4944,15 +4931,6 @@ public class WebView extends AbsoluteLayout
}
/* package */ void passToJavaScript(String currentText, KeyEvent event) {
- if (nativeCursorWantsKeyEvents() && !nativeCursorMatchesFocus()) {
- mWebViewCore.sendMessage(EventHub.CLICK);
- if (mWebTextView.mOkayForFocusNotToMatch) {
- int select = nativeFocusCandidateIsTextField() ?
- nativeFocusCandidateMaxLength() : 0;
- setSelection(select, select);
- mWebTextView.mOkayForFocusNotToMatch = false; // only once
- }
- }
WebViewCore.JSKeyData arg = new WebViewCore.JSKeyData();
arg.mEvent = event;
arg.mCurrentText = currentText;
@@ -5191,9 +5169,7 @@ public class WebView extends AbsoluteLayout
}
break;
case MOVE_OUT_OF_PLUGIN:
- if (nativePluginEatsNavKey()) {
- navHandledKey(msg.arg1, 1, false, 0, true);
- }
+ navHandledKey(msg.arg1, 1, false, 0, true);
break;
case UPDATE_TEXT_ENTRY_MSG_ID:
// this is sent after finishing resize in WebViewCore. Make
@@ -5687,7 +5663,7 @@ public class WebView extends AbsoluteLayout
if (mNativeClass == 0) {
return false;
}
- if (ignorePlugin == false && nativePluginEatsNavKey()) {
+ if (ignorePlugin == false && nativeFocusIsPlugin()) {
KeyEvent event = new KeyEvent(time, time, KeyEvent.ACTION_DOWN
, keyCode, count, (mShiftIsPressed ? KeyEvent.META_SHIFT_ON : 0)
| (false ? KeyEvent.META_ALT_ON : 0) // FIXME
@@ -5803,8 +5779,8 @@ public class WebView extends AbsoluteLayout
private native void nativeDestroy();
private native void nativeDrawCursorRing(Canvas content);
private native void nativeDrawMatches(Canvas canvas);
- private native void nativeDrawSelection(Canvas content, float scale,
- int offset, int x, int y, boolean extendSelection);
+ private native void nativeDrawSelectionPointer(Canvas content,
+ float scale, int x, int y, boolean extendSelection);
private native void nativeDrawSelectionRegion(Canvas content);
private native void nativeDumpDisplayTree(String urlOrNull);
private native int nativeFindAll(String findLower, String findUpper);
@@ -5821,6 +5797,7 @@ public class WebView extends AbsoluteLayout
/* package */ native int nativeFocusCandidatePointer();
private native String nativeFocusCandidateText();
private native int nativeFocusCandidateTextSize();
+ private native boolean nativeFocusIsPlugin();
/* package */ native int nativeFocusNodePointer();
private native Rect nativeGetCursorRingBounds();
private native Region nativeGetSelection();
@@ -5838,7 +5815,6 @@ public class WebView extends AbsoluteLayout
private native int nativeMoveGeneration();
private native void nativeMoveSelection(int x, int y,
boolean extendSelection);
- private native boolean nativePluginEatsNavKey();
// Like many other of our native methods, you must make sure that
// mNativeClass is not null before calling this method.
private native void nativeRecordButtons(boolean focused,
@@ -5860,7 +5836,6 @@ public class WebView extends AbsoluteLayout
// we always want to pass in our generation number.
private native void nativeUpdateCachedTextfield(String updatedText,
int generation);
- private native void nativeUpdatePluginReceivesEvents();
// return NO_LEFTEDGE means failure.
private static final int NO_LEFTEDGE = -1;
private native int nativeGetBlockLeftEdge(int x, int y, float scale);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 8155813..6505ee2 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -560,8 +560,6 @@ final class WebViewCore {
*/
private native void nativeSetNewStorageLimit(long limit);
- private native void nativeUpdatePluginState(int framePtr, int nodePtr, int state);
-
/**
* Provide WebCore with a Geolocation permission state for the specified
* origin.
@@ -716,12 +714,6 @@ final class WebViewCore {
int mY;
}
- static class PluginStateData {
- int mFrame;
- int mNode;
- int mState;
- }
-
static class GeolocationPermissionsData {
String mOrigin;
boolean mAllow;
@@ -758,7 +750,7 @@ final class WebViewCore {
"SINGLE_LISTBOX_CHOICE", // = 124;
"MESSAGE_RELAY", // = 125;
"SET_BACKGROUND_COLOR", // = 126;
- "PLUGIN_STATE", // = 127;
+ "127", // = 127
"SAVE_DOCUMENT_STATE", // = 128;
"GET_SELECTION", // = 129;
"WEBKIT_DRAW", // = 130;
@@ -809,7 +801,6 @@ final class WebViewCore {
static final int SINGLE_LISTBOX_CHOICE = 124;
static final int MESSAGE_RELAY = 125;
static final int SET_BACKGROUND_COLOR = 126;
- static final int PLUGIN_STATE = 127; // plugin notifications
static final int SAVE_DOCUMENT_STATE = 128;
static final int GET_SELECTION = 129;
static final int WEBKIT_DRAW = 130;
@@ -1069,11 +1060,6 @@ final class WebViewCore {
nativeFreeMemory();
break;
- case PLUGIN_STATE:
- PluginStateData psd = (PluginStateData) msg.obj;
- nativeUpdatePluginState(psd.mFrame, psd.mNode, psd.mState);
- break;
-
case SET_NETWORK_STATE:
if (BrowserFrame.sJavaBridge == null) {
throw new IllegalStateException("No WebView " +
diff --git a/core/java/com/android/internal/os/IDropBoxService.aidl b/core/java/com/android/internal/os/IDropBoxService.aidl
new file mode 100644
index 0000000..f940041
--- /dev/null
+++ b/core/java/com/android/internal/os/IDropBoxService.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.os.DropBox;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * "Backend" interface used by {@link android.os.DropBox} to talk to the
+ * DropBoxService that actually implements the drop box functionality.
+ *
+ * @see DropBox
+ * @hide
+ */
+interface IDropBoxService {
+ /**
+ * @see DropBox#addText
+ * @see DropBox#addData
+ * @see DropBox#addFile
+ */
+ void add(in DropBox.Entry entry);
+
+ /** @see DropBox#getNextEntry */
+ boolean isTagEnabled(String tag);
+
+ /** @see DropBox#getNextEntry */
+ DropBox.Entry getNextEntry(String tag, long millis);
+}
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index dc72008..e1e9536 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -27,6 +27,9 @@
#include "SkShader.h"
#include "SkTemplates.h"
+#include "SkBoundaryPatch.h"
+#include "SkMeshUtils.h"
+
#define TIME_DRAWx
static uint32_t get_thread_msec() {
@@ -861,8 +864,6 @@ public:
*matrix = canvas->getTotalMatrix();
}
};
-
-///////////////////////////////////////////////////////////////////////////////
static JNINativeMethod gCanvasMethods[] = {
{"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer},
@@ -965,6 +966,42 @@ static JNINativeMethod gCanvasMethods[] = {
{"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches}
};
+///////////////////////////////////////////////////////////////////////////////
+
+static void BoundaryPatch_computeCubic(JNIEnv* env, jobject, jfloatArray jpts,
+ int texW, int texH, int rows, int cols,
+ jfloatArray jverts, jshortArray jidx) {
+ AutoJavaFloatArray ptsArray(env, jpts, 24, kRO_JNIAccess);
+
+ int vertCount = rows * cols;
+ AutoJavaFloatArray vertsArray(env, jverts, vertCount * 4, kRW_JNIAccess);
+ SkPoint* verts = (SkPoint*)vertsArray.ptr();
+ SkPoint* texs = verts + vertCount;
+
+ int idxCount = (rows - 1) * (cols - 1) * 6;
+ AutoJavaShortArray idxArray(env, jidx, idxCount, kRW_JNIAccess);
+ uint16_t* idx = (uint16_t*)idxArray.ptr(); // cast from int16_t*
+
+ SkCubicBoundary cubic;
+ memcpy(cubic.fPts, ptsArray.ptr(), 12 * sizeof(SkPoint));
+
+ SkBoundaryPatch patch;
+ patch.setBoundary(&cubic);
+ // generate our verts
+ patch.evalPatch(verts, rows, cols);
+
+ SkMeshIndices mesh;
+ // generate our texs and idx
+ mesh.init(texs, idx, texW, texH, rows, cols);
+}
+
+static JNINativeMethod gBoundaryPatchMethods[] = {
+ {"nativeComputeCubicPatch", "([FIIII[F[S)V",
+ (void*)BoundaryPatch_computeCubic },
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
#include <android_runtime/AndroidRuntime.h>
#define REG(env, name, array) \
@@ -976,6 +1013,7 @@ int register_android_graphics_Canvas(JNIEnv* env) {
int result;
REG(env, "android/graphics/Canvas", gCanvasMethods);
+ REG(env, "android/graphics/utils/BoundaryPatch", gBoundaryPatchMethods);
return result;
}
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 2e0caed..01aad93 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -56,7 +56,7 @@ bool GraphicsJNI::hasException(JNIEnv *env) {
///////////////////////////////////////////////////////////////////////////////
AutoJavaFloatArray::AutoJavaFloatArray(JNIEnv* env, jfloatArray array,
- int minLength)
+ int minLength, JNIAccess access)
: fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
SkASSERT(env);
if (array) {
@@ -66,11 +66,12 @@ AutoJavaFloatArray::AutoJavaFloatArray(JNIEnv* env, jfloatArray array,
}
fPtr = env->GetFloatArrayElements(array, NULL);
}
+ fReleaseMode = (access == kRO_JNIAccess) ? JNI_ABORT : 0;
}
AutoJavaFloatArray::~AutoJavaFloatArray() {
if (fPtr) {
- fEnv->ReleaseFloatArrayElements(fArray, fPtr, 0);
+ fEnv->ReleaseFloatArrayElements(fArray, fPtr, fReleaseMode);
}
}
@@ -94,7 +95,7 @@ AutoJavaIntArray::~AutoJavaIntArray() {
}
AutoJavaShortArray::AutoJavaShortArray(JNIEnv* env, jshortArray array,
- int minLength)
+ int minLength, JNIAccess access)
: fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
SkASSERT(env);
if (array) {
@@ -104,11 +105,12 @@ AutoJavaShortArray::AutoJavaShortArray(JNIEnv* env, jshortArray array,
}
fPtr = env->GetShortArrayElements(array, NULL);
}
+ fReleaseMode = (access == kRO_JNIAccess) ? JNI_ABORT : 0;
}
AutoJavaShortArray::~AutoJavaShortArray() {
if (fPtr) {
- fEnv->ReleaseShortArrayElements(fArray, fPtr, 0);
+ fEnv->ReleaseShortArrayElements(fArray, fPtr, fReleaseMode);
}
}
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 7adadbc..fe24b05 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -80,9 +80,15 @@ private:
bool fReportSizeToVM;
};
+enum JNIAccess {
+ kRO_JNIAccess,
+ kRW_JNIAccess
+};
+
class AutoJavaFloatArray {
public:
- AutoJavaFloatArray(JNIEnv* env, jfloatArray array, int minLength = 0);
+ AutoJavaFloatArray(JNIEnv* env, jfloatArray array,
+ int minLength = 0, JNIAccess = kRW_JNIAccess);
~AutoJavaFloatArray();
float* ptr() const { return fPtr; }
@@ -93,6 +99,7 @@ private:
jfloatArray fArray;
float* fPtr;
int fLen;
+ int fReleaseMode;
};
class AutoJavaIntArray {
@@ -112,7 +119,8 @@ private:
class AutoJavaShortArray {
public:
- AutoJavaShortArray(JNIEnv* env, jshortArray array, int minLength = 0);
+ AutoJavaShortArray(JNIEnv* env, jshortArray array,
+ int minLength = 0, JNIAccess = kRW_JNIAccess);
~AutoJavaShortArray();
jshort* ptr() const { return fPtr; }
@@ -123,6 +131,7 @@ private:
jshortArray fArray;
jshort* fPtr;
int fLen;
+ int fReleaseMode;
};
class AutoJavaByteArray {
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>