Merge "Fix: Retrieval of location to caclulate twilight"
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index bf9b021..ebc64d7 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -19,23 +19,25 @@
import static android.app.SuggestionsAdapter.getColumnString;
+import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Browser;
import android.speech.RecognizerIntent;
@@ -43,11 +45,8 @@
import android.text.InputType;
import android.text.TextUtils;
import android.text.TextWatcher;
-import android.util.AndroidRuntimeException;
import android.util.AttributeSet;
import android.util.Log;
-import android.util.Patterns;
-import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -69,10 +68,6 @@
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
-import java.util.ArrayList;
-import java.util.WeakHashMap;
-import java.util.concurrent.atomic.AtomicLong;
-
/**
* Search dialog. This is controlled by the
* SearchManager and runs in the current foreground process.
@@ -154,6 +149,16 @@
mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mSearchManager = searchManager;
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+ context.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
+ onConfigurationChanged();
+ }
+ }
+ }, filter);
}
/**
@@ -394,10 +399,18 @@
updateSearchAppIcon();
updateSearchBadge();
updateQueryHint();
+ if (isLandscapeMode(getContext())) {
+ mSearchAutoComplete.ensureImeVisible(true);
+ }
mSearchAutoComplete.showDropDownAfterLayout();
- }
+ }
}
-
+
+ static boolean isLandscapeMode(Context context) {
+ return context.getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_LANDSCAPE;
+ }
+
/**
* Update the UI according to the info in the current value of {@link #mSearchable}.
*/
@@ -983,7 +996,7 @@
mSearchAutoComplete.setSelection(selPoint);
mSearchAutoComplete.setListSelection(0);
mSearchAutoComplete.clearListSelection();
- mSearchAutoComplete.ensureImeVisible();
+ mSearchAutoComplete.ensureImeVisible(true);
return true;
}
@@ -1362,6 +1375,11 @@
InputMethodManager inputManager = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.showSoftInput(this, 0);
+ // If in landscape mode, then make sure that
+ // the ime is in front of the dropdown.
+ if (isLandscapeMode(getContext())) {
+ ensureImeVisible(true);
+ }
}
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 825ea46..390550f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2301,15 +2301,18 @@
scrollBar.draw(canvas);
}
+ private boolean canOverscrollHorizontally() {
+ return (Math.abs(mMinZoomScale - mMaxZoomScale) >= MINIMUM_SCALE_INCREMENT)
+ && getSettings().supportZoom()
+ && getSettings().getUseWideViewPort();
+ }
+
@Override
protected void onOverscrolled(int scrollX, int scrollY, boolean clampedX,
boolean clampedY) {
mInOverScrollMode = false;
int maxX = computeMaxScrollX();
- if (maxX == 0 && (Math.abs(mMinZoomScale - mMaxZoomScale)
- < MINIMUM_SCALE_INCREMENT)
- || !getSettings().supportZoom()
- || !getSettings().getUseWideViewPort()) {
+ if (maxX == 0 && !canOverscrollHorizontally()) {
// do not over scroll x if the page just fits the screen and it
// can't zoom or the view doesn't use wide viewport
scrollX = pinLocX(scrollX);
@@ -3115,6 +3118,14 @@
return;
}
+ // if both mContentWidth and mContentHeight are 0, it means there is no
+ // valid Picture passed to WebView yet. This can happen when WebView
+ // just starts. Draw the background and return.
+ if ((mContentWidth | mContentHeight) == 0 && mHistoryPicture == null) {
+ canvas.drawColor(mBackgroundColor);
+ return;
+ }
+
int saveCount = canvas.save();
if (mInOverScrollMode
&& getSettings().getUseSystemOverscrollBackground()) {
@@ -4207,7 +4218,7 @@
// Textfields and plugins need to receive the shift up key even if
// another key was released while the shift key was held down.
- if (!inEditingMode() && !nativeFocusIsPlugin()) {
+ if (!inEditingMode() && (mNativeClass == 0 || !nativeFocusIsPlugin())) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
mGotKeyDown = true;
} else {
@@ -5112,8 +5123,10 @@
if (ev.getY() < 0) pageUp(true);
return true;
}
+ boolean shiftPressed = mShiftIsPressed && (mNativeClass == 0
+ || !nativeFocusIsPlugin());
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- if (mShiftIsPressed && !nativeFocusIsPlugin()) {
+ if (shiftPressed) {
return true; // discard press if copy in progress
}
mTrackballDown = true;
@@ -5138,7 +5151,7 @@
mPrivateHandler.removeMessages(LONG_PRESS_CENTER);
mTrackballDown = false;
mTrackballUpTime = time;
- if (mShiftIsPressed && !nativeFocusIsPlugin()) {
+ if (shiftPressed) {
if (mExtendSelection) {
commitCopy();
} else {
@@ -5276,7 +5289,7 @@
float yRate = mTrackballRemainsY * 1000 / elapsed;
int viewWidth = getViewWidth();
int viewHeight = getViewHeight();
- if (mShiftIsPressed && !nativeFocusIsPlugin()) {
+ if (mShiftIsPressed && (mNativeClass == 0 || !nativeFocusIsPlugin())) {
moveSelection(scaleTrackballX(xRate, viewWidth),
scaleTrackballY(yRate, viewHeight));
mTrackballRemainsX = mTrackballRemainsY = 0;
@@ -5314,7 +5327,7 @@
+ " mTrackballRemainsX=" + mTrackballRemainsX
+ " mTrackballRemainsY=" + mTrackballRemainsY);
}
- if (nativeFocusIsPlugin()) {
+ if (mNativeClass != 0 && nativeFocusIsPlugin()) {
for (int i = 0; i < count; i++) {
letPluginHandleNavKey(selectKeyCode, time, true);
}
@@ -5381,7 +5394,9 @@
vx = 0;
}
}
-
+ if (maxX == 0 && !canOverscrollHorizontally()) {
+ vx = 0;
+ }
if (true /* EMG release: make our fling more like Maps' */) {
// maps cuts their velocity in half
vx = vx * 3 / 4;
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index ed63787..65f7cdb 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -17,9 +17,11 @@
package android.widget;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable.Orientation;
import android.text.Editable;
import android.text.Selection;
import android.text.TextUtils;
@@ -210,10 +212,10 @@
* Private hook into the on click event, dispatched from {@link PassThroughClickListener}
*/
private void onClickImpl() {
- // If the dropdown is showing, bring it back in front of the soft
- // keyboard when the user touches the text field.
- if (mPopup.isShowing() && isInputMethodNotNeeded()) {
- ensureImeVisible();
+ // If the dropdown is showing, bring the keyboard to the front
+ // when the user touches the text field.
+ if (mPopup.isShowing()) {
+ ensureImeVisible(true);
}
}
@@ -1114,11 +1116,13 @@
/**
* Ensures that the drop down is not obscuring the IME.
- *
+ * @param visible whether the ime should be in front. If false, the ime is pushed to
+ * the background.
* @hide internal used only here and SearchDialog
*/
- public void ensureImeVisible() {
- mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
+ public void ensureImeVisible(boolean visible) {
+ mPopup.setInputMethodMode(visible
+ ? PopupWindow.INPUT_METHOD_NEEDED : PopupWindow.INPUT_METHOD_NOT_NEEDED);
showDropDown();
}
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 999b27d..ee2fc12 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.internal.widget;
import android.content.Context;
diff --git a/core/java/com/google/android/util/AbstractMessageParser.java b/core/java/com/google/android/util/AbstractMessageParser.java
index 25f6b33..1871682 100644
--- a/core/java/com/google/android/util/AbstractMessageParser.java
+++ b/core/java/com/google/android/util/AbstractMessageParser.java
@@ -1,5 +1,18 @@
-// Copyright 2007 The Android Open Source Project
-// All Rights Reserved.
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.google.android.util;
diff --git a/include/media/stagefright/HTTPDataSource.h b/include/media/stagefright/HTTPDataSource.h
index 23522bd..b6176eb 100644
--- a/include/media/stagefright/HTTPDataSource.h
+++ b/include/media/stagefright/HTTPDataSource.h
@@ -20,6 +20,7 @@
#include <media/stagefright/DataSource.h>
#include <utils/String8.h>
+#include <utils/threads.h>
namespace android {
@@ -35,6 +36,9 @@
const char *uri,
const KeyedVector<String8, String8> *headers = NULL);
+ status_t connect();
+ void disconnect();
+
virtual status_t initCheck() const;
virtual ssize_t readAt(off_t offset, void *data, size_t size);
@@ -53,8 +57,21 @@
kBufferSize = 32 * 1024
};
+ enum State {
+ DISCONNECTED,
+ CONNECTING,
+ CONNECTED
+ };
+
+ State mState;
+ mutable Mutex mStateLock;
+
String8 mHeaders;
+ String8 mStartingHost;
+ String8 mStartingPath;
+ int mStartingPort;
+
HTTPStream *mHttp;
char *mHost;
int mPort;
@@ -67,11 +84,7 @@
bool mContentLengthValid;
unsigned long long mContentLength;
- status_t mInitCheck;
-
- void init(
- const char *_host, int port, const char *_path,
- const KeyedVector<String8, String8> *headers);
+ void init(const KeyedVector<String8, String8> *headers);
ssize_t sendRangeRequest(size_t offset);
void initHeaders(const KeyedVector<String8, String8> *overrides);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index e00ba470..10b7be34 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -26,6 +26,7 @@
#include <binder/IPCThreadState.h>
#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/CachingDataSource.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBuffer.h>
@@ -318,6 +319,14 @@
}
void AwesomePlayer::reset_l() {
+ if (mFlags & PREPARING) {
+ mFlags |= PREPARE_CANCELLED;
+ if (mConnectingDataSource != NULL) {
+ LOGI("interrupting the connection process");
+ mConnectingDataSource->disconnect();
+ }
+ }
+
while (mFlags & PREPARING) {
mPreparedCondition.wait(mLock);
}
@@ -337,6 +346,12 @@
// If we did this later, audio would continue playing while we
// shutdown the video-related resources and the player appear to
// not be as responsive to a reset request.
+ if (mAudioPlayer == NULL && mAudioSource != NULL) {
+ // If we had an audio player, it would have effectively
+ // taken possession of the audio source and stopped it when
+ // _it_ is stopped. Otherwise this is still our responsibility.
+ mAudioSource->stop();
+ }
mAudioSource.clear();
if (mTimeSource != mAudioPlayer) {
@@ -1039,8 +1054,29 @@
}
status_t AwesomePlayer::finishSetDataSource_l() {
- sp<DataSource> dataSource =
- DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
+ sp<DataSource> dataSource;
+
+ if (!strncasecmp("http://", mUri.string(), 7)) {
+ mConnectingDataSource = new HTTPDataSource(mUri, &mUriHeaders);
+
+ mLock.unlock();
+ status_t err = mConnectingDataSource->connect();
+ mLock.lock();
+
+ if (err != OK) {
+ mConnectingDataSource.clear();
+
+ LOGI("mConnectingDataSource->connect() returned %d", err);
+ return err;
+ }
+
+ dataSource = new CachingDataSource(
+ mConnectingDataSource, 32 * 1024, 20);
+
+ mConnectingDataSource.clear();
+ } else {
+ dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
+ }
if (dataSource == NULL) {
return UNKNOWN_ERROR;
@@ -1067,7 +1103,7 @@
}
mPrepareResult = err;
- mFlags &= ~PREPARING;
+ mFlags &= ~(PREPARING|PREPARE_CANCELLED);
mAsyncPrepareEvent = NULL;
mPreparedCondition.broadcast();
}
@@ -1078,6 +1114,12 @@
{
Mutex::Autolock autoLock(mLock);
+ if (mFlags & PREPARE_CANCELLED) {
+ LOGI("prepare was cancelled before doing anything");
+ abortPrepare(UNKNOWN_ERROR);
+ return;
+ }
+
if (mUri.size() > 0) {
status_t err = finishSetDataSource_l();
@@ -1109,7 +1151,19 @@
}
if (prefetcher != NULL) {
+ {
+ Mutex::Autolock autoLock(mLock);
+ if (mFlags & PREPARE_CANCELLED) {
+ LOGI("prepare was cancelled before preparing the prefetcher");
+ abortPrepare(UNKNOWN_ERROR);
+ return;
+ }
+ }
+
+ LOGI("calling prefetcher->prepare()");
prefetcher->prepare();
+ LOGV("prefetcher is done preparing");
+
prefetcher.clear();
}
@@ -1126,20 +1180,28 @@
}
mPrepareResult = OK;
- mFlags &= ~PREPARING;
+ mFlags &= ~(PREPARING|PREPARE_CANCELLED);
mFlags |= PREPARED;
mAsyncPrepareEvent = NULL;
mPreparedCondition.broadcast();
}
status_t AwesomePlayer::suspend() {
- LOGI("suspend");
+ LOGV("suspend");
Mutex::Autolock autoLock(mLock);
if (mSuspensionState != NULL) {
return INVALID_OPERATION;
}
+ if (mFlags & PREPARING) {
+ mFlags |= PREPARE_CANCELLED;
+ if (mConnectingDataSource != NULL) {
+ LOGI("interrupting the connection process");
+ mConnectingDataSource->disconnect();
+ }
+ }
+
while (mFlags & PREPARING) {
mPreparedCondition.wait(mLock);
}
@@ -1180,7 +1242,7 @@
}
status_t AwesomePlayer::resume() {
- LOGI("resume");
+ LOGV("resume");
Mutex::Autolock autoLock(mLock);
if (mSuspensionState == NULL) {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 8468a07..284e3bc 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -101,8 +101,11 @@
if (!strncasecmp("file://", uri, 7)) {
source = new FileSource(uri + 7);
} else if (!strncasecmp("http://", uri, 7)) {
- source = new HTTPDataSource(uri, headers);
- source = new CachingDataSource(source, 32 * 1024, 20);
+ sp<HTTPDataSource> httpSource = new HTTPDataSource(uri, headers);
+ if (httpSource->connect() != OK) {
+ return NULL;
+ }
+ source = new CachingDataSource(httpSource, 32 * 1024, 20);
} else {
// Assume it's a filename.
source = new FileSource(uri);
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
index d79c1bd..451fc26 100644
--- a/media/libstagefright/HTTPDataSource.cpp
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -126,41 +126,71 @@
host = string(host, 0, colon - host.c_str());
}
- init(host.c_str(), port, path.c_str(), headers);
+ mStartingHost = host.c_str();
+ mStartingPath = path.c_str();
+ mStartingPort = port;
+
+ init(headers);
}
HTTPDataSource::HTTPDataSource(
const char *_host, int port, const char *_path,
const KeyedVector<String8, String8> *headers) {
- init(_host, port, _path, headers);
+ mStartingHost = _host;
+ mStartingPath = _path;
+ mStartingPort = port;
+
+ init(headers);
}
-void HTTPDataSource::init(
- const char *_host, int port, const char *_path,
- const KeyedVector<String8, String8> *headers) {
+void HTTPDataSource::init(const KeyedVector<String8, String8> *headers) {
+ mState = DISCONNECTED;
mHttp = new HTTPStream;
+
mHost = NULL;
mPort = 0;
- mPath = NULL,
- mBuffer = malloc(kBufferSize);
- mBufferLength = 0;
- mBufferOffset = 0;
- mContentLengthValid = false;
+ mPath = NULL;
initHeaders(headers);
- string host = _host;
- string path = _path;
+ mBuffer = malloc(kBufferSize);
+ mBufferLength = 0;
+ mBufferOffset = 0;
+}
+
+status_t HTTPDataSource::connect() {
+ {
+ Mutex::Autolock autoLock(mStateLock);
+
+ if (mState != DISCONNECTED) {
+ return ERROR_ALREADY_CONNECTED;
+ }
+
+ mState = CONNECTING;
+ }
+
+ mContentLengthValid = false;
+
+ string host = mStartingHost.string();
+ string path = mStartingPath.string();
+ int port = mStartingPort;
LOGI("Connecting to host '%s', port %d, path '%s'",
host.c_str(), port, path.c_str());
int numRedirectsRemaining = 5;
do {
- mInitCheck = mHttp->connect(host.c_str(), port);
+ status_t err = mHttp->connect(host.c_str(), port);
- if (mInitCheck != OK) {
- return;
+ if (err != OK) {
+ Mutex::Autolock autoLock(mStateLock);
+
+ if (mState != CONNECTING) {
+ LOGV("connect() cancelled");
+ }
+ mState = DISCONNECTED;
+
+ return err;
}
} while (PerformRedirectIfNecessary(mHttp, mHeaders, &host, &path, &port)
&& numRedirectsRemaining-- > 0);
@@ -175,17 +205,44 @@
mHost = strdup(host.c_str());
mPort = port;
mPath = strdup(path.c_str());
+
+ Mutex::Autolock autoLock(mStateLock);
+
+ if (mState != CONNECTING) {
+ // disconnect was called when we had just successfully connected.
+ LOGV("connect() cancelled (we had just succeeded connecting)");
+
+ mHttp->disconnect();
+ return UNKNOWN_ERROR;
+ }
+
+ mState = CONNECTED;
+ return OK;
+}
+
+void HTTPDataSource::disconnect() {
+ Mutex::Autolock autoLock(mStateLock);
+
+ if (mState == CONNECTING || mState == CONNECTED) {
+ mHttp->disconnect();
+ mState = DISCONNECTED;
+ }
}
status_t HTTPDataSource::initCheck() const {
- return mInitCheck;
+ Mutex::Autolock autoLock(mStateLock);
+
+ return (mState == CONNECTED) ? (status_t)OK : ERROR_NOT_CONNECTED;
}
status_t HTTPDataSource::getSize(off_t *size) {
*size = 0;
- if (mInitCheck != OK) {
- return mInitCheck;
+ {
+ Mutex::Autolock autoLock(mStateLock);
+ if (mState != CONNECTED) {
+ return ERROR_NOT_CONNECTED;
+ }
}
if (!mContentLengthValid) {
@@ -198,7 +255,10 @@
}
HTTPDataSource::~HTTPDataSource() {
- mHttp->disconnect();
+ disconnect();
+
+ delete mHttp;
+ mHttp = NULL;
free(mBuffer);
mBuffer = NULL;
@@ -212,9 +272,6 @@
free(mHost);
mHost = NULL;
}
-
- delete mHttp;
- mHttp = NULL;
}
ssize_t HTTPDataSource::sendRangeRequest(size_t offset) {
@@ -271,6 +328,13 @@
ssize_t HTTPDataSource::readAt(off_t offset, void *data, size_t size) {
LOGV("readAt %ld, size %d", offset, size);
+ {
+ Mutex::Autolock autoLock(mStateLock);
+ if (mState != CONNECTED) {
+ return ERROR_NOT_CONNECTED;
+ }
+ }
+
if (offset >= mBufferOffset
&& offset < (off_t)(mBufferOffset + mBufferLength)) {
size_t num_bytes_available = mBufferLength - (offset - mBufferOffset);
@@ -304,7 +368,7 @@
mBufferOffset = offset;
if (mContentLengthValid
- && mBufferOffset + contentLength >= mContentLength) {
+ && mBufferOffset + contentLength >= (off_t)mContentLength) {
// If we never triggered a range request but know the content length,
// make sure to not read more data than there could be, otherwise
// we'd block indefinitely if the server doesn't close the connection.
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index 2c5da68..66eadf6 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -44,12 +44,19 @@
}
status_t HTTPStream::connect(const char *server, int port) {
+ Mutex::Autolock autoLock(mLock);
+
status_t err = OK;
if (mState == CONNECTED) {
return ERROR_ALREADY_CONNECTED;
}
+ struct hostent *ent = gethostbyname(server);
+ if (ent == NULL) {
+ return ERROR_UNKNOWN_HOST;
+ }
+
CHECK_EQ(mSocket, -1);
mSocket = socket(AF_INET, SOCK_STREAM, 0);
@@ -57,11 +64,11 @@
return UNKNOWN_ERROR;
}
- struct hostent *ent = gethostbyname(server);
- if (ent == NULL) {
- err = ERROR_UNKNOWN_HOST;
- goto exit1;
- }
+ mState = CONNECTING;
+
+ int s = mSocket;
+
+ mLock.unlock();
struct sockaddr_in addr;
addr.sin_family = AF_INET;
@@ -69,24 +76,31 @@
addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
- if (::connect(mSocket, (const struct sockaddr *)&addr, sizeof(addr)) < 0) {
- err = ERROR_CANNOT_CONNECT;
- goto exit1;
+ int res = ::connect(s, (const struct sockaddr *)&addr, sizeof(addr));
+
+ mLock.lock();
+
+ if (mState != CONNECTING) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (res < 0) {
+ close(mSocket);
+ mSocket = -1;
+
+ mState = READY;
+ return UNKNOWN_ERROR;
}
mState = CONNECTED;
return OK;
-
-exit1:
- close(mSocket);
- mSocket = -1;
-
- return err;
}
status_t HTTPStream::disconnect() {
- if (mState != CONNECTED) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mState != CONNECTED && mState != CONNECTING) {
return ERROR_NOT_CONNECTED;
}
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index c0cf97c..4679207 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -23,7 +23,6 @@
#include <media/stagefright/ColorConverter.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/FileSource.h>
-#include <media/stagefright/HTTPDataSource.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 7106524..32c28c1 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -22,6 +22,7 @@
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/DataSource.h>
+#include <media/stagefright/HTTPDataSource.h>
#include <media/stagefright/OMXClient.h>
#include <utils/threads.h>
@@ -87,12 +88,13 @@
friend struct AwesomeEvent;
enum Flags {
- PLAYING = 1,
- LOOPING = 2,
- FIRST_FRAME = 4,
- PREPARING = 8,
- PREPARED = 16,
- AT_EOS = 32,
+ PLAYING = 1,
+ LOOPING = 2,
+ FIRST_FRAME = 4,
+ PREPARING = 8,
+ PREPARED = 16,
+ AT_EOS = 32,
+ PREPARE_CANCELLED = 64,
};
mutable Mutex mLock;
@@ -160,6 +162,7 @@
MediaBuffer *mVideoBuffer;
sp<Prefetcher> mPrefetcher;
+ sp<HTTPDataSource> mConnectingDataSource;
struct SuspensionState {
String8 mUri;
diff --git a/media/libstagefright/include/HTTPStream.h b/media/libstagefright/include/HTTPStream.h
index 43ef614..5d638f3 100644
--- a/media/libstagefright/include/HTTPStream.h
+++ b/media/libstagefright/include/HTTPStream.h
@@ -24,6 +24,7 @@
#include <media/stagefright/MediaErrors.h>
#include <utils/KeyedVector.h>
+#include <utils/threads.h>
namespace android {
@@ -54,10 +55,12 @@
private:
enum State {
READY,
+ CONNECTING,
CONNECTED
};
State mState;
+ Mutex mLock;
int mSocket;
KeyedVector<string, string> mHeaders;
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index fc6bfcd..d72416d 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -2205,32 +2205,28 @@
if (mHandler == null || !ActivityManagerNative.isSystemReady()) {
throw new IllegalStateException("Too early to call reboot()");
}
-
+
final String finalReason = reason;
Runnable runnable = new Runnable() {
public void run() {
synchronized (this) {
ShutdownThread.reboot(mContext, finalReason, false);
- // if we get here we failed
- notify();
}
}
};
-
+ // ShutdownThread must run on a looper capable of displaying the UI.
mHandler.post(runnable);
- // block until we reboot or fail.
- // throw an exception if we failed to reboot
+ // PowerManager.reboot() is documented not to return so just wait for the inevitable.
synchronized (runnable) {
- try {
- runnable.wait();
- } catch (InterruptedException e) {
+ while (true) {
+ try {
+ runnable.wait();
+ } catch (InterruptedException e) {
+ }
}
}
-
- // if we get here we failed
- throw new IllegalStateException("unable to reboot!");
}
/**
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index 3f64b25..be1d1c4 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -828,7 +828,13 @@
ArrayList pids = new ArrayList();
pids.add(Process.myPid());
+ if (mPhonePid > 0) pids.add(mPhonePid);
File stack = ActivityManagerService.dumpStackTraces(pids);
+
+ // Give some extra time to make sure the stack traces get written.
+ // The system's been hanging for a minute, another second or two won't hurt much.
+ SystemClock.sleep(2000);
+
mActivity.addErrorToDropBox("watchdog", null, null, null, name, null, stack, null);
// Only kill the process if the debugger is not attached.
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index f6289ae..8866bbd 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4708,7 +4708,8 @@
final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
HistoryRecord parent, final String annotation) {
- if (app.notResponding || app.crashing) {
+ // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
+ if (mShuttingDown || app.notResponding || app.crashing) {
return;
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
index 08946d2..188145b 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
@@ -592,8 +592,11 @@
if (!isIncoming) {
// outgoing calls only
processNextPostDialChar();
+ } else {
+ // Only release wake lock for incoming calls, for outgoing calls the wake lock
+ // will be released after any pause-dial is completed
+ releaseWakeLock();
}
- releaseWakeLock();
}
private void
@@ -688,6 +691,7 @@
Registrant postDialHandler;
if (postDialState == PostDialState.CANCELLED) {
+ releaseWakeLock();
//Log.v("CDMA", "##### processNextPostDialChar: postDialState == CANCELLED, bail");
return;
}
@@ -696,6 +700,9 @@
postDialString.length() <= nextPostDialChar) {
setPostDialState(PostDialState.COMPLETE);
+ // We were holding a wake lock until pause-dial was complete, so give it up now
+ releaseWakeLock();
+
// notifyMessage.arg1 is 0 on complete
c = 0;
} else {
@@ -770,19 +777,24 @@
}
/**
- * Set post dial state and acquire wake lock while switching to "started"
- * state, the wake lock will be released if state switches out of "started"
+ * Set post dial state and acquire wake lock while switching to "started" or "wait"
+ * state, the wake lock will be released if state switches out of "started" or "wait"
* state or after WAKE_LOCK_TIMEOUT_MILLIS.
* @param s new PostDialState
*/
private void setPostDialState(PostDialState s) {
- if (postDialState != PostDialState.STARTED
- && s == PostDialState.STARTED) {
- acquireWakeLock();
- Message msg = h.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT);
- h.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT_MILLIS);
- } else if (postDialState == PostDialState.STARTED
- && s != PostDialState.STARTED) {
+ if (s == PostDialState.STARTED ||
+ s == PostDialState.PAUSE) {
+ synchronized (mPartialWakeLock) {
+ if (mPartialWakeLock.isHeld()) {
+ h.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
+ } else {
+ acquireWakeLock();
+ }
+ Message msg = h.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT);
+ h.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT_MILLIS);
+ }
+ } else {
h.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
releaseWakeLock();
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/EriInfo.java b/telephony/java/com/android/internal/telephony/cdma/EriInfo.java
index 5c8e23e..3e5d37e 100644
--- a/telephony/java/com/android/internal/telephony/cdma/EriInfo.java
+++ b/telephony/java/com/android/internal/telephony/cdma/EriInfo.java
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
diff --git a/telephony/java/com/android/internal/telephony/cdma/EriManager.java b/telephony/java/com/android/internal/telephony/cdma/EriManager.java
index 37c1d55..1bcc90a 100644
--- a/telephony/java/com/android/internal/telephony/cdma/EriManager.java
+++ b/telephony/java/com/android/internal/telephony/cdma/EriManager.java
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index eecd00a..e3486a0 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -24,9 +24,8 @@
private static final String LOGTAG = "FileFilter";
// Returns whether we should ignore this test and skip running it.
- // Currently we use this only for tests that crash the browser.
- // TODO: Once these crashes are fixed, we should probably eliminate this
- // method, as no test should crash.
+ // Currently we use this only for tests that crash or hang DumpRenderTree.
+ // TODO: Fix these and eliminate this method.
public static boolean ignoreTest(String file) {
for (int i = 0; i < ignoreTestList.length; i++) {
if (file.endsWith(ignoreTestList[i])) {
@@ -74,6 +73,8 @@
static final String[] ignoreTestList = {
"fast/js/regexp-charclass-crash.html", // RegExp is too large, causing OOM
+ "fast/regex/test1.html", // Causes DumpRenderTree to hang with V8
+ "fast/regex/slow.html", // Causes DumpRenderTree to hang with V8
"editing/selection/move-left-right.html" // Causes DumpRenderTree to hang
};