diff options
Diffstat (limited to 'core')
| -rw-r--r-- | core/java/android/app/Notification.java | 43 | ||||
| -rw-r--r-- | core/java/android/database/sqlite/SQLiteSession.java | 8 | ||||
| -rw-r--r-- | core/java/android/webkit/BrowserFrame.java | 13 | ||||
| -rw-r--r-- | core/java/android/webkit/CacheManager.java | 9 | ||||
| -rw-r--r-- | core/java/android/webkit/CookieManager.java | 200 | ||||
| -rw-r--r-- | core/java/android/webkit/CookieSyncManager.java | 6 | ||||
| -rw-r--r-- | core/java/android/webkit/JniUtil.java | 2 | ||||
| -rw-r--r-- | core/java/android/webkit/MimeTypeMap.java | 1 | ||||
| -rw-r--r-- | core/java/android/webkit/QuadF.java | 85 | ||||
| -rw-r--r-- | core/java/android/webkit/URLUtil.java | 3 | ||||
| -rw-r--r-- | core/java/android/webkit/WebViewClassic.java | 205 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 1 | ||||
| -rw-r--r-- | core/res/res/layout/notification_intruder_content.xml | 21 | ||||
| -rw-r--r-- | core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java | 4 |
14 files changed, 321 insertions, 280 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 04ab407..bbb6a4e 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -918,6 +918,8 @@ public class Notification implements Parcelable private Bundle mExtras; private int mPriority; private ArrayList<Action> mActions = new ArrayList<Action>(3); + private boolean mCanHasIntruder; + private boolean mIntruderActionsShowText; /** * Constructs a new Builder with the defaults: @@ -1313,6 +1315,38 @@ public class Notification implements Parcelable return this; } + /** + * Specify whether this notification should pop up as an + * "intruder alert" (a small window that shares the screen with the + * current activity). This sort of notification is (as the name implies) + * very intrusive, so use it sparingly for notifications that require + * the user's attention. + * + * Notes: + * <ul> + * <li>Intruder alerts only show when the screen is on.</li> + * <li>Intruder alerts take precedence over fullScreenIntents.</li> + * </ul> + * + * @param intrude Whether to pop up an intruder alert (default false). + */ + public Builder setUsesIntruderAlert(boolean intrude) { + mCanHasIntruder = intrude; + return this; + } + + /** + * Control text on intruder alert action buttons. By default, action + * buttons in intruders do not show textual labels. + * + * @param showActionText Whether to show text labels beneath action + * icons (default false). + */ + public Builder setIntruderActionsShowText(boolean showActionText) { + mIntruderActionsShowText = showActionText; + return this; + } + private void setFlag(int mask, boolean value) { if (value) { mFlags |= mask; @@ -1394,7 +1428,7 @@ public class Notification implements Parcelable } } - private RemoteViews makeIntruderView() { + private RemoteViews makeIntruderView(boolean showLabels) { RemoteViews intruderView = new RemoteViews(mContext.getPackageName(), R.layout.notification_intruder_content); if (mLargeIcon != null) { @@ -1422,7 +1456,8 @@ public class Notification implements Parcelable final int buttonId = BUTTONS[i]; intruderView.setViewVisibility(buttonId, View.VISIBLE); - intruderView.setImageViewResource(buttonId, action.icon); + intruderView.setTextViewText(buttonId, showLabels ? action.title : null); + intruderView.setTextViewCompoundDrawables(buttonId, 0, action.icon, 0, 0); intruderView.setContentDescription(buttonId, action.title); intruderView.setOnClickPendingIntent(buttonId, action.actionIntent); } @@ -1457,7 +1492,9 @@ public class Notification implements Parcelable n.ledOffMS = mLedOffMs; n.defaults = mDefaults; n.flags = mFlags; - n.intruderView = makeIntruderView(); + if (mCanHasIntruder) { + n.intruderView = makeIntruderView(mIntruderActionsShowText); + } if (mLedOnMs != 0 && mLedOffMs != 0) { n.flags |= FLAG_SHOW_LIGHTS; } diff --git a/core/java/android/database/sqlite/SQLiteSession.java b/core/java/android/database/sqlite/SQLiteSession.java index 43efb03..9410243 100644 --- a/core/java/android/database/sqlite/SQLiteSession.java +++ b/core/java/android/database/sqlite/SQLiteSession.java @@ -398,16 +398,16 @@ public final class SQLiteSession { throwIfNoTransaction(); assert mConnection != null; - endTransactionUnchecked(cancellationSignal); + endTransactionUnchecked(cancellationSignal, false); } - private void endTransactionUnchecked(CancellationSignal cancellationSignal) { + private void endTransactionUnchecked(CancellationSignal cancellationSignal, boolean yielding) { if (cancellationSignal != null) { cancellationSignal.throwIfCanceled(); } final Transaction top = mTransactionStack; - boolean successful = top.mMarkedSuccessful && !top.mChildFailed; + boolean successful = (top.mMarkedSuccessful || yielding) && !top.mChildFailed; RuntimeException listenerException = null; final SQLiteTransactionListener listener = top.mListener; @@ -534,7 +534,7 @@ public final class SQLiteSession { final int transactionMode = mTransactionStack.mMode; final SQLiteTransactionListener listener = mTransactionStack.mListener; final int connectionFlags = mConnectionFlags; - endTransactionUnchecked(cancellationSignal); // might throw + endTransactionUnchecked(cancellationSignal, true); // might throw if (sleepAfterYieldDelayMillis > 0) { try { diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java index 72af251..7b6b54c 100644 --- a/core/java/android/webkit/BrowserFrame.java +++ b/core/java/android/webkit/BrowserFrame.java @@ -692,13 +692,10 @@ class BrowserFrame extends Handler { * @return An InputStream to the android resource */ private InputStream inputStreamForAndroidResource(String url) { - // This list needs to be kept in sync with the list in - // external/webkit/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp - final String ANDROID_ASSET = "file:///android_asset/"; - final String ANDROID_RESOURCE = "file:///android_res/"; - final String ANDROID_CONTENT = "content:"; + final String ANDROID_ASSET = URLUtil.ASSET_BASE; + final String ANDROID_RESOURCE = URLUtil.RESOURCE_BASE; + final String ANDROID_CONTENT = URLUtil.CONTENT_BASE; - // file:///android_res if (url.startsWith(ANDROID_RESOURCE)) { url = url.replaceFirst(ANDROID_RESOURCE, ""); if (url == null || url.length() == 0) { @@ -736,8 +733,6 @@ class BrowserFrame extends Handler { Log.e(LOGTAG, "Exception: " + url); return null; } - - // file:///android_asset } else if (url.startsWith(ANDROID_ASSET)) { url = url.replaceFirst(ANDROID_ASSET, ""); try { @@ -747,8 +742,6 @@ class BrowserFrame extends Handler { } catch (IOException e) { return null; } - - // content:// } else if (mSettings.getAllowContentAccess() && url.startsWith(ANDROID_CONTENT)) { try { diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java index 6a85e00..671c064 100644 --- a/core/java/android/webkit/CacheManager.java +++ b/core/java/android/webkit/CacheManager.java @@ -17,25 +17,18 @@ package android.webkit; import android.content.Context; -import android.net.http.AndroidHttpClient; import android.net.http.Headers; -import android.os.FileUtils; import android.util.Log; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.List; import java.util.Map; -import com.android.org.bouncycastle.crypto.Digest; -import com.android.org.bouncycastle.crypto.digests.SHA1Digest; - /** * Manages the HTTP cache used by an application's {@link WebView} instances. * @deprecated Access to the HTTP cache will be removed in a future release. diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java index 497cab7..5f7ef41 100644 --- a/core/java/android/webkit/CookieManager.java +++ b/core/java/android/webkit/CookieManager.java @@ -18,21 +18,10 @@ package android.webkit; import android.net.ParseException; import android.net.WebAddress; -import android.net.http.AndroidHttpClient; import android.os.AsyncTask; import android.util.Log; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; - /** * Manages the cookies used by an application's {@link WebView} instances. * Cookies are manipulated according to RFC2109. @@ -43,197 +32,8 @@ public final class CookieManager { private static final String LOGTAG = "webkit"; - private static final String DOMAIN = "domain"; - - private static final String PATH = "path"; - - private static final String EXPIRES = "expires"; - - private static final String SECURE = "secure"; - - private static final String MAX_AGE = "max-age"; - - private static final String HTTP_ONLY = "httponly"; - - private static final String HTTPS = "https"; - - private static final char PERIOD = '.'; - - private static final char COMMA = ','; - - private static final char SEMICOLON = ';'; - - private static final char EQUAL = '='; - - private static final char PATH_DELIM = '/'; - - private static final char QUESTION_MARK = '?'; - - private static final char WHITE_SPACE = ' '; - - private static final char QUOTATION = '\"'; - - private static final int SECURE_LENGTH = SECURE.length(); - - private static final int HTTP_ONLY_LENGTH = HTTP_ONLY.length(); - - // RFC2109 defines 4k as maximum size of a cookie - private static final int MAX_COOKIE_LENGTH = 4 * 1024; - - // RFC2109 defines 20 as max cookie count per domain. As we track with base - // domain, we allow 50 per base domain - private static final int MAX_COOKIE_COUNT_PER_BASE_DOMAIN = 50; - - // RFC2109 defines 300 as max count of domains. As we track with base - // domain, we set 200 as max base domain count - private static final int MAX_DOMAIN_COUNT = 200; - - // max cookie count to limit RAM cookie takes less than 100k, it is based on - // average cookie entry size is less than 100 bytes - private static final int MAX_RAM_COOKIES_COUNT = 1000; - - // max domain count to limit RAM cookie takes less than 100k, - private static final int MAX_RAM_DOMAIN_COUNT = 15; - private int mPendingCookieOperations = 0; - /** - * This contains a list of 2nd-level domains that aren't allowed to have - * wildcards when combined with country-codes. For example: [.co.uk]. - */ - private final static String[] BAD_COUNTRY_2LDS = - { "ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info", - "lg", "ne", "net", "or", "org" }; - - static { - Arrays.sort(BAD_COUNTRY_2LDS); - } - - /** - * Package level class to be accessed by cookie sync manager - */ - static class Cookie { - static final byte MODE_NEW = 0; - - static final byte MODE_NORMAL = 1; - - static final byte MODE_DELETED = 2; - - static final byte MODE_REPLACED = 3; - - String domain; - - String path; - - String name; - - String value; - - long expires; - - long lastAcessTime; - - long lastUpdateTime; - - boolean secure; - - byte mode; - - Cookie() { - } - - Cookie(String defaultDomain, String defaultPath) { - domain = defaultDomain; - path = defaultPath; - expires = -1; - } - - boolean exactMatch(Cookie in) { - // An exact match means that domain, path, and name are equal. If - // both values are null, the cookies match. If both values are - // non-null, the cookies match. If one value is null and the other - // is non-null, the cookies do not match (i.e. "foo=;" and "foo;") - boolean valuesMatch = !((value == null) ^ (in.value == null)); - return domain.equals(in.domain) && path.equals(in.path) && - name.equals(in.name) && valuesMatch; - } - - boolean domainMatch(String urlHost) { - if (domain.startsWith(".")) { - if (urlHost.endsWith(domain.substring(1))) { - int len = domain.length(); - int urlLen = urlHost.length(); - if (urlLen > len - 1) { - // make sure bar.com doesn't match .ar.com - return urlHost.charAt(urlLen - len) == PERIOD; - } - return true; - } - return false; - } else { - // exact match if domain is not leading w/ dot - return urlHost.equals(domain); - } - } - - boolean pathMatch(String urlPath) { - if (urlPath.startsWith(path)) { - int len = path.length(); - if (len == 0) { - Log.w(LOGTAG, "Empty cookie path"); - return false; - } - int urlLen = urlPath.length(); - if (path.charAt(len-1) != PATH_DELIM && urlLen > len) { - // make sure /wee doesn't match /we - return urlPath.charAt(len) == PATH_DELIM; - } - return true; - } - return false; - } - - public String toString() { - return "domain: " + domain + "; path: " + path + "; name: " + name - + "; value: " + value; - } - } - - private static final CookieComparator COMPARATOR = new CookieComparator(); - - private static final class CookieComparator implements Comparator<Cookie> { - public int compare(Cookie cookie1, Cookie cookie2) { - // According to RFC 2109, multiple cookies are ordered in a way such - // that those with more specific Path attributes precede those with - // less specific. Ordering with respect to other attributes (e.g., - // Domain) is unspecified. - // As Set is not modified if the two objects are same, we do want to - // assign different value for each cookie. - int diff = cookie2.path.length() - cookie1.path.length(); - if (diff != 0) return diff; - - diff = cookie2.domain.length() - cookie1.domain.length(); - if (diff != 0) return diff; - - // If cookie2 has a null value, it should come later in - // the list. - if (cookie2.value == null) { - // If both cookies have null values, fall back to using the name - // difference. - if (cookie1.value != null) { - return -1; - } - } else if (cookie1.value == null) { - // Now we know that cookie2 does not have a null value, if - // cookie1 has a null value, place it later in the list. - return 1; - } - - // Fallback to comparing the name to ensure consistent order. - return cookie1.name.compareTo(cookie2.name); - } - } - private CookieManager() { } diff --git a/core/java/android/webkit/CookieSyncManager.java b/core/java/android/webkit/CookieSyncManager.java index 19fa096..4e99335 100644 --- a/core/java/android/webkit/CookieSyncManager.java +++ b/core/java/android/webkit/CookieSyncManager.java @@ -18,10 +18,7 @@ package android.webkit; import android.content.Context; import android.util.Log; -import android.webkit.CookieManager.Cookie; -import java.util.ArrayList; -import java.util.Iterator; /** * The CookieSyncManager is used to synchronize the browser cookie store @@ -62,9 +59,6 @@ public final class CookieSyncManager extends WebSyncManager { private static CookieSyncManager sRef; - // time when last update happened - private long mLastUpdate; - private CookieSyncManager(Context context) { super(context, "CookieSyncManager"); } diff --git a/core/java/android/webkit/JniUtil.java b/core/java/android/webkit/JniUtil.java index 343d34a..e3e6092 100644 --- a/core/java/android/webkit/JniUtil.java +++ b/core/java/android/webkit/JniUtil.java @@ -100,7 +100,7 @@ class JniUtil { return sContext.getPackageName(); } - private static final String ANDROID_CONTENT = "content:"; + private static final String ANDROID_CONTENT = URLUtil.CONTENT_BASE; /** * Called by JNI. Calculates the size of an input stream by reading it. diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java index 35483c9..da8901a 100644 --- a/core/java/android/webkit/MimeTypeMap.java +++ b/core/java/android/webkit/MimeTypeMap.java @@ -17,7 +17,6 @@ package android.webkit; import android.text.TextUtils; -import java.util.HashMap; import java.util.regex.Pattern; import libcore.net.MimeUtils; diff --git a/core/java/android/webkit/QuadF.java b/core/java/android/webkit/QuadF.java new file mode 100644 index 0000000..e9011e3 --- /dev/null +++ b/core/java/android/webkit/QuadF.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012 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.webkit; + +import android.graphics.PointF; + +/** + * A quadrilateral, determined by four points, clockwise order. Typically + * p1 is "top-left" and p4 is "bottom-left" following webkit's rectangle-to- + * FloatQuad conversion. + */ +class QuadF { + public PointF p1; + public PointF p2; + public PointF p3; + public PointF p4; + + public QuadF() { + p1 = new PointF(); + p2 = new PointF(); + p3 = new PointF(); + p4 = new PointF(); + } + + public void offset(float dx, float dy) { + p1.offset(dx, dy); + p2.offset(dx, dy); + p3.offset(dx, dy); + p4.offset(dx, dy); + } + + /** + * Determines if the quadrilateral contains the given point. This does + * not work if the quadrilateral is self-intersecting or if any inner + * angle is reflex (greater than 180 degrees). + */ + public boolean containsPoint(float x, float y) { + return isPointInTriangle(x, y, p1, p2, p3) || + isPointInTriangle(x, y, p1, p3, p4); + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder("QuadF("); + s.append(p1.x).append(",").append(p1.y); + s.append(" - "); + s.append(p2.x).append(",").append(p2.y); + s.append(" - "); + s.append(p3.x).append(",").append(p3.y); + s.append(" - "); + s.append(p4.x).append(",").append(p4.y); + s.append(")"); + return s.toString(); + } + + private static boolean isPointInTriangle(float x0, float y0, + PointF r1, PointF r2, PointF r3) { + // Use the barycentric technique + float x13 = r1.x - r3.x; + float y13 = r1.y - r3.y; + float x23 = r2.x - r3.x; + float y23 = r2.y - r3.y; + float x03 = x0 - r3.x; + float y03 = y0 - r3.y; + + float determinant = (y23 * x13) - (x23 * y13); + float lambda1 = ((y23 * x03) - (x23 * y03))/determinant; + float lambda2 = ((x13 * y03) - (y13 * x03))/determinant; + float lambda3 = 1 - lambda1 - lambda2; + return lambda1 >= 0.0f && lambda2 >= 0.0f && lambda3 >= 0.0f; + } +} diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java index 9970c93..b47f04f 100644 --- a/core/java/android/webkit/URLUtil.java +++ b/core/java/android/webkit/URLUtil.java @@ -38,6 +38,7 @@ public final class URLUtil { static final String RESOURCE_BASE = "file:///android_res/"; static final String FILE_BASE = "file://"; static final String PROXY_BASE = "file:///cookieless_proxy/"; + static final String CONTENT_BASE = "content:"; /** * Cleans up (if possible) user-entered web addresses @@ -253,7 +254,7 @@ public final class URLUtil { * @return True iff the url is a content: url. */ public static boolean isContentUrl(String url) { - return (null != url) && url.startsWith("content:"); + return (null != url) && url.startsWith(CONTENT_BASE); } /** diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index 5ae2fe0..7ddff8e 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -43,6 +43,7 @@ import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; import android.graphics.Picture; import android.graphics.Point; +import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; @@ -56,9 +57,7 @@ import android.net.http.SslCertificate; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; -import android.os.Looper; import android.os.Message; -import android.os.StrictMode; import android.os.SystemClock; import android.provider.Settings; import android.security.KeyChain; @@ -758,22 +757,21 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc this.setContentView(mContentView); } - public void show(Rect cursorRect, int windowLeft, int windowTop) { + public void show(Point cursorBottom, Point cursorTop, + int windowLeft, int windowTop) { measureContent(); int width = mContentView.getMeasuredWidth(); int height = mContentView.getMeasuredHeight(); - int y = cursorRect.top - height; + int y = cursorTop.y - height; + int x = cursorTop.x - (width / 2); if (y < windowTop) { // There's not enough room vertically, move it below the // handle. - // The selection handle is vertically offset by 1/4 of the - // line height. ensureSelectionHandles(); - y = cursorRect.bottom - (cursorRect.height() / 4) + - mSelectHandleCenter.getIntrinsicHeight(); + y = cursorBottom.y + mSelectHandleCenter.getIntrinsicHeight(); + x = cursorBottom.x - (width / 2); } - int x = cursorRect.centerX() - (width / 2); if (x < windowLeft) { x = windowLeft; } @@ -1151,12 +1149,18 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc private Drawable mSelectHandleLeft; private Drawable mSelectHandleRight; private Drawable mSelectHandleCenter; - private Rect mSelectCursorBase = new Rect(); + private Point mSelectHandleLeftOffset; + private Point mSelectHandleRightOffset; + private Point mSelectHandleCenterOffset; + private Point mSelectCursorBase = new Point(); private int mSelectCursorBaseLayerId; - private Rect mSelectCursorExtent = new Rect(); + private QuadF mSelectCursorBaseTextQuad = new QuadF(); + private Point mSelectCursorExtent = new Point(); private int mSelectCursorExtentLayerId; - private Rect mSelectDraggingCursor; - private Point mSelectDraggingOffset = new Point(); + private QuadF mSelectCursorExtentTextQuad = new QuadF(); + private Point mSelectDraggingCursor; + private Point mSelectDraggingOffset; + private QuadF mSelectDraggingTextQuad; private boolean mIsCaretSelection; static final int HANDLE_ID_START = 0; static final int HANDLE_ID_END = 1; @@ -3894,9 +3898,11 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc if (mSelectingText) { if (mSelectCursorBaseLayerId == mCurrentScrollingLayerId) { mSelectCursorBase.offset(dx, dy); + mSelectCursorBaseTextQuad.offset(dx, dy); } if (mSelectCursorExtentLayerId == mCurrentScrollingLayerId) { mSelectCursorExtent.offset(dx, dy); + mSelectCursorExtentTextQuad.offset(dx, dy); } } if (mAutoCompletePopup != null && @@ -4774,6 +4780,13 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc com.android.internal.R.drawable.text_select_handle_left); mSelectHandleRight = mContext.getResources().getDrawable( com.android.internal.R.drawable.text_select_handle_right); + mSelectHandleCenterOffset = new Point(0, + -mSelectHandleCenter.getIntrinsicHeight()); + mSelectHandleLeftOffset = new Point(0, + -mSelectHandleLeft.getIntrinsicHeight()); + mSelectHandleRightOffset = new Point( + -mSelectHandleLeft.getIntrinsicWidth() / 2, + -mSelectHandleRight.getIntrinsicHeight()); } } @@ -4813,10 +4826,10 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc * startX, startY, endX, endY */ private void getSelectionHandles(int[] handles) { - handles[0] = mSelectCursorBase.left; - handles[1] = mSelectCursorBase.bottom; - handles[2] = mSelectCursorExtent.left; - handles[3] = mSelectCursorExtent.bottom; + handles[0] = mSelectCursorBase.x; + handles[1] = mSelectCursorBase.y; + handles[2] = mSelectCursorExtent.x; + handles[3] = mSelectCursorExtent.y; if (!nativeIsBaseFirst(mNativeClass)) { int swap = handles[0]; handles[0] = handles[2]; @@ -5332,17 +5345,66 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc ClipboardManager cm = (ClipboardManager)(mContext .getSystemService(Context.CLIPBOARD_SERVICE)); if (cm.hasPrimaryClip()) { - Rect cursorRect = contentToViewRect(mSelectCursorBase); + Point cursorPoint = new Point(contentToViewX(mSelectCursorBase.x), + contentToViewY(mSelectCursorBase.y)); + Point cursorTop = calculateCaretTop(); + cursorTop.set(contentToViewX(cursorTop.x), + contentToViewY(cursorTop.y)); + int[] location = new int[2]; mWebView.getLocationInWindow(location); - cursorRect.offset(location[0] - getScrollX(), location[1] - getScrollY()); + int offsetX = location[0] - getScrollX(); + int offsetY = location[1] - getScrollY(); + cursorPoint.offset(offsetX, offsetY); + cursorTop.offset(offsetX, offsetY); if (mPasteWindow == null) { mPasteWindow = new PastePopupWindow(); } - mPasteWindow.show(cursorRect, location[0], location[1]); + mPasteWindow.show(cursorPoint, cursorTop, location[0], location[1]); } } + /** + * Given segment AB, this finds the point C along AB that is closest to + * point and then returns it scale along AB. The scale factor is AC/AB. + * + * @param x The x coordinate of the point near segment AB that determines + * the scale factor. + * @param y The y coordinate of the point near segment AB that determines + * the scale factor. + * @param a The first point of the line segment. + * @param b The second point of the line segment. + * @return The scale factor AC/AB, where C is the point on AB closest to + * point. + */ + private static float scaleAlongSegment(int x, int y, PointF a, PointF b) { + // The bottom line of the text box is line AB + float abX = b.x - a.x; + float abY = b.y - a.y; + float ab2 = (abX * abX) + (abY * abY); + + // The line from first point in text bounds to bottom is AP + float apX = x - a.x; + float apY = y - a.y; + float abDotAP = (apX * abX) + (apY * abY); + float scale = abDotAP / ab2; + return scale; + } + + /** + * Assuming arbitrary shape of a quadralateral forming text bounds, this + * calculates the top of a caret. + */ + private Point calculateCaretTop() { + float scale = scaleAlongSegment(mSelectCursorBase.x, mSelectCursorBase.y, + mSelectCursorBaseTextQuad.p4, mSelectCursorBaseTextQuad.p3); + int x = Math.round(scaleCoordinate(scale, + mSelectCursorBaseTextQuad.p1.x, mSelectCursorBaseTextQuad.p2.x)); + int y = Math.round(scaleCoordinate(scale, + mSelectCursorBaseTextQuad.p1.y, mSelectCursorBaseTextQuad.p2.y)); + return new Point(x, y); + } + private void hidePasteButton() { if (mPasteWindow != null) { mPasteWindow.hide(); @@ -5351,9 +5413,54 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc private void syncSelectionCursors() { mSelectCursorBaseLayerId = - nativeGetHandleLayerId(mNativeClass, HANDLE_ID_BASE, mSelectCursorBase); + nativeGetHandleLayerId(mNativeClass, HANDLE_ID_BASE, + mSelectCursorBase, mSelectCursorBaseTextQuad); mSelectCursorExtentLayerId = - nativeGetHandleLayerId(mNativeClass, HANDLE_ID_EXTENT, mSelectCursorExtent); + nativeGetHandleLayerId(mNativeClass, HANDLE_ID_EXTENT, + mSelectCursorExtent, mSelectCursorExtentTextQuad); + } + + private void adjustSelectionCursors() { + boolean wasDraggingStart = (mSelectDraggingCursor == mSelectCursorBase); + int oldX = mSelectDraggingCursor.x; + int oldY = mSelectDraggingCursor.y; + int oldStartX = mSelectCursorBase.x; + int oldStartY = mSelectCursorBase.y; + int oldEndX = mSelectCursorExtent.x; + int oldEndY = mSelectCursorExtent.y; + + syncSelectionCursors(); + boolean dragChanged = oldX != mSelectDraggingCursor.x || + oldY != mSelectDraggingCursor.y; + if (dragChanged && !mIsCaretSelection) { + boolean draggingStart; + if (wasDraggingStart) { + float endStart = distanceSquared(oldEndX, oldEndY, + mSelectCursorBase); + float endEnd = distanceSquared(oldEndX, oldEndY, + mSelectCursorExtent); + draggingStart = endStart > endEnd; + } else { + float startStart = distanceSquared(oldStartX, oldStartY, + mSelectCursorBase); + float startEnd = distanceSquared(oldStartX, oldStartY, + mSelectCursorExtent); + draggingStart = startStart > startEnd; + } + mSelectDraggingCursor = (draggingStart + ? mSelectCursorBase : mSelectCursorExtent); + mSelectDraggingTextQuad = (draggingStart + ? mSelectCursorBaseTextQuad : mSelectCursorExtentTextQuad); + mSelectDraggingOffset = (draggingStart + ? mSelectHandleLeftOffset : mSelectHandleRightOffset); + } + mSelectDraggingCursor.set(oldX, oldY); + } + + private float distanceSquared(int x, int y, Point p) { + float dx = p.x - x; + float dy = p.y - y; + return (dx * dx) + (dy * dy); } private boolean setupWebkitSelect() { @@ -5370,14 +5477,14 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc private void updateWebkitSelection() { int[] handles = null; if (mIsCaretSelection) { - mSelectCursorExtent.set(mSelectCursorBase); + mSelectCursorExtent.set(mSelectCursorBase.x, mSelectCursorBase.y); } if (mSelectingText) { handles = new int[4]; - handles[0] = mSelectCursorBase.centerX(); - handles[1] = mSelectCursorBase.centerY(); - handles[2] = mSelectCursorExtent.centerX(); - handles[3] = mSelectCursorExtent.centerY(); + handles[0] = mSelectCursorBase.x; + handles[1] = mSelectCursorBase.y; + handles[2] = mSelectCursorExtent.x; + handles[3] = mSelectCursorExtent.y; } else { nativeSetTextSelection(mNativeClass, 0); } @@ -5968,12 +6075,15 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc } mSelectionStarted = false; if (mSelectingText) { + ensureSelectionHandles(); int shiftedY = y - getTitleHeight() + getScrollY(); int shiftedX = x + getScrollX(); if (mSelectHandleCenter != null && mSelectHandleCenter.getBounds() .contains(shiftedX, shiftedY)) { mSelectionStarted = true; mSelectDraggingCursor = mSelectCursorBase; + mSelectDraggingOffset = mSelectHandleCenterOffset; + mSelectDraggingTextQuad = mSelectCursorBaseTextQuad; mPrivateHandler.removeMessages(CLEAR_CARET_HANDLE); hidePasteButton(); } else if (mSelectHandleLeft != null @@ -5981,19 +6091,18 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc .contains(shiftedX, shiftedY)) { mSelectionStarted = true; mSelectDraggingCursor = mSelectCursorBase; + mSelectDraggingOffset = mSelectHandleLeftOffset; + mSelectDraggingTextQuad = mSelectCursorBaseTextQuad; } else if (mSelectHandleRight != null && mSelectHandleRight.getBounds() .contains(shiftedX, shiftedY)) { mSelectionStarted = true; mSelectDraggingCursor = mSelectCursorExtent; + mSelectDraggingOffset = mSelectHandleRightOffset; + mSelectDraggingTextQuad = mSelectCursorExtentTextQuad; } else if (mIsCaretSelection) { selectionDone(); } - if (mSelectDraggingCursor != null) { - mSelectDraggingOffset.set( - mSelectDraggingCursor.left - contentX, - mSelectDraggingCursor.top - contentY); - } if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "select=" + contentX + "," + contentY); } @@ -6073,9 +6182,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc parent.requestDisallowInterceptTouchEvent(true); } if (deltaX != 0 || deltaY != 0) { - mSelectDraggingCursor.offsetTo( - contentX + mSelectDraggingOffset.x, - contentY + mSelectDraggingOffset.y); + snapDraggingCursor(contentX, contentY); updateWebkitSelection(); mLastTouchX = x; mLastTouchY = y; @@ -6684,6 +6791,30 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc mTouchMode = TOUCH_DONE_MODE; } + private void snapDraggingCursor(int x, int y) { + x += viewToContentDimension(mSelectDraggingOffset.x); + y += viewToContentDimension(mSelectDraggingOffset.y); + if (mSelectDraggingTextQuad.containsPoint(x, y)) { + float scale = scaleAlongSegment(x, y, + mSelectDraggingTextQuad.p4, mSelectDraggingTextQuad.p3); + // clamp scale to ensure point is on the bottom segment + scale = Math.max(0.0f, scale); + scale = Math.min(scale, 1.0f); + float newX = scaleCoordinate(scale, + mSelectDraggingTextQuad.p4.x, mSelectDraggingTextQuad.p3.x); + float newY = scaleCoordinate(scale, + mSelectDraggingTextQuad.p4.y, mSelectDraggingTextQuad.p3.y); + mSelectDraggingCursor.set(Math.round(newX), Math.round(newY)); + } else { + mSelectDraggingCursor.set(x, y); + } + } + + private static float scaleCoordinate(float scale, float coord1, float coord2) { + float diff = coord2 - coord1; + return coord1 + (scale * diff); + } + @Override public boolean onGenericMotionEvent(MotionEvent event) { if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { @@ -8735,6 +8866,8 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc setupWebkitSelect(); } else if (!mSelectionStarted) { syncSelectionCursors(); + } else { + adjustSelectionCursors(); } if (mIsCaretSelection) { resetCaretTimer(); @@ -9398,7 +9531,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc private static native void nativeSetPauseDrawing(int instance, boolean pause); private static native void nativeSetTextSelection(int instance, int selection); private static native int nativeGetHandleLayerId(int instance, int handle, - Rect cursorLocation); + Point cursorLocation, QuadF textQuad); private static native boolean nativeIsBaseFirst(int instance); private static native void nativeMapLayerRect(int instance, int layerId, Rect rect); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 2c7a120..4bdb3e2 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -5251,7 +5251,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { - createEditorIfNeeded("onCreateInputConnection"); if (onCheckIsTextEditor() && isEnabled()) { if (getEditor().mInputMethodState == null) { getEditor().mInputMethodState = new InputMethodState(); diff --git a/core/res/res/layout/notification_intruder_content.xml b/core/res/res/layout/notification_intruder_content.xml index 61be5f5..7f37032 100644 --- a/core/res/res/layout/notification_intruder_content.xml +++ b/core/res/res/layout/notification_intruder_content.xml @@ -2,7 +2,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:background="#FF333333" android:padding="4dp" > <ImageView android:id="@+id/icon" @@ -39,29 +38,35 @@ <LinearLayout android:id="@+id/actions" android:layout_width="match_parent" - android:layout_height="40dp" + android:layout_height="wrap_content" android:layout_marginTop="48dp" android:orientation="horizontal" android:visibility="gone" > - <ImageView + <Button + style="?android:attr/buttonBarButtonStyle" + android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title" android:id="@+id/action0" android:layout_width="0dp" - android:layout_height="match_parent" + android:layout_height="wrap_content" android:layout_weight="1" android:visibility="gone" /> - <ImageView + <Button + style="?android:attr/buttonBarButtonStyle" + android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title" android:id="@+id/action1" android:layout_width="0dp" - android:layout_height="match_parent" + android:layout_height="wrap_content" android:layout_weight="1" android:visibility="gone" /> - <ImageView + <Button + style="?android:attr/buttonBarButtonStyle" + android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title" android:id="@+id/action2" android:layout_width="0dp" - android:layout_height="match_parent" + android:layout_height="wrap_content" android:layout_weight="1" android:visibility="gone" /> diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java index 27363e8..a6057de 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java @@ -215,7 +215,9 @@ public class AccessPointParserHelper { config.phase2.setValue(""); config.ca_cert.setValue(""); config.client_cert.setValue(""); - config.private_key.setValue(""); + config.engine.setValue(""); + config.engine_id.setValue(""); + config.key_id.setValue(""); config.identity.setValue(""); config.anonymous_identity.setValue(""); break; |
