diff options
87 files changed, 1306 insertions, 404 deletions
diff --git a/api/current.xml b/api/current.xml index b1763094cc2f..d935c387b1cc 100644 --- a/api/current.xml +++ b/api/current.xml @@ -225218,6 +225218,19 @@ <parameter name="modal" type="boolean"> </parameter> </method> +<method name="setOnDismissListener" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="listener" type="android.widget.PopupWindow.OnDismissListener"> +</parameter> +</method> <method name="setOnItemClickListener" return="void" abstract="false" diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 1c8c73dc0a3e..d8e249ea21f0 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3343,10 +3343,6 @@ public final class ActivityThread { Slog.e(TAG, "Failed to find provider info for " + name); return null; } - if (holder.permissionFailure != null) { - throw new SecurityException("Permission " + holder.permissionFailure - + " required for provider " + name); - } IContentProvider prov = installProvider(context, holder.provider, holder.info, true); diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java index f780e1df93f0..8ba480d23bac 100644 --- a/core/java/android/app/DatePickerDialog.java +++ b/core/java/android/app/DatePickerDialog.java @@ -34,6 +34,9 @@ import java.util.Calendar; /** * A simple dialog containing an {@link android.widget.DatePicker}. + * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date Picker + * tutorial</a>.</p> */ public class DatePickerDialog extends AlertDialog implements OnClickListener, OnDateChangedListener { diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 0d35ba4c7d23..55145828f84f 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -330,28 +330,19 @@ public interface IActivityManager extends IInterface { /** Information you can retrieve about a particular application. */ public static class ContentProviderHolder implements Parcelable { public final ProviderInfo info; - public final String permissionFailure; public IContentProvider provider; public boolean noReleaseNeeded; public ContentProviderHolder(ProviderInfo _info) { info = _info; - permissionFailure = null; } - public ContentProviderHolder(ProviderInfo _info, - String _permissionFailure) { - info = _info; - permissionFailure = _permissionFailure; - } - public int describeContents() { return 0; } public void writeToParcel(Parcel dest, int flags) { info.writeToParcel(dest, 0); - dest.writeString(permissionFailure); if (provider != null) { dest.writeStrongBinder(provider.asBinder()); } else { @@ -373,7 +364,6 @@ public interface IActivityManager extends IInterface { private ContentProviderHolder(Parcel source) { info = ProviderInfo.CREATOR.createFromParcel(source); - permissionFailure = source.readString(); provider = ContentProviderNative.asInterface( source.readStrongBinder()); noReleaseNeeded = source.readInt() != 0; diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java index a04b9e94405b..521d41c3ec4b 100644 --- a/core/java/android/app/TimePickerDialog.java +++ b/core/java/android/app/TimePickerDialog.java @@ -32,6 +32,9 @@ import java.util.Calendar; /** * A dialog that prompts the user for the time of day using a {@link TimePicker}. + * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-timepicker.html">Time Picker + * tutorial</a>.</p> */ public class TimePickerDialog extends AlertDialog implements OnClickListener, OnTimeChangedListener { diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 22bce056ef2d..88e012397083 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -91,6 +91,7 @@ public abstract class ContentProvider implements ComponentCallbacks { private String mReadPermission; private String mWritePermission; private PathPermission[] mPathPermissions; + private boolean mExported; private Transport mTransport = new Transport(); @@ -274,9 +275,9 @@ public abstract class ContentProvider implements ComponentCallbacks { final Context context = getContext(); final String rperm = getReadPermission(); final int pid = Binder.getCallingPid(); - if (rperm == null + if (mExported && (rperm == null || context.checkPermission(rperm, pid, uid) - == PackageManager.PERMISSION_GRANTED) { + == PackageManager.PERMISSION_GRANTED)) { return; } @@ -320,9 +321,9 @@ public abstract class ContentProvider implements ComponentCallbacks { final Context context = getContext(); final String wperm = getWritePermission(); final int pid = Binder.getCallingPid(); - if (wperm == null + if (mExported && (wperm == null || context.checkPermission(wperm, pid, uid) - == PackageManager.PERMISSION_GRANTED) { + == PackageManager.PERMISSION_GRANTED)) { return true; } @@ -972,6 +973,7 @@ public abstract class ContentProvider implements ComponentCallbacks { setReadPermission(info.readPermission); setWritePermission(info.writePermission); setPathPermissions(info.pathPermissions); + mExported = info.exported; } ContentProvider.this.onCreate(); } diff --git a/core/java/android/content/res/ObbInfo.java b/core/java/android/content/res/ObbInfo.java index b18d7848e77d..838c5ff5a764 100644 --- a/core/java/android/content/res/ObbInfo.java +++ b/core/java/android/content/res/ObbInfo.java @@ -25,6 +25,9 @@ import android.os.Parcelable; * @hide */ public class ObbInfo implements Parcelable { + /** Flag noting that this OBB is an overlay patch for a base OBB. */ + public static final int OBB_OVERLAY = 1 << 0; + /** * The name of the package to which the OBB file belongs. */ @@ -35,13 +38,26 @@ public class ObbInfo implements Parcelable { */ public int version; + /** + * The flags relating to the OBB. + */ + public int flags; + public ObbInfo() { } public String toString() { - return "ObbInfo{" - + Integer.toHexString(System.identityHashCode(this)) - + " packageName=" + packageName + ",version=" + version + "}"; + StringBuilder sb = new StringBuilder(); + sb.append("ObbInfo{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" packageName="); + sb.append(packageName); + sb.append(",version="); + sb.append(version); + sb.append(",flags="); + sb.append(flags); + sb.append('}'); + return sb.toString(); } public int describeContents() { @@ -51,6 +67,7 @@ public class ObbInfo implements Parcelable { public void writeToParcel(Parcel dest, int parcelableFlags) { dest.writeString(packageName); dest.writeInt(version); + dest.writeInt(flags); } public static final Parcelable.Creator<ObbInfo> CREATOR @@ -67,5 +84,6 @@ public class ObbInfo implements Parcelable { private ObbInfo(Parcel source) { packageName = source.readString(); version = source.readInt(); + flags = source.readInt(); } } diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index b0c149d18934..37fdeb652742 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -708,9 +708,7 @@ public class TypedArray { outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID]; outValue.changingConfigurations = data[index+AssetManager.STYLE_CHANGING_CONFIGURATIONS]; outValue.density = data[index+AssetManager.STYLE_DENSITY]; - if (type == TypedValue.TYPE_STRING) { - outValue.string = loadStringValueAt(index); - } + outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null; return true; } diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 7c9effadb940..4a0296b2888f 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -295,6 +295,8 @@ public class StorageManager * file matches a package ID that is owned by the calling program's UID. * That is, shared UID applications can obtain access to any other * application's OBB that shares its UID. + * <p> + * STOPSHIP document more; discuss lack of guarantees of security * * @param filename the path to the OBB file * @param key decryption key @@ -319,6 +321,8 @@ public class StorageManager * file matches a package ID that is owned by the calling program's UID. * That is, shared UID applications can obtain access to any other * application's OBB that shares its UID. + * <p> + * STOPSHIP document more; discuss lack of guarantees of security * * @param filename path to the OBB file * @param force whether to kill any programs using this in order to unmount diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java index fed55dcb10a3..55d11bb19a95 100755 --- a/core/java/android/view/WindowOrientationListener.java +++ b/core/java/android/view/WindowOrientationListener.java @@ -103,11 +103,11 @@ public abstract class WindowOrientationListener { } } - public int getCurrentRotation() { + public int getCurrentRotation(int lastRotation) { if (mEnabled) { - return mSensorEventListener.getCurrentRotation(); + return mSensorEventListener.getCurrentRotation(lastRotation); } - return -1; + return lastRotation; } /** @@ -153,9 +153,15 @@ public abstract class WindowOrientationListener { private static final int ROTATION_270 = 2; // Mapping our internal aliases into actual Surface rotation values - private static final int[] SURFACE_ROTATIONS = new int[] { + private static final int[] INTERNAL_TO_SURFACE_ROTATION = new int[] { Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_270}; + // Mapping Surface rotation values to internal aliases. + // We have no constant for Surface.ROTATION_180. That should never happen, but if it + // does, we'll arbitrarily choose a mapping. + private static final int[] SURFACE_TO_INTERNAL_ROTATION = new int[] { + ROTATION_0, ROTATION_90, ROTATION_90, ROTATION_270}; + // Threshold ranges of orientation angle to transition into other orientation states. // The first list is for transitions from ROTATION_0, the next for ROTATION_90, etc. // ROTATE_TO defines the orientation each threshold range transitions to, and must be kept @@ -243,8 +249,12 @@ public abstract class WindowOrientationListener { return (float) SAMPLING_PERIOD_MS / (timeConstantMs + SAMPLING_PERIOD_MS); } - int getCurrentRotation() { - return SURFACE_ROTATIONS[mRotation]; + int getCurrentRotation(int lastRotation) { + if (mTiltDistrust > 0) { + // we really don't know the current orientation, so trust what's currently displayed + mRotation = SURFACE_TO_INTERNAL_ROTATION[lastRotation]; + } + return INTERNAL_TO_SURFACE_ROTATION[mRotation]; } private void calculateNewRotation(float orientation, float tiltAngle) { @@ -267,7 +277,7 @@ public abstract class WindowOrientationListener { if (localLOGV) Log.i(TAG, " new rotation = " + rotation); mRotation = rotation; - mOrientationListener.onOrientationChanged(getCurrentRotation()); + mOrientationListener.onOrientationChanged(INTERNAL_TO_SURFACE_ROTATION[mRotation]); } private float lowpassFilter(float newValue, float oldValue, float alpha) { @@ -306,7 +316,8 @@ public abstract class WindowOrientationListener { mTiltAngle = lowpassFilter(newTiltAngle, mTiltAngle, alpha); float absoluteTilt = Math.abs(mTiltAngle); - if (checkFullyTilted(absoluteTilt)) { + checkFullyTilted(absoluteTilt); + if (mTiltDistrust > 0) { return; // when fully tilted, ignore orientation entirely } @@ -347,11 +358,9 @@ public abstract class WindowOrientationListener { * get un-tilted. * * @param absoluteTilt the absolute value of the current tilt angle - * @return true if the phone is fully tilted */ - private boolean checkFullyTilted(float absoluteTilt) { - boolean fullyTilted = absoluteTilt > MAX_TILT; - if (fullyTilted) { + private void checkFullyTilted(float absoluteTilt) { + if (absoluteTilt > MAX_TILT) { if (mRotation == ROTATION_0) { mOrientationAngle = 0; } else if (mRotation == ROTATION_90) { @@ -366,7 +375,6 @@ public abstract class WindowOrientationListener { } else if (mTiltDistrust > 0) { mTiltDistrust--; } - return fullyTilted; } /** @@ -389,8 +397,8 @@ public abstract class WindowOrientationListener { */ private void filterOrientation(float absoluteTilt, float orientationAngle) { float alpha = DEFAULT_LOWPASS_ALPHA; - if (mTiltDistrust > 0 || mAccelerationDistrust > 1) { - // when fully tilted, or under more than a transient acceleration, distrust heavily + if (mAccelerationDistrust > 1) { + // when under more than a transient acceleration, distrust heavily alpha = ACCELERATING_LOWPASS_ALPHA; } else if (absoluteTilt > PARTIAL_TILT || mAccelerationDistrust == 1) { // when tilted partway, or under transient acceleration, distrust lightly diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index a2628ecd8b7e..4823407d2fbd 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -114,6 +114,9 @@ import java.util.Set; * href="{@docRoot}guide/topics/manifest/manifest-element.html">{@code <manifest>}</a> * element.</p> * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-webview.html">Web View + * tutorial</a>.</p> + * * <h3>Basic usage</h3> * * <p>By default, a WebView provides no browser-like widgets, does not @@ -1275,6 +1278,7 @@ public class WebView extends AbsoluteLayout outState.putBundle("certificate", SslCertificate.saveState(mCertificate)); } + outState.putBoolean("privateBrowsingEnabled", isPrivateBrowsingEnabled()); return list; } @@ -1437,6 +1441,10 @@ public class WebView extends AbsoluteLayout // Update the copy to have the correct index. returnList.setCurrentIndex(index); } + // Restore private browsing setting. + if (inState.getBoolean("privateBrowsingEnabled")) { + getSettings().setPrivateBrowsingEnabled(true); + } // Remove all pending messages because we are restoring previous // state. mWebViewCore.removeMessages(); @@ -1699,18 +1707,7 @@ public class WebView extends AbsoluteLayout getSettings().setPrivateBrowsingEnabled(true); if (!wasPrivateBrowsingEnabled) { - StringBuilder data = new StringBuilder(1024); - try { - InputStreamReader file = new InputStreamReader(mContext.getResources().openRawResource(com.android.internal.R.raw.incognito_mode_start_page)); - int size; - char[] buffer = new char[1024]; - while ((size = file.read(buffer)) != -1) { - data.append(buffer, 0, size); - } - } catch (IOException e) { - // This should never happen since this is a static resource. - } - loadDataWithBaseURL(null, data.toString(), "text/html", "utf-8", null); + loadUrl("browser:incognito"); } } diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index 34aef9928008..e07befa27dda 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -75,6 +75,9 @@ import com.android.internal.R; * } * </pre> * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-autocomplete.html">Auto Complete + * tutorial</a>.</p> + * * @attr ref android.R.styleable#AutoCompleteTextView_completionHint * @attr ref android.R.styleable#AutoCompleteTextView_completionThreshold * @attr ref android.R.styleable#AutoCompleteTextView_completionHintView diff --git a/core/java/android/widget/Button.java b/core/java/android/widget/Button.java index 5e692d4fbbe1..176233e68735 100644 --- a/core/java/android/widget/Button.java +++ b/core/java/android/widget/Button.java @@ -48,6 +48,9 @@ import android.widget.RemoteViews.RemoteView; * } * </pre> * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-formstuff.html">Form Stuff + * tutorial</a>.</p> + * * <p><strong>XML attributes</strong></p> * <p> * See {@link android.R.styleable#Button Button Attributes}, diff --git a/core/java/android/widget/CheckBox.java b/core/java/android/widget/CheckBox.java index ff63a249d769..b89c2a933f56 100644 --- a/core/java/android/widget/CheckBox.java +++ b/core/java/android/widget/CheckBox.java @@ -41,6 +41,9 @@ import android.util.AttributeSet; * } * } * </pre> + * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-formstuff.html">Form Stuff + * tutorial</a>.</p> * * <p><strong>XML attributes</strong></p> * <p> diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index 1fc23abe1eb2..8aed454a4715 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -37,6 +37,9 @@ import java.util.Calendar; /** * A view for selecting a month / year / day based on a calendar like layout. * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date Picker + * tutorial</a>.</p> + * * For a dialog using this view, see {@link android.app.DatePickerDialog}. */ @Widget diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java index 1532db194262..0da68a453e7c 100644 --- a/core/java/android/widget/EditText.java +++ b/core/java/android/widget/EditText.java @@ -35,6 +35,9 @@ import android.util.AttributeSet; /** * EditText is a thin veneer over TextView that configures itself * to be editable. + * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-formstuff.html">Form Stuff + * tutorial</a>.</p> * <p> * <b>XML attributes</b> * <p> diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java index c47292f8f88a..978965811cee 100644 --- a/core/java/android/widget/Gallery.java +++ b/core/java/android/widget/Gallery.java @@ -46,6 +46,9 @@ import android.view.animation.Transformation; * <p> * Views given to the Gallery should use {@link Gallery.LayoutParams} as their * layout parameters type. + * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-gallery.html">Gallery + * tutorial</a>.</p> * * @attr ref android.R.styleable#Gallery_animationDuration * @attr ref android.R.styleable#Gallery_spacing diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index f70051d0a0ff..dffe68589fec 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -34,6 +34,9 @@ import android.widget.RemoteViews.RemoteView; /** * A view that shows items in two-dimensional scrolling grid. The items in the * grid come from the {@link ListAdapter} associated with this view. + * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-gridview.html">Grid + * View tutorial</a>.</p> */ @RemoteView public class GridView extends AbsListView { diff --git a/core/java/android/widget/ImageButton.java b/core/java/android/widget/ImageButton.java index 5c0517022153..12a68db8af1e 100644 --- a/core/java/android/widget/ImageButton.java +++ b/core/java/android/widget/ImageButton.java @@ -62,6 +62,9 @@ import java.util.Map; * it will only be applied after {@code android:state_pressed} and {@code * android:state_focused} have both evaluated false.</p> * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-formstuff.html">Form Stuff + * tutorial</a>.</p> + * * <p><strong>XML attributes</strong></p> * <p> * See {@link android.R.styleable#ImageView Button Attributes}, diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java index 53187bf01ebd..1e5489a0fd1e 100644 --- a/core/java/android/widget/LinearLayout.java +++ b/core/java/android/widget/LinearLayout.java @@ -37,6 +37,9 @@ import android.widget.RemoteViews.RemoteView; * {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams}. * The default orientation is horizontal. * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-linearlayout.html">Linear Layout + * tutorial</a>.</p> + * * <p> * Also see {@link LinearLayout.LayoutParams android.widget.LinearLayout.LayoutParams} * for layout attributes </p> diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index 35e0603630cd..12ff2921dc4e 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -604,6 +604,15 @@ public class ListPopupWindow { mDropDownList = null; } + /** + * Set a listener to receive a callback when the popup is dismissed. + * + * @param listener Listener that will be notified when the popup is dismissed. + */ + public void setOnDismissListener(PopupWindow.OnDismissListener listener) { + mPopup.setOnDismissListener(listener); + } + private void removePromptView() { if (mPromptView != null) { final ViewParent parent = mPromptView.getParent(); diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index de7157bf4b5d..f9bdc43c44ec 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -57,6 +57,9 @@ import java.util.ArrayList; * A view that shows items in a vertically scrolling list. The items * come from the {@link ListAdapter} associated with this view. * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-listview.html">List View + * tutorial</a>.</p> + * * @attr ref android.R.styleable#ListView_entries * @attr ref android.R.styleable#ListView_divider * @attr ref android.R.styleable#ListView_dividerHeight diff --git a/core/java/android/widget/RadioButton.java b/core/java/android/widget/RadioButton.java index 14ec8c6da68c..ebbe1cd17649 100644 --- a/core/java/android/widget/RadioButton.java +++ b/core/java/android/widget/RadioButton.java @@ -34,6 +34,9 @@ import android.util.AttributeSet; * a radio group, checking one radio button unchecks all the others.</p> * </p> * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-formstuff.html">Form Stuff + * tutorial</a>.</p> + * * <p><strong>XML attributes</strong></p> * <p> * See {@link android.R.styleable#CompoundButton CompoundButton Attributes}, diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java index 1800c5a01b9a..28499d062480 100644 --- a/core/java/android/widget/RatingBar.java +++ b/core/java/android/widget/RatingBar.java @@ -41,6 +41,9 @@ import com.android.internal.R; * <p> * The secondary progress should not be modified by the client as it is used * internally as the background for a fractionally filled star. + * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-formstuff.html">Form Stuff + * tutorial</a>.</p> * * @attr ref android.R.styleable#RatingBar_numStars * @attr ref android.R.styleable#RatingBar_rating diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index 64cda49ade65..a47359f8a6a4 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -54,6 +54,9 @@ import java.util.ArrayList; * {@link #ALIGN_PARENT_BOTTOM}. * </p> * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-relativelayout.html">Relative + * Layout tutorial</a>.</p> + * * <p> * Also see {@link android.widget.RelativeLayout.LayoutParams RelativeLayout.LayoutParams} for * layout attributes diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java index 60e8568330c6..b534c340d6ea 100644 --- a/core/java/android/widget/Spinner.java +++ b/core/java/android/widget/Spinner.java @@ -33,6 +33,9 @@ import android.view.ViewGroup; * A view that displays one child at a time and lets the user pick among them. * The items in the Spinner come from the {@link Adapter} associated with * this view. + * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-spinner.html">Spinner + * tutorial</a>.</p> * * @attr ref android.R.styleable#Spinner_prompt */ diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java index 02cd6a81ebfd..f720ceed296b 100644 --- a/core/java/android/widget/TabHost.java +++ b/core/java/android/widget/TabHost.java @@ -40,6 +40,9 @@ import java.util.List; * user clicks to select a specific tab, and a FrameLayout object that displays the contents of that * page. The individual elements are typically controlled using this container object, rather than * setting values on the child elements themselves. + * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-tabwidget.html">Tab Layout + * tutorial</a>.</p> */ public class TabHost extends FrameLayout implements ViewTreeObserver.OnTouchModeChangeListener { diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java index 4e1b5856e156..afae7eff6499 100644 --- a/core/java/android/widget/TabWidget.java +++ b/core/java/android/widget/TabWidget.java @@ -40,6 +40,9 @@ import android.view.View.OnFocusChangeListener; * handler, and manage callbacks. You might call this object to iterate the list * of tabs, or to tweak the layout of the tab list, but most methods should be * called on the containing TabHost object. + * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-tabwidget.html">Tab Layout + * tutorial</a>.</p> * * @attr ref android.R.styleable#TabWidget_divider * @attr ref android.R.styleable#TabWidget_tabStripEnabled diff --git a/core/java/android/widget/TableLayout.java b/core/java/android/widget/TableLayout.java index 73760acdb253..7f26e28b0770 100644 --- a/core/java/android/widget/TableLayout.java +++ b/core/java/android/widget/TableLayout.java @@ -67,6 +67,9 @@ import java.util.regex.Pattern; * <p>Although the typical child of a TableLayout is a TableRow, you can * actually use any View subclass as a direct child of TableLayout. The View * will be displayed as a single row that spans all the table columns.</p> + * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-tablelayout.html">Table + * Layout tutorial</a>.</p> */ public class TableLayout extends LinearLayout { private int[] mMaxWidths; diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index caed308a2be7..e61fac39b54a 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -45,6 +45,9 @@ import java.util.Calendar; * Under AM/PM mode, the user can hit 'a', 'A", 'p' or 'P' to pick. * * For a dialog using this view, see {@link android.app.TimePickerDialog}. + * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-timepicker.html">Time Picker + * tutorial</a>.</p> */ @Widget public class TimePicker extends FrameLayout { diff --git a/core/java/android/widget/ToggleButton.java b/core/java/android/widget/ToggleButton.java index dc791e3b5ef5..3b680e8887ef 100644 --- a/core/java/android/widget/ToggleButton.java +++ b/core/java/android/widget/ToggleButton.java @@ -26,6 +26,9 @@ import android.util.AttributeSet; /** * Displays checked/unchecked states as a button * with a "light" indicator and by default accompanied with the text "ON" or "OFF". + * + * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-formstuff.html">Form Stuff + * tutorial</a>.</p> * * @attr ref android.R.styleable#ToggleButton_textOn * @attr ref android.R.styleable#ToggleButton_textOff diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java index b84789fc40c6..e064e2cf195f 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuView.java +++ b/core/java/com/android/internal/view/menu/ActionMenuView.java @@ -25,7 +25,6 @@ import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.LinearLayout; -import java.lang.ref.WeakReference; import java.util.ArrayList; /** @@ -41,7 +40,13 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo private int mMaxItems; private boolean mReserveOverflow; private OverflowMenuButton mOverflowButton; - private WeakReference<MenuPopupHelper> mOverflowPopup; + private MenuPopupHelper mOverflowPopup; + + private Runnable mShowOverflow = new Runnable() { + public void run() { + showOverflowMenu(); + } + }; public ActionMenuView(Context context) { this(context, null); @@ -66,6 +71,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo Configuration.SCREENLAYOUT_SIZE_XLARGE; } + @Override public void onConfigurationChanged(Configuration newConfig) { final int screen = newConfig.screenLayout; mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) == @@ -75,6 +81,11 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo mMenu.setMaxActionItems(mMaxItems); updateChildren(false); } + + if (mOverflowPopup != null && mOverflowPopup.isShowing()) { + mOverflowPopup.dismiss(); + post(mShowOverflow); + } } private int measureMaxActionButtons() { @@ -172,14 +183,14 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo popup.show(); } }); - mOverflowPopup = new WeakReference<MenuPopupHelper>(popup); + mOverflowPopup = popup; return true; } return false; } public boolean isOverflowMenuShowing() { - MenuPopupHelper popup = mOverflowPopup != null ? mOverflowPopup.get() : null; + MenuPopupHelper popup = mOverflowPopup; if (popup != null) { return popup.isShowing(); } @@ -187,7 +198,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo } public boolean hideOverflowMenu() { - MenuPopupHelper popup = mOverflowPopup != null ? mOverflowPopup.get() : null; + MenuPopupHelper popup = mOverflowPopup; if (popup != null) { popup.dismiss(); return true; diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java index f52c93cf3537..a12a4d6a7b8f 100644 --- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java +++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java @@ -26,6 +26,7 @@ import android.view.View; import android.view.View.MeasureSpec; import android.widget.AdapterView; import android.widget.ListPopupWindow; +import android.widget.PopupWindow; import java.lang.ref.WeakReference; @@ -42,6 +43,12 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On private WeakReference<View> mAnchorView; private boolean mOverflowOnly; + private PopupWindow.OnDismissListener mDismissListener = new PopupWindow.OnDismissListener() { + public void onDismiss() { + mPopup = null; + } + }; + public MenuPopupHelper(Context context, MenuBuilder menu) { this(context, menu, null, false); } @@ -69,6 +76,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On mPopup = new ListPopupWindow(mContext, null, 0, com.android.internal.R.style.Widget_Spinner); mPopup.setOnItemClickListener(this); + mPopup.setOnDismissListener(mDismissListener); final MenuAdapter adapter = mOverflowOnly ? mMenu.getOverflowMenuAdapter(MenuBuilder.TYPE_POPUP) : @@ -95,7 +103,6 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On if (isShowing()) { mPopup.dismiss(); } - mPopup = null; } public boolean isShowing() { diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index 067d0222f52f..b9e4e46b0d6f 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -221,6 +221,14 @@ public class ActionBarView extends ViewGroup { return false; } + public void postShowOverflowMenu() { + post(new Runnable() { + public void run() { + showOverflowMenu(); + } + }); + } + public boolean hideOverflowMenu() { if (mMenuView != null) { return mMenuView.hideOverflowMenu(); diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 204bb74b03f1..578de6f0329a 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -518,35 +518,48 @@ bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, /////////////////////////////////////////////////////////////////////////////// JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env, bool reportSizeToVM) - : fEnv(env), fReportSizeToVM(reportSizeToVM) {} + : fReportSizeToVM(reportSizeToVM) { + if (env->GetJavaVM(&fVM) != JNI_OK) { + SkDebugf("------ [%p] env->GetJavaVM failed\n", env); + sk_throw(); + } +} bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { - return GraphicsJNI::setJavaPixelRef(fEnv, bitmap, ctable, fReportSizeToVM); + JNIEnv* env = vm2env(fVM); + return GraphicsJNI::setJavaPixelRef(env, bitmap, ctable, fReportSizeToVM); } //////////////////////////////////////////////////////////////////////////////// JavaMemoryUsageReporter::JavaMemoryUsageReporter(JNIEnv* env) - : fEnv(env), fTotalSize(0) {} + : fTotalSize(0) { + if (env->GetJavaVM(&fVM) != JNI_OK) { + SkDebugf("------ [%p] env->GetJavaVM failed\n", env); + sk_throw(); + } +} JavaMemoryUsageReporter::~JavaMemoryUsageReporter() { + JNIEnv* env = vm2env(fVM); jlong jtotalSize = fTotalSize; - fEnv->CallVoidMethod(gVMRuntime_singleton, + env->CallVoidMethod(gVMRuntime_singleton, gVMRuntime_trackExternalFreeMethodID, jtotalSize); } bool JavaMemoryUsageReporter::reportMemory(size_t memorySize) { jlong jsize = memorySize; // the VM wants longs for the size - bool r = fEnv->CallBooleanMethod(gVMRuntime_singleton, + JNIEnv* env = vm2env(fVM); + bool r = env->CallBooleanMethod(gVMRuntime_singleton, gVMRuntime_trackExternalAllocationMethodID, jsize); - if (GraphicsJNI::hasException(fEnv)) { + if (GraphicsJNI::hasException(env)) { return false; } if (!r) { LOGE("VM won't let us allocate %zd bytes\n", memorySize); - doThrowOOME(fEnv, "bitmap size exceeds VM budget"); + doThrowOOME(env, "bitmap size exceeds VM budget"); return false; } fTotalSize += memorySize; diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index 8d6528bde70f..1a43a3e622d1 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -80,7 +80,7 @@ public: virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable); private: - JNIEnv* fEnv; + JavaVM* fVM; bool fReportSizeToVM; }; @@ -92,7 +92,7 @@ public: virtual bool reportMemory(size_t memorySize); private: - JNIEnv* fEnv; + JavaVM* fVM; size_t fTotalSize; }; diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp index 12392748f07b..62c89fc72958 100644 --- a/core/jni/android_content_res_ObbScanner.cpp +++ b/core/jni/android_content_res_ObbScanner.cpp @@ -31,6 +31,7 @@ static struct { jfieldID packageName; jfieldID version; + jfieldID flags; } gObbInfoClassInfo; static jboolean android_content_res_ObbScanner_getObbInfo(JNIEnv* env, jobject clazz, jstring file, @@ -85,6 +86,8 @@ int register_android_content_res_ObbScanner(JNIEnv* env) "packageName", "Ljava/lang/String;"); GET_FIELD_ID(gObbInfoClassInfo.version, gObbInfoClassInfo.clazz, "version", "I"); + GET_FIELD_ID(gObbInfoClassInfo.flags, gObbInfoClassInfo.clazz, + "flags", "I"); return AndroidRuntime::registerNativeMethods(env, "android/content/res/ObbScanner", gMethods, NELEM(gMethods)); diff --git a/core/res/res/raw/incognito_mode_start_page.html b/core/res/assets/webkit/incognito_mode_start_page.html index b070c6d0e428..b070c6d0e428 100644 --- a/core/res/res/raw/incognito_mode_start_page.html +++ b/core/res/assets/webkit/incognito_mode_start_page.html diff --git a/docs/html/resources/tutorials/views/hello-formstuff.jd b/docs/html/resources/tutorials/views/hello-formstuff.jd index 3dd5f21a6265..b9f6c16dd749 100644 --- a/docs/html/resources/tutorials/views/hello-formstuff.jd +++ b/docs/html/resources/tutorials/views/hello-formstuff.jd @@ -32,9 +32,19 @@ public void onCreate(Bundle savedInstanceState) { } </pre> +<p>Now select which kind of form widget you'd like to create:</p> +<ul> + <li><a href="#CustomButton">Custom Button</a></li> + <li><a href="#EditText">Edit Text</a></li> + <li><a href="#Checkbox">Checkbox</a></li> + <li><a href="#RadioButtons">Radio Buttons</a></li> + <li><a href="#ToggleButton">Toggle Button</a></li> + <li><a href="#RatingBar">Rating Bar</a></li> +</ul> -<h2>Custom Button</h2> + +<h2 id="CustomButton">Custom Button</h2> <p>In this section, you will create a button with a custom image instead of text, using the {@link android.widget.Button} widget and an XML file that defines three different images to use for the @@ -111,7 +121,8 @@ defines the action to be made when the button is clicked. In this example, a </ol> -<h2>EditText</h2> + +<h2 id="EditText">Edit Text</h2> <p>In this section, you will create a text field for user input, using the {@link android.widget.EditText} widget. Once text has been entered into the field, the "Enter" key will @@ -158,7 +169,8 @@ result in a carriage return in the text field).</p> </ol> -<h2>CheckBox</h2> + +<h2 id="Checkbox">Checkbox</h2> <p>In this section, you will create a checkbox for selecting items, using the {@link android.widget.CheckBox} widget. When the checkbox is pressed, a toast message will @@ -209,7 +221,8 @@ use the {@link android.widget.CompoundButton#setChecked(boolean)} or {@link android.widget.CompoundButton#toggle()} method.</p> -<h2>RadioButton</h2> + +<h2 id="RadioButtons">Radio Buttons</h2> <p>In this section, you will create two mutually-exclusive radio buttons (enabling one disables the other), using the {@link android.widget.RadioGroup} and {@link android.widget.RadioButton} @@ -274,7 +287,8 @@ use the {@link android.widget.CompoundButton#setChecked(boolean)} or {@link android.widget.CompoundButton#toggle()} method.</p> -<h2>ToggleButton</h2> + +<h2 id="ToggleButton">Toggle Button</h2> <p>In this section, you'll create a button used specifically for toggling between two states, using the {@link android.widget.ToggleButton} widget. This widget is an excellent @@ -330,7 +344,7 @@ android.widget.CompoundButton#toggle()} method.</p> -<h2>RatingBar</h2> +<h2 id="RatingBar">Rating Bar</h2> <p>In this section, you'll create a widget that allows the user to provide a rating, with the {@link android.widget.RatingBar} widget.</p> diff --git a/include/media/stagefright/AMRWriter.h b/include/media/stagefright/AMRWriter.h index 813dd43f0a34..aa965e173134 100644 --- a/include/media/stagefright/AMRWriter.h +++ b/include/media/stagefright/AMRWriter.h @@ -37,8 +37,8 @@ struct AMRWriter : public MediaWriter { virtual status_t addSource(const sp<MediaSource> &source); virtual bool reachedEOS(); virtual status_t start(MetaData *params = NULL); - virtual void stop(); - virtual void pause(); + virtual status_t stop(); + virtual status_t pause(); protected: virtual ~AMRWriter(); @@ -57,7 +57,7 @@ private: int64_t mEstimatedDurationUs; static void *ThreadWrapper(void *); - void threadFunc(); + status_t threadFunc(); bool exceedsFileSizeLimit(); bool exceedsFileDurationLimit(); diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h index be96935a6d6e..de82b38c0fab 100644 --- a/include/media/stagefright/MPEG4Writer.h +++ b/include/media/stagefright/MPEG4Writer.h @@ -37,9 +37,9 @@ public: virtual status_t addSource(const sp<MediaSource> &source); virtual status_t start(MetaData *param = NULL); + virtual status_t stop(); + virtual status_t pause(); virtual bool reachedEOS(); - virtual void stop(); - virtual void pause(); void beginBox(const char *fourcc); void writeInt8(int8_t x); diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h index 8d3a9df39302..151bf1639620 100644 --- a/include/media/stagefright/MediaWriter.h +++ b/include/media/stagefright/MediaWriter.h @@ -35,8 +35,9 @@ struct MediaWriter : public RefBase { virtual status_t addSource(const sp<MediaSource> &source) = 0; virtual bool reachedEOS() = 0; virtual status_t start(MetaData *params = NULL) = 0; - virtual void stop() = 0; - virtual void pause() = 0; + virtual status_t stop() = 0; + virtual status_t pause() = 0; + virtual void setMaxFileSize(int64_t bytes) { mMaxFileSizeLimitBytes = bytes; } virtual void setMaxFileDuration(int64_t durationUs) { mMaxFileDurationLimitUs = durationUs; } virtual void setListener(const sp<IMediaRecorderClient>& listener) { diff --git a/media/libstagefright/mpeg2ts/ABitReader.h b/include/media/stagefright/foundation/ABitReader.h index 513521106536..513521106536 100644 --- a/media/libstagefright/mpeg2ts/ABitReader.h +++ b/include/media/stagefright/foundation/ABitReader.h diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h index 2505cb0a89b4..aed4fa112b14 100644 --- a/include/ui/InputDispatcher.h +++ b/include/ui/InputDispatcher.h @@ -159,6 +159,12 @@ public: virtual int32_t waitForMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags, int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets) = 0; + + /* Gets the maximum suggested event delivery rate per second. + * This value is used to throttle motion event movement actions on a per-device + * basis. It is not intended to be a hard limit. + */ + virtual int32_t getMaxEventsPerSecond() = 0; }; @@ -332,6 +338,8 @@ private: // Linked list of motion samples associated with this motion event. MotionSample firstSample; MotionSample* lastSample; + + uint32_t countSamples() const; }; // Tracks the progress of dispatching a particular event to a particular connection. @@ -587,6 +595,17 @@ private: Condition mInjectionSyncFinishedCondition; void decrementPendingSyncDispatchesLocked(EventEntry* entry); + // Throttling state. + struct ThrottleState { + nsecs_t minTimeBetweenEvents; + + nsecs_t lastEventTime; + int32_t lastDeviceId; + uint32_t lastSource; + + uint32_t originalSampleCount; // only collected during debugging + } mThrottleState; + // Key repeat tracking. // XXX Move this up to the input reader instead. struct KeyRepeatState { diff --git a/include/utils/ObbFile.h b/include/utils/ObbFile.h index d2ca82eb55c7..5243f50051fd 100644 --- a/include/utils/ObbFile.h +++ b/include/utils/ObbFile.h @@ -18,12 +18,16 @@ #define OBBFILE_H_ #include <stdint.h> +#include <strings.h> #include <utils/RefBase.h> #include <utils/String8.h> namespace android { +// OBB flags (bit 0) +#define OBB_OVERLAY (1 << 0) + class ObbFile : public RefBase { protected: virtual ~ObbFile(); @@ -46,18 +50,38 @@ public: return mPackageName; } - int32_t getVersion() const { - return mVersion; - } - void setPackageName(String8 packageName) { mPackageName = packageName; } + int32_t getVersion() const { + return mVersion; + } + void setVersion(int32_t version) { mVersion = version; } + int32_t getFlags() const { + return mFlags; + } + + void setFlags(int32_t flags) { + mFlags = flags; + } + + bool isOverlay() { + return (mFlags & OBB_OVERLAY) == OBB_OVERLAY; + } + + void setOverlay(bool overlay) { + if (overlay) { + mFlags |= OBB_OVERLAY; + } else { + mFlags &= ~OBB_OVERLAY; + } + } + static inline uint32_t get4LE(const unsigned char* buf) { return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); } @@ -76,6 +100,9 @@ private: /* Package version this ObbFile is associated with */ int32_t mVersion; + /* Flags for this OBB type. */ + int32_t mFlags; + const char* mFileName; size_t mFileSize; diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index 13030b56e01f..e35050cb6e4c 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -28,6 +28,9 @@ // Log debug messages about input event injection. #define DEBUG_INJECTION 0 +// Log debug messages about input event throttling. +#define DEBUG_THROTTLING 0 + #include <cutils/log.h> #include <ui/InputDispatcher.h> @@ -66,6 +69,15 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mKeyRepeatState.lastKeyEntry = NULL; + int32_t maxEventsPerSecond = policy->getMaxEventsPerSecond(); + mThrottleState.minTimeBetweenEvents = 1000000000LL / maxEventsPerSecond; + mThrottleState.lastDeviceId = -1; + +#if DEBUG_THROTTLING + mThrottleState.originalSampleCount = 0; + LOGD("Throttling - Max events per second = %d", maxEventsPerSecond); +#endif + mCurrentInputTargetsValid = false; } @@ -144,12 +156,61 @@ void InputDispatcher::dispatchOnce() { } } else { // Inbound queue has at least one entry. - // Start processing it but leave it on the queue until later so that the + EventEntry* entry = mInboundQueue.head.next; + + // Consider throttling the entry if it is a move event and there are no + // other events behind it in the queue. Due to movement batching, additional + // samples may be appended to this event by the time the throttling timeout + // expires. + // TODO Make this smarter and consider throttling per device independently. + if (entry->type == EventEntry::TYPE_MOTION) { + MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); + int32_t deviceId = motionEntry->deviceId; + uint32_t source = motionEntry->source; + if (motionEntry->next == & mInboundQueue.tail + && motionEntry->action == AMOTION_EVENT_ACTION_MOVE + && deviceId == mThrottleState.lastDeviceId + && source == mThrottleState.lastSource) { + nsecs_t nextTime = mThrottleState.lastEventTime + + mThrottleState.minTimeBetweenEvents; + if (currentTime < nextTime) { + // Throttle it! +#if DEBUG_THROTTLING + LOGD("Throttling - Delaying motion event for " + "device 0x%x, source 0x%08x by up to %0.3fms.", + deviceId, source, (nextTime - currentTime) * 0.000001); +#endif + if (nextTime < nextWakeupTime) { + nextWakeupTime = nextTime; + } + if (mThrottleState.originalSampleCount == 0) { + mThrottleState.originalSampleCount = + motionEntry->countSamples(); + } + goto Throttle; + } + } + +#if DEBUG_THROTTLING + if (mThrottleState.originalSampleCount != 0) { + uint32_t count = motionEntry->countSamples(); + LOGD("Throttling - Motion event sample count grew by %d from %d to %d.", + count - mThrottleState.originalSampleCount, + mThrottleState.originalSampleCount, count); + mThrottleState.originalSampleCount = 0; + } +#endif + + mThrottleState.lastEventTime = entry->eventTime < currentTime + ? entry->eventTime : currentTime; + mThrottleState.lastDeviceId = deviceId; + mThrottleState.lastSource = source; + } + + // Start processing the entry but leave it on the queue until later so that the // input reader can keep appending samples onto a motion event between the // time we started processing it and the time we finally enqueue dispatch // entries for it. - EventEntry* entry = mInboundQueue.head.next; - switch (entry->type) { case EventEntry::TYPE_CONFIGURATION_CHANGED: { ConfigurationChangedEntry* typedEntry = @@ -179,6 +240,8 @@ void InputDispatcher::dispatchOnce() { mInboundQueue.dequeue(entry); mAllocator.releaseEventEntry(entry); skipPoll = true; + + Throttle: ; } } @@ -192,8 +255,8 @@ void InputDispatcher::dispatchOnce() { return; } - // Wait for callback or timeout or wake. - nsecs_t timeout = nanoseconds_to_milliseconds(nextWakeupTime - currentTime); + // Wait for callback or timeout or wake. (make sure we round up, not down) + nsecs_t timeout = (nextWakeupTime - currentTime + 999999LL) / 1000000LL; int32_t timeoutMillis = timeout > INT_MAX ? -1 : timeout > 0 ? int32_t(timeout) : 0; mPollLoop->pollOnce(timeoutMillis); } @@ -1708,6 +1771,16 @@ void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry, motionEntry->lastSample = sample; } +// --- InputDispatcher::MotionEntry --- + +uint32_t InputDispatcher::MotionEntry::countSamples() const { + uint32_t count = 1; + for (MotionSample* sample = firstSample.next; sample != NULL; sample = sample->next) { + count += 1; + } + return count; +} + // --- InputDispatcher::Connection --- InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel) : diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp index edf1aede5913..ee186c84de9c 100644 --- a/libs/ui/PixelFormat.cpp +++ b/libs/ui/PixelFormat.cpp @@ -63,7 +63,6 @@ status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info) info->bitsPerPixel = 16; goto done; case HAL_PIXEL_FORMAT_YCrCb_420_SP: - case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: case HAL_PIXEL_FORMAT_YV12: info->bitsPerPixel = 12; done: diff --git a/libs/utils/ObbFile.cpp b/libs/utils/ObbFile.cpp index adedf0c5d0dc..e170ab88c12c 100644 --- a/libs/utils/ObbFile.cpp +++ b/libs/utils/ObbFile.cpp @@ -29,12 +29,13 @@ #define kFooterTagSize 8 /* last two 32-bit integers */ -#define kFooterMinSize 21 /* 32-bit signature version - * 32-bit package version - * 32-bit package name size - * 1-character package name - * 32-bit footer size - * 32-bit footer marker +#define kFooterMinSize 25 /* 32-bit signature version (4 bytes) + * 32-bit package version (4 bytes) + * 32-bit flags (4 bytes) + * 32-bit package name size (4-bytes) + * >=1-character package name (1 byte) + * 32-bit footer size (4 bytes) + * 32-bit footer marker (4 bytes) */ #define kMaxBufSize 32768 /* Maximum file read buffer */ @@ -45,8 +46,9 @@ /* offsets in version 1 of the header */ #define kPackageVersionOffset 4 -#define kPackageNameLenOffset 8 -#define kPackageNameOffset 12 +#define kFlagsOffset 8 +#define kPackageNameLenOffset 12 +#define kPackageNameOffset 16 /* * TEMP_FAILURE_RETRY is defined by some, but not all, versions of @@ -78,7 +80,10 @@ typedef off64_t my_off64_t; namespace android { ObbFile::ObbFile() : - mVersion(-1) { + mPackageName(""), + mVersion(-1), + mFlags(0) +{ } ObbFile::~ObbFile() { @@ -199,6 +204,7 @@ bool ObbFile::parseObbFile(int fd) } mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset); + mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset); uint32_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset); if (packageNameLen <= 0 @@ -268,6 +274,12 @@ bool ObbFile::writeTo(int fd) return false; } + put4LE(intBuf, mFlags); + if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { + LOGW("couldn't write package version"); + return false; + } + size_t packageNameLen = mPackageName.size(); put4LE(intBuf, packageNameLen); if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { @@ -280,7 +292,7 @@ bool ObbFile::writeTo(int fd) return false; } - put4LE(intBuf, 3*sizeof(uint32_t) + packageNameLen); + put4LE(intBuf, kPackageNameOffset + packageNameLen); if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { LOGW("couldn't write footer size: %s", strerror(errno)); return false; diff --git a/media/java/android/media/BassBoost.java b/media/java/android/media/BassBoost.java index 73c175163f8a..476b0562ed42 100644 --- a/media/java/android/media/BassBoost.java +++ b/media/java/android/media/BassBoost.java @@ -99,7 +99,7 @@ public class BassBoost extends AudioEffect { UnsupportedOperationException, RuntimeException { super(EFFECT_TYPE_BASS_BOOST, EFFECT_TYPE_NULL, priority, audioSession); - short[] value = new short[1]; + int[] value = new int[1]; checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value)); mStrengthSupported = (value[0] != 0); } diff --git a/media/java/android/media/Virtualizer.java b/media/java/android/media/Virtualizer.java index d03c2a85d222..b08f36e5d8e3 100644 --- a/media/java/android/media/Virtualizer.java +++ b/media/java/android/media/Virtualizer.java @@ -100,7 +100,7 @@ public class Virtualizer extends AudioEffect { UnsupportedOperationException, RuntimeException { super(EFFECT_TYPE_VIRTUALIZER, EFFECT_TYPE_NULL, priority, audioSession); - short[] value = new short[1]; + int[] value = new int[1]; checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value)); mStrengthSupported = (value[0] != 0); } diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index a70bdff3564e..bcd646a34f34 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -1626,9 +1626,15 @@ int BassBoost_getParameter(EffectContext *pContext, switch (param){ case BASSBOOST_PARAM_STRENGTH_SUPPORTED: + if (*pValueSize != sizeof(uint32_t)){ + LOGV("\tLVM_ERROR : BassBoost_getParameter() invalid pValueSize %d", *pValueSize); + return -EINVAL; + } + *pValueSize = sizeof(uint32_t); + break; case BASSBOOST_PARAM_STRENGTH: if (*pValueSize != sizeof(int16_t)){ - LOGV("\tLVM_ERROR : BassBoost_getParameter() invalid pValueSize2 %d", *pValueSize); + LOGV("\tLVM_ERROR : BassBoost_getParameter() invalid pValueSize %d", *pValueSize); return -EINVAL; } *pValueSize = sizeof(int16_t); @@ -1736,9 +1742,16 @@ int Virtualizer_getParameter(EffectContext *pContext, switch (param){ case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED: + if (*pValueSize != sizeof(uint32_t)){ + LOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize); + return -EINVAL; + } + *pValueSize = sizeof(uint32_t); + break; + case VIRTUALIZER_PARAM_STRENGTH: if (*pValueSize != sizeof(int16_t)){ - LOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize2 %d",*pValueSize); + LOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize); return -EINVAL; } *pValueSize = sizeof(int16_t); diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index a616aae13fef..59a544c70f26 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -1141,8 +1141,9 @@ status_t StagefrightRecorder::pause() { status_t StagefrightRecorder::stop() { LOGV("stop"); + status_t err = OK; if (mWriter != NULL) { - mWriter->stop(); + err = mWriter->stop(); mWriter.clear(); } @@ -1164,7 +1165,7 @@ status_t StagefrightRecorder::stop() { mOutputFd = -1; } - return OK; + return err; } status_t StagefrightRecorder::close() { diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp index c71743ef717b..71d48b3dd086 100644 --- a/media/libstagefright/AMRWriter.cpp +++ b/media/libstagefright/AMRWriter.cpp @@ -136,16 +136,17 @@ status_t AMRWriter::start(MetaData *params) { return OK; } -void AMRWriter::pause() { +status_t AMRWriter::pause() { if (!mStarted) { - return; + return OK; } mPaused = true; + return OK; } -void AMRWriter::stop() { +status_t AMRWriter::stop() { if (!mStarted) { - return; + return OK; } mDone = true; @@ -153,9 +154,17 @@ void AMRWriter::stop() { void *dummy; pthread_join(mThread, &dummy); - mSource->stop(); + status_t err = (status_t) dummy; + { + status_t status = mSource->stop(); + if (err == OK && + (status != OK && status != ERROR_END_OF_STREAM)) { + err = status; + } + } mStarted = false; + return err; } bool AMRWriter::exceedsFileSizeLimit() { @@ -174,21 +183,20 @@ bool AMRWriter::exceedsFileDurationLimit() { // static void *AMRWriter::ThreadWrapper(void *me) { - static_cast<AMRWriter *>(me)->threadFunc(); - - return NULL; + return (void *) static_cast<AMRWriter *>(me)->threadFunc(); } -void AMRWriter::threadFunc() { +status_t AMRWriter::threadFunc() { mEstimatedDurationUs = 0; mEstimatedSizeBytes = 0; bool stoppedPrematurely = true; int64_t previousPausedDurationUs = 0; int64_t maxTimestampUs = 0; + status_t err = OK; while (!mDone) { MediaBuffer *buffer; - status_t err = mSource->read(&buffer); + err = mSource->read(&buffer); if (err != OK) { break; @@ -260,6 +268,10 @@ void AMRWriter::threadFunc() { fclose(mFile); mFile = NULL; mReachedEOS = true; + if (err == ERROR_END_OF_STREAM) { + return OK; + } + return err; } bool AMRWriter::reachedEOS() { diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 404762fd1886..b5a6327b3b19 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -40,6 +40,7 @@ LOCAL_SRC_FILES:= \ TimedEventQueue.cpp \ Utils.cpp \ WAVExtractor.cpp \ + avc_utils.cpp \ string.cpp LOCAL_C_INCLUDES:= \ diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index f52ec1a89ec4..6bb54bdd4f49 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -48,8 +48,8 @@ public: ~Track(); status_t start(MetaData *params); - void stop(); - void pause(); + status_t stop(); + status_t pause(); bool reachedEOS(); int64_t getDurationUs() const; @@ -144,7 +144,7 @@ private: int64_t mTrackEveryTimeDurationUs; static void *ThreadWrapper(void *me); - void threadEntry(); + status_t threadEntry(); const uint8_t *parseParamSet( const uint8_t *data, size_t length, int type, size_t *paramSetLen); @@ -378,15 +378,20 @@ status_t MPEG4Writer::start(MetaData *param) { return OK; } -void MPEG4Writer::pause() { +status_t MPEG4Writer::pause() { if (mFile == NULL) { - return; + return OK; } mPaused = true; + status_t err = OK; for (List<Track *>::iterator it = mTracks.begin(); it != mTracks.end(); ++it) { - (*it)->pause(); + status_t status = (*it)->pause(); + if (status != OK) { + err = status; + } } + return err; } void MPEG4Writer::stopWriterThread() { @@ -403,15 +408,19 @@ void MPEG4Writer::stopWriterThread() { pthread_join(mThread, &dummy); } -void MPEG4Writer::stop() { +status_t MPEG4Writer::stop() { if (mFile == NULL) { - return; + return OK; } + status_t err = OK; int64_t maxDurationUs = 0; for (List<Track *>::iterator it = mTracks.begin(); it != mTracks.end(); ++it) { - (*it)->stop(); + status_t status = (*it)->stop(); + if (err == OK && status != OK) { + err = status; + } int64_t durationUs = (*it)->getDurationUs(); if (durationUs > maxDurationUs) { @@ -421,6 +430,15 @@ void MPEG4Writer::stop() { stopWriterThread(); + // Do not write out movie header on error. + if (err != OK) { + fflush(mFile); + fclose(mFile); + mFile = NULL; + mStarted = false; + return err; + } + // Fix up the size of the 'mdat' chunk. if (mUse32BitOffset) { fseeko(mFile, mMdatOffset, SEEK_SET); @@ -508,6 +526,7 @@ void MPEG4Writer::stop() { fclose(mFile); mFile = NULL; mStarted = false; + return err; } status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { @@ -1030,13 +1049,14 @@ status_t MPEG4Writer::Track::start(MetaData *params) { return OK; } -void MPEG4Writer::Track::pause() { +status_t MPEG4Writer::Track::pause() { mPaused = true; + return OK; } -void MPEG4Writer::Track::stop() { +status_t MPEG4Writer::Track::stop() { if (mDone) { - return; + return OK; } mDone = true; @@ -1044,7 +1064,16 @@ void MPEG4Writer::Track::stop() { void *dummy; pthread_join(mThread, &dummy); - mSource->stop(); + status_t err = (status_t) dummy; + + { + status_t status = mSource->stop(); + if (err == OK && status != OK && status != ERROR_END_OF_STREAM) { + err = status; + } + } + + return err; } bool MPEG4Writer::Track::reachedEOS() { @@ -1055,9 +1084,8 @@ bool MPEG4Writer::Track::reachedEOS() { void *MPEG4Writer::Track::ThreadWrapper(void *me) { Track *track = static_cast<Track *>(me); - track->threadEntry(); - - return NULL; + status_t err = track->threadEntry(); + return (void *) err; } #include <ctype.h> @@ -1352,7 +1380,7 @@ static bool collectStatisticalData() { return false; } -void MPEG4Writer::Track::threadEntry() { +status_t MPEG4Writer::Track::threadEntry() { int32_t count = 0; const int64_t interleaveDurationUs = mOwner->interleaveDuration(); int64_t chunkTimestampUs = 0; @@ -1595,7 +1623,7 @@ void MPEG4Writer::Track::threadEntry() { } if (mSampleSizes.empty()) { - err = UNKNOWN_ERROR; + err = ERROR_MALFORMED; } mOwner->trackProgressStatus(this, -1, err); @@ -1626,6 +1654,10 @@ void MPEG4Writer::Track::threadEntry() { count, nZeroLengthFrames, mNumSamples, mMaxWriteTimeUs, mIsAudio? "audio": "video"); logStatisticalData(mIsAudio); + if (err == ERROR_END_OF_STREAM) { + return OK; + } + return err; } void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { @@ -1973,7 +2005,6 @@ void MPEG4Writer::Track::writeTrackHeader( int32_t samplerate; bool success = mMeta->findInt32(kKeySampleRate, &samplerate); CHECK(success); - mOwner->writeInt32(samplerate << 16); if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { mOwner->beginBox("esds"); diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp new file mode 100644 index 000000000000..511ae12c7412 --- /dev/null +++ b/media/libstagefright/avc_utils.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/avc_utils.h" + +#include <media/stagefright/foundation/ABitReader.h> +#include <media/stagefright/foundation/ADebug.h> + +namespace android { + +static unsigned parseUE(ABitReader *br) { + unsigned numZeroes = 0; + while (br->getBits(1) == 0) { + ++numZeroes; + } + + unsigned x = br->getBits(numZeroes); + + return x + (1u << numZeroes) - 1; +} + +// Determine video dimensions from the sequence parameterset. +void FindAVCDimensions( + const sp<ABuffer> &seqParamSet, int32_t *width, int32_t *height) { + ABitReader br(seqParamSet->data() + 1, seqParamSet->size() - 1); + + unsigned profile_idc = br.getBits(8); + br.skipBits(16); + parseUE(&br); // seq_parameter_set_id + + if (profile_idc == 100 || profile_idc == 110 + || profile_idc == 122 || profile_idc == 244 + || profile_idc == 44 || profile_idc == 83 || profile_idc == 86) { + unsigned chroma_format_idc = parseUE(&br); + if (chroma_format_idc == 3) { + br.skipBits(1); // residual_colour_transform_flag + } + parseUE(&br); // bit_depth_luma_minus8 + parseUE(&br); // bit_depth_chroma_minus8 + br.skipBits(1); // qpprime_y_zero_transform_bypass_flag + CHECK_EQ(br.getBits(1), 0u); // seq_scaling_matrix_present_flag + } + + parseUE(&br); // log2_max_frame_num_minus4 + unsigned pic_order_cnt_type = parseUE(&br); + + if (pic_order_cnt_type == 0) { + parseUE(&br); // log2_max_pic_order_cnt_lsb_minus4 + } else if (pic_order_cnt_type == 1) { + // offset_for_non_ref_pic, offset_for_top_to_bottom_field and + // offset_for_ref_frame are technically se(v), but since we are + // just skipping over them the midpoint does not matter. + + br.getBits(1); // delta_pic_order_always_zero_flag + parseUE(&br); // offset_for_non_ref_pic + parseUE(&br); // offset_for_top_to_bottom_field + + unsigned num_ref_frames_in_pic_order_cnt_cycle = parseUE(&br); + for (unsigned i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) { + parseUE(&br); // offset_for_ref_frame + } + } + + parseUE(&br); // num_ref_frames + br.getBits(1); // gaps_in_frame_num_value_allowed_flag + + unsigned pic_width_in_mbs_minus1 = parseUE(&br); + unsigned pic_height_in_map_units_minus1 = parseUE(&br); + unsigned frame_mbs_only_flag = br.getBits(1); + + *width = pic_width_in_mbs_minus1 * 16 + 16; + + *height = (2 - frame_mbs_only_flag) + * (pic_height_in_map_units_minus1 * 16 + 16); +} + +} // namespace android + diff --git a/media/libstagefright/mpeg2ts/ABitReader.cpp b/media/libstagefright/foundation/ABitReader.cpp index 24c8df89cec2..24c8df89cec2 100644 --- a/media/libstagefright/mpeg2ts/ABitReader.cpp +++ b/media/libstagefright/foundation/ABitReader.cpp diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk index 35eea7e18724..f6a8a52bc06d 100644 --- a/media/libstagefright/foundation/Android.mk +++ b/media/libstagefright/foundation/Android.mk @@ -3,6 +3,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ AAtomizer.cpp \ + ABitReader.cpp \ ABuffer.cpp \ ADebug.cpp \ AHandler.cpp \ diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h new file mode 100644 index 000000000000..cc405b5e3ba1 --- /dev/null +++ b/media/libstagefright/include/avc_utils.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AVC_UTILS_H_ + +#define AVC_UTILS_H_ + +#include <media/stagefright/foundation/ABuffer.h> + +namespace android { + +void FindAVCDimensions( + const sp<ABuffer> &seqParamSet, int32_t *width, int32_t *height); + +} // namespace android + +#endif // AVC_UTILS_H_ diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index d05975de9539..26a0fb302efa 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -16,9 +16,10 @@ #include "ATSParser.h" -#include "ABitReader.h" #include "AnotherPacketSource.h" +#include "include/avc_utils.h" +#include <media/stagefright/foundation/ABitReader.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> @@ -473,60 +474,6 @@ static sp<ABuffer> FindNAL( } } -static unsigned parseUE(ABitReader *br) { - unsigned numZeroes = 0; - while (br->getBits(1) == 0) { - ++numZeroes; - } - - unsigned x = br->getBits(numZeroes); - - return x + (1u << numZeroes) - 1; -} - -// Determine video dimensions from the sequence parameterset. -static void FindDimensions( - const sp<ABuffer> seqParamSet, int32_t *width, int32_t *height) { - ABitReader br(seqParamSet->data() + 1, seqParamSet->size() - 1); - - unsigned profile_idc = br.getBits(8); - br.skipBits(16); - parseUE(&br); // seq_parameter_set_id - - if (profile_idc == 100 || profile_idc == 110 - || profile_idc == 122 || profile_idc == 144) { - TRESPASS(); - } - - parseUE(&br); // log2_max_frame_num_minus4 - unsigned pic_order_cnt_type = parseUE(&br); - - if (pic_order_cnt_type == 0) { - parseUE(&br); // log2_max_pic_order_cnt_lsb_minus4 - } else if (pic_order_cnt_type == 1) { - br.getBits(1); // delta_pic_order_always_zero_flag - parseUE(&br); // offset_for_non_ref_pic - parseUE(&br); // offset_for_top_to_bottom_field - - unsigned num_ref_frames_in_pic_order_cnt_cycle = parseUE(&br); - for (unsigned i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) { - parseUE(&br); // offset_for_ref_frame - } - } - - parseUE(&br); // num_ref_frames - br.getBits(1); // gaps_in_frame_num_value_allowed_flag - - unsigned pic_width_in_mbs_minus1 = parseUE(&br); - unsigned pic_height_in_map_units_minus1 = parseUE(&br); - unsigned frame_mbs_only_flag = br.getBits(1); - - *width = pic_width_in_mbs_minus1 * 16 + 16; - - *height = (2 - frame_mbs_only_flag) - * (pic_height_in_map_units_minus1 * 16 + 16); -} - static sp<ABuffer> MakeAVCCodecSpecificData( const sp<ABuffer> &buffer, int32_t *width, int32_t *height) { const uint8_t *data = buffer->data(); @@ -537,7 +484,7 @@ static sp<ABuffer> MakeAVCCodecSpecificData( return NULL; } - FindDimensions(seqParamSet, width, height); + FindAVCDimensions(seqParamSet, width, height); size_t stopOffset; sp<ABuffer> picParamSet = FindNAL(data, size, 8, &stopOffset); diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk index b6772eb89592..3544b4c0151f 100644 --- a/media/libstagefright/mpeg2ts/Android.mk +++ b/media/libstagefright/mpeg2ts/Android.mk @@ -3,7 +3,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - ABitReader.cpp \ AnotherPacketSource.cpp \ ATSParser.cpp \ MPEG2TSExtractor.cpp \ diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp new file mode 100644 index 000000000000..7e633d7b7e56 --- /dev/null +++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AMPEG4ElementaryAssembler.h" + +#include "ARTPSource.h" + +#include <media/stagefright/foundation/ABuffer.h> +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/foundation/hexdump.h> + +#include <stdint.h> + +#define BE_VERBOSE 0 + +namespace android { + +// static +AMPEG4ElementaryAssembler::AMPEG4ElementaryAssembler(const sp<AMessage> ¬ify) + : mNotifyMsg(notify), + mAccessUnitRTPTime(0), + mNextExpectedSeqNoValid(false), + mNextExpectedSeqNo(0), + mAccessUnitDamaged(false) { +} + +AMPEG4ElementaryAssembler::~AMPEG4ElementaryAssembler() { +} + +ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket( + const sp<ARTPSource> &source) { + List<sp<ABuffer> > *queue = source->queue(); + + if (queue->empty()) { + return NOT_ENOUGH_DATA; + } + + if (mNextExpectedSeqNoValid) { + List<sp<ABuffer> >::iterator it = queue->begin(); + while (it != queue->end()) { + if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) { + break; + } + + it = queue->erase(it); + } + + if (queue->empty()) { + return NOT_ENOUGH_DATA; + } + } + + sp<ABuffer> buffer = *queue->begin(); + + if (!mNextExpectedSeqNoValid) { + mNextExpectedSeqNoValid = true; + mNextExpectedSeqNo = (uint32_t)buffer->int32Data(); + } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) { +#if BE_VERBOSE + LOG(VERBOSE) << "Not the sequence number I expected"; +#endif + + return WRONG_SEQUENCE_NUMBER; + } + + uint32_t rtpTime; + CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); + + if (mPackets.size() > 0 && rtpTime != mAccessUnitRTPTime) { + submitAccessUnit(); + } + mAccessUnitRTPTime = rtpTime; + + mPackets.push_back(buffer); + // hexdump(buffer->data(), buffer->size()); + + queue->erase(queue->begin()); + ++mNextExpectedSeqNo; + + return OK; +} + +void AMPEG4ElementaryAssembler::submitAccessUnit() { + CHECK(!mPackets.empty()); + +#if BE_VERBOSE + LOG(VERBOSE) << "Access unit complete (" << mPackets.size() << " nal units)"; +#endif + + uint64_t ntpTime; + CHECK((*mPackets.begin())->meta()->findInt64( + "ntp-time", (int64_t *)&ntpTime)); + + size_t totalSize = 0; + for (List<sp<ABuffer> >::iterator it = mPackets.begin(); + it != mPackets.end(); ++it) { + totalSize += (*it)->size(); + } + + sp<ABuffer> accessUnit = new ABuffer(totalSize); + size_t offset = 0; + for (List<sp<ABuffer> >::iterator it = mPackets.begin(); + it != mPackets.end(); ++it) { + sp<ABuffer> nal = *it; + memcpy(accessUnit->data() + offset, nal->data(), nal->size()); + offset += nal->size(); + } + + accessUnit->meta()->setInt64("ntp-time", ntpTime); + +#if 0 + printf(mAccessUnitDamaged ? "X" : "."); + fflush(stdout); +#endif + + if (mAccessUnitDamaged) { + accessUnit->meta()->setInt32("damaged", true); + } + + mPackets.clear(); + mAccessUnitDamaged = false; + + sp<AMessage> msg = mNotifyMsg->dup(); + msg->setObject("access-unit", accessUnit); + msg->post(); +} + +ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::assembleMore( + const sp<ARTPSource> &source) { + AssemblyStatus status = addPacket(source); + if (status == MALFORMED_PACKET) { + mAccessUnitDamaged = true; + } + return status; +} + +void AMPEG4ElementaryAssembler::packetLost() { + CHECK(mNextExpectedSeqNoValid); + LOG(VERBOSE) << "packetLost (expected " << mNextExpectedSeqNo << ")"; + + ++mNextExpectedSeqNo; + + mAccessUnitDamaged = true; +} + +void AMPEG4ElementaryAssembler::onByeReceived() { + sp<AMessage> msg = mNotifyMsg->dup(); + msg->setInt32("eos", true); + msg->post(); +} + +} // namespace android diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h new file mode 100644 index 000000000000..1566d00219f2 --- /dev/null +++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef A_MPEG4_ELEM_ASSEMBLER_H_ + +#define A_MPEG4_ELEM_ASSEMBLER_H_ + +#include "ARTPAssembler.h" + +#include <utils/List.h> +#include <utils/RefBase.h> + +namespace android { + +struct ABuffer; +struct AMessage; + +struct AMPEG4ElementaryAssembler : public ARTPAssembler { + AMPEG4ElementaryAssembler(const sp<AMessage> ¬ify); + +protected: + virtual ~AMPEG4ElementaryAssembler(); + + virtual AssemblyStatus assembleMore(const sp<ARTPSource> &source); + virtual void onByeReceived(); + virtual void packetLost(); + +private: + sp<AMessage> mNotifyMsg; + + uint32_t mAccessUnitRTPTime; + bool mNextExpectedSeqNoValid; + uint32_t mNextExpectedSeqNo; + bool mAccessUnitDamaged; + List<sp<ABuffer> > mPackets; + + AssemblyStatus addPacket(const sp<ARTPSource> &source); + void submitAccessUnit(); + + DISALLOW_EVIL_CONSTRUCTORS(AMPEG4ElementaryAssembler); +}; + +} // namespace android + +#endif // A_MPEG4_ELEM_ASSEMBLER_H_ diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp index 224b4bf68559..8c56cb785608 100644 --- a/media/libstagefright/rtsp/APacketSource.cpp +++ b/media/libstagefright/rtsp/APacketSource.cpp @@ -18,6 +18,11 @@ #include "ASessionDescription.h" +#include "avc_utils.h" + +#include <ctype.h> + +#include <media/stagefright/foundation/ABitReader.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> @@ -37,6 +42,10 @@ static bool GetAttribute(const char *s, const char *key, AString *value) { size_t keyLen = strlen(key); for (;;) { + while (isspace(*s)) { + ++s; + } + const char *colonPos = strchr(s, ';'); size_t len = @@ -90,7 +99,11 @@ static sp<ABuffer> decodeHex(const AString &s) { return buffer; } -static sp<ABuffer> MakeAVCCodecSpecificData(const char *params) { +static sp<ABuffer> MakeAVCCodecSpecificData( + const char *params, int32_t *width, int32_t *height) { + *width = 0; + *height = 0; + AString val; if (!GetAttribute(params, "profile-level-id", &val)) { return NULL; @@ -172,6 +185,11 @@ static sp<ABuffer> MakeAVCCodecSpecificData(const char *params) { memcpy(out, nal->data(), nal->size()); out += nal->size(); + + if (i == 0) { + FindAVCDimensions(nal, width, height); + LOG(INFO) << "dimensions " << *width << "x" << *height; + } } *out++ = numPicParameterSets; @@ -187,7 +205,7 @@ static sp<ABuffer> MakeAVCCodecSpecificData(const char *params) { out += nal->size(); } - hexdump(csd->data(), csd->size()); + // hexdump(csd->data(), csd->size()); return csd; } @@ -224,7 +242,162 @@ sp<ABuffer> MakeAACCodecSpecificData(const char *params) { csd->data()[sizeof(kStaticESDS)] = (x >> 8) & 0xff; csd->data()[sizeof(kStaticESDS) + 1] = x & 0xff; - hexdump(csd->data(), csd->size()); + // hexdump(csd->data(), csd->size()); + + return csd; +} + +static size_t GetSizeWidth(size_t x) { + size_t n = 1; + while (x > 127) { + ++n; + x >>= 7; + } + return n; +} + +static uint8_t *EncodeSize(uint8_t *dst, size_t x) { + while (x > 127) { + *dst++ = (x & 0x7f) | 0x80; + x >>= 7; + } + *dst++ = x; + return dst; +} + +static bool ExtractDimensionsFromVOLHeader( + const sp<ABuffer> &config, int32_t *width, int32_t *height) { + *width = 0; + *height = 0; + + const uint8_t *ptr = config->data(); + size_t offset = 0; + bool foundVOL = false; + while (offset + 3 < config->size()) { + if (memcmp("\x00\x00\x01", &ptr[offset], 3) + || (ptr[offset + 3] & 0xf0) != 0x20) { + ++offset; + continue; + } + + foundVOL = true; + break; + } + + if (!foundVOL) { + return false; + } + + ABitReader br(&ptr[offset + 4], config->size() - offset - 4); + br.skipBits(1); // random_accessible_vol + unsigned video_object_type_indication = br.getBits(8); + + CHECK_NE(video_object_type_indication, + 0x21u /* Fine Granularity Scalable */); + + unsigned video_object_layer_verid; + unsigned video_object_layer_priority; + if (br.getBits(1)) { + video_object_layer_verid = br.getBits(4); + video_object_layer_priority = br.getBits(3); + } + unsigned aspect_ratio_info = br.getBits(4); + if (aspect_ratio_info == 0x0f /* extended PAR */) { + br.skipBits(8); // par_width + br.skipBits(8); // par_height + } + if (br.getBits(1)) { // vol_control_parameters + br.skipBits(2); // chroma_format + br.skipBits(1); // low_delay + if (br.getBits(1)) { // vbv_parameters + TRESPASS(); + } + } + unsigned video_object_layer_shape = br.getBits(2); + CHECK_EQ(video_object_layer_shape, 0x00u /* rectangular */); + + CHECK(br.getBits(1)); // marker_bit + unsigned vop_time_increment_resolution = br.getBits(16); + CHECK(br.getBits(1)); // marker_bit + + if (br.getBits(1)) { // fixed_vop_rate + // range [0..vop_time_increment_resolution) + + // vop_time_increment_resolution + // 2 => 0..1, 1 bit + // 3 => 0..2, 2 bits + // 4 => 0..3, 2 bits + // 5 => 0..4, 3 bits + // ... + + CHECK_GT(vop_time_increment_resolution, 0u); + --vop_time_increment_resolution; + + unsigned numBits = 0; + while (vop_time_increment_resolution > 0) { + ++numBits; + vop_time_increment_resolution >>= 1; + } + + br.skipBits(numBits); // fixed_vop_time_increment + } + + CHECK(br.getBits(1)); // marker_bit + unsigned video_object_layer_width = br.getBits(13); + CHECK(br.getBits(1)); // marker_bit + unsigned video_object_layer_height = br.getBits(13); + CHECK(br.getBits(1)); // marker_bit + + unsigned interlaced = br.getBits(1); + + *width = video_object_layer_width; + *height = video_object_layer_height; + + LOG(INFO) << "VOL dimensions = " << *width << "x" << *height; + + return true; +} + +sp<ABuffer> MakeMPEG4VideoCodecSpecificData( + const char *params, int32_t *width, int32_t *height) { + *width = 0; + *height = 0; + + AString val; + CHECK(GetAttribute(params, "config", &val)); + + sp<ABuffer> config = decodeHex(val); + CHECK(config != NULL); + + if (!ExtractDimensionsFromVOLHeader(config, width, height)) { + return NULL; + } + + size_t len1 = config->size() + GetSizeWidth(config->size()) + 1; + size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13; + size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3; + + sp<ABuffer> csd = new ABuffer(len3); + uint8_t *dst = csd->data(); + *dst++ = 0x03; + dst = EncodeSize(dst, len2 + 3); + *dst++ = 0x00; // ES_ID + *dst++ = 0x00; + *dst++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag + + *dst++ = 0x04; + dst = EncodeSize(dst, len1 + 13); + *dst++ = 0x01; // Video ISO/IEC 14496-2 Simple Profile + for (size_t i = 0; i < 12; ++i) { + *dst++ = 0x00; + } + + *dst++ = 0x05; + dst = EncodeSize(dst, config->size()); + memcpy(dst, config->data(), config->size()); + dst += config->size(); + + // hexdump(csd->data(), csd->size()); return csd; } @@ -253,25 +426,42 @@ APacketSource::APacketSource( mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); int32_t width, height; - sessionDesc->getDimensions(index, PT, &width, &height); - - mFormat->setInt32(kKeyWidth, width); - mFormat->setInt32(kKeyHeight, height); + if (!sessionDesc->getDimensions(index, PT, &width, &height)) { + width = -1; + height = -1; + } + int32_t encWidth, encHeight; sp<ABuffer> codecSpecificData = - MakeAVCCodecSpecificData(params.c_str()); + MakeAVCCodecSpecificData(params.c_str(), &encWidth, &encHeight); if (codecSpecificData != NULL) { + if (width < 0) { + // If no explicit width/height given in the sdp, use the dimensions + // extracted from the first sequence parameter set. + width = encWidth; + height = encHeight; + } + mFormat->setData( kKeyAVCC, 0, codecSpecificData->data(), codecSpecificData->size()); + } else if (width < 0) { + mInitCheck = ERROR_UNSUPPORTED; + return; } + + mFormat->setInt32(kKeyWidth, width); + mFormat->setInt32(kKeyHeight, height); } else if (!strncmp(desc.c_str(), "H263-2000/", 10) || !strncmp(desc.c_str(), "H263-1998/", 10)) { mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); int32_t width, height; - sessionDesc->getDimensions(index, PT, &width, &height); + if (!sessionDesc->getDimensions(index, PT, &width, &height)) { + mInitCheck = ERROR_UNSUPPORTED; + return; + } mFormat->setInt32(kKeyWidth, width); mFormat->setInt32(kKeyHeight, height); @@ -317,6 +507,36 @@ APacketSource::APacketSource( if (sampleRate != 16000 || numChannels != 1) { mInitCheck = ERROR_UNSUPPORTED; } + } else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)) { + mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); + + int32_t width, height; + if (!sessionDesc->getDimensions(index, PT, &width, &height)) { + width = -1; + height = -1; + } + + int32_t encWidth, encHeight; + sp<ABuffer> codecSpecificData = + MakeMPEG4VideoCodecSpecificData( + params.c_str(), &encWidth, &encHeight); + + if (codecSpecificData != NULL) { + mFormat->setData( + kKeyESDS, 0, + codecSpecificData->data(), codecSpecificData->size()); + + if (width < 0) { + width = encWidth; + height = encHeight; + } + } else if (width < 0) { + mInitCheck = ERROR_UNSUPPORTED; + return; + } + + mFormat->setInt32(kKeyWidth, width); + mFormat->setInt32(kKeyHeight, height); } else { mInitCheck = ERROR_UNSUPPORTED; } diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp index 469af3e256c3..6816c4558710 100644 --- a/media/libstagefright/rtsp/ARTPConnection.cpp +++ b/media/libstagefright/rtsp/ARTPConnection.cpp @@ -321,6 +321,8 @@ status_t ARTPConnection::receive(StreamInfo *s, bool receiveRTP) { buffer->setRange(0, nbytes); + // LOG(INFO) << "received " << buffer->size() << " bytes."; + status_t err; if (receiveRTP) { err = parseRTP(s, buffer); diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp index 225f6e8d1f78..775c4eeaa272 100644 --- a/media/libstagefright/rtsp/ARTPSource.cpp +++ b/media/libstagefright/rtsp/ARTPSource.cpp @@ -20,6 +20,7 @@ #include "AAVCAssembler.h" #include "AH263Assembler.h" #include "AMPEG4AudioAssembler.h" +#include "AMPEG4ElementaryAssembler.h" #include "ASessionDescription.h" #include <media/stagefright/foundation/ABuffer.h> @@ -63,6 +64,9 @@ ARTPSource::ARTPSource( mAssembler = new AAMRAssembler(notify, false /* isWide */, params); } else if (!strncmp(desc.c_str(), "AMR-WB/", 7)) { mAssembler = new AAMRAssembler(notify, true /* isWide */, params); + } else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)) { + mAssembler = new AMPEG4ElementaryAssembler(notify); + mIssueFIRRequests = true; } else { TRESPASS(); } diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp index d6dd5973971e..d4eed7ce6efb 100644 --- a/media/libstagefright/rtsp/ARTPWriter.cpp +++ b/media/libstagefright/rtsp/ARTPWriter.cpp @@ -134,10 +134,10 @@ status_t ARTPWriter::start(MetaData *params) { return OK; } -void ARTPWriter::stop() { +status_t ARTPWriter::stop() { Mutex::Autolock autoLock(mLock); if (!(mFlags & kFlagStarted)) { - return; + return OK; } (new AMessage(kWhatStop, mReflector->id()))->post(); @@ -145,9 +145,11 @@ void ARTPWriter::stop() { while (mFlags & kFlagStarted) { mCondition.wait(mLock); } + return OK; } -void ARTPWriter::pause() { +status_t ARTPWriter::pause() { + return OK; } static void StripStartcode(MediaBuffer *buffer) { diff --git a/media/libstagefright/rtsp/ARTPWriter.h b/media/libstagefright/rtsp/ARTPWriter.h index b1b8b45b8b8e..fdc8d230fda2 100644 --- a/media/libstagefright/rtsp/ARTPWriter.h +++ b/media/libstagefright/rtsp/ARTPWriter.h @@ -40,8 +40,8 @@ struct ARTPWriter : public MediaWriter { virtual status_t addSource(const sp<MediaSource> &source); virtual bool reachedEOS(); virtual status_t start(MetaData *params); - virtual void stop(); - virtual void pause(); + virtual status_t stop(); + virtual status_t pause(); virtual void onMessageReceived(const sp<AMessage> &msg); diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp index 98269901eeb2..5345218f63d6 100644 --- a/media/libstagefright/rtsp/ARTSPConnection.cpp +++ b/media/libstagefright/rtsp/ARTSPConnection.cpp @@ -136,6 +136,20 @@ bool ARTSPConnection::ParseURL( return true; } +static void MakeSocketBlocking(int s, bool blocking) { + // Make socket non-blocking. + int flags = fcntl(s, F_GETFL, 0); + CHECK_NE(flags, -1); + + if (blocking) { + flags &= ~O_NONBLOCK; + } else { + flags |= O_NONBLOCK; + } + + CHECK_NE(fcntl(s, F_SETFL, flags), -1); +} + void ARTSPConnection::onConnect(const sp<AMessage> &msg) { ++mConnectionID; @@ -150,10 +164,7 @@ void ARTSPConnection::onConnect(const sp<AMessage> &msg) { mSocket = socket(AF_INET, SOCK_STREAM, 0); - // Make socket non-blocking. - int flags = fcntl(mSocket, F_GETFL, 0); - CHECK_NE(flags, -1); - CHECK_NE(fcntl(mSocket, F_SETFL, flags | O_NONBLOCK), -1); + MakeSocketBlocking(mSocket, false); AString url; CHECK(msg->findString("url", &url)); @@ -210,7 +221,7 @@ void ARTSPConnection::onDisconnect(const sp<AMessage> &msg) { mSocket = -1; flushPendingRequests(); - } + } sp<AMessage> reply; CHECK(msg->findMessage("reply", &reply)); @@ -347,7 +358,13 @@ void ARTSPConnection::onReceiveResponse() { CHECK_GE(res, 0); if (res == 1) { - if (!receiveRTSPReponse()) { + MakeSocketBlocking(mSocket, true); + + bool success = receiveRTSPReponse(); + + MakeSocketBlocking(mSocket, false); + + if (!success) { // Something horrible, irreparable has happened. flushPendingRequests(); return; diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp index 8187e0cb4253..4a8cce85cd68 100644 --- a/media/libstagefright/rtsp/ASessionDescription.cpp +++ b/media/libstagefright/rtsp/ASessionDescription.cpp @@ -203,13 +203,18 @@ void ASessionDescription::getFormatType( } } -void ASessionDescription::getDimensions( +bool ASessionDescription::getDimensions( size_t index, unsigned long PT, int32_t *width, int32_t *height) const { + *width = 0; + *height = 0; + char key[20]; sprintf(key, "a=framesize:%lu", PT); AString value; - CHECK(findAttribute(index, key, &value)); + if (!findAttribute(index, key, &value)) { + return false; + } const char *s = value.c_str(); char *end; @@ -221,6 +226,8 @@ void ASessionDescription::getDimensions( *height = strtoul(s, &end, 10); CHECK_GT(end, s); CHECK_EQ(*end, '\0'); + + return true; } bool ASessionDescription::getDurationUs(int64_t *durationUs) const { diff --git a/media/libstagefright/rtsp/ASessionDescription.h b/media/libstagefright/rtsp/ASessionDescription.h index b26980f0eb4d..a3fa79ed5a00 100644 --- a/media/libstagefright/rtsp/ASessionDescription.h +++ b/media/libstagefright/rtsp/ASessionDescription.h @@ -44,7 +44,7 @@ struct ASessionDescription : public RefBase { size_t index, unsigned long *PT, AString *desc, AString *params) const; - void getDimensions( + bool getDimensions( size_t index, unsigned long PT, int32_t *width, int32_t *height) const; diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk index 7f3659f84447..ed160596cab3 100644 --- a/media/libstagefright/rtsp/Android.mk +++ b/media/libstagefright/rtsp/Android.mk @@ -7,6 +7,7 @@ LOCAL_SRC_FILES:= \ AAVCAssembler.cpp \ AH263Assembler.cpp \ AMPEG4AudioAssembler.cpp \ + AMPEG4ElementaryAssembler.cpp \ APacketSource.cpp \ ARTPAssembler.cpp \ ARTPConnection.cpp \ diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h index 8be891499e16..3e75ffe2e1cd 100644 --- a/media/libstagefright/rtsp/MyHandler.h +++ b/media/libstagefright/rtsp/MyHandler.h @@ -309,6 +309,16 @@ struct MyHandler : public AHandler { size_t trackIndex; CHECK(msg->findSize("track-index", &trackIndex)); + int32_t eos; + if (msg->findInt32("eos", &eos)) { + LOG(INFO) << "received BYE on track index " << trackIndex; +#if 0 + TrackInfo *track = &mTracks.editItemAt(trackIndex); + track->mPacketSource->signalEOS(ERROR_END_OF_STREAM); +#endif + return; + } + sp<RefBase> obj; CHECK(msg->findObject("access-unit", &obj)); diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp index 4997dc8d5028..7fbe9b5f96ae 100644 --- a/opengl/libagl/array.cpp +++ b/opengl/libagl/array.cpp @@ -685,8 +685,8 @@ static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c, } while (num); } if (count) { - v0 = c->vc.vBuffer + 2 + num - 2; - v1 = c->vc.vBuffer + 2 + num - 1; + v0 = c->vc.vBuffer + 2 + vcs - 2; + v1 = c->vc.vBuffer + 2 + vcs - 1; if ((winding&2) == 0) { // for strips copy back the two last compiled vertices c->vc.vBuffer[0] = *v0; diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp index 8b476c0af147..53cc3984ddfe 100644 --- a/opengl/libagl/egl.cpp +++ b/opengl/libagl/egl.cpp @@ -576,41 +576,44 @@ EGLBoolean egl_window_surface_v2_t::swapBuffers() buffer = 0; // dequeue a new buffer - nativeWindow->dequeueBuffer(nativeWindow, &buffer); - - // TODO: lockBuffer should rather be executed when the very first - // direct rendering occurs. - nativeWindow->lockBuffer(nativeWindow, buffer); - - // reallocate the depth-buffer if needed - if ((width != buffer->width) || (height != buffer->height)) { - // TODO: we probably should reset the swap rect here - // if the window size has changed - width = buffer->width; - height = buffer->height; - if (depth.data) { - free(depth.data); - depth.width = width; - depth.height = height; - depth.stride = buffer->stride; - depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2); - if (depth.data == 0) { - setError(EGL_BAD_ALLOC, EGL_FALSE); - return EGL_FALSE; + if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) == NO_ERROR) { + + // TODO: lockBuffer should rather be executed when the very first + // direct rendering occurs. + nativeWindow->lockBuffer(nativeWindow, buffer); + + // reallocate the depth-buffer if needed + if ((width != buffer->width) || (height != buffer->height)) { + // TODO: we probably should reset the swap rect here + // if the window size has changed + width = buffer->width; + height = buffer->height; + if (depth.data) { + free(depth.data); + depth.width = width; + depth.height = height; + depth.stride = buffer->stride; + depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2); + if (depth.data == 0) { + setError(EGL_BAD_ALLOC, EGL_FALSE); + return EGL_FALSE; + } } } - } - - // keep a reference on the buffer - buffer->common.incRef(&buffer->common); - // finally pin the buffer down - if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN | - GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) { - LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)", - buffer, buffer->width, buffer->height); - return setError(EGL_BAD_ACCESS, EGL_FALSE); - // FIXME: we should make sure we're not accessing the buffer anymore + // keep a reference on the buffer + buffer->common.incRef(&buffer->common); + + // finally pin the buffer down + if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) { + LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)", + buffer, buffer->width, buffer->height); + return setError(EGL_BAD_ACCESS, EGL_FALSE); + // FIXME: we should make sure we're not accessing the buffer anymore + } + } else { + return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE); } return EGL_TRUE; diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 6a5290ea154f..2e95932c2927 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -222,16 +222,11 @@ public class SettingsProvider extends ContentProvider { final String value = c.moveToNext() ? c.getString(0) : null; if (value == null) { final SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); - String serial = SystemProperties.get("ro.serialno"); - if (serial != null) { - try { - random.setSeed(serial.getBytes("UTF-8")); - } catch (UnsupportedEncodingException ignore) { - // stick with default seed - } - } + String serial = SystemProperties.get("ro.serialno", ""); + random.setSeed( + (serial + System.nanoTime() + new SecureRandom().nextLong()).getBytes()); final String newAndroidIdValue = Long.toHexString(random.nextLong()); - Log.d(TAG, "Generated and saved new ANDROID_ID"); + Log.d(TAG, "Generated and saved new ANDROID_ID [" + newAndroidIdValue + "]"); final ContentValues values = new ContentValues(); values.put(Settings.NameValueTable.NAME, Settings.Secure.ANDROID_ID); values.put(Settings.NameValueTable.VALUE, newAndroidIdValue); diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 2bb445614ccd..2dabf72e1e2a 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -364,29 +364,32 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public void onConfigurationChanged(Configuration newConfig) { - PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false); - if ((st != null) && (st.menu != null)) { - final MenuBuilder menuBuilder = (MenuBuilder) st.menu; + // Action bars handle their own menu state + if (mActionBar == null) { + PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false); + if ((st != null) && (st.menu != null)) { + final MenuBuilder menuBuilder = (MenuBuilder) st.menu; - if (st.isOpen) { - // Freeze state - final Bundle state = new Bundle(); - menuBuilder.saveHierarchyState(state); + if (st.isOpen) { + // Freeze state + final Bundle state = new Bundle(); + menuBuilder.saveHierarchyState(state); - // Remove the menu views since they need to be recreated - // according to the new configuration - clearMenuViews(st); + // Remove the menu views since they need to be recreated + // according to the new configuration + clearMenuViews(st); - // Re-open the same menu - reopenMenu(false); + // Re-open the same menu + reopenMenu(false); - // Restore state - menuBuilder.restoreHierarchyState(state); + // Restore state + menuBuilder.restoreHierarchyState(state); - } else { - // Clear menu views so on next menu opening, it will use - // the proper layout - clearMenuViews(st); + } else { + // Clear menu views so on next menu opening, it will use + // the proper layout + clearMenuViews(st); + } } } } @@ -1515,6 +1518,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { static private final String FOCUSED_ID_TAG = "android:focusedViewId"; static private final String VIEWS_TAG = "android:views"; static private final String PANELS_TAG = "android:Panels"; + static private final String ACTION_BAR_TAG = "android:ActionBar"; /** {@inheritDoc} */ @Override @@ -1548,6 +1552,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { outState.putSparseParcelableArray(PANELS_TAG, panelStates); } + if (mActionBar != null) { + outState.putBoolean(ACTION_BAR_TAG, mActionBar.isOverflowMenuShowing()); + } + return outState; } @@ -1582,6 +1590,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (panelStates != null) { restorePanelState(panelStates); } + + if (mActionBar != null && savedInstanceState.getBoolean(ACTION_BAR_TAG)) { + mActionBar.postShowOverflowMenu(); + } } /** diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index a07c38583107..ecba1fe336b5 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -2096,9 +2096,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mDeskDockRotation; } else { if (useSensorForOrientationLp(orientation)) { - // If the user has enabled auto rotation by default, do it. - int curRotation = mOrientationListener.getCurrentRotation(); - return curRotation >= 0 ? curRotation : lastRotation; + return mOrientationListener.getCurrentRotation(lastRotation); } return Surface.ROTATION_0; } diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 6e7633e0fb35..ff314709eaa8 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1601,7 +1601,7 @@ bool AudioFlinger::MixerThread::threadLoop() } if (mSuspended) { - sleepTime = idleSleepTime; + sleepTime = suspendSleepTimeUs(); } // sleepTime == 0 means we must write to audio hardware if (sleepTime == 0) { @@ -2021,6 +2021,11 @@ uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() return (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000) / 2; } +uint32_t AudioFlinger::MixerThread::suspendSleepTimeUs() +{ + return (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000); +} + // ---------------------------------------------------------------------------- AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device) : PlaybackThread(audioFlinger, output, id, device) @@ -2365,7 +2370,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } if (mSuspended) { - sleepTime = idleSleepTime; + sleepTime = suspendSleepTimeUs(); } // sleepTime == 0 means we must write to audio hardware if (sleepTime == 0) { @@ -2486,6 +2491,18 @@ uint32_t AudioFlinger::DirectOutputThread::idleSleepTimeUs() return time; } +uint32_t AudioFlinger::DirectOutputThread::suspendSleepTimeUs() +{ + uint32_t time; + if (AudioSystem::isLinearPCM(mFormat)) { + time = (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000); + } else { + time = 10000; + } + return time; +} + + // ---------------------------------------------------------------------------- AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id) @@ -2612,7 +2629,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop() } if (mSuspended) { - sleepTime = idleSleepTime; + sleepTime = suspendSleepTimeUs(); } // sleepTime == 0 means we must write to audio hardware if (sleepTime == 0) { diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 5520551992f4..51881f01567a 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -664,6 +664,7 @@ private: virtual void deleteTrackName_l(int name) = 0; virtual uint32_t activeSleepTimeUs() = 0; virtual uint32_t idleSleepTimeUs() = 0; + virtual uint32_t suspendSleepTimeUs() = 0; private: @@ -724,6 +725,7 @@ private: virtual void deleteTrackName_l(int name); virtual uint32_t activeSleepTimeUs(); virtual uint32_t idleSleepTimeUs(); + virtual uint32_t suspendSleepTimeUs(); AudioMixer* mAudioMixer; }; @@ -744,6 +746,7 @@ private: virtual void deleteTrackName_l(int name); virtual uint32_t activeSleepTimeUs(); virtual uint32_t idleSleepTimeUs(); + virtual uint32_t suspendSleepTimeUs(); private: void applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp); diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java index c2c799b4e0a0..f330d40a80f6 100644 --- a/services/java/com/android/server/InputManager.java +++ b/services/java/com/android/server/InputManager.java @@ -26,6 +26,7 @@ import android.content.res.Configuration; import android.os.Environment; import android.os.LocalPowerManager; import android.os.PowerManager; +import android.os.SystemProperties; import android.util.Slog; import android.util.Xml; import android.view.InputChannel; @@ -47,9 +48,6 @@ import java.util.ArrayList; /* * Wraps the C++ InputManager and provides its callbacks. - * - * XXX Tempted to promote this to a first-class service, ie. InputManagerService, to - * improve separation of concerns with respect to the window manager. */ public class InputManager { static final String TAG = "InputManager"; @@ -507,5 +505,18 @@ public class InputManager { return names.toArray(new String[names.size()]); } + + @SuppressWarnings("unused") + public int getMaxEventsPerSecond() { + int result = 0; + try { + result = Integer.parseInt(SystemProperties.get("windowsmgr.max_events_per_sec")); + } catch (NumberFormatException e) { + } + if (result < 1) { + result = 60; + } + return result; + } } } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 55ec6aa6d9df..63746e7b7c0d 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -1163,7 +1163,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } catch (RemoteException e) { } } catch (NameNotFoundException e) { - Log.w(TAG, "Unable to create context for heavy notification", e); + Slog.w(TAG, "Unable to create context for heavy notification", e); } } break; case CANCEL_HEAVY_NOTIFICATION_MSG: { @@ -2368,7 +2368,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } if (proc == null) { - Log.w(TAG, "crashApplication: nothing for uid=" + uid + Slog.w(TAG, "crashApplication: nothing for uid=" + uid + " initialPid=" + initialPid + " packageName=" + packageName); return; @@ -4058,6 +4058,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return false; } } + if (!pi.exported && pi.applicationInfo.uid != uid) { + return false; + } return true; } catch (RemoteException e) { return false; @@ -4206,8 +4209,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (perm == null) { perm = new UriPermission(targetUid, uri); targetUris.put(uri, perm); - } + perm.modeFlags |= modeFlags; if (activity == null) { perm.globalModeFlags |= modeFlags; @@ -4228,6 +4231,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen void grantUriPermissionFromIntentLocked(int callingUid, String targetPkg, Intent intent, ActivityRecord activity) { + if (DEBUG_URI_PERMISSION) Slog.v(TAG, + "Grant URI perm to " + (intent != null ? intent.getData() : null) + + " from " + intent + "; flags=0x" + + Integer.toHexString(intent != null ? intent.getFlags() : 0)); + if (intent == null) { return; } @@ -4906,13 +4914,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } private final String checkContentProviderPermissionLocked( - ProviderInfo cpi, ProcessRecord r, int mode) { + ProviderInfo cpi, ProcessRecord r) { final int callingPid = (r != null) ? r.pid : Binder.getCallingPid(); final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid(); if (checkComponentPermission(cpi.readPermission, callingPid, callingUid, cpi.exported ? -1 : cpi.applicationInfo.uid) - == PackageManager.PERMISSION_GRANTED - && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) { + == PackageManager.PERMISSION_GRANTED) { return null; } if (checkComponentPermission(cpi.writePermission, callingPid, callingUid, @@ -4929,8 +4936,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen PathPermission pp = pps[i]; if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid, cpi.exported ? -1 : cpi.applicationInfo.uid) - == PackageManager.PERMISSION_GRANTED - && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) { + == PackageManager.PERMISSION_GRANTED) { return null; } if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid, @@ -4941,6 +4947,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(callingUid); + if (perms != null) { + for (Map.Entry<Uri, UriPermission> uri : perms.entrySet()) { + if (uri.getKey().getAuthority().equals(cpi.authority)) { + return null; + } + } + } + String msg = "Permission Denial: opening provider " + cpi.name + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid + ", uid=" + callingUid + ") requires " @@ -4970,10 +4985,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen cpr = mProvidersByName.get(name); if (cpr != null) { cpi = cpr.info; - if (checkContentProviderPermissionLocked(cpi, r, -1) != null) { - return new ContentProviderHolder(cpi, - cpi.readPermission != null - ? cpi.readPermission : cpi.writePermission); + String msg; + if ((msg=checkContentProviderPermissionLocked(cpi, r)) != null) { + throw new SecurityException(msg); } if (r != null && cpr.canRunHere(r)) { @@ -5033,10 +5047,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return null; } - if (checkContentProviderPermissionLocked(cpi, r, -1) != null) { - return new ContentProviderHolder(cpi, - cpi.readPermission != null - ? cpi.readPermission : cpi.writePermission); + String msg; + if ((msg=checkContentProviderPermissionLocked(cpi, r)) != null) { + throw new SecurityException(msg); } if (!mSystemReady && !mDidUpdate && !mWaitingUpdate @@ -6208,7 +6221,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen Binder.restoreCallingIdentity(origId); } int res = result.get(); - Log.w(TAG, "handleApplicationStrictModeViolation; res=" + res); + Slog.w(TAG, "handleApplicationStrictModeViolation; res=" + res); } } diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index ba58b43e2df4..3addc0d2e208 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -139,6 +139,7 @@ static struct { jmethodID filterJumpyTouchEvents; jmethodID getVirtualKeyDefinitions; jmethodID getExcludedDeviceNames; + jmethodID getMaxEventsPerSecond; } gCallbacksClassInfo; static struct { @@ -249,6 +250,7 @@ public: int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets); virtual int32_t waitForMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags, int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets); + virtual int32_t getMaxEventsPerSecond(); private: struct InputWindow { @@ -310,6 +312,9 @@ private: int32_t mFilterTouchEvents; int32_t mFilterJumpyTouchEvents; + // Cached throttling policy. + int32_t mMaxEventsPerSecond; + // Cached display state. (lock mDisplayLock) Mutex mDisplayLock; int32_t mDisplayWidth, mDisplayHeight; @@ -400,6 +405,7 @@ private: NativeInputManager::NativeInputManager(jobject callbacksObj) : mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), + mMaxEventsPerSecond(-1), mDisplayWidth(-1), mDisplayHeight(-1), mDisplayOrientation(ROTATION_0), mDispatchEnabled(true), mDispatchFrozen(false), mWindowsReady(true), mFocusedWindow(NULL), mTouchDown(false), mTouchedWindow(NULL), @@ -921,6 +927,21 @@ nsecs_t NativeInputManager::getKeyRepeatTimeout() { } } +int32_t NativeInputManager::getMaxEventsPerSecond() { + if (mMaxEventsPerSecond < 0) { + JNIEnv* env = jniEnv(); + + jint result = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getMaxEventsPerSecond); + if (checkAndClearExceptionFromCallback(env, "getMaxEventsPerSecond")) { + result = 60; + } + + mMaxEventsPerSecond = result; + } + return mMaxEventsPerSecond; +} + void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowObjArray) { #if DEBUG_FOCUS LOGD("setInputWindows"); @@ -2293,6 +2314,9 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz, "getExcludedDeviceNames", "()[Ljava/lang/String;"); + GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, gCallbacksClassInfo.clazz, + "getMaxEventsPerSecond", "()I"); + // VirtualKeyDefinition FIND_CLASS(gVirtualKeyDefinitionClassInfo.clazz, diff --git a/services/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp index 0f448e08cc95..76f61598b15e 100644 --- a/services/surfaceflinger/TextureManager.cpp +++ b/services/surfaceflinger/TextureManager.cpp @@ -121,7 +121,6 @@ bool TextureManager::isYuvFormat(int format) case HAL_PIXEL_FORMAT_YCbCr_422_SP: case HAL_PIXEL_FORMAT_YCrCb_420_SP: case HAL_PIXEL_FORMAT_YCbCr_422_I: - case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: return true; } diff --git a/tools/obbtool/Main.cpp b/tools/obbtool/Main.cpp index 2a9bf0420102..49e077fc2af6 100644 --- a/tools/obbtool/Main.cpp +++ b/tools/obbtool/Main.cpp @@ -29,7 +29,7 @@ static const char* gProgVersion = "1.0"; static int wantUsage = 0; static int wantVersion = 0; -#define ADD_OPTS "n:v:f:c:" +#define ADD_OPTS "n:v:o" static const struct option longopts[] = { {"help", no_argument, &wantUsage, 1}, {"version", no_argument, &wantVersion, 1}, @@ -37,8 +37,7 @@ static const struct option longopts[] = { /* Args for "add" */ {"name", required_argument, NULL, 'n'}, {"version", required_argument, NULL, 'v'}, - {"filesystem", required_argument, NULL, 'f'}, - {"crypto", required_argument, NULL, 'c'}, + {"overlay", optional_argument, NULL, 'o'}, {NULL, 0, NULL, '\0'} }; @@ -46,8 +45,7 @@ static const struct option longopts[] = { struct package_info_t { char* packageName; int packageVersion; - char* filesystem; - char* crypto; + bool overlay; }; /* @@ -77,6 +75,7 @@ void doAdd(const char* filename, struct package_info_t* info) { obb->setPackageName(String8(info->packageName)); obb->setVersion(info->packageVersion); + obb->setOverlay(info->overlay); if (!obb->writeTo(filename)) { fprintf(stderr, "ERROR: %s: couldn't write OBB signature: %s\n", @@ -112,6 +111,8 @@ void doInfo(const char* filename) { printf("OBB info for '%s':\n", filename); printf("Package name: %s\n", obb->getPackageName().string()); printf(" Version: %d\n", obb->getVersion()); + printf(" Flags: 0x%08x\n", obb->getFlags()); + printf(" Overlay: %s\n", obb->isOverlay() ? "true" : "false"); } /* @@ -143,7 +144,7 @@ int main(int argc, char* const argv[]) case 'n': package_info.packageName = optarg; break; - case 'v': + case 'v': { char *end; package_info.packageVersion = strtol(optarg, &end, 10); if (*optarg == '\0' || *end != '\0') { @@ -152,11 +153,9 @@ int main(int argc, char* const argv[]) goto bail; } break; - case 'f': - package_info.filesystem = optarg; - break; - case 'c': - package_info.crypto = optarg; + } + case 'o': + package_info.overlay = true; break; case '?': wantUsage = 1; diff --git a/voip/java/android/net/rtp/AudioGroup.java b/voip/java/android/net/rtp/AudioGroup.java index dc860826b5fe..37cc12103612 100644 --- a/voip/java/android/net/rtp/AudioGroup.java +++ b/voip/java/android/net/rtp/AudioGroup.java @@ -49,27 +49,28 @@ public class AudioGroup { synchronized void add(AudioStream stream, AudioCodec codec, int codecType, int dtmfType) { if (!mStreams.containsKey(stream)) { try { - int id = add(stream.getMode(), stream.dup(), + int socket = stream.dup(); + add(stream.getMode(), socket, stream.getRemoteAddress().getHostAddress(), stream.getRemotePort(), codec.name, codec.sampleRate, codec.sampleCount, codecType, dtmfType); - mStreams.put(stream, id); + mStreams.put(stream, socket); } catch (NullPointerException e) { throw new IllegalStateException(e); } } } - private native int add(int mode, int socket, String remoteAddress, int remotePort, + private native void add(int mode, int socket, String remoteAddress, int remotePort, String codecName, int sampleRate, int sampleCount, int codecType, int dtmfType); synchronized void remove(AudioStream stream) { - Integer id = mStreams.remove(stream); - if (id != null) { - remove(id); + Integer socket = mStreams.remove(stream); + if (socket != null) { + remove(socket); } } - private native void remove(int id); + private native void remove(int socket); /** * Sends a DTMF digit to every {@link AudioStream} in this group. Currently diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp index fc1ed9b06292..08a8d1c6d524 100644 --- a/voip/jni/rtp/AudioGroup.cpp +++ b/voip/jni/rtp/AudioGroup.cpp @@ -367,7 +367,7 @@ void AudioStream::decode(int tick) MSG_TRUNC | MSG_DONTWAIT); // Do we need to check SSRC, sequence, and timestamp? They are not - // reliable but at least they can be used to identity duplicates? + // reliable but at least they can be used to identify duplicates? if (length < 12 || length > (int)sizeof(buffer) || (ntohl(*(uint32_t *)buffer) & 0xC07F0000) != mCodecMagic) { LOGD("stream[%d] malformed packet", mSocket); @@ -526,70 +526,6 @@ AudioGroup::~AudioGroup() LOGD("group[%d] is dead", mDeviceSocket); } -#define FROYO_COMPATIBLE -#ifdef FROYO_COMPATIBLE - -// Copied from AudioRecord.cpp. -status_t AudioRecord_getMinFrameCount( - int* frameCount, - uint32_t sampleRate, - int format, - int channelCount) -{ - size_t size = 0; - if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &size) - != NO_ERROR) { - LOGE("AudioSystem could not query the input buffer size."); - return NO_INIT; - } - - if (size == 0) { - LOGE("Unsupported configuration: sampleRate %d, format %d, channelCount %d", - sampleRate, format, channelCount); - return BAD_VALUE; - } - - // We double the size of input buffer for ping pong use of record buffer. - size <<= 1; - - if (AudioSystem::isLinearPCM(format)) { - size /= channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1); - } - - *frameCount = size; - return NO_ERROR; -} - -// Copied from AudioTrack.cpp. -status_t AudioTrack_getMinFrameCount( - int* frameCount, - int streamType, - uint32_t sampleRate) -{ - int afSampleRate; - if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { - return NO_INIT; - } - int afFrameCount; - if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { - return NO_INIT; - } - uint32_t afLatency; - if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) { - return NO_INIT; - } - - // Ensure that buffer depth covers at least audio hardware latency - uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate); - if (minBufCount < 2) minBufCount = 2; - - *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount : - afFrameCount * minBufCount * sampleRate / afSampleRate; - return NO_ERROR; -} - -#endif - bool AudioGroup::set(int sampleRate, int sampleCount) { mEventQueue = epoll_create(2); @@ -603,15 +539,6 @@ bool AudioGroup::set(int sampleRate, int sampleCount) // Find out the frame count for AudioTrack and AudioRecord. int output = 0; int input = 0; -#ifdef FROYO_COMPATIBLE - if (AudioTrack_getMinFrameCount(&output, AudioSystem::VOICE_CALL, - sampleRate) != NO_ERROR || output <= 0 || - AudioRecord_getMinFrameCount(&input, sampleRate, - AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) { - LOGE("cannot compute frame count"); - return false; - } -#else if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL, sampleRate) != NO_ERROR || output <= 0 || AudioRecord::getMinFrameCount(&input, sampleRate, @@ -619,7 +546,6 @@ bool AudioGroup::set(int sampleRate, int sampleCount) LOGE("cannot compute frame count"); return false; } -#endif LOGD("reported frame count: output %d, input %d", output, input); output = (output + sampleCount - 1) / sampleCount * sampleCount; @@ -771,6 +697,10 @@ bool AudioGroup::remove(int socket) for (AudioStream *stream = mChain; stream->mNext; stream = stream->mNext) { AudioStream *target = stream->mNext; if (target->mSocket == socket) { + if (epoll_ctl(mEventQueue, EPOLL_CTL_DEL, socket, NULL)) { + LOGE("epoll_ctl: %s", strerror(errno)); + return false; + } stream->mNext = target->mNext; LOGD("stream[%d] leaves group[%d]", socket, mDeviceSocket); delete target; @@ -874,7 +804,7 @@ bool AudioGroup::deviceLoop() static jfieldID gNative; static jfieldID gMode; -jint add(JNIEnv *env, jobject thiz, jint mode, +void add(JNIEnv *env, jobject thiz, jint mode, jint socket, jstring jRemoteAddress, jint remotePort, jstring jCodecName, jint sampleRate, jint sampleCount, jint codecType, jint dtmfType) @@ -887,7 +817,7 @@ jint add(JNIEnv *env, jobject thiz, jint mode, sockaddr_storage remote; if (parse(env, jRemoteAddress, remotePort, &remote) < 0) { // Exception already thrown. - return -1; + goto error; } if (sampleRate < 0 || sampleCount < 0 || codecType < 0 || codecType > 127) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); @@ -895,12 +825,12 @@ jint add(JNIEnv *env, jobject thiz, jint mode, } if (!jCodecName) { jniThrowNullPointerException(env, "codecName"); - return -1; + goto error; } codecName = env->GetStringUTFChars(jCodecName, NULL); if (!codecName) { // Exception already thrown. - return -1; + goto error; } // Create audio stream. @@ -909,8 +839,10 @@ jint add(JNIEnv *env, jobject thiz, jint mode, codecType, dtmfType)) { jniThrowException(env, "java/lang/IllegalStateException", "cannot initialize audio stream"); + env->ReleaseStringUTFChars(jCodecName, codecName); goto error; } + env->ReleaseStringUTFChars(jCodecName, codecName); socket = -1; // Create audio group. @@ -934,16 +866,13 @@ jint add(JNIEnv *env, jobject thiz, jint mode, // Succeed. env->SetIntField(thiz, gNative, (int)group); - env->ReleaseStringUTFChars(jCodecName, codecName); - return socket; + return; error: delete group; delete stream; close(socket); env->SetIntField(thiz, gNative, NULL); - env->ReleaseStringUTFChars(jCodecName, codecName); - return -1; } void remove(JNIEnv *env, jobject thiz, jint socket) @@ -976,7 +905,7 @@ void sendDtmf(JNIEnv *env, jobject thiz, jint event) } JNINativeMethod gMethods[] = { - {"add", "(IILjava/lang/String;ILjava/lang/String;IIII)I", (void *)add}, + {"add", "(IILjava/lang/String;ILjava/lang/String;IIII)V", (void *)add}, {"remove", "(I)V", (void *)remove}, {"setMode", "(I)V", (void *)setMode}, {"sendDtmf", "(I)V", (void *)sendDtmf}, |