Merge "Fix bcm4329 FW dump in bugreport for user-debug build"
diff --git a/api/current.xml b/api/current.xml
index d3e673e..9dc2218 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -80540,6 +80540,17 @@
visibility="public"
>
</method>
+<method name="isBluetoothScoAvailableOffCall"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isBluetoothScoOn"
return="boolean"
abstract="false"
@@ -80860,6 +80871,28 @@
<parameter name="vibrateType" type="int">
</parameter>
</method>
+<method name="startBluetoothSco"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="stopBluetoothSco"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="unloadSoundEffects"
return="void"
abstract="false"
@@ -80895,6 +80928,17 @@
visibility="public"
>
</field>
+<field name="ACTION_SCO_AUDIO_STATE_CHANGED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.media.SCO_AUDIO_STATE_CHANGED""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ADJUST_LOWER"
type="int"
transient="false"
@@ -80950,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"
@@ -80972,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"
@@ -81005,6 +81071,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_SCO_AUDIO_STATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.media.extra.SCO_AUDIO_STATE""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_VIBRATE_SETTING"
type="java.lang.String"
transient="false"
@@ -81368,6 +81445,39 @@
visibility="public"
>
</field>
+<field name="SCO_AUDIO_STATE_CONNECTED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCO_AUDIO_STATE_DISCONNECTED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCO_AUDIO_STATE_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="STREAM_ALARM"
type="int"
transient="false"
@@ -193625,7 +193735,7 @@
visibility="public"
>
</method>
-<method name="getUseSystemOverscrollBackground"
+<method name="getUseWebViewBackgroundForOverscrollBackground"
return="boolean"
abstract="false"
native="false"
@@ -194215,7 +194325,7 @@
<parameter name="use" type="boolean">
</parameter>
</method>
-<method name="setUseSystemOverscrollBackground"
+<method name="setUseWebViewBackgroundForOverscrollBackground"
return="void"
abstract="false"
native="false"
@@ -194225,7 +194335,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="system" type="boolean">
+<parameter name="view" type="boolean">
</parameter>
</method>
<method name="setUseWideViewPort"
@@ -199610,6 +199720,8 @@
>
<implements name="android.widget.ExpandableListAdapter">
</implements>
+<implements name="android.widget.HeterogeneousExpandableList">
+</implements>
<constructor name="BaseExpandableListAdapter"
type="android.widget.BaseExpandableListAdapter"
static="false"
@@ -199629,6 +199741,32 @@
visibility="public"
>
</method>
+<method name="getChildType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="groupPosition" type="int">
+</parameter>
+<parameter name="childPosition" type="int">
+</parameter>
+</method>
+<method name="getChildTypeCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getCombinedChildId"
return="long"
abstract="false"
@@ -199657,6 +199795,30 @@
<parameter name="groupId" type="long">
</parameter>
</method>
+<method name="getGroupType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="groupPosition" type="int">
+</parameter>
+</method>
+<method name="getGroupTypeCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isEmpty"
return="boolean"
abstract="false"
@@ -203399,6 +203561,64 @@
</parameter>
</method>
</class>
+<interface name="HeterogeneousExpandableList"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getChildType"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="groupPosition" type="int">
+</parameter>
+<parameter name="childPosition" type="int">
+</parameter>
+</method>
+<method name="getChildTypeCount"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getGroupType"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="groupPosition" type="int">
+</parameter>
+</method>
+<method name="getGroupTypeCount"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</interface>
<class name="HorizontalScrollView"
extends="android.widget.FrameLayout"
abstract="false"
diff --git a/cmds/rawbu/backup.cpp b/cmds/rawbu/backup.cpp
index 394ce41..c4fa765 100644
--- a/cmds/rawbu/backup.cpp
+++ b/cmds/rawbu/backup.cpp
@@ -318,7 +318,7 @@
result = 0;
goto done;
}
- } else {
+ } else if (S_ISREG(statBuffer.st_mode)) {
printf("Saving file %s...\n", fullPath);
if (write_header(fh, TYPE_FILE, fullPath, &statBuffer) == 0) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4464ab9..f296f43 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2935,9 +2935,14 @@
private boolean writeFileLocked() {
// Rename the current file so it may be used as a backup during the next read
if (mFile.exists()) {
- if (!mFile.renameTo(mBackupFile)) {
- Log.e(TAG, "Couldn't rename file " + mFile + " to backup file " + mBackupFile);
- return false;
+ if (!mBackupFile.exists()) {
+ if (!mFile.renameTo(mBackupFile)) {
+ Log.e(TAG, "Couldn't rename file " + mFile
+ + " to backup file " + mBackupFile);
+ return false;
+ }
+ } else {
+ mFile.delete();
}
}
diff --git a/core/java/android/bluetooth/ScoSocket.java b/core/java/android/bluetooth/ScoSocket.java
index 116310a..b65a99a 100644
--- a/core/java/android/bluetooth/ScoSocket.java
+++ b/core/java/android/bluetooth/ScoSocket.java
@@ -86,14 +86,14 @@
/** Connect this SCO socket to the given BT address.
* Does not block.
*/
- public synchronized boolean connect(String address) {
+ public synchronized boolean connect(String address, String name) {
if (DBG) log("connect() " + this);
if (mState != STATE_READY) {
if (DBG) log("connect(): Bad state");
return false;
}
acquireWakeLock();
- if (connectNative(address)) {
+ if (connectNative(address, name)) {
mState = STATE_CONNECTING;
return true;
} else {
@@ -102,7 +102,7 @@
return false;
}
}
- private native boolean connectNative(String address);
+ private native boolean connectNative(String address, String name);
/** Accept incoming SCO connections.
* Does not block.
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index e9a9f31..af327c3 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -153,6 +153,12 @@
* the {@link android.R.attr#installLocation} attribute.
* @hide
*/
+ public static final int INSTALL_LOCATION_UNSPECIFIED = -1;
+ /**
+ * Constant corresponding to <code>auto</code> in
+ * the {@link android.R.attr#installLocation} attribute.
+ * @hide
+ */
public static final int INSTALL_LOCATION_AUTO = 0;
/**
* Constant corresponding to <code>internalOnly</code> in
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c33f305..3be4cebd 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -96,7 +96,8 @@
private static final Object mSync = new Object();
private static WeakReference<byte[]> mReadBuffer;
- private static boolean sCompatibilityModeEnabled = true;
+ private static boolean sCompatibilityModeEnabled = true;
+ private static final int PARSE_DEFAULT_INSTALL_LOCATION = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
static class ParsePackageItemArgs {
final Package owner;
@@ -352,6 +353,7 @@
public final static int PARSE_IGNORE_PROCESSES = 1<<3;
public final static int PARSE_FORWARD_LOCK = 1<<4;
public final static int PARSE_ON_SDCARD = 1<<5;
+ public final static int PARSE_IS_SYSTEM_DIR = 1<<6;
public int getParseError() {
return mParseError;
@@ -707,12 +709,12 @@
+ pkgName + "\": " + nameError;
return null;
}
- int installLocation = PackageInfo.INSTALL_LOCATION_AUTO;
+ int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
for (int i = 0; i < attrs.getAttributeCount(); i++) {
String attr = attrs.getAttributeName(i);
if (attr.equals("installLocation")) {
installLocation = attrs.getAttributeIntValue(i,
- PackageInfo.INSTALL_LOCATION_AUTO);
+ PARSE_DEFAULT_INSTALL_LOCATION);
break;
}
}
@@ -778,7 +780,7 @@
pkg.installLocation = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_installLocation,
- PackageInfo.INSTALL_LOCATION_AUTO);
+ PARSE_DEFAULT_INSTALL_LOCATION);
// Resource boolean are -1, so 1 means we don't know the value.
int supportsSmallScreens = 1;
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index 816f8a8..72ceb9b 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -139,7 +139,10 @@
if (SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION) {
Log.v(TAG, "** warning ** Finalized DbObj (id#" + nStatement + ")");
}
- Log.w(TAG, "finalizer should never be called on sql: " + mSqlStmt, mStackTrace);
+ int len = mSqlStmt.length();
+ Log.w(TAG, "Releasing statement in a finalizer. Please ensure " +
+ "that you explicitly call close() on your cursor: " +
+ mSqlStmt.substring(0, (len > 100) ? 100 : len), mStackTrace);
releaseSqlStatement();
} finally {
super.finalize();
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 4780cf3..a17b7fe 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -115,6 +115,9 @@
*/
public static boolean copyToFile(InputStream inputStream, File destFile) {
try {
+ if (destFile.exists()) {
+ destFile.delete();
+ }
OutputStream out = new FileOutputStream(destFile);
try {
byte[] buffer = new byte[4096];
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 837ce91..726793d 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -24,7 +24,6 @@
import android.os.Handler;
import android.os.Message;
import android.view.View;
-import android.view.Window;
/**
* Shows a hierarchy of {@link Preference} objects as
@@ -81,6 +80,8 @@
private PreferenceManager mPreferenceManager;
+ private Bundle mSavedInstanceState;
+
/**
* The starting request code given out to preference framework.
*/
@@ -137,15 +138,19 @@
@Override
protected void onRestoreInstanceState(Bundle state) {
- super.onRestoreInstanceState(state);
-
Bundle container = state.getBundle(PREFERENCES_TAG);
if (container != null) {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
preferenceScreen.restoreHierarchyState(container);
+ mSavedInstanceState = state;
+ return;
}
}
+
+ // Only call this if we didn't save the instance state for later.
+ // If we did save it, it will be restored when we bind the adapter.
+ super.onRestoreInstanceState(state);
}
@Override
@@ -176,6 +181,10 @@
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
preferenceScreen.bind(getListView());
+ if (mSavedInstanceState != null) {
+ super.onRestoreInstanceState(mSavedInstanceState);
+ mSavedInstanceState = null;
+ }
}
}
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index dda9018..1d27828 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -870,6 +870,13 @@
public static final String ARTIST = "artist";
/**
+ * The artist credited for the album that contains the audio file
+ * <P>Type: TEXT</P>
+ * @hide
+ */
+ public static final String ALBUM_ARTIST = "album_artist";
+
+ /**
* A non human readable key calculated from the ARTIST, used for
* searching, sorting and grouping
* <P>Type: TEXT</P>
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 984e48b..7e748c0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5728,7 +5728,7 @@
* of the thumb within the scrollbar's track.</p>
*
* <p>The range is expressed in arbitrary units that must be the same as the
- * units used by {@link #computeHorizontalScrollRange()} and
+ * units used by {@link #computeVerticalScrollRange()} and
* {@link #computeVerticalScrollOffset()}.</p>
*
* <p>The default extent is the drawing height of this view.</p>
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 8311bdc..2b5489c 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -546,6 +546,9 @@
recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/");
recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".traces");
try {
+ if (recyclerDump.exists()) {
+ recyclerDump.delete();
+ }
final FileOutputStream file = new FileOutputStream(recyclerDump);
final DataOutputStream out = new DataOutputStream(file);
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index c87ffee..9df8ac3 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1675,6 +1675,16 @@
return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
}
+ private static void forceLayout(View view) {
+ view.forceLayout();
+ if (view instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup) view;
+ final int count = group.getChildCount();
+ for (int i = 0; i < count; i++) {
+ forceLayout(group.getChildAt(i));
+ }
+ }
+ }
public final static int DO_TRAVERSAL = 1000;
public final static int DIE = 1001;
@@ -1862,6 +1872,10 @@
if (msg.what == RESIZED_REPORT) {
mReportNextDraw = true;
}
+
+ if (mView != null) {
+ forceLayout(mView);
+ }
requestLayout();
}
break;
diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java
index 176169e..2709cff 100644
--- a/core/java/android/view/animation/DecelerateInterpolator.java
+++ b/core/java/android/view/animation/DecelerateInterpolator.java
@@ -28,11 +28,11 @@
public class DecelerateInterpolator implements Interpolator {
public DecelerateInterpolator() {
}
-
+
/**
* Constructor
*
- * @param factor Degree to which the animation should be eased. Seting factor to 1.0f produces
+ * @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces
* an upside-down y=x^2 parabola. Increasing factor above 1.0f makes exaggerates the
* ease-out effect (i.e., it starts even faster and ends evens slower)
*/
diff --git a/core/java/android/webkit/HttpAuthHandler.java b/core/java/android/webkit/HttpAuthHandler.java
index 1c17575..6216603 100644
--- a/core/java/android/webkit/HttpAuthHandler.java
+++ b/core/java/android/webkit/HttpAuthHandler.java
@@ -19,6 +19,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.util.Log;
import java.util.ListIterator;
import java.util.LinkedList;
@@ -52,6 +53,14 @@
private static final int AUTH_PROCEED = 100;
private static final int AUTH_CANCEL = 200;
+ // Use to synchronize when making synchronous calls to
+ // onReceivedHttpAuthRequest(). We can't use a single Boolean object for
+ // both the lock and the state, because Boolean is immutable.
+ Object mRequestInFlightLock = new Object();
+ boolean mRequestInFlight;
+ String mUsername;
+ String mPassword;
+
/**
* Creates a new HTTP authentication handler with an empty
* loader queue
@@ -70,6 +79,7 @@
synchronized (mLoaderQueue) {
loader = mLoaderQueue.poll();
}
+ assert(loader.isSynchronous() == false);
switch (msg.what) {
case AUTH_PROCEED:
@@ -87,25 +97,70 @@
processNextLoader();
}
+ /**
+ * Helper method used to unblock handleAuthRequest(), which in the case of a
+ * synchronous request will wait for proxy.onReceivedHttpAuthRequest() to
+ * call back to either proceed() or cancel().
+ *
+ * @param username The username to use for authentication
+ * @param password The password to use for authentication
+ * @return True if the request is synchronous and handleAuthRequest() has
+ * been unblocked
+ */
+ private boolean handleResponseForSynchronousRequest(String username, String password) {
+ LoadListener loader = null;
+ synchronized (mLoaderQueue) {
+ loader = mLoaderQueue.peek();
+ }
+ if (loader.isSynchronous()) {
+ mUsername = username;
+ mPassword = password;
+ return true;
+ }
+ return false;
+ }
+
+ private void signalRequestComplete() {
+ synchronized (mRequestInFlightLock) {
+ assert(mRequestInFlight);
+ mRequestInFlight = false;
+ mRequestInFlightLock.notify();
+ }
+ }
/**
* Proceed with the authorization with the given credentials
*
+ * May be called on the UI thread, rather than the WebCore thread.
+ *
* @param username The username to use for authentication
* @param password The password to use for authentication
*/
public void proceed(String username, String password) {
+ if (handleResponseForSynchronousRequest(username, password)) {
+ signalRequestComplete();
+ return;
+ }
Message msg = obtainMessage(AUTH_PROCEED);
msg.getData().putString("username", username);
msg.getData().putString("password", password);
sendMessage(msg);
+ signalRequestComplete();
}
/**
* Cancel the authorization request
+ *
+ * May be called on the UI thread, rather than the WebCore thread.
+ *
*/
public void cancel() {
+ if (handleResponseForSynchronousRequest(null, null)) {
+ signalRequestComplete();
+ return;
+ }
sendMessage(obtainMessage(AUTH_CANCEL));
+ signalRequestComplete();
}
/**
@@ -132,6 +187,34 @@
* authentication request
*/
/* package */ void handleAuthRequest(LoadListener loader) {
+ // The call to proxy.onReceivedHttpAuthRequest() may be asynchronous. If
+ // the request is synchronous, we must block here until we have a
+ // response.
+ if (loader.isSynchronous()) {
+ // If there's a request in flight, wait for it to complete. The
+ // response will queue a message on this thread.
+ waitForRequestToComplete();
+ // Make a request to the proxy for this request, jumping the queue.
+ // We use the queue so that the loader is present in
+ // useHttpAuthUsernamePassword().
+ synchronized (mLoaderQueue) {
+ mLoaderQueue.addFirst(loader);
+ }
+ processNextLoader();
+ // Wait for this request to complete.
+ waitForRequestToComplete();
+ // Pop the loader from the queue.
+ synchronized (mLoaderQueue) {
+ assert(mLoaderQueue.peek() == loader);
+ mLoaderQueue.poll();
+ }
+ // Call back.
+ loader.handleAuthResponse(mUsername, mPassword);
+ // The message queued by the response from the last asynchronous
+ // request, if present, will start the next request.
+ return;
+ }
+
boolean processNext = false;
synchronized (mLoaderQueue) {
@@ -146,6 +229,21 @@
}
/**
+ * Wait for the request in flight, if any, to complete
+ */
+ private void waitForRequestToComplete() {
+ synchronized (mRequestInFlightLock) {
+ while (mRequestInFlight) {
+ try {
+ mRequestInFlightLock.wait();
+ } catch(InterruptedException e) {
+ Log.e(LOGTAG, "Interrupted while waiting for request to complete");
+ }
+ }
+ }
+ }
+
+ /**
* Process the next loader in the queue (helper method)
*/
private void processNextLoader() {
@@ -154,6 +252,11 @@
loader = mLoaderQueue.peek();
}
if (loader != null) {
+ synchronized (mRequestInFlightLock) {
+ assert(mRequestInFlight == false);
+ mRequestInFlight = true;
+ }
+
CallbackProxy proxy = loader.getFrame().getCallbackProxy();
String hostname = loader.proxyAuthenticate() ?
diff --git a/core/java/android/webkit/ViewManager.java b/core/java/android/webkit/ViewManager.java
index 4e0e081..fc5c425 100644
--- a/core/java/android/webkit/ViewManager.java
+++ b/core/java/android/webkit/ViewManager.java
@@ -18,6 +18,7 @@
import android.view.SurfaceView;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.AbsoluteLayout;
import java.util.ArrayList;
@@ -155,17 +156,18 @@
v.isFixedSize = true;
}
- AbsoluteLayout.LayoutParams lp =
- (AbsoluteLayout.LayoutParams) v.mView.getLayoutParams();
+ AbsoluteLayout.LayoutParams lp;
+ ViewGroup.LayoutParams layoutParams = v.mView.getLayoutParams();
- if (lp == null)
- lp = new AbsoluteLayout.LayoutParams(ctvD(v.width), ctvD(v.height),
- ctvX(v.x), ctvY(v.y));
- else {
+ if (layoutParams instanceof AbsoluteLayout.LayoutParams) {
+ lp = (AbsoluteLayout.LayoutParams) layoutParams;
lp.width = ctvD(v.width);
lp.height = ctvD(v.height);
lp.x = ctvX(v.x);
lp.y = ctvY(v.y);
+ } else {
+ lp = new AbsoluteLayout.LayoutParams(ctvD(v.width), ctvD(v.height),
+ ctvX(v.x), ctvY(v.y));
}
return lp;
}
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/WebView.java b/core/java/android/webkit/WebView.java
index 622d22d..8f7bf8d 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1903,15 +1903,8 @@
// Expects y in view coordinates
private int pinLocY(int y) {
if (mInOverScrollMode) return y;
- int titleH = getTitleHeight();
- // if the titlebar is still visible, just pin against 0
- if (y <= titleH) {
- return Math.max(y, 0);
- }
- // convert to 0-based coordinate (subtract the title height)
- // pin(), and then add the title height back in
- return pinLoc(y - titleH, getViewHeight(),
- computeVerticalScrollRange()) + titleH;
+ return pinLoc(y, getViewHeightWithTitle(),
+ computeVerticalScrollRange() + getTitleHeight());
}
/**
@@ -3127,13 +3120,13 @@
}
int saveCount = canvas.save();
- if (mInOverScrollMode
- && getSettings().getUseSystemOverscrollBackground()) {
+ if (mInOverScrollMode && !getSettings()
+ .getUseWebViewBackgroundForOverscrollBackground()) {
if (mOverScrollBackground == null) {
mOverScrollBackground = new Paint();
Bitmap bm = BitmapFactory.decodeResource(
mContext.getResources(),
- com.android.internal.R.drawable.pattern_underwear);
+ com.android.internal.R.drawable.status_bar_background);
mOverScrollBackground.setShader(new BitmapShader(bm,
Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
}
@@ -4203,12 +4196,6 @@
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
sendOurVisibleRect();
- // update WebKit if visible title bar height changed. The logic is same
- // as getVisibleTitleHeight.
- int titleHeight = getTitleHeight();
- if (Math.max(titleHeight - t, 0) != Math.max(titleHeight - oldt, 0)) {
- sendViewSizeZoom();
- }
}
@Override
@@ -5371,7 +5358,7 @@
private int computeMaxScrollY() {
return Math.max(computeVerticalScrollRange() + getTitleHeight()
- - getViewHeightWithTitle(), getTitleHeight());
+ - getViewHeightWithTitle(), 0);
}
public void flingScroll(int vx, int vy) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index a78429e..86011d7 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -32,6 +32,7 @@
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
@@ -2388,6 +2389,7 @@
protected void onOverscrolled(int scrollX, int scrollY,
boolean clampedX, boolean clampedY) {
mScrollY = scrollY;
+
if (clampedY) {
// Velocity is broken by hitting the limit; don't start a fling off of this.
if (mVelocityTracker != null) {
@@ -2561,7 +2563,7 @@
/**
* Tracks the decay of a fling scroll
*/
- private OverScroller mScroller;
+ private final OverScroller mScroller;
/**
* Y value reported by mScroller on the previous fling
@@ -2598,6 +2600,21 @@
void startOverfling(int initialVelocity) {
mScroller.fling(0, mScrollY, 0, initialVelocity, 0, 0, 0, 0, 0, getHeight());
+ edgeReached();
+ mTouchMode = TOUCH_MODE_OVERFLING;
+ invalidate();
+ post(this);
+ }
+
+ void edgeReached() {
+ mScroller.notifyVerticalEdgeReached(mScrollY, 0, Integer.MAX_VALUE);
+ mTouchMode = TOUCH_MODE_OVERFLING;
+ invalidate();
+ post(this);
+ }
+
+ void marginReached() {
+ mScroller.notifyVerticalBoundaryReached(mScrollY, 0);
mTouchMode = TOUCH_MODE_OVERFLING;
invalidate();
post(this);
@@ -2677,11 +2694,7 @@
overscrollBy(0, overshoot, 0, mScrollY, 0, 0,
0, getOverscrollMax(), false);
}
- float vel = scroller.getCurrVelocity();
- if (delta > 0) {
- vel = -vel;
- }
- startOverfling(Math.round(vel));
+ edgeReached();
break;
}
@@ -2738,7 +2751,7 @@
private int mBoundPos;
private int mLastSeenPos;
private int mScrollDuration;
- private int mExtraScroll;
+ private final int mExtraScroll;
PositionScroller() {
mExtraScroll = ViewConfiguration.get(mContext).getScaledFadingEdgeLength();
@@ -3977,7 +3990,7 @@
for (int i = 0; i < count; i++) {
if (activeViews[i] != null) {
result = false;
- android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
+ Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
"AbsListView " + this + " has a view in its active recycler: " +
activeViews[i]);
}
@@ -4005,12 +4018,12 @@
final View view = scrap.get(i);
if (view.getParent() != null) {
result = false;
- android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, "AbsListView " + this +
+ Log.d(ViewDebug.CONSISTENCY_LOG_TAG, "AbsListView " + this +
" has a view in its scrap heap still attached to a parent: " + view);
}
if (indexOfChild(view) >= 0) {
result = false;
- android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, "AbsListView " + this +
+ Log.d(ViewDebug.CONSISTENCY_LOG_TAG, "AbsListView " + this +
" has a view in its scrap heap that is also a direct child: " + view);
}
}
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 5b52107..eb2da71 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -1629,7 +1629,10 @@
// of iterating throught he list of observers.
post(new Runnable() {
public void run() {
- updateDropDownForFilter(mAdapter.getCount());
+ final ListAdapter adapter = mAdapter;
+ if (adapter != null) {
+ updateDropDownForFilter(adapter.getCount());
+ }
}
});
}
diff --git a/core/java/android/widget/BaseExpandableListAdapter.java b/core/java/android/widget/BaseExpandableListAdapter.java
index 1bba7f0..396b7ae 100644
--- a/core/java/android/widget/BaseExpandableListAdapter.java
+++ b/core/java/android/widget/BaseExpandableListAdapter.java
@@ -18,7 +18,6 @@
import android.database.DataSetObservable;
import android.database.DataSetObserver;
-import android.view.KeyEvent;
/**
* Base class for a {@link ExpandableListAdapter} used to provide data and Views
@@ -31,7 +30,8 @@
* @see SimpleExpandableListAdapter
* @see SimpleCursorTreeAdapter
*/
-public abstract class BaseExpandableListAdapter implements ExpandableListAdapter {
+public abstract class BaseExpandableListAdapter implements ExpandableListAdapter,
+ HeterogeneousExpandableList {
private final DataSetObservable mDataSetObservable = new DataSetObservable();
public void registerDataSetObserver(DataSetObserver observer) {
@@ -102,5 +102,37 @@
public boolean isEmpty() {
return getGroupCount() == 0;
}
-
+
+
+ /**
+ * {@inheritDoc}
+ * @return 0 for any group or child position, since only one child type count is declared.
+ */
+ public int getChildType(int groupPosition, int childPosition) {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @return 1 as a default value in BaseExpandableListAdapter.
+ */
+ public int getChildTypeCount() {
+ return 1;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @return 0 for any groupPosition, since only one group type count is declared.
+ */
+ public int getGroupType(int groupPosition) {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @return 1 as a default value in BaseExpandableListAdapter.
+ */
+ public int getGroupTypeCount() {
+ return 1;
+ }
}
diff --git a/core/java/android/widget/ExpandableListAdapter.java b/core/java/android/widget/ExpandableListAdapter.java
index b75983c..7f6781b 100644
--- a/core/java/android/widget/ExpandableListAdapter.java
+++ b/core/java/android/widget/ExpandableListAdapter.java
@@ -17,7 +17,6 @@
package android.widget;
import android.database.DataSetObserver;
-import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -108,7 +107,7 @@
/**
* Gets a View that displays the given group. This View is only for the
* group--the Views for the group's children will be fetched using
- * getChildrenView.
+ * {@link #getChildView(int, int, boolean, View, ViewGroup)}.
*
* @param groupPosition the position of the group for which the View is
* returned
diff --git a/core/java/android/widget/ExpandableListConnector.java b/core/java/android/widget/ExpandableListConnector.java
index 01d3a4a..2ff6b70 100644
--- a/core/java/android/widget/ExpandableListConnector.java
+++ b/core/java/android/widget/ExpandableListConnector.java
@@ -442,8 +442,8 @@
View retValue;
if (posMetadata.position.type == ExpandableListPosition.GROUP) {
- retValue = mExpandableListAdapter.getGroupView(posMetadata.position.groupPos, posMetadata
- .isExpanded(), convertView, parent);
+ retValue = mExpandableListAdapter.getGroupView(posMetadata.position.groupPos,
+ posMetadata.isExpanded(), convertView, parent);
} else if (posMetadata.position.type == ExpandableListPosition.CHILD) {
final boolean isLastChild = posMetadata.groupMetadata.lastChildFlPos == flatListPos;
@@ -464,10 +464,21 @@
final ExpandableListPosition pos = getUnflattenedPos(flatListPos).position;
int retValue;
- if (pos.type == ExpandableListPosition.GROUP) {
- retValue = 0;
+ if (mExpandableListAdapter instanceof HeterogeneousExpandableList) {
+ HeterogeneousExpandableList adapter =
+ (HeterogeneousExpandableList) mExpandableListAdapter;
+ if (pos.type == ExpandableListPosition.GROUP) {
+ retValue = adapter.getGroupType(pos.groupPos);
+ } else {
+ final int childType = adapter.getChildType(pos.groupPos, pos.childPos);
+ retValue = adapter.getGroupTypeCount() + childType;
+ }
} else {
- retValue = 1;
+ if (pos.type == ExpandableListPosition.GROUP) {
+ retValue = 0;
+ } else {
+ retValue = 1;
+ }
}
pos.recycle();
@@ -477,7 +488,13 @@
@Override
public int getViewTypeCount() {
- return 2;
+ if (mExpandableListAdapter instanceof HeterogeneousExpandableList) {
+ HeterogeneousExpandableList adapter =
+ (HeterogeneousExpandableList) mExpandableListAdapter;
+ return adapter.getGroupTypeCount() + adapter.getChildTypeCount();
+ } else {
+ return 2;
+ }
}
@Override
diff --git a/core/java/android/widget/HeterogeneousExpandableList.java b/core/java/android/widget/HeterogeneousExpandableList.java
new file mode 100644
index 0000000..1292733
--- /dev/null
+++ b/core/java/android/widget/HeterogeneousExpandableList.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Additional methods that when implemented make an
+ * {@link ExpandableListAdapter} take advantage of the {@link Adapter} view type
+ * mechanism.
+ *
+ * An {@link ExpandableListAdapter} declares one view type for its group items
+ * and one view type for its child items. Although adapted for most {@link ExpandableListView}s,
+ * these values should be tuned heterogeneous {@link ExpandableListView}s. Lists that contain
+ * different types of group and/or child item views, should use an adapter that implements this
+ * interface. This way, the recycled views that will be provided to
+ * {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
+ * and
+ * {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
+ * will be of the appropriate group or child type, resulting in a more efficient reuse of the
+ * previously created views.
+ */
+public interface HeterogeneousExpandableList {
+ /**
+ * Get the type of group View that will be created by
+ * {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
+ * . for the specified group item.
+ *
+ * @param groupPosition the position of the group for which the type should be returned.
+ * @return An integer representing the type of group View. Two group views should share the same
+ * type if one can be converted to the other in
+ * {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
+ * . Note: Integers must be in the range 0 to {@link #getGroupTypeCount} - 1.
+ * {@link android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE} can also be returned.
+ * @see android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE
+ * @see getGroupTypeCount()
+ */
+ int getGroupType(int groupPosition);
+
+ /**
+ * Get the type of child View that will be created by
+ * {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
+ * for the specified child item.
+ *
+ * @param groupPosition the position of the group that the child resides in
+ * @param childPosition the position of the child with respect to other children in the group
+ * @return An integer representing the type of child View. Two child views should share the same
+ * type if one can be converted to the other in
+ * {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
+ * Note: Integers must be in the range 0 to {@link #getChildTypeCount} - 1.
+ * {@link android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE} can also be returned.
+ * @see android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE
+ * @see getChildTypeCount()
+ */
+ int getChildType(int groupPosition, int childPosition);
+
+ /**
+ * <p>
+ * Returns the number of types of group Views that will be created by
+ * {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
+ * . Each type represents a set of views that can be converted in
+ * {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
+ * . If the adapter always returns the same type of View for all group items, this method should
+ * return 1.
+ * </p>
+ * <p>
+ * This method will only be called when the adapter is set on the {@link AdapterView}.
+ * </p>
+ *
+ * @return The number of types of group Views that will be created by this adapter.
+ * @see getChildTypeCount()
+ * @see getGroupType()
+ */
+ int getGroupTypeCount();
+
+ /**
+ * <p>
+ * Returns the number of types of child Views that will be created by
+ * {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
+ * . Each type represents a set of views that can be converted in
+ * {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
+ * , for any group. If the adapter always returns the same type of View for
+ * all child items, this method should return 1.
+ * </p>
+ * <p>
+ * This method will only be called when the adapter is set on the {@link AdapterView}.
+ * </p>
+ *
+ * @return The total number of types of child Views that will be created by this adapter.
+ * @see getGroupTypeCount()
+ * @see getChildType()
+ */
+ int getChildTypeCount();
+}
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index 8469c8b..6258024 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -17,8 +17,8 @@
package android.widget;
import android.content.Context;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
/**
* This class encapsulates scrolling with the ability to overshoot the bounds
@@ -27,110 +27,34 @@
*
* @hide Pending API approval
*/
-public class OverScroller {
- private static final int SPRINGBACK_DURATION = 150;
- private static final int OVERFLING_DURATION = 150;
-
- private static final int MODE_DEFAULT = 0;
- private static final int MODE_OVERFLING = 1;
- private static final int MODE_SPRINGBACK = 2;
-
- private Scroller mDefaultScroller;
- private Scroller mDecelScroller;
- private Scroller mAccelDecelScroller;
- private Scroller mCurrScroller;
-
- private int mScrollMode = MODE_DEFAULT;
-
- private int mMinimumX;
- private int mMinimumY;
- private int mMaximumX;
- private int mMaximumY;
-
- public OverScroller(Context context) {
- mDefaultScroller = new Scroller(context);
- mDecelScroller = new Scroller(context, new DecelerateInterpolator());
- mAccelDecelScroller = new Scroller(context, new AccelerateDecelerateInterpolator());
- mCurrScroller = mDefaultScroller;
- }
-
+public class OverScroller extends Scroller {
+
+ // Identical to mScrollers, but casted to MagneticOverScroller.
+ private MagneticOverScroller mOverScrollerX;
+ private MagneticOverScroller mOverScrollerY;
+
/**
- * Call this when you want to know the new location. If it returns true,
- * the animation is not yet finished. loc will be altered to provide the
- * new location.
- */
- public boolean computeScrollOffset() {
- boolean inProgress = mCurrScroller.computeScrollOffset();
-
- switch (mScrollMode) {
- case MODE_OVERFLING:
- if (!inProgress) {
- // Overfling ended
- if (springback(mCurrScroller.getCurrX(), mCurrScroller.getCurrY(),
- mMinimumX, mMaximumX, mMinimumY, mMaximumY, mAccelDecelScroller)) {
- return mCurrScroller.computeScrollOffset();
- } else {
- mCurrScroller = mDefaultScroller;
- mScrollMode = MODE_DEFAULT;
- }
- }
- break;
-
- case MODE_SPRINGBACK:
- if (!inProgress) {
- mCurrScroller = mDefaultScroller;
- mScrollMode = MODE_DEFAULT;
- }
- break;
-
- case MODE_DEFAULT:
- // Fling/autoscroll - did we go off the edge?
- if (inProgress) {
- Scroller scroller = mCurrScroller;
- final int x = scroller.getCurrX();
- final int y = scroller.getCurrY();
- final int minX = mMinimumX;
- final int maxX = mMaximumX;
- final int minY = mMinimumY;
- final int maxY = mMaximumY;
- if (x < minX || x > maxX || y < minY || y > maxY) {
- final int startx = scroller.getStartX();
- final int starty = scroller.getStartY();
- final int time = scroller.timePassed();
- final float timeSecs = time / 1000.f;
- final float xvel = ((x - startx) / timeSecs);
- final float yvel = ((y - starty) / timeSecs);
-
- if ((x < minX && xvel > 0) || (y < minY && yvel > 0) ||
- (x > maxX && xvel < 0) || (y > maxY && yvel < 0)) {
- // If our velocity would take us back into valid areas,
- // try to springback rather than overfling.
- if (springback(x, y, minX, maxX, minY, maxY)) {
- return mCurrScroller.computeScrollOffset();
- }
- } else {
- overfling(x, y, xvel, yvel);
- return mCurrScroller.computeScrollOffset();
- }
- }
- }
- break;
- }
-
- return inProgress;
+ * Creates an OverScroller with a viscous fluid scroll interpolator.
+ * @param context
+ */
+ public OverScroller(Context context) {
+ this(context, null);
}
-
- private void overfling(int startx, int starty, float xvel, float yvel) {
- Scroller scroller = mDecelScroller;
- final float durationSecs = (OVERFLING_DURATION / 1000.f);
- int dx = (int)(xvel * durationSecs) / 8;
- int dy = (int)(yvel * durationSecs) / 8;
- mCurrScroller.abortAnimation();
- scroller.startScroll(startx, starty, dx, dy, OVERFLING_DURATION);
- mCurrScroller = scroller;
- mScrollMode = MODE_OVERFLING;
+
+ /**
+ * Creates a Scroller with the specified interpolator. If the interpolator is
+ * null, the default (viscous) interpolator will be used.
+ */
+ public OverScroller(Context context, Interpolator interpolator) {
+ super(context, interpolator);
}
-
+
+ @Override
+ void instantiateScrollers() {
+ mScrollerX = mOverScrollerX = new MagneticOverScroller();
+ mScrollerY = mOverScrollerY = new MagneticOverScroller();
+ }
+
/**
* Call this when you want to 'spring back' into a valid coordinate range.
*
@@ -140,310 +64,262 @@
* @param maxX Maximum valid X value
* @param minY Minimum valid Y value
* @param maxY Minimum valid Y value
- * @return true if a springback was initiated, false if startX/startY was
+ * @return true if a springback was initiated, false if startX and startY were
* already within the valid range.
*/
- public boolean springback(int startX, int startY, int minX, int maxX,
- int minY, int maxY) {
- return springback(startX, startY, minX, maxX, minY, maxY, mDecelScroller);
- }
-
- private boolean springback(int startX, int startY, int minX, int maxX,
- int minY, int maxY, Scroller scroller) {
- int xoff = 0;
- int yoff = 0;
- if (startX < minX) {
- xoff = minX - startX;
- } else if (startX > maxX) {
- xoff = maxX - startX;
- }
- if (startY < minY) {
- yoff = minY - startY;
- } else if (startY > maxY) {
- yoff = maxY - startY;
- }
-
- if (xoff != 0 || yoff != 0) {
- mCurrScroller.abortAnimation();
- scroller.startScroll(startX, startY, xoff, yoff, SPRINGBACK_DURATION);
- mCurrScroller = scroller;
- mScrollMode = MODE_SPRINGBACK;
- return true;
- }
-
- return false;
+ public boolean springback(int startX, int startY, int minX, int maxX, int minY, int maxY) {
+ mMode = FLING_MODE;
+ return mOverScrollerX.springback(startX, minX, maxX)
+ || mOverScrollerY.springback(startY, minY, maxY);
}
- /**
- *
- * Returns whether the scroller has finished scrolling.
- *
- * @return True if the scroller has finished scrolling, false otherwise.
- */
- public final boolean isFinished() {
- return mCurrScroller.isFinished();
- }
-
- /**
- * Returns the current X offset in the scroll.
- *
- * @return The new X offset as an absolute distance from the origin.
- */
- public final int getCurrX() {
- return mCurrScroller.getCurrX();
- }
-
- /**
- * Returns the current Y offset in the scroll.
- *
- * @return The new Y offset as an absolute distance from the origin.
- */
- public final int getCurrY() {
- return mCurrScroller.getCurrY();
- }
-
- /**
- * Stops the animation, resets any springback/overfling and completes
- * any standard flings/scrolls in progress.
- */
- public void abortAnimation() {
- mCurrScroller.abortAnimation();
- mCurrScroller = mDefaultScroller;
- mScrollMode = MODE_DEFAULT;
- mCurrScroller.abortAnimation();
- }
-
- /**
- * Start scrolling by providing a starting point and the distance to travel.
- * The scroll will use the default value of 250 milliseconds for the
- * duration. This version does not spring back to boundaries.
- *
- * @param startX Starting horizontal scroll offset in pixels. Positive
- * numbers will scroll the content to the left.
- * @param startY Starting vertical scroll offset in pixels. Positive numbers
- * will scroll the content up.
- * @param dx Horizontal distance to travel. Positive numbers will scroll the
- * content to the left.
- * @param dy Vertical distance to travel. Positive numbers will scroll the
- * content up.
- */
- public void startScroll(int startX, int startY, int dx, int dy) {
- final int minX = Math.min(startX, startX + dx);
- final int maxX = Math.max(startX, startX + dx);
- final int minY = Math.min(startY, startY + dy);
- final int maxY = Math.max(startY, startY + dy);
- startScroll(startX, startY, dx, dy, minX, maxX, minY, maxY);
- }
-
- /**
- * Start scrolling by providing a starting point and the distance to travel.
- * The scroll will use the default value of 250 milliseconds for the
- * duration. This version will spring back to the provided boundaries if
- * the scroll value would take it too far.
- *
- * @param startX Starting horizontal scroll offset in pixels. Positive
- * numbers will scroll the content to the left.
- * @param startY Starting vertical scroll offset in pixels. Positive numbers
- * will scroll the content up.
- * @param dx Horizontal distance to travel. Positive numbers will scroll the
- * content to the left.
- * @param dy Vertical distance to travel. Positive numbers will scroll the
- * content up.
- * @param minX Minimum X value. The scroller will not scroll past this
- * point.
- * @param maxX Maximum X value. The scroller will not scroll past this
- * point.
- * @param minY Minimum Y value. The scroller will not scroll past this
- * point.
- * @param maxY Maximum Y value. The scroller will not scroll past this
- * point.
- */
- public void startScroll(int startX, int startY, int dx, int dy,
- int minX, int maxX, int minY, int maxY) {
- mCurrScroller.abortAnimation();
- mCurrScroller = mDefaultScroller;
- mScrollMode = MODE_DEFAULT;
- mMinimumX = minX;
- mMaximumX = maxX;
- mMinimumY = minY;
- mMaximumY = maxY;
- mCurrScroller.startScroll(startX, startY, dx, dy);
- }
-
- /**
- * Start scrolling by providing a starting point and the distance to travel.
- *
- * @param startX Starting horizontal scroll offset in pixels. Positive
- * numbers will scroll the content to the left.
- * @param startY Starting vertical scroll offset in pixels. Positive numbers
- * will scroll the content up.
- * @param dx Horizontal distance to travel. Positive numbers will scroll the
- * content to the left.
- * @param dy Vertical distance to travel. Positive numbers will scroll the
- * content up.
- * @param duration Duration of the scroll in milliseconds.
- */
- public void startScroll(int startX, int startY, int dx, int dy, int duration) {
- mCurrScroller.abortAnimation();
- mCurrScroller = mDefaultScroller;
- mScrollMode = MODE_DEFAULT;
- mMinimumX = Math.min(startX, startX + dx);
- mMinimumY = Math.min(startY, startY + dy);
- mMaximumX = Math.max(startX, startX + dx);
- mMaximumY = Math.max(startY, startY + dy);
- mCurrScroller.startScroll(startX, startY, dx, dy, duration);
- }
-
- /**
- * Returns the duration of the active scroll in progress; standard, fling,
- * springback, or overfling. Does not account for any overflings or springback
- * that may result.
- */
- public int getDuration() {
- return mCurrScroller.getDuration();
- }
-
- /**
- * Start scrolling based on a fling gesture. The distance travelled will
- * depend on the initial velocity of the fling.
- *
- * @param startX Starting point of the scroll (X)
- * @param startY Starting point of the scroll (Y)
- * @param velocityX Initial velocity of the fling (X) measured in pixels per
- * second.
- * @param velocityY Initial velocity of the fling (Y) measured in pixels per
- * second
- * @param minX Minimum X value. The scroller will not scroll past this
- * point.
- * @param maxX Maximum X value. The scroller will not scroll past this
- * point.
- * @param minY Minimum Y value. The scroller will not scroll past this
- * point.
- * @param maxY Maximum Y value. The scroller will not scroll past this
- * point.
- */
+ @Override
public void fling(int startX, int startY, int velocityX, int velocityY,
int minX, int maxX, int minY, int maxY) {
- this.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, 0, 0);
+ fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, 0, 0);
}
/**
- * Start scrolling based on a fling gesture. The distance travelled will
+ * Start scrolling based on a fling gesture. The distance traveled will
* depend on the initial velocity of the fling.
*
* @param startX Starting point of the scroll (X)
* @param startY Starting point of the scroll (Y)
* @param velocityX Initial velocity of the fling (X) measured in pixels per
- * second.
+ * second.
* @param velocityY Initial velocity of the fling (Y) measured in pixels per
- * second
- * @param minX Minimum X value. The scroller will not scroll past this
- * point unless overX > 0. If overfling is allowed, it will use minX
- * as a springback boundary.
- * @param maxX Maximum X value. The scroller will not scroll past this
- * point unless overX > 0. If overfling is allowed, it will use maxX
- * as a springback boundary.
- * @param minY Minimum Y value. The scroller will not scroll past this
- * point unless overY > 0. If overfling is allowed, it will use minY
- * as a springback boundary.
- * @param maxY Maximum Y value. The scroller will not scroll past this
- * point unless overY > 0. If overfling is allowed, it will use maxY
- * as a springback boundary.
+ * second
+ * @param minX Minimum X value. The scroller will not scroll past this point
+ * unless overX > 0. If overfling is allowed, it will use minX as
+ * a springback boundary.
+ * @param maxX Maximum X value. The scroller will not scroll past this point
+ * unless overX > 0. If overfling is allowed, it will use maxX as
+ * a springback boundary.
+ * @param minY Minimum Y value. The scroller will not scroll past this point
+ * unless overY > 0. If overfling is allowed, it will use minY as
+ * a springback boundary.
+ * @param maxY Maximum Y value. The scroller will not scroll past this point
+ * unless overY > 0. If overfling is allowed, it will use maxY as
+ * a springback boundary.
* @param overX Overfling range. If > 0, horizontal overfling in either
- * direction will be possible.
+ * direction will be possible.
* @param overY Overfling range. If > 0, vertical overfling in either
- * direction will be possible.
+ * direction will be possible.
*/
public void fling(int startX, int startY, int velocityX, int velocityY,
int minX, int maxX, int minY, int maxY, int overX, int overY) {
- mCurrScroller = mDefaultScroller;
- mScrollMode = MODE_DEFAULT;
- mMinimumX = minX;
- mMaximumX = maxX;
- mMinimumY = minY;
- mMaximumY = maxY;
- mCurrScroller.fling(startX, startY, velocityX, velocityY,
- minX - overX, maxX + overX, minY - overY, maxY + overY);
+ mMode = FLING_MODE;
+ mOverScrollerX.fling(startX, velocityX, minX, maxX, overX);
+ mOverScrollerY.fling(startY, velocityY, minY, maxY, overY);
+ }
+
+ void notifyHorizontalBoundaryReached(int startX, int finalX) {
+ mOverScrollerX.springback(startX, finalX, finalX);
+ }
+
+ void notifyVerticalBoundaryReached(int startY, int finalY) {
+ mOverScrollerY.springback(startY, finalY, finalY);
+ }
+
+ void notifyHorizontalEdgeReached(int startX, int finalX, int overX) {
+ mOverScrollerX.notifyEdgeReached(startX, finalX, overX);
+ }
+
+ void notifyVerticalEdgeReached(int startY, int finalY, int overY) {
+ mOverScrollerY.notifyEdgeReached(startY, finalY, overY);
}
/**
- * Returns where the scroll will end. Valid only for "fling" scrolls.
+ * Returns whether the current Scroller position is overscrolled or still within the minimum and
+ * maximum bounds provided in the
+ * {@link #fling(int, int, int, int, int, int, int, int, int, int)} method.
*
- * @return The final X offset as an absolute distance from the origin.
- */
- public int getFinalX() {
- return mCurrScroller.getFinalX();
- }
-
- /**
- * Returns where the scroll will end. Valid only for "fling" scrolls.
+ * One should check this value before calling
+ * {@link startScroll(int, int, int, int)} as the interpolation currently in progress to restore
+ * a valid position will then be stopped. The caller has to take into account the fact that the
+ * started scroll will start from an overscrolled position.
*
- * @return The final Y offset as an absolute distance from the origin.
+ * @return true when the current position is overscrolled.
*/
- public int getFinalY() {
- return mCurrScroller.getFinalY();
+ public boolean isOverscrolled() {
+ return ((!mOverScrollerX.mFinished && mOverScrollerX.mState != MagneticOverScroller.TO_EDGE) ||
+ (!mOverScrollerY.mFinished && mOverScrollerY.mState != MagneticOverScroller.TO_EDGE));
}
-
- /**
- * @hide
- * Returns the current velocity.
- *
- * @return The original velocity less the deceleration. Result may be
- * negative.
- */
- public float getCurrVelocity() {
- return mCurrScroller.getCurrVelocity();
- }
-
- /**
- * Extend the scroll animation. This allows a running animation to scroll
- * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}.
- *
- * @param extend Additional time to scroll in milliseconds.
- * @see #setFinalX(int)
- * @see #setFinalY(int)
- */
- public void extendDuration(int extend) {
- if (mScrollMode == MODE_DEFAULT) {
- mDefaultScroller.extendDuration(extend);
+
+ static class MagneticOverScroller extends Scroller.MagneticScroller {
+ private static final int TO_EDGE = 0;
+ private static final int TO_BOUNDARY = 1;
+ private static final int TO_BOUNCE = 2;
+
+ private int mState = TO_EDGE;
+
+ // The allowed overshot distance before boundary is reached.
+ private int mOver;
+
+ // When the scroll goes beyond the edges limits, the deceleration is
+ // multiplied by this coefficient, so that the return to a valid
+ // position is faster.
+ private static final float OVERSCROLL_DECELERATION_COEF = 16.0f;
+
+ // If the velocity is smaller than this value, no bounce is triggered
+ // when the edge limits are reached (would result in a zero pixels
+ // displacement anyway).
+ private static final float MINIMUM_VELOCITY_FOR_BOUNCE = 200.0f;
+
+ // Could be made public for tuning, but applications would no longer
+ // have the same look and feel.
+ private static final float BOUNCE_COEFFICIENT = 0.4f;
+
+ /*
+ * Get a signed deceleration that will reduce the velocity.
+ */
+ @Override
+ float getDeceleration(int velocity) {
+ float decelerationY = super.getDeceleration(velocity);
+ if (mState != TO_EDGE) {
+ decelerationY *= OVERSCROLL_DECELERATION_COEF;
+ }
+ return decelerationY;
}
- }
-
- /**
- * Sets the final position (X) for this scroller.
- *
- * @param newX The new X offset as an absolute distance from the origin.
- * @see #extendDuration(int)
- * @see #setFinalY(int)
- */
- public void setFinalX(int newX) {
- if (mScrollMode == MODE_DEFAULT) {
- if (newX < mMinimumX) {
- mMinimumX = newX;
+
+ boolean springback(int start, int min, int max) {
+ mFinished = true;
+
+ mStart = start;
+ mVelocity = 0;
+
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+ mDuration = 0;
+
+ if (start < min) {
+ startSpringback(start, min, -1);
+ } else if (start > max) {
+ startSpringback(start, max, 1);
}
- if (newX > mMaximumX) {
- mMaximumX = newX;
- }
- mDefaultScroller.setFinalX(newX);
+
+ return !mFinished;
}
- }
-
- /**
- * Sets the final position (Y) for this scroller.
- *
- * @param newY The new Y offset as an absolute distance from the origin.
- * @see #extendDuration(int)
- * @see #setFinalX(int)
- */
- public void setFinalY(int newY) {
- if (mScrollMode == MODE_DEFAULT) {
- if (newY < mMinimumY) {
- mMinimumY = newY;
+
+ private void startSpringback(int start, int end, int sign) {
+ mFinished = false;
+ mState = TO_BOUNCE;
+ mDeceleration = getDeceleration(sign);
+ mFinal = end;
+ mDuration = (int) (1000.0f * Math.sqrt(2.0f * (end - start) / mDeceleration));
+ }
+
+ void fling(int start, int velocity, int min, int max, int over) {
+ mState = TO_EDGE;
+ mOver = over;
+
+ super.fling(start, velocity, min, max);
+
+ if (mStart > max) {
+ if (mStart >= max + over) {
+ springback(max + over, min, max);
+ } else {
+ // Make sure the deceleration brings us back to edge
+ mVelocity = velocity > 0 ? velocity : -velocity;
+ mCurrVelocity = velocity;
+ notifyEdgeReached(start, max, over);
+ }
+ } else {
+ if (mStart < min) {
+ if (mStart <= min - over) {
+ springback(min - over, min, max);
+ } else {
+ // Make sure the deceleration brings us back to edge
+ mVelocity = velocity < 0 ? velocity : -velocity;
+ mCurrVelocity = velocity;
+ notifyEdgeReached(start, min, over);
+ }
+ }
}
- if (newY > mMaximumY) {
- mMaximumY = newY;
+ }
+
+ void notifyEdgeReached(int start, int end, int over) {
+ // Compute post-edge deceleration
+ mState = TO_BOUNDARY;
+ mDeceleration = getDeceleration(mVelocity);
+
+ // Local time, used to compute edge crossing time.
+ float timeCurrent = mCurrVelocity / mDeceleration;
+ final int distance = end - start;
+ float timeEdge = -(float) Math.sqrt((2.0f * distance / mDeceleration)
+ + (timeCurrent * timeCurrent));
+
+ mVelocity = (int) (mDeceleration * timeEdge);
+
+ // Simulate a symmetric bounce that started from edge
+ mStart = end;
+
+ mOver = over;
+
+ long time = AnimationUtils.currentAnimationTimeMillis();
+ mStartTime = (int) (time - 1000.0f * (timeCurrent - timeEdge));
+
+ onEdgeReached();
+ }
+
+ void onEdgeReached() {
+ // mStart, mVelocity and mStartTime were adjusted to their values when edge was reached.
+ mState = TO_BOUNDARY;
+ mDeceleration = getDeceleration(mVelocity);
+
+ int distance = Math.round((mVelocity * mVelocity) / (2.0f * mDeceleration));
+
+ if (Math.abs(distance) < mOver) {
+ // Deceleration will bring us back to final position
+ mState = TO_BOUNCE;
+ mFinal = mStart;
+ mDuration = (int) (-2000.0f * mVelocity / mDeceleration);
+ } else {
+ // Velocity is too high, we will hit the boundary limit
+ mFinal = mStart + (mVelocity > 0 ? mOver : -mOver);
+ mDuration = computeDuration(mStart, mFinal, mVelocity, mDeceleration);
}
- mDefaultScroller.setFinalY(newY);
+ }
+
+ @Override
+ boolean continueWhenFinished() {
+ switch (mState) {
+ case TO_EDGE:
+ // Duration from start to null velocity
+ int duration = (int) (-1000.0f * mVelocity / mDeceleration);
+ if (mDuration < duration) {
+ // If the animation was clamped, we reached the edge
+ mStart = mFinal;
+ // Speed when edge was reached
+ mVelocity = (int) (mVelocity + mDeceleration * mDuration / 1000.0f);
+ mStartTime += mDuration;
+ onEdgeReached();
+ } else {
+ // Normal stop, no need to continue
+ return false;
+ }
+ break;
+ case TO_BOUNDARY:
+ mStartTime += mDuration;
+ mStart = mFinal;
+ mFinal = mStart - (mVelocity > 0 ? mOver : -mOver);
+ mVelocity = 0;
+ mDuration = (int) (1000.0f * Math.sqrt(Math.abs(2.0f * mOver / mDeceleration)));
+ mState = TO_BOUNCE;
+ break;
+ case TO_BOUNCE:
+ float edgeVelocity = mVelocity + mDeceleration * mDuration / 1000.0f;
+ mVelocity = (int) (-edgeVelocity * BOUNCE_COEFFICIENT);
+ if (Math.abs(mVelocity) < MINIMUM_VELOCITY_FOR_BOUNCE) {
+ return false;
+ }
+ mStart = mFinal;
+ mStartTime += mDuration;
+ mDuration = (int) (-2000.0f * mVelocity / mDeceleration);
+ break;
+ }
+
+ update();
+ return true;
}
}
}
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 68c0ff0..239c5f4 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -1272,7 +1272,7 @@
* Fling the scroll view
*
* @param velocityY The initial velocity in the Y direction. Positive
- * numbers mean that the finger/curor is moving down the screen,
+ * numbers mean that the finger/cursor is moving down the screen,
* which means we want to scroll towards the top.
*/
public void fling(int velocityY) {
@@ -1307,6 +1307,7 @@
*
* <p>This version also clamps the scrolling to the bounds of our child.
*/
+ @Override
public void scrollTo(int x, int y) {
// we rely on the fact the View.scrollBy calls scrollTo.
if (getChildCount() > 0) {
diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java
index 11dab02..542866a 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -16,8 +16,10 @@
package android.widget;
+
import android.content.Context;
import android.hardware.SensorManager;
+import android.util.FloatMath;
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -25,48 +27,34 @@
/**
* This class encapsulates scrolling. The duration of the scroll
- * can be passed in the constructor and specifies the maximum time that
- * the scrolling animation should take. Past this time, the scrolling is
- * automatically moved to its final stage and computeScrollOffset()
- * will always return false to indicate that scrolling is over.
+ * is either specified along with the distance or depends on the initial fling velocity.
+ * Past this time, the scrolling is automatically moved to its final stage and
+ * computeScrollOffset() will always return false to indicate that scrolling is over.
*/
public class Scroller {
- private int mMode;
+ int mMode;
- private int mStartX;
- private int mStartY;
- private int mFinalX;
- private int mFinalY;
+ MagneticScroller mScrollerX;
+ MagneticScroller mScrollerY;
- private int mMinX;
- private int mMaxX;
- private int mMinY;
- private int mMaxY;
+ private final Interpolator mInterpolator;
- private int mCurrX;
- private int mCurrY;
- private long mStartTime;
- private int mDuration;
- private float mDurationReciprocal;
- private float mDeltaX;
- private float mDeltaY;
- private float mViscousFluidScale;
- private float mViscousFluidNormalize;
- private boolean mFinished;
- private Interpolator mInterpolator;
+ static final int DEFAULT_DURATION = 250;
+ static final int SCROLL_MODE = 0;
+ static final int FLING_MODE = 1;
- private float mCoeffX = 0.0f;
- private float mCoeffY = 1.0f;
- private float mVelocity;
+ // This controls the viscous fluid effect (how much of it)
+ private final static float VISCOUS_FLUID_SCALE = 8.0f;
+ private static float VISCOUS_FLUID_NORMALIZE;
- private static final int DEFAULT_DURATION = 250;
- private static final int SCROLL_MODE = 0;
- private static final int FLING_MODE = 1;
-
- private final float mDeceleration;
+ static {
+ // Set a neutral value that will be used in the next call to viscousFluid().
+ VISCOUS_FLUID_NORMALIZE = 1.0f;
+ VISCOUS_FLUID_NORMALIZE = 1.0f / viscousFluid(1.0f);
+ }
/**
- * Create a Scroller with the default duration and interpolator.
+ * Create a Scroller with a viscous fluid scroll interpolator.
*/
public Scroller(Context context) {
this(context, null);
@@ -77,15 +65,17 @@
* null, the default (viscous) interpolator will be used.
*/
public Scroller(Context context, Interpolator interpolator) {
- mFinished = true;
+ instantiateScrollers();
+ MagneticScroller.initializeFromContext(context);
+
mInterpolator = interpolator;
- float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
- mDeceleration = SensorManager.GRAVITY_EARTH // g (m/s^2)
- * 39.37f // inch/meter
- * ppi // pixels per inch
- * ViewConfiguration.getScrollFriction();
}
+ void instantiateScrollers() {
+ mScrollerX = new MagneticScroller();
+ mScrollerY = new MagneticScroller();
+ }
+
/**
*
* Returns whether the scroller has finished scrolling.
@@ -93,150 +83,148 @@
* @return True if the scroller has finished scrolling, false otherwise.
*/
public final boolean isFinished() {
- return mFinished;
+ return mScrollerX.mFinished && mScrollerY.mFinished;
}
-
+
/**
* Force the finished field to a particular value.
- *
+ *
* @param finished The new finished value.
*/
public final void forceFinished(boolean finished) {
- mFinished = finished;
+ mScrollerX.mFinished = mScrollerY.mFinished = finished;
}
-
+
/**
* Returns how long the scroll event will take, in milliseconds.
*
* @return The duration of the scroll in milliseconds.
*/
public final int getDuration() {
- return mDuration;
+ return Math.max(mScrollerX.mDuration, mScrollerY.mDuration);
}
-
+
/**
- * Returns the current X offset in the scroll.
+ * Returns the current X offset in the scroll.
*
* @return The new X offset as an absolute distance from the origin.
*/
public final int getCurrX() {
- return mCurrX;
+ return mScrollerX.mCurrentPosition;
}
-
+
/**
- * Returns the current Y offset in the scroll.
+ * Returns the current Y offset in the scroll.
*
* @return The new Y offset as an absolute distance from the origin.
*/
public final int getCurrY() {
- return mCurrY;
- }
-
- /**
- * @hide
- * Returns the current velocity.
- *
- * @return The original velocity less the deceleration. Result may be
- * negative.
- */
- public float getCurrVelocity() {
- return mVelocity - mDeceleration * timePassed() / 2000.0f;
+ return mScrollerY.mCurrentPosition;
}
/**
- * Returns the start X offset in the scroll.
+ * @hide
+ * Returns the current velocity.
+ *
+ * @return The original velocity less the deceleration, norm of the X and Y velocity vector.
+ */
+ public float getCurrVelocity() {
+ float squaredNorm = mScrollerX.mCurrVelocity * mScrollerX.mCurrVelocity;
+ squaredNorm += mScrollerY.mCurrVelocity * mScrollerY.mCurrVelocity;
+ return FloatMath.sqrt(squaredNorm);
+ }
+
+ /**
+ * Returns the start X offset in the scroll.
*
* @return The start X offset as an absolute distance from the origin.
*/
public final int getStartX() {
- return mStartX;
+ return mScrollerX.mStart;
}
-
+
/**
- * Returns the start Y offset in the scroll.
+ * Returns the start Y offset in the scroll.
*
* @return The start Y offset as an absolute distance from the origin.
*/
public final int getStartY() {
- return mStartY;
+ return mScrollerY.mStart;
}
-
+
/**
* Returns where the scroll will end. Valid only for "fling" scrolls.
*
* @return The final X offset as an absolute distance from the origin.
*/
public final int getFinalX() {
- return mFinalX;
+ return mScrollerX.mFinal;
}
-
+
/**
* Returns where the scroll will end. Valid only for "fling" scrolls.
*
* @return The final Y offset as an absolute distance from the origin.
*/
public final int getFinalY() {
- return mFinalY;
+ return mScrollerY.mFinal;
}
/**
- * Call this when you want to know the new location. If it returns true,
- * the animation is not yet finished. loc will be altered to provide the
- * new location.
- */
+ * Call this when you want to know the new location. If it returns true, the
+ * animation is not yet finished.
+ */
public boolean computeScrollOffset() {
- if (mFinished) {
+ if (isFinished()) {
return false;
}
- int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
-
- if (timePassed < mDuration) {
- switch (mMode) {
+ switch (mMode) {
case SCROLL_MODE:
- float x = (float)timePassed * mDurationReciprocal;
-
- if (mInterpolator == null)
- x = viscousFluid(x);
- else
- x = mInterpolator.getInterpolation(x);
-
- mCurrX = mStartX + Math.round(x * mDeltaX);
- mCurrY = mStartY + Math.round(x * mDeltaY);
- if ((mCurrX == mFinalX) && (mCurrY == mFinalY)) {
- mFinished = true;
- }
- break;
- case FLING_MODE:
- float timePassedSeconds = timePassed / 1000.0f;
- float distance = (mVelocity * timePassedSeconds)
- - (mDeceleration * timePassedSeconds * timePassedSeconds / 2.0f);
-
- mCurrX = mStartX + Math.round(distance * mCoeffX);
- // Pin to mMinX <= mCurrX <= mMaxX
- mCurrX = Math.min(mCurrX, mMaxX);
- mCurrX = Math.max(mCurrX, mMinX);
-
- mCurrY = mStartY + Math.round(distance * mCoeffY);
- // Pin to mMinY <= mCurrY <= mMaxY
- mCurrY = Math.min(mCurrY, mMaxY);
- mCurrY = Math.max(mCurrY, mMinY);
+ long time = AnimationUtils.currentAnimationTimeMillis();
+ // Any scroller can be used for time, since they were started
+ // together in scroll mode. We use X here.
+ final long elapsedTime = time - mScrollerX.mStartTime;
- if (mCurrX == mFinalX && mCurrY == mFinalY) {
- mFinished = true;
+ final int duration = mScrollerX.mDuration;
+ if (elapsedTime < duration) {
+ float q = (float) (elapsedTime) / duration;
+
+ if (mInterpolator == null)
+ q = viscousFluid(q);
+ else
+ q = mInterpolator.getInterpolation(q);
+
+ mScrollerX.updateScroll(q);
+ mScrollerY.updateScroll(q);
+ } else {
+ abortAnimation();
}
-
break;
- }
+
+ case FLING_MODE:
+ if (!mScrollerX.mFinished) {
+ if (!mScrollerX.update()) {
+ if (!mScrollerX.continueWhenFinished()) {
+ mScrollerX.finish();
+ }
+ }
+ }
+
+ if (!mScrollerY.mFinished) {
+ if (!mScrollerY.update()) {
+ if (!mScrollerY.continueWhenFinished()) {
+ mScrollerY.finish();
+ }
+ }
+ }
+
+ break;
}
- else {
- mCurrX = mFinalX;
- mCurrY = mFinalY;
- mFinished = true;
- }
+
return true;
}
-
+
/**
* Start scrolling by providing a starting point and the distance to travel.
* The scroll will use the default value of 250 milliseconds for the
@@ -270,83 +258,39 @@
*/
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
- mFinished = false;
- mDuration = duration;
- mStartTime = AnimationUtils.currentAnimationTimeMillis();
- mStartX = startX;
- mStartY = startY;
- mFinalX = startX + dx;
- mFinalY = startY + dy;
- mDeltaX = dx;
- mDeltaY = dy;
- mDurationReciprocal = 1.0f / (float) mDuration;
- // This controls the viscous fluid effect (how much of it)
- mViscousFluidScale = 8.0f;
- // must be set to 1.0 (used in viscousFluid())
- mViscousFluidNormalize = 1.0f;
- mViscousFluidNormalize = 1.0f / viscousFluid(1.0f);
+ mScrollerX.startScroll(startX, dx, duration);
+ mScrollerY.startScroll(startY, dy, duration);
}
/**
- * Start scrolling based on a fling gesture. The distance travelled will
- * depend on the initial velocity of the fling.
+ * Start scrolling based on a fling gesture. The distance traveled will
+ * depend on the initial velocity of the fling. Velocity is slowed down by a
+ * constant deceleration until it reaches 0 or the limits are reached.
*
* @param startX Starting point of the scroll (X)
* @param startY Starting point of the scroll (Y)
* @param velocityX Initial velocity of the fling (X) measured in pixels per
- * second.
+ * second.
* @param velocityY Initial velocity of the fling (Y) measured in pixels per
- * second
+ * second.
* @param minX Minimum X value. The scroller will not scroll past this
- * point.
+ * point.
* @param maxX Maximum X value. The scroller will not scroll past this
- * point.
+ * point.
* @param minY Minimum Y value. The scroller will not scroll past this
- * point.
+ * point.
* @param maxY Maximum Y value. The scroller will not scroll past this
- * point.
+ * point.
*/
public void fling(int startX, int startY, int velocityX, int velocityY,
int minX, int maxX, int minY, int maxY) {
mMode = FLING_MODE;
- mFinished = false;
-
- float velocity = (float)Math.hypot(velocityX, velocityY);
-
- mVelocity = velocity;
- mDuration = (int) (1000 * velocity / mDeceleration); // Duration is in
- // milliseconds
- mStartTime = AnimationUtils.currentAnimationTimeMillis();
- mStartX = startX;
- mStartY = startY;
-
- mCoeffX = velocity == 0 ? 1.0f : velocityX / velocity;
- mCoeffY = velocity == 0 ? 1.0f : velocityY / velocity;
-
- int totalDistance = (int) ((velocity * velocity) / (2 * mDeceleration));
-
- mMinX = minX;
- mMaxX = maxX;
- mMinY = minY;
- mMaxY = maxY;
-
-
- mFinalX = startX + Math.round(totalDistance * mCoeffX);
- // Pin to mMinX <= mFinalX <= mMaxX
- mFinalX = Math.min(mFinalX, mMaxX);
- mFinalX = Math.max(mFinalX, mMinX);
-
- mFinalY = startY + Math.round(totalDistance * mCoeffY);
- // Pin to mMinY <= mFinalY <= mMaxY
- mFinalY = Math.min(mFinalY, mMaxY);
- mFinalY = Math.max(mFinalY, mMinY);
+ mScrollerX.fling(startX, velocityX, minX, maxX);
+ mScrollerY.fling(startY, velocityY, minY, maxY);
}
-
-
-
- private float viscousFluid(float x)
- {
- x *= mViscousFluidScale;
+
+ private static float viscousFluid(float x) {
+ x *= VISCOUS_FLUID_SCALE;
if (x < 1.0f) {
x -= (1.0f - (float)Math.exp(-x));
} else {
@@ -354,70 +298,237 @@
x = 1.0f - (float)Math.exp(1.0f - x);
x = start + x * (1.0f - start);
}
- x *= mViscousFluidNormalize;
+ x *= VISCOUS_FLUID_NORMALIZE;
return x;
}
-
+
/**
* Stops the animation. Contrary to {@link #forceFinished(boolean)},
* aborting the animating cause the scroller to move to the final x and y
* position
- *
+ *
* @see #forceFinished(boolean)
*/
public void abortAnimation() {
- mCurrX = mFinalX;
- mCurrY = mFinalY;
- mFinished = true;
+ mScrollerX.finish();
+ mScrollerY.finish();
}
-
+
/**
* Extend the scroll animation. This allows a running animation to scroll
* further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}.
- *
+ *
* @param extend Additional time to scroll in milliseconds.
* @see #setFinalX(int)
* @see #setFinalY(int)
*/
public void extendDuration(int extend) {
- int passed = timePassed();
- mDuration = passed + extend;
- mDurationReciprocal = 1.0f / (float)mDuration;
- mFinished = false;
+ mScrollerX.extendDuration(extend);
+ mScrollerY.extendDuration(extend);
}
/**
* Returns the time elapsed since the beginning of the scrolling.
- *
+ *
* @return The elapsed time in milliseconds.
*/
public int timePassed() {
- return (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
+ final long time = AnimationUtils.currentAnimationTimeMillis();
+ final long startTime = Math.min(mScrollerX.mStartTime, mScrollerY.mStartTime);
+ return (int) (time - startTime);
}
/**
* Sets the final position (X) for this scroller.
- *
+ *
* @param newX The new X offset as an absolute distance from the origin.
* @see #extendDuration(int)
* @see #setFinalY(int)
*/
public void setFinalX(int newX) {
- mFinalX = newX;
- mDeltaX = mFinalX - mStartX;
- mFinished = false;
+ mScrollerX.setFinalPosition(newX);
}
/**
* Sets the final position (Y) for this scroller.
- *
+ *
* @param newY The new Y offset as an absolute distance from the origin.
* @see #extendDuration(int)
* @see #setFinalX(int)
*/
public void setFinalY(int newY) {
- mFinalY = newY;
- mDeltaY = mFinalY - mStartY;
- mFinished = false;
+ mScrollerY.setFinalPosition(newY);
+ }
+
+ static class MagneticScroller {
+ // Initial position
+ int mStart;
+
+ // Current position
+ int mCurrentPosition;
+
+ // Final position
+ int mFinal;
+
+ // Initial velocity
+ int mVelocity;
+
+ // Current velocity
+ float mCurrVelocity;
+
+ // Constant current deceleration
+ float mDeceleration;
+
+ // Animation starting time, in system milliseconds
+ long mStartTime;
+
+ // Animation duration, in milliseconds
+ int mDuration;
+
+ // Whether the animation is currently in progress
+ boolean mFinished;
+
+ // Constant gravity value, used to scale deceleration
+ static float GRAVITY;
+
+ static void initializeFromContext(Context context) {
+ final float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
+ GRAVITY = SensorManager.GRAVITY_EARTH // g (m/s^2)
+ * 39.37f // inch/meter
+ * ppi // pixels per inch
+ * ViewConfiguration.getScrollFriction();
+ }
+
+ MagneticScroller() {
+ mFinished = true;
+ }
+
+ void updateScroll(float q) {
+ mCurrentPosition = mStart + Math.round(q * (mFinal - mStart));
+ }
+
+ /*
+ * Update the current position and velocity for current time. Returns
+ * true if update has been done and false if animation duration has been
+ * reached.
+ */
+ boolean update() {
+ final long time = AnimationUtils.currentAnimationTimeMillis();
+ final long duration = time - mStartTime;
+
+ if (duration > mDuration) {
+ return false;
+ }
+
+ final float t = duration / 1000.0f;
+ mCurrVelocity = mVelocity + mDeceleration * t;
+ final float distance = mVelocity * t + mDeceleration * t * t / 2.0f;
+ mCurrentPosition = mStart + (int) distance;
+
+ return true;
+ }
+
+ /*
+ * Get a signed deceleration that will reduce the velocity.
+ */
+ float getDeceleration(int velocity) {
+ return velocity > 0 ? -GRAVITY : GRAVITY;
+ }
+
+ /*
+ * Returns the time (in milliseconds) it will take to go from start to end.
+ */
+ static int computeDuration(int start, int end, float initialVelocity, float deceleration) {
+ final int distance = start - end;
+ final float discriminant = initialVelocity * initialVelocity - 2.0f * deceleration
+ * distance;
+ if (discriminant >= 0.0f) {
+ float delta = (float) Math.sqrt(discriminant);
+ if (deceleration < 0.0f) {
+ delta = -delta;
+ }
+ return (int) (1000.0f * (-initialVelocity - delta) / deceleration);
+ }
+
+ // End position can not be reached
+ return 0;
+ }
+
+ void startScroll(int start, int distance, int duration) {
+ mFinished = false;
+
+ mStart = start;
+ mFinal = start + distance;
+
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+ mDuration = duration;
+
+ // Unused
+ mDeceleration = 0.0f;
+ mVelocity = 0;
+ }
+
+ void fling(int start, int velocity, int min, int max) {
+ mFinished = false;
+
+ mStart = start;
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+
+ mVelocity = velocity;
+
+ mDeceleration = getDeceleration(velocity);
+
+ // A start from an invalid position immediately brings back to a valid position
+ if (mStart < min) {
+ mDuration = 0;
+ mFinal = min;
+ return;
+ }
+
+ if (mStart > max) {
+ mDuration = 0;
+ mFinal = max;
+ return;
+ }
+
+ // Duration are expressed in milliseconds
+ mDuration = (int) (-1000.0f * velocity / mDeceleration);
+
+ mFinal = start - Math.round((velocity * velocity) / (2.0f * mDeceleration));
+
+ // Clamp to a valid final position
+ if (mFinal < min) {
+ mFinal = min;
+ mDuration = computeDuration(mStart, min, mVelocity, mDeceleration);
+ }
+
+ if (mFinal > max) {
+ mFinal = max;
+ mDuration = computeDuration(mStart, max, mVelocity, mDeceleration);
+ }
+ }
+
+ void finish() {
+ mCurrentPosition = mFinal;
+ // Not reset since WebView relies on this value for fast fling.
+ // mCurrVelocity = 0.0f;
+ mFinished = true;
+ }
+
+ boolean continueWhenFinished() {
+ return false;
+ }
+
+ void setFinalPosition(int position) {
+ mFinal = position;
+ mFinished = false;
+ }
+
+ void extendDuration(int extend) {
+ final long time = AnimationUtils.currentAnimationTimeMillis();
+ final int elapsedTime = (int) (time - mStartTime);
+ mDuration = elapsedTime + extend;
+ mFinished = false;
+ }
}
}
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 9e4b606..b436363 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -105,6 +105,9 @@
+ " key64=" + base64Key);
if (dataSize >= 0) {
+ if (entityFile.exists()) {
+ entityFile.delete();
+ }
FileOutputStream entity = new FileOutputStream(entityFile);
if (dataSize > bufSize) {
diff --git a/core/java/com/android/internal/os/AtomicFile.java b/core/java/com/android/internal/os/AtomicFile.java
index ca0345f..e675ef0 100644
--- a/core/java/com/android/internal/os/AtomicFile.java
+++ b/core/java/com/android/internal/os/AtomicFile.java
@@ -45,12 +45,13 @@
public FileOutputStream startWrite() throws IOException {
// Rename the current file so it may be used as a backup during the next read
if (mBaseName.exists()) {
- if (!mBaseName.renameTo(mBackupName)) {
- mBackupName.delete();
+ if (!mBackupName.exists()) {
if (!mBaseName.renameTo(mBackupName)) {
Log.w("AtomicFile", "Couldn't rename file " + mBaseName
+ " to backup file " + mBackupName);
}
+ } else {
+ mBaseName.delete();
}
}
FileOutputStream str = null;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 71ccb3b..24275ec 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -16,6 +16,8 @@
package com.android.internal.os;
+import com.android.internal.util.JournaledFile;
+
import android.bluetooth.BluetoothHeadset;
import android.net.TrafficStats;
import android.os.BatteryStats;
@@ -30,6 +32,7 @@
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
+import android.util.Slog;
import android.util.SparseArray;
import java.io.BufferedReader;
@@ -43,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
@@ -57,7 +61,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 42;
+ private static final int VERSION = 43;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -68,8 +72,7 @@
private static int sNumSpeedSteps;
- private final File mFile;
- private final File mBackupFile;
+ private final JournaledFile mFile;
/**
* The statistics we have collected organized by uids.
@@ -216,7 +219,7 @@
// For debugging
public BatteryStatsImpl() {
- mFile = mBackupFile = null;
+ mFile = null;
}
public static interface Unpluggable {
@@ -228,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();
@@ -247,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();
}
/**
@@ -283,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) {
@@ -295,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;
}
}
@@ -327,8 +334,8 @@
super(unpluggables);
}
- public void addCountLocked(long count) {
- mCount += count;
+ public void addCountAtomic(long count) {
+ mCount.addAndGet((int)count);
}
}
@@ -1122,8 +1129,8 @@
}
}
- public void noteInputEventLocked() {
- mInputEventCounter.stepLocked();
+ public void noteInputEventAtomic() {
+ mInputEventCounter.stepAtomic();
}
public void noteUserActivityLocked(int uid, int event) {
@@ -1678,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
@@ -2170,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]);
}
}
@@ -2704,8 +2711,7 @@
}
public BatteryStatsImpl(String filename) {
- mFile = new File(filename);
- mBackupFile = new File(filename + ".bak");
+ mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
mStartCount++;
mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
@@ -2736,7 +2742,7 @@
}
public BatteryStatsImpl(Parcel p) {
- mFile = mBackupFile = null;
+ mFile = null;
readFromParcel(p);
}
@@ -2799,7 +2805,7 @@
if (m == null) {
// Not crashing might make board bringup easier.
- Log.w(TAG, "Couldn't get kernel wake lock stats");
+ Slog.w(TAG, "Couldn't get kernel wake lock stats");
return;
}
@@ -3047,26 +3053,19 @@
return u.getServiceStatsLocked(pkg, name);
}
+ private static JournaledFile makeJournaledFile() {
+ final String base = "/data/system/device_policies.xml";
+ return new JournaledFile(new File(base), new File(base + ".tmp"));
+ }
+
public void writeLocked() {
- if ((mFile == null) || (mBackupFile == null)) {
- Log.w("BatteryStats", "writeLocked: no file associated with this instance");
+ if (mFile == null) {
+ Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
return;
}
- // Keep the old file around until we know the new one has
- // been successfully written.
- if (mFile.exists()) {
- if (mBackupFile.exists()) {
- mBackupFile.delete();
- }
- if (!mFile.renameTo(mBackupFile)) {
- Log.w("BatteryStats", "Failed to back up file before writing new stats");
- return;
- }
- }
-
try {
- FileOutputStream stream = new FileOutputStream(mFile);
+ FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
Parcel out = Parcel.obtain();
writeSummaryToParcel(out);
stream.write(out.marshall());
@@ -3074,18 +3073,14 @@
stream.flush();
stream.close();
- mBackupFile.delete();
+ mFile.commit();
mLastWriteTime = SystemClock.elapsedRealtime();
return;
} catch (IOException e) {
- Log.w("BatteryStats", "Error writing battery statistics", e);
+ Slog.w("BatteryStats", "Error writing battery statistics", e);
}
- if (mFile.exists()) {
- if (!mFile.delete()) {
- Log.w(TAG, "Failed to delete mangled file " + mFile);
- }
- }
+ mFile.rollback();
}
static byte[] readFully(FileInputStream stream) throws java.io.IOException {
@@ -3112,29 +3107,19 @@
}
public void readLocked() {
- if ((mFile == null) || (mBackupFile == null)) {
- Log.w("BatteryStats", "readLocked: no file associated with this instance");
+ if (mFile == null) {
+ Slog.w("BatteryStats", "readLocked: no file associated with this instance");
return;
}
mUidStats.clear();
- FileInputStream stream = null;
- if (mBackupFile.exists()) {
- try {
- stream = new FileInputStream(mBackupFile);
- } catch (java.io.IOException e) {
- // We'll try for the normal settings file.
- }
- }
-
try {
- if (stream == null) {
- if (!mFile.exists()) {
- return;
- }
- stream = new FileInputStream(mFile);
+ File file = mFile.chooseForRead();
+ if (!file.exists()) {
+ return;
}
+ FileInputStream stream = new FileInputStream(file);
byte[] raw = readFully(stream);
Parcel in = Parcel.obtain();
@@ -3144,7 +3129,7 @@
readSummaryFromParcel(in);
} catch(java.io.IOException e) {
- Log.e("BatteryStats", "Error reading battery statistics", e);
+ Slog.e("BatteryStats", "Error reading battery statistics", e);
}
}
@@ -3155,7 +3140,7 @@
private void readSummaryFromParcel(Parcel in) {
final int version = in.readInt();
if (version != VERSION) {
- Log.w("BatteryStats", "readFromParcel: version got " + version
+ Slog.w("BatteryStats", "readFromParcel: version got " + version
+ ", expected " + VERSION + "; erasing old stats");
return;
}
@@ -3197,6 +3182,10 @@
mBluetoothOnTimer.readSummaryFromParcelLocked(in);
int NKW = in.readInt();
+ if (NKW > 10000) {
+ Slog.w(TAG, "File corrupt: too many kernel wake locks " + NKW);
+ return;
+ }
for (int ikw = 0; ikw < NKW; ikw++) {
if (in.readInt() != 0) {
String kwltName = in.readString();
@@ -3207,6 +3196,10 @@
sNumSpeedSteps = in.readInt();
final int NU = in.readInt();
+ if (NU > 10000) {
+ Slog.w(TAG, "File corrupt: too many uids " + NU);
+ return;
+ }
for (int iu = 0; iu < NU; iu++) {
int uid = in.readInt();
Uid u = new Uid(uid);
@@ -3235,6 +3228,10 @@
}
int NW = in.readInt();
+ if (NW > 10000) {
+ Slog.w(TAG, "File corrupt: too many wake locks " + NW);
+ return;
+ }
for (int iw = 0; iw < NW; iw++) {
String wlName = in.readString();
if (in.readInt() != 0) {
@@ -3249,6 +3246,10 @@
}
int NP = in.readInt();
+ if (NP > 10000) {
+ Slog.w(TAG, "File corrupt: too many sensors " + NP);
+ return;
+ }
for (int is = 0; is < NP; is++) {
int seNumber = in.readInt();
if (in.readInt() != 0) {
@@ -3258,6 +3259,10 @@
}
NP = in.readInt();
+ if (NP > 10000) {
+ Slog.w(TAG, "File corrupt: too many processes " + NP);
+ return;
+ }
for (int ip = 0; ip < NP; ip++) {
String procName = in.readString();
Uid.Proc p = u.getProcessStatsLocked(procName);
@@ -3270,6 +3275,10 @@
}
NP = in.readInt();
+ if (NP > 10000) {
+ Slog.w(TAG, "File corrupt: too many packages " + NP);
+ return;
+ }
for (int ip = 0; ip < NP; ip++) {
String pkgName = in.readString();
Uid.Pkg p = u.getPackageStatsLocked(pkgName);
diff --git a/core/java/com/android/internal/util/HierarchicalState.java b/core/java/com/android/internal/util/HierarchicalState.java
index 002338a..b37f46c 100644
--- a/core/java/com/android/internal/util/HierarchicalState.java
+++ b/core/java/com/android/internal/util/HierarchicalState.java
@@ -21,10 +21,9 @@
/**
* {@hide}
*
- * The abstract class for implementing states in a
- * HierarchicalStateMachine and HandlerStateMachine.
+ * The class for implementing states in a HierarchicalStateMachine
*/
-public abstract class HierarchicalState {
+public class HierarchicalState {
/**
* Constructor
@@ -54,7 +53,9 @@
* if the parent state's processMessage should
* be invoked.
*/
- abstract protected boolean processMessage(Message msg);
+ protected boolean processMessage(Message msg) {
+ return false;
+ }
/**
* Called when a state is exited.
diff --git a/core/java/com/android/internal/util/HierarchicalStateMachine.java b/core/java/com/android/internal/util/HierarchicalStateMachine.java
index 7d7f130..9911f48 100644
--- a/core/java/com/android/internal/util/HierarchicalStateMachine.java
+++ b/core/java/com/android/internal/util/HierarchicalStateMachine.java
@@ -574,23 +574,41 @@
}
/**
- * Process the message abiding by the hierarchical semantics.
+ * Process the message abiding by the hierarchical semantics
+ * and perform any requested transitions.
*/
processMsg(msg);
+ performTransitions();
+ if (mDbg) Log.d(TAG, "handleMessage: X");
+ }
+
+ /**
+ * Do any transitions
+ */
+ private void performTransitions() {
/**
* If transitionTo has been called, exit and then enter
- * the appropriate states.
+ * the appropriate states. We loop on this to allow
+ * enter and exit methods to use transitionTo.
*/
- if (mDestState != null) {
+ HierarchicalState destState = null;
+ while (mDestState != null) {
if (mDbg) Log.d(TAG, "handleMessage: new destination call exit");
/**
+ * Save mDestState locally and set to null
+ * to know if enter/exit use transitionTo.
+ */
+ destState = mDestState;
+ mDestState = null;
+
+ /**
* Determine the states to exit and enter and return the
* common ancestor state of the enter/exit states. Then
* invoke the exit methods then the enter methods.
*/
- StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(mDestState);
+ StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
invokeExitMethods(commonStateInfo);
int stateStackEnteringIndex = moveTempStateStackToStateStack();
invokeEnterMethods(stateStackEnteringIndex);
@@ -603,25 +621,31 @@
* message queue.
*/
moveDeferredMessageAtFrontOfQueue();
+ }
- /**
- * Call halting() if we've transitioned to the halting
- * state. All subsequent messages will be processed in
- * in the halting state which invokes haltedProcessMessage(msg);
- */
- if (mDestState == mQuittingState) {
+ /**
+ * After processing all transitions check and
+ * see if the last transition was to quit or halt.
+ */
+ if (destState != null) {
+ if (destState == mQuittingState) {
+ /**
+ * We are quitting so ignore all messages.
+ */
mHsm.quitting();
if (mHsm.mHsmThread != null) {
// If we made the thread then quit looper
getLooper().quit();
}
- } else if (mDestState == mHaltingState) {
+ } else if (destState == mHaltingState) {
+ /**
+ * Call halting() if we've transitioned to the halting
+ * state. All subsequent messages will be processed in
+ * in the halting state which invokes haltedProcessMessage(msg);
+ */
mHsm.halting();
}
- mDestState = null;
}
-
- if (mDbg) Log.d(TAG, "handleMessage: X");
}
/**
@@ -657,6 +681,11 @@
mIsConstructionCompleted = true;
invokeEnterMethods(0);
+ /**
+ * Perform any transitions requested by the enter methods
+ */
+ performTransitions();
+
if (mDbg) Log.d(TAG, "completeConstruction: X");
}
@@ -1167,7 +1196,6 @@
return Message.obtain(mHsmHandler, what, obj);
}
-
/**
* Enqueue a message to this state machine.
*/
diff --git a/services/java/com/android/server/JournaledFile.java b/core/java/com/android/internal/util/JournaledFile.java
similarity index 98%
rename from services/java/com/android/server/JournaledFile.java
rename to core/java/com/android/internal/util/JournaledFile.java
index 3d1f52d..af0c6c6 100644
--- a/services/java/com/android/server/JournaledFile.java
+++ b/core/java/com/android/internal/util/JournaledFile.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.internal.util;
import java.io.File;
import java.io.IOException;
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index ee2fc12..f487a16 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -60,6 +60,7 @@
public PointerLocationView(Context c) {
super(c);
+ setFocusable(true);
mVC = ViewConfiguration.get(c);
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
@@ -350,4 +351,11 @@
addTouchEvent(event);
return true;
}
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent event) {
+ Log.i("Pointer", "Trackball: " + event);
+ return super.onTrackballEvent(event);
+ }
+
}
diff --git a/core/jni/android_bluetooth_ScoSocket.cpp b/core/jni/android_bluetooth_ScoSocket.cpp
index 3afe5f5..94e4409 100644
--- a/core/jni/android_bluetooth_ScoSocket.cpp
+++ b/core/jni/android_bluetooth_ScoSocket.cpp
@@ -37,6 +37,23 @@
#ifdef HAVE_BLUETOOTH
#include <bluetooth/bluetooth.h>
#include <bluetooth/sco.h>
+#include <bluetooth/hci.h>
+
+#define MAX_LINE 255
+
+/*
+ * Defines the module strings used in the blacklist file.
+ * These are used by consumers of the blacklist file to see if the line is
+ * used by that module.
+ */
+#define SCO_BLACKLIST_MODULE_NAME "scoSocket"
+
+
+/* Define the type strings used in the blacklist file. */
+#define BLACKLIST_BY_NAME "name"
+#define BLACKLIST_BY_PARTIAL_NAME "partial_name"
+#define BLACKLIST_BY_OUI "vendor_oui"
+
#endif
/* Ideally, blocking I/O on a SCO socket would return when another thread
@@ -67,11 +84,28 @@
struct thread_data_t;
static void *work_thread(void *arg);
-static int connect_work(const char *address);
+static int connect_work(const char *address, uint16_t sco_pkt_type);
static int accept_work(int signal_sk);
static void wait_for_close(int sk, int signal_sk);
static void closeNative(JNIEnv *env, jobject object);
+static void parseBlacklist(void);
+static uint16_t getScoType(char *address, const char *name);
+
+#define COMPARE_STRING(key, s) (!strncmp(key, s, strlen(s)))
+
+/* Blacklist data */
+typedef struct scoBlacklist {
+ int fieldType;
+ char *value;
+ uint16_t scoType;
+ struct scoBlacklist *next;
+} scoBlacklist_t;
+
+#define BL_TYPE_NAME 1 // Field type is name string
+
+static scoBlacklist_t *blacklist = NULL;
+
/* shared native data - protected by mutex */
typedef struct {
pthread_mutex_t mutex;
@@ -87,11 +121,144 @@
bool is_accept; // accept (listening) or connect (outgoing) thread
int signal_sk; // socket for thread to listen for unblock signal
char address[BTADDR_SIZE]; // BT addres as string
+ uint16_t sco_pkt_type; // SCO packet types supported
};
static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
return (native_data_t *)(env->GetIntField(object, field_mNativeData));
}
+
+static uint16_t str2scoType (char *key) {
+ LOGV("%s: key = %s", __FUNCTION__, key);
+ if (COMPARE_STRING(key, "ESCO_HV1"))
+ return ESCO_HV1;
+ if (COMPARE_STRING(key, "ESCO_HV2"))
+ return ESCO_HV2;
+ if (COMPARE_STRING(key, "ESCO_HV3"))
+ return ESCO_HV3;
+ if (COMPARE_STRING(key, "ESCO_EV3"))
+ return ESCO_EV3;
+ if (COMPARE_STRING(key, "ESCO_EV4"))
+ return ESCO_EV4;
+ if (COMPARE_STRING(key, "ESCO_EV5"))
+ return ESCO_EV5;
+ if (COMPARE_STRING(key, "ESCO_2EV3"))
+ return ESCO_2EV3;
+ if (COMPARE_STRING(key, "ESCO_3EV3"))
+ return ESCO_3EV3;
+ if (COMPARE_STRING(key, "ESCO_2EV5"))
+ return ESCO_2EV5;
+ if (COMPARE_STRING(key, "ESCO_3EV5"))
+ return ESCO_3EV5;
+ if (COMPARE_STRING(key, "SCO_ESCO_MASK"))
+ return SCO_ESCO_MASK;
+ if (COMPARE_STRING(key, "EDR_ESCO_MASK"))
+ return EDR_ESCO_MASK;
+ if (COMPARE_STRING(key, "ALL_ESCO_MASK"))
+ return ALL_ESCO_MASK;
+ LOGE("Unknown SCO Type (%s) skipping",key);
+ return 0;
+}
+
+static void parseBlacklist(void) {
+ const char *filename = "/etc/bluetooth/blacklist.conf";
+ char line[MAX_LINE];
+ scoBlacklist_t *list = NULL;
+ scoBlacklist_t *newelem;
+
+ LOGV(__FUNCTION__);
+
+ /* Open file */
+ FILE *fp = fopen(filename, "r");
+ if(!fp) {
+ LOGE("Error(%s)opening blacklist file", strerror(errno));
+ return;
+ }
+
+ while (fgets(line, MAX_LINE, fp) != NULL) {
+ if ((COMPARE_STRING(line, "//")) || (!strcmp(line, "")))
+ continue;
+ char *module = strtok(line,":");
+ if (COMPARE_STRING(module, SCO_BLACKLIST_MODULE_NAME)) {
+ newelem = (scoBlacklist_t *)calloc(1, sizeof(scoBlacklist_t));
+ if (newelem == NULL) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ return;
+ }
+ // parse line
+ char *type = strtok(NULL, ",");
+ char *valueList = strtok(NULL, ",");
+ char *paramList = strtok(NULL, ",");
+ if (COMPARE_STRING(type, BLACKLIST_BY_NAME)) {
+ // Extract Name from Value list
+ newelem->fieldType = BL_TYPE_NAME;
+ newelem->value = (char *)calloc(1, strlen(valueList));
+ if (newelem->value == NULL) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ continue;
+ }
+ valueList++; // Skip open quote
+ strncpy(newelem->value, valueList, strlen(valueList) - 1);
+
+ // Get Sco Settings from Parameters
+ char *param = strtok(paramList, ";");
+ uint16_t scoTypes = 0;
+ while (param != NULL) {
+ uint16_t sco;
+ if (param[0] == '-') {
+ param++;
+ sco = str2scoType(param);
+ if (sco != 0)
+ scoTypes &= ~sco;
+ } else if (param[0] == '+') {
+ param++;
+ sco = str2scoType(param);
+ if (sco != 0)
+ scoTypes |= sco;
+ } else if (param[0] == '=') {
+ param++;
+ sco = str2scoType(param);
+ if (sco != 0)
+ scoTypes = sco;
+ } else {
+ LOGE("Invalid SCO type must be =, + or -");
+ }
+ param = strtok(NULL, ";");
+ }
+ newelem->scoType = scoTypes;
+ } else {
+ LOGE("Unknown SCO type entry in Blacklist file");
+ continue;
+ }
+ if (list) {
+ list->next = newelem;
+ list = newelem;
+ } else {
+ blacklist = list = newelem;
+ }
+ LOGI("Entry name = %s ScoTypes = 0x%x", newelem->value,
+ newelem->scoType);
+ }
+ }
+ fclose(fp);
+ return;
+}
+static uint16_t getScoType(char *address, const char *name) {
+ uint16_t ret = 0;
+ scoBlacklist_t *list = blacklist;
+
+ while (list != NULL) {
+ if (list->fieldType == BL_TYPE_NAME) {
+ if (COMPARE_STRING(name, list->value)) {
+ ret = list->scoType;
+ break;
+ }
+ }
+ list = list->next;
+ }
+ LOGI("%s %s - 0x%x", __FUNCTION__, name, ret);
+ return ret;
+}
#endif
static void classInitNative(JNIEnv* env, jclass clazz) {
@@ -104,6 +271,9 @@
method_onAccepted = env->GetMethodID(clazz, "onAccepted", "(I)V");
method_onConnected = env->GetMethodID(clazz, "onConnected", "(I)V");
method_onClosed = env->GetMethodID(clazz, "onClosed", "()V");
+
+ /* Read the blacklist file in here */
+ parseBlacklist();
#endif
}
@@ -192,7 +362,9 @@
return JNI_FALSE;
}
-static jboolean connectNative(JNIEnv *env, jobject object, jstring address) {
+static jboolean connectNative(JNIEnv *env, jobject object, jstring address,
+ jstring name) {
+
LOGV(__FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
@@ -200,6 +372,7 @@
pthread_t thread;
struct thread_data_t *data;
const char *c_address;
+ const char *c_name;
pthread_mutex_lock(&nat->mutex);
if (nat->signal_sk != -1) {
@@ -231,6 +404,15 @@
env->ReleaseStringUTFChars(address, c_address);
data->is_accept = false;
+ 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;
@@ -282,7 +464,7 @@
sk = accept_work(data->signal_sk);
LOGV("SCO OBJECT %p END ACCEPT *****", data->nat->object);
} else {
- sk = connect_work(data->address);
+ sk = connect_work(data->address, data->sco_pkt_type);
}
/* callback with connection result */
@@ -426,7 +608,7 @@
return -1;
}
-static int connect_work(const char *address) {
+static int connect_work(const char *address, uint16_t sco_pkt_type) {
LOGV(__FUNCTION__);
struct sockaddr_sco addr;
int sk = -1;
@@ -449,6 +631,7 @@
memset(&addr, 0, sizeof(addr));
addr.sco_family = AF_BLUETOOTH;
get_bdaddr(address, &addr.sco_bdaddr);
+ addr.sco_pkt_type = sco_pkt_type;
LOGI("Connecting to socket");
while (connect(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
if (errno != EINTR) {
@@ -493,7 +676,7 @@
{"classInitNative", "()V", (void*)classInitNative},
{"initNative", "()V", (void *)initNative},
{"destroyNative", "()V", (void *)destroyNative},
- {"connectNative", "(Ljava/lang/String;)Z", (void *)connectNative},
+ {"connectNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)connectNative},
{"acceptNative", "()Z", (void *)acceptNative},
{"closeNative", "()V", (void *)closeNative},
};
diff --git a/core/res/res/drawable/pattern_underwear.png b/core/res/res/drawable/pattern_underwear.png
deleted file mode 100644
index 651212f..0000000
--- a/core/res/res/drawable/pattern_underwear.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/values-en-rUS/donottranslate-names.xml b/core/res/res/values-en-rUS/donottranslate-names.xml
index f8ec765..aa0abe3 100644
--- a/core/res/res/values-en-rUS/donottranslate-names.xml
+++ b/core/res/res/values-en-rUS/donottranslate-names.xml
@@ -4,35 +4,51 @@
<!-- various string resources for Contacts -->
<string-array name="common_nicknames">
- <item>Abigail, Abbie, Gail, Gayle</item>
+ <item>Abigail, Abbie</item>
+ <item>Abigail, Gail, Gayle</item>
<item>Abe, Abraham</item>
- <item>Aggie, Agatha, Agnes</item>
- <item>Albert, Al, Bert, Bertie</item>
- <item>Alexander, Al, Alec, Alex, Lex, Sasha</item>
- <item>Alexandra, Al, Allie, Ally, Lex, Lexie, Sandra, Sandy, Sasha</item>
+ <item>Agatha, Aggie</item>
+ <item>Agatha, Agnes</item>
+ <item>Albert, Al</item>
+ <item>Albert, Bert, Bertie</item>
+ <item>Alexander, Al, Alex</item>
+ <item>Alexander, Al, Alec</item>
+ <item>Alexander, Alex, Lex</item>
+ <item>Alexander, Alex, Sasha</item>
+ <item>Alexandra, Al, Allie, Ally</item>
+ <item>Alexandra, Lex, Lexie</item>
+ <item>Alexandra, Sandra, Sandy</item>
+ <item>Alexandra, Sasha</item>
<item>Alf, Alfred, Alfredo, Alfie</item>
<item>Alice, Allie, Ally</item>
<item>Alison, Allie, Ally</item>
<item>Allison, Allie, Ally</item>
<item>Amanda, Mandi, Mandy</item>
<item>Andrea, Andie</item>
- <item>Andrew, Andy, Drew</item>
+ <item>Andrew, Andy</item>
+ <item>Andrew, Drew</item>
<item>Anne, Annie, Annette</item>
<item>Anthony, Tony, Toni, Tone</item>
<item>Arthur, Art, Arty</item>
- <item>Barbara, Babs, Barb, Barbie</item>
- <item>Benjamin, Ben, Benji, Benny</item>
- <item>Bernard, Bern, Bernie, Barnie</item>
+ <item>Barbara, Barb, Barbie</item>
+ <item>Benjamin, Ben, Benny</item>
+ <item>Benjamin, Benji</item>
+ <item>Bernard, Barnie</item>
+ <item>Bernard, Bern, Bernie</item>
<item>Bertram, Bert, Bertie</item>
<item>Bradly, Brad</item>
<item>Calvin, Cal</item>
<item>Catherine, Cat, Cate, Cath, Catie, Cathy, Kat, Kate, Katie, Kathy</item>
<item>Carrie, Caroline, Carolyn</item>
- <item>Charles, Chuck, Chaz, Charlie, Buck</item>
+ <item>Charles, Charlie</item>
+ <item>Charles, Chuck</item>
+ <item>Charles, Chaz</item>
+ <item>Charles, Buck</item>
<item>Christine, Chrissy, Chrissie</item>
<item>Christopher, Chris</item>
<item>Clinton, Clint</item>
- <item>Cynthia, Cindy, Cynth</item>
+ <item>Cynthia, Cindy</item>
+ <item>Cynthia, Cynth</item>
<item>Daniel, Dan, Danny</item>
<item>David, Dave</item>
<item>Deborah, Deb, Debbie</item>
@@ -43,30 +59,46 @@
<item>Dorothea, Dot, Dotty</item>
<item>Dorothy, Dot, Dotty</item>
<item>Douglas, Doug</item>
- <item>Edward, Ed, Eddie, Ned, Neddie, Neddy, Ted, Teddy, Teddie</item>
- <item>Eleanor, Ella, Ellie, Elle</item>
+ <item>Edward, Ed, Eddie</item>
+ <item>Edward, Ned, Neddie, Neddy</item>
+ <item>Edward, Ted, Teddy, Teddie</item>
+ <item>Eleanor, Ella</item>
+ <item>Eleanor, Ellie, Elle</item>
<item>Elisabetta, Betta</item>
- <item>Elizabeth, Beth, Bess, Bessie, Betsy, Betty, Bette, Eliza, Lisa, Liza, Liz</item>
+ <item>Elizabeth, Beth</item>
+ <item>Elizabeth, Bess, Bessie</item>
+ <item>Elizabeth, Betsy</item>
+ <item>Elizabeth, Betty, Bette</item>
+ <item>Elizabeth, Eliza</item>
+ <item>Elizabeth, Lisa, Liza, Liz</item>
<item>Emily, Em, Ems, Emmy</item>
<item>Emma, Em, Ems, Emmy</item>
<item>Eugene, Gene</item>
<item>Fannie, Fanny</item>
<item>Florence, Flo</item>
- <item>Frances, Fran, Francie</item>
- <item>Francis, Fran, Frank, Frankie</item>
+ <item>Frances, Fran</item>
+ <item>Frances, Francie</item>
+ <item>Francis, Fran</item>
+ <item>Francis, Frank, Frankie</item>
<item>Frederick, Fred, Freddy</item>
<item>Gabriel, Gabe</item>
<item>Gerald, Gerry</item>
<item>Gerard, Gerry</item>
<item>Gregory, Greg, Gregg</item>
- <item>Harold, Hal, Harry</item>
- <item>Henry, Hal, Hank, Harry</item>
+ <item>Harold, Hal</item>
+ <item>Harold, Harry</item>
+ <item>Henry, Hal</item>
+ <item>Henry, Hank</item>
+ <item>Henry, Harry</item>
<item>Herbert, Bert, Bertie</item>
<item>Irving, Irv</item>
- <item>Isabella, Isa, Izzy, Bella</item>
+ <item>Isabella, Isa</item>
+ <item>Isabella, Izzy</item>
+ <item>Isabella, Bella</item>
<item>Jacob, Jake</item>
<item>Jacqueline, Jackie</item>
- <item>James, Jim, Jimmy, Jamie, Jock</item>
+ <item>James, Jim, Jimmy</item>
+ <item>James, Jamie</item>
<item>Janet, Jan</item>
<item>Janice, Jan</item>
<item>Jason, Jay</item>
@@ -90,10 +122,15 @@
<item>Laura, Lauri, Laurie</item>
<item>Lauren, Lauri, Laurie</item>
<item>Lawrence, Larry</item>
- <item>Leonard, Leo, Len, Lenny</item>
- <item>Leopold, Leo, Len, Lenny</item>
+ <item>Leonard, Leo</item>
+ <item>Leonard, Len, Lenny</item>
+ <item>Leopold, Leo</item>
<item>Madeline, Maddie, Maddy</item>
- <item>Margaret, Marge, Marg, Maggie, Mags, Meg, Peggy, Greta, Gretchen</item>
+ <item>Margaret, Marge, Marg</item>
+ <item>Margaret, Maggie, Mags</item>
+ <item>Margaret, Meg</item>
+ <item>Margaret, Peggy</item>
+ <item>Margaret, Greta, Gretchen</item>
<item>Martin, Martie, Marty</item>
<item>Matthew, Matt, Mattie</item>
<item>Maureen, Mo</item>
@@ -101,27 +138,36 @@
<item>Maxwell, Max</item>
<item>Maximilian, Maxim, Max</item>
<item>Megan, Meg</item>
- <item>Michael, Mickey, Mick, Mike, Mikey</item>
+ <item>Michael, Mickey, Mick</item>
+ <item>Michael, Mike, Mikey</item>
<item>Morris, Mo</item>
<item>Nancy, Nan</item>
- <item>Nathan, Nat, Nate</item>
- <item>Nathaniel, Nat, Nate</item>
+ <item>Nathan, Nat</item>
+ <item>Nathan, Nate</item>
+ <item>Nathaniel, Nat</item>
+ <item>Nathaniel, Nate</item>
<item>Nicholas, Nick</item>
<item>Nicole, Nicky, Nickie, Nikky</item>
<item>Pamela, Pam</item>
- <item>Patricia, Pat, Patsy, Patty, Trish, Tricia</item>
- <item>Patrick, Pat, Patter</item>
+ <item>Patricia, Pat, Patty</item>
+ <item>Patricia, Patsy</item>
+ <item>Patricia, Trish, Tricia</item>
+ <item>Patrick, Pat</item>
<item>Penelope, Penny</item>
<item>Peter, Pete</item>
<item>Raymond, Ray</item>
<item>Philip, Phil</item>
<item>Rebecca, Becca, Becky</item>
- <item>Richard, Rick, Rich, Dick</item>
- <item>Robert, Bob, Rob, Robbie, Bobby, Rab</item>
+ <item>Richard, Rick</item>
+ <item>Richard, Rich</item>
+ <item>Richard, Dick</item>
+ <item>Robert, Bob, Bobby</item>
+ <item>Robert, Rob, Robbie</item>
<item>Rodney. Rod</item>
<item>Ronald, Ron, Ronnie</item>
<item>Rosemary, Rosie, Rose</item>
- <item>Russell, Russ, Rusty</item>
+ <item>Russell, Russ</item>
+ <item>Russell, Rusty</item>
<item>Ryan, Ry</item>
<item>Samantha, Sam</item>
<item>Samuel, Sam, Sammy</item>
@@ -130,23 +176,34 @@
<item>Stephen, Steve</item>
<item>Steven, Steve</item>
<item>Stuart, Stu</item>
- <item>Susan, Sue, Susie, Suzie</item>
- <item>Suzanne, Sue, Susie, Suzie</item>
+ <item>Susan, Sue</item>
+ <item>Susan, Susie, Suzie</item>
+ <item>Suzanne, Sue</item>
+ <item>Suzanne, Susie, Suzie</item>
<item>Tamara, Tammy</item>
<item>Theresa, Teresa</item>
- <item>Theodora, Teddie, Thea, Theo</item>
- <item>Theodore, Ted, Teddy, Theo</item>
+ <item>Theodora, Teddie</item>
+ <item>Theodora, Thea</item>
+ <item>Theodore, Ted, Teddy</item>
+ <item>Theodore, Theo</item>
<item>Thomas, Tom, Thom, Tommy</item>
<item>Timothy, Tim, Timmy</item>
<item>Valerie, Val</item>
- <item>Veronica, Ronnie, Roni, Nica, Nikki, Nikka</item>
+ <item>Veronica, Ronnie, Roni</item>
+ <item>Veronica, Nica, Nikki, Nikka</item>
<item>Victor, Vic</item>
- <item>Victoria, Vicky, Vicki, Vickie, Tori</item>
- <item>Vincent, Vince, Vin, Vinnie</item>
+ <item>Victoria, Vicky, Vicki, Vickie</item>
+ <item>Victoria, Tori</item>
+ <item>Vincent, Vince</item>
+ <item>Vincent, Vin, Vinnie</item>
<item>Vivian, Vivi</item>
- <item>Walter, Walt, Wally</item>
- <item>Wendy, Wen, Wendel</item>
- <item>William, Bill, Billy, Will, Willy, Liam</item>
+ <item>Walter, Wally</item>
+ <item>Walter, Walt</item>
+ <item>Wendy, Wen</item>
+ <item>Wendy, Wendel</item>
+ <item>William, Bill, Billy</item>
+ <item>William, Will, Willy</item>
+ <item>William, Liam</item>
<item>Yvonna, Vonna</item>
<item>Zachary, Zach, Zack, Zac</item>
</string-array>
diff --git a/core/tests/coretests/src/android/os/HierarchicalStateMachineTest.java b/core/tests/coretests/src/android/os/HierarchicalStateMachineTest.java
index c51fecc..89b3fb6 100644
--- a/core/tests/coretests/src/android/os/HierarchicalStateMachineTest.java
+++ b/core/tests/coretests/src/android/os/HierarchicalStateMachineTest.java
@@ -48,7 +48,7 @@
private static final int TEST_CMD_6 = 6;
private static final boolean DBG = true;
- private static final boolean WAIT_FOR_DEBUGGER = false;
+ private static final boolean WAIT_FOR_DEBUGGER = true;
private static final String TAG = "HierarchicalStateMachineTest";
/**
@@ -152,6 +152,154 @@
}
/**
+ * Test enter/exit can use transitionTo
+ */
+ class StateMachineEnterExitTransitionToTest extends HierarchicalStateMachine {
+ StateMachineEnterExitTransitionToTest(String name) {
+ super(name);
+ mThisSm = this;
+ setDbg(DBG);
+
+ // Setup state machine with 1 state
+ addState(mS1);
+ addState(mS2);
+ addState(mS3);
+ addState(mS4);
+
+ // Set the initial state
+ setInitialState(mS1);
+ }
+
+ class S1 extends HierarchicalState {
+ @Override protected void enter() {
+ // Test that a transition in enter and the initial state works
+ mS1EnterCount += 1;
+ transitionTo(mS2);
+ Log.d(TAG, "S1.enter");
+ }
+ @Override protected void exit() {
+ mS1ExitCount += 1;
+ Log.d(TAG, "S1.exit");
+ }
+ }
+
+ class S2 extends HierarchicalState {
+ @Override protected void enter() {
+ mS2EnterCount += 1;
+ Log.d(TAG, "S2.enter");
+ }
+ @Override protected void exit() {
+ // Test transition in exit work
+ mS2ExitCount += 1;
+ transitionTo(mS4);
+ Log.d(TAG, "S2.exit");
+ }
+ @Override protected boolean processMessage(Message message) {
+ // Start a transition to S3 but it will be
+ // changed to a transition to S4
+ transitionTo(mS3);
+ Log.d(TAG, "S2.processMessage");
+ return true;
+ }
+ }
+
+ class S3 extends HierarchicalState {
+ @Override protected void enter() {
+ // Test that we can do halting in an enter/exit
+ transitionToHaltingState();
+ mS3EnterCount += 1;
+ Log.d(TAG, "S3.enter");
+ }
+ @Override protected void exit() {
+ mS3ExitCount += 1;
+ Log.d(TAG, "S3.exit");
+ }
+ }
+
+
+ class S4 extends HierarchicalState {
+ @Override protected void enter() {
+ // Test that we can do halting in an enter/exit
+ transitionToHaltingState();
+ mS4EnterCount += 1;
+ Log.d(TAG, "S4.enter");
+ }
+ @Override protected void exit() {
+ mS4ExitCount += 1;
+ Log.d(TAG, "S4.exit");
+ }
+ }
+
+ @Override
+ protected void halting() {
+ synchronized (mThisSm) {
+ mThisSm.notifyAll();
+ }
+ }
+
+ private StateMachineEnterExitTransitionToTest mThisSm;
+ private S1 mS1 = new S1();
+ private S2 mS2 = new S2();
+ private S3 mS3 = new S3();
+ private S4 mS4 = new S4();
+ private int mS1EnterCount = 0;
+ private int mS1ExitCount = 0;
+ private int mS2EnterCount = 0;
+ private int mS2ExitCount = 0;
+ private int mS3EnterCount = 0;
+ private int mS3ExitCount = 0;
+ private int mS4EnterCount = 0;
+ private int mS4ExitCount = 0;
+ }
+
+ @SmallTest
+ public void testStateMachineEnterExitTransitionToTest() throws Exception {
+ //if (WAIT_FOR_DEBUGGER) Debug.waitForDebugger();
+
+ StateMachineEnterExitTransitionToTest smEnterExitTranstionToTest =
+ new StateMachineEnterExitTransitionToTest("smEnterExitTranstionToTest");
+ smEnterExitTranstionToTest.start();
+ if (smEnterExitTranstionToTest.isDbg()) {
+ Log.d(TAG, "testStateMachineEnterExitTransitionToTest E");
+ }
+
+ synchronized (smEnterExitTranstionToTest) {
+ smEnterExitTranstionToTest.sendMessage(1);
+
+ try {
+ // wait for the messages to be handled
+ smEnterExitTranstionToTest.wait();
+ } catch (InterruptedException e) {
+ Log.e(TAG, "testStateMachineEnterExitTransitionToTest: exception while waiting "
+ + e.getMessage());
+ }
+ }
+
+ assertTrue(smEnterExitTranstionToTest.getProcessedMessagesCount() == 1);
+
+ ProcessedMessages.Info pmi;
+
+ // Message should be handled by mS2.
+ pmi = smEnterExitTranstionToTest.getProcessedMessage(0);
+ assertEquals(TEST_CMD_1, pmi.getWhat());
+ assertEquals(smEnterExitTranstionToTest.mS2, pmi.getState());
+ assertEquals(smEnterExitTranstionToTest.mS2, pmi.getOriginalState());
+
+ assertEquals(smEnterExitTranstionToTest.mS1EnterCount, 1);
+ assertEquals(smEnterExitTranstionToTest.mS1ExitCount, 1);
+ assertEquals(smEnterExitTranstionToTest.mS2EnterCount, 1);
+ assertEquals(smEnterExitTranstionToTest.mS2ExitCount, 1);
+ assertEquals(smEnterExitTranstionToTest.mS3EnterCount, 1);
+ assertEquals(smEnterExitTranstionToTest.mS3ExitCount, 1);
+ assertEquals(smEnterExitTranstionToTest.mS3EnterCount, 1);
+ assertEquals(smEnterExitTranstionToTest.mS3ExitCount, 1);
+
+ if (smEnterExitTranstionToTest.isDbg()) {
+ Log.d(TAG, "testStateMachineEnterExitTransitionToTest X");
+ }
+ }
+
+ /**
* Tests that ProcessedMessage works as a circular buffer.
*/
class StateMachine0 extends HierarchicalStateMachine {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 473f580..0016503 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -935,17 +935,27 @@
mCallingPid = tr.sender_pid;
mCallingUid = tr.sender_euid;
- bool doBackground = !gDisableBackgroundScheduling &&
- getpriority(PRIO_PROCESS, mMyThreadId)
- >= ANDROID_PRIORITY_BACKGROUND;
- if (doBackground) {
- // We have inherited a background priority from the caller.
- // Ensure this thread is in the background scheduling class,
- // since the driver won't modify scheduling classes for us.
- androidSetThreadSchedulingGroup(mMyThreadId,
- ANDROID_TGROUP_BG_NONINTERACT);
+ int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
+ if (gDisableBackgroundScheduling) {
+ if (curPrio > ANDROID_PRIORITY_NORMAL) {
+ // We have inherited a reduced priority from the caller, but do not
+ // want to run in that state in this process. The driver set our
+ // priority already (though not our scheduling class), so bounce
+ // it back to the default before invoking the transaction.
+ setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
+ }
+ } else {
+ if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
+ // We want to use the inherited priority from the caller.
+ // Ensure this thread is in the background scheduling class,
+ // since the driver won't modify scheduling classes for us.
+ // The scheduling group is reset to default by the caller
+ // once this method returns after the transaction is complete.
+ androidSetThreadSchedulingGroup(mMyThreadId,
+ ANDROID_TGROUP_BG_NONINTERACT);
+ }
}
-
+
//LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
Parcel reply;
@@ -982,14 +992,7 @@
mCallingPid = origPid;
mCallingUid = origUid;
-
- if (doBackground) {
- // We moved to the background scheduling group to execute
- // this transaction, so now that we are done go back in the
- // foreground.
- androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
- }
-
+
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3a3c66b..68b351b 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -693,10 +693,8 @@
//====================================================================
// Bluetooth SCO control
/**
- * @hide
- * TODO unhide for SDK
* Sticky broadcast intent action indicating that the bluetoooth SCO audio
- * connection state has changed. The intent contains on extra {@link EXTRA_SCO_AUDIO_STATE}
+ * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE}
* indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED}
* or {@link #SCO_AUDIO_STATE_CONNECTED}
*
@@ -706,8 +704,6 @@
public static final String ACTION_SCO_AUDIO_STATE_CHANGED =
"android.media.SCO_AUDIO_STATE_CHANGED";
/**
- * @hide
- * TODO unhide for SDK
* Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} containing the new
* bluetooth SCO connection state.
*/
@@ -715,22 +711,16 @@
"android.media.extra.SCO_AUDIO_STATE";
/**
- * @hide
- * TODO unhide for SDK
* Value for extra {@link #EXTRA_SCO_AUDIO_STATE} indicating that the
* SCO audio channel is not established
*/
public static final int SCO_AUDIO_STATE_DISCONNECTED = 0;
/**
- * @hide
- * TODO unhide for SDK
* Value for extra {@link #EXTRA_SCO_AUDIO_STATE} indicating that the
* SCO audio channel is established
*/
public static final int SCO_AUDIO_STATE_CONNECTED = 1;
/**
- * @hide
- * TODO unhide for SDK
* Value for extra {@link #EXTRA_SCO_AUDIO_STATE} indicating that
* there was an error trying to obtain the state
*/
@@ -738,8 +728,6 @@
/**
- * @hide
- * TODO unhide for SDK
* Indicates if current platform supports use of SCO for off call use cases.
* Application wanted to use bluetooth SCO audio when the phone is not in call
* must first call thsi method to make sure that the platform supports this
@@ -754,8 +742,6 @@
}
/**
- * @hide
- * TODO unhide for SDK
* Start bluetooth SCO audio connection.
* <p>Requires Permission:
* {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
@@ -772,7 +758,7 @@
* down the bluetooth connection.
* <p>Even if a SCO connection is established, the following restrictions apply on audio
* output streams so that they can be routed to SCO headset:
- * - the stream type must be {@link #STREAM_VOICE_CALL} or {@link #STREAM_BLUETOOTH_SCO}
+ * - the stream type must be {@link #STREAM_VOICE_CALL}
* - the format must be mono
* - the sampling must be 16kHz or 8kHz
* <p>The following restrictions apply on input streams:
@@ -797,8 +783,6 @@
}
/**
- * @hide
- * TODO unhide for SDK
* Stop bluetooth SCO audio connection.
* <p>Requires Permission:
* {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
@@ -1260,16 +1244,6 @@
}
/**
- * Used to indicate a loss of audio focus of unknown duration.
- * @see OnAudioFocusChangeListener#onAudioFocusChanged(int)
- */
- public static final int AUDIOFOCUS_LOSS = -1;
- /**
- * Used to indicate a transient loss of audio focus.
- * @see OnAudioFocusChangeListener#onAudioFocusChanged(int)
- */
- public static final int AUDIOFOCUS_LOSS_TRANSIENT = -2;
- /**
* Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration.
* @see OnAudioFocusChangeListener#onAudioFocusChanged(int)
* @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
@@ -1283,6 +1257,34 @@
* @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
*/
public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
+ /**
+ * 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 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)
+ * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
+ */
+ public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
+ /**
+ * Used to indicate a loss of audio focus of unknown duration.
+ * @see OnAudioFocusChangeListener#onAudioFocusChanged(int)
+ */
+ public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
+ /**
+ * Used to indicate a transient loss of audio focus.
+ * @see OnAudioFocusChangeListener#onAudioFocusChanged(int)
+ */
+ public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
+ /**
+ * Used to indicate a transient loss of audio focus where the loser of the audio focus can
+ * 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 =
+ -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
/**
* Interface definition for a callback to be invoked when the audio focus of the system is
@@ -1294,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},
- * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}.
+ * 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);
}
@@ -1324,14 +1327,7 @@
*/
private FocusEventHandlerDelegate mAudioFocusEventHandlerDelegate =
new FocusEventHandlerDelegate();
- /**
- * Event id denotes a loss of focus
- */
- private static final int AUDIOFOCUS_EVENT_LOSS = 0;
- /**
- * Event id denotes a gain of focus
- */
- private static final int AUDIOFOCUS_EVENT_GAIN = 1;
+
/**
* Helper class to handle the forwarding of audio focus events to the appropriate listener
*/
@@ -1432,8 +1428,10 @@
* @param streamType the main audio stream type affected by the focus request
* @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} for a focus request of unknown duration such
+ * 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 75e51f9..1992c93 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -1822,7 +1822,7 @@
public IAudioFocusDispatcher mFocusDispatcher = null;
public IBinder mSourceRef = null;
public String mClientId;
- public int mDurationHint;
+ public int mFocusChangeType;
public FocusStackEntry() {
}
@@ -1834,7 +1834,7 @@
mFocusDispatcher = afl;
mSourceRef = source;
mClientId = id;
- mDurationHint = duration;
+ mFocusChangeType = duration;
}
}
@@ -1851,7 +1851,7 @@
while(stackIterator.hasNext()) {
FocusStackEntry fse = stackIterator.next();
pw.println(" source:" + fse.mSourceRef + " -- client: " + fse.mClientId
- + " -- duration: " +fse.mDurationHint);
+ + " -- duration: " +fse.mFocusChangeType);
}
}
}
@@ -1953,7 +1953,7 @@
/** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */
- public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
+ public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
IAudioFocusDispatcher fd, String clientId) {
Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId);
// the main stream type for the audio focus request is currently not used. It may
@@ -1970,7 +1970,7 @@
synchronized(mFocusStack) {
if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) {
- mFocusStack.peek().mDurationHint = durationHint;
+ mFocusStack.peek().mFocusChangeType = focusChangeHint;
// if focus is already owned by this client, don't do anything
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
@@ -1979,9 +1979,7 @@
if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
try {
mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
- (durationHint == AudioManager.AUDIOFOCUS_GAIN) ?
- AudioManager.AUDIOFOCUS_LOSS :
- AudioManager.AUDIOFOCUS_LOSS_TRANSIENT,
+ -1 * focusChangeHint, // loss and gain codes are inverse of each other
mFocusStack.peek().mClientId);
} catch (RemoteException e) {
Log.e(TAG, " Failure to signal loss of focus due to "+ e);
@@ -1990,7 +1988,7 @@
}
// push focus requester at the top of the audio focus stack
- mFocusStack.push(new FocusStackEntry(mainStreamType, durationHint, false, fd, cb,
+ mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, false, fd, cb,
clientId));
}//synchronized(mFocusStack)
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 1047fa4..f845fec1 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -634,8 +634,12 @@
} else if (MediaFile.isImageFileType(mFileType)) {
// FIXME - add DESCRIPTION
} else if (MediaFile.isAudioFileType(mFileType)) {
- map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaStore.UNKNOWN_STRING));
- map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 ? mAlbum : MediaStore.UNKNOWN_STRING));
+ map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0) ?
+ mArtist : MediaStore.UNKNOWN_STRING);
+ map.put(Audio.Media.ALBUM_ARTIST, (mAlbumArtist != null &&
+ mAlbumArtist.length() > 0) ? mAlbumArtist : null);
+ map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0) ?
+ mAlbum : MediaStore.UNKNOWN_STRING);
map.put(Audio.Media.COMPOSER, mComposer);
if (mYear != 0) {
map.put(Audio.Media.YEAR, mYear);
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index a555244..1d71577 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -18,6 +18,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 8cd9578..f30346b 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -839,8 +839,6 @@
addLocked(di, curTimeNano, ev.flags,
RawInputEvent.CLASS_TRACKBALL, me);
}
-
- ms.finish();
}
}
}
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 87a744e..48b3fbb 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -20,8 +20,8 @@
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.PackageHelper;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
-import com.android.server.JournaledFile;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -851,7 +851,8 @@
mFrameworkInstallObserver = new AppDirObserver(
mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
mFrameworkInstallObserver.startWatching();
- scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM,
+ scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
scanMode | SCAN_NO_DEX);
// Collect all system packages.
@@ -859,7 +860,8 @@
mSystemInstallObserver = new AppDirObserver(
mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
mSystemInstallObserver.startWatching();
- scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM, scanMode);
+ scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM
+ | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode);
if (mInstaller != null) {
if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
@@ -2711,8 +2713,6 @@
SharedUserSetting suid = null;
PackageSetting pkgSetting = null;
- boolean removeExisting = false;
-
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
// Only system apps can use these features.
pkg.mOriginalPackages = null;
@@ -2903,7 +2903,7 @@
if (!verifySignaturesLP(pkgSetting, pkg, parseFlags,
(scanMode&SCAN_UPDATE_SIGNATURE) != 0)) {
- if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) == 0) {
+ if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
return null;
}
@@ -2922,7 +2922,10 @@
return null;
}
}
- removeExisting = true;
+ // File a report about this.
+ String msg = "System package " + pkg.packageName
+ + " signature changed; retaining data.";
+ reportSettingsProblem(Log.WARN, msg);
}
// Verify that this new package doesn't have any content providers
@@ -2955,23 +2958,6 @@
final String pkgName = pkg.packageName;
- if (removeExisting) {
- boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(pkg);
- if (mInstaller != null) {
- int ret = mInstaller.remove(pkgName, useEncryptedFSDir);
- if (ret != 0) {
- String msg = "System package " + pkg.packageName
- + " could not have data directory erased after signature change.";
- reportSettingsProblem(Log.WARN, msg);
- mLastScanError = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
- return null;
- }
- }
- Slog.w(TAG, "System package " + pkg.packageName
- + " signature changed: existing data removed.");
- mLastScanError = PackageManager.INSTALL_SUCCEEDED;
- }
-
if (pkg.mAdoptPermissions != null) {
// This package wants to adopt ownership of permissions from
// another package.
@@ -4500,7 +4486,8 @@
if ((event&ADD_EVENTS) != 0) {
if (p == null) {
p = scanPackageLI(fullPath,
- (mIsRom ? PackageParser.PARSE_IS_SYSTEM : 0) |
+ (mIsRom ? PackageParser.PARSE_IS_SYSTEM
+ | PackageParser.PARSE_IS_SYSTEM_DIR: 0) |
PackageParser.PARSE_CHATTY |
PackageParser.PARSE_MUST_BE_APK,
SCAN_MONITOR | SCAN_NO_PATHS);
@@ -4701,23 +4688,22 @@
}
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
} else {
- // When replacing apps make sure we honour
- // the existing app location if not overwritten by other options
- boolean prevOnSd = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
if (onSd) {
// Install flag overrides everything.
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
- // If current upgrade does not specify install location.
+ // If current upgrade specifies particular preference
if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
// Application explicitly specified internal.
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
} else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
// App explictly prefers external. Let policy decide
- } else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
+ } else {
// Prefer previous location
- return prevOnSd ? PackageHelper.RECOMMEND_INSTALL_EXTERNAL:
- PackageHelper.RECOMMEND_INSTALL_INTERNAL;
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+ return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
+ }
+ return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
}
}
} else {
@@ -8294,6 +8280,7 @@
return;
}
} else {
+ mSettingsFilename.delete();
Slog.w(TAG, "Preserving older settings backup");
}
}
@@ -9566,6 +9553,8 @@
// Scan the package
if (scanPackageLI(pkg, parseFlags, SCAN_MONITOR) != null) {
synchronized (mPackages) {
+ updatePermissionsLP(pkg.packageName, pkg,
+ pkg.permissions.size() > 0, false);
retCode = PackageManager.INSTALL_SUCCEEDED;
pkgList.add(pkg.packageName);
// Post process args
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index f4bdd1f..124da4e 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -68,6 +68,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.service.wallpaper.ImageWallpaper;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.JournaledFile;
import com.android.server.DevicePolicyManagerService.ActiveAdmin;
import com.android.server.DevicePolicyManagerService.MyPackageMonitor;
@@ -804,6 +805,9 @@
}
res = r.openRawResource(resId);
+ if (WALLPAPER_FILE.exists()) {
+ WALLPAPER_FILE.delete();
+ }
fos = new FileOutputStream(WALLPAPER_FILE);
byte[] buffer = new byte[32768];
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 90529e5..35b250e 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -1897,6 +1897,7 @@
setWifiApEnabledBlocking(true,
msg.arg1,
(WifiConfiguration) msg.obj);
+ sWakeLock.release();
break;
case MESSAGE_STOP_ACCESS_POINT:
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/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index d170b02..1b9e1c7 100644
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -383,9 +383,13 @@
File backupFile = null;
if (mFile != null && mFile.exists()) {
backupFile = new File(mFile.getPath() + ".bak");
- if (!mFile.renameTo(backupFile)) {
- Slog.w(TAG, "Failed to persist new stats");
- return;
+ if (!backupFile.exists()) {
+ if (!mFile.renameTo(backupFile)) {
+ Slog.w(TAG, "Failed to persist new stats");
+ return;
+ }
+ } else {
+ mFile.delete();
}
}
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index fcb39c9..166b6b6 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -365,6 +365,13 @@
return;
}
+ if (mTetheredNotification != null) {
+ if (mTetheredNotification.icon == icon) {
+ return;
+ }
+ notificationManager.cancel(mTetheredNotification.icon);
+ }
+
Intent intent = new Intent();
intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
@@ -613,10 +620,8 @@
static final int CMD_STOP_TETHERING_ERROR = 10;
// notification from the master SM that it had trouble setting the DNS forwarders
static final int CMD_SET_DNS_FORWARDERS_ERROR = 11;
- // a mechanism to transition self to another state from an enter function
- static final int CMD_TRANSITION_TO_STATE = 12;
// the upstream connection has changed
- static final int CMD_TETHER_CONNECTION_CHANGED = 13;
+ static final int CMD_TETHER_CONNECTION_CHANGED = 12;
private HierarchicalState mDefaultState;
@@ -746,13 +751,14 @@
TetherInterfaceSM.this);
setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
- sendMessageAtFrontOfQueue(CMD_TRANSITION_TO_STATE, mInitialState);
+ transitionTo(mInitialState);
return;
}
}
sendTetherStateChangedBroadcast();
- sendMessageAtFrontOfQueue(CMD_TRANSITION_TO_STATE, mTetheredState);
+ // Skipping StartingState
+ transitionTo(mTetheredState);
}
@Override
public boolean processMessage(Message message) {
@@ -786,10 +792,6 @@
TetherInterfaceSM.this);
transitionTo(mUnavailableState);
break;
- case CMD_TRANSITION_TO_STATE:
- HierarchicalState s = (HierarchicalState)(message.obj);
- transitionTo(s);
- break;
default:
retValue = false;
}
@@ -808,7 +810,7 @@
} catch (Exception e) {
setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);
- sendMessageAtFrontOfQueue(CMD_TRANSITION_TO_STATE, mInitialState);
+ transitionTo(mInitialState);
return;
}
if (mUsb) Tethering.this.enableUsbRndis(true);
@@ -945,10 +947,6 @@
}
transitionTo(mInitialState);
break;
- case CMD_TRANSITION_TO_STATE:
- HierarchicalState s = (HierarchicalState)(message.obj);
- transitionTo(s);
- break;
default:
retValue = false;
break;
@@ -996,10 +994,8 @@
static final int CMD_UPSTREAM_CHANGED = 3;
// we received notice that the cellular DUN connection is up
static final int CMD_CELL_CONNECTION_RENEW = 4;
- // need to do delayed transition from enter/exit
- static final int CMD_TRANSITION_TO_STATE = 5;
// we don't have a valid upstream conn, check again after a delay
- static final int CMD_RETRY_UPSTREAM = 6;
+ static final int CMD_RETRY_UPSTREAM = 5;
// This indicates what a timeout event relates to. A state that
// sends itself a delayed timeout event and handles incoming timeout events
@@ -1103,21 +1099,19 @@
try {
service.setIpForwardingEnabled(true);
} catch (Exception e) {
- sendMessageAtFrontOfQueue(CMD_TRANSITION_TO_STATE,
- mSetIpForwardingEnabledErrorState);
+ transitionTo(mSetIpForwardingEnabledErrorState);
return false;
}
try {
service.startTethering(mDhcpRange[0], mDhcpRange[1]);
} catch (Exception e) {
- sendMessageAtFrontOfQueue(CMD_TRANSITION_TO_STATE, mStartTetheringErrorState);
+ transitionTo(mStartTetheringErrorState);
return false;
}
try {
service.setDnsForwarders(mDnsServers);
} catch (Exception e) {
- sendMessageAtFrontOfQueue(CMD_TRANSITION_TO_STATE,
- mSetDnsForwardersErrorState);
+ transitionTo(mSetDnsForwardersErrorState);
return false;
}
return true;
@@ -1328,10 +1322,6 @@
chooseUpstreamType(mTryCell);
mTryCell = !mTryCell;
break;
- case CMD_TRANSITION_TO_STATE:
- HierarchicalState s = (HierarchicalState)(message.obj);
- transitionTo(s);
- break;
default:
retValue = false;
break;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index 6c20204..95cb1c6 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -20,6 +20,8 @@
import android.util.Log;
import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.gsm.ApnSetting;
+import com.android.internal.telephony.Phone;
import com.android.internal.telephony.RILConstants;
/**
@@ -71,12 +73,20 @@
createTime = -1;
lastFailTime = -1;
lastFailCause = FailCause.NONE;
+ int dataProfile;
+ if ((cp.apn != null) && (cp.apn.types.length > 0) && (cp.apn.types[0] != null) &&
+ (cp.apn.types[0].equals(Phone.APN_TYPE_DUN))) {
+ if (DBG) log("CdmaDataConnection using DUN");
+ dataProfile = RILConstants.DATA_PROFILE_TETHERED;
+ } else {
+ dataProfile = RILConstants.DATA_PROFILE_DEFAULT;
+ }
// msg.obj will be returned in AsyncResult.userObj;
Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
msg.obj = cp;
phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_CDMA),
- Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), null, null,
+ Integer.toString(dataProfile), null, null,
null, Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP), msg);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index af9c652..2f801ccc 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -48,6 +48,7 @@
import com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.EventLogTags;
+import com.android.internal.telephony.gsm.ApnSetting;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.RetryManager;
import com.android.internal.telephony.ServiceStateTracker;
@@ -77,9 +78,6 @@
/** Currently active CdmaDataConnection */
private CdmaDataConnection mActiveDataConnection;
- /** mimic of GSM's mActiveApn */
- private boolean mIsApnActive = false;
-
private boolean mPendingRestartRadio = false;
private static final int TIME_DELAYED_TO_RESTART_RADIO =
SystemProperties.getInt("ro.cdma.timetoradiorestart", 60000);
@@ -108,6 +106,14 @@
Phone.APN_TYPE_DUN,
Phone.APN_TYPE_HIPRI };
+ private static final String[] mDefaultApnTypes = {
+ Phone.APN_TYPE_DEFAULT,
+ Phone.APN_TYPE_MMS,
+ Phone.APN_TYPE_HIPRI };
+
+ // if we have no active Apn this is null
+ protected ApnSetting mActiveApn;
+
// Possibly promoate to base class, the only difference is
// the INTENT_RECONNECT_ALARM action is a different string.
// Do consider technology changes if it is promoted.
@@ -250,7 +256,7 @@
@Override
protected boolean isApnTypeActive(String type) {
- return (mIsApnActive && isApnTypeAvailable(type));
+ return mActiveApn != null && mActiveApn.canHandleType(type);
}
@Override
@@ -265,10 +271,9 @@
protected String[] getActiveApnTypes() {
String[] result;
- if (mIsApnActive) {
- result = mSupportedApnTypes.clone();
+ if (mActiveApn != null) {
+ result = mActiveApn.types;
} else {
- // TODO - should this return an empty array? See GSM too.
result = new String[1];
result[0] = Phone.APN_TYPE_DEFAULT;
}
@@ -414,7 +419,6 @@
}
private boolean setupData(String reason) {
-
CdmaDataConnection conn = findFreeDataConnection();
if (conn == null) {
@@ -423,12 +427,19 @@
}
mActiveDataConnection = conn;
- mIsApnActive = true;
+ String[] types;
+ if (mRequestedApnType.equals(Phone.APN_TYPE_DUN)) {
+ types = new String[1];
+ types[0] = Phone.APN_TYPE_DUN;
+ } else {
+ types = mDefaultApnTypes;
+ }
+ mActiveApn = new ApnSetting(0, "", "", "", "", "", "", "", "", "", "", 0, types);
Message msg = obtainMessage();
msg.what = EVENT_DATA_SETUP_COMPLETE;
msg.obj = reason;
- conn.connect(msg);
+ conn.connect(msg, mActiveApn);
setState(State.INITING);
phone.notifyDataConnection(reason);
@@ -627,7 +638,7 @@
if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason);
setState(State.IDLE);
phone.notifyDataConnection(reason);
- mIsApnActive = false;
+ mActiveApn = null;
}
protected void onRecordsLoaded() {
@@ -649,8 +660,7 @@
*/
@Override
protected void onEnableNewApn() {
- // for cdma we only use this when default data is enabled..
- onTrySetupData(Phone.REASON_DATA_ENABLED);
+ cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
}
/**
@@ -763,7 +773,7 @@
}
phone.notifyDataConnection(reason);
- mIsApnActive = false;
+ mActiveApn = null;
if (retryAfterDisconnected(reason)) {
trySetupData(reason);
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
index 8d807fd..4cbfc87 100644
--- a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
+++ b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
@@ -32,12 +32,12 @@
String user;
String password;
int authType;
- String[] types;
+ public String[] types;
int id;
String numeric;
- ApnSetting(int id, String numeric, String carrier, String apn, String proxy, String port,
+ public ApnSetting(int id, String numeric, String carrier, String apn, String proxy, String port,
String mmsc, String mmsProxy, String mmsPort,
String user, String password, int authType, String[] types) {
this.id = id;
@@ -73,7 +73,7 @@
return sb.toString();
}
- boolean canHandleType(String type) {
+ public boolean canHandleType(String type) {
for (String t : types) {
// DEFAULT handles all, and HIPRI is handled by DEFAULT
if (t.equals(type) || t.equals(Phone.APN_TYPE_ALL) ||
diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
index ee6b89c..63d50c7 100644
--- a/test-runner/src/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -121,6 +121,10 @@
* -e class com.android.foo.FooTest,com.android.foo.TooTest
* com.android.foo/android.test.InstrumentationTestRunner
* <p/>
+ * <b>Running all tests in a java package:</b> adb shell am instrument -w
+ * -e package com.android.foo.subpkg
+ * com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
* <b>Including performance tests:</b> adb shell am instrument -w
* -e perf true
* com.android.foo/android.test.InstrumentationTestRunner
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index 009c0f2d93..dd7a169 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -86,8 +86,7 @@
fail(errMsg);
}
void failStr(Exception e) {
- Log.w(TAG, "e.getMessage="+e.getMessage());
- Log.w(TAG, "e="+e);
+ failStr(e.getMessage());
}
@Override
@@ -297,6 +296,17 @@
private static final int INSTALL_LOC_INT = 1;
private static final int INSTALL_LOC_SD = 2;
private static final int INSTALL_LOC_ERR = -1;
+ private int checkDefaultPolicy(long pkgLen) {
+ // Check for free memory internally
+ if (checkInt(pkgLen)) {
+ return INSTALL_LOC_INT;
+ }
+ // Check for free memory externally
+ if (checkSd(pkgLen)) {
+ return INSTALL_LOC_SD;
+ }
+ return INSTALL_LOC_ERR;
+ }
private int getInstallLoc(int flags, int expInstallLocation, long pkgLen) {
// Flags explicitly over ride everything else.
if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0 ) {
@@ -324,15 +334,7 @@
return INSTALL_LOC_ERR;
}
if (expInstallLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
- // Check for free memory internally
- if (checkInt(pkgLen)) {
- return INSTALL_LOC_INT;
- }
- // Check for free memory externally
- if (checkSd(pkgLen)) {
- return INSTALL_LOC_SD;
- }
- return INSTALL_LOC_ERR;
+ return checkDefaultPolicy(pkgLen);
}
// Check for settings preference.
boolean checkSd = false;
@@ -359,19 +361,9 @@
return INSTALL_LOC_SD;
}
return INSTALL_LOC_ERR;
- } else if (userPref == APP_INSTALL_AUTO) {
- if (checkInt(pkgLen)) {
- return INSTALL_LOC_INT;
- }
- // Check for free memory externally
- if (checkSd(pkgLen)) {
- return INSTALL_LOC_SD;
- }
- return INSTALL_LOC_ERR;
-
}
- }
- return INSTALL_LOC_ERR;
+ }
+ return checkDefaultPolicy(pkgLen);
}
private void assertInstall(PackageParser.Package pkg, int flags, int expInstallLocation) {
@@ -434,7 +426,7 @@
private InstallParams sampleInstallFromRawResource(int flags, boolean cleanUp) {
return installFromRawResource("install.apk", R.raw.install, flags, cleanUp,
- false, -1, PackageInfo.INSTALL_LOCATION_AUTO);
+ false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
}
static final String PERM_PACKAGE = "package";
@@ -1114,7 +1106,7 @@
public void testManifestInstallLocationUnspecified() {
installFromRawResource("install.apk", R.raw.install_loc_unspecified,
- 0, true, false, -1, PackageInfo.INSTALL_LOCATION_AUTO);
+ 0, true, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
}
public void testManifestInstallLocationFwdLockedFlagSdcard() {
@@ -1122,7 +1114,7 @@
PackageManager.INSTALL_FORWARD_LOCK |
PackageManager.INSTALL_EXTERNAL, true, true,
PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION,
- PackageInfo.INSTALL_LOCATION_AUTO);
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
}
public void testManifestInstallLocationFwdLockedSdcard() {
@@ -1178,12 +1170,12 @@
public void testManifestInstallLocationReplaceInternalSdcard() {
int iFlags = 0;
- int iApk = R.raw.install_loc_unspecified;
+ int iApk = R.raw.install_loc_internal;
int rFlags = 0;
int rApk = R.raw.install_loc_sdcard;
InstallParams ip = installFromRawResource("install.apk", iApk,
iFlags, false,
- false, -1, PackageInfo.INSTALL_LOCATION_AUTO);
+ false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName);
int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING;
try {
@@ -1855,21 +1847,28 @@
* The following set of tests check install location for existing
* application based on user setting.
*/
- private void setExistingXUserX(int userSetting, int iFlags) {
+ private int getExpectedInstallLocation(int userSetting) {
+ int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+ boolean enable = getUserSettingSetInstallLocation();
+ if (enable) {
+ if (userSetting == PackageHelper.APP_INSTALL_AUTO) {
+ iloc = PackageInfo.INSTALL_LOCATION_AUTO;
+ } else if (userSetting == PackageHelper.APP_INSTALL_EXTERNAL) {
+ iloc = PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL;
+ } else if (userSetting == PackageHelper.APP_INSTALL_INTERNAL) {
+ iloc = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
+ }
+ }
+ return iloc;
+ }
+ private void setExistingXUserX(int userSetting, int iFlags, int iloc) {
int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
// First install.
installFromRawResource("install.apk", R.raw.install,
iFlags,
false,
false, -1,
- -1);
- // Watch out for this.
- int iloc = PackageInfo.INSTALL_LOCATION_AUTO;
- if ((iFlags & PackageManager.INSTALL_INTERNAL) != 0) {
- iloc = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
- } else if ((iFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
- iloc = PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL;
- }
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
int origSetting = getInstallLoc();
try {
// Set user setting
@@ -1887,49 +1886,56 @@
public void testExistingIUserI() {
int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
int iFlags = PackageManager.INSTALL_INTERNAL;
- setExistingXUserX(userSetting, iFlags);
+ setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
}
public void testExistingIUserE() {
int userSetting = PackageHelper.APP_INSTALL_EXTERNAL;
int iFlags = PackageManager.INSTALL_INTERNAL;
- setExistingXUserX(userSetting, iFlags);
+ setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
}
public void testExistingIUserA() {
int userSetting = PackageHelper.APP_INSTALL_AUTO;
int iFlags = PackageManager.INSTALL_INTERNAL;
- setExistingXUserX(userSetting, iFlags);
+ setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
}
public void testExistingEUserI() {
int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
int iFlags = PackageManager.INSTALL_EXTERNAL;
- setExistingXUserX(userSetting, iFlags);
+ setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
}
public void testExistingEUserE() {
int userSetting = PackageHelper.APP_INSTALL_EXTERNAL;
int iFlags = PackageManager.INSTALL_EXTERNAL;
- setExistingXUserX(userSetting, iFlags);
+ setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
}
public void testExistingEUserA() {
int userSetting = PackageHelper.APP_INSTALL_AUTO;
int iFlags = PackageManager.INSTALL_EXTERNAL;
- setExistingXUserX(userSetting, iFlags);
+ setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
}
/*
* The following set of tests verify that the user setting defines
* the install location.
*
*/
- private void setUserX(int userSetting) {
- int origSetting = getInstallLoc();
- int iloc = PackageInfo.INSTALL_LOCATION_AUTO;
- if (userSetting == PackageHelper.APP_INSTALL_AUTO) {
- iloc = PackageInfo.INSTALL_LOCATION_AUTO;
- } else if (userSetting == PackageHelper.APP_INSTALL_EXTERNAL) {
- iloc = PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL;
- } else if (userSetting == PackageHelper.APP_INSTALL_INTERNAL) {
- iloc = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
- }
+ private boolean getUserSettingSetInstallLocation() {
try {
+ return Settings.System.getInt(mContext.getContentResolver(), Settings.System.SET_INSTALL_LOCATION) != 0;
+
+ } catch (SettingNotFoundException e1) {
+ }
+ return false;
+ }
+
+ private void setUserSettingSetInstallLocation(boolean value) {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SET_INSTALL_LOCATION, value ? 1 : 0);
+ }
+ private void setUserX(boolean enable, int userSetting, int iloc) {
+ boolean origUserSetting = getUserSettingSetInstallLocation();
+ int origSetting = getInstallLoc();
+ try {
+ setUserSettingSetInstallLocation(enable);
// Set user setting
setInstallLoc(userSetting);
// Replace now
@@ -1939,20 +1945,44 @@
false, -1,
iloc);
} finally {
+ // Restore original setting
+ setUserSettingSetInstallLocation(origUserSetting);
setInstallLoc(origSetting);
}
}
public void testUserI() {
int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
- setUserX(userSetting);
+ int iloc = getExpectedInstallLocation(userSetting);
+ setUserX(true, userSetting, iloc);
}
public void testUserE() {
int userSetting = PackageHelper.APP_INSTALL_EXTERNAL;
- setUserX(userSetting);
+ int iloc = getExpectedInstallLocation(userSetting);
+ setUserX(true, userSetting, iloc);
}
public void testUserA() {
int userSetting = PackageHelper.APP_INSTALL_AUTO;
- setUserX(userSetting);
+ int iloc = getExpectedInstallLocation(userSetting);
+ setUserX(true, userSetting, iloc);
+ }
+ /*
+ * The following set of tests turn on/off the basic
+ * user setting for turning on install location.
+ */
+ public void testUserPrefOffUserI() {
+ int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
+ int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+ setUserX(false, userSetting, iloc);
+ }
+ public void testUserPrefOffUserE() {
+ int userSetting = PackageHelper.APP_INSTALL_EXTERNAL;
+ int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+ setUserX(false, userSetting, iloc);
+ }
+ public void testUserPrefOffA() {
+ int userSetting = PackageHelper.APP_INSTALL_AUTO;
+ int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+ setUserX(false, userSetting, iloc);
}
static final String BASE_PERMISSIONS_DEFINED[] = new String[] {
@@ -2126,6 +2156,33 @@
}
}
+ /*
+ * Ensure that permissions are properly declared.
+ */
+ public void testInstallOnSdPermissionsUnmount() {
+ InstallParams ip = null;
+ boolean origMediaState = getMediaState();
+ try {
+ // **: Upon installing a package, are its declared permissions published?
+ int iFlags = PackageManager.INSTALL_INTERNAL;
+ int iApk = R.raw.install_decl_perm;
+ ip = installFromRawResource("install.apk", iApk,
+ iFlags, false,
+ false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+ assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
+ assertPermissions(BASE_PERMISSIONS_DEFINED);
+ // Unmount media here
+ assertTrue(unmountMedia());
+ // Mount media again
+ mountMedia();
+ //Check permissions now
+ assertPermissions(BASE_PERMISSIONS_DEFINED);
+ } finally {
+ if (ip != null) {
+ cleanUpInstall(ip);
+ }
+ }
+ }
/*---------- Recommended install location tests ----*/
/*
* TODO's
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index b668bd0..d51d17a 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -91,7 +91,6 @@
ignoreResultList.add("http/tests/appcache/disabled.html"); // not found
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/local-content.html"); // text diff
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
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 87f2420..a8ac2ec 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -611,7 +611,8 @@
const String16 attr(attr8);
if (node->getAttribute(ns, attr) != NULL) {
- fprintf(stderr, "Warning: AndroidManifest.xml already defines %s (in %s)\n",
+ fprintf(stderr, "Warning: AndroidManifest.xml already defines %s (in %s);"
+ " using existing value in manifest.\n",
String8(attr).string(), String8(ns).string());
return;
}