Merge "Clear the WebView picture when a new load starts."
diff --git a/api/current.txt b/api/current.txt
index 9610853..9eb2075 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4244,6 +4244,7 @@
method public int getProfileConnectionState(int);
method public boolean getProfileProxy(android.content.Context, android.bluetooth.BluetoothProfile.ServiceListener, int);
method public android.bluetooth.BluetoothDevice getRemoteDevice(java.lang.String);
+ method public android.bluetooth.BluetoothDevice getRemoteDevice(byte[]);
method public int getScanMode();
method public int getState();
method public boolean isDiscovering();
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 5f5ba50..e420bfd 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -399,6 +399,25 @@
}
/**
+ * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
+ * address.
+ * <p>Valid Bluetooth hardware addresses must be 6 bytes. This method
+ * expects the address in network byte order (MSB first).
+ * <p>A {@link BluetoothDevice} will always be returned for a valid
+ * hardware address, even if this adapter has never seen that device.
+ *
+ * @param address Bluetooth MAC address (6 bytes)
+ * @throws IllegalArgumentException if address is invalid
+ */
+ public BluetoothDevice getRemoteDevice(byte[] address) {
+ if (address == null || address.length != 6) {
+ throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
+ }
+ return new BluetoothDevice(String.format("%02X:%02X:%02X:%02X:%02X:%02X",
+ address[0], address[1], address[2], address[3], address[4], address[5]));
+ }
+
+ /**
* Return true if Bluetooth is currently enabled and ready for use.
* <p>Equivalent to:
* <code>getBluetoothState() == STATE_ON</code>
@@ -1281,7 +1300,7 @@
}
/**
- * Validate a Bluetooth address, such as "00:43:A8:23:10:F0"
+ * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
* <p>Alphabetic characters must be uppercase to be valid.
*
* @param address Bluetooth address as string
diff --git a/core/java/android/content/ContentUris.java b/core/java/android/content/ContentUris.java
index aa7603470b..dbe8a7c 100644
--- a/core/java/android/content/ContentUris.java
+++ b/core/java/android/content/ContentUris.java
@@ -19,9 +19,54 @@
import android.net.Uri;
/**
- * Utility methods useful for working with content {@link android.net.Uri}s,
- * those with a "content" scheme.
- */
+* Utility methods useful for working with {@link android.net.Uri} objects
+* that use the "content" (content://) scheme.
+*
+*<p>
+* Content URIs have the syntax
+*</p>
+*<p>
+* <code>content://<em>authority</em>/<em>path</em>/<em>id</em></code>
+*</p>
+*<dl>
+* <dt>
+* <code>content:</code>
+* </dt>
+* <dd>
+* The scheme portion of the URI. This is always set to {@link
+* android.content.ContentResolver#SCHEME_CONTENT ContentResolver.SCHEME_CONTENT} (value
+* <code>content://</code>).
+* </dd>
+* <dt>
+* <em>authority</em>
+* </dt>
+* <dd>
+* A string that identifies the entire content provider. All the content URIs for the provider
+* start with this string. To guarantee a unique authority, providers should consider
+* using an authority that is the same as the provider class' package identifier.
+* </dd>
+* <dt>
+* <em>path</em>
+* </dt>
+* <dd>
+* Zero or more segments, separated by a forward slash (<code>/</code>), that identify
+* some subset of the provider's data. Most providers use the path part to identify
+* individual tables. Individual segments in the path are often called
+* "directories" although they do not refer to file directories. The right-most
+* segment in a path is often called a "twig"
+* </dd>
+* <dt>
+* <em>id</em>
+* </dt>
+* <dd>
+* A unique numeric identifier for a single row in the subset of data identified by the
+* preceding path part. Most providers recognize content URIs that contain an id part
+* and give them special handling. A table that contains a column named <code>_ID</code>
+* often expects the id part to be a particular value for that column.
+* </dd>
+*</dl>
+*
+*/
public class ContentUris {
/**
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
index 72431f3..10c1195 100644
--- a/core/java/android/inputmethodservice/ExtractEditText.java
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -158,25 +158,46 @@
}
/**
- * Delete the range of text, supposedly valid
+ * {@inheritDoc}
* @hide
*/
@Override
protected void deleteText_internal(int start, int end) {
- // Do not call the super method. This will change the source TextView instead, which
- // will update the ExtractTextView.
+ // Do not call the super method.
+ // This will change the source TextView instead, which will update the ExtractTextView.
mIME.onExtractedDeleteText(start, end);
}
/**
- * Replaces the range of text [start, end[ by replacement text
+ * {@inheritDoc}
* @hide
*/
@Override
protected void replaceText_internal(int start, int end, CharSequence text) {
- // Do not call the super method. This will change the source TextView instead, which
- // will update the ExtractTextView.
+ // Do not call the super method.
+ // This will change the source TextView instead, which will update the ExtractTextView.
mIME.onExtractedReplaceText(start, end, text);
}
+ /**
+ * {@inheritDoc}
+ * @hide
+ */
+ @Override
+ protected void setSpan_internal(Object span, int start, int end, int flags) {
+ // Do not call the super method.
+ // This will change the source TextView instead, which will update the ExtractTextView.
+ mIME.onExtractedSetSpan(span, start, end, flags);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @hide
+ */
+ @Override
+ protected void setCursorPosition_internal(int start, int end) {
+ // Do not call the super method.
+ // This will change the source TextView instead, which will update the ExtractTextView.
+ mIME.onExtractedSelectionChanged(start, end);
+ }
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 02839db..53cdf21 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -2006,6 +2006,22 @@
}
/**
+ * @hide
+ */
+ public void onExtractedSetSpan(Object span, int start, int end, int flags) {
+ InputConnection conn = getCurrentInputConnection();
+ if (conn != null) {
+ if (!conn.setSelection(start, end)) return;
+ CharSequence text = conn.getSelectedText(InputConnection.GET_TEXT_WITH_STYLES);
+ if (text instanceof Spannable) {
+ ((Spannable) text).setSpan(span, 0, text.length(), flags);
+ conn.setComposingRegion(start, end);
+ conn.commitText(text, 1);
+ }
+ }
+ }
+
+ /**
* This is called when the user has clicked on the extracted text view,
* when running in fullscreen mode. The default implementation hides
* the candidates view when this happens, but only if the extracted text
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index e289fc1..d39e741 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -250,4 +250,32 @@
}
return result;
}
+
+ /**
+ * Trim leading zeros from IPv4 address strings
+ * Our base libraries will interpret that as octel..
+ * Must leave non v4 addresses and host names alone.
+ * For example, 192.168.000.010 -> 192.168.0.10
+ * TODO - fix base libraries and remove this function
+ * @param addr a string representing an ip addr
+ * @return a string propertly trimmed
+ */
+ public static String trimV4AddrZeros(String addr) {
+ if (addr == null) return null;
+ String[] octets = addr.split("\\.");
+ if (octets.length != 4) return addr;
+ StringBuilder builder = new StringBuilder(16);
+ String result = null;
+ for (int i = 0; i < 4; i++) {
+ try {
+ if (octets[i].length() > 3) return addr;
+ builder.append(Integer.parseInt(octets[i]));
+ } catch (NumberFormatException e) {
+ return addr;
+ }
+ if (i < 3) builder.append('.');
+ }
+ result = builder.toString();
+ return result;
+ }
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 7d034940..88fea91 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -311,7 +311,7 @@
public static final int ICE_CREAM_SANDWICH = 14;
/**
- * Android 4.1.
+ * Android 4.0.3.
*/
public static final int ICE_CREAM_SANDWICH_MR1 = 15;
}
diff --git a/core/java/android/os/storage/package.html b/core/java/android/os/storage/package.html
new file mode 100644
index 0000000..a5f1e1c
--- /dev/null
+++ b/core/java/android/os/storage/package.html
@@ -0,0 +1,8 @@
+<HTML>
+<BODY>
+<p>
+Contains classes for the system storage service, which manages binary asset filesystems
+known as Opaque Binary Blobs (OBBs).
+</p>
+</BODY>
+</HTML>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index caff53b..c44f23b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2779,10 +2779,10 @@
public static final String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
/**
- * If injection of accessibility enhancing JavaScript scripts
+ * If injection of accessibility enhancing JavaScript screen-reader
* is enabled.
* <p>
- * Note: Accessibility injecting scripts are served by the
+ * Note: The JavaScript based screen-reader is served by the
* Google infrastructure and enable users with disabilities to
* efficiantly navigate in and explore web content.
* </p>
@@ -2795,6 +2795,22 @@
"accessibility_script_injection";
/**
+ * The URL for the injected JavaScript based screen-reader used
+ * for providing accessiblity of content in WebView.
+ * <p>
+ * Note: The JavaScript based screen-reader is served by the
+ * Google infrastructure and enable users with disabilities to
+ * efficiently navigate in and explore web content.
+ * </p>
+ * <p>
+ * This property represents a string value.
+ * </p>
+ * @hide
+ */
+ public static final String ACCESSIBILITY_SCREEN_READER_URL =
+ "accessibility_script_injection_url";
+
+ /**
* Key bindings for navigation in built-in accessibility support for web content.
* <p>
* Note: These key bindings are for the built-in accessibility navigation for
diff --git a/core/java/android/speech/tts/AudioPlaybackQueueItem.java b/core/java/android/speech/tts/AudioPlaybackQueueItem.java
index 668b459..1a1fda81 100644
--- a/core/java/android/speech/tts/AudioPlaybackQueueItem.java
+++ b/core/java/android/speech/tts/AudioPlaybackQueueItem.java
@@ -15,27 +15,91 @@
*/
package android.speech.tts;
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.ConditionVariable;
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
import android.util.Log;
class AudioPlaybackQueueItem extends PlaybackQueueItem {
- private final BlockingMediaPlayer mPlayer;
+ private static final String TAG = "TTS.AudioQueueItem";
+
+ private final Context mContext;
+ private final Uri mUri;
+ private final int mStreamType;
+
+ private final ConditionVariable mDone;
+ private MediaPlayer mPlayer;
+ private volatile boolean mFinished;
AudioPlaybackQueueItem(UtteranceProgressDispatcher dispatcher,
- Object callerIdentity, BlockingMediaPlayer player) {
+ Object callerIdentity,
+ Context context, Uri uri, int streamType) {
super(dispatcher, callerIdentity);
- mPlayer = player;
+
+ mContext = context;
+ mUri = uri;
+ mStreamType = streamType;
+
+ mDone = new ConditionVariable();
+ mPlayer = null;
+ mFinished = false;
}
@Override
public void run() {
- getDispatcher().dispatchOnStart();
- // TODO: This can be avoided. Will be fixed later in this CL.
- mPlayer.startAndWait();
- getDispatcher().dispatchOnDone();
+ final UtteranceProgressDispatcher dispatcher = getDispatcher();
+
+ dispatcher.dispatchOnStart();
+ mPlayer = MediaPlayer.create(mContext, mUri);
+ if (mPlayer == null) {
+ dispatcher.dispatchOnError();
+ return;
+ }
+
+ try {
+ mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+ @Override
+ public boolean onError(MediaPlayer mp, int what, int extra) {
+ Log.w(TAG, "Audio playback error: " + what + ", " + extra);
+ mDone.open();
+ return true;
+ }
+ });
+ mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+ @Override
+ public void onCompletion(MediaPlayer mp) {
+ mFinished = true;
+ mDone.open();
+ }
+ });
+ mPlayer.setAudioStreamType(mStreamType);
+ mPlayer.start();
+ mDone.block();
+ finish();
+ } catch (IllegalArgumentException ex) {
+ Log.w(TAG, "MediaPlayer failed", ex);
+ mDone.open();
+ }
+
+ if (mFinished) {
+ dispatcher.dispatchOnDone();
+ } else {
+ dispatcher.dispatchOnError();
+ }
+ }
+
+ private void finish() {
+ try {
+ mPlayer.stop();
+ } catch (IllegalStateException ex) {
+ // Do nothing, the player is already stopped
+ }
+ mPlayer.release();
}
@Override
void stop(boolean isError) {
- mPlayer.stop();
+ mDone.open();
}
}
diff --git a/core/java/android/speech/tts/BlockingMediaPlayer.java b/core/java/android/speech/tts/BlockingMediaPlayer.java
deleted file mode 100644
index 1ccc6e4..0000000
--- a/core/java/android/speech/tts/BlockingMediaPlayer.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * 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.content.Context;
-import android.media.MediaPlayer;
-import android.net.Uri;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.util.Log;
-
-/**
- * A media player that allows blocking to wait for it to finish.
- */
-class BlockingMediaPlayer {
-
- private static final String TAG = "BlockMediaPlayer";
-
- private static final String MEDIA_PLAYER_THREAD_NAME = "TTS-MediaPlayer";
-
- private final Context mContext;
- private final Uri mUri;
- private final int mStreamType;
- private final ConditionVariable mDone;
- // Only accessed on the Handler thread
- private MediaPlayer mPlayer;
- private volatile boolean mFinished;
-
- /**
- * Creates a new blocking media player.
- * Creating a blocking media player is a cheap operation.
- *
- * @param context
- * @param uri
- * @param streamType
- */
- public BlockingMediaPlayer(Context context, Uri uri, int streamType) {
- mContext = context;
- mUri = uri;
- mStreamType = streamType;
- mDone = new ConditionVariable();
- }
-
- /**
- * Starts playback and waits for it to finish.
- * Can be called from any thread.
- *
- * @return {@code true} if the playback finished normally, {@code false} if the playback
- * failed or {@link #stop} was called before the playback finished.
- */
- public boolean startAndWait() {
- HandlerThread thread = new HandlerThread(MEDIA_PLAYER_THREAD_NAME);
- thread.start();
- Handler handler = new Handler(thread.getLooper());
- mFinished = false;
- handler.post(new Runnable() {
- @Override
- public void run() {
- startPlaying();
- }
- });
- mDone.block();
- handler.post(new Runnable() {
- @Override
- public void run() {
- finish();
- // No new messages should get posted to the handler thread after this
- Looper.myLooper().quit();
- }
- });
- return mFinished;
- }
-
- /**
- * Stops playback. Can be called multiple times.
- * Can be called from any thread.
- */
- public void stop() {
- mDone.open();
- }
-
- /**
- * Starts playback.
- * Called on the handler thread.
- */
- private void startPlaying() {
- mPlayer = MediaPlayer.create(mContext, mUri);
- if (mPlayer == null) {
- Log.w(TAG, "Failed to play " + mUri);
- mDone.open();
- return;
- }
- try {
- mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
- @Override
- public boolean onError(MediaPlayer mp, int what, int extra) {
- Log.w(TAG, "Audio playback error: " + what + ", " + extra);
- mDone.open();
- return true;
- }
- });
- mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
- @Override
- public void onCompletion(MediaPlayer mp) {
- mFinished = true;
- mDone.open();
- }
- });
- mPlayer.setAudioStreamType(mStreamType);
- mPlayer.start();
- } catch (IllegalArgumentException ex) {
- Log.w(TAG, "MediaPlayer failed", ex);
- mDone.open();
- }
- }
-
- /**
- * Stops playback and release the media player.
- * Called on the handler thread.
- */
- private void finish() {
- try {
- mPlayer.stop();
- } catch (IllegalStateException ex) {
- // Do nothing, the player is already stopped
- }
- mPlayer.release();
- }
-
-}
\ No newline at end of file
diff --git a/core/java/android/speech/tts/MessageParams.java b/core/java/android/speech/tts/MessageParams.java
deleted file mode 100644
index f83b793..0000000
--- a/core/java/android/speech/tts/MessageParams.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
-
-abstract class MessageParams {
- static final int TYPE_SYNTHESIS = 1;
- static final int TYPE_AUDIO = 2;
- static final int TYPE_SILENCE = 3;
-
- private final UtteranceProgressDispatcher mDispatcher;
- private final Object mCallerIdentity;
-
- MessageParams(UtteranceProgressDispatcher dispatcher, Object callerIdentity) {
- mDispatcher = dispatcher;
- mCallerIdentity = callerIdentity;
- }
-
- UtteranceProgressDispatcher getDispatcher() {
- return mDispatcher;
- }
-
- Object getCallerIdentity() {
- return mCallerIdentity;
- }
-
- @Override
- public String toString() {
- return "MessageParams[" + hashCode() + "]";
- }
-
- abstract int getType();
-}
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index ba8485a..4c1a0af 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -694,12 +694,12 @@
}
private class AudioSpeechItem extends SpeechItem {
- private final BlockingMediaPlayer mPlayer;
-
+ private final AudioPlaybackQueueItem mItem;
public AudioSpeechItem(Object callerIdentity, int callerUid, int callerPid,
Bundle params, Uri uri) {
super(callerIdentity, callerUid, callerPid, params);
- mPlayer = new BlockingMediaPlayer(TextToSpeechService.this, uri, getStreamType());
+ mItem = new AudioPlaybackQueueItem(this, getCallerIdentity(),
+ TextToSpeechService.this, uri, getStreamType());
}
@Override
@@ -709,8 +709,7 @@
@Override
protected int playImpl() {
- mAudioPlaybackHandler.enqueue(new AudioPlaybackQueueItem(
- this, getCallerIdentity(), mPlayer));
+ mAudioPlaybackHandler.enqueue(mItem);
return TextToSpeech.SUCCESS;
}
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 231f913..b708750 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -863,6 +863,17 @@
return new String(buf);
}
+ /**
+ * Return a String containing a copy of the chars in this buffer, limited to the
+ * [start, end[ range.
+ * @hide
+ */
+ public String substring(int start, int end) {
+ char[] buf = new char[end - start];
+ getChars(start, end, buf, 0);
+ return new String(buf);
+ }
+
private TextWatcher[] sendTextWillChange(int start, int before, int after) {
TextWatcher[] recip = getSpans(start, start + before, TextWatcher.class);
int n = recip.length;
diff --git a/core/java/android/text/method/WordIterator.java b/core/java/android/text/method/WordIterator.java
index 239d9e8..11226a9 100644
--- a/core/java/android/text/method/WordIterator.java
+++ b/core/java/android/text/method/WordIterator.java
@@ -18,6 +18,7 @@
package android.text.method;
import android.text.Selection;
+import android.text.SpannableStringBuilder;
import java.text.BreakIterator;
import java.util.Locale;
@@ -58,7 +59,11 @@
mOffsetShift = Math.max(0, start - WINDOW_WIDTH);
final int windowEnd = Math.min(charSequence.length(), end + WINDOW_WIDTH);
- mString = charSequence.toString().substring(mOffsetShift, windowEnd);
+ if (charSequence instanceof SpannableStringBuilder) {
+ mString = ((SpannableStringBuilder) charSequence).substring(mOffsetShift, windowEnd);
+ } else {
+ mString = charSequence.subSequence(mOffsetShift, windowEnd).toString();
+ }
mIterator.setText(mString);
}
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index ed2af10..0f26a34 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -92,11 +92,6 @@
private float mAutoCorrectionUnderlineThickness;
private int mAutoCorrectionUnderlineColor;
- /*
- * TODO: If switching IME is required, needs to add parameters for ids of InputMethodInfo
- * and InputMethodSubtype.
- */
-
/**
* @param context Context for the application
* @param suggestions Suggestions for the string under the span
@@ -146,6 +141,16 @@
}
private void initStyle(Context context) {
+ if (context == null) {
+ mMisspelledUnderlineThickness = 0;
+ mEasyCorrectUnderlineThickness = 0;
+ mAutoCorrectionUnderlineThickness = 0;
+ mMisspelledUnderlineColor = Color.BLACK;
+ mEasyCorrectUnderlineColor = Color.BLACK;
+ mAutoCorrectionUnderlineColor = Color.BLACK;
+ return;
+ }
+
int defStyle = com.android.internal.R.attr.textAppearanceMisspelledSuggestion;
TypedArray typedArray = context.obtainStyledAttributes(
null, com.android.internal.R.styleable.SuggestionSpan, defStyle, 0);
@@ -169,7 +174,6 @@
com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
mAutoCorrectionUnderlineColor = typedArray.getColor(
com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
-
}
public SuggestionSpan(Parcel src) {
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 443acf6..3f793bb 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -441,6 +441,8 @@
}
boolean mDirtyRegionsEnabled;
+ boolean mUpdateDirtyRegions;
+
final boolean mVsyncDisabled;
final int mGlVersion;
@@ -675,6 +677,12 @@
initCaches();
+ enableDirtyRegions();
+
+ return mEglContext.getGL();
+ }
+
+ private void enableDirtyRegions() {
// If mDirtyRegions is set, this means we have an EGL configuration
// with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
if (sDirtyRegions) {
@@ -690,8 +698,6 @@
// configuration (see RENDER_DIRTY_REGIONS)
mDirtyRegionsEnabled = GLES20Canvas.isBackBufferPreserved();
}
-
- return mEglContext.getGL();
}
abstract void initCaches();
@@ -745,6 +751,9 @@
if (!createSurface(holder)) {
return;
}
+
+ mUpdateDirtyRegions = true;
+
if (mCanvas != null) {
setEnabled(true);
}
@@ -943,6 +952,10 @@
fallback(true);
return SURFACE_STATE_ERROR;
} else {
+ if (mUpdateDirtyRegions) {
+ enableDirtyRegions();
+ mUpdateDirtyRegions = false;
+ }
return SURFACE_STATE_UPDATED;
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index af8f8cb..5c93a42 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12220,13 +12220,16 @@
* @param location an array of two integers in which to hold the coordinates
*/
public void getLocationInWindow(int[] location) {
- // When the view is not attached to a window, this method does not make sense
- if (mAttachInfo == null) return;
-
if (location == null || location.length < 2) {
throw new IllegalArgumentException("location must be an array of two integers");
}
+ if (mAttachInfo == null) {
+ // When the view is not attached to a window, this method does not make sense
+ location[0] = location[1] = 0;
+ return;
+ }
+
float[] position = mAttachInfo.mTmpTransformLocation;
position[0] = position[1] = 0.0f;
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 05c5daa..b455ad5 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -149,7 +149,7 @@
* It may be appropriate to tweak this on a device-specific basis in an overlay based on
* the characteristics of the touch panel and firmware.
*/
- private static final int TOUCH_SLOP = 4;
+ private static final int TOUCH_SLOP = 8;
/**
* Distance the first touch can wander before we stop considering this event a double tap
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 5035cae..1102a47 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2719,13 +2719,6 @@
return more;
}
- float alpha = child.getAlpha();
- // Bail out early if the view does not need to be drawn
- if (alpha <= ViewConfiguration.ALPHA_THRESHOLD && (child.mPrivateFlags & ALPHA_SET) == 0 &&
- !(child instanceof SurfaceView)) {
- return more;
- }
-
if (hardwareAccelerated) {
// Clear INVALIDATED flag to allow invalidation to occur during rendering, but
// retain the flag's value temporarily in the mRecreateDisplayList flag
@@ -2779,6 +2772,7 @@
}
}
+ float alpha = child.getAlpha();
if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) {
if (transformToApply != null || !childHasIdentityMatrix) {
int transX = 0;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7a9d82c..72966ef4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3257,8 +3257,9 @@
}
// If the Control modifier is held, try to interpret the key as a shortcut.
- if (event.getAction() == KeyEvent.ACTION_UP
+ if (event.getAction() == KeyEvent.ACTION_DOWN
&& event.isCtrlPressed()
+ && event.getRepeatCount() == 0
&& !KeyEvent.isModifierKey(event.getKeyCode())) {
if (mView.dispatchKeyShortcutEvent(event)) {
finishInputEvent(q, true);
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 3574a0d..2b59b80 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -19,10 +19,13 @@
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Paint.Style;
+import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -51,7 +54,6 @@
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
-import android.widget.AbsoluteLayout;
import android.widget.AbsoluteLayout.LayoutParams;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
@@ -74,7 +76,6 @@
static final String LOGTAG = "webtextview";
- private Paint mRingPaint;
private int mRingInset;
private WebView mWebView;
@@ -207,13 +208,51 @@
}
}
};
- float ringWidth = 4f * context.getResources().getDisplayMetrics().density;
mReceiver = new MyResultReceiver(mHandler);
- mRingPaint = new Paint();
- mRingPaint.setColor(0x6633b5e5);
- mRingPaint.setStrokeWidth(ringWidth);
- mRingPaint.setStyle(Style.FILL);
+ float ringWidth = 2f * context.getResources().getDisplayMetrics().density;
mRingInset = (int) ringWidth;
+ setBackgroundDrawable(new BackgroundDrawable(mRingInset));
+ setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
+ getPaddingBottom());
+ }
+
+ private static class BackgroundDrawable extends Drawable {
+
+ private Paint mPaint = new Paint();
+ private int mBorderWidth;
+ private Rect mInsetRect = new Rect();
+
+ public BackgroundDrawable(int width) {
+ mPaint = new Paint();
+ mPaint.setStrokeWidth(width);
+ mBorderWidth = width;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ mPaint.setColor(0x6633b5e5);
+ canvas.drawRect(getBounds(), mPaint);
+ mInsetRect.left = getBounds().left + mBorderWidth;
+ mInsetRect.top = getBounds().top + mBorderWidth;
+ mInsetRect.right = getBounds().right - mBorderWidth;
+ mInsetRect.bottom = getBounds().bottom - mBorderWidth;
+ mPaint.setColor(Color.WHITE);
+ canvas.drawRect(mInsetRect, mPaint);
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
}
public void setAutoFillable(int queryId) {
@@ -223,35 +262,9 @@
}
@Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- if (isFocused()) {
- final int ib = getHeight() - mRingInset;
- canvas.drawRect(0, 0, getWidth(), mRingInset, mRingPaint);
- canvas.drawRect(0, ib, getWidth(), getHeight(), mRingPaint);
- canvas.drawRect(0, mRingInset, mRingInset, ib, mRingPaint);
- canvas.drawRect(getWidth() - mRingInset, mRingInset, getWidth(), ib, mRingPaint);
- }
- }
-
- private void growOrShrink(boolean grow) {
- AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams) getLayoutParams();
- if (grow) {
- lp.x -= mRingInset;
- lp.y -= mRingInset;
- lp.width += 2 * mRingInset;
- lp.height += 2 * mRingInset;
- setPadding(getPaddingLeft() + mRingInset, getPaddingTop() + mRingInset,
- getPaddingRight() + mRingInset, getPaddingBottom() + mRingInset);
- } else {
- lp.x += mRingInset;
- lp.y += mRingInset;
- lp.width -= 2 * mRingInset;
- lp.height -= 2 * mRingInset;
- setPadding(getPaddingLeft() - mRingInset, getPaddingTop() - mRingInset,
- getPaddingRight() - mRingInset, getPaddingBottom() - mRingInset);
- }
- setLayoutParams(lp);
+ public void setPadding(int left, int top, int right, int bottom) {
+ super.setPadding(left + mRingInset, top + mRingInset,
+ right + mRingInset, bottom + mRingInset);
}
@Override
@@ -555,7 +568,6 @@
} else if (!mInsideRemove) {
mWebView.setActive(false);
}
- growOrShrink(focused);
mFromFocusChange = false;
}
@@ -966,6 +978,10 @@
*/
/* package */ void setRect(int x, int y, int width, int height) {
LayoutParams lp = (LayoutParams) getLayoutParams();
+ x -= mRingInset;
+ y -= mRingInset;
+ width += 2 * mRingInset;
+ height += 2 * mRingInset;
boolean needsUpdate = false;
if (null == lp) {
lp = new LayoutParams(width, height, x, y);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index b68dec9..a284a17 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -59,6 +59,7 @@
import android.os.StrictMode;
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
@@ -849,13 +850,12 @@
// the alias via which accessibility JavaScript interface is exposed
private static final String ALIAS_ACCESSIBILITY_JS_INTERFACE = "accessibility";
- // JavaScript to inject the script chooser which will
- // pick the right script for the current URL
- private static final String ACCESSIBILITY_SCRIPT_CHOOSER_JAVASCRIPT =
+ // Template for JavaScript that injects a screen-reader.
+ private static final String ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE =
"javascript:(function() {" +
" var chooser = document.createElement('script');" +
" chooser.type = 'text/javascript';" +
- " chooser.src = 'https://ssl.gstatic.com/accessibility/javascript/android/AndroidScriptChooser.user.js';" +
+ " chooser.src = '%1s';" +
" document.getElementsByTagName('head')[0].appendChild(chooser);" +
" })();";
@@ -2496,11 +2496,12 @@
}
/**
- * Return the reading level scale of the WebView
+ * Compute the reading level scale of the WebView
+ * @param scale The current scale.
* @return The reading level scale.
*/
- /*package*/ float getReadingLevelScale() {
- return mZoomManager.getReadingLevelScale();
+ /*package*/ float computeReadingLevelScale(float scale) {
+ return mZoomManager.computeReadingLevelScale(scale);
}
/**
@@ -3818,7 +3819,7 @@
if (onDeviceScriptInjectionEnabled) {
ensureAccessibilityScriptInjectorInstance(false);
// neither script injected nor script injection opted out => we inject
- loadUrl(ACCESSIBILITY_SCRIPT_CHOOSER_JAVASCRIPT);
+ loadUrl(getScreenReaderInjectingJs());
// TODO: Set this flag after successfull script injection. Maybe upon injection
// the chooser should update the meta tag and we check it to declare success
mAccessibilityScriptInjected = true;
@@ -3832,7 +3833,7 @@
} else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED) {
ensureAccessibilityScriptInjectorInstance(false);
// the URL provides accessibility but we still need to add our generic script
- loadUrl(ACCESSIBILITY_SCRIPT_CHOOSER_JAVASCRIPT);
+ loadUrl(getScreenReaderInjectingJs());
} else {
Log.e(LOGTAG, "Unknown URL value for the \"axs\" URL parameter: " + axsParameterValue);
}
@@ -3854,6 +3855,17 @@
}
/**
+ * Gets JavaScript that injects a screen-reader.
+ *
+ * @return The JavaScript snippet.
+ */
+ private String getScreenReaderInjectingJs() {
+ String screenReaderUrl = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL);
+ return String.format(ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE, screenReaderUrl);
+ }
+
+ /**
* Gets the "axs" URL parameter value.
*
* @param url A url to fetch the paramter from.
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 6cbcb47..de4949c 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2521,7 +2521,7 @@
if (mSettings.isNarrowColumnLayout()) {
// In case of automatic text reflow in fixed view port mode.
mInitialViewState.mTextWrapScale =
- mWebView.getReadingLevelScale();
+ mWebView.computeReadingLevelScale(data.mScale);
}
} else {
// Scale is given such as when page is restored, use it.
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 14bdc42..8ffba64 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -316,7 +316,12 @@
* Returns the zoom scale used for reading text on a double-tap.
*/
public final float getReadingLevelScale() {
- return mDisplayDensity * mDoubleTapZoomFactor;
+ return computeScaleWithLimits(computeReadingLevelScale(getZoomOverviewScale()));
+ }
+
+ /* package */ final float computeReadingLevelScale(float scale) {
+ return Math.max(mDisplayDensity * mDoubleTapZoomFactor,
+ scale + MIN_DOUBLE_TAP_SCALE_INCREMENT);
}
public final float getInvDefaultScale() {
@@ -678,7 +683,7 @@
}
zoomToOverview();
} else {
- zoomToReadingLevelOrMore();
+ zoomToReadingLevel();
}
}
@@ -709,9 +714,8 @@
!mWebView.getSettings().getUseFixedViewport());
}
- private void zoomToReadingLevelOrMore() {
- final float zoomScale = Math.max(getReadingLevelScale(),
- mActualScale + MIN_DOUBLE_TAP_SCALE_INCREMENT);
+ private void zoomToReadingLevel() {
+ final float readingScale = getReadingLevelScale();
int left = mWebView.nativeGetBlockLeftEdge(mAnchorX, mAnchorY, mActualScale);
if (left != WebView.NO_LEFTEDGE) {
@@ -721,13 +725,13 @@
// Re-calculate the zoom center so that the new scroll x will be
// on the left edge.
if (viewLeft > 0) {
- mZoomCenterX = viewLeft * zoomScale / (zoomScale - mActualScale);
+ mZoomCenterX = viewLeft * readingScale / (readingScale - mActualScale);
} else {
mWebView.scrollBy(viewLeft, 0);
mZoomCenterX = 0;
}
}
- startZoomAnimation(zoomScale,
+ startZoomAnimation(readingScale,
!mWebView.getSettings().getUseFixedViewport());
}
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 9d541e0..7d0f98e 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -774,6 +774,7 @@
mBeginEditOnUpEvent = false;
mAdjustScrollerOnUpEvent = true;
if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) {
+ mSelectorWheelPaint.setAlpha(SELECTOR_WHEEL_BRIGHT_ALPHA);
boolean scrollersFinished = mFlingScroller.isFinished()
&& mAdjustScroller.isFinished();
if (!scrollersFinished) {
@@ -1608,23 +1609,11 @@
*/
private void fling(int velocityY) {
mPreviousScrollerY = 0;
- Scroller flingScroller = mFlingScroller;
- if (mWrapSelectorWheel) {
- if (velocityY > 0) {
- flingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE);
- } else {
- flingScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE);
- }
+ if (velocityY > 0) {
+ mFlingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE);
} else {
- if (velocityY > 0) {
- int maxY = mTextSize * (mValue - mMinValue);
- flingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, maxY);
- } else {
- int startY = mTextSize * (mMaxValue - mValue);
- int maxY = startY;
- flingScroller.fling(0, startY, 0, velocityY, 0, 0, 0, maxY);
- }
+ mFlingScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE);
}
invalidate();
diff --git a/core/java/android/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java
index 7ba4777..07bd918 100644
--- a/core/java/android/widget/RemoteViewsService.java
+++ b/core/java/android/widget/RemoteViewsService.java
@@ -145,6 +145,9 @@
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
}
}
+ public synchronized void onDataSetChangedAsync() {
+ onDataSetChanged();
+ }
public synchronized int getCount() {
int count = 0;
try {
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 4bd7165..31da5b5 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.text.Editable;
import android.text.Selection;
+import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.WordIterator;
import android.text.style.SpellCheckSpan;
@@ -220,7 +221,6 @@
TextInfo[] textInfos = new TextInfo[mLength];
int textInfosCount = 0;
- final String text = editable.toString();
for (int i = 0; i < mLength; i++) {
final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[i];
if (spellCheckSpan.isSpellCheckInProgress()) continue;
@@ -230,7 +230,9 @@
// Do not check this word if the user is currently editing it
if (start >= 0 && end > start && (selectionEnd < start || selectionStart > end)) {
- final String word = text.substring(start, end);
+ final String word = (editable instanceof SpannableStringBuilder) ?
+ ((SpannableStringBuilder) editable).substring(start, end) :
+ editable.subSequence(start, end).toString();
spellCheckSpan.setSpellCheckInProgress(true);
textInfos[textInfosCount++] = new TextInfo(word, mCookie, mIds[i]);
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 82bcd3e..5b73a74 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5517,7 +5517,7 @@
* call performClick(), but that won't do anything in
* this case.)
*/
- if (hasOnClickListeners()) {
+ if (!hasOnClickListeners()) {
if (mMovement != null && mText instanceof Editable
&& mLayout != null && onCheckIsTextEditor()) {
InputMethodManager imm = InputMethodManager.peekInstance();
@@ -5554,7 +5554,7 @@
* call performClick(), but that won't do anything in
* this case.)
*/
- if (hasOnClickListeners()) {
+ if (!hasOnClickListeners()) {
View v = focusSearch(FOCUS_DOWN);
if (v != null) {
@@ -9835,7 +9835,7 @@
highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd);
}
- // Add to dictionary item is there a span with the misspelled flag
+ // Add to dictionary item if there is a span with the misspelled flag
if (misspelledSpan != null) {
final int misspelledStart = spannable.getSpanStart(misspelledSpan);
final int misspelledEnd = spannable.getSpanEnd(misspelledSpan);
@@ -9921,7 +9921,7 @@
final int spanStart = editable.getSpanStart(suggestionInfo.suggestionSpan);
final int spanEnd = editable.getSpanEnd(suggestionInfo.suggestionSpan);
- if (spanStart < 0 || spanEnd < 0) {
+ if (spanStart < 0 || spanEnd <= spanStart) {
// Span has been removed
hide();
return;
@@ -9931,6 +9931,7 @@
if (suggestionInfo.suggestionIndex == ADD_TO_DICTIONARY) {
Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_INSERT);
intent.putExtra("word", originalText);
+ intent.putExtra("locale", getTextServicesLocale().toString());
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
// There is no way to know if the word was indeed added. Re-check.
@@ -9988,14 +9989,14 @@
// way to assign them a valid range after replacement
if (suggestionSpansStarts[i] <= spanStart &&
suggestionSpansEnds[i] >= spanEnd) {
- // TODO The ExtractEditText should restore these spans in the original text
- editable.setSpan(suggestionSpans[i], suggestionSpansStarts[i],
+ setSpan_internal(suggestionSpans[i], suggestionSpansStarts[i],
suggestionSpansEnds[i] + lengthDifference, suggestionSpansFlags[i]);
}
}
// Move cursor at the end of the replaced word
- Selection.setSelection(editable, spanEnd + lengthDifference);
+ final int newCursorPosition = spanEnd + lengthDifference;
+ setCursorPosition_internal(newCursorPosition, newCursorPosition);
}
hide();
@@ -11468,6 +11469,22 @@
((Editable) mText).replace(start, end, text);
}
+ /**
+ * Sets a span on the specified range of text
+ * @hide
+ */
+ protected void setSpan_internal(Object span, int start, int end, int flags) {
+ ((Editable) mText).setSpan(span, start, end, flags);
+ }
+
+ /**
+ * Moves the cursor to the specified offset position in text
+ * @hide
+ */
+ protected void setCursorPosition_internal(int start, int end) {
+ Selection.setSelection(((Editable) mText), start, end);
+ }
+
@ViewDebug.ExportedProperty(category = "text")
private CharSequence mText;
private CharSequence mTransformed;
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 72489a2..61c0c8e 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -1367,10 +1367,12 @@
/**
* Get a message and set Message.target = this.
*
- * @return message
+ * @return message or null if SM has quit
*/
public final Message obtainMessage()
{
+ if (mSmHandler == null) return null;
+
return Message.obtain(mSmHandler);
}
@@ -1378,9 +1380,11 @@
* Get a message and set Message.target = this and what
*
* @param what is the assigned to Message.what.
- * @return message
+ * @return message or null if SM has quit
*/
public final Message obtainMessage(int what) {
+ if (mSmHandler == null) return null;
+
return Message.obtain(mSmHandler, what);
}
@@ -1390,10 +1394,12 @@
*
* @param what is the assigned to Message.what.
* @param obj is assigned to Message.obj.
- * @return message
+ * @return message or null if SM has quit
*/
public final Message obtainMessage(int what, Object obj)
{
+ if (mSmHandler == null) return null;
+
return Message.obtain(mSmHandler, what, obj);
}
@@ -1404,10 +1410,13 @@
* @param what is assigned to Message.what
* @param arg1 is assigned to Message.arg1
* @param arg2 is assigned to Message.arg2
- * @return A Message object from the global pool.
+ * @return A Message object from the global pool or null if
+ * SM has quit
*/
public final Message obtainMessage(int what, int arg1, int arg2)
{
+ if (mSmHandler == null) return null;
+
return Message.obtain(mSmHandler, what, arg1, arg2);
}
@@ -1419,10 +1428,13 @@
* @param arg1 is assigned to Message.arg1
* @param arg2 is assigned to Message.arg2
* @param obj is assigned to Message.obj
- * @return A Message object from the global pool.
+ * @return A Message object from the global pool or null if
+ * SM has quit
*/
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
+ if (mSmHandler == null) return null;
+
return Message.obtain(mSmHandler, what, arg1, arg2, obj);
}
@@ -1430,6 +1442,9 @@
* Enqueue a message to this state machine.
*/
public final void sendMessage(int what) {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.sendMessage(obtainMessage(what));
}
@@ -1437,6 +1452,9 @@
* Enqueue a message to this state machine.
*/
public final void sendMessage(int what, Object obj) {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.sendMessage(obtainMessage(what,obj));
}
@@ -1444,6 +1462,9 @@
* Enqueue a message to this state machine.
*/
public final void sendMessage(Message msg) {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.sendMessage(msg);
}
@@ -1451,6 +1472,9 @@
* Enqueue a message to this state machine after a delay.
*/
public final void sendMessageDelayed(int what, long delayMillis) {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
}
@@ -1458,6 +1482,9 @@
* Enqueue a message to this state machine after a delay.
*/
public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
}
@@ -1465,6 +1492,9 @@
* Enqueue a message to this state machine after a delay.
*/
public final void sendMessageDelayed(Message msg, long delayMillis) {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.sendMessageDelayed(msg, delayMillis);
}
@@ -1509,6 +1539,9 @@
* will be processed.
*/
public final void quit() {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.quit();
}
@@ -1523,6 +1556,9 @@
* @return if debugging is enabled
*/
public boolean isDbg() {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return false;
+
return mSmHandler.isDbg();
}
@@ -1532,6 +1568,9 @@
* @param dbg is true to enable debugging.
*/
public void setDbg(boolean dbg) {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.setDbg(dbg);
}
@@ -1539,6 +1578,9 @@
* Start the state machine.
*/
public void start() {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
/** Send the complete construction message */
mSmHandler.completeConstruction();
}
diff --git a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
index 18076c4..7317ecf 100644
--- a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
+++ b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
@@ -22,6 +22,7 @@
/** {@hide} */
interface IRemoteViewsFactory {
void onDataSetChanged();
+ oneway void onDataSetChangedAsync();
oneway void onDestroy(in Intent intent);
int getCount();
RemoteViews getViewAt(int position);
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 7724646..feba1e6 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -732,11 +732,7 @@
jcharArray text, int index, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
jchar* textArray = env->GetCharArrayElements(text, NULL);
-#if RTL_USE_HARFBUZZ
drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
-#else
- TextLayout::drawText(paint, textArray + index, count, flags, x, y, canvas);
-#endif
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
@@ -745,11 +741,7 @@
int start, int end,
jfloat x, jfloat y, int flags, SkPaint* paint) {
const jchar* textArray = env->GetStringChars(text, NULL);
-#if RTL_USE_HARFBUZZ
drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
-#else
- TextLayout::drawText(paint, textArray + start, end - start, flags, x, y, canvas);
-#endif
env->ReleaseStringChars(text, textArray);
}
@@ -770,12 +762,14 @@
value = TextLayoutCache::getInstance().getValue(paint, textArray, start, count,
contextCount, flags);
if (value == NULL) {
- LOGE("Cannot get TextLayoutCache value");
+ LOGE("Cannot get TextLayoutCache value for text = '%s'",
+ String8(textArray + start, count).string());
return ;
}
#else
- value = new TextLayoutCacheValue();
- value->computeValues(paint, textArray, start, count, contextCount, flags);
+ value = new TextLayoutCacheValue(contextCount);
+ TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+ reinterpret_cast<const UChar*>(textArray), start, count, contextCount, flags);
#endif
doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), x, y, flags, paint);
}
@@ -802,13 +796,8 @@
jfloat x, jfloat y, int dirFlags, SkPaint* paint) {
jchar* chars = env->GetCharArrayElements(text, NULL);
-#if RTL_USE_HARFBUZZ
drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
count, contextCount, x, y, dirFlags, paint);
-#else
- TextLayout::drawTextRun(paint, chars + contextIndex, index - contextIndex,
- count, contextCount, dirFlags, x, y, canvas);
-#endif
env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
}
@@ -820,13 +809,8 @@
jint count = end - start;
jint contextCount = contextEnd - contextStart;
const jchar* chars = env->GetStringChars(text, NULL);
-#if RTL_USE_HARFBUZZ
drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
count, contextCount, x, y, dirFlags, paint);
-#else
- TextLayout::drawTextRun(paint, chars + contextStart, start - contextStart,
- count, contextCount, dirFlags, x, y, canvas);
-#endif
env->ReleaseStringChars(text, chars);
}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 883940b..19f53d7 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -350,14 +350,10 @@
SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
const jchar* textArray = env->GetCharArrayElements(text, NULL);
jfloat result = 0;
-#if RTL_USE_HARFBUZZ
+
TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength,
paint->getFlags(), NULL /* dont need all advances */, &result);
-#else
- // we double count, since measureText wants a byteLength
- SkScalar width = paint->measureText(textArray + index, count << 1);
- result = SkScalarToFloat(width);
-#endif
+
env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
return result;
}
@@ -380,13 +376,9 @@
SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
jfloat width = 0;
-#if RTL_USE_HARFBUZZ
TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength,
paint->getFlags(), NULL /* dont need all advances */, &width);
-#else
- width = SkScalarToFloat(paint->measureText(textArray + start, count << 1));
-#endif
env->ReleaseStringChars(text, textArray);
return width;
}
@@ -404,12 +396,9 @@
SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
jfloat width = 0;
-#if RTL_USE_HARFBUZZ
TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength,
paint->getFlags(), NULL /* dont need all advances */, &width);
-#else
- width = SkScalarToFloat(paint->measureText(textArray, textLength << 1));
-#endif
+
env->ReleaseStringChars(text, textArray);
return width;
}
@@ -434,17 +423,9 @@
AutoJavaFloatArray autoWidths(env, widths, count);
jfloat* widthsArray = autoWidths.ptr();
-#if RTL_USE_HARFBUZZ
TextLayout::getTextRunAdvances(paint, text, 0, count, count,
paint->getFlags(), widthsArray, NULL /* dont need totalAdvance */);
-#else
- SkScalar* scalarArray = (SkScalar*)widthsArray;
- count = paint->getTextWidths(text, count << 1, scalarArray);
- for (int i = 0; i < count; i++) {
- widthsArray[i] = SkScalarToFloat(scalarArray[i]);
- }
-#endif
return count;
}
@@ -597,54 +578,11 @@
static jint doTextRunCursor(JNIEnv *env, SkPaint* paint, const jchar *text, jint start,
jint count, jint flags, jint offset, jint opt) {
-#if RTL_USE_HARFBUZZ
jfloat scalarArray[count];
TextLayout::getTextRunAdvances(paint, text, start, count, count, flags,
scalarArray, NULL /* dont need totalAdvance */);
-#else
- SkScalar scalarArray[count];
- jchar buffer[count];
- // this is where we'd call harfbuzz
- // for now we just use ushape.c and widths returned from skia
-
- int widths;
- if (flags & 0x1) { // rtl, call arabic shaping in case
- UErrorCode status = U_ZERO_ERROR;
- // Use fixed length since we need to keep start and count valid
- u_shapeArabic(text + start, count, buffer, count,
- U_SHAPE_LENGTH_FIXED_SPACES_NEAR | U_SHAPE_TEXT_DIRECTION_LOGICAL |
- U_SHAPE_LETTERS_SHAPE | U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
- // we shouldn't fail unless there's an out of memory condition,
- // in which case we're hosed anyway
- for (int i = 0; i < count; ++i) {
- if (buffer[i] == 0xffff) {
- buffer[i] = 0x200b; // zero-width-space for skia
- }
- }
- widths = paint->getTextWidths(buffer, count << 1, scalarArray);
- } else {
- widths = paint->getTextWidths(text + start, count << 1, scalarArray);
- }
-
- if (widths < count) {
- // Skia operates on code points, not code units, so surrogate pairs return only one
- // value. Expand the result so we have one value per UTF-16 code unit.
-
- // Note, skia's getTextWidth gets confused if it encounters a surrogate pair,
- // leaving the remaining widths zero. Not nice.
- const jchar *chars = text + start;
- for (int i = count, p = widths - 1; --i > p;) {
- if (chars[i] >= 0xdc00 && chars[i] < 0xe000 &&
- chars[i-1] >= 0xd800 && chars[i-1] < 0xdc00) {
- scalarArray[i] = 0;
- } else {
- scalarArray[i] = scalarArray[--p];
- }
- }
- }
-#endif
jint pos = offset - start;
switch (opt) {
case AFTER:
diff --git a/core/jni/android/graphics/RtlProperties.h b/core/jni/android/graphics/RtlProperties.h
index a41c91b..d43745f 100644
--- a/core/jni/android/graphics/RtlProperties.h
+++ b/core/jni/android/graphics/RtlProperties.h
@@ -45,9 +45,6 @@
return kRtlDebugDisabled;
}
-// Define if we want to use Harfbuzz (1) or not (0)
-#define RTL_USE_HARFBUZZ 1
-
// Define if we want (1) to have Advances debug values or not (0)
#define DEBUG_ADVANCES 0
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index e1398e9..bc30ace 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "TextLayout"
+
#include "TextLayout.h"
#include "TextLayoutCache.h"
@@ -46,211 +48,35 @@
return false;
}
-/**
- * Character-based Arabic shaping.
- *
- * We'll use harfbuzz and glyph-based shaping instead once we're set up for it.
- *
- * @context the text context
- * @start the start of the text to render
- * @count the length of the text to render, start + count must be <= contextCount
- * @contextCount the length of the context
- * @shaped where to put the shaped text, must have capacity for count uchars
- * @return the length of the shaped text, or -1 if error
- */
-int TextLayout::shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount,
- jchar* shaped, UErrorCode& status) {
- SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
- jchar* buffer = tempBuffer.get();
-
- // Use fixed length since we need to keep start and count valid
- u_shapeArabic(context, contextCount, buffer, contextCount,
- U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
- U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE |
- U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
-
- if (U_SUCCESS(status)) {
- // trim out UNICODE_NOT_A_CHAR following ligatures, if any
- int end = 0;
- for (int i = start, e = start + count; i < e; ++i) {
- if (buffer[i] != UNICODE_NOT_A_CHAR) {
- buffer[end++] = buffer[i];
- }
- }
- count = end;
- // ALOG(LOG_INFO, "CSRTL", "start %d count %d ccount %d\n", start, count, contextCount);
- ubidi_writeReverse(buffer, count, shaped, count, UBIDI_DO_MIRRORING | UBIDI_OUTPUT_REVERSE
- | UBIDI_KEEP_BASE_COMBINING, &status);
- if (U_SUCCESS(status)) {
- return count;
- }
- }
- return -1;
-}
-
-/**
- * Basic character-based layout supporting rtl and arabic shaping.
- * Runs bidi on the text and generates a reordered, shaped line in buffer, returning
- * the length.
- * @text the text
- * @len the length of the text in uchars
- * @dir receives the resolved paragraph direction
- * @buffer the buffer to receive the reordered, shaped line. Must have capacity of
- * at least len jchars.
- * @flags line bidi flags
- * @return the length of the reordered, shaped line, or -1 if error
- */
-jint TextLayout::layoutLine(const jchar* text, jint len, jint flags, int& dir, jchar* buffer,
- UErrorCode& status) {
- static const int RTL_OPTS = UBIDI_DO_MIRRORING | UBIDI_KEEP_BASE_COMBINING |
- UBIDI_REMOVE_BIDI_CONTROLS | UBIDI_OUTPUT_REVERSE;
-
- UBiDiLevel bidiReq = 0;
- switch (flags) {
- case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
- case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
- case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
- case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break;
- case kBidi_Force_LTR: memcpy(buffer, text, len * sizeof(jchar)); return len;
- case kBidi_Force_RTL: return shapeRtlText(text, 0, len, len, buffer, status);
- }
-
- int32_t result = -1;
-
- UBiDi* bidi = ubidi_open();
- if (bidi) {
- ubidi_setPara(bidi, text, len, bidiReq, NULL, &status);
- if (U_SUCCESS(status)) {
- dir = ubidi_getParaLevel(bidi) & 0x1; // 0 if ltr, 1 if rtl
-
- int rc = ubidi_countRuns(bidi, &status);
- if (U_SUCCESS(status)) {
- // ALOG(LOG_INFO, "LAYOUT", "para bidiReq=%d dir=%d rc=%d\n", bidiReq, dir, rc);
-
- int32_t slen = 0;
- for (int i = 0; i < rc; ++i) {
- int32_t start;
- int32_t length;
- UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &start, &length);
-
- if (runDir == UBIDI_RTL) {
- slen += shapeRtlText(text + start, 0, length, length, buffer + slen, status);
- } else {
- memcpy(buffer + slen, text + start, length * sizeof(jchar));
- slen += length;
- }
- }
- if (U_SUCCESS(status)) {
- result = slen;
- }
- }
- }
- ubidi_close(bidi);
- }
-
- return result;
-}
-
-bool TextLayout::prepareText(SkPaint* paint, const jchar* text, jsize len, jint bidiFlags,
- const jchar** outText, int32_t* outBytes, jchar** outBuffer) {
- const jchar *workText = text;
- jchar *buffer = NULL;
- int dir = kDirection_LTR;
- if (needsLayout(text, len, bidiFlags)) {
- buffer =(jchar *) malloc(len * sizeof(jchar));
- if (!buffer) {
- return false;
- }
- UErrorCode status = U_ZERO_ERROR;
- len = layoutLine(text, len, bidiFlags, dir, buffer, status); // might change len, dir
- if (!U_SUCCESS(status)) {
- ALOG(LOG_WARN, "LAYOUT", "drawText error %d\n", status);
- free(buffer);
- return false; // can't render
- }
- workText = buffer; // use the shaped text
- }
-
- bool trimLeft = false;
- bool trimRight = false;
-
- SkPaint::Align horiz = paint->getTextAlign();
- switch (horiz) {
- case SkPaint::kLeft_Align: trimLeft = dir & kDirection_Mask; break;
- case SkPaint::kCenter_Align: trimLeft = trimRight = true; break;
- case SkPaint::kRight_Align: trimRight = !(dir & kDirection_Mask);
- default: break;
- }
- const jchar* workLimit = workText + len;
-
- if (trimLeft) {
- while (workText < workLimit && *workText == ' ') {
- ++workText;
- }
- }
- if (trimRight) {
- while (workLimit > workText && *(workLimit - 1) == ' ') {
- --workLimit;
- }
- }
-
- *outBytes = (workLimit - workText) << 1;
- *outText = workText;
- *outBuffer = buffer;
-
- return true;
-}
-
// Draws or gets the path of a paragraph of text on a single line, running bidi and shaping.
// This will draw if canvas is not null, otherwise path must be non-null and it will create
// a path representing the text that would have been drawn.
void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len,
jint bidiFlags, jfloat x, jfloat y,SkCanvas *canvas, SkPath *path) {
- const jchar *workText;
- jchar *buffer = NULL;
- int32_t workBytes;
- if (prepareText(paint, text, len, bidiFlags, &workText, &workBytes, &buffer)) {
- SkScalar x_ = SkFloatToScalar(x);
- SkScalar y_ = SkFloatToScalar(y);
- if (canvas) {
- canvas->drawText(workText, workBytes, x_, y_, *paint);
- } else {
- paint->getTextPath(workText, workBytes, x_, y_, path);
- }
- free(buffer);
+ sp<TextLayoutCacheValue> value;
+#if USE_TEXT_LAYOUT_CACHE
+ // Return advances from the cache. Compute them if needed
+ value = TextLayoutCache::getInstance().getValue(paint, text, 0, len,
+ len, bidiFlags);
+#else
+ value = new TextLayoutCacheValue(len);
+ TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+ reinterpret_cast<const UChar*>(text), 0, len, len, bidiFlags);
+#endif
+ if (value == NULL) {
+ LOGE("Cannot get TextLayoutCache value for text = '%s'",
+ String8(text, len).string());
+ return ;
}
-}
-
-bool TextLayout::prepareRtlTextRun(const jchar* context, jsize start, jsize& count,
- jsize contextCount, jchar* shaped) {
- UErrorCode status = U_ZERO_ERROR;
- count = shapeRtlText(context, start, count, contextCount, shaped, status);
- if (U_SUCCESS(status)) {
- return true;
+ SkScalar x_ = SkFloatToScalar(x);
+ SkScalar y_ = SkFloatToScalar(y);
+ if (canvas) {
+ canvas->drawText(value->getGlyphs(), value->getGlyphsCount() * 2, x_, y_, *paint);
} else {
- LOGW("drawTextRun error %d\n", status);
+ paint->getTextPath(value->getGlyphs(), value->getGlyphsCount() * 2, x_, y_, path);
}
- return false;
}
-void TextLayout::drawTextRun(SkPaint* paint, const jchar* chars,
- jint start, jint count, jint contextCount,
- int dirFlags, jfloat x, jfloat y, SkCanvas* canvas) {
-
- SkScalar x_ = SkFloatToScalar(x);
- SkScalar y_ = SkFloatToScalar(y);
-
- uint8_t rtl = dirFlags & 0x1;
- if (rtl) {
- SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> buffer(contextCount);
- if (prepareRtlTextRun(chars, start, count, contextCount, buffer.get())) {
- canvas->drawText(buffer.get(), count << 1, x_, y_, *paint);
- }
- } else {
- canvas->drawText(chars + start, count << 1, x_, y_, *paint);
- }
- }
-
void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
jint count, jint contextCount, jint dirFlags,
jfloat* resultAdvances, jfloat* resultTotalAdvance) {
@@ -260,16 +86,20 @@
value = TextLayoutCache::getInstance().getValue(paint, chars, start, count,
contextCount, dirFlags);
#else
- value = new TextLayoutCacheValue();
- value->computeValues(paint, chars, start, count, contextCount, dirFlags);
+ value = new TextLayoutCacheValue(contextCount);
+ TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+ reinterpret_cast<const UChar*>(chars), start, count, contextCount, dirFlags);
#endif
- if (value != NULL) {
- if (resultAdvances) {
- memcpy(resultAdvances, value->getAdvances(), value->getAdvancesCount() * sizeof(jfloat));
- }
- if (resultTotalAdvance) {
- *resultTotalAdvance = value->getTotalAdvance();
- }
+ if (value == NULL) {
+ LOGE("Cannot get TextLayoutCache value for text = '%s'",
+ String8(chars + start, count).string());
+ return ;
+ }
+ if (resultAdvances) {
+ memcpy(resultAdvances, value->getAdvances(), value->getAdvancesCount() * sizeof(jfloat));
+ }
+ if (resultTotalAdvance) {
+ *resultTotalAdvance = value->getTotalAdvance();
}
}
@@ -281,12 +111,6 @@
resultAdvances, &resultTotalAdvance);
}
-// Draws a paragraph of text on a single line, running bidi and shaping
-void TextLayout::drawText(SkPaint* paint, const jchar* text, jsize len,
- int bidiFlags, jfloat x, jfloat y, SkCanvas* canvas) {
- handleText(paint, text, len, bidiFlags, x, y, canvas, NULL);
-}
-
void TextLayout::getTextPath(SkPaint *paint, const jchar *text, jsize len,
jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
handleText(paint, text, len, bidiFlags, x, y, NULL, path);
@@ -305,14 +129,30 @@
return;
}
- SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> buffer(count);
-
- int dir = kDirection_LTR;
- UErrorCode status = U_ZERO_ERROR;
- count = layoutLine(text, count, bidiFlags, dir, buffer.get(), status);
- if (U_SUCCESS(status)) {
- canvas->drawTextOnPathHV(buffer.get(), count << 1, *path, h_, v_, *paint);
+ sp<TextLayoutCacheValue> value;
+#if USE_TEXT_LAYOUT_CACHE
+ value = TextLayoutCache::getInstance().getValue(paint, text, 0, count,
+ count, bidiFlags);
+#else
+ value = new TextLayoutCacheValue(count);
+ TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+ reinterpret_cast<const UChar*>(text), 0, count, count, bidiFlags);
+#endif
+ if (value == NULL) {
+ LOGE("Cannot get TextLayoutCache value for text = '%s'",
+ String8(text, count).string());
+ return ;
}
+
+ // Save old text encoding
+ SkPaint::TextEncoding oldEncoding = paint->getTextEncoding();
+ // Define Glyph encoding
+ paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ canvas->drawTextOnPathHV(value->getGlyphs(), value->getGlyphsCount() * 2, *path, h_, v_, *paint);
+
+ // Get back old encoding
+ paint->setTextEncoding(oldEncoding);
}
void TextLayout::computeAdvancesWithICU(SkPaint* paint, const UChar* chars,
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index 9df3829..1dabe32 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -62,13 +62,6 @@
class TextLayout {
public:
- /*
- * Draws a unidirectional run of text.
- */
- static void drawTextRun(SkPaint* paint, const jchar* chars,
- jint start, jint count, jint contextCount,
- int dirFlags, jfloat x, jfloat y, SkCanvas* canvas);
-
static void getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
jint count, jint contextCount, jint dirFlags,
jfloat* resultAdvances, jfloat* resultTotalAdvance);
@@ -77,29 +70,16 @@
jint count, jint contextCount, jint dirFlags,
jfloat* resultAdvances, jfloat& resultTotalAdvance);
- static void drawText(SkPaint* paint, const jchar* text, jsize len,
- jint bidiFlags, jfloat x, jfloat y, SkCanvas* canvas);
-
static void getTextPath(SkPaint* paint, const jchar* text, jsize len,
jint bidiFlags, jfloat x, jfloat y, SkPath* path);
static void drawTextOnPath(SkPaint* paint, const jchar* text, jsize len,
int bidiFlags, jfloat hOffset, jfloat vOffset,
SkPath* path, SkCanvas* canvas);
-
- static bool prepareText(SkPaint* paint, const jchar* text, jsize len, jint bidiFlags,
- const jchar** outText, int32_t* outBytes, jchar** outBuffer);
-
- static bool prepareRtlTextRun(const jchar* context, jsize start, jsize& count,
- jsize contextCount, jchar* shaped);
-
private:
static bool needsLayout(const jchar* text, jint len, jint bidiFlags);
- static int shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount,
- jchar* shaped, UErrorCode& status);
- static jint layoutLine(const jchar* text, jint len, jint flags, int &dir, jchar* buffer,
- UErrorCode &status);
+
static void handleText(SkPaint* paint, const jchar* text, jsize len,
int bidiFlags, jfloat x, jfloat y, SkCanvas* canvas, SkPath* path);
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index f1c3101..81bf4d5 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -34,10 +34,11 @@
#if USE_TEXT_LAYOUT_CACHE
ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutCache);
- ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine);
#endif
+ ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine);
+
//--------------------------------------------------------------------------------------------------
TextLayoutCache::TextLayoutCache() :
@@ -549,8 +550,8 @@
LOGD("Shaping Script Run with");
LOGD(" -- isRTL = %d", isRTL);
LOGD(" -- HB script = %d", mShaperItem.item.script);
- LOGD(" -- startFontRun = %d", startScriptRun);
- LOGD(" -- endFontRun = %d", endScriptRun);
+ LOGD(" -- startFontRun = %d", int(startScriptRun));
+ LOGD(" -- endFontRun = %d", int(endScriptRun));
LOGD(" -- countFontRun = %d", countScriptRun);
LOGD(" -- run = '%s'", String8(chars + startScriptRun, countScriptRun).string());
LOGD(" -- string = '%s'", String8(chars, count).string());
@@ -572,12 +573,12 @@
if (isRTL) {
endScriptRun = startScriptRun;
#if DEBUG_GLYPHS
- LOGD("Updated endScriptRun = %d", endScriptRun);
+ LOGD("Updated endScriptRun = %d", int(endScriptRun));
#endif
} else {
startScriptRun = endScriptRun;
#if DEBUG_GLYPHS
- LOGD("Updated startScriptRun = %d", startScriptRun);
+ LOGD("Updated startScriptRun = %d", int(startScriptRun));
#endif
}
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 3b45ccd..f61795d 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -107,6 +107,12 @@
return status_t(n);
}
+ status_t status = mReceiver.requestNextVsync();
+ if (status) {
+ LOGW("Failed to request next vsync, status=%d", status);
+ return status;
+ }
+
if (!mFdCallbackRegistered) {
int rc = mLooper->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
handleReceiveCallback, this);
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 9c7b108..5860658 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -44,7 +44,7 @@
#include <SkiaColorFilter.h>
#include <Rect.h>
-#include <TextLayout.h>
+#include <TextLayoutCache.h>
namespace android {
@@ -487,66 +487,45 @@
static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
-#if RTL_USE_HARFBUZZ
sp<TextLayoutCacheValue> value;
#if USE_TEXT_LAYOUT_CACHE
value = TextLayoutCache::getInstance().getValue(paint, text, 0, count, count, flags);
if (value == NULL) {
- LOGE("Cannot get TextLayoutCache value");
- return ;
+ LOGE("Cannot get TextLayoutCache value for text = '%s'",
+ String8(text, count).string());
+ return;
}
#else
- value = new TextLayoutCacheValue();
- value->computeValues(paint, text, 0, count, count, flags);
+ value = new TextLayoutCacheValue(count);
+ TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+ text, 0, count, count, flags);
#endif
const jchar* glyphs = value->getGlyphs();
size_t glyphsCount = value->getGlyphsCount();
int bytesCount = glyphsCount * sizeof(jchar);
renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y, paint);
-#else
- const jchar *workText;
- jchar* buffer = NULL;
- int32_t workBytes;
- if (TextLayout::prepareText(paint, text, count, flags, &workText, &workBytes, &buffer)) {
- renderer->drawText((const char*) workText, workBytes, count, x, y, paint);
- free(buffer);
- }
-#endif
}
static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
jint start, jint count, jint contextCount, jfloat x, jfloat y,
int flags, SkPaint* paint) {
-#if RTL_USE_HARFBUZZ
sp<TextLayoutCacheValue> value;
#if USE_TEXT_LAYOUT_CACHE
value = TextLayoutCache::getInstance().getValue(paint, text, start, count, contextCount, flags);
if (value == NULL) {
- LOGE("Cannot get TextLayoutCache value");
- return ;
+ LOGE("Cannot get TextLayoutCache value for text = '%s'",
+ String8(text + start, count).string());
+ return;
}
#else
- value = new TextLayoutCacheValue();
- value->computeValues(paint, text, start, count, contextCount, flags);
+ value = new TextLayoutCacheValue(count);
+ TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+ text, start, count, contextCount, flags);
#endif
const jchar* glyphs = value->getGlyphs();
size_t glyphsCount = value->getGlyphsCount();
int bytesCount = glyphsCount * sizeof(jchar);
renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y, paint);
-#else
- uint8_t rtl = flags & 0x1;
- if (rtl) {
- SkAutoSTMalloc<80, jchar> buffer(contextCount);
- jchar* shaped = buffer.get();
- if (TextLayout::prepareRtlTextRun(text, start, count, contextCount, shaped)) {
- renderer->drawText((const char*) shaped, count << 1, count, x, y, paint);
- } else {
- LOGW("drawTextRun error");
- }
- } else {
- renderer->drawText((const char*) (text + start), count << 1, count, x, y, paint);
- }
-#endif
}
static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
diff --git a/core/res/res/layout/global_actions_silent_mode.xml b/core/res/res/layout/global_actions_silent_mode.xml
index 09b4341..18b4715 100644
--- a/core/res/res/layout/global_actions_silent_mode.xml
+++ b/core/res/res/layout/global_actions_silent_mode.xml
@@ -26,6 +26,8 @@
android:layout_width="64dp"
android:layout_height="match_parent"
android:background="?android:attr/actionBarItemBackground"
+ android:contentDescription="@string/silent_mode_silent"
+ android:focusable="true"
>
<ImageView
android:layout_width="48dp"
@@ -52,6 +54,8 @@
android:layout_width="64dp"
android:layout_height="match_parent"
android:background="?android:attr/actionBarItemBackground"
+ android:contentDescription="@string/silent_mode_vibrate"
+ android:focusable="true"
>
<ImageView
android:layout_width="48dp"
@@ -79,6 +83,8 @@
android:layout_width="64dp"
android:layout_height="match_parent"
android:background="?android:attr/actionBarItemBackground"
+ android:contentDescription="@string/silent_mode_ring"
+ android:focusable="true"
>
<ImageView
android:layout_width="48dp"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c342c20..3ab72f4 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -750,6 +750,6 @@
<!-- Base "touch slop" value used by ViewConfiguration as a
movement threshold where scrolling should begin. -->
- <dimen name="config_viewConfigurationTouchSlop">4dp</dimen>
+ <dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7ad1d53..80aef215 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -286,6 +286,12 @@
<string name="screen_lock">Screen lock</string>
<!-- Button to turn off the phone, within the Phone Options dialog -->
<string name="power_off">Power off</string>
+ <!-- Spoken description for ringer silent option. [CHAR LIMIT=NONE] -->
+ <string name="silent_mode_silent">Ringer off</string>
+ <!-- Spoken description for ringer vibrate option. [CHAR LIMIT=NONE] -->
+ <string name="silent_mode_vibrate">Ringer vibrate</string>
+ <!-- Spoken description for ringer normal option. [CHAR LIMIT=NONE] -->
+ <string name="silent_mode_ring">Ringer on</string>
<!-- Shutdown Progress Dialog. This is shown if the user chooses to power off the phone. -->
<string name="shutdown_progress">Shutting down\u2026</string>
@@ -1986,11 +1992,11 @@
<string name="save_password_label">Confirm</string>
<!-- Toast for double-tap -->
- <string name="double_tap_toast">Tip: Double-touch to zoom in and out.</string>
+ <string name="double_tap_toast">Tip: Double-tap to zoom in and out.</string>
<!-- Text to show in the auto complete drop down list on a text view when the WebView can auto fill the entire form, and the user has configured an AutoFill profile [CHAR-LIMIT=8] -->
<string name="autofill_this_form">Autofill</string>
- <!-- Text to show in the auto complete drop down list on a text view when the WebView can auto fill the entire form but the user has not configured an AutoFill profile [CHAR-LIMIT=16] -->
+ <!-- Text to show in the auto complete drop down list on a text view when the WebView can auto fill the entire form but the user has not configured an AutoFill profile [CHAR-LIMIT=19] -->
<string name="setup_autofill">Set up Autofill</string>
<!-- String used to separate FirstName and LastName when writing out a local name
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index b18d88f..fe5388b 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -810,7 +810,7 @@
<!-- Special theme for the recent apps dialog, to allow customization
with overlays. -->
- <style name="Theme.Dialog.RecentApplications">
+ <style name="Theme.Dialog.RecentApplications" parent="Theme.DeviceDefault.Dialog">
<item name="windowFrame">@null</item>
<item name="windowBackground">@android:color/transparent</item>
<item name="android:windowAnimationStyle">@android:style/Animation.RecentApplications</item>
diff --git a/data/fonts/DroidSansArmenian.ttf b/data/fonts/DroidSansArmenian.ttf
index 62f67e0..6fafa54 100644
--- a/data/fonts/DroidSansArmenian.ttf
+++ b/data/fonts/DroidSansArmenian.ttf
Binary files differ
diff --git a/data/fonts/DroidSansGeorgian.ttf b/data/fonts/DroidSansGeorgian.ttf
index 743ae66..3a2e9fb 100644
--- a/data/fonts/DroidSansGeorgian.ttf
+++ b/data/fonts/DroidSansGeorgian.ttf
Binary files differ
diff --git a/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf b/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf
new file mode 100644
index 0000000..598a27e
--- /dev/null
+++ b/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf
Binary files differ
diff --git a/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf b/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf
new file mode 100644
index 0000000..6ef41dd
--- /dev/null
+++ b/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf
Binary files differ
diff --git a/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf b/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf
new file mode 100755
index 0000000..e56d2377
--- /dev/null
+++ b/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf
Binary files differ
diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h
index 8d07c0e..dccc164 100644
--- a/include/gui/DisplayEventReceiver.h
+++ b/include/gui/DisplayEventReceiver.h
@@ -94,6 +94,20 @@
*/
ssize_t getEvents(Event* events, size_t count);
+ /*
+ * setVsyncRate() sets the Event::VSync delivery rate. A value of
+ * 1 returns every Event::VSync. A value of 2 returns every other event,
+ * etc... a value of 0 returns no event unless requestNextVsync() has
+ * been called.
+ */
+ status_t setVsyncRate(uint32_t count);
+
+ /*
+ * requestNextVsync() schedules the next Event::VSync. It has no effect
+ * if the vsync rate is > 0.
+ */
+ status_t requestNextVsync();
+
private:
sp<IDisplayEventConnection> mEventConnection;
sp<BitTube> mDataChannel;
diff --git a/include/gui/IDisplayEventConnection.h b/include/gui/IDisplayEventConnection.h
index 8728bb5..86247de 100644
--- a/include/gui/IDisplayEventConnection.h
+++ b/include/gui/IDisplayEventConnection.h
@@ -33,9 +33,27 @@
class IDisplayEventConnection : public IInterface
{
public:
+
DECLARE_META_INTERFACE(DisplayEventConnection);
+ /*
+ * getDataChannel() returns a BitTube where to receive the events from
+ */
virtual sp<BitTube> getDataChannel() const = 0;
+
+ /*
+ * setVsyncRate() sets the vsync event delivery rate. A value of
+ * 1 returns every vsync events. A value of 2 returns every other events,
+ * etc... a value of 0 returns no event unless requestNextVsync() has
+ * been called.
+ */
+ virtual void setVsyncRate(uint32_t count) = 0;
+
+ /*
+ * requestNextVsync() schedules the next vsync event. It has no effect
+ * if the vsync rate is > 0.
+ */
+ virtual void requestNextVsync() = 0; // asynchronous
};
// ----------------------------------------------------------------------------
diff --git a/include/utils/GenerationCache.h b/include/utils/GenerationCache.h
index 83cda86..da85a9a 100644
--- a/include/utils/GenerationCache.h
+++ b/include/utils/GenerationCache.h
@@ -88,11 +88,13 @@
void attachToCache(const sp<Entry<K, V> >& entry);
void detachFromCache(const sp<Entry<K, V> >& entry);
+
+ const V mNullValue;
}; // class GenerationCache
template<typename K, typename V>
GenerationCache<K, V>::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity),
- mListener(NULL) {
+ mListener(NULL), mNullValue(NULL) {
};
template<typename K, typename V>
@@ -154,7 +156,7 @@
return entry->value;
}
- return NULL;
+ return mNullValue;
}
template<typename K, typename V>
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 3b29a11..fee1feb 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -58,6 +58,26 @@
return mDataChannel->getFd();
}
+status_t DisplayEventReceiver::setVsyncRate(uint32_t count) {
+ if (int32_t(count) < 0)
+ return BAD_VALUE;
+
+ if (mEventConnection != NULL) {
+ mEventConnection->setVsyncRate(count);
+ return NO_ERROR;
+ }
+ return NO_INIT;
+}
+
+status_t DisplayEventReceiver::requestNextVsync() {
+ if (mEventConnection != NULL) {
+ mEventConnection->requestNextVsync();
+ return NO_ERROR;
+ }
+ return NO_INIT;
+}
+
+
ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
size_t count) {
ssize_t size = mDataChannel->read(events, sizeof(events[0])*count);
diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp
index 44127fb..887d176 100644
--- a/libs/gui/IDisplayEventConnection.cpp
+++ b/libs/gui/IDisplayEventConnection.cpp
@@ -32,6 +32,8 @@
enum {
GET_DATA_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
+ SET_VSYNC_RATE,
+ REQUEST_NEXT_VSYNC
};
class BpDisplayEventConnection : public BpInterface<IDisplayEventConnection>
@@ -49,6 +51,19 @@
remote()->transact(GET_DATA_CHANNEL, data, &reply);
return new BitTube(reply);
}
+
+ virtual void setVsyncRate(uint32_t count) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
+ data.writeInt32(count);
+ remote()->transact(SET_VSYNC_RATE, data, &reply);
+ }
+
+ virtual void requestNextVsync() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
+ remote()->transact(REQUEST_NEXT_VSYNC, data, &reply, IBinder::FLAG_ONEWAY);
+ }
};
IMPLEMENT_META_INTERFACE(DisplayEventConnection, "android.gui.DisplayEventConnection");
@@ -65,6 +80,16 @@
channel->writeToParcel(reply);
return NO_ERROR;
} break;
+ case SET_VSYNC_RATE: {
+ CHECK_INTERFACE(IDisplayEventConnection, data, reply);
+ setVsyncRate(data.readInt32());
+ return NO_ERROR;
+ } break;
+ case REQUEST_NEXT_VSYNC: {
+ CHECK_INTERFACE(IDisplayEventConnection, data, reply);
+ requestNextVsync();
+ return NO_ERROR;
+ } break;
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 8d71dcf..4c70e9d 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1735,6 +1735,9 @@
/**
* Called to indicate the video size
*
+ * The video size (width and height) could be 0 if there was no video,
+ * no display surface was set, or the value was not determined yet.
+ *
* @param mp the MediaPlayer associated with this callback
* @param width the width of the video
* @param height the height of the video
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index e72adc4..6d28298 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -38,7 +38,8 @@
mFlags(0),
mState(DISCONNECTED),
mFinalResult(OK),
- mDisconnectReplyID(0) {
+ mDisconnectReplyID(0),
+ mSeekGeneration(0) {
if (headers) {
mExtraHeaders = *headers;
@@ -146,14 +147,21 @@
}
status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
+ sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id());
+ msg->setInt32("generation", ++mSeekGeneration);
+ msg->setInt64("timeUs", seekTimeUs);
+ msg->post(200000ll);
+
+ return OK;
+}
+
+void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) {
if (mState != CONNECTED) {
- return UNKNOWN_ERROR;
+ return;
}
mState = SEEKING;
mHandler->seek(seekTimeUs);
-
- return OK;
}
bool NuPlayer::RTSPSource::isSeekable() {
@@ -168,6 +176,20 @@
mDisconnectReplyID = replyID;
finishDisconnectIfPossible();
return;
+ } else if (msg->what() == kWhatPerformSeek) {
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+
+ if (generation != mSeekGeneration) {
+ // obsolete.
+ return;
+ }
+
+ int64_t seekTimeUs;
+ CHECK(msg->findInt64("timeUs", &seekTimeUs));
+
+ performSeek(seekTimeUs);
+ return;
}
CHECK_EQ(msg->what(), (int)kWhatNotify);
@@ -208,21 +230,32 @@
break;
}
- const TrackInfo &info = mTracks.editItemAt(trackIndex);
- sp<AnotherPacketSource> source = info.mSource;
+ TrackInfo *info = &mTracks.editItemAt(trackIndex);
+
+ sp<AnotherPacketSource> source = info->mSource;
if (source != NULL) {
-#if 1
uint32_t rtpTime;
CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+ if (!info->mNPTMappingValid) {
+ // This is a live stream, we didn't receive any normal
+ // playtime mapping. Assume the first packets correspond
+ // to time 0.
+
+ ALOGV("This is a live stream, assuming time = 0");
+
+ info->mRTPTime = rtpTime;
+ info->mNormalPlaytimeUs = 0ll;
+ info->mNPTMappingValid = true;
+ }
+
int64_t nptUs =
- ((double)rtpTime - (double)info.mRTPTime)
- / info.mTimeScale
+ ((double)rtpTime - (double)info->mRTPTime)
+ / info->mTimeScale
* 1000000ll
- + info.mNormalPlaytimeUs;
+ + info->mNormalPlaytimeUs;
accessUnit->meta()->setInt64("timeUs", nptUs);
-#endif
source->queueAccessUnit(accessUnit);
}
@@ -278,6 +311,7 @@
TrackInfo *info = &mTracks.editItemAt(trackIndex);
info->mRTPTime = rtpTime;
info->mNormalPlaytimeUs = nptUs;
+ info->mNPTMappingValid = true;
break;
}
@@ -305,6 +339,7 @@
info.mTimeScale = timeScale;
info.mRTPTime = 0;
info.mNormalPlaytimeUs = 0ll;
+ info.mNPTMappingValid = false;
if ((isAudio && mAudioTrack == NULL)
|| (isVideo && mVideoTrack == NULL)) {
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index 66eab72..59d06ad 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -56,6 +56,7 @@
enum {
kWhatNotify = 'noti',
kWhatDisconnect = 'disc',
+ kWhatPerformSeek = 'seek',
};
enum State {
@@ -76,6 +77,7 @@
int32_t mTimeScale;
uint32_t mRTPTime;
int64_t mNormalPlaytimeUs;
+ bool mNPTMappingValid;
};
AString mURL;
@@ -95,12 +97,16 @@
sp<AnotherPacketSource> mAudioTrack;
sp<AnotherPacketSource> mVideoTrack;
+ int32_t mSeekGeneration;
+
sp<AnotherPacketSource> getSource(bool audio);
void onConnected();
void onDisconnected(const sp<AMessage> &msg);
void finishDisconnectIfPossible();
+ void performSeek(int64_t seekTimeUs);
+
DISALLOW_EVIL_CONSTRUCTORS(RTSPSource);
};
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 759d05a..8405264 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -2021,9 +2021,9 @@
mLock.unlock();
- // Initially make sure we have at least 128 bytes for the sniff
+ // Initially make sure we have at least 192 KB for the sniff
// to complete without blocking.
- static const size_t kMinBytesForSniffing = 128;
+ static const size_t kMinBytesForSniffing = 192 * 1024;
off64_t metaDataSize = -1ll;
for (;;) {
@@ -2091,7 +2091,7 @@
String8 mimeType;
float confidence;
sp<AMessage> dummy;
- bool success = SniffDRM(dataSource, &mimeType, &confidence, &dummy);
+ bool success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
if (!success
|| strcasecmp(
@@ -2099,6 +2099,8 @@
return ERROR_UNSUPPORTED;
}
+ dataSource->DrmInitialization();
+
mWVMExtractor = new WVMExtractor(dataSource);
mWVMExtractor->setAdaptiveStreamingMode(true);
extractor = mWVMExtractor;
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index 1f3d581..afc4a80 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -282,13 +282,13 @@
if (decryptHandle != NULL) {
if (decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED) {
*mimeType = String8("drm+container_based+") + decryptHandle->mimeType;
+ *confidence = 10.0f;
} else if (decryptHandle->decryptApiType == DecryptApiType::ELEMENTARY_STREAM_BASED) {
*mimeType = String8("drm+es_based+") + decryptHandle->mimeType;
- } else if (decryptHandle->decryptApiType == DecryptApiType::WV_BASED) {
- *mimeType = MEDIA_MIMETYPE_CONTAINER_WVM;
- LOGW("SniffWVM: found match\n");
+ *confidence = 10.0f;
+ } else {
+ return false;
}
- *confidence = 10.0f;
return true;
}
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index e471f73..d0a7880 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -32,6 +32,7 @@
#include "include/DRMExtractor.h"
#include "include/FLACExtractor.h"
#include "include/AACExtractor.h"
+#include "include/WVMExtractor.h"
#include "matroska/MatroskaExtractor.h"
@@ -120,6 +121,7 @@
RegisterSniffer(SniffAAC);
RegisterSniffer(SniffAVI);
RegisterSniffer(SniffMPEG2PS);
+ RegisterSniffer(SniffWVM);
char value[PROPERTY_VALUE_MAX];
if (property_get("drm.service.enabled", value, NULL)
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index 26eda0c..79dedca 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -45,17 +45,12 @@
static Mutex gWVMutex;
WVMExtractor::WVMExtractor(const sp<DataSource> &source)
- : mDataSource(source) {
- {
- Mutex::Autolock autoLock(gWVMutex);
- if (gVendorLibHandle == NULL) {
- gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW);
- }
+ : mDataSource(source)
+{
+ Mutex::Autolock autoLock(gWVMutex);
- if (gVendorLibHandle == NULL) {
- LOGE("Failed to open libwvm.so");
- return;
- }
+ if (!getVendorLibHandle()) {
+ return;
}
typedef WVMLoadableExtractor *(*GetInstanceFunc)(sp<DataSource>);
@@ -71,6 +66,19 @@
}
}
+bool WVMExtractor::getVendorLibHandle()
+{
+ if (gVendorLibHandle == NULL) {
+ gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW);
+ }
+
+ if (gVendorLibHandle == NULL) {
+ LOGE("Failed to open libwvm.so");
+ }
+
+ return gVendorLibHandle != NULL;
+}
+
WVMExtractor::~WVMExtractor() {
}
@@ -113,5 +121,33 @@
}
}
+bool SniffWVM(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *) {
+
+ Mutex::Autolock autoLock(gWVMutex);
+
+ if (!WVMExtractor::getVendorLibHandle()) {
+ return false;
+ }
+
+ typedef WVMLoadableExtractor *(*SnifferFunc)(sp<DataSource>);
+ SnifferFunc snifferFunc =
+ (SnifferFunc) dlsym(gVendorLibHandle,
+ "_ZN7android15IsWidevineMediaENS_2spINS_10DataSourceEEE");
+
+ if (snifferFunc) {
+ if ((*snifferFunc)(source)) {
+ *mimeType = MEDIA_MIMETYPE_CONTAINER_WVM;
+ *confidence = 10.0f;
+ return true;
+ }
+ } else {
+ LOGE("IsWidevineMedia not found in libwvm.so");
+ }
+
+ return false;
+}
+
} //namespace android
diff --git a/media/libstagefright/foundation/ABitReader.cpp b/media/libstagefright/foundation/ABitReader.cpp
index f07dd4f..5499c32 100644
--- a/media/libstagefright/foundation/ABitReader.cpp
+++ b/media/libstagefright/foundation/ABitReader.cpp
@@ -79,7 +79,13 @@
}
void ABitReader::putBits(uint32_t x, size_t n) {
- CHECK_LE(mNumBitsLeft + n, 32u);
+ CHECK_LE(n, 32u);
+
+ while (mNumBitsLeft + n > 32) {
+ mNumBitsLeft -= 8;
+ --mData;
+ ++mSize;
+ }
mReservoir = (mReservoir >> n) | (x << (32 - n));
mNumBitsLeft += n;
diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
index deecd25..9f763f9 100644
--- a/media/libstagefright/include/WVMExtractor.h
+++ b/media/libstagefright/include/WVMExtractor.h
@@ -23,6 +23,8 @@
namespace android {
+struct AMessage;
+class String8;
class DataSource;
class WVMLoadableExtractor : public MediaExtractor {
@@ -58,6 +60,8 @@
// is used.
void setAdaptiveStreamingMode(bool adaptive);
+ static bool getVendorLibHandle();
+
protected:
virtual ~WVMExtractor();
@@ -69,6 +73,10 @@
WVMExtractor &operator=(const WVMExtractor &);
};
+bool SniffWVM(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *);
+
} // namespace android
#endif // DRM_EXTRACTOR_H_
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index dd049c2..21ef298 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -1100,6 +1100,8 @@
float npt1, npt2;
if (!ASessionDescription::parseNTPRange(val.c_str(), &npt1, &npt2)) {
// This is a live stream and therefore not seekable.
+
+ LOGI("This is a live stream");
return;
}
@@ -1386,12 +1388,14 @@
msg->setInt32("what", kWhatConnected);
msg->post();
- for (size_t i = 0; i < mTracks.size(); ++i) {
- TrackInfo *info = &mTracks.editItemAt(i);
+ if (mSeekable) {
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ TrackInfo *info = &mTracks.editItemAt(i);
- postNormalPlayTimeMapping(
- i,
- info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
+ postNormalPlayTimeMapping(
+ i,
+ info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
+ }
}
mFirstAccessUnit = false;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java
index 3c8d05a..e788c17 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java
@@ -353,6 +353,8 @@
AudioEffect vc = null;
MediaPlayer mp = null;
AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+ int ringerMode = am.getRingerMode();
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
am.setStreamVolume(AudioManager.STREAM_MUSIC,
am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -411,6 +413,7 @@
probe.release();
}
am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+ am.setRingerMode(ringerMode);
}
assertTrue(msg, result);
}
@@ -425,6 +428,8 @@
MediaPlayer mp = null;
AudioEffect rvb = null;
AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+ int ringerMode = am.getRingerMode();
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
am.setStreamVolume(AudioManager.STREAM_MUSIC,
am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -495,6 +500,7 @@
probe.release();
}
am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+ am.setRingerMode(ringerMode);
}
assertTrue(msg, result);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java
index 757bbc5..bc9c48d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java
@@ -198,6 +198,8 @@
AudioEffect vc = null;
MediaPlayer mp = null;
AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+ int ringerMode = am.getRingerMode();
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
am.setStreamVolume(AudioManager.STREAM_MUSIC,
am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -254,6 +256,7 @@
probe.release();
}
am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+ am.setRingerMode(ringerMode);
}
assertTrue(msg, result);
}
@@ -268,6 +271,8 @@
MediaPlayer mp = null;
AudioEffect rvb = null;
AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+ int ringerMode = am.getRingerMode();
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
am.setStreamVolume(AudioManager.STREAM_MUSIC,
am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -336,6 +341,7 @@
probe.release();
}
am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+ am.setRingerMode(ringerMode);
}
assertTrue(msg, result);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java
index e0cf51d..b0bf654 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java
@@ -200,6 +200,8 @@
AudioEffect vc = null;
MediaPlayer mp = null;
AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+ int ringerMode = am.getRingerMode();
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
am.setStreamVolume(AudioManager.STREAM_MUSIC,
am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -264,6 +266,7 @@
vc.release();
}
am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+ am.setRingerMode(ringerMode);
}
assertTrue(msg, result);
}
@@ -276,6 +279,8 @@
AudioEffect vc = null;
MediaPlayer mp = null;
AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+ int ringerMode = am.getRingerMode();
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
am.setStreamVolume(AudioManager.STREAM_MUSIC,
am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -393,6 +398,7 @@
vc.release();
}
am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+ am.setRingerMode(ringerMode);
}
assertTrue(msg, result);
}
diff --git a/nfc-extras/tests/src/com/android/nfc_extras/BasicNfcEeTest.java b/nfc-extras/tests/src/com/android/nfc_extras/tests/BasicNfcEeTest.java
similarity index 97%
rename from nfc-extras/tests/src/com/android/nfc_extras/BasicNfcEeTest.java
rename to nfc-extras/tests/src/com/android/nfc_extras/tests/BasicNfcEeTest.java
index e1025aa..389dfbe 100644
--- a/nfc-extras/tests/src/com/android/nfc_extras/BasicNfcEeTest.java
+++ b/nfc-extras/tests/src/com/android/nfc_extras/tests/BasicNfcEeTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.nfc_extras;
+package com.android.nfc_extras.tests;
import android.content.Context;
import android.nfc.NfcAdapter;
@@ -48,7 +48,7 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mContext = getInstrumentation().getContext();
+ mContext = getInstrumentation().getTargetContext();
mAdapterExtras = NfcAdapterExtras.get(NfcAdapter.getDefaultAdapter(mContext));
mEe = mAdapterExtras.getEmbeddedExecutionEnvironment();
}
diff --git a/opengl/libs/ETC1/etc1.cpp b/opengl/libs/ETC1/etc1.cpp
index 5ed2c3c..97d1085 100644
--- a/opengl/libs/ETC1/etc1.cpp
+++ b/opengl/libs/ETC1/etc1.cpp
@@ -149,13 +149,13 @@
static
inline int convert8To4(int b) {
int c = b & 0xff;
- return divideBy255(b * 15);
+ return divideBy255(c * 15);
}
static
inline int convert8To5(int b) {
int c = b & 0xff;
- return divideBy255(b * 31);
+ return divideBy255(c * 31);
}
static
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 1ebed1f..4ea2c31 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -115,6 +115,11 @@
0x200000038=0x03000701:0x03010701:0x03020701;
</string>
+ <!-- Default for Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION_URL -->
+ <string name="def_accessibility_screen_reader_url" translatable="false">
+ https://ssl.gstatic.com/accessibility/javascript/android/AndroidScriptChooser.user.js
+ </string>
+
<!-- Default for Settings.Secure.TOUCH_EXPLORATION_ENABLED -->
<bool name="def_touch_exploration_enabled">false</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 1fbe08d..a6a3303 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -63,7 +63,7 @@
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 73;
+ private static final int DATABASE_VERSION = 74;
private Context mContext;
@@ -986,6 +986,22 @@
upgradeVersion = 73;
}
+ if (upgradeVersion == 73) {
+ // URL from which WebView loads a JavaScript based screen-reader.
+ db.beginTransaction();
+ SQLiteStatement stmt = null;
+ try {
+ stmt = db.compileStatement("INSERT INTO secure(name,value) VALUES(?,?);");
+ loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
+ R.string.def_accessibility_screen_reader_url);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ if (stmt != null) stmt.close();
+ }
+ upgradeVersion = 74;
+ }
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
@@ -1526,6 +1542,9 @@
loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD,
R.bool.def_accessibility_speak_password);
+
+ loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
+ R.string.def_accessibility_screen_reader_url);
} finally {
if (stmt != null) stmt.close();
}
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml
index 6cd8899..d51f9c8 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml
@@ -15,20 +15,29 @@
* limitations under the License.
-->
-<LinearLayout
+<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="horizontal"
- android:gravity="bottom"
>
+ <View
+ android:layout_height="@*android:dimen/status_bar_height"
+ android:layout_width="match_parent"
+ android:background="@drawable/status_bar_ticker_background"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentBottom="true"
+ android:clickable="false"
+ />
+
<ImageView
android:id="@+id/large_icon"
android:layout_width="@android:dimen/notification_large_icon_height"
android:layout_height="@android:dimen/notification_large_icon_width"
android:scaleType="center"
android:visibility="gone"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentBottom="true"
/>
<FrameLayout
@@ -36,6 +45,8 @@
android:layout_weight="1"
android:layout_height="@*android:dimen/status_bar_height"
android:layout_width="match_parent"
- android:background="@drawable/status_bar_ticker_background"
+ android:layout_toRightOf="@id/large_icon"
+ android:layout_alignParentBottom="true"
+ android:layout_alignWithParentIfMissing="true"
/>
-</LinearLayout>
+</RelativeLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 490191a..9919d825 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -522,6 +522,16 @@
// don't wait for these transitions; we just want icons to fade in/out, not move around
lt.setDuration(LayoutTransition.CHANGE_APPEARING, 0);
lt.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 0);
+ lt.addTransitionListener(new LayoutTransition.TransitionListener() {
+ public void endTransition(LayoutTransition transition, ViewGroup container,
+ View view, int transitionType) {
+ // ensure the menu button doesn't stick around on the status bar after it's been
+ // removed
+ mBarContents.invalidate();
+ }
+ public void startTransition(LayoutTransition transition, ViewGroup container,
+ View view, int transitionType) {}
+ });
mNavigationArea.setLayoutTransition(lt);
// no multi-touch on the nav buttons
mNavigationArea.setMotionEventSplittingEnabled(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
index 6045e31..e93a32b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
@@ -73,6 +73,8 @@
private StatusBarNotification[] mQueue = new StatusBarNotification[QUEUE_LENGTH];
private int mQueuePos;
+ private final int mLargeIconHeight;
+
private TabletStatusBar mBar;
private LayoutTransition mLayoutTransition;
@@ -81,6 +83,9 @@
public TabletTicker(TabletStatusBar bar) {
mBar = bar;
mContext = bar.getContext();
+ final Resources res = mContext.getResources();
+ mLargeIconHeight = res.getDimensionPixelSize(
+ android.R.dimen.notification_large_icon_height);
}
public void add(IBinder key, StatusBarNotification notification) {
@@ -209,8 +214,6 @@
final Resources res = mContext.getResources();
final FrameLayout view = new FrameLayout(mContext);
final int width = res.getDimensionPixelSize(R.dimen.notification_ticker_width);
- final int height = res.getDimensionPixelSize(
- android.R.dimen.notification_large_icon_height);
int windowFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
@@ -219,7 +222,7 @@
} else {
windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
}
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, mLargeIconHeight,
WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, windowFlags,
PixelFormat.TRANSLUCENT);
lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
@@ -297,6 +300,16 @@
if (n.largeIcon != null) {
largeIcon.setImageBitmap(n.largeIcon);
largeIcon.setVisibility(View.VISIBLE);
+ final ViewGroup.LayoutParams lp = largeIcon.getLayoutParams();
+ final int statusBarHeight = mBar.getStatusBarHeight();
+ if (n.largeIcon.getHeight() <= statusBarHeight) {
+ // for smallish largeIcons, it looks a little odd to have them floating halfway up
+ // the ticker, so we vertically center them in the status bar area instead
+ lp.height = statusBarHeight;
+ } else {
+ lp.height = mLargeIconHeight;
+ }
+ largeIcon.setLayoutParams(lp);
}
if (CLICKABLE_TICKER) {
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 0e2d2a8..38c85bb 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -195,6 +195,7 @@
.setInverseBackgroundForced(true);
final AlertDialog dialog = ab.create();
+ dialog.getListView().setItemsCanFocus(true);
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
dialog.setOnDismissListener(this);
@@ -518,8 +519,6 @@
public View create(Context context, View convertView, ViewGroup parent,
LayoutInflater inflater) {
View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
- // Handle clicks outside the icons and ignore
- v.setOnClickListener(this);
int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
for (int i = 0; i < 3; i++) {
diff --git a/policy/src/com/android/internal/policy/impl/IconUtilities.java b/policy/src/com/android/internal/policy/impl/IconUtilities.java
index 4564f90..e997355 100644
--- a/policy/src/com/android/internal/policy/impl/IconUtilities.java
+++ b/policy/src/com/android/internal/policy/impl/IconUtilities.java
@@ -38,6 +38,8 @@
import android.text.TextPaint;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
import android.content.res.Resources;
import android.content.Context;
@@ -74,9 +76,13 @@
mIconTextureWidth = mIconTextureHeight = mIconWidth + (int)(blurPx*2);
mBlurPaint.setMaskFilter(new BlurMaskFilter(blurPx, BlurMaskFilter.Blur.NORMAL));
- mGlowColorPressedPaint.setColor(0xffffc300);
+
+ TypedValue value = new TypedValue();
+ mGlowColorPressedPaint.setColor(context.getTheme().resolveAttribute(
+ android.R.attr.colorPressedHighlight, value, true) ? value.data : 0xffffc300);
mGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
- mGlowColorFocusedPaint.setColor(0xffff8e00);
+ mGlowColorFocusedPaint.setColor(context.getTheme().resolveAttribute(
+ android.R.attr.colorFocusedHighlight, value, true) ? value.data : 0xffff8e00);
mGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
ColorMatrix cm = new ColorMatrix();
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 67a6855..088146b 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -52,6 +52,7 @@
import android.os.Message;
import android.os.IBinder;
import android.os.Parcelable;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -101,8 +102,8 @@
private View mLockScreen;
private View mUnlockScreen;
- private volatile boolean mScreenOn = false;
- private volatile boolean mWindowFocused = false;
+ private boolean mScreenOn;
+ private boolean mWindowFocused = false;
private boolean mEnableFallback = false; // assume no fallback UI until we know better
private boolean mShowLockBeforeUnlock = false;
@@ -311,6 +312,7 @@
mWindowController = controller;
mHasOverlay = false;
mPluggedIn = mUpdateMonitor.isDevicePluggedIn();
+ mScreenOn = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)).isScreenOn();
mUpdateMonitor.registerInfoCallback(this);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index af86ae9..535f039 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1816,22 +1816,42 @@
@Override
public boolean dispatchKeyShortcutEvent(KeyEvent ev) {
- // Perform the shortcut (mPreparedPanel can be null since
- // global shortcuts (such as search) don't rely on a
- // prepared panel or menu).
- boolean handled = performPanelShortcut(mPreparedPanel, ev.getKeyCode(), ev,
- Menu.FLAG_PERFORM_NO_CLOSE);
- if (handled) {
- if (mPreparedPanel != null) {
- mPreparedPanel.isHandled = true;
+ // If the panel is already prepared, then perform the shortcut using it.
+ boolean handled;
+ if (mPreparedPanel != null) {
+ handled = performPanelShortcut(mPreparedPanel, ev.getKeyCode(), ev,
+ Menu.FLAG_PERFORM_NO_CLOSE);
+ if (handled) {
+ if (mPreparedPanel != null) {
+ mPreparedPanel.isHandled = true;
+ }
+ return true;
}
- return true;
}
// Shortcut not handled by the panel. Dispatch to the view hierarchy.
final Callback cb = getCallback();
- return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchKeyShortcutEvent(ev)
- : super.dispatchKeyShortcutEvent(ev);
+ handled = cb != null && !isDestroyed() && mFeatureId < 0
+ ? cb.dispatchKeyShortcutEvent(ev) : super.dispatchKeyShortcutEvent(ev);
+ if (handled) {
+ return true;
+ }
+
+ // If the panel is not prepared, then we may be trying to handle a shortcut key
+ // combination such as Control+C. Temporarily prepare the panel then mark it
+ // unprepared again when finished to ensure that the panel will again be prepared
+ // the next time it is shown for real.
+ if (mPreparedPanel == null) {
+ PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
+ preparePanel(st, ev);
+ handled = performPanelShortcut(st, ev.getKeyCode(), ev,
+ Menu.FLAG_PERFORM_NO_CLOSE);
+ st.isPrepared = false;
+ if (handled) {
+ return true;
+ }
+ }
+ return false;
}
@Override
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index dfb1b07..0a5a765 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -301,9 +301,15 @@
GlobalActions mGlobalActions;
volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread
boolean mPendingPowerKeyUpCanceled;
- RecentApplicationsDialog mRecentAppsDialog;
Handler mHandler;
+ static final int RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS = 0;
+ static final int RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW = 1;
+ static final int RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH = 2;
+
+ RecentApplicationsDialog mRecentAppsDialog;
+ int mRecentAppsDialogHeldModifiers;
+
private static final int LID_ABSENT = -1;
private static final int LID_CLOSED = 0;
private static final int LID_OPEN = 1;
@@ -715,7 +721,7 @@
}
if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_DIALOG) {
- showOrHideRecentAppsDialog(0, true /*dismissIfShown*/);
+ showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS);
} else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
try {
mStatusBarService.toggleRecentApps();
@@ -726,10 +732,10 @@
}
/**
- * Create (if necessary) and launch the recent apps dialog, or hide it if it is
- * already shown.
+ * Create (if necessary) and show or dismiss the recent apps dialog according
+ * according to the requested behavior.
*/
- void showOrHideRecentAppsDialog(final int heldModifiers, final boolean dismissIfShown) {
+ void showOrHideRecentAppsDialog(final int behavior) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -737,12 +743,33 @@
mRecentAppsDialog = new RecentApplicationsDialog(mContext);
}
if (mRecentAppsDialog.isShowing()) {
- if (dismissIfShown) {
- mRecentAppsDialog.dismiss();
+ switch (behavior) {
+ case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS:
+ mRecentAppsDialog.dismiss();
+ break;
+ case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH:
+ mRecentAppsDialog.dismissAndSwitch();
+ break;
+ case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW:
+ default:
+ break;
}
} else {
- mRecentAppsDialog.setHeldModifiers(heldModifiers);
- mRecentAppsDialog.show();
+ switch (behavior) {
+ case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS:
+ mRecentAppsDialog.show();
+ break;
+ case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW:
+ try {
+ mWindowManager.setInTouchMode(false);
+ } catch (RemoteException e) {
+ }
+ mRecentAppsDialog.show();
+ break;
+ case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH:
+ default:
+ break;
+ }
}
}
});
@@ -1649,7 +1676,7 @@
return 0;
} else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
if (down && repeatCount == 0) {
- showOrHideRecentAppsDialog(0, true /*dismissIfShown*/);
+ showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS);
}
return -1;
}
@@ -1685,6 +1712,26 @@
}
}
+ // Invoke shortcuts using Meta.
+ if (down && repeatCount == 0
+ && (metaState & KeyEvent.META_META_ON) != 0) {
+ final KeyCharacterMap kcm = event.getKeyCharacterMap();
+ Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
+ metaState & ~(KeyEvent.META_META_ON
+ | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
+ if (shortcutIntent != null) {
+ shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ mContext.startActivity(shortcutIntent);
+ } catch (ActivityNotFoundException ex) {
+ Slog.w(TAG, "Dropping shortcut key combination because "
+ + "the activity to which it is registered was not found: "
+ + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
+ }
+ return -1;
+ }
+ }
+
// Handle application launch keys.
if (down && repeatCount == 0) {
String category = sApplicationLaunchKeyCategories.get(keyCode);
@@ -1698,9 +1745,29 @@
+ "the activity to which it is registered was not found: "
+ "keyCode=" + keyCode + ", category=" + category, ex);
}
+ return -1;
}
}
+ // Display task switcher for ALT-TAB or Meta-TAB.
+ if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) {
+ if (mRecentAppsDialogHeldModifiers == 0) {
+ final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
+ if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)
+ || KeyEvent.metaStateHasModifiers(
+ shiftlessModifiers, KeyEvent.META_META_ON)) {
+ mRecentAppsDialogHeldModifiers = shiftlessModifiers;
+ showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW);
+ return -1;
+ }
+ }
+ } else if (!down && mRecentAppsDialogHeldModifiers != 0
+ && (metaState & mRecentAppsDialogHeldModifiers) == 0) {
+ mRecentAppsDialogHeldModifiers = 0;
+ showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH);
+ }
+
+ // Let the application handle the key.
return 0;
}
@@ -1722,39 +1789,6 @@
final KeyCharacterMap kcm = event.getKeyCharacterMap();
final int keyCode = event.getKeyCode();
final int metaState = event.getMetaState();
- final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN
- && event.getRepeatCount() == 0;
-
- if (initialDown) {
- // Invoke shortcuts using Meta as a fallback.
- if ((metaState & KeyEvent.META_META_ON) != 0) {
- Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
- metaState & ~(KeyEvent.META_META_ON
- | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
- if (shortcutIntent != null) {
- shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- mContext.startActivity(shortcutIntent);
- } catch (ActivityNotFoundException ex) {
- Slog.w(TAG, "Dropping shortcut key combination because "
- + "the activity to which it is registered was not found: "
- + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
- }
- return null;
- }
- }
-
- // Display task switcher for ALT-TAB or Meta-TAB.
- if (keyCode == KeyEvent.KEYCODE_TAB) {
- final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
- if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)
- || KeyEvent.metaStateHasModifiers(
- shiftlessModifiers, KeyEvent.META_META_ON)) {
- showOrHideRecentAppsDialog(shiftlessModifiers, false /*dismissIfShown*/);
- return null;
- }
- }
- }
// Check for fallback actions specified by the key character map.
if (getFallbackAction(kcm, keyCode, metaState, mFallbackAction)) {
@@ -3213,10 +3247,7 @@
}
final int preferredRotation;
- if (mHdmiPlugged) {
- // Ignore sensor when plugged into HDMI.
- preferredRotation = mHdmiRotation;
- } else if (mLidOpen == LID_OPEN && mLidOpenRotation >= 0) {
+ if (mLidOpen == LID_OPEN && mLidOpenRotation >= 0) {
// Ignore sensor when lid switch is open and rotation is forced.
preferredRotation = mLidOpenRotation;
} else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR
@@ -3235,6 +3266,10 @@
// enable 180 degree rotation while docked.
preferredRotation = mDeskDockEnablesAccelerometer
? sensorRotation : mDeskDockRotation;
+ } else if (mHdmiPlugged) {
+ // Ignore sensor when plugged into HDMI.
+ // Note that the dock orientation overrides the HDMI orientation.
+ preferredRotation = mHdmiRotation;
} else if ((mAccelerometerDefault != 0 /* implies not rotation locked */
&& (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
|| orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED))
@@ -3477,6 +3512,9 @@
WindowManager.LayoutParams.FLAG_DIM_BEHIND
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
mBootMsgDialog.getWindow().setDimAmount(1);
+ WindowManager.LayoutParams lp = mBootMsgDialog.getWindow().getAttributes();
+ lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+ mBootMsgDialog.getWindow().setAttributes(lp);
mBootMsgDialog.setCancelable(false);
mBootMsgDialog.show();
}
diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
index aa00fbdd..b9903dd 100644
--- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
+++ b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
@@ -71,8 +71,6 @@
}
};
- private int mHeldModifiers;
-
public RecentApplicationsDialog(Context context) {
super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications);
@@ -124,17 +122,6 @@
}
}
- /**
- * Sets the modifier keys that are being held to keep the dialog open, or 0 if none.
- * Used to make the recent apps dialog automatically dismiss itself when the modifiers
- * all go up.
- * @param heldModifiers The held key modifiers, such as {@link KeyEvent#META_ALT_ON}.
- * Should exclude shift.
- */
- public void setHeldModifiers(int heldModifiers) {
- mHeldModifiers = heldModifiers;
- }
-
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_TAB) {
@@ -174,30 +161,27 @@
return super.onKeyDown(keyCode, event);
}
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (mHeldModifiers != 0 && (event.getModifiers() & mHeldModifiers) == 0) {
- final int numIcons = mIcons.length;
- RecentTag tag = null;
- for (int i = 0; i < numIcons; i++) {
- if (mIcons[i].getVisibility() != View.VISIBLE) {
+ /**
+ * Dismiss the dialog and switch to the selected application.
+ */
+ public void dismissAndSwitch() {
+ final int numIcons = mIcons.length;
+ RecentTag tag = null;
+ for (int i = 0; i < numIcons; i++) {
+ if (mIcons[i].getVisibility() != View.VISIBLE) {
+ break;
+ }
+ if (i == 0 || mIcons[i].hasFocus()) {
+ tag = (RecentTag) mIcons[i].getTag();
+ if (mIcons[i].hasFocus()) {
break;
}
- if (i == 0 || mIcons[i].hasFocus()) {
- tag = (RecentTag) mIcons[i].getTag();
- if (mIcons[i].hasFocus()) {
- break;
- }
- }
}
- if (tag != null) {
- switchTo(tag);
- }
- dismiss();
- return true;
}
-
- return super.onKeyUp(keyCode, event);
+ if (tag != null) {
+ switchTo(tag);
+ }
+ dismiss();
}
/**
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 382f4d9..5f31f05 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -4312,12 +4312,23 @@
mKeyMementos.removeAt(index);
return true;
}
+ /* FIXME: We can't just drop the key up event because that prevents creating
+ * popup windows that are automatically shown when a key is held and then
+ * dismissed when the key is released. The problem is that the popup will
+ * not have received the original key down, so the key up will be considered
+ * to be inconsistent with its observed state. We could perhaps handle this
+ * by synthesizing a key down but that will cause other problems.
+ *
+ * So for now, allow inconsistent key up events to be dispatched.
+ *
#if DEBUG_OUTBOUND_EVENT_DETAILS
LOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, "
"keyCode=%d, scanCode=%d",
entry->deviceId, entry->source, entry->keyCode, entry->scanCode);
#endif
return false;
+ */
+ return true;
}
case AKEY_EVENT_ACTION_DOWN: {
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 2af5103..4f81178 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -24,9 +24,9 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.Intent.FilterComparison;
import android.content.IntentFilter;
import android.content.ServiceConnection;
-import android.content.Intent.FilterComparison;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -39,6 +39,8 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -74,6 +76,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
+import java.util.Set;
class AppWidgetService extends IAppWidgetService.Stub
{
@@ -805,6 +808,45 @@
id.host.callbacks = null;
}
}
+
+ // If the host is unavailable, then we call the associated
+ // RemoteViewsFactory.onDataSetChanged() directly
+ if (id.host.callbacks == null) {
+ Set<FilterComparison> keys = mRemoteViewsServicesAppWidgets.keySet();
+ for (FilterComparison key : keys) {
+ if (mRemoteViewsServicesAppWidgets.get(key).contains(id.appWidgetId)) {
+ Intent intent = key.getIntent();
+
+ final ServiceConnection conn = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ IRemoteViewsFactory cb =
+ IRemoteViewsFactory.Stub.asInterface(service);
+ try {
+ cb.onDataSetChangedAsync();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ } catch (RuntimeException e) {
+ e.printStackTrace();
+ }
+ mContext.unbindService(this);
+ }
+ @Override
+ public void onServiceDisconnected(android.content.ComponentName name) {
+ // Do nothing
+ }
+ };
+
+ // Bind to the service and call onDataSetChanged()
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+ }
}
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 3c65255..cb291ce 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -840,7 +840,7 @@
* of WifiLock & device idle status unless wifi enabled status is toggled
*/
- mWifiStateMachine.setDriverStart(true);
+ mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode);
mWifiStateMachine.reconnectCommand();
}
@@ -854,7 +854,7 @@
* TODO: if a stop is issued, wifi is brought up only by startWifi
* unless wifi enabled status is toggled
*/
- mWifiStateMachine.setDriverStart(false);
+ mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode);
}
@@ -1074,12 +1074,11 @@
mWifiStateMachine.setWifiEnabled(true);
mWifiStateMachine.setScanOnlyMode(
strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
- mWifiStateMachine.setDriverStart(true);
+ mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode);
mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode
== WifiManager.WIFI_MODE_FULL_HIGH_PERF);
} else {
- mWifiStateMachine.requestCmWakeLock();
- mWifiStateMachine.setDriverStart(false);
+ mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode);
}
} else {
mWifiStateMachine.setWifiEnabled(false);
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index b5edc0a..6c11953 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1932,8 +1932,9 @@
// should be left as-is.
replyChainEnd = -1;
}
-
- } else if (target.resultTo != null) {
+
+ } else if (target.resultTo != null && (below == null
+ || below.task == target.task)) {
// If this activity is sending a reply to a previous
// activity, we can't do anything with it now until
// we reach the start of the reply chain.
@@ -1963,6 +1964,8 @@
replyChainEnd = targetI;
}
ActivityRecord p = null;
+ if (DEBUG_TASKS) Slog.v(TAG, "Finishing task at index "
+ + targetI + " to " + replyChainEnd);
for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
p = mHistory.get(srcPos);
if (p.finishing) {
@@ -1981,6 +1984,8 @@
if (replyChainEnd < 0) {
replyChainEnd = targetI;
}
+ if (DEBUG_TASKS) Slog.v(TAG, "Reparenting task at index "
+ + targetI + " to " + replyChainEnd);
for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
ActivityRecord p = mHistory.get(srcPos);
if (p.finishing) {
@@ -2002,6 +2007,7 @@
p.setTask(task, null, false);
mHistory.add(lastReparentPos, p);
if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
+ + " from " + srcPos + " to " + lastReparentPos
+ " in to resetting task " + task);
mService.mWindowManager.moveAppToken(lastReparentPos, p.appToken);
mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId);
@@ -2031,6 +2037,11 @@
}
}
}
+
+ } else if (below != null && below.task != target.task) {
+ // We hit the botton of a task; the reply chain can't
+ // pass through it.
+ replyChainEnd = -1;
}
target = below;
diff --git a/services/java/com/android/server/location/ComprehensiveCountryDetector.java b/services/java/com/android/server/location/ComprehensiveCountryDetector.java
index bb9e60f..f068b44 100755
--- a/services/java/com/android/server/location/ComprehensiveCountryDetector.java
+++ b/services/java/com/android/server/location/ComprehensiveCountryDetector.java
@@ -66,26 +66,12 @@
protected CountryDetectorBase mLocationBasedCountryDetector;
protected Timer mLocationRefreshTimer;
- private final int mPhoneType;
private Country mCountry;
- private TelephonyManager mTelephonyManager;
+ private final TelephonyManager mTelephonyManager;
private Country mCountryFromLocation;
private boolean mStopped = false;
- private ServiceState mLastState;
- private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
- @Override
- public void onServiceStateChanged(ServiceState serviceState) {
- // TODO: Find out how often we will be notified, if this method is called too
- // many times, let's consider querying the network.
- Slog.d(TAG, "onServiceStateChanged");
- // We only care the state change
- if (mLastState == null || mLastState.getState() != serviceState.getState()) {
- detectCountry(true, true);
- mLastState = new ServiceState(serviceState);
- }
- }
- };
+ private PhoneStateListener mPhoneStateListener;
/**
* The listener for receiving the notification from LocationBasedCountryDetector.
@@ -104,7 +90,6 @@
public ComprehensiveCountryDetector(Context context) {
super(context);
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- mPhoneType = mTelephonyManager.getPhoneType();
}
@Override
@@ -115,6 +100,7 @@
@Override
public void stop() {
+ // Note: this method in this subclass called only by tests.
Slog.i(TAG, "Stop the detector.");
cancelLocationRefresh();
removePhoneStateListener();
@@ -141,14 +127,20 @@
return result;
}
+ private boolean isNetworkCountryCodeAvailable() {
+ // On CDMA TelephonyManager.getNetworkCountryIso() just returns SIM country. We don't want
+ // to prioritize it over location based country, so ignore it.
+ final int phoneType = mTelephonyManager.getPhoneType();
+ if (DEBUG) Slog.v(TAG, " phonetype=" + phoneType);
+ return phoneType == TelephonyManager.PHONE_TYPE_GSM;
+ }
+
/**
* @return the country from the mobile network.
*/
protected Country getNetworkBasedCountry() {
String countryIso = null;
- // TODO: The document says the result may be unreliable on CDMA networks. Shall we use
- // it on CDMA phone? We may test the Android primarily used countries.
- if (mPhoneType == TelephonyManager.PHONE_TYPE_GSM) {
+ if (isNetworkCountryCodeAvailable()) {
countryIso = mTelephonyManager.getNetworkCountryIso();
if (!TextUtils.isEmpty(countryIso)) {
return new Country(countryIso, Country.COUNTRY_SOURCE_NETWORK);
@@ -356,20 +348,16 @@
}
protected synchronized void addPhoneStateListener() {
- if (mPhoneStateListener == null && mPhoneType == TelephonyManager.PHONE_TYPE_GSM) {
- mLastState = null;
+ if (mPhoneStateListener == null) {
mPhoneStateListener = new PhoneStateListener() {
@Override
public void onServiceStateChanged(ServiceState serviceState) {
- // TODO: Find out how often we will be notified, if this
- // method is called too
- // many times, let's consider querying the network.
- Slog.d(TAG, "onServiceStateChanged");
- // We only care the state change
- if (mLastState == null || mLastState.getState() != serviceState.getState()) {
- detectCountry(true, true);
- mLastState = new ServiceState(serviceState);
+ if (!isNetworkCountryCodeAvailable()) {
+ return;
}
+ if (DEBUG) Slog.d(TAG, "onServiceStateChanged: " + serviceState.getState());
+
+ detectCountry(true, true);
}
};
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
diff --git a/services/surfaceflinger/DisplayEventConnection.cpp b/services/surfaceflinger/DisplayEventConnection.cpp
index a0aa9c0..77ecbd2 100644
--- a/services/surfaceflinger/DisplayEventConnection.cpp
+++ b/services/surfaceflinger/DisplayEventConnection.cpp
@@ -25,6 +25,7 @@
#include "SurfaceFlinger.h"
#include "DisplayEventConnection.h"
+#include "EventThread.h"
// ---------------------------------------------------------------------------
@@ -33,30 +34,38 @@
// ---------------------------------------------------------------------------
DisplayEventConnection::DisplayEventConnection(
- const sp<SurfaceFlinger>& flinger)
- : mFlinger(flinger), mChannel(new BitTube())
+ const sp<EventThread>& eventThread)
+ : mEventThread(eventThread), mChannel(new BitTube())
{
}
DisplayEventConnection::~DisplayEventConnection() {
- mFlinger->cleanupDisplayEventConnection(this);
+ mEventThread->unregisterDisplayEventConnection(this);
}
void DisplayEventConnection::onFirstRef() {
- // nothing to do here for now.
+ // NOTE: mEventThread doesn't hold a strong reference on us
+ mEventThread->registerDisplayEventConnection(this);
}
sp<BitTube> DisplayEventConnection::getDataChannel() const {
return mChannel;
}
+void DisplayEventConnection::setVsyncRate(uint32_t count) {
+ mEventThread->setVsyncRate(count, this);
+}
+
+void DisplayEventConnection::requestNextVsync() {
+ mEventThread->requestNextVsync(this);
+}
+
status_t DisplayEventConnection::postEvent(const DisplayEventReceiver::Event& event)
{
ssize_t size = mChannel->write(&event, sizeof(DisplayEventReceiver::Event));
return size < 0 ? status_t(size) : status_t(NO_ERROR);
}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/DisplayEventConnection.h b/services/surfaceflinger/DisplayEventConnection.h
index 46cf64b..cc3ee36 100644
--- a/services/surfaceflinger/DisplayEventConnection.h
+++ b/services/surfaceflinger/DisplayEventConnection.h
@@ -32,13 +32,13 @@
// ---------------------------------------------------------------------------
class BitTube;
-class SurfaceFlinger;
+class EventThread;
// ---------------------------------------------------------------------------
class DisplayEventConnection : public BnDisplayEventConnection {
public:
- DisplayEventConnection(const sp<SurfaceFlinger>& flinger);
+ DisplayEventConnection(const sp<EventThread>& flinger);
status_t postEvent(const DisplayEventReceiver::Event& event);
@@ -46,8 +46,10 @@
virtual ~DisplayEventConnection();
virtual void onFirstRef();
virtual sp<BitTube> getDataChannel() const;
+ virtual void setVsyncRate(uint32_t count);
+ virtual void requestNextVsync(); // asynchronous
- sp<SurfaceFlinger> const mFlinger;
+ sp<EventThread> const mEventThread;
sp<BitTube> const mChannel;
};
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 42477a9..dc39f88 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -47,7 +47,8 @@
status_t EventThread::registerDisplayEventConnection(
const sp<DisplayEventConnection>& connection) {
Mutex::Autolock _l(mLock);
- mDisplayEventConnections.add(connection);
+ ConnectionInfo info;
+ mDisplayEventConnections.add(connection, info);
mCondition.signal();
return NO_ERROR;
}
@@ -55,44 +56,97 @@
status_t EventThread::unregisterDisplayEventConnection(
const wp<DisplayEventConnection>& connection) {
Mutex::Autolock _l(mLock);
- mDisplayEventConnections.remove(connection);
+ mDisplayEventConnections.removeItem(connection);
mCondition.signal();
return NO_ERROR;
}
-status_t EventThread::removeDisplayEventConnection(
+void EventThread::removeDisplayEventConnection(
const wp<DisplayEventConnection>& connection) {
Mutex::Autolock _l(mLock);
- mDisplayEventConnections.remove(connection);
- return NO_ERROR;
+ mDisplayEventConnections.removeItem(connection);
+}
+
+EventThread::ConnectionInfo* EventThread::getConnectionInfoLocked(
+ const wp<DisplayEventConnection>& connection) {
+ ssize_t index = mDisplayEventConnections.indexOfKey(connection);
+ if (index < 0) return NULL;
+ return &mDisplayEventConnections.editValueAt(index);
+}
+
+void EventThread::setVsyncRate(uint32_t count,
+ const wp<DisplayEventConnection>& connection) {
+ if (int32_t(count) >= 0) { // server must protect against bad params
+ Mutex::Autolock _l(mLock);
+ ConnectionInfo* info = getConnectionInfoLocked(connection);
+ if (info) {
+ info->count = (count == 0) ? -1 : count;
+ mCondition.signal();
+ }
+ }
+}
+
+void EventThread::requestNextVsync(
+ const wp<DisplayEventConnection>& connection) {
+ Mutex::Autolock _l(mLock);
+ ConnectionInfo* info = getConnectionInfoLocked(connection);
+ if (info) {
+ if (info->count < 0) {
+ info->count = 0;
+ }
+ mCondition.signal();
+ }
}
bool EventThread::threadLoop() {
nsecs_t timestamp;
DisplayEventReceiver::Event vsync;
- SortedVector<wp<DisplayEventConnection> > displayEventConnections;
+ KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > displayEventConnections;
{ // scope for the lock
Mutex::Autolock _l(mLock);
do {
// wait for listeners
- while (!mDisplayEventConnections.size()) {
+ do {
+ bool waitForNextVsync = false;
+ size_t count = mDisplayEventConnections.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const ConnectionInfo& info(
+ mDisplayEventConnections.valueAt(i));
+ if (info.count >= 1) {
+ // continuous mode
+ waitForNextVsync = true;
+ } else {
+ // one-shot event
+ if (info.count >= -1) {
+ ConnectionInfo& info(
+ mDisplayEventConnections.editValueAt(i));
+ info.count--;
+ if (info.count == -1) {
+ // fired this time around
+ waitForNextVsync = true;
+ }
+ }
+ }
+ }
+
+ if (waitForNextVsync)
+ break;
+
mCondition.wait(mLock);
- }
+ } while(true);
// wait for vsync
mLock.unlock();
timestamp = mHw.waitForVSync();
mLock.lock();
+ mDeliveredEvents++;
// make sure we still have some listeners
} while (!mDisplayEventConnections.size());
-
// dispatch vsync events to listeners...
- mDeliveredEvents++;
-
vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
vsync.header.timestamp = timestamp;
vsync.vsync.count = mDeliveredEvents;
@@ -104,9 +158,30 @@
const size_t count = displayEventConnections.size();
for (size_t i=0 ; i<count ; i++) {
- sp<DisplayEventConnection> conn(displayEventConnections.itemAt(i).promote());
+ sp<DisplayEventConnection> conn(displayEventConnections.keyAt(i).promote());
// make sure the connection didn't die
if (conn != NULL) {
+
+ const ConnectionInfo& info(
+ displayEventConnections.valueAt(i));
+
+ if ((info.count > 1) && (mDeliveredEvents % info.count)) {
+ // continuous event, but not time to send this event yet
+ continue;
+ } else if (info.count < -1) {
+ // disabled event
+ continue;
+ } else if (info.count == 0) {
+ // impossible by construction. but we prefer to be safe.
+ continue;
+ }
+
+ // here, either:
+ // count = -1 : one-shot scheduled this time around
+ // count = 1 : continuous not rate-limited
+ // count > 1 : continuous, rate-limited
+ // Note: count == 0 is not possible by construction
+
status_t err = conn->postEvent(vsync);
if (err == -EAGAIN || err == -EWOULDBLOCK) {
// The destination doesn't accept events anymore, it's probably
@@ -118,12 +193,12 @@
// handle any other error on the pipe as fatal. the only
// reasonable thing to do is to clean-up this connection.
// The most common error we'll get here is -EPIPE.
- removeDisplayEventConnection(displayEventConnections.itemAt(i));
+ removeDisplayEventConnection(displayEventConnections.keyAt(i));
}
} else {
// somehow the connection is dead, but we still have it in our list
// just clean the list.
- removeDisplayEventConnection(displayEventConnections.itemAt(i));
+ removeDisplayEventConnection(displayEventConnections.keyAt(i));
}
}
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 4872c2b..35bd299 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -24,7 +24,7 @@
#include <utils/Errors.h>
#include <utils/threads.h>
-#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
#include "DisplayEventConnection.h"
@@ -51,6 +51,11 @@
status_t unregisterDisplayEventConnection(
const wp<DisplayEventConnection>& connection);
+ void setVsyncRate(uint32_t count,
+ const wp<DisplayEventConnection>& connection);
+
+ void requestNextVsync(const wp<DisplayEventConnection>& connection);
+
void dump(String8& result, char* buffer, size_t SIZE) const;
private:
@@ -58,7 +63,20 @@
virtual status_t readyToRun();
virtual void onFirstRef();
- status_t removeDisplayEventConnection(
+ struct ConnectionInfo {
+ ConnectionInfo() : count(-1) { }
+
+ // count >= 1 : continuous event. count is the vsync rate
+ // count == 0 : one-shot event that has not fired
+ // count ==-1 : one-shot event that fired this round / disabled
+ // count ==-2 : one-shot event that fired the round before
+ int32_t count;
+ };
+
+ void removeDisplayEventConnection(
+ const wp<DisplayEventConnection>& connection);
+
+ ConnectionInfo* getConnectionInfoLocked(
const wp<DisplayEventConnection>& connection);
// constants
@@ -69,7 +87,9 @@
mutable Condition mCondition;
// protected by mLock
- SortedVector<wp<DisplayEventConnection> > mDisplayEventConnections;
+ KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > mDisplayEventConnections;
+
+ // main thread only
size_t mDeliveredEvents;
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 58196d8..014c7e2 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -389,16 +389,10 @@
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
- sp<DisplayEventConnection> result(new DisplayEventConnection(this));
- mEventThread->registerDisplayEventConnection(result);
+ sp<DisplayEventConnection> result(new DisplayEventConnection(mEventThread));
return result;
}
-void SurfaceFlinger::cleanupDisplayEventConnection(
- const wp<DisplayEventConnection>& connection) {
- mEventThread->unregisterDisplayEventConnection(connection);
-}
-
// ----------------------------------------------------------------------------
#if 0
#pragma mark -
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e6d2cd9..41caee3 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -335,9 +335,6 @@
status_t electronBeamOffAnimationImplLocked();
status_t electronBeamOnAnimationImplLocked();
- void cleanupDisplayEventConnection(
- const wp<DisplayEventConnection>& connection);
-
void debugFlashRegions();
void debugShowFPS() const;
void drawWormhole() const;
diff --git a/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java b/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
index 60677df..5f5d668 100755
--- a/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
@@ -213,7 +213,7 @@
// QueryThread should be set to NULL
assertNull(detector.getQueryThread());
assertTrue(countryListener.notified());
- assertEquals(countryListener.getCountry(), country);
+ assertEquals("us", countryListener.getCountry().toLowerCase());
}
public void testFindingCountryCancelled() {
@@ -238,7 +238,7 @@
// QueryThread should be set to NULL
assertNull(detector.getQueryThread());
assertTrue(countryListener.notified());
- assertEquals(countryListener.getCountry(), country);
+ assertEquals("us", countryListener.getCountry().toLowerCase());
}
public void testFindingLocationCancelled() {
@@ -339,7 +339,7 @@
assertNull(detector.getQueryThread());
// CountryListener should be notified
assertTrue(countryListener.notified());
- assertEquals(countryListener.getCountry(), country);
+ assertEquals("us", countryListener.getCountry().toLowerCase());
}
private void waitForTimerReset(TestCountryDetector detector) {
diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java
index f111dd6..07b6183 100644
--- a/telephony/java/com/android/internal/telephony/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/BaseCommands.java
@@ -683,6 +683,13 @@
mRilConnectedRegistrants.remove(h);
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setCurrentPreferredNetworkType() {
+ }
+
//***** Protected Methods
/**
* Store new RadioState and send notification based on the changes
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index 33ead75..d6e6ae0 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -1311,6 +1311,12 @@
void queryAvailableBandMode (Message response);
/**
+ * Set the current preferred network type. This will be the last
+ * networkType that was passed to setPreferredNetworkType.
+ */
+ void setCurrentPreferredNetworkType();
+
+ /**
* Requests to set the preferred network type for searching and registering
* (CS/PS domain, RAT, and operation mode)
* @param networkType one of NT_*_TYPE
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 9f93fb8..f2e7f45 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1823,6 +1823,16 @@
/**
* {@inheritDoc}
*/
+ @Override
+ public void setCurrentPreferredNetworkType() {
+ if (RILJ_LOGD) riljLog("setCurrentPreferredNetworkType: " + mSetPreferredNetworkType);
+ setPreferredNetworkType(mSetPreferredNetworkType, null);
+ }
+ private int mSetPreferredNetworkType;
+
+ /**
+ * {@inheritDoc}
+ */
public void setPreferredNetworkType(int networkType , Message response) {
RILRequest rr = RILRequest.obtain(
RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, response);
@@ -1830,6 +1840,7 @@
rr.mp.writeInt(1);
rr.mp.writeInt(networkType);
+ mSetPreferredNetworkType = networkType;
mPreferredNetworkType = networkType;
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 3d6cd68..d939e98 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -257,6 +257,9 @@
break;
case EVENT_RUIM_READY:
+ // TODO: Consider calling setCurrentPreferredNetworkType as we do in GsmSST.
+ // cm.setCurrentPreferredNetworkType();
+
// The RUIM is now ready i.e if it was locked it has been
// unlocked. At this stage, the radio is already powered on.
isSubscriptionFromRuim = true;
@@ -277,6 +280,9 @@
break;
case EVENT_NV_READY:
+ // TODO: Consider calling setCurrentPreferredNetworkType as we do in GsmSST.
+ // cm.setCurrentPreferredNetworkType();
+
isSubscriptionFromRuim = false;
// For Non-RUIM phones, the subscription information is stored in
// Non Volatile. Here when Non-Volatile is ready, we can poll the CDMA
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 11f1623..963db2c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -914,10 +914,16 @@
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)),
+ NetworkUtils.trimV4AddrZeros(
+ cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))),
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)),
+ NetworkUtils.trimV4AddrZeros(
+ cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
+ NetworkUtils.trimV4AddrZeros(
+ cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))),
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)),
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index 3799894..16d3129 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -132,7 +132,7 @@
// See TS 22.030 6.5.2 "Structure of the MMI"
static Pattern sPatternSuppService = Pattern.compile(
- "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)");
+ "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)([^#]*)");
/* 1 2 3 4 5 6 7 8 9 10 11 12
1 = Full string up to and including #
@@ -141,7 +141,7 @@
5 = SIA
7 = SIB
9 = SIC
- 10 = dialing number
+ 10 = dialing number which must not include #, e.g. *SCn*SI#DN format
*/
static final int MATCH_GROUP_POUND_STRING = 1;
@@ -1338,4 +1338,20 @@
* SpecialCharSequenceMgr class.
*/
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("GsmMmiCode {");
+
+ sb.append("State=" + getState());
+ if (action != null) sb.append(" action=" + action);
+ if (sc != null) sb.append(" sc=" + sc);
+ if (sia != null) sb.append(" sia=" + sia);
+ if (sib != null) sb.append(" sib=" + sib);
+ if (sic != null) sb.append(" sic=" + sic);
+ if (poundString != null) sb.append(" poundString=" + poundString);
+ if (dialingNumber != null) sb.append(" dialingNumber=" + dialingNumber);
+ if (pwd != null) sb.append(" pwd=" + pwd);
+ sb.append("}");
+ return sb.toString();
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index eea2780..84127cf 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -270,6 +270,9 @@
break;
case EVENT_SIM_READY:
+ // Set the network type, in case the radio does not restore it.
+ cm.setCurrentPreferredNetworkType();
+
// The SIM is now ready i.e if it was locked
// it has been unlocked. At this stage, the radio is already
// powered on.
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
index 06b4af7..ba70c71 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
@@ -62,6 +62,9 @@
mTests[index].testName = Allocation.createFromString(mRS,
mNames[index],
Allocation.USAGE_SCRIPT);
+ mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+ mNames[index],
+ Allocation.USAGE_SCRIPT);
ScriptField_FillTestData_s.Item dataItem = new ScriptField_FillTestData_s.Item();
dataItem.testId = testId;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java
index f39e7db..cdb4435 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java
@@ -69,6 +69,9 @@
mTests[index].testName = Allocation.createFromString(mRS,
mNames[index],
Allocation.USAGE_SCRIPT);
+ mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+ mNames[index],
+ Allocation.USAGE_SCRIPT);
ScriptField_MeshTestData_s.Item dataItem = new ScriptField_MeshTestData_s.Item();
dataItem.meshNum = meshNum;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
index 4ed42b4..0dceafe 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
@@ -95,8 +95,10 @@
switch (item.getItemId()) {
case R.id.benchmark_all:
mView.setBenchmarkMode(-1);
+ mView.suspendRendering(false);
return true;
case R.id.benchmark_one:
+ mView.suspendRendering(true);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Pick a Test");
builder.setItems(mView.getTestNames(),
@@ -106,11 +108,13 @@
"Starting to benchmark: " + mView.getTestNames()[item],
Toast.LENGTH_SHORT).show();
mView.setBenchmarkMode(item);
+ mView.suspendRendering(false);
}
});
builder.show();
return true;
case R.id.debug_mode:
+ mView.suspendRendering(true);
AlertDialog.Builder debugBuilder = new AlertDialog.Builder(this);
debugBuilder.setTitle("Pick a Test");
debugBuilder.setItems(mView.getTestNames(),
@@ -120,6 +124,7 @@
"Switching to: " + mView.getTestNames()[item],
Toast.LENGTH_SHORT).show();
mView.setDebugMode(item);
+ mView.suspendRendering(false);
}
});
debugBuilder.show();
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
index c51bd82..4ac7dd5 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
@@ -60,7 +60,6 @@
mWidth = width;
mHeight = height;
mMode = 0;
- mMaxModes = 0;
mLoops = loops;
mCurrentLoop = 0;
mBenchmarkDimX = 1280;
@@ -88,11 +87,30 @@
ScriptField_TestScripts_s.Item[] mIndividualTests;
int mMode;
- int mMaxModes;
String[] mTestNames;
float[] mLocalTestResults;
+ static Allocation createZeroTerminatedAlloc(RenderScript rs,
+ String str,
+ int usage) {
+ byte[] allocArray = null;
+ try {
+ allocArray = str.getBytes("UTF-8");
+ byte[] allocArrayZero = new byte[allocArray.length + 1];
+ System.arraycopy(allocArray, 0, allocArrayZero, 0, allocArray.length);
+ allocArrayZero[allocArrayZero.length - 1] = '\0';
+ Allocation alloc = Allocation.createSized(rs, Element.U8(rs),
+ allocArrayZero.length, usage);
+ alloc.copyFrom(allocArrayZero);
+ return alloc;
+ }
+ catch (Exception e) {
+ throw new RSRuntimeException("Could not convert string to utf-8.");
+ }
+
+ }
+
void appendTests(RsBenchBaseTest testSet) {
ScriptField_TestScripts_s.Item[] newTests = testSet.getTests();
if (mIndividualTests != null) {
@@ -119,6 +137,7 @@
void createTestAllocation() {
int numTests = mIndividualTests.length;
+ mLocalTestResults = new float[numTests];
ScriptField_TestScripts_s allTests;
allTests = new ScriptField_TestScripts_s(mRS, numTests);
for (int i = 0; i < numTests; i ++) {
@@ -239,11 +258,6 @@
return count;
}
- private void prepareTestData() {
- mTestNames = new String[mMaxModes];
- mLocalTestResults = new float[mMaxModes];
- }
-
public void setDebugMode(int num) {
mScript.invoke_setDebugMode(num);
}
@@ -252,6 +266,10 @@
mScript.invoke_setBenchmarkMode(benchNum);
}
+ public void pause(boolean pause) {
+ mScript.set_gPauseRendering(pause);
+ }
+
private void initRS() {
mScript = new ScriptC_rsbench(mRS, mRes, R.raw.rsbench);
@@ -261,8 +279,6 @@
mScript.set_gMaxLoops(mLoops);
- prepareTestData();
-
initProgramVertex();
initProgramFragment();
mScript.set_gFontSerif(Font.create(mRS, mRes, "serif", Font.Style.NORMAL, 8));
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
index 004e6bf..124071e 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
@@ -92,6 +92,10 @@
mRender.setBenchmarkMode(benchNum);
}
+ void suspendRendering(boolean pause) {
+ mRender.pause(pause);
+ }
+
void setDebugMode(int num) {
mRender.setDebugMode(num);
}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java
index ca9e660..3ca2792 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java
@@ -48,6 +48,9 @@
mTests[index].testName = Allocation.createFromString(mRS,
mNames[index],
Allocation.USAGE_SCRIPT);
+ mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+ mNames[index],
+ Allocation.USAGE_SCRIPT);
ScriptField_TextTestData_s.Item dataItem = new ScriptField_TextTestData_s.Item();
dataItem.fillNum = fillNum;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java
index d785dc1..5c9ecd5 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java
@@ -98,6 +98,9 @@
mTests[index].testName = Allocation.createFromString(mRS,
mNames[index],
Allocation.USAGE_SCRIPT);
+ mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+ mNames[index],
+ Allocation.USAGE_SCRIPT);
ScriptField_TorusTestData_s.Item dataItem = new ScriptField_TorusTestData_s.Item();
dataItem.testId = testId;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java
index cca237e..c8b58b2 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java
@@ -82,6 +82,9 @@
mTests[index].testName = Allocation.createFromString(mRS,
mNames[index],
Allocation.USAGE_SCRIPT);
+ mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+ mNames[index],
+ Allocation.USAGE_SCRIPT);
ScriptField_UiTestData_s.Item dataItem = new ScriptField_UiTestData_s.Item();
dataItem.testId = testId;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
index 2b849a2..27e5b11 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
@@ -45,11 +45,13 @@
typedef struct TestScripts_s {
rs_allocation testData;
rs_allocation testName;
+ rs_allocation debugName;
rs_script testScript;
} TestScripts;
TestScripts *gTestScripts;
bool gLoadComplete = false;
+bool gPauseRendering = false;
static float gDt = 0;
@@ -195,7 +197,8 @@
int64_t end = rsUptimeMillis();
float fps = (float)(frameCount) / ((float)(end - start)*0.001f);
- rsDebug("Finishes test ", fps);
+ const char *testName = rsGetElementAt(gTestScripts[benchMode].debugName, 0);
+ rsDebug(testName, fps);
gResultBuffer[benchMode] = fps;
int bufferW = rsAllocationGetDimX(gRenderBufferColor);
@@ -255,6 +258,10 @@
return 1;
}
+ if (gPauseRendering) {
+ rsgDrawText("Paused", 50, 50);
+ return 30;
+ }
if (gIsDebugMode) {
debug();
} else {
diff --git a/tests/StatusBar/res/layout/notification_builder_test.xml b/tests/StatusBar/res/layout/notification_builder_test.xml
index e1199c7..6c384f7 100644
--- a/tests/StatusBar/res/layout/notification_builder_test.xml
+++ b/tests/StatusBar/res/layout/notification_builder_test.xml
@@ -605,6 +605,11 @@
style="@style/FieldContents"
android:text="pineapple2"
/>
+ <RadioButton
+ android:id="@+id/large_icon_small"
+ style="@style/FieldContents"
+ android:text="small"
+ />
</RadioGroup>
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
index 5a2ebac..fefd890 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
@@ -287,6 +287,9 @@
case R.id.large_icon_pineapple2:
b.setLargeIcon(loadBitmap(R.drawable.pineapple2));
break;
+ case R.id.large_icon_small:
+ b.setLargeIcon(loadBitmap(R.drawable.icon2));
+ break;
}
// sound TODO
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 637c27d..d7ac15e 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -625,6 +625,11 @@
bool actImeService = false;
bool actWallpaperService = false;
+ // These two implement the implicit permissions that are granted
+ // to pre-1.6 applications.
+ bool hasWriteExternalStoragePermission = false;
+ bool hasReadPhoneStatePermission = false;
+
// This next group of variables is used to implement a group of
// backward-compatibility heuristics necessitated by the addition of
// some new uses-feature constants in 2.1 and 2.2. In most cases, the
@@ -986,6 +991,10 @@
name == "android.permission.WRITE_APN_SETTINGS" ||
name == "android.permission.WRITE_SMS") {
hasTelephonyPermission = true;
+ } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
+ hasWriteExternalStoragePermission = true;
+ } else if (name == "android.permission.READ_PHONE_STATE") {
+ hasReadPhoneStatePermission = true;
}
printf("uses-permission:'%s'\n", name.string());
} else {
@@ -1144,6 +1153,16 @@
}
}
+ // Pre-1.6 implicitly granted permission compatibility logic
+ if (targetSdk < 4) {
+ if (!hasWriteExternalStoragePermission) {
+ printf("uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'\n");
+ }
+ if (!hasReadPhoneStatePermission) {
+ printf("uses-permission:'android.permission.READ_PHONE_STATE'\n");
+ }
+ }
+
/* The following blocks handle printing "inferred" uses-features, based
* on whether related features or permissions are used by the app.
* Note that the various spec*Feature variables denote whether the
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index d5b404e..7bb927b 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -70,7 +70,6 @@
private InetAddress mIpAddress;
private String mMacAddress;
- private boolean mExplicitConnect;
WifiInfo() {
mSSID = null;
@@ -80,7 +79,6 @@
mRssi = -9999;
mLinkSpeed = -1;
mHiddenSSID = false;
- mExplicitConnect = false;
}
/**
@@ -98,7 +96,6 @@
mLinkSpeed = source.mLinkSpeed;
mIpAddress = source.mIpAddress;
mMacAddress = source.mMacAddress;
- mExplicitConnect = source.mExplicitConnect;
}
}
@@ -175,22 +172,6 @@
mNetworkId = id;
}
-
- /**
- * @hide
- */
- public boolean isExplicitConnect() {
- return mExplicitConnect;
- }
-
- /**
- * @hide
- */
- public void setExplicitConnect(boolean explicitConnect) {
- this.mExplicitConnect = explicitConnect;
- }
-
-
/**
* Each configured network has a unique small integer ID, used to identify
* the network when performing operations on the supplicant. This method
@@ -279,8 +260,7 @@
append(mSupplicantState == null ? none : mSupplicantState).
append(", RSSI: ").append(mRssi).
append(", Link speed: ").append(mLinkSpeed).
- append(", Net ID: ").append(mNetworkId).
- append(", Explicit connect: ").append(mExplicitConnect);
+ append(", Net ID: ").append(mNetworkId);
return sb.toString();
}
@@ -304,7 +284,6 @@
dest.writeString(getSSID());
dest.writeString(mBSSID);
dest.writeString(mMacAddress);
- dest.writeByte(mExplicitConnect ? (byte)1 : (byte)0);
mSupplicantState.writeToParcel(dest, flags);
}
@@ -324,7 +303,6 @@
info.setSSID(in.readString());
info.mBSSID = in.readString();
info.mMacAddress = in.readString();
- info.mExplicitConnect = in.readByte() == 1 ? true : false;
info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
return info;
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 40ac2a0..1a0e0da 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -413,6 +413,13 @@
private static final int MAX_RSSI = -55;
/**
+ * Number of RSSI levels used in the framework to initiate
+ * {@link #RSSI_CHANGED_ACTION} broadcast
+ * @hide
+ */
+ public static final int RSSI_LEVELS = 5;
+
+ /**
* Auto settings in the driver. The driver could choose to operate on both
* 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
* @hide
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 253e0ec..5437caa 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -306,8 +306,6 @@
static final int CMD_SET_HIGH_PERF_MODE = BASE + 77;
/* Set the country code */
static final int CMD_SET_COUNTRY_CODE = BASE + 80;
- /* Request connectivity manager wake lock before driver stop */
- static final int CMD_REQUEST_CM_WAKELOCK = BASE + 81;
/* Enables RSSI poll */
static final int CMD_ENABLE_RSSI_POLL = BASE + 82;
/* RSSI poll */
@@ -370,6 +368,10 @@
private static final int SUCCESS = 1;
private static final int FAILURE = -1;
+ /* Phone in emergency call back mode */
+ private static final int IN_ECM_STATE = 1;
+ private static final int NOT_IN_ECM_STATE = 0;
+
/**
* The maximum number of times we will retry a connection to an access point
* for which we have failed in acquiring an IP address from DHCP. A value of
@@ -535,11 +537,6 @@
private final WorkSource mLastRunningWifiUids = new WorkSource();
private final IBatteryStats mBatteryStats;
- private boolean mNextWifiActionExplicit = false;
- private int mLastExplicitNetworkId;
- private long mLastNetworkChoiceTime;
- private static final long EXPLICIT_CONNECT_ALLOWED_DELAY_MS = 2 * 60 * 1000;
-
public WifiStateMachine(Context context, String wlanInterface) {
super(TAG);
@@ -780,11 +777,11 @@
/**
* TODO: doc
*/
- public void setDriverStart(boolean enable) {
+ public void setDriverStart(boolean enable, boolean ecm) {
if (enable) {
sendMessage(CMD_START_DRIVER);
} else {
- sendMessage(CMD_STOP_DRIVER);
+ sendMessage(obtainMessage(CMD_STOP_DRIVER, ecm ? IN_ECM_STATE : NOT_IN_ECM_STATE, 0));
}
}
@@ -1061,15 +1058,6 @@
return result;
}
- /**
- * Request a wakelock with connectivity service to
- * keep the device awake until we hand-off from wifi
- * to an alternate network
- */
- public void requestCmWakeLock() {
- sendMessage(CMD_REQUEST_CM_WAKELOCK);
- }
-
public void updateBatteryWorkSource(WorkSource newSource) {
synchronized (mRunningWifiUids) {
try {
@@ -1469,14 +1457,11 @@
* be displayed in the status bar, and only send the
* broadcast if that much more coarse-grained number
* changes. This cuts down greatly on the number of
- * broadcasts, at the cost of not mWifiInforming others
+ * broadcasts, at the cost of not informing others
* interested in RSSI of all the changes in signal
* level.
*/
- // TODO: The second arg to the call below needs to be a symbol somewhere, but
- // it's actually the size of an array of icons that's private
- // to StatusBar Policy.
- int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4);
+ int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS);
if (newSignalLevel != mLastSignalLevel) {
sendRssiChangeBroadcast(newRssi);
}
@@ -1651,7 +1636,6 @@
mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
mWifiInfo.setRssi(MIN_RSSI);
mWifiInfo.setLinkSpeed(-1);
- mWifiInfo.setExplicitConnect(false);
/* send event to CM & network change broadcast */
setNetworkDetailedState(DetailedState.DISCONNECTED);
@@ -1867,7 +1851,6 @@
case CMD_SET_HIGH_PERF_MODE:
case CMD_SET_COUNTRY_CODE:
case CMD_SET_FREQUENCY_BAND:
- case CMD_REQUEST_CM_WAKELOCK:
case CMD_CONNECT_NETWORK:
case CMD_SAVE_NETWORK:
case CMD_FORGET_NETWORK:
@@ -2588,16 +2571,25 @@
WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive);
break;
case CMD_STOP_DRIVER:
- /* Already doing a delayed stop */
- if (mInDelayedStop) {
+ int mode = message.arg1;
+
+ /* Already doing a delayed stop && not in ecm state */
+ if (mInDelayedStop && mode != IN_ECM_STATE) {
if (DBG) log("Already in delayed stop");
break;
}
mInDelayedStop = true;
mDelayedStopCounter++;
if (DBG) log("Delayed stop message " + mDelayedStopCounter);
- sendMessageDelayed(obtainMessage(CMD_DELAYED_STOP_DRIVER, mDelayedStopCounter,
- 0), DELAYED_DRIVER_STOP_MS);
+
+ if (mode == IN_ECM_STATE) {
+ /* send a shut down immediately */
+ sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, mDelayedStopCounter, 0));
+ } else {
+ /* send regular delayed shut down */
+ sendMessageDelayed(obtainMessage(CMD_DELAYED_STOP_DRIVER,
+ mDelayedStopCounter, 0), DELAYED_DRIVER_STOP_MS);
+ }
break;
case CMD_START_DRIVER:
if (mInDelayedStop) {
@@ -2836,10 +2828,6 @@
mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK);
WifiNative.reconnectCommand();
- mLastExplicitNetworkId = netId;
- mLastNetworkChoiceTime = SystemClock.elapsedRealtime();
- mNextWifiActionExplicit = true;
- if (DBG) log("Setting wifi connect explicit for netid " + netId);
/* Expect a disconnection from the old connection */
transitionTo(mDisconnectingState);
break;
@@ -2861,13 +2849,6 @@
mWifiInfo.setSSID(fetchSSID());
mWifiInfo.setBSSID(mLastBssid);
mWifiInfo.setNetworkId(mLastNetworkId);
- if (mNextWifiActionExplicit &&
- mWifiInfo.getNetworkId() == mLastExplicitNetworkId &&
- SystemClock.elapsedRealtime() < mLastNetworkChoiceTime +
- EXPLICIT_CONNECT_ALLOWED_DELAY_MS) {
- mWifiInfo.setExplicitConnect(true);
- }
- mNextWifiActionExplicit = false;
/* send event to CM & network change broadcast */
setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
sendNetworkStateChangeBroadcast(mLastBssid);
@@ -3024,10 +3005,6 @@
WifiNative.disconnectCommand();
transitionTo(mDisconnectingState);
break;
- case CMD_REQUEST_CM_WAKELOCK:
- checkAndSetConnectivityInstance();
- mCm.requestNetworkTransitionWakelock(TAG);
- break;
case CMD_SET_SCAN_MODE:
if (message.arg1 == SCAN_ONLY_MODE) {
sendMessage(CMD_DISCONNECT);
@@ -3100,6 +3077,11 @@
}
@Override
public void exit() {
+
+ /* Request a CS wakelock during transition to mobile */
+ checkAndSetConnectivityInstance();
+ mCm.requestNetworkTransitionWakelock(TAG);
+
/* If a scan result is pending in connected state, the supplicant
* is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit
*/
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index b27c60f..0ca3852 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -1030,7 +1030,7 @@
mHasConnectedWifiManager = true;
}
mWifiManager.disableNetwork(networkId, WifiConfiguration.DISABLED_DNS_FAILURE);
- if (mShowDisabledNotification && mConnectionInfo.isExplicitConnect()) {
+ if (mShowDisabledNotification) {
setDisabledNetworkNotificationVisible(true);
}
transitionTo(mNotConnectedState);