Merge "Unittests for EntropyService. Make EntropyService more testable."
diff --git a/api/current.xml b/api/current.xml
index cd11b1d..9dc2218 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -80994,6 +80994,17 @@
visibility="public"
>
</field>
+<field name="AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="AUDIOFOCUS_LOSS"
type="int"
transient="false"
@@ -81016,6 +81027,17 @@
visibility="public"
>
</field>
+<field name="AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="AUDIOFOCUS_REQUEST_FAILED"
type="int"
transient="false"
@@ -193713,7 +193735,7 @@
visibility="public"
>
</method>
-<method name="getUseSystemOverscrollBackground"
+<method name="getUseWebViewBackgroundForOverscrollBackground"
return="boolean"
abstract="false"
native="false"
@@ -194303,7 +194325,7 @@
<parameter name="use" type="boolean">
</parameter>
</method>
-<method name="setUseSystemOverscrollBackground"
+<method name="setUseWebViewBackgroundForOverscrollBackground"
return="void"
abstract="false"
native="false"
@@ -194313,7 +194335,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="system" type="boolean">
+<parameter name="view" type="boolean">
</parameter>
</method>
<method name="setUseWideViewPort"
@@ -385783,7 +385805,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="text" type="java.lang.String">
+<parameter name="message" type="java.lang.String">
</parameter>
</method>
</class>
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index e9b21f1..e8b5eaf 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -105,7 +105,7 @@
#ifdef FWDUMP_bcm4329
run_command("DUMP WIFI FIRMWARE LOG", 60,
- "dhdutil", "-i", "eth0", "upload", "/data/local/tmp/wlan_crash.dump", NULL);
+ "su", "root", "dhdutil", "-i", "eth0", "upload", "/data/local/tmp/wlan_crash.dump", NULL);
#endif
print_properties();
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index cfc2e75..659d70f 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -92,11 +92,6 @@
return;
}
- if ("mountsd".equals(op)) {
- runMountSd();
- return;
- }
-
if ("uninstall".equals(op)) {
runUninstall();
return;
@@ -646,37 +641,6 @@
}
}
- private void runMountSd() {
- String opt;
- boolean mount = false;
- while ((opt=nextOption()) != null) {
- if (opt.equals("-m")) {
- String mountStr = nextOptionData();
- if (mountStr == null) {
- System.err.println("Error: no value specified for -m");
- showUsage();
- return;
- }
- if ("true".equalsIgnoreCase(mountStr)) {
- mount = true;
- } else if ("false".equalsIgnoreCase(mountStr)) {
- mount = false;
- } else {
- System.err.println("Error: no value specified for -m");
- showUsage();
- return;
- }
- }
- }
-
- try {
- mPm.updateExternalMediaStatus(mount);
- } catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(PM_NOT_RUNNING_ERR);
- }
- }
-
class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
boolean finished;
boolean result;
@@ -866,7 +830,6 @@
System.err.println(" pm path PACKAGE");
System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH");
System.err.println(" pm uninstall [-k] PACKAGE");
- System.err.println(" pm mountsd [-m true/false]");
System.err.println(" pm enable PACKAGE_OR_COMPONENT");
System.err.println(" pm disable PACKAGE_OR_COMPONENT");
System.err.println("");
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 6d5686a..596ca9d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -980,10 +980,11 @@
return true;
}
- case KILL_PIDS_FOR_MEMORY_TRANSACTION: {
+ case KILL_PIDS_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int[] pids = data.createIntArray();
- boolean res = killPidsForMemory(pids);
+ String reason = data.readString();
+ boolean res = killPids(pids, reason);
reply.writeNoException();
reply.writeInt(res ? 1 : 0);
return true;
@@ -2393,12 +2394,13 @@
mRemote.transact(NOTE_WAKEUP_ALARM_TRANSACTION, data, null, 0);
data.recycle();
}
- public boolean killPidsForMemory(int[] pids) throws RemoteException {
+ public boolean killPids(int[] pids, String reason) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeIntArray(pids);
- mRemote.transact(KILL_PIDS_FOR_MEMORY_TRANSACTION, data, reply, 0);
+ data.writeString(reason);
+ mRemote.transact(KILL_PIDS_TRANSACTION, data, reply, 0);
boolean res = reply.readInt() != 0;
data.recycle();
reply.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 14571de..30feae1 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -241,7 +241,7 @@
public void noteWakeupAlarm(IIntentSender sender) throws RemoteException;
- public boolean killPidsForMemory(int[] pids) throws RemoteException;
+ public boolean killPids(int[] pids, String reason) throws RemoteException;
public void reportPss(IApplicationThread caller, int pss) throws RemoteException;
@@ -476,7 +476,7 @@
int GET_PROCESSES_IN_ERROR_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+76;
int CLEAR_APP_DATA_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+77;
int FORCE_STOP_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+78;
- int KILL_PIDS_FOR_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79;
+ int KILL_PIDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79;
int GET_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+80;
int REPORT_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81;
int GET_RUNNING_APP_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+82;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 399a87d..c638d04 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -309,7 +309,7 @@
* MountService uses this to call into the package manager to update
* status of sdcard.
*/
- boolean updateExternalMediaStatus(boolean mounted);
+ void updateExternalMediaStatus(boolean mounted, boolean reportStatus);
String nextPackageToClean(String lastPackage);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index bbf4ca1..0318b6c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -233,7 +233,7 @@
/**
* Flag parameter for {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} to
* indicate that this package should be installed as forward locked, i.e. only the app itself
- * should have access to it's code and non-resource assets.
+ * should have access to its code and non-resource assets.
* @hide
*/
public static final int INSTALL_FORWARD_LOCK = 0x00000001;
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 9201e3b..4b48409 100644
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -175,6 +175,7 @@
private boolean mShowTouchPoints = true;
private int mPopupPreviewX;
private int mPopupPreviewY;
+ private int mWindowY;
private int mLastX;
private int mLastY;
@@ -909,20 +910,36 @@
getLocationInWindow(mOffsetInWindow);
mOffsetInWindow[0] += mMiniKeyboardOffsetX; // Offset may be zero
mOffsetInWindow[1] += mMiniKeyboardOffsetY; // Offset may be zero
+ int[] mWindowLocation = new int[2];
+ getLocationOnScreen(mWindowLocation);
+ mWindowY = mWindowLocation[1];
}
// Set the preview background state
mPreviewText.getBackground().setState(
key.popupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET);
+ mPopupPreviewX += mOffsetInWindow[0];
+ mPopupPreviewY += mOffsetInWindow[1];
+
+ // If the popup cannot be shown above the key, put it on the side
+ if (mPopupPreviewY + mWindowY < 0) {
+ // If the key you're pressing is on the left side of the keyboard, show the popup on
+ // the right, offset by enough to see at least one key to the left/right.
+ if (key.x + key.width <= getWidth() / 2) {
+ mPopupPreviewX += (int) (key.width * 2.5);
+ } else {
+ mPopupPreviewX -= (int) (key.width * 2.5);
+ }
+ mPopupPreviewY += popupHeight;
+ }
+
if (previewPopup.isShowing()) {
- previewPopup.update(mPopupPreviewX + mOffsetInWindow[0],
- mPopupPreviewY + mOffsetInWindow[1],
+ previewPopup.update(mPopupPreviewX, mPopupPreviewY,
popupWidth, popupHeight);
} else {
previewPopup.setWidth(popupWidth);
previewPopup.setHeight(popupHeight);
previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY,
- mPopupPreviewX + mOffsetInWindow[0],
- mPopupPreviewY + mOffsetInWindow[1]);
+ mPopupPreviewX, mPopupPreviewY);
}
mPreviewText.setVisibility(VISIBLE);
}
diff --git a/core/java/android/net/http/Connection.java b/core/java/android/net/http/Connection.java
index b8e17da..43fb5f1 100644
--- a/core/java/android/net/http/Connection.java
+++ b/core/java/android/net/http/Connection.java
@@ -222,6 +222,12 @@
}
}
+ /* we have a connection, let the event handler
+ * know of any associated certificate,
+ * potentially none.
+ */
+ req.mEventHandler.certificate(mCertificate);
+
try {
/* FIXME: don't increment failure count if old
connection? There should not be a penalty for
diff --git a/core/java/android/net/http/EventHandler.java b/core/java/android/net/http/EventHandler.java
index a035c19..2aa05eb 100644
--- a/core/java/android/net/http/EventHandler.java
+++ b/core/java/android/net/http/EventHandler.java
@@ -125,8 +125,8 @@
public void endData();
/**
- * SSL certificate callback called every time a resource is
- * loaded via a secure connection
+ * SSL certificate callback called before resource request is
+ * made, which will be null for insecure connection.
*/
public void certificate(SslCertificate certificate);
diff --git a/core/java/android/net/http/HttpsConnection.java b/core/java/android/net/http/HttpsConnection.java
index a67fd9a..e512a1df 100644
--- a/core/java/android/net/http/HttpsConnection.java
+++ b/core/java/android/net/http/HttpsConnection.java
@@ -308,12 +308,6 @@
SslError error = CertificateChainValidator.getInstance().
doHandshakeAndValidateServerCertificates(this, sslSock, mHost.getHostName());
- EventHandler eventHandler = req.getEventHandler();
-
- // Update the certificate info (to be consistent, it is better to do it
- // here, before we start handling SSL errors, if any)
- eventHandler.certificate(mCertificate);
-
// Inform the user if there is a problem
if (error != null) {
// handleSslErrorRequest may immediately unsuspend if it wants to
@@ -325,7 +319,7 @@
mSuspended = true;
}
// don't hold the lock while calling out to the event handler
- boolean canHandle = eventHandler.handleSslErrorRequest(error);
+ boolean canHandle = req.getEventHandler().handleSslErrorRequest(error);
if(!canHandle) {
throw new IOException("failed to handle "+ error);
}
diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl
index 75455ab..4862f80 100644
--- a/core/java/android/os/storage/IMountService.aidl
+++ b/core/java/android/os/storage/IMountService.aidl
@@ -84,7 +84,7 @@
int[] getStorageUsers(String path);
/**
- * Gets the state of an volume via it's mountpoint.
+ * Gets the state of a volume via its mountpoint.
*/
String getVolumeState(String mountPoint);
@@ -146,4 +146,10 @@
* Invokes call back once the shutdown is complete.
*/
void shutdown(IMountShutdownObserver observer);
+
+ /**
+ * Call into MountService by PackageManager to notify that its done
+ * processing the media status update request.
+ */
+ void finishMediaUpdate();
}
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index af42ce0..344b390 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -527,20 +527,12 @@
*/
private int getFileSize(String uri) {
int size = 0;
- Cursor cursor = mContext.getContentResolver().query(Uri.parse(uri),
- new String[] { OpenableColumns.SIZE },
- null,
- null,
- null);
- if (cursor != null) {
- try {
- if (cursor.moveToNext()) {
- size = cursor.getInt(0);
- }
- } finally {
- cursor.close();
- }
- }
+ try {
+ InputStream stream = mContext.getContentResolver()
+ .openInputStream(Uri.parse(uri));
+ size = stream.available();
+ stream.close();
+ } catch (Exception e) {}
return size;
}
@@ -586,7 +578,10 @@
* @param headers The http headers.
* @param postData If the method is "POST" postData is sent as the request
* body. Is null when empty.
- * @param cacheMode The cache mode to use when loading this resource.
+ * @param postDataIdentifier If the post data contained form this is the form identifier, otherwise it is 0.
+ * @param cacheMode The cache mode to use when loading this resource. See WebSettings.setCacheMode
+ * @param mainResource True if the this resource is the main request, not a supporting resource
+ * @param userGesture
* @param synchronous True if the load is synchronous.
* @return A newly created LoadListener object.
*/
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 1c59c10..4f680e5 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -733,11 +733,15 @@
ret.contentdisposition = contentDisposition;
}
+ // lastModified and etag may be set back to http header. So they can't
+ // be empty string.
String lastModified = headers.getLastModified();
- if (lastModified != null) ret.lastModified = lastModified;
+ if (lastModified != null && lastModified.length() > 0) {
+ ret.lastModified = lastModified;
+ }
String etag = headers.getEtag();
- if (etag != null) ret.etag = etag;
+ if (etag != null && etag.length() > 0) ret.etag = etag;
String cacheControl = headers.getCacheControl();
if (cacheControl != null) {
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 4f2830b..1eb3fa4 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -397,6 +397,7 @@
notify();
}
}
+ mWebView.dismissZoomControl();
}
break;
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 427ce76..74a648e 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -230,14 +230,8 @@
return 1;
}
- diff = cookie2.name.hashCode() - cookie1.name.hashCode();
- if (diff != 0) return diff;
-
- // cookie1 and cookie2 both have non-null values so we emit a
- // warning and treat them as the same.
- Log.w(LOGTAG, "Found two cookies with the same value."
- + "cookie1=" + cookie1 + " , cookie2=" + cookie2);
- return 0;
+ // Fallback to comparing the name to ensure consistent order.
+ return cookie1.name.compareTo(cookie2.name);
}
}
@@ -255,7 +249,7 @@
* first.
*
* @return CookieManager
-= */
+ */
public static synchronized CookieManager getInstance() {
if (sRef == null) {
sRef = new CookieManager();
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index a23a4ce..dc7723f 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -121,6 +121,7 @@
// Does this loader correspond to the main-frame top-level page?
private boolean mIsMainPageLoader;
+ // Does this loader correspond to the main content (as opposed to a supporting resource)
private final boolean mIsMainResourceLoader;
private final boolean mUserGesture;
@@ -520,23 +521,28 @@
}
/**
- * Implementation of certificate handler for EventHandler.
- * Called every time a resource is loaded via a secure
- * connection. In this context, can be called multiple
- * times if we have redirects
- * @param certificate The SSL certifcate
- * IMPORTANT: as this is called from network thread, can't call native
- * directly
+ * Implementation of certificate handler for EventHandler. Called
+ * before a resource is requested. In this context, can be called
+ * multiple times if we have redirects
+ *
+ * IMPORTANT: as this is called from network thread, can't call
+ * native directly
+ *
+ * @param certificate The SSL certifcate or null if the request
+ * was not secure
*/
public void certificate(SslCertificate certificate) {
+ if (DebugFlags.LOAD_LISTENER) {
+ Log.v(LOGTAG, "LoadListener.certificate: " + certificate);
+ }
sendMessageInternal(obtainMessage(MSG_SSL_CERTIFICATE, certificate));
}
// Handle the certificate on the WebCore thread.
private void handleCertificate(SslCertificate certificate) {
- // if this is the top-most main-frame page loader
- if (mIsMainPageLoader) {
- // update the browser frame (ie, the main frame)
+ // if this is main resource of the top frame
+ if (mIsMainPageLoader && mIsMainResourceLoader) {
+ // update the browser frame with certificate
mBrowserFrame.certificate(certificate);
}
}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index fb15f78..d1da5ea 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -192,7 +192,7 @@
private boolean mBuiltInZoomControls = false;
private boolean mAllowFileAccess = true;
private boolean mLoadWithOverviewMode = false;
- private boolean mUseSystemOverscrollBackground = false;
+ private boolean mUseWebViewBackgroundOverscrollBackground = true;
// private WebSettings, not accessible by the host activity
static private int mDoubleTapToastCount = 3;
@@ -471,20 +471,20 @@
}
/**
- * Set whether the WebView uses system background for over scroll
- * background. If false, it will use the WebView's background. Default is
- * false.
+ * Set whether the WebView uses its background for over scroll background.
+ * If true, it will use the WebView's background. If false, it will use an
+ * internal pattern. Default is true.
*/
- public void setUseSystemOverscrollBackground(boolean system) {
- mUseSystemOverscrollBackground = system;
+ public void setUseWebViewBackgroundForOverscrollBackground(boolean view) {
+ mUseWebViewBackgroundOverscrollBackground = view;
}
/**
- * Returns true if this WebView uses system background instead of WebView
- * background for over scroll background.
+ * Returns true if this WebView uses WebView's background instead of
+ * internal pattern for over scroll background.
*/
- public boolean getUseSystemOverscrollBackground() {
- return mUseSystemOverscrollBackground;
+ public boolean getUseWebViewBackgroundForOverscrollBackground() {
+ return mUseWebViewBackgroundOverscrollBackground;
}
/**
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 9314d7b..5345879 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -340,6 +340,15 @@
}
/**
+ * Sets the maximum size of the ApplicationCache.
+ * This should only ever be called on the WebKit thread.
+ * @hide Pending API council approval
+ */
+ public void setAppCacheMaximumSize(long size) {
+ nativeSetAppCacheMaximumSize(size);
+ }
+
+ /**
* Utility function to send a message to our handler
*/
private synchronized void postMessage(Message msg) {
@@ -402,4 +411,5 @@
private static native void nativeSetQuotaForOrigin(String origin, long quota);
private static native void nativeDeleteOrigin(String origin);
private static native void nativeDeleteAllData();
+ private static native void nativeSetAppCacheMaximumSize(long size);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 1becf9e..cabda85 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1088,6 +1088,9 @@
* Sets the SSL certificate for the main top-level page.
*/
public void setCertificate(SslCertificate certificate) {
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "setCertificate=" + certificate);
+ }
// here, the certificate can be null (if the site is not secure)
mCertificate = certificate;
}
@@ -2294,20 +2297,13 @@
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 && !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
+ if (maxX == 0) {
+ // do not over scroll x if the page just fits the screen
scrollX = pinLocX(scrollX);
} else if (scrollX < 0 || scrollX > maxX) {
mInOverScrollMode = true;
@@ -3120,8 +3116,8 @@
}
int saveCount = canvas.save();
- if (mInOverScrollMode
- && getSettings().getUseSystemOverscrollBackground()) {
+ if (mInOverScrollMode && !getSettings()
+ .getUseWebViewBackgroundForOverscrollBackground()) {
if (mOverScrollBackground == null) {
mOverScrollBackground = new Paint();
Bitmap bm = BitmapFactory.decodeResource(
@@ -3983,8 +3979,7 @@
protected void onDetachedFromWindow() {
clearTextEntry(false);
super.onDetachedFromWindow();
- // Clean up the zoom controller
- mZoomButtonsController.setVisible(false);
+ dismissZoomControl();
}
/**
@@ -4183,6 +4178,8 @@
}
}
+ dismissZoomControl();
+
// onSizeChanged() is called during WebView layout. And any
// requestLayout() is blocked during layout. As setNewZoomScale() will
// call its child View to reposition itself through ViewManager's
@@ -4444,9 +4441,7 @@
public boolean onScaleBegin(ScaleGestureDetector detector) {
// cancel the single touch handling
cancelTouch();
- if (mZoomButtonsController.isVisible()) {
- mZoomButtonsController.setVisible(false);
- }
+ dismissZoomControl();
// reset the zoom overview mode so that the page won't auto grow
mInZoomOverview = false;
// If it is in password mode, turn it off so it does not draw
@@ -5385,9 +5380,6 @@
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;
@@ -5426,8 +5418,9 @@
mLastVelY = vy;
mLastVelocity = (float) Math.hypot(vx, vy);
+ // no horizontal overscroll if the content just fits
mScroller.fling(mScrollX, mScrollY, -vx, -vy, 0, maxX, 0, maxY,
- getViewWidth() / 3, getViewHeight() / 3);
+ maxX == 0 ? 0 : getViewWidth() / 3, getViewHeight() / 3);
// TODO: duration is calculated based on velocity, if the range is
// small, the animation will stop before duration is up. We may
// want to calculate how long the animation is going to run to precisely
@@ -5779,6 +5772,31 @@
}
}
+ void dismissZoomControl() {
+ if (mWebViewCore == null) {
+ // maybe called after WebView's destroy(). As we can't get settings,
+ // just hide zoom control for both styles.
+ mZoomButtonsController.setVisible(false);
+ if (mZoomControls != null) {
+ mZoomControls.hide();
+ }
+ return;
+ }
+ WebSettings settings = getSettings();
+ if (settings.getBuiltInZoomControls()) {
+ if (mZoomButtonsController.isVisible()) {
+ mZoomButtonsController.setVisible(false);
+ }
+ } else {
+ if (mZoomControlRunnable != null) {
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ }
+ if (mZoomControls != null) {
+ mZoomControls.hide();
+ }
+ }
+ }
+
// Rule for double tap:
// 1. if the current scale is not same as the text wrap scale and layout
// algorithm is NARROW_COLUMNS, fit to column;
@@ -5793,20 +5811,9 @@
mAnchorX = viewToContentX((int) mZoomCenterX + mScrollX);
mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
WebSettings settings = getSettings();
- // remove the zoom control after double tap
- if (settings.getBuiltInZoomControls()) {
- if (mZoomButtonsController.isVisible()) {
- mZoomButtonsController.setVisible(false);
- }
- } else {
- if (mZoomControlRunnable != null) {
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- }
- if (mZoomControls != null) {
- mZoomControls.hide();
- }
- }
settings.setDoubleTapToastCount(0);
+ // remove the zoom control after double tap
+ dismissZoomControl();
ViewManager.ChildView plugin = mViewManager.hitTest(mAnchorX, mAnchorY);
if (plugin != null) {
if (isPluginFitOnScreen(plugin)) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 46769ce..24275ec 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -46,6 +46,7 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* All information we are collecting about things that can happen that impact
@@ -230,14 +231,15 @@
* State for keeping track of counting information.
*/
public static class Counter extends BatteryStats.Counter implements Unpluggable {
- int mCount;
+ final AtomicInteger mCount = new AtomicInteger();
int mLoadedCount;
int mLastCount;
int mUnpluggedCount;
int mPluggedCount;
Counter(ArrayList<Unpluggable> unpluggables, Parcel in) {
- mPluggedCount = mCount = in.readInt();
+ mPluggedCount = in.readInt();
+ mCount.set(mPluggedCount);
mLoadedCount = in.readInt();
mLastCount = in.readInt();
mUnpluggedCount = in.readInt();
@@ -249,18 +251,19 @@
}
public void writeToParcel(Parcel out) {
- out.writeInt(mCount);
+ out.writeInt(mCount.get());
out.writeInt(mLoadedCount);
out.writeInt(mLastCount);
out.writeInt(mUnpluggedCount);
}
public void unplug(long batteryUptime, long batteryRealtime) {
- mUnpluggedCount = mCount = mPluggedCount;
+ mUnpluggedCount = mPluggedCount;
+ mCount.set(mPluggedCount);
}
public void plug(long batteryUptime, long batteryRealtime) {
- mPluggedCount = mCount;
+ mPluggedCount = mCount.get();
}
/**
@@ -285,7 +288,7 @@
if (which == STATS_LAST) {
val = mLastCount;
} else {
- val = mCount;
+ val = mCount.get();
if (which == STATS_UNPLUGGED) {
val -= mUnpluggedCount;
} else if (which != STATS_TOTAL) {
@@ -297,25 +300,27 @@
}
public void logState(Printer pw, String prefix) {
- pw.println(prefix + "mCount=" + mCount
+ pw.println(prefix + "mCount=" + mCount.get()
+ " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
+ " mUnpluggedCount=" + mUnpluggedCount
+ " mPluggedCount=" + mPluggedCount);
}
- void stepLocked() {
- mCount++;
+ void stepAtomic() {
+ mCount.incrementAndGet();
}
void writeSummaryFromParcelLocked(Parcel out) {
- out.writeInt(mCount);
- out.writeInt(mCount - mLoadedCount);
+ int count = mCount.get();
+ out.writeInt(count);
+ out.writeInt(count - mLoadedCount);
}
void readSummaryFromParcelLocked(Parcel in) {
- mCount = mLoadedCount = in.readInt();
+ mLoadedCount = in.readInt();
+ mCount.set(mLoadedCount);
mLastCount = in.readInt();
- mUnpluggedCount = mPluggedCount = mCount;
+ mUnpluggedCount = mPluggedCount = mLoadedCount;
}
}
@@ -329,8 +334,8 @@
super(unpluggables);
}
- public void addCountLocked(long count) {
- mCount += count;
+ public void addCountAtomic(long count) {
+ mCount.addAndGet((int)count);
}
}
@@ -1124,8 +1129,8 @@
}
}
- public void noteInputEventLocked() {
- mInputEventCounter.stepLocked();
+ public void noteInputEventAtomic() {
+ mInputEventCounter.stepAtomic();
}
public void noteUserActivityLocked(int uid, int event) {
@@ -1680,7 +1685,7 @@
}
if (type < 0) type = 0;
else if (type >= NUM_USER_ACTIVITY_TYPES) type = NUM_USER_ACTIVITY_TYPES-1;
- mUserActivityCounters[type].stepLocked();
+ mUserActivityCounters[type].stepAtomic();
}
@Override
@@ -2172,7 +2177,7 @@
/* Called by ActivityManagerService when CPU times are updated. */
public void addSpeedStepTimes(long[] values) {
for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
- mSpeedBins[i].addCountLocked(values[i]);
+ mSpeedBins[i].addCountAtomic(values[i]);
}
}
diff --git a/core/jni/android_bluetooth_ScoSocket.cpp b/core/jni/android_bluetooth_ScoSocket.cpp
index 8588bc2..94e4409 100644
--- a/core/jni/android_bluetooth_ScoSocket.cpp
+++ b/core/jni/android_bluetooth_ScoSocket.cpp
@@ -404,11 +404,15 @@
env->ReleaseStringUTFChars(address, c_address);
data->is_accept = false;
- c_name = env->GetStringUTFChars(name, NULL);
- /* See if this device is in the black list */
- data->sco_pkt_type = getScoType(data->address, c_name);
- env->ReleaseStringUTFChars(name, c_name);
-
+ if (name == NULL) {
+ LOGE("%s: Null pointer passed in for device name", __FUNCTION__);
+ data->sco_pkt_type = 0;
+ } else {
+ c_name = env->GetStringUTFChars(name, NULL);
+ /* See if this device is in the black list */
+ data->sco_pkt_type = getScoType(data->address, c_name);
+ env->ReleaseStringUTFChars(name, c_name);
+ }
if (pthread_create(&thread, NULL, &work_thread, (void *)data) < 0) {
LOGE("%s: pthread_create() failed: %s", __FUNCTION__, strerror(errno));
return JNI_FALSE;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4e2caa0..a3c73d8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -732,7 +732,7 @@
@hide -->
<permission android:name="android.permission.ASEC_ACCESS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="dangerous"
+ android:protectionLevel="signature"
android:label="@string/permlab_asec_access"
android:description="@string/permdesc_asec_access" />
@@ -740,7 +740,7 @@
@hide -->
<permission android:name="android.permission.ASEC_CREATE"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="dangerous"
+ android:protectionLevel="signature"
android:label="@string/permlab_asec_create"
android:description="@string/permdesc_asec_create" />
@@ -748,7 +748,7 @@
@hide -->
<permission android:name="android.permission.ASEC_DESTROY"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="dangerous"
+ android:protectionLevel="signature"
android:label="@string/permlab_asec_destroy"
android:description="@string/permdesc_asec_destroy" />
@@ -756,7 +756,7 @@
@hide -->
<permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="dangerous"
+ android:protectionLevel="signature"
android:label="@string/permlab_asec_mount_unmount"
android:description="@string/permdesc_asec_mount_unmount" />
@@ -764,7 +764,7 @@
@hide -->
<permission android:name="android.permission.ASEC_RENAME"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="dangerous"
+ android:protectionLevel="signature"
android:label="@string/permlab_asec_rename"
android:description="@string/permdesc_asec_rename" />
diff --git a/include/utils/threads.h b/include/utils/threads.h
index 130d83c..5ac0c5e 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -209,7 +209,7 @@
class Mutex {
public:
enum {
- NORMAL = 0,
+ PRIVATE = 0,
SHARED = 1
};
@@ -305,7 +305,13 @@
*/
class Condition {
public:
+ enum {
+ PRIVATE = 0,
+ SHARED = 1
+ };
+
Condition();
+ Condition(int type);
~Condition();
// Wait on the condition variable. Lock the mutex before calling.
status_t wait(Mutex& mutex);
@@ -329,6 +335,17 @@
inline Condition::Condition() {
pthread_cond_init(&mCond, NULL);
}
+inline Condition::Condition(int type) {
+ if (type == SHARED) {
+ pthread_condattr_t attr;
+ pthread_condattr_init(&attr);
+ pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+ pthread_cond_init(&mCond, &attr);
+ pthread_condattr_destroy(&attr);
+ } else {
+ pthread_cond_init(&mCond, NULL);
+ }
+}
inline Condition::~Condition() {
pthread_cond_destroy(&mCond);
}
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index 65ce1c1..a17e8ac 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -34,7 +34,7 @@
// ----------------------------------------------------------------------------
SharedClient::SharedClient()
- : lock(Mutex::SHARED)
+ : lock(Mutex::SHARED), cv(Condition::SHARED)
{
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 104ecb4..68b351b 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1258,9 +1258,9 @@
*/
public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
/**
- * @hide
* Used to indicate a temporary request of audio focus, anticipated to last a short
- * amount of time, and where it is acceptable for other audio applications to duck.
+ * amount of time, and where it is acceptable for other audio applications to keep playing
+ * after having lowered their output level (also referred to as "ducking").
* Examples of temporary changes are the playback of driving directions where playback of music
* in the background is acceptable.
* @see OnAudioFocusChangeListener#onAudioFocusChanged(int)
@@ -1278,10 +1278,9 @@
*/
public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
/**
- * @hide
* Used to indicate a transient loss of audio focus where the loser of the audio focus can
- * duck if it wants to continue playing, as the new focus owner doesn't require others
- * to be silent.
+ * lower its output volume if it wants to continue playing (also referred to as "ducking"), as
+ * the new focus owner doesn't require others to be silent.
* @see OnAudioFocusChangeListener#onAudioFocusChanged(int)
*/
public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
@@ -1297,11 +1296,12 @@
* The focusChange value indicates whether the focus was gained,
* whether the focus was lost, and whether that loss is transient, or whether the new focus
* holder will hold it for an unknown amount of time.
- * When losing focus, listeners can use the duration hint to decide what
- * behavior to adopt when losing focus. A music player could for instance elect to duck its
- * music stream for transient focus losses, and pause otherwise.
- * @param focusChange one of {@link AudioManager#AUDIOFOCUS_GAIN},
+ * When losing focus, listeners can use the focus change information to decide what
+ * behavior to adopt when losing focus. A music player could for instance elect to lower
+ * the volume of its music stream (duck) for transient focus losses, and pause otherwise.
+ * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN},
* {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
+ * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
*/
public void onAudioFocusChanged(int focusChange);
}
@@ -1429,6 +1429,8 @@
* @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
* is temporary, and focus will be abandonned shortly. Examples of transient requests are
* for the playback of driving directions, or notifications sounds.
+ * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
+ * the previous focus owner to keep playing if it ducks its audio output.
* Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
* as the playback of a song or a video.
* @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 1992c93..ae0eccb 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -687,6 +687,7 @@
}
if (mode != mMode) {
if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
+ checkForUndispatchedAudioFocusChange(mMode, mode);
mMode = mode;
synchronized(mSetModeDeathHandlers) {
@@ -1816,6 +1817,40 @@
//==========================================================================================
// AudioFocus
//==========================================================================================
+ /**
+ * Flag to indicate that the top of the audio focus stack needs to recover focus
+ * but hasn't been signaled yet.
+ */
+ private boolean mHasUndispatchedAudioFocus = false;
+
+ private void checkForUndispatchedAudioFocusChange(int prevMode, int newMode) {
+ // when exiting a call
+ if ((prevMode == AudioSystem.MODE_IN_CALL) && (newMode != AudioSystem.MODE_IN_CALL)) {
+ // check for undispatched remote control focus gain
+ if (mHasUndispatchedAudioFocus) {
+ notifyTopOfAudioFocusStack();
+ }
+ }
+ }
+
+ private void notifyTopOfAudioFocusStack() {
+ // notify the top of the stack it gained focus
+ if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
+ if (canReassignAudioFocus()) {
+ try {
+ mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
+ AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId);
+ mHasUndispatchedAudioFocus = false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e);
+ e.printStackTrace();
+ }
+ } else {
+ mHasUndispatchedAudioFocus = true;
+ }
+ }
+ }
+
private static class FocusStackEntry {
public int mStreamType = -1;// no stream type
public boolean mIsTransportControlReceiver = false;
@@ -1871,16 +1906,7 @@
mFocusStack.pop();
if (signal) {
// notify the new top of the stack it gained focus
- if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)
- && canReassignAudioFocus()) {
- try {
- mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
- AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId);
- } catch (RemoteException e) {
- Log.e(TAG, " Failure to signal gain of focus due to "+ e);
- e.printStackTrace();
- }
- }
+ notifyTopOfAudioFocusStack();
}
} else {
// focus is abandoned by a client that's not at the top of the stack,
@@ -1902,8 +1928,9 @@
* Remove focus listeners from the focus stack for a particular client.
*/
private void removeFocusStackEntryForClient(IBinder cb) {
- // focus is abandoned by a client that's not at the top of the stack,
- // no need to update focus.
+ // is the owner of the audio focus part of the client to remove?
+ boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
+ mFocusStack.peek().mSourceRef.equals(cb);
Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
while(stackIterator.hasNext()) {
FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
@@ -1913,6 +1940,11 @@
mFocusStack.remove(fse);
}
}
+ if (isTopOfStackForClientToRemove) {
+ // we removed an entry at the top of the stack:
+ // notify the new top of the stack it gained focus.
+ notifyTopOfAudioFocusStack();
+ }
}
/**
@@ -1970,9 +2002,14 @@
synchronized(mFocusStack) {
if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) {
- mFocusStack.peek().mFocusChangeType = focusChangeHint;
- // if focus is already owned by this client, don't do anything
- return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+ // if focus is already owned by this client and the reason for acquiring the focus
+ // hasn't changed, don't do anything
+ if (mFocusStack.peek().mFocusChangeType == focusChangeHint) {
+ return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+ }
+ // the reason for the audio focus request has changed: remove the current top of
+ // stack and respond as if we had a new focus owner
+ mFocusStack.pop();
}
// notify current top of stack it is losing focus
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 2c5cbf6..5988d34 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -52,6 +52,7 @@
*
* <p>See the <a href="{@docRoot}guide/topics/media/index.html">Audio and Video</a>
* documentation for additional help with using MediaRecorder.
+ * <p>Note: Currently, MediaRecorder does not work on the emulator.
*/
public class MediaRecorder
{
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 74852dc..cd7bcd5 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -983,8 +983,10 @@
// =========================================================================
audio_track_cblk_t::audio_track_cblk_t()
- : lock(Mutex::SHARED), user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0),
- loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0), flowControlFlag(1), forceReady(0)
+ : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0),
+ userBase(0), serverBase(0), buffers(0), frameCount(0),
+ loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0),
+ flowControlFlag(1), forceReady(0)
{
}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index d50f5910..d3ac026 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -135,17 +135,6 @@
private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
private static final int MAX_UNMOUNT_RETRIES = 4;
- private IntentFilter mPmFilter = new IntentFilter(
- Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- private BroadcastReceiver mPmReceiver = new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
- mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
- }
- }
- };
-
class UnmountCallBack {
String path;
int retries;
@@ -200,49 +189,35 @@
class MountServiceHandler extends Handler {
ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>();
- boolean mRegistered = false;
+ boolean mUpdatingStatus = false;
MountServiceHandler(Looper l) {
super(l);
}
- void registerReceiver() {
- mRegistered = true;
- if (DEBUG_UNMOUNT) Log.i(TAG, "Registering receiver");
- mContext.registerReceiver(mPmReceiver, mPmFilter);
- }
-
- void unregisterReceiver() {
- mRegistered = false;
- if (DEBUG_UNMOUNT) Log.i(TAG, "Unregistering receiver");
- mContext.unregisterReceiver(mPmReceiver);
- }
-
public void handleMessage(Message msg) {
switch (msg.what) {
case H_UNMOUNT_PM_UPDATE: {
if (DEBUG_UNMOUNT) Log.i(TAG, "H_UNMOUNT_PM_UPDATE");
UnmountCallBack ucb = (UnmountCallBack) msg.obj;
mForceUnmounts.add(ucb);
- if (DEBUG_UNMOUNT) Log.i(TAG, " registered = " + mRegistered);
+ if (DEBUG_UNMOUNT) Log.i(TAG, " registered = " + mUpdatingStatus);
// Register only if needed.
- if (!mRegistered) {
- registerReceiver();
- if (DEBUG_UNMOUNT) Log.i(TAG, "Updating external media status");
- boolean hasExtPkgs = mPms.updateExternalMediaStatus(false);
- if (!hasExtPkgs) {
- // Unregister right away
- mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
- }
+ if (!mUpdatingStatus) {
+ if (DEBUG_UNMOUNT) Log.i(TAG, "Updating external media status on PackageManager");
+ mUpdatingStatus = true;
+ mPms.updateExternalMediaStatus(false, true);
}
break;
}
case H_UNMOUNT_PM_DONE: {
if (DEBUG_UNMOUNT) Log.i(TAG, "H_UNMOUNT_PM_DONE");
- // Unregister now.
- if (mRegistered) {
- unregisterReceiver();
+ if (!mUpdatingStatus) {
+ // Does not correspond to unmount's status update.
+ return;
}
+ if (DEBUG_UNMOUNT) Log.i(TAG, "Updated status. Processing requests");
+ mUpdatingStatus = false;
int size = mForceUnmounts.size();
int sizeArr[] = new int[size];
int sizeArrN = 0;
@@ -261,7 +236,7 @@
ActivityManagerService ams = (ActivityManagerService)
ServiceManager.getService("activity");
// Eliminate system process here?
- boolean ret = ams.killPidsForMemory(pids);
+ boolean ret = ams.killPids(pids, "Unmount media");
if (ret) {
// Confirm if file references have been freed.
pids = getStorageUsers(path);
@@ -277,8 +252,8 @@
ucb));
} else {
if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
- Log.i(TAG, "Cannot unmount inspite of " +
- MAX_UNMOUNT_RETRIES + " to unmount media");
+ Log.i(TAG, "Cannot unmount media inspite of " +
+ MAX_UNMOUNT_RETRIES + " retries");
// Send final broadcast indicating failure to unmount.
} else {
mHandler.sendMessageDelayed(
@@ -337,16 +312,23 @@
public void run() {
try {
String path = Environment.getExternalStorageDirectory().getPath();
- if (getVolumeState(
- Environment.getExternalStorageDirectory().getPath()).equals(
- Environment.MEDIA_UNMOUNTED)) {
+ String state = getVolumeState(path);
+
+ if (state.equals(Environment.MEDIA_UNMOUNTED)) {
int rc = doMountVolume(path);
if (rc != StorageResultCode.OperationSucceeded) {
Log.e(TAG, String.format("Boot-time mount failed (%d)", rc));
}
+ } else if (state.equals(Environment.MEDIA_SHARED)) {
+ /*
+ * Bootstrap UMS enabled state since vold indicates
+ * the volume is shared (runtime restart while ums enabled)
+ */
+ notifyVolumeStateChange(null, path, VolumeState.NoMedia, VolumeState.Shared);
}
+
/*
- * If UMS is connected in boot, send the connected event
+ * If UMS was connected on boot, send the connected event
* now that we're up.
*/
if (mSendUmsConnectedOnBoot) {
@@ -405,9 +387,9 @@
}
// Update state on PackageManager
if (Environment.MEDIA_UNMOUNTED.equals(state)) {
- mPms.updateExternalMediaStatus(false);
+ mPms.updateExternalMediaStatus(false, false);
} else if (Environment.MEDIA_MOUNTED.equals(state)) {
- mPms.updateExternalMediaStatus(true);
+ mPms.updateExternalMediaStatus(true, false);
}
String oldState = mLegacyState;
mLegacyState = state;
@@ -750,19 +732,15 @@
if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
return VoldResponseCode.OpFailedVolNotMounted;
}
-
- // We unmounted the volume. No of the asec containers are available now.
- synchronized (mAsecMountSet) {
- mAsecMountSet.clear();
- }
- // Notify PackageManager of potential media removal and deal with
- // return code later on. The caller of this api should be aware or have been
- // notified that the applications installed on the media will be killed.
// Redundant probably. But no harm in updating state again.
- mPms.updateExternalMediaStatus(false);
+ mPms.updateExternalMediaStatus(false, false);
try {
mConnector.doCommand(String.format(
"volume unmount %s%s", path, (force ? " force" : "")));
+ // We unmounted the volume. None of the asec containers are available now.
+ synchronized (mAsecMountSet) {
+ mAsecMountSet.clear();
+ }
return StorageResultCode.OperationSucceeded;
} catch (NativeDaemonConnectorException e) {
// Don't worry about mismatch in PackageManager since the
@@ -1325,5 +1303,9 @@
Log.e(TAG, "Got an empty response");
return "";
}
+
+ public void finishMediaUpdate() {
+ mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
+ }
}
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 5be919d..a3f2e09 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -483,8 +483,8 @@
* argv7 - Preamble
* argv8 - Max SCB
*/
- String str = String.format("softap set " + wlanIface + " " + softapIface + " %s %s %s",
- wifiConfig.SSID,
+ String str = String.format("softap set " + wlanIface + " " + softapIface +
+ " \"%s\" %s %s", wifiConfig.SSID,
wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
"wpa2-psk" : "open",
wifiConfig.preSharedKey);
@@ -511,7 +511,7 @@
mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
} else {
String str = String.format("softap set " + wlanIface + " " + softapIface +
- " %s %s %s", wifiConfig.SSID,
+ " \"%s\" %s %s", wifiConfig.SSID,
wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
"wpa2-psk" : "open",
wifiConfig.preSharedKey);
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 48b3fbb..9eb63a6 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -343,6 +343,7 @@
static final int POST_INSTALL = 9;
static final int MCS_RECONNECT = 10;
static final int MCS_GIVE_UP = 11;
+ static final int UPDATED_MEDIA_STATUS = 12;
// Delay time in millisecs
static final int BROADCAST_DELAY = 10 * 1000;
@@ -596,6 +597,13 @@
Slog.e(TAG, "Bogus post-install token " + msg.arg1);
}
} break;
+ case UPDATED_MEDIA_STATUS: {
+ try {
+ PackageHelper.getMountService().finishMediaUpdate();
+ } catch (RemoteException e) {
+ Log.e(TAG, "MountService not running?");
+ }
+ } break;
}
}
}
@@ -9373,10 +9381,12 @@
}
/*
- * Return true if PackageManager does have packages to be updated.
+ * Update media status on PackageManager.
*/
- public boolean updateExternalMediaStatus(final boolean mediaStatus) {
- final boolean ret;
+ public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Media status can only be updated by the system");
+ }
synchronized (mPackages) {
Log.i(TAG, "Updating external media status from " +
(mMediaMounted ? "mounted" : "unmounted") + " to " +
@@ -9384,32 +9394,29 @@
if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
mediaStatus+", mMediaMounted=" + mMediaMounted);
if (mediaStatus == mMediaMounted) {
- return false;
+ if (reportStatus) {
+ mHandler.sendEmptyMessage(UPDATED_MEDIA_STATUS);
+ }
+ return;
}
mMediaMounted = mediaStatus;
- Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_EXTERNAL_STORAGE);
- ret = appList != null && appList.size() > 0;
- if (DEBUG_SD_INSTALL) {
- if (appList != null) {
- for (String app : appList) {
- Log.i(TAG, "Should enable " + app + " on sdcard");
- }
- }
- }
- if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus returning " + ret);
}
// Queue up an async operation since the package installation may take a little while.
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
- updateExternalMediaStatusInner(mediaStatus, ret);
+ try {
+ updateExternalMediaStatusInner(mediaStatus);
+ } finally {
+ if (reportStatus) {
+ mHandler.sendEmptyMessage(UPDATED_MEDIA_STATUS);
+ }
+ }
}
});
- return ret;
}
- private void updateExternalMediaStatusInner(boolean mediaStatus,
- boolean sendUpdateBroadcast) {
+ private void updateExternalMediaStatusInner(boolean mediaStatus) {
// If we are up here that means there are packages to be
// enabled or disabled.
final String list[] = PackageHelper.getSecureContainerList();
@@ -9474,11 +9481,11 @@
// Process packages with valid entries.
if (mediaStatus) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
- loadMediaPackages(processCids, uidArr, sendUpdateBroadcast, removeCids);
+ loadMediaPackages(processCids, uidArr, removeCids);
startCleaningPackages();
} else {
if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
- unloadMediaPackages(processCids, uidArr, sendUpdateBroadcast);
+ unloadMediaPackages(processCids, uidArr);
}
}
@@ -9509,8 +9516,7 @@
* to avoid unnecessary crashes.
*/
private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids,
- int uidArr[], boolean sendUpdateBroadcast,
- HashSet<String> removeCids) {
+ int uidArr[], HashSet<String> removeCids) {
ArrayList<String> pkgList = new ArrayList<String>();
Set<SdInstallArgs> keys = processCids.keySet();
boolean doGc = false;
@@ -9578,7 +9584,7 @@
mSettings.writeLP();
}
// Send a broadcast to let everyone know we are done processing
- if (sendUpdateBroadcast) {
+ if (pkgList.size() > 0) {
sendResourcesChangedBroadcast(true, pkgList, uidArr);
}
if (doGc) {
@@ -9594,7 +9600,7 @@
}
private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids,
- int uidArr[], boolean sendUpdateBroadcast) {
+ int uidArr[]) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages");
ArrayList<String> pkgList = new ArrayList<String>();
ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
@@ -9617,7 +9623,7 @@
}
}
// Send broadcasts
- if (sendUpdateBroadcast) {
+ if (pkgList.size() > 0) {
sendResourcesChangedBroadcast(false, pkgList, uidArr);
}
// Force gc
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 93e45fc..fdb67f8 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -10755,7 +10755,7 @@
pids[i] = pidCandidates.keyAt(i);
}
try {
- if (mActivityManager.killPidsForMemory(pids)) {
+ if (mActivityManager.killPids(pids, "Free memory")) {
killedApps = true;
}
} catch (RemoteException e) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2ecebed..7034c88 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -8359,11 +8359,11 @@
}
}
- public boolean killPidsForMemory(int[] pids) {
+ public boolean killPids(int[] pids, String pReason) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("killPidsForMemory only available to the system");
+ throw new SecurityException("killPids only available to the system");
}
-
+ String reason = (pReason == null) ? "Unknown" : pReason;
// XXX Note: don't acquire main activity lock here, because the window
// manager calls in with its locks held.
@@ -8387,7 +8387,7 @@
if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
worstType = HIDDEN_APP_MIN_ADJ;
}
- Slog.w(TAG, "Killing processes for memory at adjustment " + worstType);
+ Slog.w(TAG, "Killing processes " + reason + " at adjustment " + worstType);
for (int i=0; i<pids.length; i++) {
ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
if (proc == null) {
@@ -8395,10 +8395,10 @@
}
int adj = proc.setAdj;
if (adj >= worstType) {
- Slog.w(TAG, "Killing for memory: " + proc + " (adj "
+ Slog.w(TAG, "Killing " + reason + " : " + proc + " (adj "
+ adj + ")");
- EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
- proc.processName, adj);
+ EventLog.writeEvent(EventLogTags.AM_KILL, proc.pid,
+ proc.processName, adj, reason);
killed = true;
Process.killProcess(pids[i]);
}
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index cdf4e95..33bbc13 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -158,9 +158,7 @@
public void noteInputEvent() {
enforceCallingPermission();
- synchronized (mStats) {
- mStats.noteInputEventLocked();
- }
+ mStats.noteInputEventAtomic();
}
public void noteUserActivity(int uid, int event) {
diff --git a/services/java/com/android/server/am/EventLogTags.logtags b/services/java/com/android/server/am/EventLogTags.logtags
index 0ddcc247..aadd37d 100644
--- a/services/java/com/android/server/am/EventLogTags.logtags
+++ b/services/java/com/android/server/am/EventLogTags.logtags
@@ -58,7 +58,7 @@
# The activity's onResume has been called.
30022 am_on_resume_called (Component Name|3)
# Kill a process to reclaim memory.
-30023 am_kill_for_memory (PID|1|5),(Process Name|3),(OomAdj|1|5)
+30023 am_kill (PID|1|5),(Process Name|3),(OomAdj|1|5),(Reason|3)
# Discard an undelivered serialized broadcast (timeout/ANR/crash)
30024 am_broadcast_discard_filter (Broadcast|1|5),(Action|3),(Receiver Number|1|1),(BroadcastFilter|1|5)
30025 am_broadcast_discard_app (Broadcast|1|5),(Action|3),(Receiver Number|1|1),(App|3)
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index 6eea46e..d3a34ec 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -202,7 +202,7 @@
/**
* Supply the ICC PIN to the ICC
*
- * When the operation is complete, onComplete will be sent to it's
+ * When the operation is complete, onComplete will be sent to its
* Handler.
*
* onComplete.obj will be an AsyncResult
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index dd7a169..6975c70 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -93,6 +93,9 @@
protected void setUp() throws Exception {
super.setUp();
mOrigState = getMediaState();
+ if (!mountMedia()) {
+ Log.i(TAG, "sdcard not mounted? Some of these tests might fail");
+ }
}
@Override
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
index ce1bf8d..5780c43 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
@@ -73,6 +73,7 @@
private static final int LAYOUT_DUMP_DATABASE_CALLBACKS = 41;
private static final int LAYOUT_SET_CAN_OPEN_WINDOWS = 42;
private static final int SET_GEOLOCATION_PERMISSION = 43;
+ private static final int OVERRIDE_PREFERENCE = 44;
CallbackProxy(EventSender eventSender,
LayoutTestController layoutTestController) {
@@ -266,6 +267,12 @@
mLayoutTestController.setGeolocationPermission(
msg.arg1 == 1 ? true : false);
break;
+
+ case OVERRIDE_PREFERENCE:
+ String key = msg.getData().getString("key");
+ boolean value = msg.getData().getBoolean("value");
+ mLayoutTestController.overridePreference(key, value);
+ break;
}
}
@@ -461,6 +468,10 @@
WebStorage.getInstance().setQuotaForOrigin("file://", quota);
}
+ public void setAppCacheMaximumSize(long size) {
+ WebStorage.getInstance().setAppCacheMaximumSize(size);
+ }
+
public void setCanOpenWindows() {
obtainMessage(LAYOUT_SET_CAN_OPEN_WINDOWS).sendToTarget();
}
@@ -480,4 +491,11 @@
public void setGeolocationPermission(boolean allow) {
obtainMessage(SET_GEOLOCATION_PERMISSION, allow ? 1 : 0, 0).sendToTarget();
}
+
+ public void overridePreference(String key, boolean value) {
+ Message message = obtainMessage(OVERRIDE_PREFERENCE);
+ message.getData().putString("key", key);
+ message.getData().putBoolean("value", value);
+ message.sendToTarget();
+ }
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index d51d17a..d10e382 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -82,18 +82,10 @@
// This first block of tests are for HTML5 features, for which Android
// should pass all tests. They are skipped only temporarily.
// TODO: Fix these failing tests and remove them from this list.
- ignoreResultList.add("http/tests/appcache/auth.html"); // file not found
- ignoreResultList.add("http/tests/appcache/deferred-events.html"); // file not found
- ignoreResultList.add("http/tests/appcache/deferred-events-delete-while-raising.html"); // file not found
- ignoreResultList.add("http/tests/appcache/destroyed-frame.html"); // file not found
- ignoreResultList.add("http/tests/appcache/detached-iframe.html"); // file not found
- ignoreResultList.add("http/tests/appcache/different-scheme.html"); // file not found
- ignoreResultList.add("http/tests/appcache/disabled.html"); // not found
+ ignoreResultList.add("http/tests/appcache/auth.html"); // DumpRenderTree throws exception when authentication fails
ignoreResultList.add("http/tests/appcache/empty-manifest.html"); // flaky
ignoreResultList.add("http/tests/appcache/foreign-iframe-main.html"); // flaky - skips states
- ignoreResultList.add("http/tests/appcache/max-size.html"); // no layoutTestController.setAppCacheMaximumSize
ignoreResultList.add("http/tests/appcache/manifest-with-empty-file.html"); // flaky
- ignoreResultList.add("http/tests/appcache/whitelist-wildcard.html"); // file not found
ignoreResultList.add("storage/database-lock-after-reload.html"); // Succeeds but DumpRenderTree does not read result correctly
ignoreResultList.add("storage/hash-change-with-xhr.html"); // Succeeds but DumpRenderTree does not read result correctly
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
index f535ed7..9236345 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
@@ -65,4 +65,6 @@
// For Geolocation tests
public void setGeolocationPermission(boolean allow);
+
+ public void overridePreference(String key, boolean value);
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 02a7046..24f58b2 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -61,6 +61,9 @@
static enum DumpDataType {DUMP_AS_TEXT, EXT_REPR, NO_OP}
+ // String constants for use with layoutTestController.overridePreferences
+ private final String WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED = "WebKitOfflineWebApplicationCacheEnabled";
+
public class AsyncHandler extends Handler {
@Override
public void handleMessage(Message msg) {
@@ -459,6 +462,16 @@
mGeolocationPermission = allow;
}
+ public void overridePreference(String key, boolean value) {
+ // TODO: We should look up the correct WebView for the frame which
+ // called the layoutTestController method. Currently, we just use the
+ // WebView for the main frame. EventSender suffers from the same
+ // problem.
+ if (key.equals(WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED)) {
+ mWebView.getSettings().setAppCacheEnabled(value);
+ }
+ }
+
private final WebViewClient mViewClient = new WebViewClient(){
@Override
public void onPageFinished(WebView view, String url) {