Merge "API CHANGE: expose the backup-related ApplicationInfo flag masks"
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 6849fd76..6d5686a 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -227,6 +227,15 @@
return true;
}
+ case WILL_ACTIVITY_BE_VISIBLE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ boolean res = willActivityBeVisible(token);
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
+ return true;
+ }
+
case REGISTER_RECEIVER_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
@@ -1360,6 +1369,18 @@
data.recycle();
reply.recycle();
}
+ public boolean willActivityBeVisible(IBinder token) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(WILL_ACTIVITY_BE_VISIBLE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean res = reply.readInt() != 0;
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
public Intent registerReceiver(IApplicationThread caller,
IIntentReceiver receiver,
IntentFilter filter, String perm) throws RemoteException
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7b5b63e..35d1948 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3095,9 +3095,6 @@
r.paused = false;
r.stopped = false;
- if (r.activity.mStartedActivity) {
- r.hideForNow = true;
- }
r.state = null;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
@@ -3132,7 +3129,15 @@
// If the window hasn't yet been added to the window manager,
// and this guy didn't finish itself or start another activity,
// then go ahead and add the window.
- if (r.window == null && !a.mFinished && !a.mStartedActivity) {
+ boolean willBeVisible = !a.mStartedActivity;
+ if (!willBeVisible) {
+ try {
+ willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
+ a.getActivityToken());
+ } catch (RemoteException e) {
+ }
+ }
+ if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
@@ -3148,8 +3153,8 @@
// If the window has already been added, but during resume
// we started another activity, then don't yet make the
- // window visisble.
- } else if (a.mStartedActivity) {
+ // window visible.
+ } else if (!willBeVisible) {
if (localLOGV) Log.v(
TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
@@ -3157,7 +3162,7 @@
// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
- if (!r.activity.mFinished && !a.mStartedActivity
+ if (!r.activity.mFinished && willBeVisible
&& r.activity.mDecor != null && !r.hideForNow) {
if (r.newConfig != null) {
if (DEBUG_CONFIGURATION) Log.v(TAG, "Resuming activity "
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 3913ed5..14571de 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -97,6 +97,7 @@
public boolean finishActivity(IBinder token, int code, Intent data)
throws RemoteException;
public void finishSubActivity(IBinder token, String resultWho, int requestCode) throws RemoteException;
+ public boolean willActivityBeVisible(IBinder token) throws RemoteException;
public Intent registerReceiver(IApplicationThread caller,
IIntentReceiver receiver, IntentFilter filter,
String requiredPermission) throws RemoteException;
@@ -501,4 +502,5 @@
int KILL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+102;
int IS_USER_A_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+103;
int START_ACTIVITY_AND_WAIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+104;
+ int WILL_ACTIVITY_BE_VISIBLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+105;
}
diff --git a/core/java/android/app/ListActivity.java b/core/java/android/app/ListActivity.java
index 4b4cc05..84a57b5 100644
--- a/core/java/android/app/ListActivity.java
+++ b/core/java/android/app/ListActivity.java
@@ -51,31 +51,31 @@
* The following code demonstrates an (ugly) custom screen layout. It has a list
* with a green background, and an alternate red "no data" message.
* </p>
- *
+ *
* <pre>
* <?xml version="1.0" encoding="utf-8"?>
* <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
* android:orientation="vertical"
- * android:layout_width="match_parent"
+ * android:layout_width="match_parent"
* android:layout_height="match_parent"
* android:paddingLeft="8dp"
* android:paddingRight="8dp">
- *
+ *
* <ListView android:id="@id/android:list"
- * android:layout_width="match_parent"
+ * android:layout_width="match_parent"
* android:layout_height="match_parent"
* android:background="#00FF00"
* android:layout_weight="1"
* android:drawSelectorOnTop="false"/>
- *
+ *
* <TextView id="@id/android:empty"
- * android:layout_width="match_parent"
+ * android:layout_width="match_parent"
* android:layout_height="match_parent"
* android:background="#FF0000"
* android:text="No data"/>
* </LinearLayout>
* </pre>
- *
+ *
* <p>
* <strong>Row Layout</strong>
* </p>
@@ -96,27 +96,27 @@
* source for the resource two_line_list_item, which displays two data
* fields,one above the other, for each list row.
* </p>
- *
+ *
* <pre>
* <?xml version="1.0" encoding="utf-8"?>
* <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
* android:layout_width="match_parent"
* android:layout_height="wrap_content"
* android:orientation="vertical">
- *
+ *
* <TextView android:id="@+id/text1"
* android:textSize="16sp"
* android:textStyle="bold"
* android:layout_width="match_parent"
* android:layout_height="wrap_content"/>
- *
+ *
* <TextView android:id="@+id/text2"
* android:textSize="16sp"
* android:layout_width="match_parent"
* android:layout_height="wrap_content"/>
* </LinearLayout>
* </pre>
- *
+ *
* <p>
* You must identify the data bound to each TextView object in this layout. The
* syntax for this is discussed in the next section.
@@ -137,40 +137,40 @@
* Contacts provider for all contacts, then binding the Name and Company fields
* to a two line row layout in the activity's ListView.
* </p>
- *
+ *
* <pre>
* public class MyListAdapter extends ListActivity {
- *
+ *
* @Override
* protected void onCreate(Bundle savedInstanceState){
* super.onCreate(savedInstanceState);
- *
+ *
* // We'll define a custom screen layout here (the one shown above), but
* // typically, you could just use the standard ListActivity layout.
* setContentView(R.layout.custom_list_activity_view);
- *
+ *
* // Query for all people contacts using the {@link android.provider.Contacts.People} convenience class.
* // Put a managed wrapper around the retrieved cursor so we don't have to worry about
* // requerying or closing it as the activity changes state.
* mCursor = this.getContentResolver().query(People.CONTENT_URI, null, null, null, null);
* startManagingCursor(mCursor);
- *
- * // Now create a new list adapter bound to the cursor.
+ *
+ * // Now create a new list adapter bound to the cursor.
* // SimpleListAdapter is designed for binding to a Cursor.
* ListAdapter adapter = new SimpleCursorAdapter(
* this, // Context.
- * android.R.layout.two_line_list_item, // Specify the row template to use (here, two columns bound to the two retrieved cursor
+ * android.R.layout.two_line_list_item, // Specify the row template to use (here, two columns bound to the two retrieved cursor
* rows).
* mCursor, // Pass in the cursor to bind to.
* new String[] {People.NAME, People.COMPANY}, // Array of cursor columns to bind to.
* new int[] {android.R.id.text1, android.R.id.text2}); // Parallel array of which template objects to bind to those columns.
- *
+ *
* // Bind to our new adapter.
* setListAdapter(adapter);
* }
* }
* </pre>
- *
+ *
* @see #setListAdapter
* @see android.widget.ListView
*/
@@ -194,13 +194,13 @@
mList.focusableViewAvailable(mList);
}
};
-
+
/**
* This method will be called when an item in the list is selected.
* Subclasses should override. Subclasses can call
* getListView().getItemAtPosition(position) if they need to access the
* data associated with the selected item.
- *
+ *
* @param l The ListView where the click happened
* @param v The view that was clicked within the ListView
* @param position The position of the view in the list
@@ -208,11 +208,11 @@
*/
protected void onListItemClick(ListView l, View v, int position, long id) {
}
-
+
/**
* Ensures the list view has been created before Activity restores all
* of the view states.
- *
+ *
*@see Activity#onRestoreInstanceState(Bundle)
*/
@Override
@@ -222,9 +222,18 @@
}
/**
+ * @see Activity#onDestroy()
+ */
+ @Override
+ protected void onDestroy() {
+ mHandler.removeCallbacks(mRequestFocus);
+ super.onDestroy();
+ }
+
+ /**
* Updates the screen state (current list and other views) when the
* content changes.
- *
+ *
* @see Activity#onContentChanged()
*/
@Override
@@ -262,7 +271,7 @@
/**
* Set the currently selected list item to the specified
* position with the adapter's data
- *
+ *
* @param position
*/
public void setSelection(int position) {
@@ -290,7 +299,7 @@
ensureList();
return mList;
}
-
+
/**
* Get the ListAdapter associated with this activity's ListView.
*/
@@ -303,7 +312,7 @@
return;
}
setContentView(com.android.internal.R.layout.list_content);
-
+
}
private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {
@@ -313,4 +322,3 @@
}
};
}
-
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 17b0330..22e4325 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -359,7 +359,12 @@
case Phone.APN_REQUEST_FAILED:
if (mPhoneService == null && mApnType == Phone.APN_TYPE_DEFAULT) {
// on startup we may try to talk to the phone before it's ready
- // just leave mEnabled as it is for the default apn.
+ // since the phone will come up enabled, go with that.
+ // TODO - this also comes up on telephony crash: if we think mobile data is
+ // off and the telephony stuff crashes and has to restart it will come up
+ // enabled (making a data connection). We will then be out of sync.
+ // A possible solution is a broadcast when telephony restarts.
+ mEnabled = true;
return false;
}
// else fall through
diff --git a/core/java/android/pim/vcard/VCardEntryCommitter.java b/core/java/android/pim/vcard/VCardEntryCommitter.java
index 3cd64b0..2f99e4a 100644
--- a/core/java/android/pim/vcard/VCardEntryCommitter.java
+++ b/core/java/android/pim/vcard/VCardEntryCommitter.java
@@ -19,6 +19,8 @@
import android.net.Uri;
import android.util.Log;
+import java.util.ArrayList;
+
/**
* <P>
* {@link VCardEntryHandler} implementation which commits the entry to ContentResolver.
@@ -35,7 +37,7 @@
private final ContentResolver mContentResolver;
private long mTimeToCommit;
- private Uri mLastCreatedUri;
+ private ArrayList<Uri> mCreatedUris = new ArrayList<Uri>();
public VCardEntryCommitter(ContentResolver resolver) {
mContentResolver = resolver;
@@ -52,11 +54,21 @@
public void onEntryCreated(final VCardEntry contactStruct) {
long start = System.currentTimeMillis();
- mLastCreatedUri = contactStruct.pushIntoContentResolver(mContentResolver);
+ mCreatedUris.add(contactStruct.pushIntoContentResolver(mContentResolver));
mTimeToCommit += System.currentTimeMillis() - start;
}
+ // TODO: Compatibility function to not break the build. Will be removed shortly
+ @Deprecated
public Uri getLastCreatedUri() {
- return mLastCreatedUri;
+ return mCreatedUris.size() == 0 ? null : mCreatedUris.get(mCreatedUris.size() - 1);
+ }
+
+ /**
+ * Returns the list of created Uris. This list should not be modified by the caller as it is
+ * not a clone.
+ */
+ public ArrayList<Uri> getCreatedUris() {
+ return mCreatedUris;
}
}
\ No newline at end of file
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index a5c85c1..4377a2b 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -363,7 +363,7 @@
str[i] = c.getString(0);
i++;
}
- c.deactivate();
+ c.close();
return str;
} catch (IllegalStateException e) {
return new String[0];
@@ -402,7 +402,7 @@
if (!c.moveToNext()) break;
}
}
- c.deactivate();
+ c.close();
} catch (IllegalStateException e) {
Log.e(LOGTAG, "truncateHistory", e);
return;
@@ -427,7 +427,7 @@
null
);
boolean ret = c.moveToFirst();
- c.deactivate();
+ c.close();
return ret;
} catch (IllegalStateException e) {
return false;
@@ -462,7 +462,7 @@
null,
null);
if (!c.moveToFirst()) {
- c.deactivate();
+ c.close();
return;
}
@@ -489,7 +489,7 @@
iconDb.releaseIconForPageUrl(url);
}
} while (c.moveToNext());
- c.deactivate();
+ c.close();
if (!firstTime) {
ContentValues map = new ContentValues();
@@ -576,7 +576,7 @@
} else {
cr.insert(SEARCHES_URI, map);
}
- c.deactivate();
+ c.close();
} catch (IllegalStateException e) {
Log.e(LOGTAG, "addSearchUrl", e);
return;
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index c06a1e2..40a408a 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -887,6 +887,25 @@
"as_vcard");
/**
+ * Base {@link Uri} for referencing multiple {@link Contacts} entry,
+ * created by appending {@link #LOOKUP_KEY} using
+ * {@link Uri#withAppendedPath(Uri, String)}. The lookup keys have to be
+ * encoded and joined with the colon (":") seperator. The resulting string
+ * has to be encoded again. Provides
+ * {@link OpenableColumns} columns when queried, or returns the
+ * referenced contact formatted as a vCard when opened through
+ * {@link ContentResolver#openAssetFileDescriptor(Uri, String)}.
+ *
+ * This is private API because we do not have a well-defined way to
+ * specify several entities yet. The format of this Uri might change in the future
+ * or the Uri might be completely removed.
+ *
+ * @hide
+ */
+ public static final Uri CONTENT_MULTI_VCARD_URI = Uri.withAppendedPath(CONTENT_URI,
+ "as_multi_vcard");
+
+ /**
* Builds a {@link #CONTENT_LOOKUP_URI} style {@link Uri} describing the
* requested {@link Contacts} entry.
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 873e1a6f..503d8b8d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2900,6 +2900,15 @@
*/
public static final String DROPBOX_TAG_PREFIX =
"dropbox:";
+ /**
+ * Lines of logcat to include with system crash/ANR/etc. reports,
+ * as a prefix of the dropbox tag of the report type.
+ * For example, "logcat_for_system_server_anr" controls the lines
+ * of logcat captured with system server ANR reports. 0 to disable.
+ * @hide
+ */
+ public static final String ERROR_LOGCAT_PREFIX =
+ "logcat_for_";
/**
diff --git a/core/java/android/text/style/LeadingMarginSpan.java b/core/java/android/text/style/LeadingMarginSpan.java
index f320701..2f429ff 100644
--- a/core/java/android/text/style/LeadingMarginSpan.java
+++ b/core/java/android/text/style/LeadingMarginSpan.java
@@ -68,7 +68,20 @@
boolean first, Layout layout);
+ /**
+ * An extended version of {@link LeadingMarginSpan}, which allows
+ * the implementor to specify the number of lines of text to which
+ * this object is attached that the "first line of paragraph" margin
+ * width will be applied to.
+ */
public interface LeadingMarginSpan2 extends LeadingMarginSpan, WrapTogetherSpan {
+ /**
+ * Returns the number of lines of text to which this object is
+ * attached that the "first line" margin will apply to.
+ * Note that if this returns N, the first N lines of the region,
+ * not the first N lines of each paragraph, will be given the
+ * special margin width.
+ */
public int getLeadingMarginLineCount();
};
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index d8b6d1f..ff34f4a 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.util.DisplayMetrics;
+import android.util.FloatMath;
/**
* Detects transformation gestures involving more than one pointer ("multitouch")
@@ -96,14 +97,16 @@
* A convenience class to extend when you only want to listen for a subset
* of scaling-related events. This implements all methods in
* {@link OnScaleGestureListener} but does nothing.
- * {@link OnScaleGestureListener#onScale(ScaleGestureDetector)} and
- * {@link OnScaleGestureListener#onScaleBegin(ScaleGestureDetector)} return
+ * {@link OnScaleGestureListener#onScale(ScaleGestureDetector)} returns
+ * {@code false} so that a subclass can retrieve the accumulated scale
+ * factor in an overridden onScaleEnd.
+ * {@link OnScaleGestureListener#onScaleBegin(ScaleGestureDetector)} returns
* {@code true}.
*/
public static class SimpleOnScaleGestureListener implements OnScaleGestureListener {
public boolean onScale(ScaleGestureDetector detector) {
- return true;
+ return false;
}
public boolean onScaleBegin(ScaleGestureDetector detector) {
@@ -115,10 +118,19 @@
}
}
+ /**
+ * This value is the threshold ratio between our previous combined pressure
+ * and the current combined pressure. We will only fire an onScale event if
+ * the computed ratio between the current and previous event pressures is
+ * greater than this value. When pressure decreases rapidly between events
+ * the position values can often be imprecise, as it usually indicates
+ * that the user is in the process of lifting a pointer off of the device.
+ * Its value was tuned experimentally.
+ */
private static final float PRESSURE_THRESHOLD = 0.67f;
- private Context mContext;
- private OnScaleGestureListener mListener;
+ private final Context mContext;
+ private final OnScaleGestureListener mListener;
private boolean mGestureInProgress;
private MotionEvent mPrevEvent;
@@ -137,7 +149,7 @@
private float mPrevPressure;
private long mTimeDelta;
- private float mEdgeSlop;
+ private final float mEdgeSlop;
private float mRightSlopEdge;
private float mBottomSlopEdge;
private boolean mSloppyGesture;
@@ -410,7 +422,7 @@
if (mCurrLen == -1) {
final float cvx = mCurrFingerDiffX;
final float cvy = mCurrFingerDiffY;
- mCurrLen = (float)Math.sqrt(cvx*cvx + cvy*cvy);
+ mCurrLen = FloatMath.sqrt(cvx*cvx + cvy*cvy);
}
return mCurrLen;
}
@@ -425,7 +437,7 @@
if (mPrevLen == -1) {
final float pvx = mPrevFingerDiffX;
final float pvy = mPrevFingerDiffY;
- mPrevLen = (float)Math.sqrt(pvx*pvx + pvy*pvy);
+ mPrevLen = FloatMath.sqrt(pvx*pvx + pvy*pvy);
}
return mPrevLen;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 54c805f..e83b9b5 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1775,6 +1775,7 @@
private CheckForLongPress mPendingCheckForLongPress;
private CheckForTap mPendingCheckForTap = null;
+ private PerformClick mPerformClick;
private UnsetPressedState mUnsetPressedState;
@@ -4330,7 +4331,15 @@
// Only perform take click actions if we were in the pressed state
if (!focusTaken) {
- performClick();
+ // Use a Runnable and post this rather than calling
+ // performClick directly. This lets other visual state
+ // of the view update before click actions start.
+ if (mPerformClick == null) {
+ mPerformClick = new PerformClick();
+ }
+ if (!post(mPerformClick)) {
+ performClick();
+ }
}
}
@@ -8965,6 +8974,12 @@
}
}
+ private final class PerformClick implements Runnable {
+ public void run() {
+ performClick();
+ }
+ }
+
/**
* Interface definition for a callback to be invoked when a key event is
* dispatched to this view. The callback will be invoked before the key
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 390550f..c5a4e9e 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -535,9 +535,10 @@
static final int SET_ROOT_LAYER_MSG_ID = 124;
static final int RETURN_LABEL = 125;
static final int FIND_AGAIN = 126;
+ static final int CENTER_FIT_RECT = 127;
private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
- private static final int LAST_PACKAGE_MSG_ID = FIND_AGAIN;
+ private static final int LAST_PACKAGE_MSG_ID = CENTER_FIT_RECT;
static final String[] HandlerPrivateDebugString = {
"REMEMBER_PASSWORD", // = 1;
@@ -578,7 +579,8 @@
"IMMEDIATE_REPAINT_MSG_ID", // = 123;
"SET_ROOT_LAYER_MSG_ID", // = 124;
"RETURN_LABEL", // = 125;
- "FIND_AGAIN" // = 126;
+ "FIND_AGAIN", // = 126;
+ "CENTER_FIT_RECT" // = 127;
};
// If the site doesn't use the viewport meta tag to specify the viewport,
@@ -5737,49 +5739,50 @@
}
/*
- * Maximize and center the view inside the WebView. If the zoom doesn't need
- * to be changed, do an animated scroll to center it. If the zoom needs to
- * be changed, find the zoom center and do a smooth zoom transition.
+ * Maximize and center the rectangle, specified in the document coordinate
+ * space, inside the WebView. If the zoom doesn't need to be changed, do an
+ * animated scroll to center it. If the zoom needs to be changed, find the
+ * zoom center and do a smooth zoom transition.
*/
- private void centerPluginOnScreen(ViewManager.ChildView child) {
+ private void centerFitRect(int docX, int docY, int docWidth, int docHeight) {
int viewWidth = getViewWidth();
int viewHeight = getViewHeightWithTitle();
- float scale = Math.min((float) viewWidth / child.width,
- (float) viewHeight / child.height);
+ float scale = Math.min((float) viewWidth / docWidth, (float) viewHeight
+ / docHeight);
if (scale < mMinZoomScale) {
scale = mMinZoomScale;
} else if (scale > mMaxZoomScale) {
scale = mMaxZoomScale;
}
if (Math.abs(scale - mActualScale) < MINIMUM_SCALE_INCREMENT) {
- pinScrollTo(
- contentToViewX(child.x + child.width / 2) - viewWidth / 2,
- contentToViewY(child.y + child.height / 2) - viewHeight / 2,
+ pinScrollTo(contentToViewX(docX + docWidth / 2) - viewWidth / 2,
+ contentToViewY(docY + docHeight / 2) - viewHeight / 2,
true, 0);
} else {
- int oldScreenX = contentToViewX(child.x) - mScrollX;
- int newPluginX = (int) (child.x * scale);
- int newPluginWidth = (int) (child.width * scale);
+ int oldScreenX = contentToViewX(docX) - mScrollX;
+ int rectViewX = (int) (docX * scale);
+ int rectViewWidth = (int) (docWidth * scale);
int newMaxWidth = (int) (mContentWidth * scale);
- int newScreenX = (viewWidth - newPluginWidth) / 2;
+ int newScreenX = (viewWidth - rectViewWidth) / 2;
// pin the newX to the WebView
- if (newScreenX > newPluginX) {
- newScreenX = newPluginX;
- } else if (newScreenX > (newMaxWidth - newPluginX - newPluginWidth)) {
- newScreenX = viewWidth - (newMaxWidth - newPluginX);
+ if (newScreenX > rectViewX) {
+ newScreenX = rectViewX;
+ } else if (newScreenX > (newMaxWidth - rectViewX - rectViewWidth)) {
+ newScreenX = viewWidth - (newMaxWidth - rectViewX);
}
mZoomCenterX = (oldScreenX * scale - newScreenX * mActualScale)
/ (scale - mActualScale);
- int oldScreenY = contentToViewY(child.y) - mScrollY;
- int newPluginY = (int) (child.y * scale) + getTitleHeight();
- int newPluginHeight = (int) (child.height * scale);
- int newMaxHeight = (int) (mContentHeight * scale) + getTitleHeight();
- int newScreenY = (viewHeight - newPluginHeight) / 2;
+ int oldScreenY = contentToViewY(docY) - mScrollY;
+ int rectViewY = (int) (docY * scale) + getTitleHeight();
+ int rectViewHeight = (int) (docHeight * scale);
+ int newMaxHeight = (int) (mContentHeight * scale)
+ + getTitleHeight();
+ int newScreenY = (viewHeight - rectViewHeight) / 2;
// pin the newY to the WebView
- if (newScreenY > newPluginY) {
- newScreenY = newPluginY;
- } else if (newScreenY > (newMaxHeight - newPluginY - newPluginHeight)) {
- newScreenY = viewHeight - (newMaxHeight - newPluginY);
+ if (newScreenY > rectViewY) {
+ newScreenY = rectViewY;
+ } else if (newScreenY > (newMaxHeight - rectViewY - rectViewHeight)) {
+ newScreenY = viewHeight - (newMaxHeight - rectViewY);
}
mZoomCenterY = (oldScreenY * scale - newScreenY * mActualScale)
/ (scale - mActualScale);
@@ -5825,7 +5828,7 @@
true);
} else {
mInZoomOverview = false;
- centerPluginOnScreen(plugin);
+ centerFitRect(plugin.x, plugin.y, plugin.width, plugin.height);
}
return;
}
@@ -6642,6 +6645,12 @@
}
break;
+ case CENTER_FIT_RECT:
+ Rect r = (Rect)msg.obj;
+ mInZoomOverview = false;
+ centerFitRect(r.left, r.top, r.width(), r.height());
+ break;
+
default:
super.handleMessage(msg);
break;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 27c7208..a274378 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2462,6 +2462,15 @@
}
}
+ // called by JNI
+ private void centerFitRect(int x, int y, int width, int height) {
+ if (mWebView == null) {
+ return;
+ }
+ mWebView.mPrivateHandler.obtainMessage(WebView.CENTER_FIT_RECT,
+ new Rect(x, y, x + width, y + height)).sendToTarget();
+ }
+
private native void nativePause();
private native void nativeResume();
private native void nativeFreeMemory();
diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index baed020..b3f8830 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -1,21 +1,12 @@
page.title=Designing for Performance
@jd:body
-<p>An Android application should be <em>efficient</em>. It will run on a mobile
-device with limited computing power and storage, a smaller screen, and
-constrained battery life. Battery life is one reason you might want to
-optimize your app even if it already seems to run "fast enough". Battery life
-is important to users, and Android's battery usage breakdown means users will
-know if your app is responsible draining their battery.</p>
-
-<p>One of the trickiest problems you'll face when optimizing Android apps is
-that it's not generally the case that you can say "device X is a factor F
-faster/slower than device Y".
-This is especially true if one of the devices is the emulator, or one of the
-devices has a JIT. If you want to know how your app performs on a given device,
-you need to test it on that device. Drawing conclusions from the emulator is
-particularly dangerous, as is attempting to compare JIT versus non-JIT
-performance: the performance <em>profiles</em> can differ wildly.</p>
+<p>An Android application will run on a mobile device with limited computing
+power and storage, and constrained battery life. Because of
+this, it should be <em>efficient</em>. Battery life is one reason you might
+want to optimize your app even if it already seems to run "fast enough".
+Battery life is important to users, and Android's battery usage breakdown
+means users will know if your app is responsible draining their battery.</p>
<p>This document covers these topics: </p>
<ul>
@@ -32,15 +23,18 @@
<li><a href="#avoidfloat">Use Floating-Point Judiciously</a> </li>
<li><a href="#library">Know And Use The Libraries</a></li>
<li><a href="#native_methods">Use Native Methods Judiciously</a></li>
- <li><a href="#samples">Some Sample Performance Numbers</a> </li>
<li><a href="#closing_notes">Closing Notes</a></li>
</ul>
+<p>Note that although this document primarily covers micro-optimizations,
+these will almost never make or break your software. Choosing the right
+algorithms and data structures should always be your priority, but is
+outside the scope of this document.</p>
+
<a name="intro" id="intro"></a>
<h2>Introduction</h2>
<p>There are two basic rules for writing efficient code:</p>
-
<ul>
<li>Don't do work that you don't need to do.</li>
<li>Don't allocate memory if you can avoid it.</li>
@@ -221,6 +215,16 @@
</blockquote>
+<p>One of the trickiest problems you'll face when micro-optimizing Android
+apps is that the "if you will be running your program on ... multiple hardware
+platforms" clause above is always true. And it's not even generally the case
+that you can say "device X is a factor F faster/slower than device Y".
+This is especially true if one of the devices is the emulator, or one of the
+devices has a JIT. If you want to know how your app performs on a given device,
+you need to test it on that device. Drawing conclusions from the emulator is
+particularly dangerous, as is attempting to compare JIT versus non-JIT
+performance: the performance <em>profiles</em> can differ wildly.</p>
+
<a name="object_creation"></a>
<h2>Avoid Creating Objects</h2>
@@ -529,91 +533,36 @@
<a name="native_methods" id="native_methods"></a>
<h2>Use Native Methods Judiciously</h2>
-<p>Native code isn't necessarily more efficient than Java. There's a cost
-associated with the Java-native transition, it can be significantly more
-difficult to arrange timely collection of your native resources, and you
+<p>Native code isn't necessarily more efficient than Java. For one thing,
+there's a cost associated with the Java-native transition, and the JIT can't
+optimize across these boundaries. If you're allocating native resources (memory
+on the native heap, file descriptors, or whatever), it can be significantly
+more difficult to arrange timely collection of these resources. You also
need to compile your code for each architecture you wish to run on (rather
-than rely on it having a JIT).</p>
+than rely on it having a JIT). You may even have to compile multiple versions
+for what you consider the same architecture: native code compiled for the ARM
+processor in the G1 can't take full advantage of the ARM in the Nexus One, and
+code compiled for the ARM in the Nexus One won't run on the ARM in the G1.</p>
+
+<p>Native code is primarily useful when you have an existing native codebase
+that you want to port to Android, not for "speeding up" parts of a Java app.</p>
<p>(See also <em>Effective Java</em> item 54.)</p>
-<a name="samples" id="samples"></a>
-<h2>Some Sample Performance Numbers</h2>
-
-<p>To illustrate some of our ideas, here is a table listing the approximate
-run times for a few basic actions. Note that these values should NOT be taken
-as absolute numbers: they are a combination of CPU and wall clock time, and
-will change as improvements are made to the system. However, it is worth
-noting how these values apply relative to each other — for example,
-adding a member variable currently takes about four times as long as adding a
-local variable.</p>
-
-<table>
- <tr>
- <th>Action</th>
- <th>Time</th>
- </tr>
- <tr>
- <td>Add a local variable </td>
- <td>1</td>
- </tr>
- <tr class="alt">
- <td>Add a member variable </td>
- <td>4</td>
- </tr>
- <tr>
- <td>Call String.length()</td>
- <td>5</td>
- </tr>
- <tr class="alt">
- <td>Call empty static native method</td>
- <td>5</td>
- </tr>
- <tr>
- <td>Call empty static method </td>
- <td>12</td>
- </tr>
- <tr class="alt">
- <td>Call empty virtual method </td>
- <td>12.5</td>
- </tr>
- <tr>
- <td>Call empty interface method </td>
- <td>15</td>
- </tr>
- <tr class="alt">
- <td>Call Iterator:next() on a HashMap </td>
- <td>165</td>
- </tr>
- <tr>
- <td>Call put() on a HashMap</td>
- <td>600</td>
- </tr>
- <tr class="alt">
- <td>Inflate 1 View from XML </td>
- <td>22,000</td>
- </tr>
- <tr>
- <td>Inflate 1 LinearLayout containing 1 TextView </td>
- <td>25,000</td>
- </tr>
- <tr class="alt">
- <td>Inflate 1 LinearLayout containing 6 View objects </td>
- <td>100,000</td>
- </tr>
- <tr>
- <td>Inflate 1 LinearLayout containing 6 TextView objects </td>
- <td>135,000</td>
- </tr>
- <tr class="alt">
- <td>Launch an empty activity </td>
- <td>3,000,000</td>
- </tr>
-</table>
-
<a name="closing_notes" id="closing_notes"></a>
<h2>Closing Notes</h2>
<p>One last thing: always measure. Before you start optimizing, make sure you
have a problem. Make sure you can accurately measure your existing performance,
or you won't be able to measure the benefit of the alternatives you try.</p>
+
+<p>Every claim made in this document is backed up by a benchmark. The source
+to these benchmarks can be found in the <a href="http://code.google.com/p/dalvik/source/browse/#svn/trunk/benchmarks">code.google.com "dalvik" project</a>.</p>
+
+<p>The benchmarks are built with the
+<a href="http://code.google.com/p/caliper/">Caliper</a> microbenchmarking
+framework for Java. Microbenchmarks are hard to get right, so Caliper goes out
+of its way to do the hard work for you, and even detect some cases where you're
+not measuring what you think you're measuring (because, say, the VM has
+managed to optimize all your code away). We highly recommend you use Caliper
+to run your own microbenchmarks.</p>
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index ff8757d..13cb460 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -19,6 +19,8 @@
#include <utils/Log.h>
#include <dlfcn.h>
+#include <linux/prctl.h>
+#include <sys/resource.h>
#include "../include/OMX.h"
#include "OMXRenderer.h"
@@ -29,6 +31,7 @@
#include <binder/IMemory.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/VideoRenderer.h>
+#include <utils/threads.h>
#include "OMXMaster.h"
@@ -91,6 +94,7 @@
void OMX::CallbackDispatcher::post(const omx_message &msg) {
Mutex::Autolock autoLock(mLock);
+
mQueue.push_back(msg);
mQueueChanged.signal();
}
@@ -112,6 +116,9 @@
}
void OMX::CallbackDispatcher::threadEntry() {
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+ prctl(PR_SET_NAME, (unsigned long)"OMXCallbackDisp", 0, 0, 0);
+
for (;;) {
omx_message msg;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java
index ddf5e0b..8489a67 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java
@@ -49,7 +49,7 @@
private final String TAG = "MediaMimeTest";
private Context mContext;
private final String MP3_FILE = "/sdcard/media_api/music/SHORTMP3.mp3";
- private final String MEDIA_PLAYBACK_NAME = "com.android.music.MediaPlaybackActivity";
+ private final String MEDIA_PLAYBACK_NAME = "com.android.music.MediaPlaybackActivityStarter";
public MediaMimeTest() {
super("com.android.mediaframeworktest", MediaFrameworkTest.class);
@@ -77,7 +77,7 @@
assertMediaPlaybackActivityHandles("audio/mp3");
}
- @MediumTest
+ @Suppress
// Checks the MediaPlaybackActivity handles audio/*.
public void testCheckMediaPlaybackHandlesAudio() throws Exception {
assertMediaPlaybackActivityHandles("audio/*");
@@ -86,7 +86,7 @@
// TODO: temporarily remove from medium suite because it hangs whole suite
// @MediumTest
// Checks the MediaPlaybackActivity handles application/itunes. Some servers
- // set the Content-type header to application/iTunes (with capital T, but
+ // set the Content-type hadb ieader to application/iTunes (with capital T, but
// the download manager downcasts it) for their MP3 podcasts. This is non
// standard but we try to support it anyway.
// See bug 1401491
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index a3bbb74..8202efd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -395,10 +395,10 @@
Thread.sleep(10000);
mEndPid = getMediaserverPid();
int memDiff = mEndMemory - startMemory;
- if (memDiff < 0)
+ if (memDiff < 0) {
memDiff = 0;
- else
- output.write("The total diff = " + memDiff);
+ }
+ output.write("The total diff = " + memDiff);
output.write("\n\n");
// mediaserver crash
if (startPid != mEndPid) {
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index fa25fa9..9407bd5 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -1488,7 +1488,7 @@
height = cbSurface.height - y;
int err = copyPixels(c,
- surface, xoffset, yoffset,
+ txSurface, xoffset, yoffset,
cbSurface, x, y, width, height);
if (err) {
ogles_error(c, err);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index fc20d96..81b8d40 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -81,8 +81,6 @@
*/
private List mNetRequestersPids[];
- private WifiWatchdogService mWifiWatchdogService;
-
// priority order of the nettrackers
// (excluding dynamically set mNetworkPreference)
// TODO - move mNetworkTypePreference into this
@@ -298,11 +296,10 @@
WifiStateTracker wst = new WifiStateTracker(context, mHandler);
WifiService wifiService = new WifiService(context, wst);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
+ wifiService.startWifi();
mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
wst.startMonitoring();
- // Constructing this starts it too
- mWifiWatchdogService = new WifiWatchdogService(context, wst);
break;
case ConnectivityManager.TYPE_MOBILE:
mNetTrackers[netType] = new MobileDataStateTracker(context, mHandler,
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 248f579..97a4329 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -124,6 +124,7 @@
private INetworkManagementService nwService;
ConnectivityManager mCm;
+ private WifiWatchdogService mWifiWatchdogService = null;
private String[] mWifiRegexs;
/**
@@ -217,8 +218,6 @@
mWifiStateTracker.setWifiState(WIFI_STATE_DISABLED);
mWifiApState = WIFI_AP_STATE_DISABLED;
- boolean wifiEnabled = getPersistedWifiEnabled();
- boolean wifiAPEnabled = wifiEnabled ? false : getPersistedWifiApEnabled();
mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
@@ -240,9 +239,6 @@
}
);
- Slog.i(TAG, "WifiService starting up with Wi-Fi " +
- (wifiEnabled ? "enabled" : "disabled"));
-
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
@@ -267,7 +263,17 @@
}
},new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
+ }
+ /**
+ * Check if Wi-Fi needs to be enabled and start
+ * if needed
+ */
+ public void startWifi() {
+ boolean wifiEnabled = getPersistedWifiEnabled();
+ boolean wifiAPEnabled = wifiEnabled ? false : getPersistedWifiApEnabled();
+ Slog.i(TAG, "WifiService starting up with Wi-Fi " +
+ (wifiEnabled ? "enabled" : "disabled"));
setWifiEnabledBlocking(wifiEnabled, false, Process.myUid());
setWifiApEnabledBlocking(wifiAPEnabled, true, Process.myUid(), null);
}
@@ -446,6 +452,7 @@
registerForBroadcasts();
mWifiStateTracker.startEventLoop();
+
} else {
mContext.unregisterReceiver(mReceiver);
@@ -1803,6 +1810,9 @@
switch (msg.what) {
case MESSAGE_ENABLE_WIFI:
+ if (mWifiWatchdogService == null) {
+ mWifiWatchdogService = new WifiWatchdogService(mContext, mWifiStateTracker);
+ }
setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2);
sWakeLock.release();
break;
@@ -1821,6 +1831,10 @@
// a non-zero msg.arg1 value means the "enabled" setting
// should be persisted
setWifiEnabledBlocking(false, msg.arg1 == 1, msg.arg2);
+ if (mWifiWatchdogService != null) {
+ mWifiWatchdogService.quit();
+ mWifiWatchdogService = null;
+ }
sWakeLock.release();
break;
diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java
index e50b317..e2c523d 100644
--- a/services/java/com/android/server/WifiWatchdogService.java
+++ b/services/java/com/android/server/WifiWatchdogService.java
@@ -89,6 +89,8 @@
*/
private WifiWatchdogHandler mHandler;
+ private ContentObserver mContentObserver;
+
/**
* The current watchdog state. Only written from the main thread!
*/
@@ -132,7 +134,7 @@
ContentResolver contentResolver = mContext.getContentResolver();
contentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_ON), false,
- new ContentObserver(mHandler) {
+ mContentObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
if (isWatchdogEnabled()) {
@@ -272,6 +274,16 @@
}
/**
+ * Unregister broadcasts and quit the watchdog thread
+ */
+ public void quit() {
+ unregisterForWifiBroadcasts();
+ mContext.getContentResolver().unregisterContentObserver(mContentObserver);
+ mHandler.removeAllActions();
+ mHandler.getLooper().quit();
+ }
+
+ /**
* Waits for the main watchdog thread to create the handler.
*/
private void waitForHandlerCreation() {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8866bbd..a437d95 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -111,6 +111,7 @@
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.IllegalStateException;
import java.lang.ref.WeakReference;
@@ -3515,7 +3516,7 @@
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new task " + r.task);
newTask = true;
- addRecentTask(r.task);
+ addRecentTaskLocked(r.task);
} else if (sourceRecord != null) {
if (!addingToTask &&
@@ -3890,7 +3891,7 @@
}
}
- private final void addRecentTask(TaskRecord task) {
+ private final void addRecentTaskLocked(TaskRecord task) {
// Remove any existing entries that are the same kind of task.
int N = mRecentTasks.size();
for (int i=0; i<N; i++) {
@@ -4267,6 +4268,22 @@
}
}
+ public boolean willActivityBeVisible(IBinder token) {
+ synchronized(this) {
+ int i;
+ for (i=mHistory.size()-1; i>=0; i--) {
+ HistoryRecord r = (HistoryRecord)mHistory.get(i);
+ if (r == token) {
+ return true;
+ }
+ if (r.fullscreen && !r.finishing) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
public void overridePendingTransition(IBinder token, String packageName,
int enterAnim, int exitAnim) {
synchronized(this) {
@@ -4922,9 +4939,11 @@
Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
Uri.fromParts("package", packageName, null));
intent.putExtra(Intent.EXTRA_UID, pkgUid);
- broadcastIntentLocked(null, null, intent,
- null, null, 0, null, null, null,
- false, false, MY_PID, Process.SYSTEM_UID);
+ synchronized (this) {
+ broadcastIntentLocked(null, null, intent,
+ null, null, 0, null, null, null,
+ false, false, MY_PID, Process.SYSTEM_UID);
+ }
} catch (RemoteException e) {
}
} finally {
@@ -6984,7 +7003,7 @@
taskTopI = -1;
}
replyChainEnd = -1;
- addRecentTask(target.task);
+ addRecentTaskLocked(target.task);
} else if (forceReset || finishOnTaskLaunch
|| clearWhenTaskReset) {
// If the activity should just be removed -- either
@@ -7206,7 +7225,7 @@
moved.add(0, r);
top--;
if (first) {
- addRecentTask(r.task);
+ addRecentTaskLocked(r.task);
first = false;
}
}
@@ -7231,11 +7250,11 @@
mWindowManager.validateAppTokens(mHistory);
}
- finishTaskMove(task);
+ finishTaskMoveLocked(task);
EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
}
- private final void finishTaskMove(int task) {
+ private final void finishTaskMoveLocked(int task) {
resumeTopActivityLocked(null);
}
@@ -7353,7 +7372,7 @@
mWindowManager.validateAppTokens(mHistory);
}
- finishTaskMove(task);
+ finishTaskMoveLocked(task);
return true;
}
@@ -7985,19 +8004,24 @@
}
public static final void installSystemProviders() {
- ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
- List providers = mSelf.generateApplicationProvidersLocked(app);
- if (providers != null) {
- for (int i=providers.size()-1; i>=0; i--) {
- ProviderInfo pi = (ProviderInfo)providers.get(i);
- if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
- Slog.w(TAG, "Not installing system proc provider " + pi.name
- + ": not system .apk");
- providers.remove(i);
+ List providers;
+ synchronized (mSelf) {
+ ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
+ providers = mSelf.generateApplicationProvidersLocked(app);
+ if (providers != null) {
+ for (int i=providers.size()-1; i>=0; i--) {
+ ProviderInfo pi = (ProviderInfo)providers.get(i);
+ if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ Slog.w(TAG, "Not installing system proc provider " + pi.name
+ + ": not system .apk");
+ providers.remove(i);
+ }
}
}
}
- mSystemThread.installSystemProviders(providers);
+ if (providers != null) {
+ mSystemThread.installSystemProviders(providers);
+ }
}
// =========================================================
@@ -8280,11 +8304,15 @@
}
public void registerActivityWatcher(IActivityWatcher watcher) {
- mWatchers.register(watcher);
+ synchronized (this) {
+ mWatchers.register(watcher);
+ }
}
public void unregisterActivityWatcher(IActivityWatcher watcher) {
- mWatchers.unregister(watcher);
+ synchronized (this) {
+ mWatchers.unregister(watcher);
+ }
}
public final void enterSafeMode() {
@@ -8960,77 +8988,122 @@
* @param crashInfo giving an application stack trace, null if absent
*/
public void addErrorToDropBox(String eventType,
- ProcessRecord process, HistoryRecord activity, HistoryRecord parent,
- String subject, String report, File logFile,
- ApplicationErrorReport.CrashInfo crashInfo) {
+ ProcessRecord process, HistoryRecord activity, HistoryRecord parent, String subject,
+ final String report, final File logFile,
+ final ApplicationErrorReport.CrashInfo crashInfo) {
// NOTE -- this must never acquire the ActivityManagerService lock,
// otherwise the watchdog may be prevented from resetting the system.
- String dropboxTag;
+ String prefix;
if (process == null || process.pid == MY_PID) {
- dropboxTag = "system_server_" + eventType;
+ prefix = "system_server_";
} else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- dropboxTag = "system_app_" + eventType;
+ prefix = "system_app_";
} else {
- dropboxTag = "data_app_" + eventType;
+ prefix = "data_app_";
}
- DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
- if (dbox != null && dbox.isTagEnabled(dropboxTag)) {
- StringBuilder sb = new StringBuilder(1024);
- if (process == null || process.pid == MY_PID) {
- sb.append("Process: system_server\n");
- } else {
- sb.append("Process: ").append(process.processName).append("\n");
- }
- if (process != null) {
- int flags = process.info.flags;
- IPackageManager pm = ActivityThread.getPackageManager();
- sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
- for (String pkg : process.pkgList) {
- sb.append("Package: ").append(pkg);
- try {
- PackageInfo pi = pm.getPackageInfo(pkg, 0);
- if (pi != null) {
- sb.append(" v").append(pi.versionCode);
- if (pi.versionName != null) {
- sb.append(" (").append(pi.versionName).append(")");
- }
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Error getting package info: " + pkg, e);
- }
- sb.append("\n");
- }
- }
- if (activity != null) {
- sb.append("Activity: ").append(activity.shortComponentName).append("\n");
- }
- if (parent != null && parent.app != null && parent.app.pid != process.pid) {
- sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
- }
- if (parent != null && parent != activity) {
- sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
- }
- if (subject != null) {
- sb.append("Subject: ").append(subject).append("\n");
- }
- sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
- sb.append("\n");
- if (report != null) {
- sb.append(report);
- }
- if (logFile != null) {
+ final String dropboxTag = prefix + eventType;
+ final DropBoxManager dbox = (DropBoxManager)
+ mContext.getSystemService(Context.DROPBOX_SERVICE);
+
+ // Exit early if the dropbox isn't configured to accept this report type.
+ if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
+
+ final StringBuilder sb = new StringBuilder(1024);
+ if (process == null || process.pid == MY_PID) {
+ sb.append("Process: system_server\n");
+ } else {
+ sb.append("Process: ").append(process.processName).append("\n");
+ }
+ if (process != null) {
+ int flags = process.info.flags;
+ IPackageManager pm = ActivityThread.getPackageManager();
+ sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
+ for (String pkg : process.pkgList) {
+ sb.append("Package: ").append(pkg);
try {
- sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]"));
- } catch (IOException e) {
- Slog.e(TAG, "Error reading " + logFile, e);
+ PackageInfo pi = pm.getPackageInfo(pkg, 0);
+ if (pi != null) {
+ sb.append(" v").append(pi.versionCode);
+ if (pi.versionName != null) {
+ sb.append(" (").append(pi.versionName).append(")");
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error getting package info: " + pkg, e);
}
+ sb.append("\n");
}
- if (crashInfo != null && crashInfo.stackTrace != null) {
- sb.append(crashInfo.stackTrace);
+ }
+ if (activity != null) {
+ sb.append("Activity: ").append(activity.shortComponentName).append("\n");
+ }
+ if (parent != null && parent.app != null && parent.app.pid != process.pid) {
+ sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
+ }
+ if (parent != null && parent != activity) {
+ sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
+ }
+ if (subject != null) {
+ sb.append("Subject: ").append(subject).append("\n");
+ }
+ sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
+ sb.append("\n");
+
+ // Do the rest in a worker thread to avoid blocking the caller on I/O
+ // (After this point, we shouldn't access AMS internal data structures.)
+ Thread worker = new Thread("Error dump: " + dropboxTag) {
+ @Override
+ public void run() {
+ if (report != null) {
+ sb.append(report);
+ }
+ if (logFile != null) {
+ try {
+ sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]"));
+ } catch (IOException e) {
+ Slog.e(TAG, "Error reading " + logFile, e);
+ }
+ }
+ if (crashInfo != null && crashInfo.stackTrace != null) {
+ sb.append(crashInfo.stackTrace);
+ }
+
+ String setting = Settings.Secure.ERROR_LOGCAT_PREFIX + dropboxTag;
+ int lines = Settings.Secure.getInt(mContext.getContentResolver(), setting, 0);
+ if (lines > 0) {
+ sb.append("\n");
+
+ // Merge several logcat streams, and take the last N lines
+ InputStreamReader input = null;
+ try {
+ java.lang.Process logcat = new ProcessBuilder("/system/bin/logcat",
+ "-v", "time", "-b", "events", "-b", "system", "-b", "main",
+ "-t", String.valueOf(lines)).redirectErrorStream(true).start();
+
+ try { logcat.getOutputStream().close(); } catch (IOException e) {}
+ try { logcat.getErrorStream().close(); } catch (IOException e) {}
+ input = new InputStreamReader(logcat.getInputStream());
+
+ int num;
+ char[] buf = new char[8192];
+ while ((num = input.read(buf)) > 0) sb.append(buf, 0, num);
+ } catch (IOException e) {
+ Slog.e(TAG, "Error running logcat", e);
+ } finally {
+ if (input != null) try { input.close(); } catch (IOException e) {}
+ }
+ }
+
+ dbox.addText(dropboxTag, sb.toString());
}
- dbox.addText(dropboxTag, sb.toString());
+ };
+
+ if (process == null || process.pid == MY_PID) {
+ worker.run(); // We may be about to die -- need to run this synchronously
+ } else {
+ worker.start();
}
}
@@ -11875,7 +11948,7 @@
// BROADCASTS
// =========================================================
- private final List getStickies(String action, IntentFilter filter,
+ private final List getStickiesLocked(String action, IntentFilter filter,
List cur) {
final ContentResolver resolver = mContext.getContentResolver();
final ArrayList<Intent> list = mStickyBroadcasts.get(action);
@@ -11927,10 +12000,10 @@
if (actions != null) {
while (actions.hasNext()) {
String action = (String)actions.next();
- allSticky = getStickies(action, filter, allSticky);
+ allSticky = getStickiesLocked(action, filter, allSticky);
}
} else {
- allSticky = getStickies(null, filter, allSticky);
+ allSticky = getStickiesLocked(null, filter, allSticky);
}
// The first sticky in the list is returned directly back to
@@ -13778,7 +13851,7 @@
/**
* Returns true if things are idle enough to perform GCs.
*/
- private final boolean canGcNow() {
+ private final boolean canGcNowLocked() {
return mParallelBroadcasts.size() == 0
&& mOrderedBroadcasts.size() == 0
&& (mSleeping || (mResumedActivity != null &&
@@ -13794,7 +13867,7 @@
if (N <= 0) {
return;
}
- if (canGcNow()) {
+ if (canGcNowLocked()) {
while (mProcessesToGc.size() > 0) {
ProcessRecord proc = mProcessesToGc.remove(0);
if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
@@ -13822,7 +13895,7 @@
* If all looks good, perform GCs on all processes waiting for them.
*/
final void performAppGcsIfAppropriateLocked() {
- if (canGcNow()) {
+ if (canGcNowLocked()) {
performAppGcsLocked();
return;
}
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 25f123c..ccb5fc6 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -123,17 +123,21 @@
mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
mTetherMasterSM.start();
- // TODO - remove this hack after real USB connections are detected.
+ mStateReceiver = new StateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
+ mContext.registerReceiver(mStateReceiver, filter);
+
+ filter = new IntentFilter();
filter.addAction(Intent.ACTION_MEDIA_SHARED);
filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
+ filter.addDataScheme("file");
+ mContext.registerReceiver(mStateReceiver, filter);
+
mUsbMassStorageOff = !Environment.MEDIA_SHARED.equals(
Environment.getExternalStorageState());
- mStateReceiver = new StateReceiver();
- mContext.registerReceiver(mStateReceiver, filter);
mDhcpRange = context.getResources().getStringArray(
com.android.internal.R.array.config_tether_dhcp_range);
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 521072e..70fdadf 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -135,15 +135,26 @@
}
/**
+ * An instance used for notification of blockingReset.
+ * TODO: Remove when blockingReset is removed.
+ */
+ class ResetSynchronouslyLock {
+ }
+
+ /**
* Used internally for saving disconnecting parameters.
*/
protected static class DisconnectParams {
public DisconnectParams(Message onCompletedMsg) {
this.onCompletedMsg = onCompletedMsg;
}
+ public DisconnectParams(ResetSynchronouslyLock lockObj) {
+ this.lockObj = lockObj;
+ }
public int tag;
public Message onCompletedMsg;
+ public ResetSynchronouslyLock lockObj;
}
/**
@@ -339,11 +350,18 @@
private void notifyDisconnectCompleted(DisconnectParams dp) {
if (DBG) log("NotifyDisconnectCompleted");
- Message msg = dp.onCompletedMsg;
- log(String.format("msg.what=%d msg.obj=%s",
- msg.what, ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>")));
- AsyncResult.forMessage(msg);
- msg.sendToTarget();
+ if (dp.onCompletedMsg != null) {
+ Message msg = dp.onCompletedMsg;
+ log(String.format("msg.what=%d msg.obj=%s",
+ msg.what, ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>")));
+ AsyncResult.forMessage(msg);
+ msg.sendToTarget();
+ }
+ if (dp.lockObj != null) {
+ synchronized(dp.lockObj) {
+ dp.lockObj.notify();
+ }
+ }
clearSettings();
}
@@ -778,6 +796,23 @@
}
/**
+ * Reset the connection and wait for it to complete.
+ * TODO: Remove when all callers only need the asynchronous
+ * reset defined above.
+ */
+ public void resetSynchronously() {
+ ResetSynchronouslyLock lockObj = new ResetSynchronouslyLock();
+ synchronized(lockObj) {
+ sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(lockObj)));
+ try {
+ lockObj.wait();
+ } catch (InterruptedException e) {
+ log("blockingReset: unexpected interrupted of wait()");
+ }
+ }
+ }
+
+ /**
* Connect to the apn and return an AsyncResult in onCompletedMsg.
* Used for cellular networks that use Acess Point Names (APN) such
* as GSM networks.
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 9218715..af9c652 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -386,18 +386,19 @@
if (tearDown) {
if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, reason));
+ notificationDeferred = true;
} else {
- if (DBG) log("cleanUpConnection: !tearDown, call conn.reset");
- conn.reset(obtainMessage(EVENT_RESET_DONE, reason));
+ if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously");
+ conn.resetSynchronously();
+ notificationDeferred = false;
}
- notificationDeferred = true;
}
}
stopNetStatPoll();
if (!notificationDeferred) {
- if (DBG) log("cleanupConnection: !tearDown && !resettingConn");
+ if (DBG) log("cleanupConnection: !notificationDeferred");
gotoIdleAndNotifyDataConnection(reason);
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index f26e54e..f968652 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -507,16 +507,17 @@
if (tearDown) {
if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, reason));
+ notificationDeferred = true;
} else {
- if (DBG) log("cleanUpConnection: !tearDown, call conn.reset");
- conn.reset(obtainMessage(EVENT_RESET_DONE, reason));
+ if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously");
+ conn.resetSynchronously();
+ notificationDeferred = false;
}
- notificationDeferred = true;
}
stopNetStatPoll();
if (!notificationDeferred) {
- if (DBG) log("cleanupConnection: !tearDown && !resettingConn");
+ if (DBG) log("cleanupConnection: !notificationDeferred");
gotoIdleAndNotifyDataConnection(reason);
}
}
diff --git a/test-runner/src/android/test/BundlePrinter.java b/test-runner/src/android/test/BundlePrinter.java
index 96213e7..3c47379 100644
--- a/test-runner/src/android/test/BundlePrinter.java
+++ b/test-runner/src/android/test/BundlePrinter.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.test;
import java.io.PrintStream;
diff --git a/test-runner/src/android/test/IsolatedContext.java b/test-runner/src/android/test/IsolatedContext.java
index f093598..b483b82 100644
--- a/test-runner/src/android/test/IsolatedContext.java
+++ b/test-runner/src/android/test/IsolatedContext.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2008 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.test;
import com.google.android.collect.Lists;
diff --git a/test-runner/src/android/test/ProviderTestCase.java b/test-runner/src/android/test/ProviderTestCase.java
index 668e9f7..e1172cf 100644
--- a/test-runner/src/android/test/ProviderTestCase.java
+++ b/test-runner/src/android/test/ProviderTestCase.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.test;
import android.content.ContentProvider;
diff --git a/test-runner/src/android/test/ProviderTestCase2.java b/test-runner/src/android/test/ProviderTestCase2.java
index f3655fc..28ecee5 100644
--- a/test-runner/src/android/test/ProviderTestCase2.java
+++ b/test-runner/src/android/test/ProviderTestCase2.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.test;
import android.content.ContentProvider;
diff --git a/test-runner/src/android/test/RenamingDelegatingContext.java b/test-runner/src/android/test/RenamingDelegatingContext.java
index 0ea43ab..973b9f2 100644
--- a/test-runner/src/android/test/RenamingDelegatingContext.java
+++ b/test-runner/src/android/test/RenamingDelegatingContext.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.test;
import com.google.android.collect.Sets;
@@ -230,4 +246,4 @@
// }
// return files.toArray(new String[]{});
// }
-}
\ No newline at end of file
+}
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index f2414dd..3c471ca 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -359,7 +359,7 @@
const char* errorMsg = NULL;
int errorPixel = -1;
- const char* errorEdge = "";
+ const char* errorEdge = NULL;
int colorIndex = 0;
@@ -463,6 +463,14 @@
if (yDivs[numYDivs - 1] == H) {
numRows--;
}
+
+ // Make sure the amount of rows and columns will fit in the number of
+ // colors we can use in the 9-patch format.
+ if (numRows * numCols > 0x7F) {
+ errorMsg = "Too many rows and columns in 9-patch perimeter";
+ goto getout;
+ }
+
numColors = numRows * numCols;
image->info9Patch.numColors = numColors;
image->info9Patch.colors = (uint32_t*)malloc(numColors * sizeof(uint32_t));
@@ -533,12 +541,14 @@
fprintf(stderr,
"ERROR: 9-patch image %s malformed.\n"
" %s.\n", imageName, errorMsg);
- if (errorPixel >= 0) {
- fprintf(stderr,
- " Found at pixel #%d along %s edge.\n", errorPixel, errorEdge);
- } else {
- fprintf(stderr,
- " Found along %s edge.\n", errorEdge);
+ if (errorEdge != NULL) {
+ if (errorPixel >= 0) {
+ fprintf(stderr,
+ " Found at pixel #%d along %s edge.\n", errorPixel, errorEdge);
+ } else {
+ fprintf(stderr,
+ " Found along %s edge.\n", errorEdge);
+ }
}
return UNKNOWN_ERROR;
}
@@ -613,7 +623,7 @@
} else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
bpp = 2;
} else if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
- // We use a padding byte even when there is no alpha
+ // We use a padding byte even when there is no alpha
bpp = 4;
} else {
printf("Unknown color type %d.\n", color_type);