summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.xml13
-rw-r--r--core/java/android/app/ActivityThread.java4
-rw-r--r--core/java/android/app/DatePickerDialog.java3
-rw-r--r--core/java/android/app/IActivityManager.java10
-rw-r--r--core/java/android/app/TimePickerDialog.java3
-rw-r--r--core/java/android/content/ContentProvider.java10
-rw-r--r--core/java/android/content/res/ObbInfo.java24
-rw-r--r--core/java/android/content/res/TypedArray.java4
-rw-r--r--core/java/android/os/storage/StorageManager.java4
-rwxr-xr-xcore/java/android/view/WindowOrientationListener.java38
-rw-r--r--core/java/android/webkit/WebView.java21
-rw-r--r--core/java/android/widget/AutoCompleteTextView.java3
-rw-r--r--core/java/android/widget/Button.java3
-rw-r--r--core/java/android/widget/CheckBox.java3
-rw-r--r--core/java/android/widget/DatePicker.java3
-rw-r--r--core/java/android/widget/EditText.java3
-rw-r--r--core/java/android/widget/Gallery.java3
-rw-r--r--core/java/android/widget/GridView.java3
-rw-r--r--core/java/android/widget/ImageButton.java3
-rw-r--r--core/java/android/widget/LinearLayout.java3
-rw-r--r--core/java/android/widget/ListPopupWindow.java9
-rw-r--r--core/java/android/widget/ListView.java3
-rw-r--r--core/java/android/widget/RadioButton.java3
-rw-r--r--core/java/android/widget/RatingBar.java3
-rw-r--r--core/java/android/widget/RelativeLayout.java3
-rw-r--r--core/java/android/widget/Spinner.java3
-rw-r--r--core/java/android/widget/TabHost.java3
-rw-r--r--core/java/android/widget/TabWidget.java3
-rw-r--r--core/java/android/widget/TableLayout.java3
-rw-r--r--core/java/android/widget/TimePicker.java3
-rw-r--r--core/java/android/widget/ToggleButton.java3
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuView.java21
-rw-r--r--core/java/com/android/internal/view/menu/MenuPopupHelper.java9
-rw-r--r--core/java/com/android/internal/widget/ActionBarView.java8
-rw-r--r--core/jni/android/graphics/Graphics.cpp27
-rw-r--r--core/jni/android/graphics/GraphicsJNI.h4
-rw-r--r--core/jni/android_content_res_ObbScanner.cpp3
-rw-r--r--core/res/assets/webkit/incognito_mode_start_page.html (renamed from core/res/res/raw/incognito_mode_start_page.html)0
-rw-r--r--docs/html/resources/tutorials/views/hello-formstuff.jd26
-rw-r--r--include/media/stagefright/AMRWriter.h6
-rw-r--r--include/media/stagefright/MPEG4Writer.h4
-rw-r--r--include/media/stagefright/MediaWriter.h5
-rw-r--r--include/media/stagefright/foundation/ABitReader.h (renamed from media/libstagefright/mpeg2ts/ABitReader.h)0
-rw-r--r--include/ui/InputDispatcher.h19
-rw-r--r--include/utils/ObbFile.h35
-rw-r--r--libs/ui/InputDispatcher.cpp83
-rw-r--r--libs/ui/PixelFormat.cpp1
-rw-r--r--libs/utils/ObbFile.cpp32
-rw-r--r--media/java/android/media/BassBoost.java2
-rw-r--r--media/java/android/media/Virtualizer.java2
-rw-r--r--media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp17
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp5
-rw-r--r--media/libstagefright/AMRWriter.cpp32
-rw-r--r--media/libstagefright/Android.mk1
-rw-r--r--media/libstagefright/MPEG4Writer.cpp69
-rw-r--r--media/libstagefright/avc_utils.cpp91
-rw-r--r--media/libstagefright/foundation/ABitReader.cpp (renamed from media/libstagefright/mpeg2ts/ABitReader.cpp)0
-rw-r--r--media/libstagefright/foundation/Android.mk1
-rw-r--r--media/libstagefright/include/avc_utils.h30
-rw-r--r--media/libstagefright/mpeg2ts/ATSParser.cpp59
-rw-r--r--media/libstagefright/mpeg2ts/Android.mk1
-rw-r--r--media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp166
-rw-r--r--media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h58
-rw-r--r--media/libstagefright/rtsp/APacketSource.cpp238
-rw-r--r--media/libstagefright/rtsp/ARTPConnection.cpp2
-rw-r--r--media/libstagefright/rtsp/ARTPSource.cpp4
-rw-r--r--media/libstagefright/rtsp/ARTPWriter.cpp8
-rw-r--r--media/libstagefright/rtsp/ARTPWriter.h4
-rw-r--r--media/libstagefright/rtsp/ARTSPConnection.cpp29
-rw-r--r--media/libstagefright/rtsp/ASessionDescription.cpp11
-rw-r--r--media/libstagefright/rtsp/ASessionDescription.h2
-rw-r--r--media/libstagefright/rtsp/Android.mk1
-rw-r--r--media/libstagefright/rtsp/MyHandler.h10
-rw-r--r--opengl/libagl/array.cpp4
-rw-r--r--opengl/libagl/egl.cpp67
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java13
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java48
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java4
-rw-r--r--services/audioflinger/AudioFlinger.cpp23
-rw-r--r--services/audioflinger/AudioFlinger.h3
-rw-r--r--services/java/com/android/server/InputManager.java17
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java47
-rw-r--r--services/jni/com_android_server_InputManager.cpp24
-rw-r--r--services/surfaceflinger/TextureManager.cpp1
-rw-r--r--tools/obbtool/Main.cpp21
-rw-r--r--voip/java/android/net/rtp/AudioGroup.java15
-rw-r--r--voip/jni/rtp/AudioGroup.cpp97
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 &lt;manifest&gt;}</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> &notify)
+ : 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> &notify);
+
+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},