summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/java/android/content/XmlDocumentProvider.java438
-rw-r--r--core/java/android/speech/tts/AudioPlaybackHandler.java7
-rw-r--r--core/java/android/speech/tts/EventLogTags.logtags6
-rw-r--r--core/java/android/speech/tts/EventLogger.java175
-rw-r--r--core/java/android/speech/tts/PlaybackSynthesisCallback.java33
-rw-r--r--core/java/android/speech/tts/SynthesisMessageParams.java4
-rw-r--r--core/java/android/speech/tts/TextToSpeechService.java13
-rw-r--r--core/java/android/text/method/AllCapsTransformationMethod.java59
-rw-r--r--core/java/android/text/method/TransformationMethod2.java33
-rw-r--r--core/java/android/view/GLES20Canvas.java17
-rw-r--r--core/java/android/view/HardwareRenderer.java26
-rw-r--r--core/java/android/view/ViewGroup.java3
-rw-r--r--core/java/android/webkit/L10nUtils.java3
-rw-r--r--core/java/android/webkit/WebViewCore.java23
-rw-r--r--core/java/android/widget/TextView.java67
-rw-r--r--core/java/com/android/internal/util/Protocol.java5
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuItemView.java7
-rw-r--r--core/java/com/android/internal/widget/ScrollingTabContainerView.java1
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp23
-rwxr-xr-xcore/res/res/values/attrs.xml4
-rw-r--r--core/res/res/values/public.xml2
-rwxr-xr-xcore/res/res/values/strings.xml4
-rw-r--r--core/res/res/values/styles.xml2
23 files changed, 466 insertions, 489 deletions
diff --git a/core/java/android/content/XmlDocumentProvider.java b/core/java/android/content/XmlDocumentProvider.java
deleted file mode 100644
index 76539c7..0000000
--- a/core/java/android/content/XmlDocumentProvider.java
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Copyright (C) 2010 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.content;
-
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.client.methods.HttpGet;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
-import android.content.ContentResolver.OpenResourceIdResult;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.net.Uri;
-import android.net.http.AndroidHttpClient;
-import android.util.Log;
-import android.widget.CursorAdapter;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.BitSet;
-import java.util.Stack;
-import java.util.regex.Pattern;
-
-/**
- * @hide -- not yet ready to support, should be provided just as a static lib.
- *
- * A read-only content provider which extracts data out of an XML document.
- *
- * <p>A XPath-like selection pattern is used to select some nodes in the XML document. Each such
- * node will create a row in the {@link Cursor} result.</p>
- *
- * Each row is then populated with columns that are also defined as XPath-like projections. These
- * projections fetch attributes values or text in the matching row node or its children.
- *
- * <p>To add this provider in your application, you should add its declaration to your application
- * manifest:
- * <pre class="prettyprint">
- * &lt;provider android:name="android.content.XmlDocumentProvider" android:authorities="xmldocument" /&gt;
- * </pre>
- * </p>
- *
- * <h2>Node selection syntax</h2>
- * The node selection syntax is made of the concatenation of an arbitrary number (at least one) of
- * <code>/node_name</code> node selection patterns.
- *
- * <p>The <code>/root/child1/child2</code> pattern will for instance match all nodes named
- * <code>child2</code> which are children of a node named <code>child1</code> which are themselves
- * children of a root node named <code>root</code>.</p>
- *
- * Any <code>/</code> separator in the previous expression can be replaced by a <code>//</code>
- * separator instead, which indicated a <i>descendant</i> instead of a child.
- *
- * <p>The <code>//node1//node2</code> pattern will for instance match all nodes named
- * <code>node2</code> which are descendant of a node named <code>node1</code> located anywhere in
- * the document hierarchy.</p>
- *
- * Node names can contain namespaces in the form <code>namespace:node</code>.
- *
- * <h2>Projection syntax</h2>
- * For every selected node, the projection will then extract actual data from this node and its
- * descendant.
- *
- * <p>Use a syntax similar to the selection syntax described above to select the text associated
- * with a child of the selected node. The implicit root of this projection pattern is the selected
- * node. <code>/</code> will hence refer to the text of the selected node, while
- * <code>/child1</code> will fetch the text of its child named <code>child1</code> and
- * <code>//child1</code> will match any <i>descendant</i> named <code>child1</code>. If several
- * nodes match the projection pattern, their texts are appended as a result.</p>
- *
- * A projection can also fetch any node attribute by appending a <code>@attribute_name</code>
- * pattern to the previously described syntax. <code>//child1@price</code> will for instance match
- * the attribute <code>price</code> of any <code>child1</code> descendant.
- *
- * <p>If a projection does not match any node/attribute, its associated value will be an empty
- * string.</p>
- *
- * <h2>Example</h2>
- * Using the following XML document:
- * <pre class="prettyprint">
- * &lt;library&gt;
- * &lt;book id="EH94"&gt;
- * &lt;title&gt;The Old Man and the Sea&lt;/title&gt;
- * &lt;author&gt;Ernest Hemingway&lt;/author&gt;
- * &lt;/book&gt;
- * &lt;book id="XX10"&gt;
- * &lt;title&gt;The Arabian Nights: Tales of 1,001 Nights&lt;/title&gt;
- * &lt;/book&gt;
- * &lt;no-id&gt;
- * &lt;book&gt;
- * &lt;title&gt;Animal Farm&lt;/title&gt;
- * &lt;author&gt;George Orwell&lt;/author&gt;
- * &lt;/book&gt;
- * &lt;/no-id&gt;
- * &lt;/library&gt;
- * </pre>
- * A selection pattern of <code>/library//book</code> will match the three book entries (while
- * <code>/library/book</code> will only match the first two ones).
- *
- * <p>Defining the projections as <code>/title</code>, <code>/author</code> and <code>@id</code>
- * will retrieve the associated data. Note that the author of the second book as well as the id of
- * the third are empty strings.
- */
-public class XmlDocumentProvider extends ContentProvider {
- /*
- * Ideas for improvement:
- * - Expand XPath-like syntax to allow for [nb] child number selector
- * - Address the starting . bug in AbstractCursor which prevents a true XPath syntax.
- * - Provide an alternative to concatenation when several node match (list-like).
- * - Support namespaces in attribute names.
- * - Incremental Cursor creation, pagination
- */
- private static final String LOG_TAG = "XmlDocumentProvider";
- private AndroidHttpClient mHttpClient;
-
- @Override
- public boolean onCreate() {
- return true;
- }
-
- /**
- * Query data from the XML document referenced in the URI.
- *
- * <p>The XML document can be a local resource or a file that will be downloaded from the
- * Internet. In the latter case, your application needs to request the INTERNET permission in
- * its manifest.</p>
- *
- * The URI will be of the form <code>content://xmldocument/?resource=R.xml.myFile</code> for a
- * local resource. <code>xmldocument</code> should match the authority declared for this
- * provider in your manifest. Internet documents are referenced using
- * <code>content://xmldocument/?url=</code> followed by an encoded version of the URL of your
- * document (see {@link Uri#encode(String)}).
- *
- * <p>The number of columns of the resulting Cursor is equal to the size of the projection
- * array plus one, named <code>_id</code> which will contain a unique row id (allowing the
- * Cursor to be used with a {@link CursorAdapter}). The other columns' names are the projection
- * patterns.</p>
- *
- * @param uri The URI of your local resource or Internet document.
- * @param projection A set of patterns that will be used to extract data from each selected
- * node. See class documentation for pattern syntax.
- * @param selection A selection pattern which will select the nodes that will create the
- * Cursor's rows. See class documentation for pattern syntax.
- * @param selectionArgs This parameter is ignored.
- * @param sortOrder The row order in the resulting cursor is determined from the node order in
- * the XML document. This parameter is ignored.
- * @return A Cursor or null in case of error.
- */
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
-
- XmlPullParser parser = null;
- mHttpClient = null;
-
- final String url = uri.getQueryParameter("url");
- if (url != null) {
- parser = getUriXmlPullParser(url);
- } else {
- final String resource = uri.getQueryParameter("resource");
- if (resource != null) {
- Uri resourceUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
- getContext().getPackageName() + "/" + resource);
- parser = getResourceXmlPullParser(resourceUri);
- }
- }
-
- if (parser != null) {
- XMLCursor xmlCursor = new XMLCursor(selection, projection);
- try {
- xmlCursor.parseWith(parser);
- return xmlCursor;
- } catch (IOException e) {
- Log.w(LOG_TAG, "I/O error while parsing XML " + uri, e);
- } catch (XmlPullParserException e) {
- Log.w(LOG_TAG, "Error while parsing XML " + uri, e);
- } finally {
- if (mHttpClient != null) {
- mHttpClient.close();
- }
- }
- }
-
- return null;
- }
-
- /**
- * Creates an XmlPullParser for the provided URL. Can be overloaded to provide your own parser.
- * @param url The URL of the XML document that is to be parsed.
- * @return An XmlPullParser on this document.
- */
- protected XmlPullParser getUriXmlPullParser(String url) {
- XmlPullParser parser = null;
- try {
- XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
- factory.setNamespaceAware(true);
- parser = factory.newPullParser();
- } catch (XmlPullParserException e) {
- Log.e(LOG_TAG, "Unable to create XmlPullParser", e);
- return null;
- }
-
- InputStream inputStream = null;
- try {
- final HttpGet get = new HttpGet(url);
- mHttpClient = AndroidHttpClient.newInstance("Android");
- HttpResponse response = mHttpClient.execute(get);
- if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
- final HttpEntity entity = response.getEntity();
- if (entity != null) {
- inputStream = entity.getContent();
- }
- }
- } catch (IOException e) {
- Log.w(LOG_TAG, "Error while retrieving XML file " + url, e);
- return null;
- }
-
- try {
- parser.setInput(inputStream, null);
- } catch (XmlPullParserException e) {
- Log.w(LOG_TAG, "Error while reading XML file from " + url, e);
- return null;
- }
-
- return parser;
- }
-
- /**
- * Creates an XmlPullParser for the provided local resource. Can be overloaded to provide your
- * own parser.
- * @param resourceUri A fully qualified resource name referencing a local XML resource.
- * @return An XmlPullParser on this resource.
- */
- protected XmlPullParser getResourceXmlPullParser(Uri resourceUri) {
- OpenResourceIdResult resourceId;
- try {
- resourceId = getContext().getContentResolver().getResourceId(resourceUri);
- return resourceId.r.getXml(resourceId.id);
- } catch (FileNotFoundException e) {
- Log.w(LOG_TAG, "XML resource not found: " + resourceUri.toString(), e);
- return null;
- }
- }
-
- /**
- * Returns "vnd.android.cursor.dir/xmldoc".
- */
- @Override
- public String getType(Uri uri) {
- return "vnd.android.cursor.dir/xmldoc";
- }
-
- /**
- * This ContentProvider is read-only. This method throws an UnsupportedOperationException.
- **/
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * This ContentProvider is read-only. This method throws an UnsupportedOperationException.
- **/
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * This ContentProvider is read-only. This method throws an UnsupportedOperationException.
- **/
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException();
- }
-
- private static class XMLCursor extends MatrixCursor {
- private final Pattern mSelectionPattern;
- private Pattern[] mProjectionPatterns;
- private String[] mAttributeNames;
- private String[] mCurrentValues;
- private BitSet[] mActiveTextDepthMask;
- private final int mNumberOfProjections;
-
- public XMLCursor(String selection, String[] projections) {
- super(projections);
- // The first column in projections is used for the _ID
- mNumberOfProjections = projections.length - 1;
- mSelectionPattern = createPattern(selection);
- createProjectionPattern(projections);
- }
-
- private Pattern createPattern(String input) {
- String pattern = input.replaceAll("//", "/(.*/|)").replaceAll("^/", "^/") + "$";
- return Pattern.compile(pattern);
- }
-
- private void createProjectionPattern(String[] projections) {
- mProjectionPatterns = new Pattern[mNumberOfProjections];
- mAttributeNames = new String[mNumberOfProjections];
- mActiveTextDepthMask = new BitSet[mNumberOfProjections];
- // Add a column to store _ID
- mCurrentValues = new String[mNumberOfProjections + 1];
-
- for (int i=0; i<mNumberOfProjections; i++) {
- mActiveTextDepthMask[i] = new BitSet();
- String projection = projections[i + 1]; // +1 to skip the _ID column
- int atIndex = projection.lastIndexOf('@', projection.length());
- if (atIndex >= 0) {
- mAttributeNames[i] = projection.substring(atIndex+1);
- projection = projection.substring(0, atIndex);
- } else {
- mAttributeNames[i] = null;
- }
-
- // Conforms to XPath standard: reference to local context starts with a .
- if (projection.charAt(0) == '.') {
- projection = projection.substring(1);
- }
- mProjectionPatterns[i] = createPattern(projection);
- }
- }
-
- public void parseWith(XmlPullParser parser) throws IOException, XmlPullParserException {
- StringBuilder path = new StringBuilder();
- Stack<Integer> pathLengthStack = new Stack<Integer>();
-
- // There are two parsing mode: in root mode, rootPath is updated and nodes matching
- // selectionPattern are searched for and currentNodeDepth is negative.
- // When a node matching selectionPattern is found, currentNodeDepth is set to 0 and
- // updated as children are parsed and projectionPatterns are searched in nodePath.
- int currentNodeDepth = -1;
-
- // Index where local selected node path starts from in path
- int currentNodePathStartIndex = 0;
-
- int eventType = parser.getEventType();
- while (eventType != XmlPullParser.END_DOCUMENT) {
-
- if (eventType == XmlPullParser.START_TAG) {
- // Update path
- pathLengthStack.push(path.length());
- path.append('/');
- String prefix = null;
- try {
- // getPrefix is not supported by local Xml resource parser
- prefix = parser.getPrefix();
- } catch (RuntimeException e) {
- prefix = null;
- }
- if (prefix != null) {
- path.append(prefix);
- path.append(':');
- }
- path.append(parser.getName());
-
- if (currentNodeDepth >= 0) {
- currentNodeDepth++;
- } else {
- // A node matching selection is found: initialize child parsing mode
- if (mSelectionPattern.matcher(path.toString()).matches()) {
- currentNodeDepth = 0;
- currentNodePathStartIndex = path.length();
- mCurrentValues[0] = Integer.toString(getCount()); // _ID
- for (int i = 0; i < mNumberOfProjections; i++) {
- // Reset values to default (empty string)
- mCurrentValues[i + 1] = "";
- mActiveTextDepthMask[i].clear();
- }
- }
- }
-
- // This test has to be separated from the previous one as currentNodeDepth can
- // be modified above (when a node matching selection is found).
- if (currentNodeDepth >= 0) {
- final String localNodePath = path.substring(currentNodePathStartIndex);
- for (int i = 0; i < mNumberOfProjections; i++) {
- if (mProjectionPatterns[i].matcher(localNodePath).matches()) {
- String attribute = mAttributeNames[i];
- if (attribute != null) {
- mCurrentValues[i + 1] =
- parser.getAttributeValue(null, attribute);
- } else {
- mActiveTextDepthMask[i].set(currentNodeDepth, true);
- }
- }
- }
- }
-
- } else if (eventType == XmlPullParser.END_TAG) {
- // Pop last node from path
- final int length = pathLengthStack.pop();
- path.setLength(length);
-
- if (currentNodeDepth >= 0) {
- if (currentNodeDepth == 0) {
- // Leaving a selection matching node: add a new row with results
- addRow(mCurrentValues);
- } else {
- for (int i = 0; i < mNumberOfProjections; i++) {
- mActiveTextDepthMask[i].set(currentNodeDepth, false);
- }
- }
- currentNodeDepth--;
- }
-
- } else if ((eventType == XmlPullParser.TEXT) && (!parser.isWhitespace())) {
- for (int i = 0; i < mNumberOfProjections; i++) {
- if ((currentNodeDepth >= 0) &&
- (mActiveTextDepthMask[i].get(currentNodeDepth))) {
- mCurrentValues[i + 1] += parser.getText();
- }
- }
- }
-
- eventType = parser.next();
- }
- }
- }
-}
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index c7603ee..8ef4295 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -384,11 +384,16 @@ class AudioPlaybackHandler {
}
count += written;
}
+
+ param.mLogger.onPlaybackStart();
}
private void handleSynthesisDone(MessageParams msg) {
final SynthesisMessageParams params = (SynthesisMessageParams) msg;
handleSynthesisDone(params);
+ // This call is delayed more than it should be, but we are
+ // certain at this point that we have all the data we want.
+ params.mLogger.onWriteData();
}
// Flush all remaining data to the audio track, stop it and release
@@ -416,6 +421,8 @@ class AudioPlaybackHandler {
final SynthesisMessageParams params = (SynthesisMessageParams) msg;
if (DBG) Log.d(TAG, "completeAudioAvailable(" + params + ")");
+ params.mLogger.onPlaybackStart();
+
// Channel config and bytes per frame are checked before
// this message is sent.
int channelConfig = AudioPlaybackHandler.getChannelConfig(params.mChannelCount);
diff --git a/core/java/android/speech/tts/EventLogTags.logtags b/core/java/android/speech/tts/EventLogTags.logtags
new file mode 100644
index 0000000..1a9f5fe
--- /dev/null
+++ b/core/java/android/speech/tts/EventLogTags.logtags
@@ -0,0 +1,6 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package android.speech.tts;
+
+76001 tts_speak_success (engine|3),(caller|3),(length|1),(locale|3),(rate|1),(pitch|1),(engine_latency|2|3),(engine_total|2|3),(audio_latency|2|3)
+76002 tts_speak_failure (engine|3),(caller|3),(length|1),(locale|3),(rate|1),(pitch|1)
diff --git a/core/java/android/speech/tts/EventLogger.java b/core/java/android/speech/tts/EventLogger.java
new file mode 100644
index 0000000..63b954b
--- /dev/null
+++ b/core/java/android/speech/tts/EventLogger.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2011 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.speech.tts;
+
+import android.os.SystemClock;
+import android.text.TextUtils;
+
+/**
+ * Writes data about a given speech synthesis request to the event logs.
+ * The data that is logged includes the calling app, length of the utterance,
+ * speech rate / pitch and the latency and overall time taken.
+ *
+ * Note that {@link EventLogger#onStopped()} and {@link EventLogger#onError()}
+ * might be called from any thread, but on {@link EventLogger#onPlaybackStart()} and
+ * {@link EventLogger#onComplete()} must be called from a single thread
+ * (usually the audio playback thread}
+ */
+class EventLogger {
+ private final SynthesisRequest mRequest;
+ private final String mCallingApp;
+ private final String mServiceApp;
+ private final long mReceivedTime;
+ private long mPlaybackStartTime = -1;
+ private volatile long mRequestProcessingStartTime = -1;
+ private volatile long mEngineStartTime = -1;
+ private volatile long mEngineCompleteTime = -1;
+
+ private volatile boolean mError = false;
+ private volatile boolean mStopped = false;
+ private boolean mLogWritten = false;
+
+ EventLogger(SynthesisRequest request, String callingApp,
+ String serviceApp) {
+ mRequest = request;
+ mCallingApp = callingApp;
+ mServiceApp = serviceApp;
+ mReceivedTime = SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Notifies the logger that this request has been selected from
+ * the processing queue for processing. Engine latency / total time
+ * is measured from this baseline.
+ */
+ public void onRequestProcessingStart() {
+ mRequestProcessingStartTime = SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Notifies the logger that a chunk of data has been received from
+ * the engine. Might be called multiple times.
+ */
+ public void onEngineDataReceived() {
+ if (mEngineStartTime == -1) {
+ mEngineStartTime = SystemClock.elapsedRealtime();
+ }
+ }
+
+ /**
+ * Notifies the logger that the engine has finished processing data.
+ * Will be called exactly once.
+ */
+ public void onEngineComplete() {
+ mEngineCompleteTime = SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Notifies the logger that audio playback has started for some section
+ * of the synthesis. This is normally some amount of time after the engine
+ * has synthesized data and varides depending on utterances and
+ * other audio currently in the queue.
+ */
+ public void onPlaybackStart() {
+ // For now, keep track of only the first chunk of audio
+ // that was played.
+ if (mPlaybackStartTime == -1) {
+ mPlaybackStartTime = SystemClock.elapsedRealtime();
+ }
+ }
+
+ /**
+ * Notifies the logger that the current synthesis was stopped.
+ * Latency numbers are not reported for stopped syntheses.
+ */
+ public void onStopped() {
+ mStopped = false;
+ }
+
+ /**
+ * Notifies the logger that the current synthesis resulted in
+ * an error. This is logged using {@link EventLogTags#writeTtsSpeakFailure}.
+ */
+ public void onError() {
+ mError = true;
+ }
+
+ /**
+ * Notifies the logger that the current synthesis has completed.
+ * All available data is not logged.
+ */
+ public void onWriteData() {
+ if (mLogWritten) {
+ return;
+ } else {
+ mLogWritten = true;
+ }
+
+ long completionTime = SystemClock.elapsedRealtime();
+ // onPlaybackStart() should normally always be called if an
+ // error does not occur.
+ if (mError || mPlaybackStartTime == -1 || mEngineCompleteTime == -1) {
+ EventLogTags.writeTtsSpeakFailure(mServiceApp, mCallingApp,
+ getUtteranceLength(), getLocaleString(),
+ mRequest.getSpeechRate(), mRequest.getPitch());
+ return;
+ }
+
+ // We don't report stopped syntheses because their overall
+ // total time spent will be innacurate (will not correlate with
+ // the length of the utterance).
+ if (mStopped) {
+ return;
+ }
+
+ final long audioLatency = mPlaybackStartTime - mReceivedTime;
+ final long engineLatency = mEngineStartTime - mRequestProcessingStartTime;
+ final long engineTotal = mEngineCompleteTime - mRequestProcessingStartTime;
+ EventLogTags.writeTtsSpeakSuccess(mServiceApp, mCallingApp,
+ getUtteranceLength(), getLocaleString(),
+ mRequest.getSpeechRate(), mRequest.getPitch(),
+ engineLatency, engineTotal, audioLatency);
+ }
+
+ /**
+ * @return the length of the utterance for the given synthesis, 0
+ * if the utterance was {@code null}.
+ */
+ private int getUtteranceLength() {
+ final String utterance = mRequest.getText();
+ return utterance == null ? 0 : utterance.length();
+ }
+
+ /**
+ * Returns a formatted locale string from the synthesis params of the
+ * form lang-country-variant.
+ */
+ private String getLocaleString() {
+ StringBuilder sb = new StringBuilder(mRequest.getLanguage());
+ if (!TextUtils.isEmpty(mRequest.getCountry())) {
+ sb.append('-');
+ sb.append(mRequest.getCountry());
+
+ if (!TextUtils.isEmpty(mRequest.getVariant())) {
+ sb.append('-');
+ sb.append(mRequest.getVariant());
+ }
+ }
+
+ return sb.toString();
+ }
+
+}
diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
index bdaa1b8..38030a6 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
@@ -65,29 +65,42 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback {
private final UtteranceCompletedDispatcher mDispatcher;
private final String mCallingApp;
+ private final EventLogger mLogger;
PlaybackSynthesisCallback(int streamType, float volume, float pan,
AudioPlaybackHandler audioTrackHandler, UtteranceCompletedDispatcher dispatcher,
- String callingApp) {
+ String callingApp, EventLogger logger) {
mStreamType = streamType;
mVolume = volume;
mPan = pan;
mAudioTrackHandler = audioTrackHandler;
mDispatcher = dispatcher;
mCallingApp = callingApp;
+ mLogger = logger;
}
@Override
void stop() {
if (DBG) Log.d(TAG, "stop()");
+ // Note that mLogger.mError might be true too at this point.
+ mLogger.onStopped();
+
synchronized (mStateLock) {
- if (mToken == null || mStopped) {
- Log.w(TAG, "stop() called twice, before start(), or after done()");
+ if (mStopped) {
+ Log.w(TAG, "stop() called twice");
return;
}
- mAudioTrackHandler.stop(mToken);
- mToken = null;
+ // mToken will be null if the engine encounters
+ // an error before it called start().
+ if (mToken != null) {
+ mAudioTrackHandler.stop(mToken);
+ mToken = null;
+ } else {
+ // In all other cases, mAudioTrackHandler.stop() will
+ // result in onComplete being called.
+ mLogger.onWriteData();
+ }
mStopped = true;
}
}
@@ -124,7 +137,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback {
}
SynthesisMessageParams params = new SynthesisMessageParams(
mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
- mDispatcher, mCallingApp);
+ mDispatcher, mCallingApp, mLogger);
mAudioTrackHandler.enqueueSynthesisStart(params);
mToken = params;
@@ -157,6 +170,8 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback {
mAudioTrackHandler.enqueueSynthesisDataAvailable(mToken);
}
+ mLogger.onEngineDataReceived();
+
return TextToSpeech.SUCCESS;
}
@@ -177,6 +192,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback {
}
mAudioTrackHandler.enqueueSynthesisDone(mToken);
+ mLogger.onEngineComplete();
}
return TextToSpeech.SUCCESS;
}
@@ -184,6 +200,9 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback {
@Override
public void error() {
if (DBG) Log.d(TAG, "error() [will call stop]");
+ // Currently, this call will not be logged if error( ) is called
+ // before start.
+ mLogger.onError();
stop();
}
@@ -208,7 +227,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback {
}
SynthesisMessageParams params = new SynthesisMessageParams(
mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
- mDispatcher, mCallingApp);
+ mDispatcher, mCallingApp, mLogger);
params.addBuffer(buffer, offset, length);
mAudioTrackHandler.enqueueSynthesisCompleteDataAvailable(params);
diff --git a/core/java/android/speech/tts/SynthesisMessageParams.java b/core/java/android/speech/tts/SynthesisMessageParams.java
index 51f3d2e..caf02ef 100644
--- a/core/java/android/speech/tts/SynthesisMessageParams.java
+++ b/core/java/android/speech/tts/SynthesisMessageParams.java
@@ -30,6 +30,7 @@ final class SynthesisMessageParams extends MessageParams {
final int mChannelCount;
final float mVolume;
final float mPan;
+ final EventLogger mLogger;
public volatile AudioTrack mAudioTrack;
@@ -38,7 +39,7 @@ final class SynthesisMessageParams extends MessageParams {
SynthesisMessageParams(int streamType, int sampleRate,
int audioFormat, int channelCount,
float volume, float pan, UtteranceCompletedDispatcher dispatcher,
- String callingApp) {
+ String callingApp, EventLogger logger) {
super(dispatcher, callingApp);
mStreamType = streamType;
@@ -47,6 +48,7 @@ final class SynthesisMessageParams extends MessageParams {
mChannelCount = channelCount;
mVolume = volume;
mPan = pan;
+ mLogger = logger;
// initially null.
mAudioTrack = null;
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 7ea9373..010c155 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -82,8 +82,7 @@ public abstract class TextToSpeechService extends Service {
private AudioPlaybackHandler mAudioPlaybackHandler;
private CallbackMap mCallbacks;
-
- private int mDefaultAvailability = TextToSpeech.LANG_NOT_SUPPORTED;
+ private String mPackageName;
@Override
public void onCreate() {
@@ -99,9 +98,10 @@ public abstract class TextToSpeechService extends Service {
mCallbacks = new CallbackMap();
+ mPackageName = getApplicationInfo().packageName;
+
// Load default language
- mDefaultAvailability = onLoadLanguage(getDefaultLanguage(),
- getDefaultCountry(), getDefaultVariant());
+ onLoadLanguage(getDefaultLanguage(), getDefaultCountry(), getDefaultVariant());
}
@Override
@@ -457,12 +457,14 @@ public abstract class TextToSpeechService extends Service {
// Non null after synthesis has started, and all accesses
// guarded by 'this'.
private AbstractSynthesisCallback mSynthesisCallback;
+ private final EventLogger mEventLogger;
public SynthesisSpeechItem(String callingApp, Bundle params, String text) {
super(callingApp, params);
mText = text;
mSynthesisRequest = new SynthesisRequest(mText, mParams);
setRequestParams(mSynthesisRequest);
+ mEventLogger = new EventLogger(mSynthesisRequest, getCallingApp(), mPackageName);
}
public String getText() {
@@ -485,6 +487,7 @@ public abstract class TextToSpeechService extends Service {
@Override
protected int playImpl() {
AbstractSynthesisCallback synthesisCallback;
+ mEventLogger.onRequestProcessingStart();
synchronized (this) {
mSynthesisCallback = createSynthesisCallback();
synthesisCallback = mSynthesisCallback;
@@ -495,7 +498,7 @@ public abstract class TextToSpeechService extends Service {
protected AbstractSynthesisCallback createSynthesisCallback() {
return new PlaybackSynthesisCallback(getStreamType(), getVolume(), getPan(),
- mAudioPlaybackHandler, this, getCallingApp());
+ mAudioPlaybackHandler, this, getCallingApp(), mEventLogger);
}
private void setRequestParams(SynthesisRequest request) {
diff --git a/core/java/android/text/method/AllCapsTransformationMethod.java b/core/java/android/text/method/AllCapsTransformationMethod.java
new file mode 100644
index 0000000..f9920dd
--- /dev/null
+++ b/core/java/android/text/method/AllCapsTransformationMethod.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 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.text.method;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.View;
+
+import java.util.Locale;
+
+/**
+ * Transforms source text into an ALL CAPS string, locale-aware.
+ *
+ * @hide
+ */
+public class AllCapsTransformationMethod implements TransformationMethod2 {
+ private static final String TAG = "AllCapsTransformationMethod";
+
+ private boolean mEnabled;
+ private Locale mLocale;
+
+ public AllCapsTransformationMethod(Context context) {
+ mLocale = context.getResources().getConfiguration().locale;
+ }
+
+ @Override
+ public CharSequence getTransformation(CharSequence source, View view) {
+ if (mEnabled) {
+ return source != null ? source.toString().toUpperCase(mLocale) : null;
+ }
+ Log.w(TAG, "Caller did not enable length changes; not transforming text");
+ return source;
+ }
+
+ @Override
+ public void onFocusChanged(View view, CharSequence sourceText, boolean focused, int direction,
+ Rect previouslyFocusedRect) {
+ }
+
+ @Override
+ public void setLengthChangesAllowed(boolean allowLengthChanges) {
+ mEnabled = allowLengthChanges;
+ }
+
+}
diff --git a/core/java/android/text/method/TransformationMethod2.java b/core/java/android/text/method/TransformationMethod2.java
new file mode 100644
index 0000000..ef00ecd
--- /dev/null
+++ b/core/java/android/text/method/TransformationMethod2.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 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.text.method;
+
+/**
+ * TransformationMethod2 extends the TransformationMethod interface
+ * and adds the ability to relax restrictions of TransformationMethod.
+ *
+ * @hide
+ */
+public interface TransformationMethod2 extends TransformationMethod {
+ /**
+ * Relax the contract of TransformationMethod to allow length changes,
+ * or revert to the length-restricted behavior.
+ *
+ * @param allowLengthChanges true to allow the transformation to change the length
+ * of the input string.
+ */
+ public void setLengthChangesAllowed(boolean allowLengthChanges);
+}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index b6c5522..4987e2f 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -246,8 +246,19 @@ class GLES20Canvas extends HardwareCanvas {
return nIsBackBufferPreserved();
}
- private static native boolean nIsBackBufferPreserved();
-
+ private static native boolean nIsBackBufferPreserved();
+
+ /**
+ * Disables v-sync. For performance testing only.
+ *
+ * @hide
+ */
+ public static void disableVsync() {
+ nDisableVsync();
+ }
+
+ private static native void nDisableVsync();
+
@Override
void onPreDraw(Rect dirty) {
if (dirty != null) {
@@ -265,7 +276,7 @@ class GLES20Canvas extends HardwareCanvas {
void onPostDraw() {
nFinish(mRenderer);
}
-
+
private static native void nFinish(int renderer);
@Override
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index bbfb4c1..188970c 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -57,6 +57,16 @@ public abstract class HardwareRenderer {
* "false", to disable partial invalidates
*/
static final String RENDER_DIRTY_REGIONS_PROPERTY = "hwui.render_dirty_regions";
+
+ /**
+ * System property used to enable or disable vsync.
+ * The default value of this property is assumed to be false.
+ *
+ * Possible values:
+ * "true", to disable vsync
+ * "false", to enable vsync
+ */
+ static final String DISABLE_VSYNC_PROPERTY = "hwui.disable_vsync";
/**
* Turn on to draw dirty regions every other frame.
@@ -303,6 +313,7 @@ public abstract class HardwareRenderer {
boolean mDirtyRegions;
final boolean mDirtyRegionsRequested;
+ final boolean mVsyncDisabled;
final int mGlVersion;
final boolean mTranslucent;
@@ -314,10 +325,17 @@ public abstract class HardwareRenderer {
GlRenderer(int glVersion, boolean translucent) {
mGlVersion = glVersion;
mTranslucent = translucent;
+
final String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
//noinspection PointlessBooleanExpression,ConstantConditions
mDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
mDirtyRegionsRequested = mDirtyRegions;
+
+ final String vsyncProperty = SystemProperties.get(DISABLE_VSYNC_PROPERTY, "false");
+ mVsyncDisabled = "true".equalsIgnoreCase(vsyncProperty);
+ if (mVsyncDisabled) {
+ Log.d(LOG_TAG, "Disabling v-sync");
+ }
}
/**
@@ -765,6 +783,14 @@ public abstract class HardwareRenderer {
}
@Override
+ void setup(int width, int height) {
+ super.setup(width, height);
+ if (mVsyncDisabled) {
+ GLES20Canvas.disableVsync();
+ }
+ }
+
+ @Override
DisplayList createDisplayList(View v) {
return new GLES20DisplayList(v);
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 41412de..e6fdb17 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -46,7 +46,6 @@ import com.android.internal.util.Predicate;
import java.util.ArrayList;
import java.util.HashSet;
-import java.util.Locale;
/**
* <p>
@@ -5019,7 +5018,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
@Override
protected void resolveTextDirection() {
- int resolvedTextDirection = TEXT_DIRECTION_UNDEFINED;
+ int resolvedTextDirection;
switch(mTextDirection) {
default:
case TEXT_DIRECTION_INHERIT:
diff --git a/core/java/android/webkit/L10nUtils.java b/core/java/android/webkit/L10nUtils.java
index 4c42cde..f9d0067d 100644
--- a/core/java/android/webkit/L10nUtils.java
+++ b/core/java/android/webkit/L10nUtils.java
@@ -74,7 +74,8 @@ public class L10nUtils {
com.android.internal.R.string.autofill_country_code_re, // IDS_AUTOFILL_COUNTRY_CODE_RE
com.android.internal.R.string.autofill_area_code_notext_re, // IDS_AUTOFILL_AREA_CODE_NOTEXT_RE
com.android.internal.R.string.autofill_phone_prefix_separator_re, // IDS_AUTOFILL_PHONE_PREFIX_SEPARATOR_RE
- com.android.internal.R.string.autofill_phone_suffix_separator_re // IDS_AUTOFILL_PHONE_SUFFIX_SEPARATOR_RE
+ com.android.internal.R.string.autofill_phone_suffix_separator_re, // IDS_AUTOFILL_PHONE_SUFFIX_SEPARATOR_RE
+ com.android.internal.R.string.credit_card_number_preview_format // IDS_CREDIT_CARD_NUMBER_PREVIEW_FORMAT
};
private static Context mApplicationContext;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 4f97066..c652e55 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2235,16 +2235,15 @@ public final class WebViewCore {
// called by JNI
private void updateViewport() {
- // if updateViewport is called before first layout, wait until first
- // layout to update the viewport. In the rare case, this is called after
- // first layout, force an update as we have just parsed the viewport
- // meta tag.
- if (mBrowserFrame.firstLayoutDone()) {
- setupViewport(true);
- }
+ // Update viewport asap to make sure we get correct one.
+ setupViewport(true);
}
private void setupViewport(boolean updateViewState) {
+ if (mWebView == null || mSettings == null) {
+ // We've been destroyed or are being destroyed, return early
+ return;
+ }
// set the viewport settings from WebKit
setViewportSettingsFromNative();
@@ -2375,8 +2374,12 @@ public final class WebViewCore {
(float) webViewWidth / mViewportWidth;
} else {
mInitialViewState.mTextWrapScale = adjust;
- // 0 will trigger WebView to turn on zoom overview mode
- mInitialViewState.mViewScale = 0;
+ if (mSettings.getUseWideViewPort()) {
+ // 0 will trigger WebView to turn on zoom overview mode
+ mInitialViewState.mViewScale = 0;
+ } else {
+ mInitialViewState.mViewScale = adjust;
+ }
}
}
@@ -2407,7 +2410,7 @@ public final class WebViewCore {
mEventHub.removeMessages(EventHub.VIEW_SIZE_CHANGED);
mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
EventHub.VIEW_SIZE_CHANGED, data));
- } else if (mSettings.getUseWideViewPort()) {
+ } else {
if (viewportWidth == 0) {
// Trick to ensure VIEW_SIZE_CHANGED will be sent from WebView
// to WebViewCore
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 772e8e9..1e63e26 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -16,6 +16,11 @@
package android.widget;
+import com.android.internal.util.FastMath;
+import com.android.internal.widget.EditableInputConnection;
+
+import org.xmlpull.v1.XmlPullParserException;
+
import android.R;
import android.content.ClipData;
import android.content.ClipData.Item;
@@ -62,6 +67,7 @@ import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.TextWatcher;
+import android.text.method.AllCapsTransformationMethod;
import android.text.method.ArrowKeyMovementMethod;
import android.text.method.DateKeyListener;
import android.text.method.DateTimeKeyListener;
@@ -76,6 +82,7 @@ import android.text.method.SingleLineTransformationMethod;
import android.text.method.TextKeyListener;
import android.text.method.TimeKeyListener;
import android.text.method.TransformationMethod;
+import android.text.method.TransformationMethod2;
import android.text.method.WordIterator;
import android.text.style.ClickableSpan;
import android.text.style.ParagraphStyle;
@@ -125,11 +132,6 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.RemoteViews.RemoteView;
-import com.android.internal.util.FastMath;
-import com.android.internal.widget.EditableInputConnection;
-
-import org.xmlpull.v1.XmlPullParserException;
-
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.text.BreakIterator;
@@ -424,6 +426,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
int textSize = 15;
int typefaceIndex = -1;
int styleIndex = -1;
+ boolean allCaps = false;
/*
* Look the appearance up without checking first if it exists because
@@ -471,6 +474,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
case com.android.internal.R.styleable.TextAppearance_textStyle:
styleIndex = appearance.getInt(attr, -1);
break;
+
+ case com.android.internal.R.styleable.TextAppearance_textAllCaps:
+ allCaps = appearance.getBoolean(attr, false);
+ break;
}
}
@@ -822,6 +829,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
case com.android.internal.R.styleable.TextView_suggestionsEnabled:
mSuggestionsEnabled = a.getBoolean(attr, true);
break;
+
+ case com.android.internal.R.styleable.TextView_textAllCaps:
+ allCaps = a.getBoolean(attr, false);
+ break;
}
}
a.recycle();
@@ -1004,6 +1015,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
setRawTextSize(textSize);
+ if (allCaps) {
+ setTransformationMethod(new AllCapsTransformationMethod(getContext()));
+ }
+
if (password || passwordInputType || webPasswordInputType || numberPasswordInputType) {
setTransformationMethod(PasswordTransformationMethod.getInstance());
typefaceIndex = MONOSPACE;
@@ -1331,6 +1346,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mTransformation = method;
+ if (method instanceof TransformationMethod2) {
+ TransformationMethod2 method2 = (TransformationMethod2) method;
+ mAllowTransformationLengthChange = !mTextIsSelectable && !(mText instanceof Editable);
+ method2.setLengthChangesAllowed(mAllowTransformationLengthChange);
+ } else {
+ mAllowTransformationLengthChange = false;
+ }
+
setText(mText);
}
@@ -1775,6 +1798,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
setTypefaceByIndex(typefaceIndex, styleIndex);
+ if (appearance.getBoolean(com.android.internal.R.styleable.TextAppearance_textAllCaps,
+ false)) {
+ setTransformationMethod(new AllCapsTransformationMethod(getContext()));
+ }
+
appearance.recycle();
}
@@ -2823,14 +2851,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mBufferType = type;
mText = text;
- if (mTransformation == null)
+ if (mTransformation == null) {
mTransformed = text;
- else
+ } else {
mTransformed = mTransformation.getTransformation(text, this);
+ }
final int textLength = text.length();
- if (text instanceof Spannable) {
+ if (text instanceof Spannable && !mAllowTransformationLengthChange) {
Spannable sp = (Spannable) text;
// Remove any ChangeWatchers that might have come
@@ -2852,7 +2881,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mTransformation != null) {
sp.setSpan(mTransformation, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-
}
if (mMovement != null) {
@@ -6570,6 +6598,26 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Sets the properties of this field to transform input to ALL CAPS
+ * display. This may use a "small caps" formatting if available.
+ * This setting will be ignored if this field is editable or selectable.
+ *
+ * This call replaces the current transformation method. Disabling this
+ * will not necessarily restore the previous behavior from before this
+ * was enabled.
+ *
+ * @see #setTransformationMethod(TransformationMethod)
+ * @attr ref android.R.styleable#TextView_textAllCaps
+ */
+ public void setAllCaps(boolean allCaps) {
+ if (allCaps) {
+ setTransformationMethod(new AllCapsTransformationMethod(getContext()));
+ } else {
+ setTransformationMethod(null);
+ }
+ }
+
+ /**
* If true, sets the properties of this field (number of lines, horizontally scrolling,
* transformation method) to be for a single-line input; if false, restores these to the default
* conditions.
@@ -10254,6 +10302,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private MovementMethod mMovement;
private TransformationMethod mTransformation;
+ private boolean mAllowTransformationLengthChange;
private ChangeWatcher mChangeWatcher;
private ArrayList<TextWatcher> mListeners = null;
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index 2e7ec58..b754d94 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -26,6 +26,9 @@ package com.android.internal.util;
* codes with Message.what starting at Protocol.WIFI + 1 and less than or equal to Protocol.WIFI +
* Protocol.MAX_MESSAGE
*
+ * NOTE: After a value is created and source released a value shouldn't be changed to
+ * maintain backwards compatibility.
+ *
* {@hide}
*/
public class Protocol {
@@ -40,7 +43,7 @@ public class Protocol {
public static final int BASE_DHCP = 0x00030000;
public static final int BASE_DATA_CONNECTION = 0x00040000;
public static final int BASE_DATA_CONNECTION_AC = 0x00041000;
- public static final int BASE_DATA_CONNECTION_TRACKER = 0x00050000;
+ public static final int BASE_DATA_CONNECTION_TRACKER = 0x00042000;
//TODO: define all used protocols
}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index 3b497e4..09bebae 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -154,12 +154,7 @@ public class ActionMenuItemView extends LinearLayout
// populate accessibility description with title
setContentDescription(title);
- if (mShowTextAllCaps && title != null) {
- mTextButton.setText(title.toString().toUpperCase(
- getContext().getResources().getConfiguration().locale));
- } else {
- mTextButton.setText(mTitle);
- }
+ mTextButton.setText(mTitle);
updateTextButtonVisibility();
}
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index 2f7adf0..40e5e8a 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -260,7 +260,6 @@ public class ScrollingTabContainerView extends HorizontalScrollView {
if (mTextView == null) {
TextView textView = new TextView(getContext(), null,
com.android.internal.R.attr.actionBarTabTextStyle);
- textView.setSingleLine();
textView.setEllipsize(TruncateAt.END);
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 2106eb4..681f43f 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -115,6 +115,18 @@ static jboolean android_view_GLES20Canvas_isBackBufferPreserved(JNIEnv* env, job
return error == EGL_SUCCESS && value == EGL_BUFFER_PRESERVED;
}
+static void android_view_GLES20Canvas_disableVsync(JNIEnv* env, jobject clazz) {
+ EGLDisplay display = eglGetCurrentDisplay();
+
+ eglGetError();
+ eglSwapInterval(display, 0);
+
+ EGLint error = eglGetError();
+ if (error != EGL_SUCCESS) {
+ RENDERER_LOGD("Could not disable v-sync (%x)", error);
+ }
+}
+
// ----------------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------------
@@ -621,7 +633,7 @@ static Layer* android_view_GLES20Canvas_createTextureLayer(JNIEnv* env, jobject
if (layer) {
jint* storage = env->GetIntArrayElements(layerInfo, NULL);
- storage[0] = layer->texture;
+ storage[0] = layer->getTexture();
env->ReleaseIntArrayElements(layerInfo, storage, 0);
}
@@ -634,8 +646,8 @@ static Layer* android_view_GLES20Canvas_createLayer(JNIEnv* env, jobject clazz,
if (layer) {
jint* storage = env->GetIntArrayElements(layerInfo, NULL);
- storage[0] = layer->width;
- storage[1] = layer->height;
+ storage[0] = layer->getWidth();
+ storage[1] = layer->getHeight();
env->ReleaseIntArrayElements(layerInfo, storage, 0);
}
@@ -647,8 +659,8 @@ static void android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz,
LayerRenderer::resizeLayer(layer, width, height);
jint* storage = env->GetIntArrayElements(layerInfo, NULL);
- storage[0] = layer->width;
- storage[1] = layer->height;
+ storage[0] = layer->getWidth();
+ storage[1] = layer->getHeight();
env->ReleaseIntArrayElements(layerInfo, storage, 0);
}
@@ -722,6 +734,7 @@ static JNINativeMethod gMethods[] = {
#ifdef USE_OPENGL_RENDERER
{ "nIsBackBufferPreserved", "()Z", (void*) android_view_GLES20Canvas_isBackBufferPreserved },
{ "nPreserveBackBuffer", "()Z", (void*) android_view_GLES20Canvas_preserveBackBuffer },
+ { "nDisableVsync", "()V", (void*) android_view_GLES20Canvas_disableVsync },
{ "nCreateRenderer", "()I", (void*) android_view_GLES20Canvas_createRenderer },
{ "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Canvas_destroyRenderer },
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2cc8171..39de054 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2810,6 +2810,8 @@
<attr name="textColorHint" />
<!-- Color of the links. -->
<attr name="textColorLink" />
+ <!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
+ <attr name="textAllCaps" format="boolean" />
</declare-styleable>
<declare-styleable name="TextSwitcher">
</declare-styleable>
@@ -3074,6 +3076,8 @@
<attr name="textIsSelectable" />
<!-- Suggestions will be displayed when the user double taps on editable text. -->
<attr name="suggestionsEnabled" />
+ <!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
+ <attr name="textAllCaps" />
</declare-styleable>
<!-- An <code>input-extras</code> is a container for extra data to supply to
an input method. Contains
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2de9cd3..3c23add 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1779,6 +1779,8 @@
<public type="attr" name="backgroundStacked" />
<public type="attr" name="backgroundSplit" />
+ <public type="attr" name="textAllCaps" />
+
<public type="style" name="TextAppearance.SuggestionHighlight" />
<public type="style" name="Theme.Holo.SplitActionBarWhenNarrow" />
<public type="style" name="Theme.Holo.Light.SplitActionBarWhenNarrow" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 50f8df7..97a8c0b 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2085,6 +2085,10 @@
<!-- Do not translate. Regex used by AutoFill. -->
<string name="autofill_phone_suffix_separator_re">^-$</string>
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <!-- Ex: ************1234 -->
+ <string name="credit_card_number_preview_format">$1</string>
+
<!-- Title of an application permission, listed so the user can choose whether
they want to allow the application to do this. -->
<string name="permlab_readHistoryBookmarks">read Browser\'s history and bookmarks</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 11016f4..8a8f81a 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1319,6 +1319,7 @@
<item name="android:textSize">12sp</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">?android:attr/actionMenuTextColor</item>
+ <item name="android:textAllCaps">true</item>
</style>
<style name="TextAppearance.Holo.Widget.ActionMode">
@@ -1857,6 +1858,7 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">12sp</item>
<item name="android:textStyle">bold</item>
+ <item name="android:textAllCaps">true</item>
</style>
<style name="Widget.Holo.ActionMode" parent="Widget.ActionMode">