summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ActivityThread.java52
-rw-r--r--core/java/android/content/Context.java11
-rw-r--r--core/java/android/content/res/Configuration.java23
-rw-r--r--core/java/android/os/IUpdateLock.aidl27
-rwxr-xr-xcore/java/android/os/TokenWatcher.java22
-rw-r--r--core/java/android/os/UpdateLock.java166
-rw-r--r--core/java/android/text/Html.java25
-rw-r--r--core/java/android/text/TextDirectionHeuristics.java3
-rw-r--r--core/java/android/util/LocaleUtil.java27
-rw-r--r--core/java/android/view/View.java4
-rw-r--r--core/java/android/view/animation/Animation.java2
-rw-r--r--core/java/android/view/inputmethod/BaseInputConnection.java9
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java4
-rw-r--r--core/java/android/webkit/WebView.java56
-rw-r--r--core/java/android/webkit/WebViewCore.java9
-rw-r--r--core/java/android/widget/TextView.java145
-rw-r--r--core/java/com/android/internal/util/FileRotator.java2
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java32
18 files changed, 426 insertions, 193 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5d1d461..1230c81 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3986,31 +3986,39 @@ public final class ActivityThread {
dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
}
- // If the app is being launched for full backup or restore, bring it up in
- // a restricted environment with the base application class.
- Application app = data.info.makeApplication(data.restrictedBackupMode, null);
- mInitialApplication = app;
-
- // don't bring up providers in restricted mode; they may depend on the
- // app's custom Application class
- if (!data.restrictedBackupMode){
- List<ProviderInfo> providers = data.providers;
- if (providers != null) {
- installContentProviders(app, providers);
- // For process that contains content providers, we want to
- // ensure that the JIT is enabled "at some point".
- mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
+ // Allow disk access during application and provider setup. This could
+ // block processing ordered broadcasts, but later processing would
+ // probably end up doing the same disk access.
+ final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
+ try {
+ // If the app is being launched for full backup or restore, bring it up in
+ // a restricted environment with the base application class.
+ Application app = data.info.makeApplication(data.restrictedBackupMode, null);
+ mInitialApplication = app;
+
+ // don't bring up providers in restricted mode; they may depend on the
+ // app's custom Application class
+ if (!data.restrictedBackupMode) {
+ List<ProviderInfo> providers = data.providers;
+ if (providers != null) {
+ installContentProviders(app, providers);
+ // For process that contains content providers, we want to
+ // ensure that the JIT is enabled "at some point".
+ mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
+ }
}
- }
- try {
- mInstrumentation.callApplicationOnCreate(app);
- } catch (Exception e) {
- if (!mInstrumentation.onException(app, e)) {
- throw new RuntimeException(
- "Unable to create application " + app.getClass().getName()
- + ": " + e.toString(), e);
+ try {
+ mInstrumentation.callApplicationOnCreate(app);
+ } catch (Exception e) {
+ if (!mInstrumentation.onException(app, e)) {
+ throw new RuntimeException(
+ "Unable to create application " + app.getClass().getName()
+ + ": " + e.toString(), e);
+ }
}
+ } finally {
+ StrictMode.setThreadPolicy(savedPolicy);
}
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a1198de..111f45e 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1646,6 +1646,17 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a {@link
+ * android.os.IUpdateLock} for managing runtime sequences that
+ * must not be interrupted by headless OTA application or similar.
+ *
+ * @hide
+ * @see #getSystemService
+ * @see android.os.UpdateLock
+ */
+ public static final String UPDATE_LOCK_SERVICE = "updatelock";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a {@link
* android.net.NetworkManagementService} for handling management of
* system network services
*
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index e04b2f7..079f739 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -20,6 +20,7 @@ import android.content.pm.ActivityInfo;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.LocaleUtil;
+import android.view.View;
import java.util.Locale;
@@ -280,9 +281,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public int compatSmallestScreenWidthDp;
/**
- * @hide The text layout direction associated to the current Locale
+ * @hide The layout direction associated to the current Locale
*/
- public int textLayoutDirection;
+ public int layoutDirection;
/**
* @hide Internal book-keeping.
@@ -310,7 +311,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
mnc = o.mnc;
if (o.locale != null) {
locale = (Locale) o.locale.clone();
- textLayoutDirection = o.textLayoutDirection;
+ layoutDirection = o.layoutDirection;
}
userSetLocale = o.userSetLocale;
touchscreen = o.touchscreen;
@@ -346,10 +347,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
} else {
sb.append(" (no locale)");
}
- switch (textLayoutDirection) {
- case LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE: /* ltr not interesting */ break;
- case LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE: sb.append(" rtl"); break;
- default: sb.append(" layoutdir="); sb.append(textLayoutDirection); break;
+ switch (layoutDirection) {
+ case View.LAYOUT_DIRECTION_LTR: /* ltr not interesting */ break;
+ case View.LAYOUT_DIRECTION_RTL: sb.append(" rtl"); break;
+ default: sb.append(" layoutDir="); sb.append(layoutDirection); break;
}
if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
sb.append(" sw"); sb.append(smallestScreenWidthDp); sb.append("dp");
@@ -472,7 +473,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
- textLayoutDirection = LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
+ layoutDirection = View.LAYOUT_DIRECTION_LTR;
seq = 0;
}
@@ -508,7 +509,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
changed |= ActivityInfo.CONFIG_LOCALE;
locale = delta.locale != null
? (Locale) delta.locale.clone() : null;
- textLayoutDirection = LocaleUtil.getLayoutDirectionFromLocale(locale);
+ layoutDirection = LocaleUtil.getLayoutDirectionFromLocale(locale);
}
if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
{
@@ -776,7 +777,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
dest.writeInt(compatScreenWidthDp);
dest.writeInt(compatScreenHeightDp);
dest.writeInt(compatSmallestScreenWidthDp);
- dest.writeInt(textLayoutDirection);
+ dest.writeInt(layoutDirection);
dest.writeInt(seq);
}
@@ -804,7 +805,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
compatScreenWidthDp = source.readInt();
compatScreenHeightDp = source.readInt();
compatSmallestScreenWidthDp = source.readInt();
- textLayoutDirection = source.readInt();
+ layoutDirection = source.readInt();
seq = source.readInt();
}
diff --git a/core/java/android/os/IUpdateLock.aidl b/core/java/android/os/IUpdateLock.aidl
new file mode 100644
index 0000000..4492fb8
--- /dev/null
+++ b/core/java/android/os/IUpdateLock.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.os;
+
+/**
+ * Direct interface to the UpdateLockService's functionality
+ *
+ * {@hide}
+ */
+interface IUpdateLock {
+ void acquireUpdateLock(IBinder token, String tag);
+ void releaseUpdateLock(IBinder token);
+}
diff --git a/core/java/android/os/TokenWatcher.java b/core/java/android/os/TokenWatcher.java
index ac3cc92..9b3a2d6 100755
--- a/core/java/android/os/TokenWatcher.java
+++ b/core/java/android/os/TokenWatcher.java
@@ -16,6 +16,8 @@
package android.os;
+import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.WeakHashMap;
import java.util.Set;
import android.util.Log;
@@ -115,15 +117,31 @@ public abstract class TokenWatcher
public void dump()
{
+ ArrayList<String> a = dumpInternal();
+ for (String s : a) {
+ Log.i(mTag, s);
+ }
+ }
+
+ public void dump(PrintWriter pw) {
+ ArrayList<String> a = dumpInternal();
+ for (String s : a) {
+ pw.println(s);
+ }
+ }
+
+ private ArrayList<String> dumpInternal() {
+ ArrayList<String> a = new ArrayList<String>();
synchronized (mTokens) {
Set<IBinder> keys = mTokens.keySet();
- Log.i(mTag, "Token count: " + mTokens.size());
+ a.add("Token count: " + mTokens.size());
int i = 0;
for (IBinder b: keys) {
- Log.i(mTag, "[" + i + "] " + mTokens.get(b).tag + " - " + b);
+ a.add("[" + i + "] " + mTokens.get(b).tag + " - " + b);
i++;
}
}
+ return a;
}
private Runnable mNotificationTask = new Runnable() {
diff --git a/core/java/android/os/UpdateLock.java b/core/java/android/os/UpdateLock.java
new file mode 100644
index 0000000..4060326
--- /dev/null
+++ b/core/java/android/os/UpdateLock.java
@@ -0,0 +1,166 @@
+/*
+ * 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.os;
+
+import android.content.Context;
+import android.util.Log;
+
+/**
+ * Advisory wakelock-like mechanism by which processes that should not be interrupted for
+ * OTA/update purposes can so advise the OS. This is particularly relevant for headless
+ * or kiosk-like operation.
+ *
+ * @hide
+ */
+public class UpdateLock {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "UpdateLock";
+
+ private static IUpdateLock sService;
+ private static void checkService() {
+ if (sService == null) {
+ sService = IUpdateLock.Stub.asInterface(
+ ServiceManager.getService(Context.UPDATE_LOCK_SERVICE));
+ }
+ }
+
+ IBinder mToken;
+ int mCount = 0;
+ boolean mRefCounted = true;
+ boolean mHeld = false;
+ final String mTag;
+
+ /**
+ * Broadcast Intent action sent when the global update lock state changes,
+ * i.e. when the first locker acquires an update lock, or when the last
+ * locker releases theirs. The broadcast is sticky but is sent only to
+ * registered receivers.
+ */
+ public static final String UPDATE_LOCK_CHANGED = "android.os.UpdateLock.UPDATE_LOCK_CHANGED";
+
+ /**
+ * Boolean Intent extra on the UPDATE_LOCK_CHANGED sticky broadcast, indicating
+ * whether now is an appropriate time to interrupt device activity with an
+ * update operation. True means that updates are okay right now; false indicates
+ * that perhaps later would be a better time.
+ */
+ public static final String NOW_IS_CONVENIENT = "nowisconvenient";
+
+ /**
+ * Long Intent extra on the UPDATE_LOCK_CHANGED sticky broadcast, marking the
+ * wall-clock time [in UTC] at which the broadcast was sent. Note that this is
+ * in the System.currentTimeMillis() time base, which may be non-monotonic especially
+ * around reboots.
+ */
+ public static final String TIMESTAMP = "timestamp";
+
+ /**
+ * Construct an UpdateLock instance.
+ * @param tag An arbitrary string used to identify this lock instance in dump output.
+ */
+ public UpdateLock(String tag) {
+ mTag = tag;
+ mToken = new Binder();
+ }
+
+ /**
+ * Change the refcount behavior of this update lock.
+ */
+ public void setReferenceCounted(boolean isRefCounted) {
+ if (DEBUG) {
+ Log.v(TAG, "setting refcounted=" + isRefCounted + " : " + this);
+ }
+ mRefCounted = isRefCounted;
+ }
+
+ /**
+ * Is this lock currently held?
+ */
+ public boolean isHeld() {
+ synchronized (mToken) {
+ return mHeld;
+ }
+ }
+
+ /**
+ * Acquire an update lock.
+ */
+ public void acquire() {
+ if (DEBUG) {
+ Log.v(TAG, "acquire() : " + this, new RuntimeException("here"));
+ }
+ checkService();
+ synchronized (mToken) {
+ acquireLocked();
+ }
+ }
+
+ private void acquireLocked() {
+ if (!mRefCounted || mCount++ == 0) {
+ if (sService != null) {
+ try {
+ sService.acquireUpdateLock(mToken, mTag);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to contact service to acquire");
+ }
+ }
+ mHeld = true;
+ }
+ }
+
+ /**
+ * Release this update lock.
+ */
+ public void release() {
+ if (DEBUG) Log.v(TAG, "release() : " + this, new RuntimeException("here"));
+ checkService();
+ synchronized (mToken) {
+ releaseLocked();
+ }
+ }
+
+ private void releaseLocked() {
+ if (!mRefCounted || --mCount == 0) {
+ if (sService != null) {
+ try {
+ sService.releaseUpdateLock(mToken);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to contact service to release");
+ }
+ }
+ mHeld = false;
+ }
+ if (mCount < 0) {
+ throw new RuntimeException("UpdateLock under-locked");
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ synchronized (mToken) {
+ // if mHeld is true, sService must be non-null
+ if (mHeld) {
+ Log.wtf(TAG, "UpdateLock finalized while still held");
+ try {
+ sService.releaseUpdateLock(mToken);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to contact service to release");
+ }
+ }
+ }
+ }
+}
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index ca7263c..8c97293 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -16,6 +16,7 @@
package android.text;
+import com.android.internal.util.ArrayUtils;
import org.ccil.cowan.tagsoup.HTMLSchema;
import org.ccil.cowan.tagsoup.Parser;
import org.xml.sax.Attributes;
@@ -45,13 +46,11 @@ import android.text.style.TextAppearanceSpan;
import android.text.style.TypefaceSpan;
import android.text.style.URLSpan;
import android.text.style.UnderlineSpan;
-import android.util.Log;
import com.android.internal.util.XmlUtils;
import java.io.IOException;
import java.io.StringReader;
-import java.nio.CharBuffer;
import java.util.HashMap;
/**
@@ -203,9 +202,26 @@ public class Html {
}
}
+ private static String getOpenParaTagWithDirection(Spanned text, int start, int end) {
+ final int len = end - start;
+ final byte[] levels = new byte[ArrayUtils.idealByteArraySize(len)];
+ final char[] buffer = TextUtils.obtain(len);
+ TextUtils.getChars(text, start, end, buffer, 0);
+
+ int paraDir = AndroidBidi.bidi(Layout.DIR_REQUEST_DEFAULT_LTR, buffer, levels, len,
+ false /* no info */);
+ switch(paraDir) {
+ case Layout.DIR_RIGHT_TO_LEFT:
+ return "<p dir=rtl>";
+ case Layout.DIR_LEFT_TO_RIGHT:
+ default:
+ return "<p dir=ltr>";
+ }
+ }
+
private static void withinBlockquote(StringBuilder out, Spanned text,
int start, int end) {
- out.append("<p>");
+ out.append(getOpenParaTagWithDirection(text, start, end));
int next;
for (int i = start; i < end; i = next) {
@@ -340,7 +356,7 @@ public class Html {
}
}
- String p = last ? "" : "</p>\n<p>";
+ String p = last ? "" : "</p>\n" + getOpenParaTagWithDirection(text, start, end);
if (nl == 1) {
out.append("<br>\n");
@@ -350,7 +366,6 @@ public class Html {
for (int i = 2; i < nl; i++) {
out.append("<br>");
}
-
out.append(p);
}
}
diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java
index ae41eab..6ca6161 100644
--- a/core/java/android/text/TextDirectionHeuristics.java
+++ b/core/java/android/text/TextDirectionHeuristics.java
@@ -18,6 +18,7 @@ package android.text;
import android.util.LocaleUtil;
+import android.view.View;
/**
* Some objects that implement TextDirectionHeuristic.
@@ -240,7 +241,7 @@ public class TextDirectionHeuristics {
@Override
protected boolean defaultIsRtl() {
final int dir = LocaleUtil.getLayoutDirectionFromLocale(java.util.Locale.getDefault());
- return (dir == LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE);
+ return (dir == View.LAYOUT_DIRECTION_RTL);
}
public static final TextDirectionHeuristicLocale INSTANCE =
diff --git a/core/java/android/util/LocaleUtil.java b/core/java/android/util/LocaleUtil.java
index 4d773f6..9953252 100644
--- a/core/java/android/util/LocaleUtil.java
+++ b/core/java/android/util/LocaleUtil.java
@@ -18,6 +18,7 @@ package android.util;
import java.util.Locale;
+import android.view.View;
import libcore.icu.ICU;
/**
@@ -29,16 +30,6 @@ public class LocaleUtil {
private LocaleUtil() { /* cannot be instantiated */ }
- /**
- * @hide Do not use. Implementation not finished.
- */
- public static final int TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE = 0;
-
- /**
- * @hide Do not use. Implementation not finished.
- */
- public static final int TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE = 1;
-
private static String ARAB_SCRIPT_SUBTAG = "Arab";
private static String HEBR_SCRIPT_SUBTAG = "Hebr";
@@ -47,8 +38,8 @@ public class LocaleUtil {
*
* @param locale the Locale for which we want the layout direction. Can be null.
* @return the layout direction. This may be one of:
- * {@link #TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE} or
- * {@link #TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE}.
+ * {@link View#LAYOUT_DIRECTION_LTR} or
+ * {@link View#LAYOUT_DIRECTION_RTL}.
*
* Be careful: this code will need to be changed when vertical scripts will be supported
*
@@ -61,11 +52,11 @@ public class LocaleUtil {
if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG) ||
scriptSubtag.equalsIgnoreCase(HEBR_SCRIPT_SUBTAG)) {
- return TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE;
+ return View.LAYOUT_DIRECTION_RTL;
}
}
- return TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
+ return View.LAYOUT_DIRECTION_LTR;
}
/**
@@ -75,8 +66,8 @@ public class LocaleUtil {
*
* @param locale
* @return the layout direction. This may be one of:
- * {@link #TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE} or
- * {@link #TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE}.
+ * {@link View#LAYOUT_DIRECTION_LTR} or
+ * {@link View#LAYOUT_DIRECTION_RTL}.
*
* Be careful: this code will need to be changed when vertical scripts will be supported
*
@@ -86,11 +77,11 @@ public class LocaleUtil {
switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
- return TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE;
+ return View.LAYOUT_DIRECTION_RTL;
case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
default:
- return TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
+ return View.LAYOUT_DIRECTION_LTR;
}
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e6b41da..5cf0459 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -40,7 +40,6 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
@@ -9711,8 +9710,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @hide
*/
protected static boolean isLayoutDirectionRtl(Locale locale) {
- return (LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE ==
- LocaleUtil.getLayoutDirectionFromLocale(locale));
+ return (LAYOUT_DIRECTION_RTL == LocaleUtil.getLayoutDirectionFromLocale(locale));
}
/**
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index e8c0239..dc8c71b 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -913,7 +913,7 @@ public abstract class Animation implements Cloneable {
*
* @param interpolatedTime The value of the normalized time (0.0 to 1.0)
* after it has been run through the interpolation function.
- * @param t The Transofrmation object to fill in with the current
+ * @param t The Transformation object to fill in with the current
* transforms.
*/
protected void applyTransformation(float interpolatedTime, Transformation t) {
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 89aba3c..7ec5398 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -152,6 +152,15 @@ public class BaseInputConnection implements InputConnection {
}
/**
+ * Called when this InputConnection is no longer used by the InputMethodManager.
+ *
+ * @hide
+ */
+ protected void reportFinish() {
+ // Intentionaly empty
+ }
+
+ /**
* Default implementation uses
* {@link MetaKeyKeyListener#clearMetaKeyState(long, int)
* MetaKeyKeyListener.clearMetaKeyState(long, int)} to clear the state.
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index b6b27c1..3b6ebbe 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -708,6 +708,10 @@ public final class InputMethodManager {
public void reportFinishInputConnection(InputConnection ic) {
if (mServedInputConnection != ic) {
ic.finishComposingText();
+ // To avoid modifying the public InputConnection interface
+ if (ic instanceof BaseInputConnection) {
+ ((BaseInputConnection) ic).reportFinish();
+ }
}
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 424dd6d..af3bb4d 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -378,6 +378,7 @@ public class WebView extends AbsoluteLayout
private int mInputType;
private int mImeOptions;
private String mHint;
+ private int mMaxLength;
public WebViewInputConnection() {
super(WebView.this, true);
@@ -412,13 +413,9 @@ public class WebView extends AbsoluteLayout
Editable editable = getEditable();
int selectionStart = Selection.getSelectionStart(editable);
int selectionEnd = Selection.getSelectionEnd(editable);
+ text = limitReplaceTextByMaxLength(text, editable.length());
editable.replace(0, editable.length(), text);
- InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null) {
- // Since the text has changed, do not allow the IME to replace the
- // existing text as though it were a completion.
- imm.restartInput(WebView.this);
- }
+ restartInput();
// Keep the previous selection.
selectionStart = Math.min(selectionStart, editable.length());
selectionEnd = Math.min(selectionEnd, editable.length());
@@ -429,14 +426,10 @@ public class WebView extends AbsoluteLayout
Editable editable = getEditable();
int selectionStart = Selection.getSelectionStart(editable);
int selectionEnd = Selection.getSelectionEnd(editable);
+ text = limitReplaceTextByMaxLength(text, selectionEnd - selectionStart);
setNewText(selectionStart, selectionEnd, text);
editable.replace(selectionStart, selectionEnd, text);
- InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null) {
- // Since the text has changed, do not allow the IME to replace the
- // existing text as though it were a completion.
- imm.restartInput(WebView.this);
- }
+ restartInput();
// Move caret to the end of the new text
int newCaret = selectionStart + text.length();
setSelection(newCaret, newCaret);
@@ -456,8 +449,19 @@ public class WebView extends AbsoluteLayout
end = start;
start = temp;
}
- setNewText(start, end, text);
- return super.setComposingText(text, newCursorPosition);
+ CharSequence limitedText = limitReplaceTextByMaxLength(text, end - start);
+ setNewText(start, end, limitedText);
+ if (limitedText != text) {
+ newCursorPosition -= text.length() - limitedText.length();
+ }
+ super.setComposingText(limitedText, newCursorPosition);
+ if (limitedText != text) {
+ restartInput();
+ int lastCaret = start + limitedText.length();
+ finishComposingText();
+ setSelection(lastCaret, lastCaret);
+ }
+ return true;
}
@Override
@@ -573,6 +577,7 @@ public class WebView extends AbsoluteLayout
mHint = initData.mLabel;
mInputType = inputType;
mImeOptions = imeOptions;
+ mMaxLength = initData.mMaxLength;
}
public void setupEditorInfo(EditorInfo outAttrs) {
@@ -660,6 +665,29 @@ public class WebView extends AbsoluteLayout
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD));
}
+
+ private CharSequence limitReplaceTextByMaxLength(CharSequence text,
+ int numReplaced) {
+ if (mMaxLength > 0) {
+ Editable editable = getEditable();
+ int maxReplace = mMaxLength - editable.length() + numReplaced;
+ if (maxReplace < text.length()) {
+ maxReplace = Math.max(maxReplace, 0);
+ // New length is greater than the maximum. trim it down.
+ text = text.subSequence(0, maxReplace);
+ }
+ }
+ return text;
+ }
+
+ private void restartInput() {
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ // Since the text has changed, do not allow the IME to replace the
+ // existing text as though it were a completion.
+ imm.restartInput(WebView.this);
+ }
+ }
}
private class PastePopupWindow extends PopupWindow implements OnClickListener {
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index e7da1a8..93fd92b 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -923,13 +923,14 @@ public final class WebViewCore {
static class TextFieldInitData {
public TextFieldInitData(int fieldPointer,
String text, int type, boolean isSpellCheckEnabled,
- boolean isTextFieldNext, String label) {
+ boolean isTextFieldNext, String label, int maxLength) {
mFieldPointer = fieldPointer;
mText = text;
mType = type;
mIsSpellCheckEnabled = isSpellCheckEnabled;
mIsTextFieldNext = isTextFieldNext;
mLabel = label;
+ mMaxLength = maxLength;
}
int mFieldPointer;
String mText;
@@ -937,6 +938,7 @@ public final class WebViewCore {
boolean mIsSpellCheckEnabled;
boolean mIsTextFieldNext;
String mLabel;
+ int mMaxLength;
}
// mAction of TouchEventData can be MotionEvent.getAction() which uses the
@@ -2826,12 +2828,13 @@ public final class WebViewCore {
// called by JNI
private void initEditField(int pointer, String text, int inputType,
boolean isSpellCheckEnabled, boolean nextFieldIsText,
- String label, int start, int end, int selectionPtr) {
+ String label, int start, int end, int selectionPtr, int maxLength) {
if (mWebView == null) {
return;
}
TextFieldInitData initData = new TextFieldInitData(pointer,
- text, inputType, isSpellCheckEnabled, nextFieldIsText, label);
+ text, inputType, isSpellCheckEnabled, nextFieldIsText, label,
+ maxLength);
Message.obtain(mWebView.mPrivateHandler,
WebView.INIT_EDIT_FIELD, initData).sendToTarget();
Message.obtain(mWebView.mPrivateHandler,
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f384dc1..a162eaa 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -243,10 +243,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private static final int SIGNED = 2;
private static final int DECIMAL = 4;
- private static enum TEXT_ALIGN {
- INHERIT, GRAVITY, TEXT_START, TEXT_END, CENTER, VIEW_START, VIEW_END;
- }
-
/**
* Draw marquee text with fading edges as usual
*/
@@ -329,9 +325,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// The alignment to pass to Layout, or null if not resolved.
private Layout.Alignment mLayoutAlignment;
- // The default value for mTextAlign.
- private TEXT_ALIGN mTextAlign = TEXT_ALIGN.INHERIT;
-
private boolean mResolvedDrawables;
/**
@@ -5667,69 +5660,28 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
physicalWidth, false);
}
- @Override
- protected void resetResolvedLayoutDirection() {
- super.resetResolvedLayoutDirection();
-
- if (mLayoutAlignment != null &&
- (mTextAlign == TEXT_ALIGN.VIEW_START ||
- mTextAlign == TEXT_ALIGN.VIEW_END)) {
- mLayoutAlignment = null;
- }
- }
-
private Layout.Alignment getLayoutAlignment() {
if (mLayoutAlignment == null) {
- Layout.Alignment alignment;
- TEXT_ALIGN textAlign = mTextAlign;
- switch (textAlign) {
- case INHERIT:
- // fall through to gravity temporarily
- // intention is to inherit value through view hierarchy.
- case GRAVITY:
- switch (mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) {
- case Gravity.START:
- alignment = Layout.Alignment.ALIGN_NORMAL;
- break;
- case Gravity.END:
- alignment = Layout.Alignment.ALIGN_OPPOSITE;
- break;
- case Gravity.LEFT:
- alignment = Layout.Alignment.ALIGN_LEFT;
- break;
- case Gravity.RIGHT:
- alignment = Layout.Alignment.ALIGN_RIGHT;
- break;
- case Gravity.CENTER_HORIZONTAL:
- alignment = Layout.Alignment.ALIGN_CENTER;
- break;
- default:
- alignment = Layout.Alignment.ALIGN_NORMAL;
- break;
- }
- break;
- case TEXT_START:
- alignment = Layout.Alignment.ALIGN_NORMAL;
+ switch (mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) {
+ case Gravity.START:
+ mLayoutAlignment = Layout.Alignment.ALIGN_NORMAL;
break;
- case TEXT_END:
- alignment = Layout.Alignment.ALIGN_OPPOSITE;
+ case Gravity.END:
+ mLayoutAlignment = Layout.Alignment.ALIGN_OPPOSITE;
break;
- case CENTER:
- alignment = Layout.Alignment.ALIGN_CENTER;
+ case Gravity.LEFT:
+ mLayoutAlignment = Layout.Alignment.ALIGN_LEFT;
break;
- case VIEW_START:
- alignment = (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
- Layout.Alignment.ALIGN_RIGHT : Layout.Alignment.ALIGN_LEFT;
+ case Gravity.RIGHT:
+ mLayoutAlignment = Layout.Alignment.ALIGN_RIGHT;
break;
- case VIEW_END:
- alignment = (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
- Layout.Alignment.ALIGN_LEFT : Layout.Alignment.ALIGN_RIGHT;
+ case Gravity.CENTER_HORIZONTAL:
+ mLayoutAlignment = Layout.Alignment.ALIGN_CENTER;
break;
default:
- alignment = Layout.Alignment.ALIGN_NORMAL;
+ mLayoutAlignment = Layout.Alignment.ALIGN_NORMAL;
break;
}
- mLayoutAlignment = alignment;
}
return mLayoutAlignment;
}
@@ -6044,7 +5996,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (des < 0) {
des = (int) FloatMath.ceil(Layout.getDesiredWidth(mTransformed, mTextPaint));
}
-
width = des;
} else {
width = boring.width;
@@ -6065,7 +6016,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
if (hintDes < 0) {
- hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mHintBoring);
+ hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir, mHintBoring);
if (hintBoring != null) {
mHintBoring = hintBoring;
}
@@ -6073,10 +6024,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (hintBoring == null || hintBoring == UNKNOWN_BORING) {
if (hintDes < 0) {
- hintDes = (int) FloatMath.ceil(
- Layout.getDesiredWidth(mHint, mTextPaint));
+ hintDes = (int) FloatMath.ceil(Layout.getDesiredWidth(mHint, mTextPaint));
}
-
hintWidth = hintDes;
} else {
hintWidth = hintBoring.width;
@@ -6340,20 +6289,25 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (changed && mEditor != null) getEditor().mTextDisplayListIsValid = false;
}
+ private boolean isShowingHint() {
+ return TextUtils.isEmpty(mText) && !TextUtils.isEmpty(mHint);
+ }
+
/**
* Returns true if anything changed.
*/
private boolean bringTextIntoView() {
+ Layout layout = isShowingHint() ? mHintLayout : mLayout;
int line = 0;
if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM) {
- line = mLayout.getLineCount() - 1;
+ line = layout.getLineCount() - 1;
}
- Layout.Alignment a = mLayout.getParagraphAlignment(line);
- int dir = mLayout.getParagraphDirection(line);
+ Layout.Alignment a = layout.getParagraphAlignment(line);
+ int dir = layout.getParagraphDirection(line);
int hspace = mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight();
int vspace = mBottom - mTop - getExtendedPaddingTop() - getExtendedPaddingBottom();
- int ht = mLayout.getHeight();
+ int ht = layout.getHeight();
int scrollx, scrolly;
@@ -6372,8 +6326,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* keep leading edge in view.
*/
- int left = (int) FloatMath.floor(mLayout.getLineLeft(line));
- int right = (int) FloatMath.ceil(mLayout.getLineRight(line));
+ int left = (int) FloatMath.floor(layout.getLineLeft(line));
+ int right = (int) FloatMath.ceil(layout.getLineRight(line));
if (right - left < hspace) {
scrollx = (right + left) / 2 - hspace / 2;
@@ -6385,10 +6339,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
} else if (a == Layout.Alignment.ALIGN_RIGHT) {
- int right = (int) FloatMath.ceil(mLayout.getLineRight(line));
+ int right = (int) FloatMath.ceil(layout.getLineRight(line));
scrollx = right - hspace;
} else { // a == Layout.Alignment.ALIGN_LEFT (will also be the default)
- scrollx = (int) FloatMath.floor(mLayout.getLineLeft(line));
+ scrollx = (int) FloatMath.floor(layout.getLineLeft(line));
}
if (ht < vspace) {
@@ -6416,22 +6370,24 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public boolean bringPointIntoView(int offset) {
boolean changed = false;
- if (mLayout == null) return changed;
+ Layout layout = isShowingHint() ? mHintLayout: mLayout;
+
+ if (layout == null) return changed;
- int line = mLayout.getLineForOffset(offset);
+ int line = layout.getLineForOffset(offset);
// FIXME: Is it okay to truncate this, or should we round?
- final int x = (int)mLayout.getPrimaryHorizontal(offset);
- final int top = mLayout.getLineTop(line);
- final int bottom = mLayout.getLineTop(line + 1);
+ final int x = (int)layout.getPrimaryHorizontal(offset);
+ final int top = layout.getLineTop(line);
+ final int bottom = layout.getLineTop(line + 1);
- int left = (int) FloatMath.floor(mLayout.getLineLeft(line));
- int right = (int) FloatMath.ceil(mLayout.getLineRight(line));
- int ht = mLayout.getHeight();
+ int left = (int) FloatMath.floor(layout.getLineLeft(line));
+ int right = (int) FloatMath.ceil(layout.getLineRight(line));
+ int ht = layout.getHeight();
int grav;
- switch (mLayout.getParagraphAlignment(line)) {
+ switch (layout.getParagraphAlignment(line)) {
case ALIGN_LEFT:
grav = 1;
break;
@@ -6439,10 +6395,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
grav = -1;
break;
case ALIGN_NORMAL:
- grav = mLayout.getParagraphDirection(line);
+ grav = layout.getParagraphDirection(line);
break;
case ALIGN_OPPOSITE:
- grav = -mLayout.getParagraphDirection(line);
+ grav = -layout.getParagraphDirection(line);
break;
case ALIGN_CENTER:
default:
@@ -8189,24 +8145,26 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public boolean performLongClick() {
boolean handled = false;
- boolean vibrate = true;
if (super.performLongClick()) {
handled = true;
}
+ if (mEditor == null) {
+ return handled;
+ }
+
// Long press in empty space moves cursor and shows the Paste affordance if available.
- if (!handled && mEditor != null && !isPositionOnText(getEditor().mLastDownPositionX, getEditor().mLastDownPositionY) &&
+ if (!handled && !isPositionOnText(getEditor().mLastDownPositionX, getEditor().mLastDownPositionY) &&
getEditor().mInsertionControllerEnabled) {
final int offset = getOffsetForPosition(getEditor().mLastDownPositionX, getEditor().mLastDownPositionY);
stopSelectionActionMode();
Selection.setSelection((Spannable) mText, offset);
getInsertionController().showWithActionPopup();
handled = true;
- vibrate = false;
}
- if (!handled && mEditor != null && getEditor().mSelectionActionMode != null) {
+ if (!handled && getEditor().mSelectionActionMode != null) {
if (touchPositionIsInSelection()) {
// Start a drag
final int start = getSelectionStart();
@@ -8225,15 +8183,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
// Start a new selection
- if (!handled && mEditor != null) {
- vibrate = handled = startSelectionActionMode();
+ if (!handled) {
+ handled = startSelectionActionMode();
}
- if (vibrate) {
+ if (handled) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- }
-
- if (handled && mEditor != null) {
getEditor().mDiscardNextActionUp = true;
}
@@ -8759,6 +8714,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void onResolveTextDirection() {
if (hasPasswordTransformationMethod()) {
+ // TODO: take care of the content direction to show the password text and dots justified
+ // to the left or to the right
mTextDir = TextDirectionHeuristics.LOCALE;
return;
}
diff --git a/core/java/com/android/internal/util/FileRotator.java b/core/java/com/android/internal/util/FileRotator.java
index 8a8f315..6cfb97d 100644
--- a/core/java/com/android/internal/util/FileRotator.java
+++ b/core/java/com/android/internal/util/FileRotator.java
@@ -48,7 +48,7 @@ import libcore.io.IoUtils;
*/
public class FileRotator {
private static final String TAG = "FileRotator";
- private static final boolean LOGD = true;
+ private static final boolean LOGD = false;
private final File mBasePath;
private final String mPrefix;
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index 9579bce..4cbdf78 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -70,7 +70,7 @@ public class EditableInputConnection extends BaseInputConnection {
public boolean endBatchEdit() {
synchronized(this) {
if (mBatchEditNesting > 0) {
- // When the connection is reset by the InputMethodManager and finishComposingText
+ // When the connection is reset by the InputMethodManager and reportFinish
// is called, some endBatchEdit calls may still be asynchronously received from the
// IME. Do not take these into account, thus ensuring that this IC's final
// contribution to mTextView's nested batch edit count is zero.
@@ -83,6 +83,19 @@ public class EditableInputConnection extends BaseInputConnection {
}
@Override
+ protected void reportFinish() {
+ super.reportFinish();
+
+ synchronized(this) {
+ while (mBatchEditNesting > 0) {
+ endBatchEdit();
+ }
+ // Will prevent any further calls to begin or endBatchEdit
+ mBatchEditNesting = -1;
+ }
+ }
+
+ @Override
public boolean clearMetaKeyStates(int states) {
final Editable content = getEditable();
if (content == null) return false;
@@ -99,23 +112,6 @@ public class EditableInputConnection extends BaseInputConnection {
}
@Override
- public boolean finishComposingText() {
- final boolean superResult = super.finishComposingText();
- synchronized(this) {
- if (mBatchEditNesting < 0) {
- // The connection was already finished
- return false;
- }
- while (mBatchEditNesting > 0) {
- endBatchEdit();
- }
- // Will prevent any further calls to begin or endBatchEdit
- mBatchEditNesting = -1;
- }
- return superResult;
- }
-
- @Override
public boolean commitCompletion(CompletionInfo text) {
if (DEBUG) Log.v(TAG, "commitCompletion " + text);
mTextView.beginBatchEdit();