Merge "Fix soft Ap handling on system restart" into honeycomb
diff --git a/Android.mk b/Android.mk
index ad7027c..5d989d1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -167,6 +167,7 @@
 	core/java/com/android/internal/view/IInputMethodManager.aidl \
 	core/java/com/android/internal/view/IInputMethodSession.aidl \
 	core/java/com/android/internal/widget/IRemoteViewsFactory.aidl \
+	core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \
 	location/java/android/location/ICountryDetector.aidl \
 	location/java/android/location/ICountryListener.aidl \
 	location/java/android/location/IGeocodeProvider.aidl \
@@ -366,7 +367,7 @@
     -since ./frameworks/base/api/7.xml 7 \
     -since ./frameworks/base/api/8.xml 8 \
     -since ./frameworks/base/api/9.xml 9 \
-    -since ./frameworks/base/api/current.xml HC \
+    -since ./frameworks/base/api/current.xml Honeycomb \
 		-werror -hide 113 \
 		-overview $(LOCAL_PATH)/core/java/overview.html
 
@@ -436,15 +437,14 @@
 
 ## SDK version identifiers used in the published docs
   # major[.minor] version for current SDK. (full releases only)
-framework_docs_SDK_VERSION:=2.3
+framework_docs_SDK_VERSION:=3.0
   # release version (ie "Release x")  (full releases only)
-framework_docs_SDK_REL_ID:=1
+framework_docs_SDK_REL_ID:=Preview
 
 framework_docs_LOCAL_DROIDDOC_OPTIONS += \
 		-hdf sdk.version $(framework_docs_SDK_VERSION) \
 		-hdf sdk.rel.id $(framework_docs_SDK_REL_ID) \
 		-hdf sdk.preview true \
-		-hdf sdk.preview.version Honeycomb
 
 # ====  the api stubs and current.xml ===========================
 include $(CLEAR_VARS)
diff --git a/NOTICE b/NOTICE
index 8d6f583..d857ba3 100644
--- a/NOTICE
+++ b/NOTICE
@@ -72,6 +72,17 @@
 OF ANY KIND, either express or implied; not even the implied warranty
 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
+  =========================================================================
+  ==  NOTICE file corresponding to the section 4 d of                    ==
+  ==  the Apache License, Version 2.0,                                   ==
+  ==  in this case for the Audio Effects code.                           ==
+  =========================================================================
+
+Audio Effects
+These files are Copyright (C) 2004-2010 NXP Software and
+Copyright (C) 2010 The Android Open Source Project, but released under
+the Apache2 License.
+
 
                                Apache License
                            Version 2.0, January 2004
diff --git a/api/10.xml b/api/10.xml
index 3b9ab1a..15fcffe 100644
--- a/api/10.xml
+++ b/api/10.xml
@@ -157967,21 +157967,6 @@
 <parameter name="flags" type="int">
 </parameter>
 </method>
-<method name="setPackageObbPath"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-<parameter name="path" type="java.lang.String">
-</parameter>
-</method>
 </class>
 <class name="MockResources"
  extends="android.content.res.Resources"
diff --git a/api/11.xml b/api/11.xml
index 5b6765b..6c06a0a 100644
--- a/api/11.xml
+++ b/api/11.xml
@@ -188,6 +188,17 @@
  visibility="public"
 >
 </field>
+<field name="BIND_REMOTEVIEWS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.BIND_REMOTEVIEWS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="BIND_WALLPAPER"
  type="java.lang.String"
  transient="false"
@@ -1790,7 +1801,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843501"
+ value="16843499"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1812,7 +1823,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843510"
+ value="16843508"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1823,7 +1834,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843509"
+ value="16843507"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1834,7 +1845,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843511"
+ value="16843509"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1867,7 +1878,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843517"
+ value="16843515"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1889,7 +1900,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843513"
+ value="16843511"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1911,7 +1922,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843540"
+ value="16843538"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1922,7 +1933,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843539"
+ value="16843537"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1933,7 +1944,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843541"
+ value="16843539"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1944,7 +1955,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843512"
+ value="16843510"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1955,7 +1966,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843518"
+ value="16843516"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1966,7 +1977,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843519"
+ value="16843517"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2043,7 +2054,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843607"
+ value="16843605"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2065,7 +2076,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843531"
+ value="16843529"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2109,7 +2120,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843572"
+ value="16843570"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2142,7 +2153,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843553"
+ value="16843551"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2208,7 +2219,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843508"
+ value="16843506"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2274,7 +2285,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843548"
+ value="16843546"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2340,7 +2351,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843537"
+ value="16843535"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2450,7 +2461,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843550"
+ value="16843548"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2494,7 +2505,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843565"
+ value="16843563"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2582,7 +2593,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843526"
+ value="16843524"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2593,7 +2604,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843525"
+ value="16843523"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2626,7 +2637,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843569"
+ value="16843567"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2637,7 +2648,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843568"
+ value="16843566"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2703,7 +2714,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843598"
+ value="16843596"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3220,7 +3231,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843581"
+ value="16843579"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3275,7 +3286,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843595"
+ value="16843593"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3385,7 +3396,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843600"
+ value="16843598"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3451,7 +3462,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843530"
+ value="16843528"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3572,7 +3583,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843566"
+ value="16843564"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3583,7 +3594,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843564"
+ value="16843562"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3594,7 +3605,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843532"
+ value="16843530"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3825,7 +3836,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843604"
+ value="16843602"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3836,7 +3847,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843603"
+ value="16843601"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3946,7 +3957,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843534"
+ value="16843532"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4001,7 +4012,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843535"
+ value="16843533"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4199,7 +4210,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843575"
+ value="16843573"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4221,7 +4232,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843580"
+ value="16843578"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4232,7 +4243,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843577"
+ value="16843575"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4243,7 +4254,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843578"
+ value="16843576"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4254,7 +4265,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843611"
+ value="16843609"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4265,7 +4276,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843576"
+ value="16843574"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4276,7 +4287,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843579"
+ value="16843577"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4375,7 +4386,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843583"
+ value="16843581"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4430,7 +4441,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843589"
+ value="16843587"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4514,7 +4525,7 @@
  visibility="public"
 >
 </field>
-<field name="fragmentNextEnterAnimation"
+<field name="fragmentFadeEnterAnimation"
  type="int"
  transient="false"
  volatile="false"
@@ -4525,7 +4536,7 @@
  visibility="public"
 >
 </field>
-<field name="fragmentNextExitAnimation"
+<field name="fragmentFadeExitAnimation"
  type="int"
  transient="false"
  volatile="false"
@@ -4558,28 +4569,6 @@
  visibility="public"
 >
 </field>
-<field name="fragmentPrevEnterAnimation"
- type="int"
- transient="false"
- volatile="false"
- value="16843499"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="fragmentPrevExitAnimation"
- type="int"
- transient="false"
- volatile="false"
- value="16843500"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="freezesText"
  type="int"
  transient="false"
@@ -4969,7 +4958,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843533"
+ value="16843531"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4980,7 +4969,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843551"
+ value="16843549"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5013,7 +5002,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843605"
+ value="16843603"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5068,7 +5057,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843516"
+ value="16843514"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5189,7 +5178,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843504"
+ value="16843502"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5200,7 +5189,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843502"
+ value="16843500"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5211,7 +5200,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843503"
+ value="16843501"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5321,7 +5310,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843546"
+ value="16843544"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5497,7 +5486,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843573"
+ value="16843571"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5596,7 +5585,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843567"
+ value="16843565"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5827,7 +5816,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843612"
+ value="16843610"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5860,7 +5849,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843606"
+ value="16843604"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6289,7 +6278,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843506"
+ value="16843504"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6333,7 +6322,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843527"
+ value="16843525"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6344,7 +6333,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843521"
+ value="16843519"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6432,7 +6421,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843529"
+ value="16843527"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6487,7 +6476,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843586"
+ value="16843584"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6641,7 +6630,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843585"
+ value="16843583"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6795,7 +6784,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843582"
+ value="16843580"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6927,7 +6916,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843552"
+ value="16843550"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -7323,7 +7312,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843522"
+ value="16843520"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -7477,7 +7466,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843547"
+ value="16843545"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -7642,7 +7631,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843610"
+ value="16843608"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -7961,7 +7950,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843560"
+ value="16843558"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -7972,7 +7961,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843561"
+ value="16843559"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -7983,7 +7972,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843562"
+ value="16843560"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8082,7 +8071,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843558"
+ value="16843556"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8093,7 +8082,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843559"
+ value="16843557"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8445,7 +8434,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843570"
+ value="16843568"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8478,7 +8467,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843536"
+ value="16843534"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8489,7 +8478,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843593"
+ value="16843591"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8500,7 +8489,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843588"
+ value="16843586"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8643,7 +8632,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843563"
+ value="16843561"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8665,7 +8654,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843584"
+ value="16843582"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8676,7 +8665,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843587"
+ value="16843585"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8742,7 +8731,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843596"
+ value="16843594"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8797,7 +8786,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843507"
+ value="16843505"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8819,7 +8808,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843597"
+ value="16843595"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8830,7 +8819,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843505"
+ value="16843503"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8929,7 +8918,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843549"
+ value="16843547"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8940,7 +8929,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843520"
+ value="16843518"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9072,7 +9061,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843599"
+ value="16843597"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9127,7 +9116,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843571"
+ value="16843569"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9193,7 +9182,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843515"
+ value="16843513"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9578,7 +9567,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843523"
+ value="16843521"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9655,7 +9644,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843524"
+ value="16843522"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9699,7 +9688,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843528"
+ value="16843526"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9721,7 +9710,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843601"
+ value="16843599"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9765,7 +9754,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843602"
+ value="16843600"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9908,7 +9897,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843543"
+ value="16843541"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9919,7 +9908,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843542"
+ value="16843540"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9941,7 +9930,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843544"
+ value="16843542"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10172,7 +10161,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843514"
+ value="16843512"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10326,7 +10315,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843554"
+ value="16843552"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10337,7 +10326,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843555"
+ value="16843553"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10348,7 +10337,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843556"
+ value="16843554"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10359,7 +10348,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843557"
+ value="16843555"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10403,7 +10392,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843590"
+ value="16843588"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10436,7 +10425,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843538"
+ value="16843536"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10579,7 +10568,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843574"
+ value="16843572"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10799,7 +10788,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843594"
+ value="16843592"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10810,7 +10799,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843591"
+ value="16843589"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10821,7 +10810,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843592"
+ value="16843590"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10942,7 +10931,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843545"
+ value="16843543"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -11030,7 +11019,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843608"
+ value="16843606"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -11041,7 +11030,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843609"
+ value="16843607"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -28602,17 +28591,6 @@
  visibility="public"
 >
 </method>
-<method name="getCancelable"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getDialog"
  return="android.app.Dialog"
  abstract="false"
@@ -28646,6 +28624,17 @@
  visibility="public"
 >
 </method>
+<method name="isCancelable"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onCancel"
  return="void"
  abstract="false"
@@ -28822,6 +28811,19 @@
 <parameter name="request" type="android.app.DownloadManager.Request">
 </parameter>
 </method>
+<method name="getMaxBytesOverMobile"
+ return="java.lang.Long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
 <method name="getMimeTypeForDownloadedFile"
  return="java.lang.String"
  abstract="false"
@@ -28835,6 +28837,19 @@
 <parameter name="id" type="long">
 </parameter>
 </method>
+<method name="getRecommendedMaxBytesOverMobile"
+ return="java.lang.Long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
 <method name="getUriForDownloadedFile"
  return="android.net.Uri"
  abstract="false"
@@ -30672,8 +30687,8 @@
 <parameter name="listener" type="android.app.FragmentManager.OnBackStackChangedListener">
 </parameter>
 </method>
-<method name="countBackStackEntries"
- return="int"
+<method name="beginTransaction"
+ return="android.app.FragmentTransaction"
  abstract="true"
  native="false"
  synchronized="false"
@@ -30752,7 +30767,7 @@
 <parameter name="tag" type="java.lang.String">
 </parameter>
 </method>
-<method name="getBackStackEntry"
+<method name="getBackStackEntryAt"
  return="android.app.FragmentManager.BackStackEntry"
  abstract="true"
  native="false"
@@ -30765,6 +30780,17 @@
 <parameter name="index" type="int">
 </parameter>
 </method>
+<method name="getBackStackEntryCount"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getFragment"
  return="android.app.Fragment"
  abstract="true"
@@ -30780,17 +30806,6 @@
 <parameter name="key" type="java.lang.String">
 </parameter>
 </method>
-<method name="openTransaction"
- return="android.app.FragmentTransaction"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="popBackStack"
  return="void"
  abstract="true"
@@ -30933,6 +30948,17 @@
  visibility="public"
 >
 </method>
+<method name="getBreadCrumbShortTitleRes"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getBreadCrumbTitle"
  return="java.lang.CharSequence"
  abstract="true"
@@ -30944,6 +30970,17 @@
  visibility="public"
 >
 </method>
+<method name="getBreadCrumbTitleRes"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getId"
  return="int"
  abstract="true"
@@ -31303,7 +31340,7 @@
  visibility="public"
 >
 </field>
-<field name="TRANSIT_FRAGMENT_NEXT"
+<field name="TRANSIT_FRAGMENT_FADE"
  type="int"
  transient="false"
  volatile="false"
@@ -31325,17 +31362,6 @@
  visibility="public"
 >
 </field>
-<field name="TRANSIT_FRAGMENT_PREV"
- type="int"
- transient="false"
- volatile="false"
- value="8196"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="TRANSIT_NONE"
  type="int"
  transient="false"
@@ -33061,19 +33087,6 @@
 <parameter name="callback" type="android.app.LoaderManager.LoaderCallbacks&lt;D&gt;">
 </parameter>
 </method>
-<method name="stopLoader"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<parameter name="id" type="int">
-</parameter>
-</method>
 </class>
 <interface name="LoaderManager.LoaderCallbacks"
  abstract="true"
@@ -37816,7 +37829,7 @@
 </parameter>
 </method>
 <method name="getStorageEncryption"
- return="int"
+ return="boolean"
  abstract="false"
  native="false"
  synchronized="false"
@@ -37828,6 +37841,17 @@
 <parameter name="admin" type="android.content.ComponentName">
 </parameter>
 </method>
+<method name="getStorageEncryptionStatus"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="hasGrantedPolicy"
  return="boolean"
  abstract="false"
@@ -38168,7 +38192,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="3"
+ value="2"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -38179,7 +38203,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="4"
+ value="3"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -38197,17 +38221,6 @@
  visibility="public"
 >
 </field>
-<field name="ENCRYPTION_STATUS_REQUESTED"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="ENCRYPTION_STATUS_UNSUPPORTED"
  type="int"
  transient="false"
@@ -43770,7 +43783,7 @@
  visibility="public"
 >
 </method>
-<method name="onCancelled"
+<method name="onCanceled"
  return="void"
  abstract="false"
  native="false"
@@ -43783,6 +43796,19 @@
 <parameter name="data" type="D">
 </parameter>
 </method>
+<method name="onCancelled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="data" type="D">
+</parameter>
+</method>
 <method name="onLoadInBackground"
  return="D"
  abstract="false"
@@ -43807,17 +43833,6 @@
 <parameter name="delayMS" type="long">
 </parameter>
 </method>
-<method name="waitForLoader"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 </class>
 <class name="BroadcastReceiver"
  extends="java.lang.Object"
@@ -44225,8 +44240,6 @@
 </parameter>
 <parameter name="mimeTypes" type="java.lang.String[]">
 </parameter>
-<parameter name="icon" type="android.graphics.Bitmap">
-</parameter>
 <parameter name="item" type="android.content.ClipData.Item">
 </parameter>
 </constructor>
@@ -44239,8 +44252,6 @@
 >
 <parameter name="description" type="android.content.ClipDescription">
 </parameter>
-<parameter name="icon" type="android.graphics.Bitmap">
-</parameter>
 <parameter name="item" type="android.content.ClipData.Item">
 </parameter>
 </constructor>
@@ -44279,18 +44290,7 @@
  visibility="public"
 >
 </method>
-<method name="getIcon"
- return="android.graphics.Bitmap"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getItem"
+<method name="getItemAt"
  return="android.content.ClipData.Item"
  abstract="false"
  native="false"
@@ -44326,8 +44326,6 @@
 >
 <parameter name="label" type="java.lang.CharSequence">
 </parameter>
-<parameter name="icon" type="android.graphics.Bitmap">
-</parameter>
 <parameter name="intent" type="android.content.Intent">
 </parameter>
 </method>
@@ -44343,8 +44341,6 @@
 >
 <parameter name="label" type="java.lang.CharSequence">
 </parameter>
-<parameter name="icon" type="android.graphics.Bitmap">
-</parameter>
 <parameter name="text" type="java.lang.CharSequence">
 </parameter>
 </method>
@@ -44360,8 +44356,6 @@
 >
 <parameter name="label" type="java.lang.CharSequence">
 </parameter>
-<parameter name="icon" type="android.graphics.Bitmap">
-</parameter>
 <parameter name="uri" type="android.net.Uri">
 </parameter>
 </method>
@@ -44379,8 +44373,6 @@
 </parameter>
 <parameter name="label" type="java.lang.CharSequence">
 </parameter>
-<parameter name="icon" type="android.graphics.Bitmap">
-</parameter>
 <parameter name="uri" type="android.net.Uri">
 </parameter>
 </method>
@@ -50351,6 +50343,16 @@
 >
 <parameter name="context" type="android.content.Context">
 </parameter>
+</constructor>
+<constructor name="CursorLoader"
+ type="android.content.CursorLoader"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
 <parameter name="uri" type="android.net.Uri">
 </parameter>
 <parameter name="projection" type="java.lang.String[]">
@@ -50441,7 +50443,7 @@
  visibility="public"
 >
 </method>
-<method name="onCancelled"
+<method name="onCanceled"
  return="void"
  abstract="false"
  native="false"
@@ -57375,145 +57377,6 @@
 >
 </field>
 </class>
-<class name="XmlDocumentProvider"
- extends="android.content.ContentProvider"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="XmlDocumentProvider"
- type="android.content.XmlDocumentProvider"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="delete"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uri" type="android.net.Uri">
-</parameter>
-<parameter name="selection" type="java.lang.String">
-</parameter>
-<parameter name="selectionArgs" type="java.lang.String[]">
-</parameter>
-</method>
-<method name="getResourceXmlPullParser"
- return="org.xmlpull.v1.XmlPullParser"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="resourceUri" type="android.net.Uri">
-</parameter>
-</method>
-<method name="getType"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uri" type="android.net.Uri">
-</parameter>
-</method>
-<method name="getUriXmlPullParser"
- return="org.xmlpull.v1.XmlPullParser"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-</method>
-<method name="insert"
- return="android.net.Uri"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uri" type="android.net.Uri">
-</parameter>
-<parameter name="values" type="android.content.ContentValues">
-</parameter>
-</method>
-<method name="onCreate"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="query"
- return="android.database.Cursor"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uri" type="android.net.Uri">
-</parameter>
-<parameter name="projection" type="java.lang.String[]">
-</parameter>
-<parameter name="selection" type="java.lang.String">
-</parameter>
-<parameter name="selectionArgs" type="java.lang.String[]">
-</parameter>
-<parameter name="sortOrder" type="java.lang.String">
-</parameter>
-</method>
-<method name="update"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uri" type="android.net.Uri">
-</parameter>
-<parameter name="values" type="android.content.ContentValues">
-</parameter>
-<parameter name="selection" type="java.lang.String">
-</parameter>
-<parameter name="selectionArgs" type="java.lang.String[]">
-</parameter>
-</method>
-</class>
 </package>
 <package name="android.content.pm"
 >
@@ -57783,17 +57646,6 @@
  type="int"
  transient="false"
  volatile="false"
- value="1024"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="FLAG_IMMERSIVE"
- type="int"
- transient="false"
- volatile="false"
  value="512"
  static="true"
  final="true"
@@ -60287,19 +60139,6 @@
 <exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
 </exception>
 </method>
-<method name="getPackageObbPaths"
- return="java.lang.String[]"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-</method>
 <method name="getPackagesForUid"
  return="java.lang.String[]"
  abstract="true"
@@ -60786,21 +60625,6 @@
 <parameter name="installerPackageName" type="java.lang.String">
 </parameter>
 </method>
-<method name="setPackageObbPaths"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-<parameter name="paths" type="java.lang.String[]">
-</parameter>
-</method>
 <field name="COMPONENT_ENABLED_STATE_DEFAULT"
  type="int"
  transient="false"
@@ -61562,6 +61386,46 @@
  visibility="public"
 >
 </field>
+<field name="externalCacheSize"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="externalDataSize"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="externalMediaSize"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="externalObbSize"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="packageName"
  type="java.lang.String"
  transient="false"
@@ -77084,6 +76948,16 @@
  visibility="public"
 >
 </field>
+<field name="inMutable"
+ type="boolean"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="inPreferQualityOverSpeed"
  type="boolean"
  transient="false"
@@ -86319,7 +86193,7 @@
 <method name="updateTexImage"
  return="void"
  abstract="false"
- native="true"
+ native="false"
  synchronized="false"
  static="false"
  final="false"
@@ -95577,6 +95451,17 @@
  visibility="public"
 >
 </field>
+<field name="TOUCHABLE_INSETS_REGION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TOUCHABLE_INSETS_VISIBLE"
  type="int"
  transient="false"
@@ -95608,6 +95493,16 @@
  visibility="public"
 >
 </field>
+<field name="touchableRegion"
+ type="android.graphics.Region"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="visibleTopInsets"
  type="int"
  transient="false"
@@ -147371,53 +147266,6 @@
 >
 </field>
 </class>
-<class name="StorageEventListener"
- extends="java.lang.Object"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="StorageEventListener"
- type="android.os.storage.StorageEventListener"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="onStorageStateChanged"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="path" type="java.lang.String">
-</parameter>
-<parameter name="oldState" type="java.lang.String">
-</parameter>
-<parameter name="newState" type="java.lang.String">
-</parameter>
-</method>
-<method name="onUsbMassStorageConnectionChanged"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="connected" type="boolean">
-</parameter>
-</method>
-</class>
 <class name="StorageManager"
  extends="java.lang.Object"
  abstract="false"
@@ -147487,111 +147335,6 @@
 </parameter>
 </method>
 </class>
-<class name="StorageResultCode"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="StorageResultCode"
- type="android.os.storage.StorageResultCode"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<field name="OperationFailedInternalError"
- type="int"
- transient="false"
- volatile="false"
- value="-1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OperationFailedMediaBlank"
- type="int"
- transient="false"
- volatile="false"
- value="-3"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OperationFailedMediaCorrupt"
- type="int"
- transient="false"
- volatile="false"
- value="-4"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OperationFailedNoMedia"
- type="int"
- transient="false"
- volatile="false"
- value="-2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OperationFailedStorageBusy"
- type="int"
- transient="false"
- volatile="false"
- value="-7"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OperationFailedStorageMounted"
- type="int"
- transient="false"
- volatile="false"
- value="-6"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OperationFailedStorageNotMounted"
- type="int"
- transient="false"
- volatile="false"
- value="-5"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OperationSucceeded"
- type="int"
- transient="false"
- volatile="false"
- value="0"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-</class>
 </package>
 <package name="android.preference"
 >
@@ -167286,6 +167029,38 @@
 <parameter name="dimX" type="int">
 </parameter>
 </method>
+<method name="setFromFieldPacker"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="xoff" type="int">
+</parameter>
+<parameter name="fp" type="android.renderscript.FieldPacker">
+</parameter>
+</method>
+<method name="setFromFieldPacker"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="xoff" type="int">
+</parameter>
+<parameter name="component_number" type="int">
+</parameter>
+<parameter name="fp" type="android.renderscript.FieldPacker">
+</parameter>
+</method>
 <method name="syncAll"
  return="void"
  abstract="false"
@@ -173046,6 +172821,49 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<method name="bindAllocation"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="va" type="android.renderscript.Allocation">
+</parameter>
+<parameter name="slot" type="int">
+</parameter>
+</method>
+<method name="invoke"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="slot" type="int">
+</parameter>
+</method>
+<method name="invoke"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="slot" type="int">
+</parameter>
+<parameter name="v" type="android.renderscript.FieldPacker">
+</parameter>
+</method>
 <method name="setTimeZone"
  return="void"
  abstract="false"
@@ -173059,6 +172877,111 @@
 <parameter name="timeZone" type="java.lang.String">
 </parameter>
 </method>
+<method name="setVar"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+<parameter name="v" type="float">
+</parameter>
+</method>
+<method name="setVar"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+<parameter name="v" type="double">
+</parameter>
+</method>
+<method name="setVar"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+<parameter name="v" type="int">
+</parameter>
+</method>
+<method name="setVar"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+<parameter name="v" type="long">
+</parameter>
+</method>
+<method name="setVar"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+<parameter name="v" type="boolean">
+</parameter>
+</method>
+<method name="setVar"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+<parameter name="o" type="android.renderscript.BaseObj">
+</parameter>
+</method>
+<method name="setVar"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+<parameter name="v" type="android.renderscript.FieldPacker">
+</parameter>
+</method>
 </class>
 <class name="Script.Builder"
  extends="java.lang.Object"
@@ -173190,6 +173113,32 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<constructor name="ScriptC"
+ type="android.renderscript.ScriptC"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="rs" type="android.renderscript.RenderScript">
+</parameter>
+</constructor>
+<constructor name="ScriptC"
+ type="android.renderscript.ScriptC"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="rs" type="android.renderscript.RenderScript">
+</parameter>
+<parameter name="resources" type="android.content.res.Resources">
+</parameter>
+<parameter name="resourceID" type="int">
+</parameter>
+</constructor>
 </class>
 <class name="Short2"
  extends="java.lang.Object"
@@ -183646,6 +183595,17 @@
  visibility="public"
 >
 </method>
+<method name="getObbDir"
+ return="java.io.File"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getPackageCodePath"
  return="java.lang.String"
  abstract="false"
@@ -185234,19 +185194,6 @@
 <exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
 </exception>
 </method>
-<method name="getPackageObbPaths"
- return="java.lang.String[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-</method>
 <method name="getPackagesForUid"
  return="java.lang.String[]"
  abstract="false"
@@ -185731,36 +185678,6 @@
 <parameter name="installerPackageName" type="java.lang.String">
 </parameter>
 </method>
-<method name="setPackageObbPath"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-<parameter name="path" type="java.lang.String">
-</parameter>
-</method>
-<method name="setPackageObbPaths"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-<parameter name="paths" type="java.lang.String[]">
-</parameter>
-</method>
 </class>
 <class name="MockResources"
  extends="android.content.res.Resources"
@@ -252426,6 +252343,23 @@
 <parameter name="intent" type="android.content.Intent">
 </parameter>
 </method>
+<method name="setRemoteAdapter"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="appWidgetId" type="int">
+</parameter>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
 <method name="setScrollPosition"
  return="void"
  abstract="false"
diff --git a/api/9.xml b/api/9.xml
index 3b9ab1a..15fcffe 100644
--- a/api/9.xml
+++ b/api/9.xml
@@ -157967,21 +157967,6 @@
 <parameter name="flags" type="int">
 </parameter>
 </method>
-<method name="setPackageObbPath"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-<parameter name="path" type="java.lang.String">
-</parameter>
-</method>
 </class>
 <class name="MockResources"
  extends="android.content.res.Resources"
diff --git a/api/current.xml b/api/current.xml
index ef23af2..73581f1 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -188,6 +188,17 @@
  visibility="public"
 >
 </field>
+<field name="BIND_REMOTEVIEWS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.BIND_REMOTEVIEWS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="BIND_WALLPAPER"
  type="java.lang.String"
  transient="false"
@@ -1790,7 +1801,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843501"
+ value="16843499"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1812,7 +1823,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843510"
+ value="16843508"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1823,7 +1834,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843509"
+ value="16843507"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1834,7 +1845,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843511"
+ value="16843509"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1867,7 +1878,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843517"
+ value="16843515"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1889,7 +1900,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843513"
+ value="16843511"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1911,7 +1922,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843540"
+ value="16843538"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1922,7 +1933,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843539"
+ value="16843537"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1933,7 +1944,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843541"
+ value="16843539"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1944,7 +1955,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843512"
+ value="16843510"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1955,7 +1966,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843518"
+ value="16843516"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1966,7 +1977,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843519"
+ value="16843517"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2043,7 +2054,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843607"
+ value="16843605"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2065,7 +2076,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843531"
+ value="16843529"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2109,7 +2120,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843572"
+ value="16843570"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2142,7 +2153,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843553"
+ value="16843551"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2208,7 +2219,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843508"
+ value="16843506"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2274,7 +2285,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843548"
+ value="16843546"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2340,7 +2351,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843537"
+ value="16843535"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2450,7 +2461,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843550"
+ value="16843548"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2494,7 +2505,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843565"
+ value="16843563"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2582,7 +2593,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843526"
+ value="16843524"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2593,7 +2604,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843525"
+ value="16843523"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2626,7 +2637,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843569"
+ value="16843567"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2637,7 +2648,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843568"
+ value="16843566"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -2703,7 +2714,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843598"
+ value="16843596"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3220,7 +3231,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843581"
+ value="16843579"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3275,7 +3286,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843595"
+ value="16843593"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3385,7 +3396,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843600"
+ value="16843598"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3451,7 +3462,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843530"
+ value="16843528"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3572,7 +3583,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843566"
+ value="16843564"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3583,7 +3594,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843564"
+ value="16843562"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3594,7 +3605,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843532"
+ value="16843530"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3825,7 +3836,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843604"
+ value="16843602"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3836,7 +3847,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843603"
+ value="16843601"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -3946,7 +3957,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843534"
+ value="16843532"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4001,7 +4012,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843535"
+ value="16843533"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4199,7 +4210,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843575"
+ value="16843573"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4221,7 +4232,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843580"
+ value="16843578"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4232,7 +4243,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843577"
+ value="16843575"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4243,7 +4254,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843578"
+ value="16843576"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4254,7 +4265,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843611"
+ value="16843609"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4265,7 +4276,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843576"
+ value="16843574"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4276,7 +4287,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843579"
+ value="16843577"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4375,7 +4386,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843583"
+ value="16843581"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4430,7 +4441,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843589"
+ value="16843587"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4514,7 +4525,7 @@
  visibility="public"
 >
 </field>
-<field name="fragmentNextEnterAnimation"
+<field name="fragmentFadeEnterAnimation"
  type="int"
  transient="false"
  volatile="false"
@@ -4525,7 +4536,7 @@
  visibility="public"
 >
 </field>
-<field name="fragmentNextExitAnimation"
+<field name="fragmentFadeExitAnimation"
  type="int"
  transient="false"
  volatile="false"
@@ -4558,28 +4569,6 @@
  visibility="public"
 >
 </field>
-<field name="fragmentPrevEnterAnimation"
- type="int"
- transient="false"
- volatile="false"
- value="16843499"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="fragmentPrevExitAnimation"
- type="int"
- transient="false"
- volatile="false"
- value="16843500"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="freezesText"
  type="int"
  transient="false"
@@ -4969,7 +4958,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843533"
+ value="16843531"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4980,7 +4969,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843551"
+ value="16843549"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5013,7 +5002,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843605"
+ value="16843603"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5068,7 +5057,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843516"
+ value="16843514"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5189,7 +5178,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843504"
+ value="16843502"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5200,7 +5189,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843502"
+ value="16843500"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5211,7 +5200,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843503"
+ value="16843501"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5321,7 +5310,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843546"
+ value="16843544"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5497,7 +5486,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843573"
+ value="16843571"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5596,7 +5585,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843567"
+ value="16843565"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5827,7 +5816,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843612"
+ value="16843610"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5860,7 +5849,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843606"
+ value="16843604"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6289,7 +6278,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843506"
+ value="16843504"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6333,7 +6322,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843527"
+ value="16843525"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6344,7 +6333,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843521"
+ value="16843519"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6432,7 +6421,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843529"
+ value="16843527"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6487,7 +6476,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843586"
+ value="16843584"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6641,7 +6630,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843585"
+ value="16843583"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6795,7 +6784,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843582"
+ value="16843580"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -6927,7 +6916,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843552"
+ value="16843550"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -7323,7 +7312,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843522"
+ value="16843520"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -7477,7 +7466,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843547"
+ value="16843545"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -7642,7 +7631,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843610"
+ value="16843608"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -7961,7 +7950,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843560"
+ value="16843558"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -7972,7 +7961,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843561"
+ value="16843559"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -7983,7 +7972,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843562"
+ value="16843560"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8082,7 +8071,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843558"
+ value="16843556"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8093,7 +8082,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843559"
+ value="16843557"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8445,7 +8434,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843570"
+ value="16843568"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8478,7 +8467,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843536"
+ value="16843534"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8489,7 +8478,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843593"
+ value="16843591"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8500,7 +8489,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843588"
+ value="16843586"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8643,7 +8632,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843563"
+ value="16843561"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8665,7 +8654,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843584"
+ value="16843582"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8676,7 +8665,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843587"
+ value="16843585"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8742,7 +8731,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843596"
+ value="16843594"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8797,7 +8786,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843507"
+ value="16843505"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8819,7 +8808,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843597"
+ value="16843595"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8830,7 +8819,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843505"
+ value="16843503"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8929,7 +8918,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843549"
+ value="16843547"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -8940,7 +8929,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843520"
+ value="16843518"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9072,7 +9061,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843599"
+ value="16843597"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9127,7 +9116,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843571"
+ value="16843569"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9193,7 +9182,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843515"
+ value="16843513"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9578,7 +9567,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843523"
+ value="16843521"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9655,7 +9644,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843524"
+ value="16843522"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9699,7 +9688,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843528"
+ value="16843526"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9721,7 +9710,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843601"
+ value="16843599"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9765,7 +9754,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843602"
+ value="16843600"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9908,7 +9897,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843543"
+ value="16843541"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9919,7 +9908,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843542"
+ value="16843540"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9941,7 +9930,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843544"
+ value="16843542"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10172,7 +10161,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843514"
+ value="16843512"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10326,7 +10315,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843554"
+ value="16843552"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10337,7 +10326,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843555"
+ value="16843553"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10348,7 +10337,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843556"
+ value="16843554"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10359,7 +10348,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843557"
+ value="16843555"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10403,7 +10392,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843590"
+ value="16843588"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10436,7 +10425,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843538"
+ value="16843536"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10579,7 +10568,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843574"
+ value="16843572"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10799,7 +10788,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843594"
+ value="16843592"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10810,7 +10799,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843591"
+ value="16843589"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10821,7 +10810,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843592"
+ value="16843590"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -10916,6 +10905,17 @@
  visibility="public"
 >
 </field>
+<field name="windowCloseOnTouchOutside"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843611"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="windowContentOverlay"
  type="int"
  transient="false"
@@ -10942,7 +10942,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843545"
+ value="16843543"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -11030,7 +11030,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843608"
+ value="16843606"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -11041,7 +11041,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843609"
+ value="16843607"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -24322,6 +24322,19 @@
 <parameter name="uri" type="android.net.Uri">
 </parameter>
 </method>
+<method name="setFinishOnTouchOutside"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="finish" type="boolean">
+</parameter>
+</method>
 <method name="setIntent"
  return="void"
  abstract="false"
@@ -28602,17 +28615,6 @@
  visibility="public"
 >
 </method>
-<method name="getCancelable"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getDialog"
  return="android.app.Dialog"
  abstract="false"
@@ -28646,6 +28648,17 @@
  visibility="public"
 >
 </method>
+<method name="isCancelable"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onCancel"
  return="void"
  abstract="false"
@@ -28822,6 +28835,19 @@
 <parameter name="request" type="android.app.DownloadManager.Request">
 </parameter>
 </method>
+<method name="getMaxBytesOverMobile"
+ return="java.lang.Long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
 <method name="getMimeTypeForDownloadedFile"
  return="java.lang.String"
  abstract="false"
@@ -28835,6 +28861,19 @@
 <parameter name="id" type="long">
 </parameter>
 </method>
+<method name="getRecommendedMaxBytesOverMobile"
+ return="java.lang.Long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
 <method name="getUriForDownloadedFile"
  return="android.net.Uri"
  abstract="false"
@@ -30672,8 +30711,8 @@
 <parameter name="listener" type="android.app.FragmentManager.OnBackStackChangedListener">
 </parameter>
 </method>
-<method name="countBackStackEntries"
- return="int"
+<method name="beginTransaction"
+ return="android.app.FragmentTransaction"
  abstract="true"
  native="false"
  synchronized="false"
@@ -30752,7 +30791,7 @@
 <parameter name="tag" type="java.lang.String">
 </parameter>
 </method>
-<method name="getBackStackEntry"
+<method name="getBackStackEntryAt"
  return="android.app.FragmentManager.BackStackEntry"
  abstract="true"
  native="false"
@@ -30765,6 +30804,17 @@
 <parameter name="index" type="int">
 </parameter>
 </method>
+<method name="getBackStackEntryCount"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getFragment"
  return="android.app.Fragment"
  abstract="true"
@@ -30780,17 +30830,6 @@
 <parameter name="key" type="java.lang.String">
 </parameter>
 </method>
-<method name="openTransaction"
- return="android.app.FragmentTransaction"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="popBackStack"
  return="void"
  abstract="true"
@@ -30933,6 +30972,17 @@
  visibility="public"
 >
 </method>
+<method name="getBreadCrumbShortTitleRes"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getBreadCrumbTitle"
  return="java.lang.CharSequence"
  abstract="true"
@@ -30944,6 +30994,17 @@
  visibility="public"
 >
 </method>
+<method name="getBreadCrumbTitleRes"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getId"
  return="int"
  abstract="true"
@@ -31303,7 +31364,7 @@
  visibility="public"
 >
 </field>
-<field name="TRANSIT_FRAGMENT_NEXT"
+<field name="TRANSIT_FRAGMENT_FADE"
  type="int"
  transient="false"
  volatile="false"
@@ -31325,17 +31386,6 @@
  visibility="public"
 >
 </field>
-<field name="TRANSIT_FRAGMENT_PREV"
- type="int"
- transient="false"
- volatile="false"
- value="8196"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="TRANSIT_NONE"
  type="int"
  transient="false"
@@ -33061,19 +33111,6 @@
 <parameter name="callback" type="android.app.LoaderManager.LoaderCallbacks&lt;D&gt;">
 </parameter>
 </method>
-<method name="stopLoader"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<parameter name="id" type="int">
-</parameter>
-</method>
 </class>
 <interface name="LoaderManager.LoaderCallbacks"
  abstract="true"
@@ -37816,7 +37853,7 @@
 </parameter>
 </method>
 <method name="getStorageEncryption"
- return="int"
+ return="boolean"
  abstract="false"
  native="false"
  synchronized="false"
@@ -37828,6 +37865,17 @@
 <parameter name="admin" type="android.content.ComponentName">
 </parameter>
 </method>
+<method name="getStorageEncryptionStatus"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="hasGrantedPolicy"
  return="boolean"
  abstract="false"
@@ -38168,7 +38216,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="3"
+ value="2"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -38179,7 +38227,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="4"
+ value="3"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -38197,17 +38245,6 @@
  visibility="public"
 >
 </field>
-<field name="ENCRYPTION_STATUS_REQUESTED"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="ENCRYPTION_STATUS_UNSUPPORTED"
  type="int"
  transient="false"
@@ -43770,7 +43807,7 @@
  visibility="public"
 >
 </method>
-<method name="onCancelled"
+<method name="onCanceled"
  return="void"
  abstract="false"
  native="false"
@@ -43783,6 +43820,19 @@
 <parameter name="data" type="D">
 </parameter>
 </method>
+<method name="onCancelled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="data" type="D">
+</parameter>
+</method>
 <method name="onLoadInBackground"
  return="D"
  abstract="false"
@@ -43807,17 +43857,6 @@
 <parameter name="delayMS" type="long">
 </parameter>
 </method>
-<method name="waitForLoader"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 </class>
 <class name="BroadcastReceiver"
  extends="java.lang.Object"
@@ -44225,8 +44264,6 @@
 </parameter>
 <parameter name="mimeTypes" type="java.lang.String[]">
 </parameter>
-<parameter name="icon" type="android.graphics.Bitmap">
-</parameter>
 <parameter name="item" type="android.content.ClipData.Item">
 </parameter>
 </constructor>
@@ -44239,8 +44276,6 @@
 >
 <parameter name="description" type="android.content.ClipDescription">
 </parameter>
-<parameter name="icon" type="android.graphics.Bitmap">
-</parameter>
 <parameter name="item" type="android.content.ClipData.Item">
 </parameter>
 </constructor>
@@ -44279,18 +44314,7 @@
  visibility="public"
 >
 </method>
-<method name="getIcon"
- return="android.graphics.Bitmap"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getItem"
+<method name="getItemAt"
  return="android.content.ClipData.Item"
  abstract="false"
  native="false"
@@ -44326,8 +44350,6 @@
 >
 <parameter name="label" type="java.lang.CharSequence">
 </parameter>
-<parameter name="icon" type="android.graphics.Bitmap">
-</parameter>
 <parameter name="intent" type="android.content.Intent">
 </parameter>
 </method>
@@ -44343,8 +44365,6 @@
 >
 <parameter name="label" type="java.lang.CharSequence">
 </parameter>
-<parameter name="icon" type="android.graphics.Bitmap">
-</parameter>
 <parameter name="text" type="java.lang.CharSequence">
 </parameter>
 </method>
@@ -44360,8 +44380,6 @@
 >
 <parameter name="label" type="java.lang.CharSequence">
 </parameter>
-<parameter name="icon" type="android.graphics.Bitmap">
-</parameter>
 <parameter name="uri" type="android.net.Uri">
 </parameter>
 </method>
@@ -44379,8 +44397,6 @@
 </parameter>
 <parameter name="label" type="java.lang.CharSequence">
 </parameter>
-<parameter name="icon" type="android.graphics.Bitmap">
-</parameter>
 <parameter name="uri" type="android.net.Uri">
 </parameter>
 </method>
@@ -50351,6 +50367,16 @@
 >
 <parameter name="context" type="android.content.Context">
 </parameter>
+</constructor>
+<constructor name="CursorLoader"
+ type="android.content.CursorLoader"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
 <parameter name="uri" type="android.net.Uri">
 </parameter>
 <parameter name="projection" type="java.lang.String[]">
@@ -50441,7 +50467,7 @@
  visibility="public"
 >
 </method>
-<method name="onCancelled"
+<method name="onCanceled"
  return="void"
  abstract="false"
  native="false"
@@ -57375,145 +57401,6 @@
 >
 </field>
 </class>
-<class name="XmlDocumentProvider"
- extends="android.content.ContentProvider"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="XmlDocumentProvider"
- type="android.content.XmlDocumentProvider"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="delete"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uri" type="android.net.Uri">
-</parameter>
-<parameter name="selection" type="java.lang.String">
-</parameter>
-<parameter name="selectionArgs" type="java.lang.String[]">
-</parameter>
-</method>
-<method name="getResourceXmlPullParser"
- return="org.xmlpull.v1.XmlPullParser"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="resourceUri" type="android.net.Uri">
-</parameter>
-</method>
-<method name="getType"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uri" type="android.net.Uri">
-</parameter>
-</method>
-<method name="getUriXmlPullParser"
- return="org.xmlpull.v1.XmlPullParser"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-</method>
-<method name="insert"
- return="android.net.Uri"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uri" type="android.net.Uri">
-</parameter>
-<parameter name="values" type="android.content.ContentValues">
-</parameter>
-</method>
-<method name="onCreate"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="query"
- return="android.database.Cursor"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uri" type="android.net.Uri">
-</parameter>
-<parameter name="projection" type="java.lang.String[]">
-</parameter>
-<parameter name="selection" type="java.lang.String">
-</parameter>
-<parameter name="selectionArgs" type="java.lang.String[]">
-</parameter>
-<parameter name="sortOrder" type="java.lang.String">
-</parameter>
-</method>
-<method name="update"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uri" type="android.net.Uri">
-</parameter>
-<parameter name="values" type="android.content.ContentValues">
-</parameter>
-<parameter name="selection" type="java.lang.String">
-</parameter>
-<parameter name="selectionArgs" type="java.lang.String[]">
-</parameter>
-</method>
-</class>
 </package>
 <package name="android.content.pm"
 >
@@ -57783,17 +57670,6 @@
  type="int"
  transient="false"
  volatile="false"
- value="1024"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="FLAG_IMMERSIVE"
- type="int"
- transient="false"
- volatile="false"
  value="512"
  static="true"
  final="true"
@@ -60287,19 +60163,6 @@
 <exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
 </exception>
 </method>
-<method name="getPackageObbPaths"
- return="java.lang.String[]"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-</method>
 <method name="getPackagesForUid"
  return="java.lang.String[]"
  abstract="true"
@@ -60786,21 +60649,6 @@
 <parameter name="installerPackageName" type="java.lang.String">
 </parameter>
 </method>
-<method name="setPackageObbPaths"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-<parameter name="paths" type="java.lang.String[]">
-</parameter>
-</method>
 <field name="COMPONENT_ENABLED_STATE_DEFAULT"
  type="int"
  transient="false"
@@ -61592,6 +61440,16 @@
  visibility="public"
 >
 </field>
+<field name="externalObbSize"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="packageName"
  type="java.lang.String"
  transient="false"
@@ -77114,6 +76972,16 @@
  visibility="public"
 >
 </field>
+<field name="inMutable"
+ type="boolean"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="inPreferQualityOverSpeed"
  type="boolean"
  transient="false"
@@ -86349,7 +86217,7 @@
 <method name="updateTexImage"
  return="void"
  abstract="false"
- native="true"
+ native="false"
  synchronized="false"
  static="false"
  final="false"
@@ -136255,6 +136123,17 @@
  visibility="public"
 >
 </method>
+<method name="getPreserveEGLContextOnPause"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getRenderMode"
  return="int"
  abstract="false"
@@ -136426,6 +136305,19 @@
 <parameter name="glWrapper" type="android.opengl.GLSurfaceView.GLWrapper">
 </parameter>
 </method>
+<method name="setPreserveEGLContextOnPause"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="preserveOnPause" type="boolean">
+</parameter>
+</method>
 <method name="setRenderMode"
  return="void"
  abstract="false"
@@ -146858,6 +146750,16 @@
  visibility="public"
 >
 </constructor>
+<constructor name="StrictMode.VmPolicy.Builder"
+ type="android.os.StrictMode.VmPolicy.Builder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="base" type="android.os.StrictMode.VmPolicy">
+</parameter>
+</constructor>
 <method name="build"
  return="android.os.StrictMode.VmPolicy"
  abstract="false"
@@ -146935,6 +146837,21 @@
  visibility="public"
 >
 </method>
+<method name="setClassInstanceLimit"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="klass" type="java.lang.Class">
+</parameter>
+<parameter name="instanceLimit" type="int">
+</parameter>
+</method>
 </class>
 <class name="SystemClock"
  extends="java.lang.Object"
@@ -147422,53 +147339,6 @@
 >
 </field>
 </class>
-<class name="StorageEventListener"
- extends="java.lang.Object"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="StorageEventListener"
- type="android.os.storage.StorageEventListener"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="onStorageStateChanged"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="path" type="java.lang.String">
-</parameter>
-<parameter name="oldState" type="java.lang.String">
-</parameter>
-<parameter name="newState" type="java.lang.String">
-</parameter>
-</method>
-<method name="onUsbMassStorageConnectionChanged"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="connected" type="boolean">
-</parameter>
-</method>
-</class>
 <class name="StorageManager"
  extends="java.lang.Object"
  abstract="false"
@@ -147538,111 +147408,6 @@
 </parameter>
 </method>
 </class>
-<class name="StorageResultCode"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="StorageResultCode"
- type="android.os.storage.StorageResultCode"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<field name="OperationFailedInternalError"
- type="int"
- transient="false"
- volatile="false"
- value="-1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OperationFailedMediaBlank"
- type="int"
- transient="false"
- volatile="false"
- value="-3"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OperationFailedMediaCorrupt"
- type="int"
- transient="false"
- volatile="false"
- value="-4"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OperationFailedNoMedia"
- type="int"
- transient="false"
- volatile="false"
- value="-2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OperationFailedStorageBusy"
- type="int"
- transient="false"
- volatile="false"
- value="-7"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OperationFailedStorageMounted"
- type="int"
- transient="false"
- volatile="false"
- value="-6"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OperationFailedStorageNotMounted"
- type="int"
- transient="false"
- volatile="false"
- value="-5"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OperationSucceeded"
- type="int"
- transient="false"
- volatile="false"
- value="0"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-</class>
 </package>
 <package name="android.preference"
 >
@@ -175942,6 +175707,17 @@
  visibility="public"
 >
 </field>
+<field name="KEY_PARAM_PAN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;pan&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="KEY_PARAM_STREAM"
  type="java.lang.String"
  transient="false"
@@ -175964,6 +175740,17 @@
  visibility="public"
 >
 </field>
+<field name="KEY_PARAM_VOLUME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;volume&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <interface name="TextToSpeech.OnInitListener"
  abstract="true"
@@ -183903,6 +183690,17 @@
  visibility="public"
 >
 </method>
+<method name="getObbDir"
+ return="java.io.File"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getPackageCodePath"
  return="java.lang.String"
  abstract="false"
@@ -185491,19 +185289,6 @@
 <exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
 </exception>
 </method>
-<method name="getPackageObbPaths"
- return="java.lang.String[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-</method>
 <method name="getPackagesForUid"
  return="java.lang.String[]"
  abstract="false"
@@ -185988,36 +185773,6 @@
 <parameter name="installerPackageName" type="java.lang.String">
 </parameter>
 </method>
-<method name="setPackageObbPath"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-<parameter name="path" type="java.lang.String">
-</parameter>
-</method>
-<method name="setPackageObbPaths"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-<parameter name="paths" type="java.lang.String[]">
-</parameter>
-</method>
 </class>
 <class name="MockResources"
  extends="android.content.res.Resources"
@@ -219736,6 +219491,14 @@
 <parameter name="view" type="android.view.View">
 </parameter>
 </constructor>
+<constructor name="View.DragShadowBuilder"
+ type="android.view.View.DragShadowBuilder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
 <method name="getView"
  return="android.view.View"
  abstract="false"
@@ -236386,6 +236149,48 @@
 </parameter>
 </method>
 </class>
+<class name="WebStorage.Origin"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getOrigin"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getQuota"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getUsage"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
 <interface name="WebStorage.QuotaUpdater"
  abstract="true"
  static="true"
@@ -252683,6 +252488,23 @@
 <parameter name="intent" type="android.content.Intent">
 </parameter>
 </method>
+<method name="setRemoteAdapter"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="appWidgetId" type="int">
+</parameter>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
 <method name="setScrollPosition"
  return="void"
  abstract="false"
@@ -260476,7 +260298,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
 </parameter>
 </method>
 </interface>
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 9cbc7be..e6eaf71 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -1019,6 +1019,10 @@
             AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
 
         Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
+        // See FLAT_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
+        // Since it was set in Eclair+ we can't change it without breaking apps using
+        // the intent from a non-Activity context.
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         intent.addCategory(
                 String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
 
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ec2f771..0a64070 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -45,6 +45,7 @@
 import android.os.Looper;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.os.StrictMode;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
@@ -858,6 +859,7 @@
             mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                     ? mLastNonConfigurationInstances.fragments : null);
         }
+        StrictMode.noteActivityClass(this.getClass());
         mFragments.dispatchCreate();
         mCalled = true;
     }
@@ -1806,6 +1808,14 @@
     }
 
     /**
+     * Sets whether this activity is finished when touched outside its window's
+     * bounds.
+     */
+    public void setFinishOnTouchOutside(boolean finish) {
+        mWindow.setCloseOnTouchOutside(finish);
+    }
+    
+    /**
      * Use with {@link #setDefaultKeyMode} to turn off default handling of
      * keys.
      * 
@@ -2061,6 +2071,11 @@
      * The default implementation always returns false.
      */
     public boolean onTouchEvent(MotionEvent event) {
+        if (mWindow.shouldCloseOnTouch(this, event)) {
+            finish();
+            return true;
+        }
+        
         return false;
     }
     
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index 70e3616..428f4e3 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -64,11 +64,13 @@
 
     protected AlertDialog(Context context, int theme) {
         super(context, theme == 0 ? getDefaultDialogTheme(context) : theme);
+        mWindow.alwaysReadCloseOnTouchAttr();
         mAlert = new AlertController(context, this, getWindow());
     }
 
     protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
         super(context, getDefaultDialogTheme(context));
+        mWindow.alwaysReadCloseOnTouchAttr();
         setCancelable(cancelable);
         setOnCancelListener(cancelListener);
         mAlert = new AlertController(context, this, getWindow());
@@ -81,25 +83,6 @@
         return outValue.resourceId;
     }
 
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        if (mCancelable) {
-            final View decor = mWindow.getDecorView();
-            final int width = decor.getWidth();
-            final int height = decor.getHeight();
-            final float x = ev.getX();
-            final float y = ev.getY();
-
-            if (mCancelable && (x < 0 || x > width || y < 0 || y > height)
-                    &&  mDecor != null && isShowing()) {
-                cancel();
-                return true;
-            }
-        }
-
-        return super.onTouchEvent(ev);
-    }
-
     /**
      * Gets one of the buttons used in the dialog.
      * <p>
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index b64069d..079d4cf 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1103,25 +1103,6 @@
         return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
     }
 
-    @Override
-    public void setPackageObbPaths(String packageName, String[] paths) {
-        try {
-            mPM.setPackageObbPaths(packageName, paths);
-        } catch (RemoteException e) {
-            // Should never happen!
-        }
-    }
-
-    @Override
-    public String[] getPackageObbPaths(String packageName) {
-        try {
-            return mPM.getPackageObbPaths(packageName);
-        } catch (RemoteException e) {
-            // Should never happen!
-        }
-        return null;
-    }
-
     private final ContextImpl mContext;
     private final IPackageManager mPM;
 
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 33b747c..1d217f0 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -267,6 +267,14 @@
         return mIndex;
     }
 
+    public int getBreadCrumbTitleRes() {
+        return mBreadCrumbTitleRes;
+    }
+
+    public int getBreadCrumbShortTitleRes() {
+        return mBreadCrumbShortTitleRes;
+    }
+
     public CharSequence getBreadCrumbTitle() {
         if (mBreadCrumbTitleRes != 0) {
             return mManager.mActivity.getText(mBreadCrumbTitleRes);
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 6791400..7365670 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -41,7 +41,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnCreateContextMenuListener;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.Window;
@@ -90,12 +89,6 @@
     private Message mDismissMessage;
     private Message mShowMessage;
 
-    /**
-     * Whether to cancel the dialog when a touch is received outside of the
-     * window's bounds.
-     */
-    private boolean mCanceledOnTouchOutside = false;
-    
     private OnKeyListener mOnKeyListener;
 
     private boolean mCreated = false;
@@ -597,8 +590,7 @@
      *         happens outside of the window bounds.
      */
     public boolean onTouchEvent(MotionEvent event) {
-        if (mCancelable && mCanceledOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
-                && isOutOfBounds(event) && mDecor != null && mShowing) {
+        if (mCancelable && mShowing && mWindow.shouldCloseOnTouch(mContext, event)) {
             cancel();
             return true;
         }
@@ -606,16 +598,6 @@
         return false;
     }
 
-    private boolean isOutOfBounds(MotionEvent event) {
-        final int x = (int) event.getX();
-        final int y = (int) event.getY();
-        final int slop = ViewConfiguration.get(mContext).getScaledWindowTouchSlop();
-        final View decorView = getWindow().getDecorView();
-        return (x < -slop) || (y < -slop)
-                || (x > (decorView.getWidth()+slop))
-                || (y > (decorView.getHeight()+slop));
-    }
-    
     /**
      * Called when the trackball was moved and not handled by any of the
      * views inside of the activity.  So, for example, if the trackball moves
@@ -1021,7 +1003,7 @@
             mCancelable = true;
         }
         
-        mCanceledOnTouchOutside = cancel;
+        mWindow.setCloseOnTouchOutside(cancel);
     }
     
     /**
diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java
index 6194240..0bc89e7 100644
--- a/core/java/android/app/DialogFragment.java
+++ b/core/java/android/app/DialogFragment.java
@@ -218,7 +218,7 @@
      * {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}.
      */
     public void show(FragmentManager manager, String tag) {
-        FragmentTransaction ft = manager.openTransaction();
+        FragmentTransaction ft = manager.beginTransaction();
         ft.add(this, tag);
         ft.commit();
     }
@@ -260,7 +260,7 @@
                     FragmentManager.POP_BACK_STACK_INCLUSIVE);
             mBackStackId = -1;
         } else {
-            FragmentTransaction ft = getFragmentManager().openTransaction();
+            FragmentTransaction ft = getFragmentManager().beginTransaction();
             ft.remove(this);
             if (allowStateLoss) {
                 ft.commitAllowingStateLoss();
@@ -295,7 +295,7 @@
     /**
      * Return the current value of {@link #setCancelable(boolean)}.
      */
-    public boolean getCancelable() {
+    public boolean isCancelable() {
         return mCancelable;
     }
 
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 12f4a18..297d246 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -28,6 +28,8 @@
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.provider.Downloads;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
 import android.util.Log;
 import android.util.Pair;
 
@@ -1035,6 +1037,40 @@
     }
 
     /**
+     * Returns maximum size, in bytes, of downloads that may go over a mobile connection; or null if
+     * there's no limit
+     *
+     * @param context the {@link Context} to use for accessing the {@link ContentResolver}
+     * @return maximum size, in bytes, of downloads that may go over a mobile connection; or null if
+     * there's no limit
+     */
+    public static Long getMaxBytesOverMobile(Context context) {
+        try {
+            return Settings.Secure.getLong(context.getContentResolver(),
+                    Settings.Secure.DOWNLOAD_MAX_BYTES_OVER_MOBILE);
+        } catch (SettingNotFoundException exc) {
+            return null;
+        }
+    }
+
+    /**
+     * Returns recommended maximum size, in bytes, of downloads that may go over a mobile
+     * connection; or null if there's no recommended limit.  The user will have the option to bypass
+     * this limit.
+     *
+     * @param context the {@link Context} to use for accessing the {@link ContentResolver}
+     * @return recommended maximum size, in bytes, of downloads that may go over a mobile
+     * connection; or null if there's no recommended limit.
+     */
+    public static Long getRecommendedMaxBytesOverMobile(Context context) {
+        try {
+            return Settings.Secure.getLong(context.getContentResolver(),
+                    Settings.Secure.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE);
+        } catch (SettingNotFoundException exc) {
+            return null;
+        }
+    }
+    /**
      * Get the DownloadProvider URI for the download with the given ID.
      */
     Uri getDownloadUri(long id) {
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 316e513..3280b22 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -912,6 +912,12 @@
         return null;
     }
     
+    /**
+     * Get the root view for the fragment's layout (the one returned by {@link #onCreateView}),
+     * if provided.
+     * 
+     * @return The fragment's root view, or null if it has no layout.
+     */
     public View getView() {
         return mView;
     }
diff --git a/core/java/android/app/FragmentBreadCrumbs.java b/core/java/android/app/FragmentBreadCrumbs.java
index fb89099..72a8e9a 100644
--- a/core/java/android/app/FragmentBreadCrumbs.java
+++ b/core/java/android/app/FragmentBreadCrumbs.java
@@ -204,13 +204,13 @@
 
     void updateCrumbs() {
         FragmentManager fm = mActivity.getFragmentManager();
-        int numEntries = fm.countBackStackEntries();
+        int numEntries = fm.getBackStackEntryCount();
         int numPreEntries = getPreEntryCount();
         int numViews = mContainer.getChildCount();
         for (int i = 0; i < numEntries + numPreEntries; i++) {
             BackStackEntry bse = i < numPreEntries
                     ? getPreEntry(i)
-                    : fm.getBackStackEntry(i - numPreEntries);
+                    : fm.getBackStackEntryAt(i - numPreEntries);
             if (i < numViews) {
                 View v = mContainer.getChildAt(i);
                 Object tag = v.getTag();
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index eb9b8a3..bce240f 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -49,7 +49,7 @@
      * Representation of an entry on the fragment back stack, as created
      * with {@link FragmentTransaction#addToBackStack(String)
      * FragmentTransaction.addToBackStack()}.  Entries can later be
-     * retrieved with {@link FragmentManager#getBackStackEntry(int)
+     * retrieved with {@link FragmentManager#getBackStackEntryAt(int)
      * FragmentManager.getBackStackEntry()}.
      *
      * <p>Note that you should never hold on to a BackStackEntry object;
@@ -65,6 +65,18 @@
         public int getId();
 
         /**
+         * Return the full bread crumb title resource identifier for the entry,
+         * or 0 if it does not have one.
+         */
+        public int getBreadCrumbTitleRes();
+
+        /**
+         * Return the short bread crumb title resource identifier for the entry,
+         * or 0 if it does not have one.
+         */
+        public int getBreadCrumbShortTitleRes();
+
+        /**
          * Return the full bread crumb title for the entry, or null if it
          * does not have one.
          */
@@ -100,8 +112,14 @@
      * in the state, and if changes are made after the state is saved then they
      * will be lost.</p>
      */
-    public abstract FragmentTransaction openTransaction();
+    public abstract FragmentTransaction beginTransaction();
 
+    /** @hide -- remove once prebuilts are in. */
+    @Deprecated
+    public FragmentTransaction openTransaction() {
+        return beginTransaction();
+    }
+    
     /**
      * After a {@link FragmentTransaction} is committed with
      * {@link FragmentTransaction#commit FragmentTransaction.commit()}, it
@@ -148,7 +166,9 @@
 
     /**
      * Pop the top state off the back stack.  Returns true if there was one
-     * to pop, else false.
+     * to pop, else false.  This function is asynchronous -- it enqueues the
+     * request to pop, but the action will not be performed until the application
+     * returns to its event loop.
      */
     public abstract void popBackStack();
 
@@ -163,6 +183,10 @@
     /**
      * Pop the last fragment transition from the manager's fragment
      * back stack.  If there is nothing to pop, false is returned.
+     * This function is asynchronous -- it enqueues the
+     * request to pop, but the action will not be performed until the application
+     * returns to its event loop.
+     * 
      * @param name If non-null, this is the name of a previous back state
      * to look for; if found, all states up to that state will be popped.  The
      * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
@@ -181,6 +205,10 @@
 
     /**
      * Pop all back stack states up to the one with the given identifier.
+     * This function is asynchronous -- it enqueues the
+     * request to pop, but the action will not be performed until the application
+     * returns to its event loop.
+     * 
      * @param id Identifier of the stated to be popped. If no identifier exists,
      * false is returned.
      * The identifier is the number returned by
@@ -202,13 +230,13 @@
     /**
      * Return the number of entries currently in the back stack.
      */
-    public abstract int countBackStackEntries();
+    public abstract int getBackStackEntryCount();
 
     /**
      * Return the BackStackEntry at index <var>index</var> in the back stack;
      * entries start index 0 being the bottom of the stack.
      */
-    public abstract BackStackEntry getBackStackEntry(int index);
+    public abstract BackStackEntry getBackStackEntryAt(int index);
 
     /**
      * Add a new listener for changes to the fragment back stack.
@@ -347,7 +375,7 @@
     };
 
     @Override
-    public FragmentTransaction openTransaction() {
+    public FragmentTransaction beginTransaction() {
         return new BackStackRecord(this);
     }
 
@@ -411,12 +439,12 @@
     }
 
     @Override
-    public int countBackStackEntries() {
+    public int getBackStackEntryCount() {
         return mBackStack != null ? mBackStack.size() : 0;
     }
 
     @Override
-    public BackStackEntry getBackStackEntry(int index) {
+    public BackStackEntry getBackStackEntryAt(int index) {
         return mBackStack.get(index);
     }
 
@@ -1673,11 +1701,8 @@
             case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
                 rev = FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
                 break;
-            case FragmentTransaction.TRANSIT_FRAGMENT_NEXT:
-                rev = FragmentTransaction.TRANSIT_FRAGMENT_PREV;
-                break;
-            case FragmentTransaction.TRANSIT_FRAGMENT_PREV:
-                rev = FragmentTransaction.TRANSIT_FRAGMENT_NEXT;
+            case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
+                rev = FragmentTransaction.TRANSIT_FRAGMENT_FADE;
                 break;
         }
         return rev;
@@ -1697,15 +1722,10 @@
                     ? com.android.internal.R.styleable.FragmentAnimation_fragmentCloseEnterAnimation
                     : com.android.internal.R.styleable.FragmentAnimation_fragmentCloseExitAnimation;
                 break;
-            case FragmentTransaction.TRANSIT_FRAGMENT_NEXT:
+            case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
                 animAttr = enter
-                    ? com.android.internal.R.styleable.FragmentAnimation_fragmentNextEnterAnimation
-                    : com.android.internal.R.styleable.FragmentAnimation_fragmentNextExitAnimation;
-                break;
-            case FragmentTransaction.TRANSIT_FRAGMENT_PREV:
-                animAttr = enter
-                    ? com.android.internal.R.styleable.FragmentAnimation_fragmentPrevEnterAnimation
-                    : com.android.internal.R.styleable.FragmentAnimation_fragmentPrevExitAnimation;
+                    ? com.android.internal.R.styleable.FragmentAnimation_fragmentFadeEnterAnimation
+                    : com.android.internal.R.styleable.FragmentAnimation_fragmentFadeExitAnimation;
                 break;
         }
         return animAttr;
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 1b8debc..0cc774d 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -110,10 +110,9 @@
     public static final int TRANSIT_FRAGMENT_OPEN = 1 | TRANSIT_ENTER_MASK;
     /** Fragment is being removed from the stack */
     public static final int TRANSIT_FRAGMENT_CLOSE = 2 | TRANSIT_EXIT_MASK;
-    /** Fragment is being added in a 'next' operation*/
-    public static final int TRANSIT_FRAGMENT_NEXT = 3 | TRANSIT_ENTER_MASK;
-    /** Fragment is being removed in a 'previous' operation */
-    public static final int TRANSIT_FRAGMENT_PREV = 4 | TRANSIT_EXIT_MASK;
+    /** Fragment should simply fade in or out; that is, no strong navigation associated
+     * with it except that it is appearing or disappearing for some reason. */
+    public static final int TRANSIT_FRAGMENT_FADE = 3 | TRANSIT_ENTER_MASK;
 
     /**
      * Set specific animation resources to run for the fragments that are
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index 5f8c098..ffe2a5d 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -60,7 +60,7 @@
          * Called when a previously created loader has finished its load.  Note
          * that normally an application is <em>not</em> allowed to commit fragment
          * transactions while in this call, since it can happen after an
-         * activity's state is saved.  See {@link FragmentManager#openTransaction()
+         * activity's state is saved.  See {@link FragmentManager#beginTransaction()
          * FragmentManager.openTransaction()} for further discussion on this.
          * 
          * <p>This function is guaranteed to be called prior to the release of
@@ -159,14 +159,6 @@
     public abstract void destroyLoader(int id);
 
     /**
-     * @deprecated Renamed to {@link #destroyLoader}.
-     */
-    @Deprecated
-    public void stopLoader(int id) {
-        destroyLoader(id);
-    }
-
-    /**
      * Return the Loader with the given id or null if no matching Loader
      * is found.
      */
@@ -353,7 +345,7 @@
             
             // Notify of the new data so the app can switch out the old data before
             // we try to destroy it.
-            if (mData != data) {
+            if (data == null || mData != data) {
                 mData = data;
                 if (mStarted) {
                     callOnLoadFinished(loader, data);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4186fec..3f3aa74 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1093,38 +1093,32 @@
     }
 
     /**
-     * Result code for {@link #setStorageEncryption} and {@link #getStorageEncryption}:
+     * Result code for {@link #setStorageEncryption} and {@link #getStorageEncryptionStatus}:
      * indicating that encryption is not supported.
      */
     public static final int ENCRYPTION_STATUS_UNSUPPORTED = 0;
 
     /**
-     * Result code for {@link #setStorageEncryption} and {@link #getStorageEncryption}:
+     * Result code for {@link #setStorageEncryption} and {@link #getStorageEncryptionStatus}:
      * indicating that encryption is supported, but is not currently active.
      */
     public static final int ENCRYPTION_STATUS_INACTIVE = 1;
 
     /**
-     * Result code for {@link #setStorageEncryption} and {@link #getStorageEncryption}:
-     * indicating that encryption is not currently active, but has been requested.
-     */
-    public static final int ENCRYPTION_STATUS_REQUESTED = 2;
-
-    /**
-     * Result code for {@link #setStorageEncryption} and {@link #getStorageEncryption}:
+     * Result code for {@link #setStorageEncryption} and {@link #getStorageEncryptionStatus}:
      * indicating that encryption is not currently active, but is currently
      * being activated.  This is only reported by devices that support
      * encryption of data and only when the storage is currently
      * undergoing a process of becoming encrypted.  A device that must reboot and/or wipe data
      * to become encrypted will never return this value.
      */
-    public static final int ENCRYPTION_STATUS_ACTIVATING = 3;
+    public static final int ENCRYPTION_STATUS_ACTIVATING = 2;
 
     /**
-     * Result code for {@link #setStorageEncryption} and {@link #getStorageEncryption}:
+     * Result code for {@link #setStorageEncryption} and {@link #getStorageEncryptionStatus}:
      * indicating that encryption is active.
      */
-    public static final int ENCRYPTION_STATUS_ACTIVE = 4;
+    public static final int ENCRYPTION_STATUS_ACTIVE = 3;
 
     /**
      * Activity action: begin the process of encrypting data on the device.  This activity should
@@ -1139,14 +1133,7 @@
 
     /**
      * Called by an application that is administering the device to
-     * request that the storage system be encrypted.  Depending
-     * on the returned status code, the caller may proceed in different
-     * ways.  If the result is {@link #ENCRYPTION_STATUS_UNSUPPORTED}, the
-     * storage system does not support encryption.  If the
-     * result is {@link #ENCRYPTION_STATUS_REQUESTED}, use {@link
-     * #ACTION_START_ENCRYPTION} to begin the process of encrypting or decrypting the
-     * storage.  If the result is {@link #ENCRYPTION_STATUS_ACTIVATING} or
-     * {@link #ENCRYPTION_STATUS_ACTIVE}, no further action is required.
+     * request that the storage system be encrypted.
      *
      * <p>When multiple device administrators attempt to control device
      * encryption, the most secure, supported setting will always be
@@ -1167,7 +1154,10 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param encrypt true to request encryption, false to release any previous request
-     * @return current status of encryption
+     * @return the new request status (for all active admins) - will be one of
+     * {@link #ENCRYPTION_STATUS_UNSUPPORTED}, {@link #ENCRYPTION_STATUS_INACTIVE}, or
+     * {@link #ENCRYPTION_STATUS_ACTIVE}.  This is the value of the requests;  Use
+     * {@link #getStorageEncryptionStatus()} to query the actual device state.
      */
     public int setStorageEncryption(ComponentName admin, boolean encrypt) {
         if (mService != null) {
@@ -1182,12 +1172,14 @@
 
     /**
      * Called by an application that is administering the device to
-     * determine the encryption status of a specific storage system.
+     * determine the requested setting for secure storage.
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @return current status of encryption
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.  If null,
+     * this will return the requested encryption setting as an aggregate of all active
+     * administrators.
+     * @return true if the admin(s) are requesting encryption, false if not.
      */
-    public int getStorageEncryption(ComponentName admin) {
+    public boolean getStorageEncryption(ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getStorageEncryption(admin);
@@ -1195,6 +1187,33 @@
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
         }
+        return false;
+    }
+
+    /**
+     * Called by an application that is administering the device to
+     * determine the current encryption status of the device.
+     *
+     * Depending on the returned status code, the caller may proceed in different
+     * ways.  If the result is {@link #ENCRYPTION_STATUS_UNSUPPORTED}, the
+     * storage system does not support encryption.  If the
+     * result is {@link #ENCRYPTION_STATUS_INACTIVE}, use {@link
+     * #ACTION_START_ENCRYPTION} to begin the process of encrypting or decrypting the
+     * storage.  If the result is {@link #ENCRYPTION_STATUS_ACTIVATING} or
+     * {@link #ENCRYPTION_STATUS_ACTIVE}, no further action is required.
+     *
+     * @return current status of encryption.  The value will be one of
+     * {@link #ENCRYPTION_STATUS_UNSUPPORTED}, {@link #ENCRYPTION_STATUS_INACTIVE},
+     * {@link #ENCRYPTION_STATUS_ACTIVATING}, or{@link #ENCRYPTION_STATUS_ACTIVE}.
+     */
+    public int getStorageEncryptionStatus() {
+        if (mService != null) {
+            try {
+                return mService.getStorageEncryptionStatus();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
         return ENCRYPTION_STATUS_UNSUPPORTED;
     }
 
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index d3b5cf3..e8caca1 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -76,7 +76,8 @@
     ComponentName getGlobalProxyAdmin();
 
     int setStorageEncryption(in ComponentName who, boolean encrypt);
-    int getStorageEncryption(in ComponentName who);
+    boolean getStorageEncryption(in ComponentName who);
+    int getStorageEncryptionStatus();
 
     void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing);
     boolean isAdminActive(in ComponentName policyReceiver);
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 2a583c1..019652c 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -438,6 +439,47 @@
     }
 
     /**
+     * Binds the RemoteViewsService for a given appWidgetId and intent.
+     *
+     * The appWidgetId specified must already be bound to the calling AppWidgetHost via
+     * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
+     *
+     * @param appWidgetId   The AppWidget instance for which to bind the RemoteViewsService.
+     * @param intent        The intent of the service which will be providing the data to the
+     *                      RemoteViewsAdapter.
+     * @param connection    The callback interface to be notified when a connection is made or lost.
+     * @hide
+     */
+    public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) {
+        try {
+            sService.bindRemoteViewsService(appWidgetId, intent, connection);
+        }
+        catch (RemoteException e) {
+            throw new RuntimeException("system server dead?", e);
+        }
+    }
+
+    /**
+     * Unbinds the RemoteViewsService for a given appWidgetId and intent.
+     *
+     * The appWidgetId specified muse already be bound to the calling AppWidgetHost via
+     * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
+     *
+     * @param appWidgetId   The AppWidget instance for which to bind the RemoteViewsService.
+     * @param intent        The intent of the service which will be providing the data to the
+     *                      RemoteViewsAdapter.
+     * @hide
+     */
+    public void unbindRemoteViewsService(int appWidgetId, Intent intent) {
+        try {
+            sService.unbindRemoteViewsService(appWidgetId, intent);
+        }
+        catch (RemoteException e) {
+            throw new RuntimeException("system server dead?", e);
+        }
+    }
+
+    /**
      * Get the list of appWidgetIds that have been bound to the given AppWidget
      * provider.
      *
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index c6b9e80..3d6182b 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -168,6 +168,11 @@
      * Called if the task was canceled before it was completed.  Gives the class a chance
      * to properly dispose of the result.
      */
+    public void onCanceled(D data) {
+        onCancelled(data);
+    }
+
+    @Deprecated
     public void onCancelled(D data) {
     }
 
@@ -195,7 +200,7 @@
     }
 
     void dispatchOnCancelled(LoadTask task, D data) {
-        onCancelled(data);
+        onCanceled(data);
         if (mCancellingTask == task) {
             if (DEBUG) Slog.v(TAG, "Cancelled task is now canceled!");
             mLastLoadCompleteTime = SystemClock.uptimeMillis();
@@ -240,6 +245,8 @@
      * thread would cause a deadlock.
      * <p>
      * Use for testing only.  <b>Never</b> call this from a UI thread.
+     *
+     * @hide
      */
     public void waitForLoader() {
         LoadTask task = mTask;
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 5939643..028149b 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -170,6 +170,16 @@
      * State for a result that is pending for a broadcast receiver.  Returned
      * by {@link BroadcastReceiver#goAsync() goAsync()}
      * while in {@link BroadcastReceiver#onReceive BroadcastReceiver.onReceive()}.
+     * This allows you to return from onReceive() without having the broadcast
+     * terminate; you must call {@link #finish()} once you are done with the
+     * broadcast.  This allows you to process the broadcast off of the main
+     * thread of your app.
+     * 
+     * <p>Note on threading: the state inside of this class is not itself
+     * thread-safe, however you can use it from any thread if you properly
+     * sure that you do not have races.  Typically this means you will hand
+     * the entire object to another thread, which will be solely responsible
+     * for setting any results and finally calling {@link #finish()}.
      */
     public static class PendingResult {
         /** @hide */
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 6f4d098..d9c6b07 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -42,9 +42,9 @@
  * {@link ClipDescription#getMimeType(int) getDescription().getMimeType(int)}
  * must return correct MIME type(s) describing the data in the clip.  For help
  * in correctly constructing a clip with the correct MIME type, use
- * {@link #newPlainText(CharSequence, Bitmap, CharSequence)},
- * {@link #newUri(ContentResolver, CharSequence, Bitmap, Uri)}, and
- * {@link #newIntent(CharSequence, Bitmap, Intent)}.
+ * {@link #newPlainText(CharSequence, CharSequence)},
+ * {@link #newUri(ContentResolver, CharSequence, Uri)}, and
+ * {@link #newIntent(CharSequence, Intent)}.
  *
  * <p>Each Item instance can be one of three main classes of data: a simple
  * CharSequence of text, a single Intent object, or a Uri.  See {@link Item}
@@ -70,7 +70,7 @@
  * "content:" URIs.  A content URI allows the recipient of a ClippedData item
  * to interact closely with the ContentProvider holding the data in order to
  * negotiate the transfer of that data.  The clip must also be filled in with
- * the available MIME types; {@link #newUri(ContentResolver, CharSequence, Bitmap, Uri)}
+ * the available MIME types; {@link #newUri(ContentResolver, CharSequence, Uri)}
  * will take care of correctly doing this.
  *
  * <p>For example, here is the paste function of a simple NotePad application.
@@ -321,16 +321,14 @@
      *
      * @param label Label to show to the user describing this clip.
      * @param mimeTypes An array of MIME types this data is available as.
-     * @param icon Bitmap providing the user with an iconing representation of
-     * the clip.
      * @param item The contents of the first item in the clip.
      */
-    public ClipData(CharSequence label, String[] mimeTypes, Bitmap icon, Item item) {
+    public ClipData(CharSequence label, String[] mimeTypes, Item item) {
         mClipDescription = new ClipDescription(label, mimeTypes);
         if (item == null) {
             throw new NullPointerException("item is null");
         }
-        mIcon = icon;
+        mIcon = null;
         mItems.add(item);
     }
 
@@ -338,16 +336,14 @@
      * Create a new clip.
      *
      * @param description The ClipDescription describing the clip contents.
-     * @param icon Bitmap providing the user with an iconing representation of
-     * the clip.
      * @param item The contents of the first item in the clip.
      */
-    public ClipData(ClipDescription description, Bitmap icon, Item item) {
+    public ClipData(ClipDescription description, Item item) {
         mClipDescription = description;
         if (item == null) {
             throw new NullPointerException("item is null");
         }
-        mIcon = icon;
+        mIcon = null;
         mItems.add(item);
     }
 
@@ -356,13 +352,12 @@
      * {@link ClipDescription#MIMETYPE_TEXT_PLAIN}.
      *
      * @param label User-visible label for the clip data.
-     * @param icon Iconic representation of the clip data.
      * @param text The actual text in the clip.
      * @return Returns a new ClipData containing the specified data.
      */
-    static public ClipData newPlainText(CharSequence label, Bitmap icon, CharSequence text) {
+    static public ClipData newPlainText(CharSequence label, CharSequence text) {
         Item item = new Item(text);
-        return new ClipData(label, MIMETYPES_TEXT_PLAIN, icon, item);
+        return new ClipData(label, MIMETYPES_TEXT_PLAIN, item);
     }
 
     /**
@@ -370,13 +365,12 @@
      * {@link ClipDescription#MIMETYPE_TEXT_INTENT}.
      *
      * @param label User-visible label for the clip data.
-     * @param icon Iconic representation of the clip data.
      * @param intent The actual Intent in the clip.
      * @return Returns a new ClipData containing the specified data.
      */
-    static public ClipData newIntent(CharSequence label, Bitmap icon, Intent intent) {
+    static public ClipData newIntent(CharSequence label, Intent intent) {
         Item item = new Item(intent);
-        return new ClipData(label, MIMETYPES_TEXT_INTENT, icon, item);
+        return new ClipData(label, MIMETYPES_TEXT_INTENT, item);
     }
 
     /**
@@ -387,12 +381,11 @@
      *
      * @param resolver ContentResolver used to get information about the URI.
      * @param label User-visible label for the clip data.
-     * @param icon Iconic representation of the clip data.
      * @param uri The URI in the clip.
      * @return Returns a new ClipData containing the specified data.
      */
     static public ClipData newUri(ContentResolver resolver, CharSequence label,
-            Bitmap icon, Uri uri) {
+            Uri uri) {
         Item item = new Item(uri);
         String[] mimeTypes = null;
         if ("content".equals(uri.getScheme())) {
@@ -417,24 +410,23 @@
         if (mimeTypes == null) {
             mimeTypes = MIMETYPES_TEXT_URILIST;
         }
-        return new ClipData(label, mimeTypes, icon, item);
+        return new ClipData(label, mimeTypes, item);
     }
 
     /**
      * Create a new ClipData holding an URI with MIME type
      * {@link ClipDescription#MIMETYPE_TEXT_URILIST}.
-     * Unlike {@link #newUri(ContentResolver, CharSequence, Bitmap, Uri)}, nothing
+     * Unlike {@link #newUri(ContentResolver, CharSequence, Uri)}, nothing
      * is inferred about the URI -- if it is a content: URI holding a bitmap,
      * the reported type will still be uri-list.  Use this with care!
      *
      * @param label User-visible label for the clip data.
-     * @param icon Iconic representation of the clip data.
      * @param uri The URI in the clip.
      * @return Returns a new ClipData containing the specified data.
      */
-    static public ClipData newRawUri(CharSequence label, Bitmap icon, Uri uri) {
+    static public ClipData newRawUri(CharSequence label, Uri uri) {
         Item item = new Item(uri);
-        return new ClipData(label, MIMETYPES_TEXT_URILIST, icon, item);
+        return new ClipData(label, MIMETYPES_TEXT_URILIST, item);
     }
 
     /**
@@ -445,6 +437,9 @@
         return mClipDescription;
     }
     
+    /**
+     * Add a new Item to the overall ClipData container.
+     */
     public void addItem(Item item) {
         if (item == null) {
             throw new NullPointerException("item is null");
@@ -452,15 +447,23 @@
         mItems.add(item);
     }
 
+    /** @hide */
     public Bitmap getIcon() {
         return mIcon;
     }
 
+    /**
+     * Return the number of items in the clip data.
+     */
     public int getItemCount() {
         return mItems.size();
     }
 
-    public Item getItem(int index) {
+    /**
+     * Return a single item inside of the clip data.  The index can range
+     * from 0 to {@link #getItemCount()}-1.
+     */
+    public Item getItemAt(int index) {
         return mItems.get(index);
     }
 
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 3e2b763..a79f060 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -170,7 +170,7 @@
     public CharSequence getText() {
         ClipData clip = getPrimaryClip();
         if (clip != null && clip.getItemCount() > 0) {
-            return clip.getItem(0).coerceToText(mContext);
+            return clip.getItemAt(0).coerceToText(mContext);
         }
         return null;
     }
@@ -181,7 +181,7 @@
      * primary clip.  It has no label or icon.
      */
     public void setText(CharSequence text) {
-        setPrimaryClip(ClipData.newPlainText(null, null, text));
+        setPrimaryClip(ClipData.newPlainText(null, text));
     }
 
     /**
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index 38ebaf2..6228bd0 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -26,6 +26,17 @@
 
 /**
  * A loader that queries the {@link ContentResolver} and returns a {@link Cursor}.
+ * This class implements the {@link Loader} protocol in a standard way for
+ * querying cursors, building on {@link AsyncTaskLoader} to perform the cursor
+ * query on a background thread so that it does not block the application's UI.
+ * 
+ * <p>A CursorLoader must be built with the full information for the query to
+ * perform, either through the
+ * {@link #CursorLoader(Context, Uri, String[], String, String[], String)} or
+ * creating an empty instance with {@link #CursorLoader(Context)} and filling
+ * in the desired paramters with {@link #setUri(Uri)}, {@link #setSelection(String)},
+ * {@link #setSelectionArgs(String[])}, {@link #setSortOrder(String)},
+ * and {@link #setProjection(String[])}.
  */
 public class CursorLoader extends AsyncTaskLoader<Cursor> {
     final ForceLoadContentObserver mObserver;
@@ -81,6 +92,22 @@
         }
     }
 
+    /**
+     * Creates an empty unspecified CursorLoader.  You must follow this with
+     * calls to {@link #setUri(Uri)}, {@link #setSelection(String)}, etc
+     * to specify the query to perform.
+     */
+    public CursorLoader(Context context) {
+        super(context);
+        mObserver = new ForceLoadContentObserver();
+    }
+
+    /**
+     * Creates a fully-specified CursorLoader.  See
+     * {@link ContentResolver#query(Uri, String[], String, String[], String)
+     * ContentResolver.query()} for documentation on the meaning of the
+     * parameters.  These will be passed as-is to that call.
+     */
     public CursorLoader(Context context, Uri uri, String[] projection, String selection,
             String[] selectionArgs, String sortOrder) {
         super(context);
@@ -119,7 +146,7 @@
     }
 
     @Override
-    public void onCancelled(Cursor cursor) {
+    public void onCanceled(Cursor cursor) {
         if (cursor != null && !cursor.isClosed()) {
             cursor.close();
         }
diff --git a/core/java/android/content/XmlDocumentProvider.java b/core/java/android/content/XmlDocumentProvider.java
index 153ad38..76539c7 100644
--- a/core/java/android/content/XmlDocumentProvider.java
+++ b/core/java/android/content/XmlDocumentProvider.java
@@ -40,6 +40,8 @@
 import java.util.regex.Pattern;
 
 /**
+ * @hide -- not yet ready to support, should be provided just as a static lib.
+ * 
  * A read-only content provider which extracts data out of an XML document.
  *
  * <p>A XPath-like selection pattern is used to select some nodes in the XML document. Each such
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index e688c86..46f611f 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -149,7 +149,13 @@
      * {@link android.R.attr#finishOnCloseSystemDialogs} attribute.
      */
     public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 0x0100;
-    /** 
+    /**
+     * Value for {@link #flags}: true when the application's rendering should
+     * be hardware accelerated.
+     */
+    public static final int FLAG_HARDWARE_ACCELERATED = 0x0200;
+    /**
+     * @hide
      * Bit in {@link #flags} corresponding to an immersive activity
      * that wishes not to be interrupted by notifications.
      * Applications that hide the system notification bar with
@@ -164,12 +170,7 @@
      * "toast" window).
      * {@see android.app.Notification#FLAG_HIGH_PRIORITY}
      */
-    public static final int FLAG_IMMERSIVE = 0x0200;
-    /**
-     * Value for {@link #flags}: true when the application's rendering should
-     * be hardware accelerated.
-     */
-    public static final int FLAG_HARDWARE_ACCELERATED = 0x0400;
+    public static final int FLAG_IMMERSIVE = 0x0400;
     /**
      * Options that have been set in the activity declaration in the
      * manifest.
@@ -180,7 +181,7 @@
      * {@link #FLAG_STATE_NOT_NEEDED}, {@link #FLAG_EXCLUDE_FROM_RECENTS},
      * {@link #FLAG_ALLOW_TASK_REPARENTING}, {@link #FLAG_NO_HISTORY},
      * {@link #FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS},
-     * {@link #FLAG_IMMERSIVE}, {@link #FLAG_HARDWARE_ACCELERATED}
+     * {@link #FLAG_HARDWARE_ACCELERATED}
      */
     public int flags;
 
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 28e1a63..034525e 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -323,7 +323,4 @@
 
     boolean setInstallLocation(int loc);
     int getInstallLocation();
-
-    void setPackageObbPaths(in String packageName, in String[] paths);
-    String[] getPackageObbPaths(in String packageName);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 47418aa..6e9cdbe 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2289,32 +2289,4 @@
      */
     public abstract void movePackage(
             String packageName, IPackageMoveObserver observer, int flags);
-
-    /**
-     * Sets the Opaque Binary Blob (OBB) file path associated with a package
-     * name. The caller must have the
-     * {@link android.Manifest.permission#INSTALL_PACKAGES} permission.
-     * <p>
-     * NOTE: The existence or format of this file is not currently checked, but
-     * it may be in the future.
-     * 
-     * @param packageName Name of the package with which to associate the .obb
-     *            file.
-     * @param paths Arrays of paths on the filesystem to the .obb files
-     *            associated with the package.
-     * @see #getPackageObbPaths(String)
-     */
-    public abstract void setPackageObbPaths(String packageName, String[] paths);
-
-    /**
-     * Gets the Opaque Binary Blob (OBB) file path associated with the package.
-     * The caller must be the owner of the package queried or have the
-     * {@link android.Manifest.permission#INSTALL_PACKAGES} permission.
-     * 
-     * @param packageName Name of the package with which to associate the .obb
-     *            file.
-     * @return array of paths to .obb files associated with the package
-     * @see #setPackageObbPaths(String, String[])
-     */
-    public abstract String[] getPackageObbPaths(String packageName);
 }
diff --git a/core/java/android/content/pm/PackageStats.java b/core/java/android/content/pm/PackageStats.java
index 28a2886..11068e5 100755
--- a/core/java/android/content/pm/PackageStats.java
+++ b/core/java/android/content/pm/PackageStats.java
@@ -55,6 +55,9 @@
     /** Size of the external media size used by the application. */
     public long externalMediaSize;
 
+    /** Size of the package's OBBs placed on external media. */
+    public long externalObbSize;
+
     public static final Parcelable.Creator<PackageStats> CREATOR
             = new Parcelable.Creator<PackageStats>() {
         public PackageStats createFromParcel(Parcel in) {
@@ -83,6 +86,8 @@
         sb.append(externalCacheSize);
         sb.append(",externalMediaSize=");
         sb.append(externalMediaSize);
+        sb.append(",externalObbSize=");
+        sb.append(externalObbSize);
         return sb.toString();
     }
 
@@ -98,6 +103,7 @@
         externalDataSize = source.readLong();
         externalCacheSize = source.readLong();
         externalMediaSize = source.readLong();
+        externalObbSize = source.readLong();
     }
 
     public PackageStats(PackageStats pStats) {
@@ -108,6 +114,7 @@
         externalDataSize = pStats.externalDataSize;
         externalCacheSize = pStats.externalCacheSize;
         externalMediaSize = pStats.externalMediaSize;
+        externalObbSize = pStats.externalObbSize;
     }
 
     public int describeContents() {
@@ -122,5 +129,6 @@
         dest.writeLong(externalDataSize);
         dest.writeLong(externalCacheSize);
         dest.writeLong(externalMediaSize);
+        dest.writeLong(externalObbSize);
     }
 }
diff --git a/core/java/android/database/DefaultDatabaseErrorHandler.java b/core/java/android/database/DefaultDatabaseErrorHandler.java
index 3619e48..61337dd 100644
--- a/core/java/android/database/DefaultDatabaseErrorHandler.java
+++ b/core/java/android/database/DefaultDatabaseErrorHandler.java
@@ -24,8 +24,22 @@
 import android.util.Pair;
 
 /**
- * Default class used defining the actions to take when the following errors are detected
- *   database corruption
+ * Default class used to define the actions to take when the database corruption is reported
+ * by sqlite.
+ * <p>
+ * An application can specify an implementation of {@link DatabaseErrorHandler} on the
+ * following:
+ * <ul>
+ *   <li>{@link SQLiteDatabase#openOrCreateDatabase(String,
+ *      android.database.sqlite.SQLiteDatabase.CursorFactory, DatabaseErrorHandler)}</li>
+ *   <li>{@link SQLiteDatabase#openDatabase(String,
+ *      android.database.sqlite.SQLiteDatabase.CursorFactory, int, DatabaseErrorHandler)}</li>
+ * </ul>
+ * The specified {@link DatabaseErrorHandler} is used to handle database corruption errors, if they
+ * occur.
+ * <p>
+ * If null is specified for DatabaeErrorHandler param in the above calls, then this class is used
+ * as the default {@link DatabaseErrorHandler}.
  */
 public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler {
 
diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index 980048c..d1bbaa4 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -39,14 +39,36 @@
     public String toString() {
         StringBuffer str = new StringBuffer();
 
-        str.append("ipddress "); str.append(addr.toString());
-        str.append(" netmask "); str.append(mask.toString());
+        str.append("ipddress ");
+        str.append((addr != null) ? addr.toString() : "NULL");
+        str.append(" netmask ");
+        str.append((mask != null) ? mask.toString() : "NULL");
         str.append(" flags ").append(interfaceFlags);
         str.append(" hwaddr ").append(hwAddr);
 
         return str.toString();
     }
 
+    /**
+     * This function determines if the interface is up and has a valid IP
+     * configuration (IP address has a non zero octet).
+     *
+     * Note: It is supposed to be quick and hence should not initiate
+     * any network activity
+     */
+    public boolean isActive() {
+        try {
+            if(interfaceFlags.contains("up")) {
+                for (byte b : addr.getAddress()) {
+                    if (b != 0) return true;
+                }
+            }
+        } catch (NullPointerException e) {
+            return false;
+        }
+        return false;
+    }
+
     /** Implement the Parcelable interface {@hide} */
     public int describeContents() {
         return 0;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index af7b28b..35f1c58 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -211,6 +211,12 @@
          *      {@link android.R.style#Theme_Holo}.
          * <li> The activity lifecycle has changed slightly as per
          * {@link android.app.Activity}.
+         * <li> When an application requires a permission to access on of
+         * its components (activity, receiver, service, provider), this
+         * permission is no longer enforced when the application wants to
+         * access its own component.  This means it can require a permission
+         * on a component that it does not itself hold and still access that
+         * component.
          * </ul>
          */
         public static final int HONEYCOMB = CUR_DEVELOPMENT;
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index cc95642..ec5030c 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -20,22 +20,19 @@
 
 import android.content.res.Resources;
 import android.os.storage.IMountService;
+import android.util.Log;
 
 /**
  * Provides access to environment variables.
  */
 public class Environment {
+    private static final String TAG = "Environment";
 
     private static final File ROOT_DIRECTORY
             = getDirectory("ANDROID_ROOT", "/system");
 
     private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
 
-    private static class MountServiceHolder {
-        static IMountService mSingleton = IMountService.Stub.asInterface(ServiceManager
-                .getService("mount"));
-    }
-
     private static final Object mLock = new Object();
 
     private volatile static Boolean mIsExternalStorageEmulated = null;
@@ -401,7 +398,9 @@
      */
     public static String getExternalStorageState() {
         try {
-            return MountServiceHolder.mSingleton.getVolumeState(getExternalStorageDirectory()
+            IMountService mountService = IMountService.Stub.asInterface(ServiceManager
+                    .getService("mount"));
+            return mountService.getVolumeState(getExternalStorageDirectory()
                     .toString());
         } catch (Exception rex) {
             return Environment.MEDIA_REMOVED;
@@ -417,6 +416,7 @@
      * <p>See {@link #getExternalStorageDirectory()} for more information.
      */
     public static boolean isExternalStorageRemovable() {
+        if (isExternalStorageEmulated()) return false;
         return Resources.getSystem().getBoolean(
                 com.android.internal.R.bool.config_externalStorageRemovable);
     }
@@ -433,12 +433,14 @@
                 if (mIsExternalStorageEmulated == null) {
                     boolean externalStorageEmulated;
                     try {
-                        externalStorageEmulated =
-                                MountServiceHolder.mSingleton.isExternalStorageEmulated();
+                        IMountService mountService = IMountService.Stub.asInterface(ServiceManager
+                                .getService("mount"));
+                        externalStorageEmulated = mountService.isExternalStorageEmulated();
+                        mIsExternalStorageEmulated = Boolean.valueOf(externalStorageEmulated);
                     } catch (Exception e) {
-                        externalStorageEmulated = false;
+                        Log.e(TAG, "couldn't talk to MountService", e);
+                        return false;
                     }
-                    mIsExternalStorageEmulated = Boolean.valueOf(externalStorageEmulated);
                 }
             }
         }
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 0f062cc..997ea53 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -34,6 +34,7 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -166,13 +167,19 @@
      * Note, a "VM_" bit, not thread.
      * @hide
      */
-    public static final int DETECT_VM_CURSOR_LEAKS = 0x200;  // for ProcessPolicy
+    public static final int DETECT_VM_CURSOR_LEAKS = 0x200;  // for VmPolicy
 
     /**
      * Note, a "VM_" bit, not thread.
      * @hide
      */
-    public static final int DETECT_VM_CLOSABLE_LEAKS = 0x400;  // for ProcessPolicy
+    public static final int DETECT_VM_CLOSABLE_LEAKS = 0x400;  // for VmPolicy
+
+    /**
+     * Note, a "VM_" bit, not thread.
+     * @hide
+     */
+    public static final int DETECT_VM_ACTIVITY_LEAKS = 0x800;  // for VmPolicy
 
     /**
      * @hide
@@ -232,10 +239,18 @@
             PENALTY_LOG | PENALTY_DIALOG | PENALTY_DEATH | PENALTY_DROPBOX | PENALTY_GATHER |
             PENALTY_DEATH_ON_NETWORK | PENALTY_FLASH;
 
+
+    // TODO: wrap in some ImmutableHashMap thing.
+    // Note: must be before static initialization of sVmPolicy.
+    private static final HashMap<Class, Integer> EMPTY_CLASS_LIMIT_MAP = new HashMap<Class, Integer>();
+
     /**
      * The current VmPolicy in effect.
+     *
+     * TODO: these are redundant (mask is in VmPolicy).  Should remove sVmPolicyMask.
      */
     private static volatile int sVmPolicyMask = 0;
+    private static volatile VmPolicy sVmPolicy = VmPolicy.LAX;
 
     /**
      * The number of threads trying to do an async dropbox write.
@@ -481,12 +496,19 @@
         /**
          * The default, lax policy which doesn't catch anything.
          */
-        public static final VmPolicy LAX = new VmPolicy(0);
+        public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP);
 
         final int mask;
 
-        private VmPolicy(int mask) {
+        // Map from class to max number of allowed instances in memory.
+        final HashMap<Class, Integer> classInstanceLimit;
+
+        private VmPolicy(int mask, HashMap<Class, Integer> classInstanceLimit) {
+            if (classInstanceLimit == null) {
+                throw new NullPointerException("classInstanceLimit == null");
+            }
             this.mask = mask;
+            this.classInstanceLimit = classInstanceLimit;
         }
 
         @Override
@@ -516,6 +538,49 @@
         public static final class Builder {
             private int mMask;
 
+            private HashMap<Class, Integer> mClassInstanceLimit;  // null until needed
+            private boolean mClassInstanceLimitNeedCow = false;  // need copy-on-write
+
+            public Builder() {
+                mMask = 0;
+            }
+
+            /**
+             * Build upon an existing VmPolicy.
+             */
+            public Builder(VmPolicy base) {
+                mMask = base.mask;
+                mClassInstanceLimitNeedCow = true;
+                mClassInstanceLimit = base.classInstanceLimit;
+            }
+
+            /**
+             * Set an upper bound on how many instances of a class can be in memory
+             * at once.  Helps to prevent object leaks.
+             */
+            public Builder setClassInstanceLimit(Class klass, int instanceLimit) {
+                if (klass == null) {
+                    throw new NullPointerException("klass == null");
+                }
+                if (mClassInstanceLimitNeedCow) {
+                    if (mClassInstanceLimit.containsKey(klass) &&
+                        mClassInstanceLimit.get(klass) == instanceLimit) {
+                        // no-op; don't break COW
+                        return this;
+                    }
+                    mClassInstanceLimitNeedCow = false;
+                    mClassInstanceLimit = (HashMap<Class, Integer>) mClassInstanceLimit.clone();
+                } else if (mClassInstanceLimit == null) {
+                    mClassInstanceLimit = new HashMap<Class, Integer>();
+                }
+                mClassInstanceLimit.put(klass, instanceLimit);
+                return this;
+            }
+
+            private Builder detectActivityLeaks() {
+                return enable(DETECT_VM_ACTIVITY_LEAKS);
+            }
+
             /**
              * Detect everything that's potentially suspect.
              *
@@ -524,7 +589,8 @@
              * likely expand in future releases.
              */
             public Builder detectAll() {
-                return enable(DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS);
+                return enable(DETECT_VM_ACTIVITY_LEAKS |
+                        DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS);
             }
 
             /**
@@ -598,7 +664,8 @@
                               PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) {
                     penaltyLog();
                 }
-                return new VmPolicy(mMask);
+                return new VmPolicy(mMask,
+                        mClassInstanceLimit != null ? mClassInstanceLimit : EMPTY_CLASS_LIMIT_MAP);
             }
         }
     }
@@ -829,9 +896,7 @@
         if (IS_USER_BUILD) {
             setCloseGuardEnabled(false);
         } else {
-            sVmPolicyMask = StrictMode.DETECT_VM_CURSOR_LEAKS |
-                    StrictMode.DETECT_VM_CLOSABLE_LEAKS |
-                    StrictMode.PENALTY_DROPBOX;
+            setVmPolicy(new VmPolicy.Builder().detectAll().penaltyDropBox().build());
             setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
         }
         return true;
@@ -1289,6 +1354,7 @@
      * @param policy the policy to put into place
      */
     public static void setVmPolicy(final VmPolicy policy) {
+        sVmPolicy = policy;
         sVmPolicyMask = policy.mask;
         setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
     }
@@ -1297,7 +1363,7 @@
      * Gets the current VM policy.
      */
     public static VmPolicy getVmPolicy() {
-        return new VmPolicy(sVmPolicyMask);
+        return sVmPolicy;
     }
 
     /**
@@ -1652,6 +1718,20 @@
     }
 
     /**
+     * @hide
+     */
+    public static void noteActivityClass(Class klass) {
+        if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
+            return;
+        }
+        if (sVmPolicy.classInstanceLimit.containsKey(klass)) {
+            return;
+        }
+        // Note: capping at 2, not 1, to give some breathing room.
+        setVmPolicy(new VmPolicy.Builder(sVmPolicy).setClassInstanceLimit(klass, 2).build());
+    }
+
+    /**
      * Parcelable that gets sent in Binder call headers back to callers
      * to report violations that happened during a cross-process call.
      *
diff --git a/core/java/android/os/storage/StorageEventListener.java b/core/java/android/os/storage/StorageEventListener.java
index d3d39d6d..6c73d04 100644
--- a/core/java/android/os/storage/StorageEventListener.java
+++ b/core/java/android/os/storage/StorageEventListener.java
@@ -18,6 +18,8 @@
 
 /**
  * Used for receiving notifications from the StorageManager
+ * 
+ * @hide
  */
 public abstract class StorageEventListener {
     /**
diff --git a/core/java/android/os/storage/StorageResultCode.java b/core/java/android/os/storage/StorageResultCode.java
index 07d95df..8e7db31 100644
--- a/core/java/android/os/storage/StorageResultCode.java
+++ b/core/java/android/os/storage/StorageResultCode.java
@@ -19,6 +19,8 @@
 /**
  * Class that provides access to constants returned from StorageManager
  * and lower level MountService APIs.
+ * 
+ * @hide
  */
 public class StorageResultCode
 {
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index e869f3f..7d37e5b 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -285,7 +285,7 @@
      * @see #Preference(Context, AttributeSet, int)
      */
     public Preference(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
+        this(context, attrs, com.android.internal.R.attr.preferenceStyle);
     }
 
     /**
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 7a186f3..3883451 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -1044,10 +1044,8 @@
         getFragmentManager().popBackStack(BACK_STACK_PREFS,
                 FragmentManager.POP_BACK_STACK_INCLUSIVE);
         Fragment f = Fragment.instantiate(this, fragmentName, args);
-        FragmentTransaction transaction = getFragmentManager().openTransaction();
-        transaction.setTransition(direction == 0 ? FragmentTransaction.TRANSIT_NONE
-                : direction > 0 ? FragmentTransaction.TRANSIT_FRAGMENT_NEXT
-                        : FragmentTransaction.TRANSIT_FRAGMENT_PREV);
+        FragmentTransaction transaction = getFragmentManager().beginTransaction();
+        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
         transaction.replace(com.android.internal.R.id.prefs, f);
         transaction.commit();
     }
@@ -1136,13 +1134,13 @@
      * the current fragment will be replaced.
      */
     public void startPreferenceFragment(Fragment fragment, boolean push) {
-        FragmentTransaction transaction = getFragmentManager().openTransaction();
+        FragmentTransaction transaction = getFragmentManager().beginTransaction();
         transaction.replace(com.android.internal.R.id.prefs, fragment);
         if (push) {
             transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
             transaction.addToBackStack(BACK_STACK_PREFS);
         } else {
-            transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_NEXT);
+            transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
         }
         transaction.commit();
     }
@@ -1175,7 +1173,7 @@
             if (resultTo != null) {
                 f.setTargetFragment(resultTo, resultRequestCode);
             }
-            FragmentTransaction transaction = getFragmentManager().openTransaction();
+            FragmentTransaction transaction = getFragmentManager().beginTransaction();
             transaction.replace(com.android.internal.R.id.prefs, f);
             if (titleRes != 0) {
                 transaction.setBreadCrumbTitle(titleRes);
diff --git a/core/java/android/preference/PreferenceScreen.java b/core/java/android/preference/PreferenceScreen.java
index c7f8ab2..45e3a4c 100644
--- a/core/java/android/preference/PreferenceScreen.java
+++ b/core/java/android/preference/PreferenceScreen.java
@@ -80,6 +80,8 @@
     private ListAdapter mRootAdapter;
     
     private Dialog mDialog;
+
+    private ListView mListView;
     
     /**
      * Do NOT use this constructor, use {@link PreferenceManager#createPreferenceScreen(Context)}.
@@ -146,15 +148,18 @@
     
     private void showDialog(Bundle state) {
         Context context = getContext();
-        ListView listView = new ListView(context);
-        bind(listView);
+        if (mListView != null) {
+            mListView.setAdapter(null);
+        }
+        mListView = new ListView(context);
+        bind(mListView);
 
         // Set the title bar if title is available, else no title bar
         final CharSequence title = getTitle();
         Dialog dialog = mDialog = new Dialog(context, TextUtils.isEmpty(title)
                 ? com.android.internal.R.style.Theme_NoTitleBar
                 : com.android.internal.R.style.Theme);
-        dialog.setContentView(listView);
+        dialog.setContentView(mListView);
         if (!TextUtils.isEmpty(title)) {
             dialog.setTitle(title);
         }
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index f010076..c46d2c5 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -349,19 +349,17 @@
          */
         public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId";
         /**
-         * {@hide}
          * Parameter key to specify the speech volume relative to the current stream type
          * volume used when speaking text. Volume is specified as a float ranging from 0 to 1
-         * where 0 is silence, and 1 is the maximum volume.
+         * where 0 is silence, and 1 is the maximum volume (the default behavior).
          * @see TextToSpeech#speak(String, int, HashMap)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          */
         public static final String KEY_PARAM_VOLUME = "volume";
         /**
-         * {@hide}
          * Parameter key to specify how the speech is panned from left to right when speaking text.
          * Pan is specified as a float ranging from -1 to +1 where -1 maps to a hard-left pan,
-         * 0 to center, and +1 to hard-right.
+         * 0 to center (the default behavior), and +1 to hard-right.
          * @see TextToSpeech#speak(String, int, HashMap)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          */
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 5fac525..99b686e 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -374,16 +374,18 @@
 
     @Override
     public void translate(float dx, float dy) {
-        nTranslate(mRenderer, dx, dy);
+        if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy);
     }
     
     private native void nTranslate(int renderer, float dx, float dy);
 
     @Override
     public void skew(float sx, float sy) {
-        throw new UnsupportedOperationException();
+        nSkew(mRenderer, sx, sy);
     }
 
+    private native void nSkew(int renderer, float sx, float sy);
+
     @Override
     public void rotate(float degrees) {
         nRotate(mRenderer, degrees);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index f9a6c1b..addd1b3 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -84,6 +84,13 @@
      * @return True if the initialization was successful, false otherwise.
      */
     abstract boolean initialize(SurfaceHolder holder);
+    
+    /**
+     * Updates the hardware renderer for the specified surface.
+     * 
+     * @param holder The holder for the surface to hardware accelerate.
+     */
+    abstract void updateSurface(SurfaceHolder holder);
 
     /**
      * Setup the hardware renderer for drawing. This is called for every
@@ -330,6 +337,13 @@
             }
             return false;
         }
+        
+        @Override
+        void updateSurface(SurfaceHolder holder) {
+            if (isRequested() && isEnabled()) {
+                createEglSurface(holder);
+            }
+        }
 
         abstract GLES20Canvas createCanvas();
 
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index e203355..0326a8f 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -159,6 +159,8 @@
     private Canvas mCanvas;
     @SuppressWarnings("unused")
     private int mNativeSurface;
+    @SuppressWarnings("unused")
+    private int mSurfaceGenerationId;
     private String mName;
 
     // The display metrics used to provide the pseudo canvas size for applications
@@ -308,6 +310,13 @@
      * returns false.
      */
     public native   boolean isValid();
+
+    /**
+     * @hide
+     */
+    public int getGenerationId() {
+        return mSurfaceGenerationId;
+    }
     
     /** Free all server-side state associated with this surface and
      * release this object's reference. {@hide} */
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f05ef8c..270ea76 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7905,7 +7905,16 @@
                     + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE");
         }
         
-        if (layerType == mLayerType) return;
+        if (layerType == mLayerType) {
+            if (layerType != LAYER_TYPE_NONE && paint != mLayerPaint) {
+                mLayerPaint = paint == null ? new Paint() : paint;
+                if (mParent instanceof ViewGroup) {
+                    ((ViewGroup) mParent).invalidate();
+                }
+                invalidate();
+            }
+            return;
+        }
 
         // Destroy any previous software drawing cache if needed
         switch (mLayerType) {
@@ -7931,9 +7940,11 @@
         }
 
         mLayerType = layerType;
-        mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint;
+        mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : (paint == null ? new Paint() : paint);
 
-        // TODO: Make sure we invalidate the parent's display list
+        if (mParent instanceof ViewGroup) {
+            ((ViewGroup) mParent).invalidate();
+        }
         invalidate();
     }
 
@@ -10595,13 +10606,38 @@
         private final WeakReference<View> mView;
 
         /**
-         * Construct a shadow builder object for use with the given view.
-         * @param view
+         * Construct a shadow builder object for use with the given View object.  The
+         * default implementation will construct a drag shadow the same size and
+         * appearance as the supplied View.
+         *
+         * @param view A view within the application's layout whose appearance
+         *        should be replicated as the drag shadow.
          */
         public DragShadowBuilder(View view) {
             mView = new WeakReference<View>(view);
         }
 
+        /**
+         * Construct a shadow builder object with no associated View.  This
+         * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)}
+         * and {@link #onDrawShadow(Canvas)} methods are also overridden in order
+         * to supply the drag shadow's dimensions and appearance without
+         * reference to any View object.
+         */
+        public DragShadowBuilder() {
+            mView = new WeakReference<View>(null);
+        }
+
+        /**
+         * Returns the View object that had been passed to the
+         * {@link #View.DragShadowBuilder(View)}
+         * constructor.  If that View parameter was {@code null} or if the
+         * {@link #View.DragShadowBuilder()}
+         * constructor was used to instantiate the builder object, this method will return
+         * null.
+         *
+         * @return The View object associate with this builder object.
+         */
         final public View getView() {
             return mView.get();
         }
@@ -10612,8 +10648,10 @@
          * be centered under the touch location while dragging.
          * <p>
          * The default implementation sets the dimensions of the shadow to be the
-         * same as the dimensions of the View itself and centers the shadow under
-         * the touch point.
+         * same as the dimensions of the View object that had been supplied to the
+         * {@link #View.DragShadowBuilder(View)} constructor
+         * when the builder object was instantiated, and centers the shadow under the touch
+         * point.
          *
          * @param shadowSize The application should set the {@code x} member of this
          *        parameter to the desired shadow width, and the {@code y} member to
@@ -10636,6 +10674,11 @@
          * Draw the shadow image for the upcoming drag.  The shadow canvas was
          * created with the dimensions supplied by the
          * {@link #onProvideShadowMetrics(Point, Point)} callback.
+         * <p>
+         * The default implementation replicates the appearance of the View object
+         * that had been supplied to the
+         * {@link #View.DragShadowBuilder(View)}
+         * constructor when the builder object was instantiated.
          *
          * @param canvas
          */
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index f6b6778..d1781cc 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2398,16 +2398,15 @@
                                 layerType != LAYER_TYPE_NONE) {
                             layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
                         }
-                        if (layerType != LAYER_TYPE_NONE && child.mLayerPaint != null) {
+                        if (layerType != LAYER_TYPE_NONE) {
                             child.mLayerPaint.setAlpha(multipliedAlpha);
                         } else {
                             canvas.saveLayerAlpha(sx, sy, sx + cr - cl, sy + cb - ct,
                                     multipliedAlpha, layerFlags);
-                            layerSaved = true;
                         }
                     } else {
                         // Alpha is handled by the child directly, clobber the layer's alpha
-                        if (layerType != LAYER_TYPE_NONE && child.mLayerPaint != null) {
+                        if (layerType != LAYER_TYPE_NONE) {
                             child.mLayerPaint.setAlpha(255);
                         }
                         child.mPrivateFlags |= ALPHA_SET;
@@ -2433,7 +2432,7 @@
 
         if (hasNoCache) {
             boolean layerRendered = false;
-            if (!layerSaved && layerType == LAYER_TYPE_HARDWARE) {
+            if (layerType == LAYER_TYPE_HARDWARE) {
                 final HardwareLayer layer = child.getHardwareLayer(canvas);
                 if (layer != null && layer.isValid()) {
                     ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, child.mLayerPaint);
@@ -2465,7 +2464,7 @@
             child.mPrivateFlags &= ~DIRTY_MASK;
             Paint cachePaint;
 
-            if (layerType == LAYER_TYPE_NONE || child.mLayerPaint == null) {
+            if (layerType == LAYER_TYPE_NONE) {
                 cachePaint = mCachePaint;
                 if (alpha < 1.0f) {
                     cachePaint.setAlpha((int) (alpha * 255));
@@ -2476,9 +2475,7 @@
                 }
             } else {
                 cachePaint = child.mLayerPaint;
-                if (alpha < 1.0f) {
-                    cachePaint.setAlpha((int) (alpha * 255));
-                }
+                cachePaint.setAlpha((int) (alpha * 255));
             }
             canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
         }
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 96f8cdc..961b633 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -983,6 +983,8 @@
                     Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
                             host.getMeasuredHeight() + ", params=" + params);
                 }
+
+                final int surfaceGenerationId = mSurface.getGenerationId();
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
 
                 if (params != null) {
@@ -1043,6 +1045,9 @@
                         mScroller.abortAnimation();
                     }
                     disposeResizeBitmap();
+                } else if (surfaceGenerationId != mSurface.getGenerationId() &&
+                        mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
+                    mAttachInfo.mHardwareRenderer.updateSurface(mHolder);
                 }
             } catch (RemoteException e) {
             }
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 2f27935..217e731 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -116,6 +116,8 @@
     private Window mActiveChild;
     private boolean mIsActive = false;
     private boolean mHasChildren = false;
+    private boolean mCloseOnTouchOutside = false;
+    private boolean mSetCloseOnTouchOutside = false;
     private int mForcedWindowFlags = 0;
 
     private int mFeatures = DEFAULT_FEATURES;
@@ -786,6 +788,42 @@
         return mHasSoftInputMode;
     }
     
+    /** @hide */
+    public void setCloseOnTouchOutside(boolean close) {
+        mCloseOnTouchOutside = close;
+        mSetCloseOnTouchOutside = true;
+    }
+    
+    /** @hide */
+    public void setCloseOnTouchOutsideIfNotSet(boolean close) {
+        if (!mSetCloseOnTouchOutside) {
+            mCloseOnTouchOutside = close;
+            mSetCloseOnTouchOutside = true;
+        }
+    }
+    
+    /** @hide */
+    public abstract void alwaysReadCloseOnTouchAttr();
+    
+    /** @hide */
+    public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
+        if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
+                && isOutOfBounds(context, event) && peekDecorView() != null) {
+            return true;
+        }
+        return false;
+    }
+    
+    private boolean isOutOfBounds(Context context, MotionEvent event) {
+        final int x = (int) event.getX();
+        final int y = (int) event.getY();
+        final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
+        final View decorView = getDecorView();
+        return (x < -slop) || (y < -slop)
+                || (x > (decorView.getWidth()+slop))
+                || (y > (decorView.getHeight()+slop));
+    }
+    
     /**
      * Enable extended screen features.  This must be called before
      * setContentView().  May be called as many times as desired as long as it
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 85bff4f..d8f34e0 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -495,6 +495,7 @@
                         break;
                     }
                     case ENDED:
+                        mSeekPosition = 0;
                         nativeOnEnded(mNativePointer);
                         break;
                     case PAUSED:
@@ -538,10 +539,15 @@
      * Play a video stream.
      * @param url is the URL of the video stream.
      */
-    public void play(String url) {
+    public void play(String url, int position) {
         if (url == null) {
             return;
         }
+
+        if (position > 0) {
+            seek(position);
+        }
+
         Message message = obtainMessage(PLAY);
         message.obj = url;
         sendMessage(message);
diff --git a/core/java/android/webkit/WebIconDatabase.java b/core/java/android/webkit/WebIconDatabase.java
index bb9ec48..54dfab3 100644
--- a/core/java/android/webkit/WebIconDatabase.java
+++ b/core/java/android/webkit/WebIconDatabase.java
@@ -24,6 +24,7 @@
 import android.provider.Browser;
 import android.util.Log;
 
+import java.io.File;
 import java.util.HashMap;
 import java.util.Vector;
 
@@ -194,13 +195,16 @@
     /**
      * Open a the icon database and store the icons in the given path.
      * @param path The directory path where the icon database will be stored.
-     * @return True if the database was successfully opened or created in
-     *         the given path.
      */
     public void open(String path) {
         if (path != null) {
+            // Make the directories and parents if they don't exist
+            File db = new File(path);
+            if (!db.exists()) {
+                db.mkdirs();
+            }
             mEventHandler.postMessage(
-                    Message.obtain(null, EventHandler.OPEN, path));
+                    Message.obtain(null, EventHandler.OPEN, db.getAbsolutePath()));
         }
     }
 
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 0670c4e..518ba69 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1569,6 +1569,7 @@
     public void setCacheMode(int mode) {
         if (mode != mOverrideCacheMode) {
             mOverrideCacheMode = mode;
+            postSync();
         }
     }
 
@@ -1629,6 +1630,11 @@
     /* package */ synchronized void setPrivateBrowsingEnabled(boolean flag) {
         if (mPrivateBrowsingEnabled != flag) {
             mPrivateBrowsingEnabled = flag;
+
+            // AutoFill is dependant on private browsing being enabled so
+            // reset it to take account of the new value of mPrivateBrowsingEnabled.
+            setAutoFillEnabled(mAutoFillEnabled);
+
             postSync();
         }
     }
@@ -1644,8 +1650,10 @@
      * @hide
      */
     public synchronized void setAutoFillEnabled(boolean enabled) {
-        if (mAutoFillEnabled != enabled) {
-            mAutoFillEnabled = enabled;
+        // AutoFill is always disabled in private browsing mode.
+        boolean autoFillEnabled = enabled && !mPrivateBrowsingEnabled;
+        if (mAutoFillEnabled != autoFillEnabled) {
+            mAutoFillEnabled = autoFillEnabled;
             postSync();
         }
     }
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 5345879..257ed2a 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -75,23 +75,23 @@
     private Handler mHandler = null;
     private Handler mUIHandler = null;
 
-    static class Origin {
-        String mOrigin = null;
-        long mQuota = 0;
-        long mUsage = 0;
+    public static class Origin {
+        private String mOrigin = null;
+        private long mQuota = 0;
+        private long mUsage = 0;
 
-        public Origin(String origin, long quota, long usage) {
+        private Origin(String origin, long quota, long usage) {
             mOrigin = origin;
             mQuota = quota;
             mUsage = usage;
         }
 
-        public Origin(String origin, long quota) {
+        private Origin(String origin, long quota) {
             mOrigin = origin;
             mQuota = quota;
         }
 
-        public Origin(String origin) {
+        private Origin(String origin) {
             mOrigin = origin;
         }
 
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 1313fcc..72b0023 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -132,6 +132,10 @@
     private boolean mAutoFillable; // Is this textview part of an autofillable form?
     private int mQueryId;
     private boolean mAutoFillProfileIsSet;
+    // Used to determine whether onFocusChanged was called as a result of
+    // calling remove().
+    private boolean mInsideRemove;
+    private boolean mInPassword;
 
     // Types used with setType.  Keep in sync with CachedInput.h
     private static final int NORMAL_TEXT_FIELD = 0;
@@ -540,6 +544,11 @@
             Rect previouslyFocusedRect) {
         mFromFocusChange = true;
         super.onFocusChanged(focused, direction, previouslyFocusedRect);
+        if (focused) {
+            mWebView.setActive(true);
+        } else if (!mInsideRemove) {
+            mWebView.setActive(false);
+        }
         mFromFocusChange = false;
     }
 
@@ -770,26 +779,17 @@
         if (imm.isActive(this)) {
             imm.hideSoftInputFromWindow(getWindowToken(), 0);
         }
+        mInsideRemove = true;
         mWebView.removeView(this);
         mWebView.requestFocus();
-    }
-
-    /**
-     * Move the caret/selection into view.
-     */
-    /* package */ void bringIntoView() {
-        bringPointIntoView(Selection.getSelectionEnd(getText()));
+        mInsideRemove = false;
     }
 
     @Override
     public boolean bringPointIntoView(int offset) {
-        if (mWebView == null) return false;
-        if (mWebView.nativeFocusCandidateIsPassword()) {
+        if (mInPassword) {
             return getLayout() != null && super.bringPointIntoView(offset);
         }
-        // For non password text input, tell webkit to move the caret/selection
-        // on screen, since webkit draws them.
-        mWebView.revealSelection();
         return true;
     }
 
@@ -904,6 +904,7 @@
      * @param   inPassword  True if the textfield is a password field.
      */
     /* package */ void setInPassword(boolean inPassword) {
+        mInPassword = inPassword;
         if (inPassword) {
             setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.
                 TYPE_TEXT_VARIATION_WEB_PASSWORD);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index eddfffe..9e09c28 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1037,7 +1037,7 @@
         String host = proxyProperties.getHost();
         int port = proxyProperties.getPort();
         if (port != 0)
-            host += ": " + port;
+            host += ":" + port;
 
         // TODO: Handle exclusion list
         // The plan is to make an AndroidProxyResolver, and handle the blacklist
@@ -4268,7 +4268,7 @@
         Rect vBox = contentToViewRect(bounds);
         mWebTextView.setRect(vBox.left, vBox.top, vBox.width(), vBox.height());
         if (!Rect.intersects(bounds, visibleRect)) {
-            mWebTextView.bringIntoView();
+            revealSelection();
         }
         String text = nativeFocusCandidateText();
         int nodePointer = nativeFocusCandidatePointer();
@@ -5050,7 +5050,7 @@
     public void onGlobalFocusChanged(View oldFocus, View newFocus) {
     }
 
-    private void setActive(boolean active) {
+    void setActive(boolean active) {
         if (active) {
             if (hasFocus()) {
                 // If our window regained focus, and we have focus, then begin
@@ -6723,43 +6723,60 @@
         }
     }
 
-    /*
-     * Return true if the view (Plugin) is fully visible and maximized inside
-     * the WebView.
+    /**
+     * Returns plugin bounds if x/y in content coordinates corresponds to a
+     * plugin. Otherwise a NULL rectangle is returned.
      */
-    boolean isPluginFitOnScreen(ViewManager.ChildView view) {
+    Rect getPluginBounds(int x, int y) {
+        if (nativePointInNavCache(x, y, mNavSlop) && nativeCacheHitIsPlugin()) {
+            return nativeCacheHitNodeBounds();
+        } else {
+            return null;
+        }
+    }
+
+    /*
+     * Return true if the rect (e.g. plugin) is fully visible and maximized
+     * inside the WebView.
+     */
+    boolean isRectFitOnScreen(Rect rect) {
+        final int rectWidth = rect.width();
+        final int rectHeight = rect.height();
         final int viewWidth = getViewWidth();
         final int viewHeight = getViewHeightWithTitle();
-        float scale = Math.min((float) viewWidth / view.width, (float) viewHeight / view.height);
+        float scale = Math.min((float) viewWidth / rectWidth, (float) viewHeight / rectHeight);
         scale = mZoomManager.computeScaleWithLimits(scale);
         return !mZoomManager.willScaleTriggerZoom(scale)
-                && contentToViewX(view.x) >= mScrollX
-                && contentToViewX(view.x + view.width) <= mScrollX + viewWidth
-                && contentToViewY(view.y) >= mScrollY
-                && contentToViewY(view.y + view.height) <= mScrollY + viewHeight;
+                && contentToViewX(rect.left) >= mScrollX
+                && contentToViewX(rect.right) <= mScrollX + viewWidth
+                && contentToViewY(rect.top) >= mScrollY
+                && contentToViewY(rect.bottom) <= mScrollY + viewHeight;
     }
 
     /*
      * Maximize and center the rectangle, specified in the document coordinate
      * space, inside the WebView. If the zoom doesn't need to be changed, do an
      * animated scroll to center it. If the zoom needs to be changed, find the
-     * zoom center and do a smooth zoom transition.
+     * zoom center and do a smooth zoom transition. The rect is in document
+     * coordinates
      */
-    void centerFitRect(int docX, int docY, int docWidth, int docHeight) {
-        int viewWidth = getViewWidth();
-        int viewHeight = getViewHeightWithTitle();
-        float scale = Math.min((float) viewWidth / docWidth, (float) viewHeight
-                / docHeight);
+    void centerFitRect(Rect rect) {
+        final int rectWidth = rect.width();
+        final int rectHeight = rect.height();
+        final int viewWidth = getViewWidth();
+        final int viewHeight = getViewHeightWithTitle();
+        float scale = Math.min((float) viewWidth / rectWidth, (float) viewHeight
+                / rectHeight);
         scale = mZoomManager.computeScaleWithLimits(scale);
         if (!mZoomManager.willScaleTriggerZoom(scale)) {
-            pinScrollTo(contentToViewX(docX + docWidth / 2) - viewWidth / 2,
-                    contentToViewY(docY + docHeight / 2) - viewHeight / 2,
+            pinScrollTo(contentToViewX(rect.left + rectWidth / 2) - viewWidth / 2,
+                    contentToViewY(rect.top + rectHeight / 2) - viewHeight / 2,
                     true, 0);
         } else {
             float actualScale = mZoomManager.getScale();
-            float oldScreenX = docX * actualScale - mScrollX;
-            float rectViewX = docX * scale;
-            float rectViewWidth = docWidth * scale;
+            float oldScreenX = rect.left * actualScale - mScrollX;
+            float rectViewX = rect.left * scale;
+            float rectViewWidth = rectWidth * scale;
             float newMaxWidth = mContentWidth * scale;
             float newScreenX = (viewWidth - rectViewWidth) / 2;
             // pin the newX to the WebView
@@ -6770,10 +6787,10 @@
             }
             float zoomCenterX = (oldScreenX * scale - newScreenX * actualScale)
                     / (scale - actualScale);
-            float oldScreenY = docY * actualScale + getTitleHeight()
+            float oldScreenY = rect.top * actualScale + getTitleHeight()
                     - mScrollY;
-            float rectViewY = docY * scale + getTitleHeight();
-            float rectViewHeight = docHeight * scale;
+            float rectViewY = rect.top * scale + getTitleHeight();
+            float rectViewHeight = rectHeight * scale;
             float newMaxHeight = mContentHeight * scale + getTitleHeight();
             float newScreenY = (viewHeight - rectViewHeight) / 2;
             // pin the newY to the WebView
@@ -7257,7 +7274,6 @@
                     // this is sent after finishing resize in WebViewCore. Make
                     // sure the text edit box is still on the  screen.
                     if (inEditingMode() && nativeCursorIsTextInput()) {
-                        mWebTextView.bringIntoView();
                         rebuildWebTextView();
                     }
                     break;
@@ -7506,8 +7522,7 @@
                     break;
 
                 case CENTER_FIT_RECT:
-                    Rect r = (Rect)msg.obj;
-                    centerFitRect(r.left, r.top, r.width(), r.height());
+                    centerFitRect((Rect)msg.obj);
                     break;
 
                 case SET_SCROLLBAR_MODES:
@@ -8150,6 +8165,7 @@
     }
 
     private native int nativeCacheHitFramePointer();
+    private native boolean  nativeCacheHitIsPlugin();
     private native Rect nativeCacheHitNodeBounds();
     private native int nativeCacheHitNodePointer();
     /* package */ native void nativeClearCursor();
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index b4a33de..9a050c5 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -20,6 +20,7 @@
 import android.content.pm.PackageManager;
 import android.graphics.Canvas;
 import android.graphics.Point;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.util.Log;
@@ -147,13 +148,13 @@
      */
     private float mInitialScale;
 
-    private static float MINIMUM_SCALE_INCREMENT = 0.01f;
+    private static float MINIMUM_SCALE_INCREMENT = 0.007f;
 
     /*
      *  The touch points could be changed even the fingers stop moving.
      *  We use the following to filter out the zooming jitters.
      */
-    private static float MINIMUM_SCALE_WITHOUT_JITTER = 0.05f;
+    private static float MINIMUM_SCALE_WITHOUT_JITTER = 0.007f;
 
     /*
      * The following member variables are only to be used for animating zoom. If
@@ -551,12 +552,12 @@
          * If the double tap was on a plugin then either zoom to maximize the
          * plugin on the screen or scale to overview mode.
          */
-        ViewManager.ChildView plugin = mWebView.mViewManager.hitTest(mAnchorX, mAnchorY);
-        if (plugin != null) {
-            if (mWebView.isPluginFitOnScreen(plugin)) {
+        Rect pluginBounds = mWebView.getPluginBounds(mAnchorX, mAnchorY);
+        if (pluginBounds != null) {
+            if (mWebView.isRectFitOnScreen(pluginBounds)) {
                 zoomToOverview();
             } else {
-                mWebView.centerFitRect(plugin.x, plugin.y, plugin.width, plugin.height);
+                mWebView.centerFitRect(pluginBounds);
             }
             return;
         }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 7631df4..a65de13 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2439,8 +2439,12 @@
             if (adapter != null && mItemCount > 0 &&
                     motionPosition != INVALID_POSITION &&
                     motionPosition < adapter.getCount() && sameWindow()) {
-                performItemClick(getChildAt(motionPosition - mFirstPosition), motionPosition,
-                        adapter.getItemId(motionPosition));
+                final View view = getChildAt(motionPosition - mFirstPosition);
+                // If there is no view, something bad happened (the view scrolled off the
+                // screen, etc.) and we should cancel the click
+                if (view != null) {
+                    performItemClick(view, motionPosition, adapter.getItemId(motionPosition));
+                }
             }
         }
     }
@@ -2642,6 +2646,7 @@
                         setPressed(true);
                         layoutChildren();
                         positionSelector(mMotionPosition, child);
+                        refreshDrawableState();
 
                         final int longPressTimeout = ViewConfiguration.getLongPressTimeout();
                         final boolean longClickable = isLongClickable();
@@ -5314,6 +5319,24 @@
         mRecycler.mRecyclerListener = listener;
     }
 
+    class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
+        @Override
+        public void onChanged() {
+            super.onChanged();
+            if (mFastScroller != null) {
+                mFastScroller.onSectionsChanged();
+            }
+        }
+
+        @Override
+        public void onInvalidated() {
+            super.onInvalidated();
+            if (mFastScroller != null) {
+                mFastScroller.onSectionsChanged();
+            }
+        }
+    }
+
     /**
      * A MultiChoiceModeListener receives events for {@link AbsListView#CHOICE_MODE_MULTIPLE_MODAL}.
      * It acts as the {@link ActionMode.Callback} for the selection mode and also receives
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index dbcf1e9..2c53005 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -46,8 +46,8 @@
  * displayed. Also the minimal and maximal date from which dates to be selected
  * can be customized.
  * <p>
- * See the <a href="{@docRoot}
- * resources/tutorials/views/hello-datepicker.html">Date Picker tutorial</a>.
+ * See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date
+ * Picker tutorial</a>.
  * </p>
  * <p>
  * For a dialog using this view, see {@link android.app.DatePickerDialog}.
@@ -471,6 +471,8 @@
      */
     public void init(int year, int monthOfYear, int dayOfMonth,
             OnDateChangedListener onDateChangedListener) {
+        // make sure there is no callback
+        mOnDateChangedListener = null;
         updateDate(year, monthOfYear, dayOfMonth);
         // register the callback after updating the date
         mOnDateChangedListener = onDateChangedListener;
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index 472a335..8279ee5 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -211,7 +211,7 @@
                 .getDimensionPixelSize(com.android.internal.R.styleable.ExpandableListView_indicatorLeft, 0);
         mIndicatorRight = a
                 .getDimensionPixelSize(com.android.internal.R.styleable.ExpandableListView_indicatorRight, 0);
-        if (mIndicatorRight == 0) {
+        if (mIndicatorRight == 0 && mGroupIndicator != null) {
             mIndicatorRight = mIndicatorLeft + mGroupIndicator.getIntrinsicWidth();
         }
         mChildIndicatorLeft = a.getDimensionPixelSize(
@@ -1022,8 +1022,11 @@
      */
     public void setGroupIndicator(Drawable groupIndicator) {
         mGroupIndicator = groupIndicator;
+        if (mIndicatorRight == 0 && mGroupIndicator != null) {
+            mIndicatorRight = mIndicatorLeft + mGroupIndicator.getIntrinsicWidth();
+        }
     }
-    
+
     /**
      * Sets the drawing bounds for the indicators (at minimum, the group indicator
      * is affected by this; the child indicator is affected by this if the
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index dfa94c7..200c870 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -476,6 +476,10 @@
         }
     }
 
+    public void onSectionsChanged() {
+        mListAdapter = null;
+    }
+
     private void scrollTo(float position) {
         int count = mList.getCount();
         mScrollCompleted = false;
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index ba46a3f..63dbfbf 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -754,7 +754,7 @@
             return;
         }
         mCurrentScrollOffset += y;
-        while (mCurrentScrollOffset - mInitialScrollOffset > mSelectorElementHeight) {
+        while (mCurrentScrollOffset - mInitialScrollOffset >= mSelectorElementHeight) {
             mCurrentScrollOffset -= mSelectorElementHeight;
             decrementSelectorIndices(selectorIndices);
             changeCurrent(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX]);
@@ -762,7 +762,7 @@
                 mCurrentScrollOffset = mInitialScrollOffset;
             }
         }
-        while (mCurrentScrollOffset - mInitialScrollOffset < -mSelectorElementHeight) {
+        while (mCurrentScrollOffset - mInitialScrollOffset <= -mSelectorElementHeight) {
             mCurrentScrollOffset += mSelectorElementHeight;
             incrementScrollSelectorIndices(selectorIndices);
             changeCurrent(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX]);
@@ -1147,8 +1147,8 @@
             postAdjustScrollerCommand(0);
             tryNotifyScrollListener(OnScrollListener.SCROLL_STATE_IDLE);
         } else {
-            showInputControls();
             updateInputTextView();
+            showInputControls();
         }
     }
 
@@ -1537,8 +1537,8 @@
         public void run() {
             mPreviousScrollerY = 0;
             if (mInitialScrollOffset == mCurrentScrollOffset) {
-                showInputControls();
                 updateInputTextView();
+                showInputControls();
                 return;
             }
             // adjust to the closest value
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 24165aa..c336ccb 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -59,6 +59,12 @@
     private static final String LOG_TAG = "RemoteViews";
     
     /**
+     * The intent extra that contains the appWidgetId.
+     * @hide
+     */
+    static final String EXTRA_REMOTEADAPTER_APPWIDGET_ID = "remoteAdapterAppWidgetId";
+
+    /**
      * The package name of the package containing the layout 
      * resource. (Added to the parcel)
      */
@@ -796,18 +802,21 @@
                     if (this.value != null) {
                         final Bitmap b = (Bitmap) this.value;
                         final Bitmap.Config c = b.getConfig();
+                        // If we don't know, be pessimistic and assume 4
                         int bpp = 4;
-                        switch (c) {
-                        case ALPHA_8:
-                            bpp = 1;
-                            break;
-                        case RGB_565:
-                        case ARGB_4444:
-                            bpp = 2;
-                            break;
-                        case ARGB_8888:
-                            bpp = 4;
-                            break;
+                        if (c != null) {
+                            switch (c) {
+                            case ALPHA_8:
+                                bpp = 1;
+                                break;
+                            case RGB_565:
+                            case ARGB_4444:
+                                bpp = 2;
+                                break;
+                            case ARGB_8888:
+                                bpp = 4;
+                                break;
+                            }
                         }
                         counter.bitmapIncrement(b.getWidth() * b.getHeight() * bpp);
                     }
@@ -1273,6 +1282,22 @@
      *            providing data to the RemoteViewsAdapter
      */
     public void setRemoteAdapter(int viewId, Intent intent) {
+        // Do nothing.  This method will be removed after all widgets have been updated to the
+        // new API.
+    }
+
+    /**
+     * Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}.
+     *
+     * @param appWidgetId The id of the app widget which contains the specified view
+     * @param viewId The id of the view whose text should change
+     * @param intent The intent of the service which will be
+     *            providing data to the RemoteViewsAdapter
+     */
+    public void setRemoteAdapter(int appWidgetId, int viewId, Intent intent) {
+        // Embed the AppWidget Id for use in RemoteViewsAdapter when connecting to the intent
+        // RemoteViewsService
+        intent.putExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID, appWidgetId);
         setIntent(viewId, "setRemoteViewsAdapter", intent);
     }
 
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index df1f4bf..f329a3e 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -22,20 +22,21 @@
 import java.util.LinkedList;
 import java.util.Map;
 
-import android.content.ComponentName;
+import android.appwidget.AppWidgetManager;
 import android.content.Context;
 import android.content.Intent;
-import android.content.ServiceConnection;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.Message;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
+import android.view.View.MeasureSpec;
 
+import com.android.internal.widget.IRemoteViewsAdapterConnection;
 import com.android.internal.widget.IRemoteViewsFactory;
 
 /**
@@ -43,11 +44,22 @@
  * to be later inflated as child views.
  */
 /** @hide */
-public class RemoteViewsAdapter extends BaseAdapter {
+public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback {
     private static final String TAG = "RemoteViewsAdapter";
 
-    private Context mContext;
-    private Intent mIntent;
+    // The max number of items in the cache
+    private static final int sDefaultCacheSize = 36;
+    // The delay (in millis) to wait until attempting to unbind from a service after a request.
+    // This ensures that we don't stay continually bound to the service and that it can be destroyed
+    // if we need the memory elsewhere in the system.
+    private static final int sUnbindServiceDelay = 5000;
+    // Type defs for controlling different messages across the main and worker message queues
+    private static final int sDefaultMessageType = 0;
+    private static final int sUnbindServiceMessageType = 1;
+
+    private final Context mContext;
+    private final Intent mIntent;
+    private final int mAppWidgetId;
     private LayoutInflater mLayoutInflater;
     private RemoteViewsAdapterServiceConnection mServiceConnection;
     private WeakReference<RemoteAdapterConnectionCallback> mCallback;
@@ -79,7 +91,8 @@
      * garbage collected, and would cause us to leak activities due to the caching mechanism for
      * FrameLayouts in the adapter).
      */
-    private static class RemoteViewsAdapterServiceConnection implements ServiceConnection {
+    private static class RemoteViewsAdapterServiceConnection extends
+            IRemoteViewsAdapterConnection.Stub {
         private boolean mConnected;
         private WeakReference<RemoteViewsAdapter> mAdapter;
         private IRemoteViewsFactory mRemoteViewsFactory;
@@ -88,8 +101,7 @@
             mAdapter = new WeakReference<RemoteViewsAdapter>(adapter);
         }
 
-        public void onServiceConnected(ComponentName name,
-                IBinder service) {
+        public void onServiceConnected(IBinder service) {
             mRemoteViewsFactory = IRemoteViewsFactory.Stub.asInterface(service);
             mConnected = true;
 
@@ -137,7 +149,7 @@
             });
         }
 
-        public void onServiceDisconnected(ComponentName name) {
+        public void onServiceDisconnected() {
             mConnected = false;
             mRemoteViewsFactory = null;
 
@@ -145,8 +157,9 @@
             if (adapter == null) return;
             
             // Clear the main/worker queues
-            adapter.mMainQueue.removeMessages(0);
-            adapter.mWorkerQueue.removeMessages(0);
+            adapter.mMainQueue.removeMessages(sUnbindServiceMessageType);
+            adapter.mMainQueue.removeMessages(sDefaultMessageType);
+            adapter.mWorkerQueue.removeMessages(sDefaultMessageType);
 
             final RemoteAdapterConnectionCallback callback = adapter.mCallback.get();
             if (callback != null) {
@@ -574,20 +587,26 @@
     public RemoteViewsAdapter(Context context, Intent intent, RemoteAdapterConnectionCallback callback) {
         mContext = context;
         mIntent = intent;
+        mAppWidgetId = intent.getIntExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1);
         mLayoutInflater = LayoutInflater.from(context);
         if (mIntent == null) {
             throw new IllegalArgumentException("Non-null Intent must be specified.");
         }
         mRequestedViews = new RemoteViewsFrameLayoutRefSet();
 
-        // initialize the worker thread
+        // Strip the previously injected app widget id from service intent
+        if (intent.hasExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID)) {
+            intent.removeExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID);
+        }
+
+        // Initialize the worker thread
         mWorkerThread = new HandlerThread("RemoteViewsCache-loader");
         mWorkerThread.start();
         mWorkerQueue = new Handler(mWorkerThread.getLooper());
-        mMainQueue = new Handler(Looper.myLooper());
+        mMainQueue = new Handler(Looper.myLooper(), this);
 
-        // initialize the cache and the service connection on startup
-        mCache = new FixedSizeRemoteViewsCache(50);
+        // Initialize the cache and the service connection on startup
+        mCache = new FixedSizeRemoteViewsCache(sDefaultCacheSize);
         mCallback = new WeakReference<RemoteAdapterConnectionCallback>(callback);
         mServiceConnection = new RemoteViewsAdapterServiceConnection(this);
         requestBindService();
@@ -687,6 +706,7 @@
                     @Override
                     public void run() {
                         mRequestedViews.notifyOnRemoteViewsLoaded(position, rv, typeId);
+                        enqueueDeferredUnbindServiceMessage();
                     }
                 });
             }
@@ -760,11 +780,12 @@
             synchronized (mCache) {
                 // Queue up other indices to be preloaded based on this position
                 mCache.queuePositionsToBePreloadedFromRequestedPosition(position);
-
-                RemoteViewsFrameLayout layout = (RemoteViewsFrameLayout) convertView;
                 View convertViewChild = null;
                 int convertViewTypeId = 0;
-                if (convertView != null) {
+                RemoteViewsFrameLayout layout = null;
+
+                if (convertView instanceof RemoteViewsFrameLayout) {
+                    layout = (RemoteViewsFrameLayout) convertView;
                     convertViewChild = layout.getChildAt(0);
                     convertViewTypeId = getConvertViewTypeId(convertViewChild);
                 }
@@ -777,17 +798,17 @@
                     int typeId = mCache.getMetaDataAt(position).typeId;
 
                     // Reuse the convert view where possible
-                    if (convertView != null) {
+                    if (layout != null) {
                         if (convertViewTypeId == typeId) {
                             rv.reapply(context, convertViewChild);
-                            return convertView;
+                            return layout;
                         }
                     }
 
                     // Otherwise, create a new view to be returned
                     View newView = rv.apply(context, parent);
                     newView.setTagInternal(com.android.internal.R.id.rowTypeId, new Integer(typeId));
-                    if (convertView != null) {
+                    if (layout != null) {
                         layout.removeAllViews();
                     } else {
                         layout = new RemoteViewsFrameLayout(context);
@@ -878,10 +899,36 @@
         super.notifyDataSetChanged();
     }
 
+    @Override
+    public boolean handleMessage(Message msg) {
+        boolean result = false;
+        switch (msg.what) {
+        case sUnbindServiceMessageType:
+            final AppWidgetManager mgr = AppWidgetManager.getInstance(mContext);
+            if (mServiceConnection.isConnected()) {
+                mgr.unbindRemoteViewsService(mAppWidgetId, mIntent);
+            }
+            result = true;
+            break;
+        default:
+            break;
+        }
+        return result;
+    }
+
+    private void enqueueDeferredUnbindServiceMessage() {
+        /* Temporarily disable delayed service unbinding
+        // Remove any existing deferred-unbind messages
+        mMainQueue.removeMessages(sUnbindServiceMessageType);
+        mMainQueue.sendEmptyMessageDelayed(sUnbindServiceMessageType, sUnbindServiceDelay);
+        */
+    }
+
     private boolean requestBindService() {
-        // try binding the service (which will start it if it's not already running)
+        // Try binding the service (which will start it if it's not already running)
         if (!mServiceConnection.isConnected()) {
-            mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+            final AppWidgetManager mgr = AppWidgetManager.getInstance(mContext);
+            mgr.bindRemoteViewsService(mAppWidgetId, mIntent, mServiceConnection.asBinder());
         }
 
         return mServiceConnection.isConnected();
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 0102628..0baddcb 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -23,6 +23,8 @@
 import android.content.DialogInterface.OnClickListener;
 import android.content.res.TypedArray;
 import android.database.DataSetObserver;
+import android.graphics.drawable.Drawable;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.view.Gravity;
@@ -632,7 +634,8 @@
     private class DropdownPopup extends ListPopupWindow implements SpinnerPopup {
         private CharSequence mHintText;
         private int mPopupMaxWidth;
-        
+        private Rect mTempRect = new Rect();
+
         public DropdownPopup(Context context, AttributeSet attrs, int defStyleRes) {
             super(context, attrs, 0, defStyleRes);
             
@@ -699,6 +702,14 @@
                 itemView.measure(widthMeasureSpec, heightMeasureSpec);
                 width = Math.max(width, itemView.getMeasuredWidth());
             }
+
+            // Add background padding to measured width
+            Drawable popupBackground = getBackground();
+            if (popupBackground != null) {
+                popupBackground.getPadding(mTempRect);
+                width += mTempRect.left + mTempRect.right;
+            }
+
             return width;
         }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 623cd41..1895d79 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7931,9 +7931,6 @@
             max = Math.max(0, Math.max(selStart, selEnd));
         }
 
-        ClipboardManager clipboard = (ClipboardManager)getContext()
-                .getSystemService(Context.CLIPBOARD_SERVICE);
-
         switch (id) {
             case ID_COPY_URL:
                 URLSpan[] urls = ((Spanned) mText).getSpans(min, max, URLSpan.class);
@@ -7942,7 +7939,7 @@
                     for (int i=0; i<urls.length; i++) {
                         Uri uri = Uri.parse(urls[0].getURL());
                         if (clip == null) {
-                            clip = ClipData.newRawUri(null, null, uri);
+                            clip = ClipData.newRawUri(null, uri);
                         } else {
                             clip.addItem(new ClipData.Item(uri));
                         }
@@ -7976,15 +7973,13 @@
                 return true;
 
             case ID_CUT:
-                setPrimaryClip(ClipData.newPlainText(null, null,
-                        mTransformed.subSequence(min, max)));
+                setPrimaryClip(ClipData.newPlainText(null, mTransformed.subSequence(min, max)));
                 ((Editable) mText).delete(min, max);
                 stopSelectionActionMode();
                 return true;
 
             case ID_COPY:
-                setPrimaryClip(ClipData.newPlainText(null, null,
-                        mTransformed.subSequence(min, max)));
+                setPrimaryClip(ClipData.newPlainText(null, mTransformed.subSequence(min, max)));
                 stopSelectionActionMode();
                 return true;
         }
@@ -8105,7 +8100,7 @@
                 final int start = getSelectionStart();
                 final int end = getSelectionEnd();
                 CharSequence selectedText = mTransformed.subSequence(start, end);
-                ClipData data = ClipData.newPlainText(null, null, selectedText);
+                ClipData data = ClipData.newPlainText(null, selectedText);
                 DragLocalState localState = new DragLocalState(this, start, end);
                 startDrag(data, getTextThumbnailBuilder(selectedText), localState, 0);
                 stopSelectionActionMode();
@@ -8257,7 +8252,7 @@
         if (clip != null) {
             boolean didfirst = false;
             for (int i=0; i<clip.getItemCount(); i++) {
-                CharSequence paste = clip.getItem(i).coerceToText(getContext());
+                CharSequence paste = clip.getItemAt(i).coerceToText(getContext());
                 if (paste != null) {
                     if (!didfirst) {
                         long minMax = prepareSpacesAroundPaste(min, max, paste);
@@ -8404,8 +8399,12 @@
          */
         public void updatePosition(HandleView handle, int x, int y);
 
+        public void updateOffset(HandleView handle, int offset);
+
         public void updatePosition();
 
+        public int getCurrentOffset(HandleView handle);
+
         /**
          * This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller
          * a chance to become active and/or visible.
@@ -8422,7 +8421,7 @@
     }
 
     private class PastePopupMenu implements OnClickListener {
-        private PopupWindow mContainer;
+        private final PopupWindow mContainer;
         private int mPositionX;
         private int mPositionY;
         private View mPasteView, mNoPasteView;
@@ -8521,12 +8520,11 @@
     }
 
     private class HandleView extends View {
-        private boolean mPositionOnTop = false;
         private Drawable mDrawable;
-        private PopupWindow mContainer;
+        private final PopupWindow mContainer;
         private int mPositionX;
         private int mPositionY;
-        private CursorController mController;
+        private final CursorController mController;
         private boolean mIsDragging;
         private float mTouchToWindowOffsetX;
         private float mTouchToWindowOffsetY;
@@ -8543,6 +8541,46 @@
         private PastePopupMenu mPastePopupWindow;
         private Runnable mLongPressCallback;
 
+        // Touch-up filter: number of previous positions remembered
+        private static final int HISTORY_SIZE = 5;
+        private static final int TOUCH_UP_FILTER_DELAY = 150;
+        private final long[] mPreviousOffsetsTimes = new long[HISTORY_SIZE];
+        private final int[] mPreviousOffsets = new int[HISTORY_SIZE];
+        private int mPreviousOffsetIndex = 0;
+        private int mNumberPreviousOffsets = 0;
+
+        public void startTouchUpFilter(int offset) {
+            mNumberPreviousOffsets = 0;
+            addPositionToTouchUpFilter(offset);
+        }
+
+        public void addPositionToTouchUpFilter(int offset) {
+            if (mNumberPreviousOffsets > 0 &&
+                    mPreviousOffsets[mPreviousOffsetIndex] == offset) {
+                // Make sure only actual changes of position are recorded.
+                return;
+            }
+
+            mPreviousOffsetIndex = (mPreviousOffsetIndex + 1) % HISTORY_SIZE;
+            mPreviousOffsets[mPreviousOffsetIndex] = offset;
+            mPreviousOffsetsTimes[mPreviousOffsetIndex] = SystemClock.uptimeMillis();
+            mNumberPreviousOffsets++;
+        }
+
+        public void filterOnTouchUp() {
+            final long now = SystemClock.uptimeMillis();
+            int i = 0;
+            int index = 0;
+            final int iMax = Math.min(mNumberPreviousOffsets, HISTORY_SIZE);
+            while (i < iMax) {
+                index = (mPreviousOffsetIndex - i + HISTORY_SIZE) % HISTORY_SIZE;
+                if ((now - mPreviousOffsetsTimes[index]) >= TOUCH_UP_FILTER_DELAY) break;
+                i++;
+            }
+
+            mController.updateOffset(this, mPreviousOffsets[index]);
+        }
+
         public static final int LEFT = 0;
         public static final int CENTER = 1;
         public static final int RIGHT = 2;
@@ -8738,20 +8776,14 @@
         @Override
         protected void onDraw(Canvas c) {
             mDrawable.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
-            if (mPositionOnTop) {
-                c.save();
-                c.rotate(180, (mRight - mLeft) / 2, (mBottom - mTop) / 2);
-                mDrawable.draw(c);
-                c.restore();
-            } else {
-                mDrawable.draw(c);
-            }
+            mDrawable.draw(c);
         }
 
         @Override
         public boolean onTouchEvent(MotionEvent ev) {
             switch (ev.getActionMasked()) {
             case MotionEvent.ACTION_DOWN: {
+                startTouchUpFilter(mController.getCurrentOffset(this));
                 mDownPositionX = ev.getRawX();
                 mDownPositionY = ev.getRawY();
                 mTouchToWindowOffsetX = mDownPositionX - mPositionX;
@@ -8808,6 +8840,7 @@
                         }
                     }
                 }
+                filterOnTouchUp();
                 mIsDragging = false;
                 break;
 
@@ -8825,6 +8858,7 @@
         }
 
         void positionAtCursor(final int offset, boolean bottom) {
+            addPositionToTouchUpFilter(offset);
             final int width = mDrawable.getIntrinsicWidth();
             final int height = mDrawable.getIntrinsicHeight();
             final int line = mLayout.getLineForOffset(offset);
@@ -8940,12 +8974,16 @@
             int offset = getHysteresisOffset(x, y, previousOffset);
 
             if (offset != previousOffset) {
-                Selection.setSelection((Spannable) mText, offset);
-                updatePosition();
+                updateOffset(handle, offset);
             }
             hideDelayed();
         }
 
+        public void updateOffset(HandleView handle, int offset) {
+            Selection.setSelection((Spannable) mText, offset);
+            updatePosition();
+        }
+
         public void updatePosition() {
             final int offset = getSelectionStart();
 
@@ -8959,6 +8997,10 @@
             getHandle().positionAtCursor(offset, true);
         }
 
+        public int getCurrentOffset(HandleView handle) {
+            return getSelectionStart();
+        }
+
         public boolean onTouchEvent(MotionEvent ev) {
             return false;
         }
@@ -9069,6 +9111,20 @@
             updatePosition();
         }
 
+        public void updateOffset(HandleView handle, int offset) {
+            int start = getSelectionStart();
+            int end = getSelectionEnd();
+
+            if (mStartHandle == handle) {
+                start = offset;
+            } else {
+                end = offset;
+            }
+
+            Selection.setSelection((Spannable) mText, start, end);
+            updatePosition();
+        }
+
         public void updatePosition() {
             if (!isShowing()) {
                 return;
@@ -9089,6 +9145,10 @@
             mEndHandle.positionAtCursor(selectionEnd, true);
         }
 
+        public int getCurrentOffset(HandleView handle) {
+            return mStartHandle == handle ? getSelectionStart() : getSelectionEnd();
+        }
+
         public boolean onTouchEvent(MotionEvent event) {
             // This is done even when the View does not have focus, so that long presses can start
             // selection and tap can move cursor from this tap position.
@@ -9300,7 +9360,7 @@
         ClipData clipData = event.getClipData();
         final int itemCount = clipData.getItemCount();
         for (int i=0; i < itemCount; i++) {
-            Item item = clipData.getItem(i);
+            Item item = clipData.getItemAt(i);
             content.append(item.coerceToText(TextView.this.mContext));
         }
 
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 29ca49a..a8f9f62 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -33,6 +33,8 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 
+import java.lang.ref.WeakReference;
+
 /**
  * A toast is a view containing a quick little message for the user.  The toast class
  * helps you create and show those.
@@ -67,7 +69,6 @@
      */
     public static final int LENGTH_LONG = 1;
 
-    final Handler mHandler = new Handler();    
     final Context mContext;
     final TN mTN;
     int mDuration;
@@ -87,7 +88,7 @@
      */
     public Toast(Context context) {
         mContext = context;
-        mTN = new TN();
+        mTN = new TN(this);
         mY = context.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.toast_y_offset);
     }
@@ -101,13 +102,10 @@
         }
 
         INotificationManager service = getService();
-
         String pkg = mContext.getPackageName();
 
-        TN tn = mTN;
-
         try {
-            service.enqueueToast(pkg, tn, mDuration);
+            service.enqueueToast(pkg, mTN, mDuration);
         } catch (RemoteException e) {
             // Empty
         }
@@ -313,7 +311,9 @@
         return sService;
     }
 
-    private class TN extends ITransientNotification.Stub {
+    private static class TN extends ITransientNotification.Stub {
+        final Handler mHandler = new Handler();    
+
         final Runnable mShow = new Runnable() {
             public void run() {
                 handleShow();
@@ -327,10 +327,12 @@
         };
 
         private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
+        private final WeakReference<Toast> mToast;
         
         WindowManagerImpl mWM;
 
-        TN() {
+        TN(Toast toast) {
+            mToast = new WeakReference<Toast>(toast);
             // XXX This should be changed to use a Dialog, with a Theme.Toast
             // defined that sets up the layout params appropriately.
             final WindowManager.LayoutParams params = mParams;
@@ -362,49 +364,53 @@
         }
 
         public void handleShow() {
-            if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
-                    + " mNextView=" + mNextView);
-            if (mView != mNextView) {
-                // remove the old view if necessary
-                handleHide();
-                mView = mNextView;
-                mWM = WindowManagerImpl.getDefault();
-                final int gravity = mGravity;
-                mParams.gravity = gravity;
-                if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
-                    mParams.horizontalWeight = 1.0f;
+            final Toast toast = mToast.get();
+            if (toast != null) {
+                if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + toast.mView
+                        + " mNextView=" + toast.mNextView);
+                if (toast.mView != toast.mNextView) {
+                    // remove the old view if necessary
+                    handleHide();
+                    toast.mView = toast.mNextView;
+                    mWM = WindowManagerImpl.getDefault();
+                    final int gravity = toast.mGravity;
+                    mParams.gravity = gravity;
+                    if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
+                        mParams.horizontalWeight = 1.0f;
+                    }
+                    if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
+                        mParams.verticalWeight = 1.0f;
+                    }
+                    mParams.x = toast.mX;
+                    mParams.y = toast.mY;
+                    mParams.verticalMargin = toast.mVerticalMargin;
+                    mParams.horizontalMargin = toast.mHorizontalMargin;
+                    if (toast.mView.getParent() != null) {
+                        if (localLOGV) Log.v(TAG, "REMOVE! " + toast.mView + " in " + this);
+                        mWM.removeView(toast.mView);
+                    }
+                    if (localLOGV) Log.v(TAG, "ADD! " + toast.mView + " in " + this);
+                    mWM.addView(toast.mView, mParams);
+                    toast.trySendAccessibilityEvent();
                 }
-                if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
-                    mParams.verticalWeight = 1.0f;
-                }
-                mParams.x = mX;
-                mParams.y = mY;
-                mParams.verticalMargin = mVerticalMargin;
-                mParams.horizontalMargin = mHorizontalMargin;
-                if (mView.getParent() != null) {
-                    if (localLOGV) Log.v(
-                            TAG, "REMOVE! " + mView + " in " + this);
-                    mWM.removeView(mView);
-                }
-                if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
-                mWM.addView(mView, mParams);
-                trySendAccessibilityEvent();
             }
         }
 
         public void handleHide() {
-            if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
-            if (mView != null) {
-                // note: checking parent() just to make sure the view has
-                // been added...  i have seen cases where we get here when
-                // the view isn't yet added, so let's try not to crash.
-                if (mView.getParent() != null) {
-                    if (localLOGV) Log.v(
-                            TAG, "REMOVE! " + mView + " in " + this);
-                    mWM.removeView(mView);
+            final Toast toast = mToast.get();
+            if (toast != null) {
+                if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + toast.mView);
+                if (toast.mView != null) {
+                    // note: checking parent() just to make sure the view has
+                    // been added...  i have seen cases where we get here when
+                    // the view isn't yet added, so let's try not to crash.
+                    if (toast.mView.getParent() != null) {
+                        if (localLOGV) Log.v(TAG, "REMOVE! " + toast.mView + " in " + this);
+                        mWM.removeView(toast.mView);
+                    }
+    
+                    toast.mView = null;
                 }
-
-                mView = null;
             }
         }
     }
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 4ee3083..a8eb6fe 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -388,6 +388,7 @@
             mActionMode.finish();
         }
 
+        mUpperContextView.killMode();
         ActionMode mode = new ActionModeImpl(callback);
         if (callback.onCreateActionMode(mode, mode.getMenu())) {
             mode.invalidate();
@@ -492,7 +493,7 @@
             return;
         }
 
-        final FragmentTransaction trans = mActivity.getFragmentManager().openTransaction()
+        final FragmentTransaction trans = mActivity.getFragmentManager().beginTransaction()
                 .disallowAddToBackStack();
 
         if (mSelectedTab == tab) {
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index a139d31..71a7a52 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -391,6 +391,7 @@
         View buttonPanel = mWindow.findViewById(R.id.buttonPanel);
         if (!hasButtons) {
             buttonPanel.setVisibility(View.GONE);
+            mWindow.setCloseOnTouchOutsideIfNotSet(true);
         }
 
         FrameLayout customPanel = null;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 9ed4dd8..38ac37d 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -17,7 +17,6 @@
 package com.android.internal.app;
 
 import android.content.Intent;
-import android.content.pm.ResolveInfo;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.util.Log;
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index e1c5564..9fbbb3d 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -29,11 +29,11 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         
-        mToast = Toast.makeText(this, "Zombie art by Jack Larson", Toast.LENGTH_SHORT);
+        mToast = Toast.makeText(this, "REZZZZZZZ...", Toast.LENGTH_SHORT);
 
         ImageView content = new ImageView(this);
         content.setImageResource(com.android.internal.R.drawable.platlogo);
-        content.setScaleType(ImageView.ScaleType.FIT_CENTER);
+        content.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
         
         setContentView(content);
     }
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index 4d56745..fa0873d 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -17,8 +17,10 @@
 package com.android.internal.appwidget;
 
 import android.content.ComponentName;
+import android.content.Intent;
 import android.appwidget.AppWidgetProviderInfo;
 import com.android.internal.appwidget.IAppWidgetHost;
+import android.os.IBinder;
 import android.widget.RemoteViews;
 
 /** {@hide} */
@@ -46,6 +48,8 @@
     List<AppWidgetProviderInfo> getInstalledProviders();
     AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId);
     void bindAppWidgetId(int appWidgetId, in ComponentName provider);
+    void bindRemoteViewsService(int appWidgetId, in Intent intent, in IBinder connection);
+    void unbindRemoteViewsService(int appWidgetId, in Intent intent);
     int[] getAppWidgetIds(in ComponentName provider);
 
 }
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 588b10c..ff59950 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -1050,7 +1050,7 @@
      */
     private ViewGroup getMeasureActionButtonParent() {
         if (mMeasureActionButtonParent == null) {
-            mMeasureActionButtonParent = (ViewGroup) mMenuTypes[TYPE_ACTION_BUTTON].getInflater()
+            mMeasureActionButtonParent = (ViewGroup) getMenuType(TYPE_ACTION_BUTTON).getInflater()
                     .inflate(LAYOUT_RES_FOR_TYPE[TYPE_ACTION_BUTTON], null, false);
         }
         return mMeasureActionButtonParent;
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 23f89f1..bb0c752 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -26,7 +26,6 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.ActionMode;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -39,6 +38,8 @@
  * @hide
  */
 public class ActionBarContextView extends ViewGroup implements AnimatorListener {
+    private static final String TAG = "ActionBarContextView";
+
     private int mContentHeight;
     
     private CharSequence mTitle;
@@ -159,10 +160,6 @@
     }
 
     public void initForMode(final ActionMode mode) {
-        if (mAnimationMode != ANIMATE_IDLE || mAnimateInOnLayout) {
-            killMode();
-        }
-
         if (mClose == null) {
             LayoutInflater inflater = LayoutInflater.from(mContext);
             mClose = inflater.inflate(R.layout.action_mode_close_item, this, false);
@@ -197,15 +194,15 @@
             return;
         }
 
-        mAnimationMode = ANIMATE_OUT;
         finishAnimation();
+        mAnimationMode = ANIMATE_OUT;
         mCurrentAnimation = makeOutAnimation();
         mCurrentAnimation.start();
     }
 
     private void finishAnimation() {
         final Animator a = mCurrentAnimation;
-        if (a != null && a.isRunning()) {
+        if (a != null) {
             mCurrentAnimation = null;
             a.end();
         }
diff --git a/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl b/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
new file mode 100644
index 0000000..7eb2aef
--- /dev/null
+++ b/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.os.IBinder;
+
+/** {@hide} */
+interface IRemoteViewsAdapterConnection {
+    void onServiceConnected(IBinder service);
+    void onServiceDisconnected();
+}
diff --git a/core/java/com/android/internal/widget/WaveView.java b/core/java/com/android/internal/widget/WaveView.java
index 4cb3966..c7a90c4 100644
--- a/core/java/com/android/internal/widget/WaveView.java
+++ b/core/java/com/android/internal/widget/WaveView.java
@@ -152,7 +152,6 @@
         mUnlockRing.setScaleX(0.1f);
         mUnlockRing.setScaleY(0.1f);
         mUnlockRing.setAlpha(0.0f);
-
         mDrawables.add(mUnlockRing);
 
         mUnlockDefault = new DrawableHolder(createDrawable(R.drawable.unlock_default));
@@ -192,7 +191,6 @@
                 if (DBG) Log.v(TAG, "State RESET_LOCK");
                 mWaveTimerDelay = WAVE_DELAY;
                 for (int i = 0; i < mLightWaves.size(); i++) {
-                    //TweenMax.to(mLightWave.get(i), .3, {alpha:0, ease:Quint.easeOut});
                     DrawableHolder holder = mLightWaves.get(i);
                     holder.addAnimTo(300, 0, "alpha", 0.0f, false);
                 }
@@ -200,16 +198,12 @@
                     mLightWaves.get(i).startAnimations(this);
                 }
 
-                //TweenMax.to(unlockRing, .5, { x: lockX, y: lockY, scaleX: .1, scaleY: .1,
-                // alpha: 0, overwrite: true, ease:Quint.easeOut   });
                 mUnlockRing.addAnimTo(DURATION, 0, "x", mLockCenterX, true);
                 mUnlockRing.addAnimTo(DURATION, 0, "y", mLockCenterY, true);
                 mUnlockRing.addAnimTo(DURATION, 0, "scaleX", 0.1f, true);
                 mUnlockRing.addAnimTo(DURATION, 0, "scaleY", 0.1f, true);
                 mUnlockRing.addAnimTo(DURATION, 0, "alpha", 0.0f, true);
 
-                //TweenMax.to(unlockDefault, 0, { x: lockX, y: lockY, scaleX: .1, scaleY: .1,
-                // alpha: 0  , overwrite: true                       });
                 mUnlockDefault.removeAnimationFor("x");
                 mUnlockDefault.removeAnimationFor("y");
                 mUnlockDefault.removeAnimationFor("scaleX");
@@ -220,15 +214,10 @@
                 mUnlockDefault.setScaleX(0.1f);
                 mUnlockDefault.setScaleY(0.1f);
                 mUnlockDefault.setAlpha(0.0f);
-
-                //TweenMax.to(unlockDefault, .5, { delay: .1, scaleX: 1, scaleY: 1,
-                // alpha: 1, overwrite: true, ease:Quint.easeOut   });
                 mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, true);
                 mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, true);
                 mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, true);
 
-                //TweenMax.to(unlockHalo, 0, { x: lockX, y: lockY, scaleX:.1, scaleY: .1,
-                // alpha: 0  , overwrite: true                       });
                 mUnlockHalo.removeAnimationFor("x");
                 mUnlockHalo.removeAnimationFor("y");
                 mUnlockHalo.removeAnimationFor("scaleX");
@@ -239,16 +228,12 @@
                 mUnlockHalo.setScaleX(0.1f);
                 mUnlockHalo.setScaleY(0.1f);
                 mUnlockHalo.setAlpha(0.0f);
-
-                //TweenMax.to(unlockHalo, .5, { x: lockX, y: lockY, scaleX: 1, scaleY: 1,
-                // alpha: 1  , overwrite: true, ease:Quint.easeOut   });
                 mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "x", mLockCenterX, true);
                 mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "y", mLockCenterY, true);
                 mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, true);
                 mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, true);
                 mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, true);
 
-                //lockTimer.stop();
                 removeCallbacks(mLockTimerActions);
 
                 mLockState = STATE_READY;
@@ -260,8 +245,6 @@
 
             case STATE_START_ATTEMPT:
                 if (DBG) Log.v(TAG, "State START_ATTEMPT");
-                //TweenMax.to(unlockDefault, 0, {scaleX: .1, scaleY:.1, alpha: 0,
-                // x:lockX +182, y: lockY  , overwrite: true   });
                 mUnlockDefault.removeAnimationFor("x");
                 mUnlockDefault.removeAnimationFor("y");
                 mUnlockDefault.removeAnimationFor("scaleX");
@@ -273,14 +256,10 @@
                 mUnlockDefault.setScaleY(0.1f);
                 mUnlockDefault.setAlpha(0.0f);
 
-                //TweenMax.to(unlockDefault, 0.5, { delay: .1   , scaleX: 1, scaleY: 1,
-                // alpha: 1, ease:Quint.easeOut                        });
                 mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, false);
                 mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, false);
                 mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, false);
 
-                //TweenMax.to(unlockRing, 0.5, {scaleX: 1, scaleY: 1,
-                // alpha: 1, ease:Quint.easeOut, overwrite: true   });
                 mUnlockRing.addAnimTo(DURATION, 0, "scaleX", 1.0f, true);
                 mUnlockRing.addAnimTo(DURATION, 0, "scaleY", 1.0f, true);
                 mUnlockRing.addAnimTo(DURATION, 0, "alpha", 1.0f, true);
@@ -292,12 +271,8 @@
 
             case STATE_ATTEMPTING:
                 if (DBG) Log.v(TAG, "State ATTEMPTING (fingerDown = " + fingerDown + ")");
-                //TweenMax.to(unlockHalo, 0.4, { x:mouseX, y:mouseY, scaleX:1, scaleY:1,
-                // alpha: 1, ease:Quint.easeOut });
                 if (dragDistance > mSnapRadius) {
                     if (fingerDown) {
-                        //TweenMax.to(unlockHalo, 0.4, {x:ringX, y:ringY, scaleX:1, scaleY:1,
-                        // alpha: 1 , ease:Quint.easeOut    , overwrite: true });
                         mUnlockHalo.addAnimTo(0, 0, "x", ringX, true);
                         mUnlockHalo.addAnimTo(0, 0, "y", ringY, true);
                         mUnlockHalo.addAnimTo(0, 0, "scaleX", 1.0f, true);
@@ -320,8 +295,6 @@
                 if (DBG) Log.v(TAG, "State UNLOCK_ATTEMPT");
                 if (dragDistance > mSnapRadius) {
                     for (int n = 0; n < mLightWaves.size(); n++) {
-                        //TweenMax.to(this["lightWave"+n], .5,{alpha:0, delay: (6+n-currentWave)*.1,
-                        // x:ringX, y:ringY, scaleX: .1, scaleY: .1, ease:Quint.easeOut});
                         DrawableHolder wave = mLightWaves.get(n);
                         long delay = 1000L*(6 + n - mCurrentWave)/10L;
                         wave.addAnimTo(FINAL_DURATION, delay, "x", ringX, true);
@@ -334,19 +307,14 @@
                         mLightWaves.get(i).startAnimations(this);
                     }
 
-                    //TweenMax.to(unlockRing, .5, {x:ringX, y: ringY, scaleX: .1, scaleY: .1,
-                    // alpha: 0, ease: Quint.easeOut   });
                     mUnlockRing.addAnimTo(FINAL_DURATION, 0, "x", ringX, false);
                     mUnlockRing.addAnimTo(FINAL_DURATION, 0, "y", ringY, false);
                     mUnlockRing.addAnimTo(FINAL_DURATION, 0, "scaleX", 0.1f, false);
                     mUnlockRing.addAnimTo(FINAL_DURATION, 0, "scaleY", 0.1f, false);
                     mUnlockRing.addAnimTo(FINAL_DURATION, 0, "alpha", 0.0f, false);
 
-                    //TweenMax.to(unlockRing, .5, { delay: 1.3, alpha: 0  , ease: Quint.easeOut });
                     mUnlockRing.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
 
-                    //TweenMax.to(unlockDefault, 0, { x:ringX, y: ringY, scaleX: .1, scaleY: .1,
-                    // alpha: 0  , overwrite: true });
                     mUnlockDefault.removeAnimationFor("x");
                     mUnlockDefault.removeAnimationFor("y");
                     mUnlockDefault.removeAnimationFor("scaleX");
@@ -358,26 +326,19 @@
                     mUnlockDefault.setScaleY(0.1f);
                     mUnlockDefault.setAlpha(0.0f);
 
-                    //TweenMax.to(unlockDefault, .5, { x:ringX, y: ringY, scaleX: 1, scaleY: 1,
-                    // alpha: 1  , ease: Quint.easeOut  , overwrite: true });
                     mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "x", ringX, true);
                     mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "y", ringY, true);
                     mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "scaleX", 1.0f, true);
                     mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "scaleY", 1.0f, true);
                     mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "alpha", 1.0f, true);
 
-                    //TweenMax.to(unlockDefault, .5, { delay: 1.3, scaleX: 3, scaleY: 3,
-                    // alpha: 1, ease: Quint.easeOut });
                     mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleX", 3.0f, false);
                     mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleY", 3.0f, false);
                     mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
 
-                    //TweenMax.to(unlockHalo, .5, { x:ringX, y: ringY , ease: Back.easeOut    });
                     mUnlockHalo.addAnimTo(FINAL_DURATION, 0, "x", ringX, false);
                     mUnlockHalo.addAnimTo(FINAL_DURATION, 0, "y", ringY, false);
 
-                    //TweenMax.to(unlockHalo, .5, { delay: 1.3, scaleX: 3, scaleY: 3,
-                    // alpha: 1, ease: Quint.easeOut   });
                     mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleX", 3.0f, false);
                     mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleY", 3.0f, false);
                     mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
@@ -429,10 +390,12 @@
             if (DBG) Log.v(TAG, "LockTimerActions");
             // reset lock after inactivity
             if (mLockState == STATE_ATTEMPTING) {
+                if (DBG) Log.v(TAG, "Timer resets to STATE_RESET_LOCK");
                 mLockState = STATE_RESET_LOCK;
             }
             // for prototype, reset after successful unlock
             if (mLockState == STATE_UNLOCK_SUCCESS) {
+                if (DBG) Log.v(TAG, "Timer resets to STATE_RESET_LOCK after success");
                 mLockState = STATE_RESET_LOCK;
             }
             invalidate();
@@ -455,16 +418,12 @@
                 wave.setX(mMouseX);
                 wave.setY(mMouseY);
 
-                //TweenMax.to(this["lightWave"+currentWave], 2, { x:lockX , y:lockY, alpha: 1.5,
-                // scaleX: 1, scaleY:1, ease:Cubic.easeOut});
                 wave.addAnimTo(WAVE_DURATION, 0, "x", mLockCenterX, true);
                 wave.addAnimTo(WAVE_DURATION, 0, "y", mLockCenterY, true);
                 wave.addAnimTo(WAVE_DURATION*2/3, 0, "alpha", 1.0f, true);
                 wave.addAnimTo(WAVE_DURATION, 0, "scaleX", 1.0f, true);
                 wave.addAnimTo(WAVE_DURATION, 0, "scaleY", 1.0f, true);
 
-                //TweenMax.to(this["lightWave"+currentWave], 1, { delay: 1.3
-                // , alpha: 0  , ease:Quint.easeOut});
                 wave.addAnimTo(1000, RING_DELAY, "alpha", 0.0f, false);
                 wave.startAnimations(WaveView.this);
 
@@ -603,6 +562,8 @@
     }
 
     public void reset() {
+        if (DBG) Log.v(TAG, "reset() : resets state to STATE_RESET_LOCK");
         mLockState = STATE_RESET_LOCK;
+        invalidate();
     }
 }
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index dac748d..491a388 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -23,6 +23,7 @@
 jfieldID gOptions_justBoundsFieldID;
 jfieldID gOptions_sampleSizeFieldID;
 jfieldID gOptions_configFieldID;
+jfieldID gOptions_mutableFieldID;
 jfieldID gOptions_ditherFieldID;
 jfieldID gOptions_purgeableFieldID;
 jfieldID gOptions_shareableFieldID;
@@ -179,6 +180,7 @@
     SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode;
     SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
     bool doDither = true;
+    bool isMutable = false;
     bool isPurgeable = forcePurgeable ||
                         (allowPurgeable && optionsPurgeable(env, options));
     bool preferQualityOverSpeed = false;
@@ -196,6 +198,7 @@
         
         jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
         prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
+        isMutable = env->GetBooleanField(options, gOptions_mutableFieldID);
         doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
         preferQualityOverSpeed = env->GetBooleanField(options,
                 gOptions_preferQualityOverSpeedFieldID);
@@ -306,15 +309,19 @@
         // already have a pixelref installed.
         pr = bitmap->pixelRef();
     }
-    // promise we will never change our pixels (great for sharing and pictures)
-    pr->setImmutable();
+
+    if (!isMutable) {
+        // promise we will never change our pixels (great for sharing and pictures)
+        pr->setImmutable();
+    }
 
     if (javaBitmap != NULL) {
         // If a java bitmap was passed in for reuse, pass it back
         return javaBitmap;
     }
     // now create the java bitmap
-    return GraphicsJNI::createBitmap(env, bitmap, javaAllocator.getStorageObj(), false, ninePatchChunk);
+    return GraphicsJNI::createBitmap(env, bitmap, javaAllocator.getStorageObj(),
+            isMutable, ninePatchChunk);
 }
 
 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz,
@@ -510,6 +517,11 @@
     }
 }
 
+static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
+    jint descriptor = env->GetIntField(fileDescriptor, gFileDescriptor_descriptor);
+    return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static JNINativeMethod gMethods[] = {
@@ -539,6 +551,11 @@
     },
 
     {   "nativeSetDefaultConfig", "(I)V", (void*)nativeSetDefaultConfig },
+
+    {   "nativeIsSeekable",
+        "(Ljava/io/FileDescriptor;)Z",
+        (void*)nativeIsSeekable
+    },
 };
 
 static JNINativeMethod gOptionsMethods[] = {
@@ -572,6 +589,7 @@
     gOptions_sampleSizeFieldID = getFieldIDCheck(env, gOptions_class, "inSampleSize", "I");
     gOptions_configFieldID = getFieldIDCheck(env, gOptions_class, "inPreferredConfig",
             "Landroid/graphics/Bitmap$Config;");
+    gOptions_mutableFieldID = getFieldIDCheck(env, gOptions_class, "inMutable", "Z");
     gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z");
     gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z");
     gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "Z");
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 40cec3e..ac491ea 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -213,6 +213,11 @@
     renderer->scale(sx, sy);
 }
 
+static void android_view_GLES20Canvas_skew(JNIEnv* env, jobject canvas,
+        OpenGLRenderer* renderer, jfloat sx, jfloat sy) {
+    renderer->skew(sx, sy);
+}
+
 static void android_view_GLES20Canvas_setMatrix(JNIEnv* env, jobject canvas,
         OpenGLRenderer* renderer, SkMatrix* matrix) {
     renderer->setMatrix(matrix);
@@ -550,6 +555,7 @@
     { "nTranslate",         "(IFF)V",          (void*) android_view_GLES20Canvas_translate },
     { "nRotate",            "(IF)V",           (void*) android_view_GLES20Canvas_rotate },
     { "nScale",             "(IFF)V",          (void*) android_view_GLES20Canvas_scale },
+    { "nSkew",              "(IFF)V",          (void*) android_view_GLES20Canvas_skew },
 
     { "nSetMatrix",         "(II)V",           (void*) android_view_GLES20Canvas_setMatrix },
     { "nGetMatrix",         "(I)I",            (void*) android_view_GLES20Canvas_getNativeMatrix },
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 8c30987..e4af33f 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -61,6 +61,7 @@
 
 struct so_t {
     jfieldID surfaceControl;
+    jfieldID surfaceGenerationId;
     jfieldID surface;
     jfieldID saveCount;
     jfieldID canvas;
@@ -189,6 +190,12 @@
         p->decStrong(clazz);
     }
     env->SetIntField(clazz, so.surface, (int)surface.get());
+    // This test is conservative and it would be better to compare the ISurfaces
+    if (p && p != surface.get()) {
+        jint generationId = env->GetIntField(clazz, so.surfaceGenerationId);
+        generationId++;
+        env->SetIntField(clazz, so.surfaceGenerationId, generationId);
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -785,6 +792,7 @@
 void nativeClassInit(JNIEnv* env, jclass clazz)
 {
     so.surface = env->GetFieldID(clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");
+    so.surfaceGenerationId = env->GetFieldID(clazz, "mSurfaceGenerationId", "I");
     so.surfaceControl = env->GetFieldID(clazz, "mSurfaceControl", "I");
     so.saveCount = env->GetFieldID(clazz, "mSaveCount", "I");
     so.canvas    = env->GetFieldID(clazz, "mCanvas", "Landroid/graphics/Canvas;");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 41c911a..9b890fa 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1210,6 +1210,13 @@
         android:description="@string/permdesc_backup"
         android:protectionLevel="signatureOrSystem" />
 
+    <!-- Must be required by a {@link android.widget.RemoteViewsService},
+         to ensure that only the system can bind to it. -->
+    <permission android:name="android.permission.BIND_REMOTEVIEWS"
+        android:label="@string/permlab_bindRemoteViews"
+        android:description="@string/permdesc_bindRemoteViews"
+        android:protectionLevel="signatureOrSystem" />
+
     <!-- Allows an application to tell the AppWidget service which application
          can access AppWidget's data.  The normal user flow is that a user
          picks an AppWidget to go into a particular host, thereby giving that
diff --git a/core/res/res/animator/fragment_next_enter.xml b/core/res/res/animator/fragment_fade_enter.xml
similarity index 100%
rename from core/res/res/animator/fragment_next_enter.xml
rename to core/res/res/animator/fragment_fade_enter.xml
diff --git a/core/res/res/animator/fragment_next_exit.xml b/core/res/res/animator/fragment_fade_exit.xml
similarity index 100%
rename from core/res/res/animator/fragment_next_exit.xml
rename to core/res/res/animator/fragment_fade_exit.xml
diff --git a/core/res/res/animator/fragment_prev_enter.xml b/core/res/res/animator/fragment_prev_enter.xml
deleted file mode 100644
index 13b15f3..0000000
--- a/core/res/res/animator/fragment_prev_enter.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-	android:zAdjustment="top">
-    <objectAnimator
-        android:interpolator="@interpolator/decelerate_cubic"
-        android:valueFrom="0"
-        android:valueTo="1"
-        android:valueType="floatType"
-        android:propertyName="alpha"
-        android:duration="@android:integer/config_activityDefaultDur"/>
-</set>
\ No newline at end of file
diff --git a/core/res/res/animator/fragment_prev_exit.xml b/core/res/res/animator/fragment_prev_exit.xml
deleted file mode 100644
index 503b7ad..0000000
--- a/core/res/res/animator/fragment_prev_exit.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-	android:zAdjustment="normal">
-    <objectAnimator
-        android:interpolator="@interpolator/decelerate_cubic"
-        android:valueFrom="1"
-        android:valueTo="0"
-        android:valueType="floatType"
-        android:propertyName="alpha"
-        android:duration="@android:integer/config_activityShortDur"/>
-</set>
\ No newline at end of file
diff --git a/core/res/res/color/secondary_text_holo_dark.xml b/core/res/res/color/secondary_text_holo_dark.xml
index 881a1de3..7c564f7 100644
--- a/core/res/res/color/secondary_text_holo_dark.xml
+++ b/core/res/res/color/secondary_text_holo_dark.xml
@@ -17,11 +17,11 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_window_focused="false" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_dark"/>
     <item android:state_window_focused="false" android:color="@android:color/dim_foreground_holo_dark"/>
-    <item android:state_selected="true" android:state_enabled="false" android:color="@android:color/dim_foreground_inverse_disabled_holo_dark"/>
-    <item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_inverse_disabled_holo_dark"/>
-    <item android:state_selected="true" android:color="@android:color/dim_foreground_inverse_holo_dark"/>
-    <item android:state_activated="true" android:color="@android:color/bright_foreground_inverse_holo_dark"/>
-    <item android:state_pressed="true" android:color="@android:color/dim_foreground_inverse_holo_dark"/>
+    <item android:state_selected="true" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_dark"/>
+    <item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_dark"/>
+    <item android:state_selected="true" android:color="@android:color/dim_foreground_holo_dark"/>
+    <item android:state_activated="true" android:color="@android:color/bright_foreground_holo_dark"/>
+    <item android:state_pressed="true" android:color="@android:color/dim_foreground_holo_dark"/>
     <item android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_dark"/>
     <item android:color="@android:color/dim_foreground_holo_dark"/> <!-- not selected -->
 </selector>
diff --git a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_dark.png b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_dark.png
deleted file mode 100644
index 3ecaa9d..0000000
--- a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_light.png b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_light.png
deleted file mode 100644
index 40009af..0000000
--- a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_0.png b/core/res/res/drawable-hdpi/stat_sys_battery_0.png
index 3ed0105..82f2509 100644
--- a/core/res/res/drawable-hdpi/stat_sys_battery_0.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_10.png b/core/res/res/drawable-hdpi/stat_sys_battery_10.png
old mode 100644
new mode 100755
index c81616b..4486553
--- a/core/res/res/drawable-hdpi/stat_sys_battery_10.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_10.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_100.png b/core/res/res/drawable-hdpi/stat_sys_battery_100.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_20.png b/core/res/res/drawable-hdpi/stat_sys_battery_20.png
old mode 100644
new mode 100755
index eb5ef09..c8f9c92
--- a/core/res/res/drawable-hdpi/stat_sys_battery_20.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_20.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_40.png b/core/res/res/drawable-hdpi/stat_sys_battery_40.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_60.png b/core/res/res/drawable-hdpi/stat_sys_battery_60.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_80.png b/core/res/res/drawable-hdpi/stat_sys_battery_80.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
old mode 100644
new mode 100755
index 9a6c683..c7464f7
--- a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png
old mode 100644
new mode 100755
index c40c622..997feb3
--- a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png b/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png
old mode 100644
new mode 100755
index 1a9abaf..dadfe8d
--- a/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_dark.png b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_dark.png
deleted file mode 100644
index c369e6f..0000000
--- a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_light.png b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_light.png
deleted file mode 100644
index a4df2bf..0000000
--- a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_arrow.png b/core/res/res/drawable-mdpi/pointer_arrow.png
index e01129c..fbd187c 100644
--- a/core/res/res/drawable-mdpi/pointer_arrow.png
+++ b/core/res/res/drawable-mdpi/pointer_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
index e5af356..67e6ac3 100644
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ b/core/res/res/drawable-nodpi/platlogo.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/btn_code_lock_default.png b/core/res/res/drawable-xlarge-hdpi/btn_code_lock_default.png
new file mode 100644
index 0000000..719eb89
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/btn_code_lock_default.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/btn_code_lock_touched.png b/core/res/res/drawable-xlarge-hdpi/btn_code_lock_touched.png
new file mode 100644
index 0000000..719eb89
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/btn_code_lock_touched.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_green_up.png b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_green_up.png
new file mode 100644
index 0000000..c605607
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_green_up.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_red_up.png b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_red_up.png
new file mode 100644
index 0000000..a798863
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_red_up.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_default.png b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_default.png
new file mode 100644
index 0000000..07e6165
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_default.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_green.png b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_green.png
new file mode 100644
index 0000000..ec17841
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_green.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_red.png b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_red.png
new file mode 100644
index 0000000..a0cb1ec
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_red.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/btn_code_lock_default.png b/core/res/res/drawable-xlarge-mdpi/btn_code_lock_default.png
index eb4e0be..45cc20d 100644
--- a/core/res/res/drawable-xlarge-mdpi/btn_code_lock_default.png
+++ b/core/res/res/drawable-xlarge-mdpi/btn_code_lock_default.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/btn_code_lock_touched.png b/core/res/res/drawable-xlarge-mdpi/btn_code_lock_touched.png
index e56ae5b..45cc20d 100644
--- a/core/res/res/drawable-xlarge-mdpi/btn_code_lock_touched.png
+++ b/core/res/res/drawable-xlarge-mdpi/btn_code_lock_touched.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_green_up.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_green_up.png
index 8c3e363..0bc86c3 100644
--- a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_green_up.png
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_green_up.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_red_up.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_red_up.png
index 7b3e41b..2ab4547 100644
--- a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_red_up.png
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_red_up.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_default.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_default.png
index f163742..fe72d00 100644
--- a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_default.png
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_default.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_green.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_green.png
index 37abb2f..be666c6 100644
--- a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_green.png
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_green.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_red.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_red.png
index c6f6fc2..9627197 100644
--- a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_red.png
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_red.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml b/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml
index 4691edf..f2b846a 100644
--- a/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml
+++ b/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml
@@ -14,6 +14,5 @@
      limitations under the License.
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_focused="true" android:drawable="@drawable/ic_menu_moreoverflow_focused_holo_dark" />
     <item android:drawable="@drawable/ic_menu_moreoverflow_normal_holo_dark" />
 </selector>
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml b/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml
index 5c52ff4..34afa71 100644
--- a/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml
+++ b/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml
@@ -14,6 +14,5 @@
      limitations under the License.
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_focused="true" android:drawable="@drawable/ic_menu_moreoverflow_focused_holo_light" />
     <item android:drawable="@drawable/ic_menu_moreoverflow_normal_holo_light" />
 </selector>
diff --git a/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml b/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml
index 4f5beff..9779074 100644
--- a/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml
+++ b/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml
@@ -100,6 +100,16 @@
                 android:text="@android:string/lockscreen_glogin_submit_button"
                 />
 
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_below="@id/ok"
+                android:layout_marginTop="50dip"
+                android:text="@android:string/lockscreen_glogin_account_recovery_hint"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+                android:gravity="center_horizontal"
+                />
+
         </RelativeLayout>
     </ScrollView>
 
diff --git a/core/res/res/layout/preference.xml b/core/res/res/layout/preference.xml
index 6bd5efa..1f92252 100644
--- a/core/res/res/layout/preference.xml
+++ b/core/res/res/layout/preference.xml
@@ -24,36 +24,30 @@
     android:gravity="center_vertical"
     android:paddingRight="?android:attr/scrollbarSize">
 
-    <LinearLayout
+    <ImageView
+        android:id="@+android:id/icon"
         android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:minWidth="@dimen/preference_widget_width"
-        android:gravity="center"
-        android:orientation="horizontal">
-        <ImageView
-            android:id="@+android:id/icon"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            />
-    </LinearLayout>
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        />
 
     <RelativeLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_marginLeft="15dip"
         android:layout_marginRight="6dip"
         android:layout_marginTop="6dip"
         android:layout_marginBottom="6dip"
         android:layout_weight="1">
-    
+
         <TextView android:id="@+android:id/title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textAppearance="?android:attr/textAppearanceLarge"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal" />
-            
+
         <TextView android:id="@+android:id/summary"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -69,8 +63,7 @@
     <LinearLayout android:id="@+android:id/widget_frame"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
-        android:minWidth="@dimen/preference_widget_width"
-        android:gravity="center"
+        android:gravity="center_vertical"
         android:orientation="vertical" />
 
 </LinearLayout>
diff --git a/core/res/res/layout/preference_category.xml b/core/res/res/layout/preference_category.xml
index 7ffdc9a..280d952 100644
--- a/core/res/res/layout/preference_category.xml
+++ b/core/res/res/layout/preference_category.xml
@@ -18,5 +18,4 @@
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
     style="?android:attr/listSeparatorTextViewStyle"
     android:id="@+android:id/title"
-    android:paddingLeft="32dp"
 />
diff --git a/core/res/res/layout/preference_category_holo.xml b/core/res/res/layout/preference_category_holo.xml
new file mode 100644
index 0000000..5fe8b28
--- /dev/null
+++ b/core/res/res/layout/preference_category_holo.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<!-- Layout used for PreferenceCategory in a PreferenceActivity. -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    style="?android:attr/listSeparatorTextViewStyle"
+    android:id="@+android:id/title"
+    android:paddingLeft="32dp"
+/>
diff --git a/core/res/res/layout/preference_child_holo.xml b/core/res/res/layout/preference_child_holo.xml
new file mode 100644
index 0000000..2e70d77
--- /dev/null
+++ b/core/res/res/layout/preference_child_holo.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<!-- Layout for a visually child-like Preference in a PreferenceActivity. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:gravity="center_vertical"
+    android:paddingLeft="16dip"
+    android:paddingRight="?android:attr/scrollbarSize">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:minWidth="@dimen/preference_widget_width"
+        android:gravity="center"
+        android:orientation="horizontal">
+        <ImageView
+            android:id="@+android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            />
+    </LinearLayout>
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginRight="6dip"
+        android:layout_marginTop="6dip"
+        android:layout_marginBottom="6dip"
+        android:layout_weight="1">
+
+        <TextView android:id="@+android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
+            
+        <TextView android:id="@+android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/title"
+            android:layout_alignLeft="@android:id/title"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="4" />
+
+    </RelativeLayout>
+
+    <!-- Preference should place its actual preference widget here. -->
+    <LinearLayout android:id="@+android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:minWidth="@dimen/preference_widget_width"
+        android:gravity="center"
+        android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/preference_holo.xml b/core/res/res/layout/preference_holo.xml
new file mode 100644
index 0000000..c448f64
--- /dev/null
+++ b/core/res/res/layout/preference_holo.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<!-- Layout for a Preference in a PreferenceActivity. The
+     Preference is able to place a specific widget for its particular
+     type in the "widget_frame" layout. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:gravity="center_vertical"
+    android:paddingRight="?android:attr/scrollbarSize">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:minWidth="@dimen/preference_widget_width"
+        android:gravity="center"
+        android:orientation="horizontal">
+        <ImageView
+            android:id="@+android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            />
+    </LinearLayout>
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginRight="6dip"
+        android:layout_marginTop="6dip"
+        android:layout_marginBottom="6dip"
+        android:layout_weight="1">
+    
+        <TextView android:id="@+android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
+            
+        <TextView android:id="@+android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/title"
+            android:layout_alignLeft="@android:id/title"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="4" />
+
+    </RelativeLayout>
+
+    <!-- Preference should place its actual preference widget here. -->
+    <LinearLayout android:id="@+android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:minWidth="@dimen/preference_widget_width"
+        android:gravity="center"
+        android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/preference_information.xml b/core/res/res/layout/preference_information.xml
index 9c9b83e..32cbb90 100644
--- a/core/res/res/layout/preference_information.xml
+++ b/core/res/res/layout/preference_information.xml
@@ -24,13 +24,10 @@
     android:gravity="center_vertical"
     android:paddingRight="?android:attr/scrollbarSize">
 
-    <View
-        android:layout_width="@dimen/preference_widget_width"
-        android:layout_height="match_parent" />
-
     <RelativeLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_marginLeft="16sp"
         android:layout_marginRight="6sp"
         android:layout_marginTop="6sp"
         android:layout_marginBottom="6sp"
@@ -40,9 +37,9 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textAppearance="?android:attr/textAppearanceLarge"
             android:textColor="?android:attr/textColorSecondary" />
-            
+
         <TextView android:id="@+android:id/summary"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -53,7 +50,7 @@
             android:maxLines="2" />
 
     </RelativeLayout>
-    
+
     <!-- Preference should place its actual preference widget here. -->
     <LinearLayout android:id="@+android:id/widget_frame"
         android:layout_width="wrap_content"
diff --git a/core/res/res/layout/preference_information_holo.xml b/core/res/res/layout/preference_information_holo.xml
new file mode 100644
index 0000000..d6cc063
--- /dev/null
+++ b/core/res/res/layout/preference_information_holo.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<!-- Layout for a Preference in a PreferenceActivity. The
+     Preference is able to place a specific widget for its particular
+     type in the "widget_frame" layout. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:gravity="center_vertical"
+    android:paddingRight="?android:attr/scrollbarSize">
+
+    <View
+        android:layout_width="@dimen/preference_widget_width"
+        android:layout_height="match_parent" />
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginRight="6sp"
+        android:layout_marginTop="6sp"
+        android:layout_marginBottom="6sp"
+        android:layout_weight="1">
+
+        <TextView android:id="@+android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary" />
+            
+        <TextView android:id="@+android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/title"
+            android:layout_alignLeft="@android:id/title"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="2" />
+
+    </RelativeLayout>
+    
+    <!-- Preference should place its actual preference widget here. -->
+    <LinearLayout android:id="@+android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:gravity="center_vertical"
+        android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 080d66d..8a506a3 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"تعيين الخادم الوكيل العمومي للجهاز لكي يتم استخدامه أثناء تمكين السياسة. يعين مشرف الجهاز الأول فقط الخادم الوكيل العمومي الفعال."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"تعيين انتهاء صلاحية كلمة المرور"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"التحكم في الوقت المستغرق قبل الحاجة إلى تغيير كلمة مرور شاشة التوقف"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"الرئيسية"</item>
     <item msgid="869923650527136615">"الجوال"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"تم توصيل تصحيح أخطاء USB"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"اختيار تعطيل تصحيح أخطاء USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"تحديد طريقة الإرسال"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"العناصر المرشحة"</u></string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index d1176b8e..2736269 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Задаване на глобалния прокси сървър, който да се използва, когато правилото е активирано. Само първият администратор на устройството задава действителния глобален прокси сървър."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Срок на валидност на паролата"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Контролирайте след колко време трябва да се променя паролата при заключване на екрана"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Домашен"</item>
     <item msgid="869923650527136615">"Мобилен"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Отстраняването на грешки през USB е свързано"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Изберете, за да деактивирате отстраняването на грешки през USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Избиране на метод на въвеждане"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index e352fc0..ba93303 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Defineix el servidor intermediari global del dispositiu que cal utilitzar mentre la política estigui activada. Només el primer administrador del dispositiu pot definir el servidor intermediari global efectiu."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Defineix la caducitat de la contrasenya"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Controla quant de temps abans de la pantalla de bloqueig cal canviar la contrasenya"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Casa"</item>
     <item msgid="869923650527136615">"Mòbil"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuració d\'USB connectada"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Seleccioneu-ho per desactivar la depuració d\'USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Selecció del mètode d\'entrada"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 441ad01..7495a66 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Vyberte globální proxy server, který se bude používat, když jsou zásady aktivní. Aktuální globální proxy server nastavuje pouze první správce zařízení."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Nastavit konec platnosti hesla"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Ovládání doby, po jejímž uplynutí je nutné změnit heslo pro odemknutí obrazovky"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Domů"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Ladění přes rozhraní USB připojeno"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Vyberte, chcete-li zakázat ladění USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Výběr metody zadávání dat"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 0242ee9..0c9aefd 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Angiv enhedens globale proxy, der skal bruges, mens politikken er aktiveret. Kun den første enhedsadministrator angiver den effektive globale proxy."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Indstil udløb for adgangskode"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Kontroller, hvor lang tid der skal gå, før adgangskoden til skærmlåsen skal ændres."</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Hjem"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-fejlretning er tilsluttet"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Vælg for at deaktivere USB-fejlretning."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Vælg indtastningsmetode"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 87f14c5..7856aaf 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Den globalen Proxy des Geräts zur Verwendung während der Aktivierung der Richtlinie festlegen. Nur der erste Geräteadministrator kann den gültigen globalen Proxy festlegen."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Ablauf des Passworts festlegen"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Zeitraum bis zur Änderung des Passworts für die Bildschirmsperre festlegen"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Privat"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-Debugging verbunden"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Auswählen, um USB-Debugging zu deaktivieren."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Eingabemethode auswählen"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 6b8db1e..7dc9747 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ορίστε τη χρήση του γενικού διακομιστή μεσολάβησης της συσκευής όταν είναι ενεργοποιημένη η πολιτική. Μόνο ο διαχειριστής της πρώτης συσκευής ορίζει τον ισχύοντα γενικό διακομιστή μεσολάβησης."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Ορισμός λήξης κωδ. πρόσβασης"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Ελέγξτε πόσος χρόνος απομένει προτού πρέπει να αλλάξετε τον κωδικό πρόσβασης κλειδώματος της οθόνης"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Οικία"</item>
     <item msgid="869923650527136615">"Κινητό"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Συνδέθηκε ο εντοπισμός σφαλμάτων USB"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Επιλογή για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Επιλογή μεθόδου εισόδου"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index a981ed6..a63e2c4 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Set the device\'s global proxy to be used while policy is enabled. Only the first device admin sets the effective global proxy."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Set password expiry"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Control how long before lock-screen password needs to be changed"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Home"</item>
     <item msgid="869923650527136615">"Mobile"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Select to disable USB debugging."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Select input method"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
diff --git a/core/res/res/values-es-rUS-xlarge/strings.xml b/core/res/res/values-es-rUS-xlarge/strings.xml
index b1409ba..81b3f1a 100644
--- a/core/res/res/values-es-rUS-xlarge/strings.xml
+++ b/core/res/res/values-es-rUS-xlarge/strings.xml
@@ -288,6 +288,8 @@
     <!-- XL -->
     <string name="capital_on" msgid="5705918046896729554">"ENCENDIDO"</string>
     <!-- XL -->
+    <string name="capital_off" msgid="6734525950925281617">"APAGADO"</string>
+    <!-- XL -->
     <string name="wait" msgid="8036803866051401072">"Espera"</string>
     <!-- XL -->
     <string name="heavy_weight_notification" msgid="5762367358298413602">"<xliff:g id="APP">%1$s</xliff:g> se está ejecutando"</string>
@@ -311,6 +313,10 @@
     <!-- XL -->
     <string name="permdesc_mediaStorageWrite" product="default" msgid="2372999661142345443">"Permite que una aplicación modifique los contenidos del almacenamiento interno de medios."</string>
     <!-- XL -->
+    <string name="policylab_encryptedStorage" msgid="488196329176602372">"Establecer la encriptación del almacenamiento"</string>
+    <!-- XL -->
+    <string name="policydesc_encryptedStorage" msgid="6111889605506443825">"Requiere que los datos almacenados de la aplicación estén encriptados"</string>
+    <!-- XL -->
     <string name="autofill_address_summary_name_format" msgid="7531610259426153850">"$1$2$3"</string>
     <!-- XL -->
     <string name="autofill_address_summary_format" msgid="8398158823767723887">"$1$2$3"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 5e6645d..5d1a25f 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -489,6 +489,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configuración del proxy global de dispositivo que se utilizará mientras se habilita la política. Sólo la primera administración de dispositivo configura el proxy global efectivo."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Establecer la caducidad de la contraseña"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Verifica cuánto tiempo antes debes cambiar la contraseña de la pantalla de bloqueo"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Casa"</item>
     <item msgid="869923650527136615">"Celular"</item>
@@ -809,8 +813,8 @@
     <string name="no" msgid="5141531044935541497">"Cancelar"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
     <string name="loading" msgid="1760724998928255250">"Cargando..."</string>
-    <string name="capital_on" msgid="1544682755514494298">"Encendido"</string>
-    <string name="capital_off" msgid="6815870386972805832">"APAGADO"</string>
+    <string name="capital_on" msgid="1544682755514494298">"Sí"</string>
+    <string name="capital_off" msgid="6815870386972805832">"No"</string>
     <string name="whichApplication" msgid="4533185947064773386">"Completar la acción mediante"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Utilizar de manera predeterminada en esta acción."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Borrar la predeterminación en Configuración de la página principal &gt; Aplicaciones &gt; Administrar aplicaciones."</string>
@@ -904,6 +908,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración de USB conectada"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Seleccionar para desactivar la depuración de USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Seleccionar método de entrada"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 4f02c4b..a4d6545 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Define el servidor proxy global que se debe utilizar mientras la política esté habilitada. Solo el primer administrador de dispositivos define el servidor proxy global efectivo."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Definir caducidad contraseña"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Permite controlar cuándo se debe cambiar la contraseña de bloqueo de la pantalla."</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Casa"</item>
     <item msgid="869923650527136615">"Móvil"</item>
@@ -501,7 +505,7 @@
     <item msgid="9192514806975898961">"Personalizar"</item>
   </string-array>
   <string-array name="emailAddressTypes">
-    <item msgid="8073994352956129127">"Personal"</item>
+    <item msgid="8073994352956129127">"Casa"</item>
     <item msgid="7084237356602625604">"Trabajo"</item>
     <item msgid="1112044410659011023">"Otra"</item>
     <item msgid="2374913952870110618">"Personalizar"</item>
@@ -810,8 +814,8 @@
     <string name="no" msgid="5141531044935541497">"Cancelar"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
     <string name="loading" msgid="1760724998928255250">"Cargando…"</string>
-    <string name="capital_on" msgid="1544682755514494298">"Activado"</string>
-    <string name="capital_off" msgid="6815870386972805832">"Desconectado"</string>
+    <string name="capital_on" msgid="1544682755514494298">"SÍ"</string>
+    <string name="capital_off" msgid="6815870386972805832">"NO"</string>
     <string name="whichApplication" msgid="4533185947064773386">"Completar acción utilizando"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Utilizar de forma predeterminada para esta acción"</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Borrar valores predeterminados en la página de configuración de la pantalla de inicio del teléfono &gt; Aplicaciones &gt; Administrar aplicaciones\"."</string>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Dispositivo de depuración USB conectado"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Seleccionar para inhabilitar la depuración USB"</string>
     <string name="select_input_method" msgid="6865512749462072765">"Seleccionar método de introducción de texto"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 95871a4..767655d 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"پروکسی جهانی دستگاه مورد نظر را جهت استفاده هنگام فعال بودن خط مشی تنظیم کنید. فقط اولین سرپرست دستگاه پروکسی جهانی مفید را تنظیم می کند."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"تنظیم زمان انقضای رمز ورود"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"کنترل مدت زمانی که رمز ورود صفحه قفل قبل از تغییر یافتن لازم دارد"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"خانه"</item>
     <item msgid="869923650527136615">"تلفن همراه"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"رفع عیب USB متصل شد"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"انتخاب کنید تا رفع عیب USB غیرفعال شود."</string>
     <string name="select_input_method" msgid="6865512749462072765">"انتخاب روش ورودی"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"داوطلبین"</u></string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 1392ebb..d8d13ef 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Aseta laitteen yleinen välityspalvelin käyttöön, kun käytäntö on käytössä. Vain ensimmäinen laitteen järjestelmänhallitsija voi asettaa käytettävän yleisen välityspalvelimen."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Aseta salasanan umpeutuminen"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Valitse, kuinka pian ruudunlukituksen poiston salasana tulee vaihtaa"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Puhelinnumero (koti)"</item>
     <item msgid="869923650527136615">"Mobiili"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-vianetsintä yhdistetty"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Poista USB-vianetsintä käytöstä valitsemalla tämä."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Valitse syöttötapa"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaatit"</u></string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 361d193..c3fb6eb 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Indiquez le proxy global à utiliser pour ce mobile lorsque les règles sont activées. Seul l\'administrateur principal du mobile peut définir le proxy global utilisé."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Définir date exp. mot de passe"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Définir la fréquence de changement du mot de passe de verrouillage d\'écran"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Domicile"</item>
     <item msgid="869923650527136615">"Mobile"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB connecté"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Sélectionnez cette option pour désactiver le débogage USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Sélectionner un mode de saisie"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index befb526..fe9f319 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Postavi globalni proxy uređaja za upotrebu dok su pravila omogućena. Samo prvi administrator uređaja postavlja djelotvoran globalni proxy."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Postavi istek zaporke"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Nadzirite za koliko vremena zaporka za zaključani zaslon treba biti promijenjena"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Početna"</item>
     <item msgid="869923650527136615">"Mobilni"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Priključen je alat za uklanjanje programske pogreške USB-a"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Odaberite da biste onemogućili rješavanje programske pogreške na USB-u."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Odaberite način unosa"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 0ee1bbc..a090f0b 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Az eszköz globális proxyja lesz használatban, amíg az irányelv engedélyezve van. Csak az eszköz első rendszergazdája állíthatja be a tényleges globális proxyt."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Jelszó lejáratának beállítása"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Azt vezérli, mennyi időnként kell módosítani a képernyőt zároló jelszót"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Otthoni"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB hibakereső csatlakoztatva"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Válassza ezt az USB hibakeresés kikapcsolásához."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Válassza ki a beviteli módszert"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"jelöltek"</u></string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 304ef90..8f738d6 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Setel proxy global perangkat yang akandigunakan ketika kebijakan diaktifkan. Hanya admin perangkat pertama yang menyetel procy global yang berlaku."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Setel kedaluwarsa sandi"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Kontrol berapa lama sebelum sandi penguncian layar perlu diubah"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Rumah"</item>
     <item msgid="869923650527136615">"Seluler"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Debugging USB terhubung"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Pilih untuk menonaktifkan debugging USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Pilih metode masukan"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 282d375..887a96d 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Imposta il proxy globale del dispositivo in modo da utilizzarlo mentre la norma è attiva. Il proxy globale effettivo è impostabile solo dal primo amministratore del dispositivo."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Imposta scadenza password"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Stabilisci la scadenza della password di blocco dello schermo"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Casa"</item>
     <item msgid="869923650527136615">"Cellulare"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Debug USB collegato"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Seleziona per disattivare il debug USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Seleziona metodo di inserimento"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidati"</u></string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index ea48002..eab8673 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"הגדר את שרת proxy הגלובלי של ההתקן לשימוש כאשר המדיניות מופעלת. רק מנהל ההתקן הראשון מגדיר את שרת ה-proxy הגלובלי הפעיל."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"הגדר תפוגת תוקף של סיסמה"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"שלוט בפרק הזמן הדרוש לשינוי הסיסמה של נעילת המסך"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"דף הבית"</item>
     <item msgid="869923650527136615">"נייד"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"ניקוי באגים של USB מחובר"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"בחר כדי להשבית ניקוי באגים ב-USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"בחר שיטת קלט"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZאבגדהוזחטיכלמנסעפצקרשת"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ  0123456789אבגדהוזחטיכלמנסעפצקרשת"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"מועמדים"</u></string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 6df5f3d..c1b9f5d 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"ポリシーが有効になっている場合は端末のグローバルプロキシが使用されるように設定します。有効なグローバルプロキシを設定できるのは最初のデバイス管理者だけです。"</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"パスワードの有効期限の設定"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"画面ロックパスワードの変更が必要になるまでの期間を指定します"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"自宅"</item>
     <item msgid="869923650527136615">"携帯"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USBデバッグが接続されました"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"USBデバッグを無効にする場合に選択します。"</string>
     <string name="select_input_method" msgid="6865512749462072765">"入力方法の選択"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"候補"</u></string>
@@ -969,7 +975,7 @@
     <string name="no_file_chosen" msgid="6363648562170759465">"ファイルが選択されていません"</string>
     <string name="reset" msgid="2448168080964209908">"リセット"</string>
     <string name="submit" msgid="1602335572089911941">"送信"</string>
-    <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"運転モードを有効にする"</string>
+    <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"運転モードになっています"</string>
     <string name="car_mode_disable_notification_message" msgid="668663626721675614">"運転モードを終了するには選択してください。"</string>
     <string name="tethered_notification_title" msgid="3146694234398202601">"テザリングまたはアクセスポイントが有効です"</string>
     <string name="tethered_notification_message" msgid="3067108323903048927">"タップして設定する"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 10eba59..eda018d 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"정책이 사용 설정되어 있는 동안 사용될 기기 전체 프록시를 설정합니다. 첫 번째 기기 관리자가 설정한 전체 프록시만 유효합니다."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"비밀번호 만료 설정"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"화면 잠금 비밀번호를 변경해야 하는 기간 변경"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"집"</item>
     <item msgid="869923650527136615">"모바일"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB 디버깅 연결됨"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"USB 디버깅을 사용하지 않으려면 선택합니다."</string>
     <string name="select_input_method" msgid="6865512749462072765">"입력 방법 선택"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"가능한 원인"</u></string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index bbb629d..f9f01e4 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Nustatyti įrenginio bendrąjį tarpinį serverį, kad būtų naudojamas, kol įgalinta politika. Tik pirmasis įrenginio administratorius nustato efektyvų bendrąjį tarpinį serverį."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Nust. slaptaž. galiojimo pab."</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Valdyti, per kiek laiko iki ekrano užrakinimo turi būti pakeistas slaptažodis"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Pagrindinis"</item>
     <item msgid="869923650527136615">"Mobilusis"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB derinimas prijungtas"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Pasirinkite, kas išjungtumėte USB derinimą."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Pasirinkti įvesties būdą"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatai"</u></string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 7ef1e0a..6d25c54 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Iestatiet izmantojamo ierīces globālo starpniekserveri, kad ir iespējota politika. Spēkā esošo globālo starpniekserveri iestata tikai pirmās ierīces administrators."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Paroles termiņa izb. iest."</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Kontrolē ekrāna bloķēšanas paroles maiņas intervālu"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Mājas"</item>
     <item msgid="869923650527136615">"Mobilais"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB atkļūdošana ir pievienota."</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Atlasiet, lai atspējotu USB atkļūdošanu."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Atlasiet ievades metodi"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidāti"</u></string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 83fd2d3c..aed9163 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Angir den globale mellomtjeneren på enheten som skal brukes når regelen er aktivert. Kun den opprinnelige administratoren av enheten kan angi den globale mellomtjeneren."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Angi utløpsdato for passordet"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Velg hvor lenge det skal gå før passordet til låseskjermen må byttes"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Hjemmenummer"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-debugging tilkoblet"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Velg for å deaktivere USB-debugging."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Velg inndatametode"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
     <string name="candidates_style" msgid="4333913089637062257">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 3c03980..062caee 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Stel de algemene proxy voor het apparaat in die moet worden gebruikt terwijl het beleid is geactiveerd. Alleen de eerste apparaatbeheerder stelt de algemene proxy in."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Verval wachtwoord instellen"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Beheren hoe lang het duurt voordat het wachtwoord voor schermvergrendeling moet worden gewijzigd"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Thuis"</item>
     <item msgid="869923650527136615">"Mobiel"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-foutopsporing verbonden"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Selecteer deze optie om USB-foutopsporing uit te schakelen."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Invoermethode selecteren"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaten"</u></string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index e82dbca..868f168 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ustaw globalny serwer proxy urządzenia do wykorzystywania przy włączonych zasadach. Tylko pierwszy administrator urządzenia ustawia obowiązujący globalny serwer proxy."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Ustaw wygasanie hasła"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Kontrola czasu, po którym należy zmienić hasło blokowania ekranu"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Dom"</item>
     <item msgid="869923650527136615">"Komórka"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Podłączono moduł debugowania USB"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Wybierz, aby wyłączyć debugowanie USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Wybierz metodę wprowadzania"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 41634f8..f306b8d 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Definir o proxy global do aparelho a ser utilizado quando a política estiver activada. Só o primeiro administrador do aparelho define o proxy global efectivo."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Def. valid. da palavra-passe"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Controle com que antecedência é necessário alterar a palavra-passe de bloqueio do ecrã"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Residência"</item>
     <item msgid="869923650527136615">"Móvel"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB ligada"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Seleccione para desactivar depuração USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Seleccionar método de entrada"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 572cbce..7cd6cc4 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configura o proxy global do dispositivo para ser usado enquanto a política estiver ativada. Somente o primeiro administrador do dispositivo pode configurar um verdadeiro proxy global."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Definir validade da senha"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Controle quanto tempo uma senha de bloqueio de tela deve ficar ativa antes de ser alterada"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Residencial"</item>
     <item msgid="869923650527136615">"Celular"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Selecione para desativar a depuração USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Selecionar método de entrada"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 9a879c7..a3d8191 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -498,6 +498,10 @@
     <skip />
     <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
     <skip />
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Privat"</item>
     <item msgid="869923650527136615">"Telefonin"</item>
@@ -947,6 +951,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Debugging USB connectà"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Tscherner per deactivar il debugging USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Tscherner ina metoda d\'endataziun"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index d0e1dc6..07a6213 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Setaţi serverul proxy global pentru dispozitiv care să fie utilizat cât timp politica este activă. Numai primul administrator al dispozitivului poate seta serverul proxy global activ."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Setaţi expirarea parolei"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Controlarea duratei până când parola de blocare a ecranului trebuie modificată"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Domiciliu"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depanarea USB este conectată"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Selectaţi pentru a dezactiva depanarea USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Selectaţi metoda de intrare"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidaţi"</u></string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 22ee02a..dfc5d08 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Настройте глобальный прокси-сервер устройства, который будет использоваться при активной политике. Глобальный прокси-сервер должен настроить первый администратор устройства."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Задать время действия пароля"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Задать время действия пароля перед появлением экрана блокировки"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Домашний"</item>
     <item msgid="869923650527136615">"Мобильный"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Отладка по USB разрешена"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Нажмите, чтобы отключить отладку USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Выберите способ ввода"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"варианты"</u></string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 397688d..e7bbaf6 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Vyberte globálny server proxy, ktorý sa bude používať po aktivácii pravidiel. Platný globálny server proxy nastavuje iba prvý správca zariadenia."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Nastav. koniec platnosti hesla"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Ovládanie doby, po uplynutí ktorej treba zmeniť heslo na odomknutie obrazovky"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Domovská stránka"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Ladenie cez rozhranie USB pripojené"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Vyberte, ak chcete zakázať ladenie USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Výber metódy vstupu"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁÄBCČDĎDZDŽEÉFGHCHIÍJKLĽMNŇOÓÔPRŔSŠTŤUÚVWXYÝZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 91c42a8..c6b4302 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Nastavite globalni strežnik proxy naprave, ki bo v uporabi, ko je pravilnik omogočen. Samo skrbnik prve naprave lahko nastavi veljaven globalni strežnik proxy."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Nastavitev poteka gesla"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Nastavite, koliko časa prej je treba spremeniti geslo za odklepanje zaslona"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Začetna stran"</item>
     <item msgid="869923650527136615">"Mobilni"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"iskanje in odpravljanje napak USB je povezano"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Izberite, če želite onemogočiti iskanje in odpravljanje napak prek vrat USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Izbiranje načina vnosa"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
@@ -997,8 +1003,7 @@
     <string name="media_unknown_state" msgid="729192782197290385">"Neznano stanje zunanjih nosilcev podatkov."</string>
     <string name="share" msgid="1778686618230011964">"Deli z dr."</string>
     <string name="find" msgid="4808270900322985960">"Najdi"</string>
-    <!-- no translation found for websearch (4337157977400211589) -->
-    <skip />
+    <string name="websearch" msgid="4337157977400211589">"Spletno iskanje"</string>
     <!-- no translation found for gpsNotifTicker (5622683912616496172) -->
     <skip />
     <!-- no translation found for gpsNotifTitle (5446858717157416839) -->
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index c5c1e43..0493685 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Подесите глобални прокси сервер уређаја који ће се користити док су омогућене смернице. Само први администратор уређаја поставља ефективни глобални прокси сервер."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Подеси време истека лозинке"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Контролишите време када лозинка за закључавање екрана треба да се промени"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Кућа"</item>
     <item msgid="869923650527136615">"Мобилни"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Отклањање грешака са USB-а је успостављено"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Изаберите да бисте онемогућили отклањања грешака са USB-а."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Избор методе уноса"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index bda3863..a60e7f9 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ange vilken global proxyserver som ska användas när policyn är aktiverad. Endast den första enhetsadministratören anger den faktiska globala proxyservern."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Ange lösenordets utgångsdatum"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Se hur långt det är kvar till du måste ändra lösenordet till låsningsskärmen"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Hem"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-felsökning ansluten"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Välj att inaktivera USB-felsökning."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Välj indatametod"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 41593f2..f192c6d 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"ตั้งค่าพร็อกซีส่วนกลางของอุปกรณ์ที่จะใช้ขณะเปิดการใช้งานนโยบาย เฉพาะผู้ดูแลอุปกรณ์คนแรกเท่านั้นที่ตั้งค่าพร็อกซีส่วนกลางที่มีผลบังคับ"</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"ตั้งค่าการหมดอายุของรหัสผ่าน"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"ควบคุมระยะเวลาก่อนที่จะต้องเปลี่ยนรหัสผ่านการล็อกหน้าจอ"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"บ้าน"</item>
     <item msgid="869923650527136615">"มือถือ"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"เชื่อมต่อการแก้ไขข้อบกพร่อง USB แล้ว"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"เลือกเพื่อปิดใช้งานการแก้ไขข้อบกพร่อง USB"</string>
     <string name="select_input_method" msgid="6865512749462072765">"เลือกวิธีป้อนข้อมูล"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ตัวเลือก"</u></string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index f65d77e..d42ef28 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Itakda ang pandaigdigang proxy ng device na gagamitin habang pinagana ang patakaran. Tanging ang unang admin ng device ang magtatakda sa may bisang pandaigdigang proxy."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Itakda pag-expire ng password"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Kontrolin kung gaano katagal bago kailangang palitan ang password sa pag-lock ng screen"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Home"</item>
     <item msgid="869923650527136615">"Mobile"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Konektado ang debugging ng USB"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Piliin upang huwag paganahin ang debugging ng USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Pumili ng pamamaraan ng pag-input"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"mga kandidato"</u></string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 762ea47..8b338dd 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Politika etkin olduğunda kullanılacak cihaz genelinde geçerli proxy\'yi ayarlayın. Etkin genel proxy\'yi yalnızca ilk cihaz yöneticisi ayarlar."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Şifre süre sonu tarihi ayarla"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Ekran kilitleme şifresinin ne kadar süre sonra değiştirilmesi gerekeceğini denetleyin."</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Ev"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB hata ayıklaması bağlandı"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"USB hata ayıklamasını devre dışı bırakmak için tıklayın."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Giriş yöntemini seç"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"adaylar"</u></string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index a2ad6dc..6e5fdaa 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Устан. використ. глоб. проксі, коли ввімкнено політику. Лише адміністратор першого пристрою встановлює активний глоб. проксі."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Установити термін дії пароля"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Регулює, за скільки часу перед блокуванням екрана треба змінювати пароль"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Дом."</item>
     <item msgid="869923650527136615">"Мобільний"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Налагодження USB підключ."</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Вибер., щоб вимкн. налагодж. USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Виберіть метод введ-ня"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 4e5220a..08c8990 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -487,6 +487,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Đặt proxy chung của điện thoại được sử dụng trong khi chính sách được bật. Chỉ quản trị viên đầu tiên của điện thoại mới có thể đặt proxy chung hiệu quả."</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"Đặt hết hạn mật khẩu"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"Kiểm soát thời lượng trước khi mật khẩu khóa màn hình cần được thay đổi"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Nhà riêng"</item>
     <item msgid="869923650527136615">"ĐT di động"</item>
@@ -900,6 +904,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Gỡ lỗi USB đã được kết nối"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"Chọn để vô hiệu hoá gỡ lỗi USB."</string>
     <string name="select_input_method" msgid="6865512749462072765">"Chọn phương thức nhập"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ứng viên"</u></string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 1cfc5cf..ecfdd63 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"请设置在启用政策的情况下要使用的设备全局代理。只有第一设备管理员才可设置有效的全局代理。"</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"设置密码有效期"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"控制屏幕锁定密码的使用期限"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"住宅"</item>
     <item msgid="869923650527136615">"手机"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"已连接 USB 调试"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"选择停用 USB 调试。"</string>
     <string name="select_input_method" msgid="6865512749462072765">"选择输入法"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"候选"</u></string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index d0f460f..28cb8b2 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -490,6 +490,10 @@
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"設定政策啟用時所要使用的裝置全域 Proxy,只有第一個裝置管理員所設定的全域 Proxy 具有效力。"</string>
     <string name="policylab_expirePassword" msgid="2314569545488269564">"設定密碼到期日"</string>
     <string name="policydesc_expirePassword" msgid="7276906351852798814">"控制螢幕鎖定密碼的使用期限"</string>
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2504984732631479399) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"住家電話"</item>
     <item msgid="869923650527136615">"行動電話"</item>
@@ -905,6 +909,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB 偵錯模式已啟用"</string>
     <string name="adb_active_notification_message" msgid="8470296818270110396">"選取以停用 USB 偵錯。"</string>
     <string name="select_input_method" msgid="6865512749462072765">"選取輸入方式"</string>
+    <!-- no translation found for configure_input_methods (6324843080254191535) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 19e2b8d..de233c8 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -362,6 +362,15 @@
              pointer will go until that pointers go up thereby enabling touches
              with multiple pointers to be split across multiple windows. -->
         <attr name="windowEnableSplitTouch" format="boolean" />
+        
+        <!-- Control whether a container should automatically close itself if
+             the user touches outside of it.  This only applies to activities
+             and dialogs.
+             
+             <p>Note: this attribute will only be respected for applications
+             that are targeting {@link android.os.Build.VERSION_CODES#HONEYCOMB}
+             or later. -->
+        <attr name="windowCloseOnTouchOutside" format="boolean" />
 
         <!-- ============ -->
         <!-- Alert Dialog styles -->
@@ -1342,6 +1351,7 @@
         <attr name="windowActionModeOverlay" />
         <attr name="windowActionBarOverlay" />
         <attr name="windowEnableSplitTouch" />
+        <attr name="windowCloseOnTouchOutside" />
         <!-- The minimum width the window is allowed to be, along the major
              axis of the screen.  That is, when in landscape.  Can be either
              an absolute dimension or a fraction of the screen size in that
@@ -1379,10 +1389,8 @@
         <attr name="fragmentOpenExitAnimation" format="reference" />
         <attr name="fragmentCloseEnterAnimation" format="reference" />
         <attr name="fragmentCloseExitAnimation" format="reference" />
-        <attr name="fragmentNextEnterAnimation" format="reference" />
-        <attr name="fragmentNextExitAnimation" format="reference" />
-        <attr name="fragmentPrevEnterAnimation" format="reference" />
-        <attr name="fragmentPrevExitAnimation" format="reference" />
+        <attr name="fragmentFadeEnterAnimation" format="reference" />
+        <attr name="fragmentFadeExitAnimation" format="reference" />
     </declare-styleable>
 
     <!-- Window animation class attributes. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8bb05fb..e0c26d4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -81,6 +81,10 @@
          specified for -large and -xlarge configurations. -->
     <dimen name="config_prefDialogWidth">0px</dimen>
     
+    <!-- Whether dialogs should close automatically when the user touches outside
+         of them.  This should not normally be modified. -->
+    <bool name="config_closeDialogWhenTouchOutside">false</bool>
+    
     <!-- The duration (in milliseconds) that the radio will scan for a signal
          when there's no network connection. If the scan doesn't timeout, use zero -->
     <integer name="config_radioScanningTimeout">0</integer>
@@ -433,7 +437,14 @@
          from the touch driver. This code exists for one particular device,
          and should not be enabled for any others. -->
     <bool name="config_filterJumpyTouchEvents">false</bool>
-    
+
+    <!-- Specifies the amount of time to disable virtual keys after the screen is touched
+         in order to filter out accidental virtual key presses due to swiping gestures
+         or taps near the edge of the display.  May be 0 to disable the feature.
+         It is recommended that this value be no more than 250 ms.
+         This feature should be disabled for most devices. -->
+    <integer name="config_virtualKeyQuietTimeMillis">0</integer>
+
     <!-- Component name of the default wallpaper. This will be ImageWallpaper if not 
          specified -->
     <string name="default_wallpaper_component">@null</string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 3ad29c4..1b47b54 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1311,10 +1311,8 @@
   <public type="attr" name="fragmentOpenExitAnimation" />
   <public type="attr" name="fragmentCloseEnterAnimation" />
   <public type="attr" name="fragmentCloseExitAnimation" />
-  <public type="attr" name="fragmentNextEnterAnimation" />
-  <public type="attr" name="fragmentNextExitAnimation" />
-  <public type="attr" name="fragmentPrevEnterAnimation" />
-  <public type="attr" name="fragmentPrevExitAnimation" />
+  <public type="attr" name="fragmentFadeEnterAnimation" />
+  <public type="attr" name="fragmentFadeExitAnimation" />
   <public type="attr" name="actionBarSize" />
   <public type="attr" name="imeSubtypeLocale" />
   <public type="attr" name="imeSubtypeMode" />
@@ -1427,6 +1425,7 @@
   <public type="attr" name="queryHint" />
   <public type="attr" name="fastScrollTextColor" />
   <public type="attr" name="largeHeap" />
+  <public type="attr" name="windowCloseOnTouchOutside" />
 
   <!-- A simple fade-in animation. -->
   <public type="animator" name="fade_in" id="0x010b0000" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2658b53..9a1b42d 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -681,6 +681,12 @@
         interface of a wallpaper. Should never be needed for normal applications.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bindRemoteViews">bind to a widget service</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bindRemoteViews">Allows the holder to bind to the top-level
+        interface of a widget service. Should never be needed for normal applications.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bindDeviceAdmin">interact with a device admin</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bindDeviceAdmin">Allows the holder to send intents to
@@ -1784,6 +1790,8 @@
     <string name="lockscreen_glogin_submit_button">Sign in</string>
     <!-- Displayed to the user when unlocking the phone with a username and password fails. -->
     <string name="lockscreen_glogin_invalid_input">Invalid username or password.</string>
+    <!-- Hint displayed on account unlock screen to advise the user on how to recover the account. -->
+    <string name="lockscreen_glogin_account_recovery_hint">Forgot your username or password\?\nVisit <b>google.com/accounts/recovery</b></string>
 
     <!-- Displayed in a progress dialog while a username and password are being checked. -->
     <string name="lockscreen_glogin_checking_password">Checking...</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index c4e815e..16c80d0 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -85,10 +85,8 @@
         <item name="fragmentOpenExitAnimation">@animator/fragment_open_exit</item>
         <item name="fragmentCloseEnterAnimation">@animator/fragment_close_enter</item>
         <item name="fragmentCloseExitAnimation">@animator/fragment_close_exit</item>
-        <item name="fragmentNextEnterAnimation">@animator/fragment_next_enter</item>
-        <item name="fragmentNextExitAnimation">@animator/fragment_next_exit</item>
-        <item name="fragmentPrevEnterAnimation">@animator/fragment_prev_enter</item>
-        <item name="fragmentPrevExitAnimation">@animator/fragment_prev_exit</item>
+        <item name="fragmentFadeEnterAnimation">@animator/fragment_fade_enter</item>
+        <item name="fragmentFadeExitAnimation">@animator/fragment_fade_exit</item>
     </style>
 
     <!-- Standard animations for a non-full-screen window or activity. -->
@@ -889,22 +887,66 @@
         <item name="android:positiveButtonText">@android:string/ok</item>
         <item name="android:negativeButtonText">@android:string/cancel</item>
     </style>
-    
+
     <style name="Preference.DialogPreference.YesNoPreference">
         <item name="android:positiveButtonText">@android:string/yes</item>
         <item name="android:negativeButtonText">@android:string/no</item>
     </style>
-    
+
     <style name="Preference.DialogPreference.EditTextPreference">
         <item name="android:dialogLayout">@android:layout/preference_dialog_edittext</item>
     </style>
-    
+
     <style name="Preference.RingtonePreference">
         <item name="android:ringtoneType">ringtone</item>
         <item name="android:showSilent">true</item>
         <item name="android:showDefault">true</item>
     </style>
 
+    <style name="Preference.Holo">
+        <item name="android:layout">@android:layout/preference_holo</item>
+    </style>
+
+    <style name="Preference.Holo.Information">
+        <item name="android:layout">@android:layout/preference_information_holo</item>
+        <item name="android:enabled">false</item>
+        <item name="android:shouldDisableView">false</item>
+    </style>
+
+    <style name="Preference.Holo.Category">
+        <item name="android:layout">@android:layout/preference_category_holo</item>
+        <!-- The title should not dim if the category is disabled, instead only the preference children should dim. -->
+        <item name="android:shouldDisableView">false</item>
+        <item name="android:selectable">false</item>
+    </style>
+
+    <style name="Preference.Holo.CheckBoxPreference">
+        <item name="android:widgetLayout">@android:layout/preference_widget_checkbox</item>
+    </style>
+
+    <style name="Preference.Holo.PreferenceScreen">
+    </style>
+
+    <style name="Preference.Holo.DialogPreference">
+        <item name="android:positiveButtonText">@android:string/ok</item>
+        <item name="android:negativeButtonText">@android:string/cancel</item>
+    </style>
+
+    <style name="Preference.Holo.DialogPreference.YesNoPreference">
+        <item name="android:positiveButtonText">@android:string/yes</item>
+        <item name="android:negativeButtonText">@android:string/no</item>
+    </style>
+
+    <style name="Preference.Holo.DialogPreference.EditTextPreference">
+        <item name="android:dialogLayout">@android:layout/preference_dialog_edittext</item>
+    </style>
+
+    <style name="Preference.Holo.RingtonePreference">
+        <item name="android:ringtoneType">ringtone</item>
+        <item name="android:showSilent">true</item>
+        <item name="android:showDefault">true</item>
+    </style>
+
     <!-- No margins or background by default. Could be different for x-large screens -->
     <style name="PreferencePanel">
     </style>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 744d0d8..b257a73 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -138,6 +138,7 @@
         <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
         <item name="windowActionBar">false</item>
         <item name="windowActionModeOverlay">false</item>
+        <item name="windowCloseOnTouchOutside">false</item>
 
         <!-- Dialog attributes -->
         <item name="alertDialogStyle">@android:style/AlertDialog</item>
@@ -506,6 +507,7 @@
         <item name="android:windowContentOverlay">@null</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
         <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
+        <item name="android:windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
 
         <item name="android:colorBackgroundCacheHint">@null</item>
         
@@ -547,6 +549,7 @@
         <item name="android:backgroundDimEnabled">false</item>
         <item name="android:windowIsTranslucent">true</item>
         <item name="android:windowNoTitle">true</item>
+        <item name="android:windowCloseOnTouchOutside">false</item>
     </style>
 
     <!-- Default theme for alert dialog windows, which is used by the
@@ -687,6 +690,7 @@
         <item name="windowIsFloating">true</item>
         <item name="windowContentOverlay">@null</item>
         <item name="textAppearance">@style/TextAppearance.Theme.Dialog.AppError</item>
+        <item name="android:windowCloseOnTouchOutside">false</item>
     </style>
     
     <!-- Special theme for the recent apps dialog, to allow customization
@@ -696,6 +700,7 @@
         <item name="windowBackground">@android:color/transparent</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.RecentApplications</item>
         <item name="android:textColor">@android:color/secondary_text_nofocus</item>
+        <item name="android:windowCloseOnTouchOutside">false</item>
     </style>
 
     <!-- Default theme for window that looks like a toast. -->
@@ -703,6 +708,7 @@
         <item name="android:windowBackground">@android:drawable/toast_frame</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.Toast</item>
         <item name="android:backgroundDimEnabled">false</item>
+        <item name="android:windowCloseOnTouchOutside">false</item>
     </style>
 
     <!-- Default theme with an Action Bar. -->
@@ -924,18 +930,18 @@
         <item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.Holo.QuickContactBadgeSmall.WindowLarge</item>
         <item name="listPopupWindowStyle">@android:style/Widget.Holo.ListPopupWindow</item>
         <item name="popupMenuStyle">@android:style/Widget.Holo.PopupMenu</item>
-        
+
         <!-- Preference styles -->
-        <item name="preferenceScreenStyle">@android:style/Preference.PreferenceScreen</item>
-        <item name="preferenceCategoryStyle">@android:style/Preference.Category</item>
-        <item name="preferenceStyle">@android:style/Preference</item>
-        <item name="preferenceInformationStyle">@android:style/Preference.Information</item>
-        <item name="checkBoxPreferenceStyle">@android:style/Preference.CheckBoxPreference</item>
-        <item name="yesNoPreferenceStyle">@android:style/Preference.DialogPreference.YesNoPreference</item>
-        <item name="dialogPreferenceStyle">@android:style/Preference.DialogPreference</item>
-        <item name="editTextPreferenceStyle">@android:style/Preference.DialogPreference.EditTextPreference</item>
-        <item name="ringtonePreferenceStyle">@android:style/Preference.RingtonePreference</item>
-        <item name="preferenceLayoutChild">@android:layout/preference_child</item>
+        <item name="preferenceScreenStyle">@android:style/Preference.Holo.PreferenceScreen</item>
+        <item name="preferenceCategoryStyle">@android:style/Preference.Holo.Category</item>
+        <item name="preferenceStyle">@android:style/Preference.Holo</item>
+        <item name="preferenceInformationStyle">@android:style/Preference.Holo.Information</item>
+        <item name="checkBoxPreferenceStyle">@android:style/Preference.Holo.CheckBoxPreference</item>
+        <item name="yesNoPreferenceStyle">@android:style/Preference.Holo.DialogPreference.YesNoPreference</item>
+        <item name="dialogPreferenceStyle">@android:style/Preference.Holo.DialogPreference</item>
+        <item name="editTextPreferenceStyle">@android:style/Preference.Holo.DialogPreference.EditTextPreference</item>
+        <item name="ringtonePreferenceStyle">@android:style/Preference.Holo.RingtonePreference</item>
+        <item name="preferenceLayoutChild">@android:layout/preference_child_holo</item>
         <item name="detailsElementBackground">@android:drawable/panel_bg_holo_dark</item>
 
         <!-- Search widget styles -->
@@ -1187,16 +1193,16 @@
         <item name="popupMenuStyle">@android:style/Widget.Holo.Light.PopupMenu</item>
         
         <!-- Preference styles -->
-        <item name="preferenceScreenStyle">@android:style/Preference.PreferenceScreen</item>
-        <item name="preferenceCategoryStyle">@android:style/Preference.Category</item>
-        <item name="preferenceStyle">@android:style/Preference</item>
-        <item name="preferenceInformationStyle">@android:style/Preference.Information</item>
-        <item name="checkBoxPreferenceStyle">@android:style/Preference.CheckBoxPreference</item>
-        <item name="yesNoPreferenceStyle">@android:style/Preference.DialogPreference.YesNoPreference</item>
-        <item name="dialogPreferenceStyle">@android:style/Preference.DialogPreference</item>
-        <item name="editTextPreferenceStyle">@android:style/Preference.DialogPreference.EditTextPreference</item>
-        <item name="ringtonePreferenceStyle">@android:style/Preference.RingtonePreference</item>
-        <item name="preferenceLayoutChild">@android:layout/preference_child</item>
+        <item name="preferenceScreenStyle">@android:style/Preference.Holo.PreferenceScreen</item>
+        <item name="preferenceCategoryStyle">@android:style/Preference.Holo.Category</item>
+        <item name="preferenceStyle">@android:style/Preference.Holo</item>
+        <item name="preferenceInformationStyle">@android:style/Preference.Holo.Information</item>
+        <item name="checkBoxPreferenceStyle">@android:style/Preference.Holo.CheckBoxPreference</item>
+        <item name="yesNoPreferenceStyle">@android:style/Preference.Holo.DialogPreference.YesNoPreference</item>
+        <item name="dialogPreferenceStyle">@android:style/Preference.Holo.DialogPreference</item>
+        <item name="editTextPreferenceStyle">@android:style/Preference.Holo.DialogPreference.EditTextPreference</item>
+        <item name="ringtonePreferenceStyle">@android:style/Preference.Holo.RingtonePreference</item>
+        <item name="preferenceLayoutChild">@android:layout/preference_child_holo</item>
         <item name="detailsElementBackground">@android:drawable/panel_bg_holo_light</item>
 
         <!-- Search widget styles -->
@@ -1291,6 +1297,7 @@
         <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
         <item name="android:windowActionBar">false</item>
         <item name="android:windowActionModeOverlay">true</item>
+        <item name="android:windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
 
         <item name="android:colorBackgroundCacheHint">@null</item>
 
@@ -1331,6 +1338,7 @@
         <item name="android:backgroundDimEnabled">false</item>
         <item name="android:windowIsTranslucent">true</item>
         <item name="android:windowNoTitle">true</item>
+        <item name="android:windowCloseOnTouchOutside">false</item>
     </style>
 
     <!-- Holo theme for alert dialog windows, which is used by the
@@ -1377,6 +1385,7 @@
         <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
         <item name="android:windowActionBar">false</item>
         <item name="android:windowActionModeOverlay">true</item>
+        <item name="android:windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
 
         <item name="android:colorBackgroundCacheHint">@null</item>
 
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
index 43cf06a3..96b028a 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
@@ -19,6 +19,16 @@
 import android.content.Context;
 import android.test.InstrumentationTestCase;
 
+/**
+ * Stress test suite for Bluetooth related functions.
+ *
+ * Includes tests for enabling/disabling bluetooth, enabling/disabling discoverable mode,
+ * starting/stopping scans, connecting/disconnecting to HFP, A2DP, HID, PAN profiles, and verifying
+ * that remote connections/disconnections occur for the PAN profile.
+ * <p>
+ * This test suite uses {@link android.bluetooth.BluetoothTestRunner} to for parameters such as the
+ * number of iterations and the addresses of remote Bluetooth devices.
+ */
 public class BluetoothStressTest extends InstrumentationTestCase {
     private static final String TAG = "BluetoothStressTest";
     private static final String OUTPUT_FILE = "BluetoothStressTestOutput.txt";
@@ -40,6 +50,9 @@
         mTestUtils.close();
     }
 
+    /**
+     * Stress test for enabling and disabling Bluetooth.
+     */
     public void testEnable() {
         int iterations = BluetoothTestRunner.sEnableIterations;
         if (iterations == 0) {
@@ -55,6 +68,9 @@
         }
     }
 
+    /**
+     * Stress test for putting the device in and taking the device out of discoverable mode.
+     */
     public void testDiscoverable() {
         int iterations = BluetoothTestRunner.sDiscoverableIterations;
         if (iterations == 0) {
@@ -73,6 +89,9 @@
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for starting and stopping Bluetooth scans.
+     */
     public void testScan() {
         int iterations = BluetoothTestRunner.sScanIterations;
         if (iterations == 0) {
@@ -91,6 +110,30 @@
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for enabling and disabling the PAN NAP profile.
+     */
+    public void testEnablePan() {
+        int iterations = BluetoothTestRunner.sEnablePanIterations;
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        mTestUtils.enable(adapter);
+
+        for (int i = 0; i < iterations; i++) {
+            mTestUtils.writeOutput("testEnablePan iteration " + (i + 1) + " of "
+                    + iterations);
+            mTestUtils.enablePan(adapter);
+            mTestUtils.disablePan(adapter);
+        }
+
+        mTestUtils.disable(adapter);
+    }
+
+    /**
+     * Stress test for pairing and unpairing with a remote device.
+     * <p>
+     * In this test, the local device initiates pairing with a remote device, and then unpairs with
+     * the device after the pairing has successfully completed.
+     */
     public void testPair() {
         int iterations = BluetoothTestRunner.sPairIterations;
         if (iterations == 0) {
@@ -110,6 +153,12 @@
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for accepting a pairing request and unpairing with a remote device.
+     * <p>
+     * In this test, the local device waits for a pairing request from a remote device.  It accepts
+     * the request and then unpairs after the paring has successfully completed.
+     */
     public void testAcceptPair() {
         int iterations = BluetoothTestRunner.sPairIterations;
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -125,6 +174,12 @@
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for connecting and disconnecting with an A2DP source.
+     * <p>
+     * In this test, the local device plays the role of an A2DP sink, and initiates connections and
+     * disconnections with an A2DP source.
+     */
     public void testConnectA2dp() {
         int iterations = BluetoothTestRunner.sConnectA2dpIterations;
         if (iterations == 0) {
@@ -143,10 +198,16 @@
             mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP);
         }
 
-        // TODO: Unpair from device if device can accept pairing after unpairing
+        mTestUtils.unpair(adapter, device);
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for connecting and disconnecting the HFP with a hands free device.
+     * <p>
+     * In this test, the local device plays the role of an HFP audio gateway, and initiates
+     * connections and disconnections with a hands free device.
+     */
     public void testConnectHeadset() {
         int iterations = BluetoothTestRunner.sConnectHeadsetIterations;
         if (iterations == 0) {
@@ -165,7 +226,94 @@
             mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET);
         }
 
-        // TODO: Unpair from device if device can accept pairing after unpairing
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.disable(adapter);
+    }
+
+    /**
+     * Stress test for connecting and disconnecting with a HID device.
+     * <p>
+     * In this test, the local device plays the role of a HID host, and initiates connections and
+     * disconnections with a HID device.
+     */
+    public void testConnectInput() {
+        int iterations = BluetoothTestRunner.sConnectInputIterations;
+        if (iterations == 0) {
+            return;
+        }
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sInputAddress);
+        mTestUtils.enable(adapter);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
+                BluetoothTestRunner.sPairPin);
+
+        for (int i = 0; i < iterations; i++) {
+            mTestUtils.writeOutput("connectInput iteration " + (i + 1) + " of " + iterations);
+            mTestUtils.connectInput(adapter, device);
+            mTestUtils.disconnectInput(adapter, device);
+        }
+
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.disable(adapter);
+    }
+
+    /**
+     * Stress test for connecting and disconnecting with a PAN NAP.
+     * <p>
+     * In this test, the local device plays the role of a PANU, and initiates connections and
+     * disconnections with a NAP.
+     */
+    public void testConnectPan() {
+        int iterations = BluetoothTestRunner.sConnectPanIterations;
+        if (iterations == 0) {
+            return;
+        }
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPanAddress);
+        mTestUtils.enable(adapter);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
+                BluetoothTestRunner.sPairPin);
+
+        for (int i = 0; i < iterations; i++) {
+            mTestUtils.writeOutput("connectPan iteration " + (i + 1) + " of " + iterations);
+            mTestUtils.connectPan(adapter, device);
+            mTestUtils.disconnectPan(adapter, device);
+        }
+
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.disable(adapter);
+    }
+
+    /**
+     * Stress test for verifying a PANU connecting and disconnecting with the device.
+     * <p>
+     * In this test, the local device plays the role of a NAP which a remote PANU connects and
+     * disconnects from.
+     */
+    public void testIncomingPanConnection() {
+        int iterations = BluetoothTestRunner.sConnectPanIterations;
+        if (iterations == 0) {
+            return;
+        }
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPanAddress);
+        mTestUtils.enable(adapter);
+        mTestUtils.enablePan(adapter);
+        mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sPairPasskey,
+                BluetoothTestRunner.sPairPin);
+
+        for (int i = 0; i < iterations; i++) {
+            mTestUtils.writeOutput("incomingPanConnection iteration " + (i + 1) + " of "
+                    + iterations);
+            mTestUtils.incomingPanConnection(adapter, device);
+            mTestUtils.incomingPanDisconnection(adapter, device);
+        }
+
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.disablePan(adapter);
         mTestUtils.disable(adapter);
     }
 }
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
index 3e589fc..cede05a 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
@@ -23,19 +23,51 @@
 import android.test.InstrumentationTestSuite;
 import android.util.Log;
 
+/**
+ * Instrumentation test runner for Bluetooth tests.
+ * <p>
+ * To run:
+ * <pre>
+ * {@code
+ * adb shell am instrument \
+ *     [-e enable_iterations <iterations>] \
+ *     [-e discoverable_iterations <iterations>] \
+ *     [-e scan_iterations <iterations>] \
+ *     [-e enable_pan_iterations <iterations>] \
+ *     [-e pair_iterations <iterations>] \
+ *     [-e connect_a2dp_iterations <iterations>] \
+ *     [-e connect_headset_iterations <iterations>] \
+ *     [-e connect_input_iterations <iterations>] \
+ *     [-e connect_pan_iterations <iterations>] \
+ *     [-e pair_address <address>] \
+ *     [-e headset_address <address>] \
+ *     [-e a2dp_address <address>] \
+ *     [-e input_address <address>] \
+ *     [-e pan_address <address>] \
+ *     [-e pair_pin <pin>] \
+ *     [-e pair_passkey <passkey>] \
+ *     -w com.android.frameworks.coretests/android.bluetooth.BluetoothTestRunner
+ * }
+ * </pre>
+ */
 public class BluetoothTestRunner extends InstrumentationTestRunner {
     private static final String TAG = "BluetoothTestRunner";
 
     public static int sEnableIterations = 100;
     public static int sDiscoverableIterations = 1000;
     public static int sScanIterations = 1000;
+    public static int sEnablePanIterations = 1000;
     public static int sPairIterations = 100;
     public static int sConnectHeadsetIterations = 100;
     public static int sConnectA2dpIterations = 100;
+    public static int sConnectInputIterations = 100;
+    public static int sConnectPanIterations = 100;
 
     public static String sPairAddress = "";
     public static String sHeadsetAddress = "";
     public static String sA2dpAddress = "";
+    public static String sInputAddress = "";
+    public static String sPanAddress = "";
 
     public static byte[] sPairPin = {'1', '2', '3', '4'};
     public static int sPairPasskey = 123456;
@@ -81,6 +113,15 @@
             }
         }
 
+        val = arguments.getString("enable_pan_iterations");
+        if (val != null) {
+            try {
+                sEnablePanIterations = Integer.parseInt(val);
+            } catch (NumberFormatException e) {
+                // Invalid argument, fall back to default value
+            }
+        }
+
         val = arguments.getString("pair_iterations");
         if (val != null) {
             try {
@@ -108,6 +149,24 @@
             }
         }
 
+        val = arguments.getString("connect_input_iterations");
+        if (val != null) {
+            try {
+                sConnectInputIterations = Integer.parseInt(val);
+            } catch (NumberFormatException e) {
+                // Invalid argument, fall back to default value
+            }
+        }
+
+        val = arguments.getString("connect_pan_iterations");
+        if (val != null) {
+            try {
+                sConnectPanIterations = Integer.parseInt(val);
+            } catch (NumberFormatException e) {
+                // Invalid argument, fall back to default value
+            }
+        }
+
         val = arguments.getString("pair_address");
         if (val != null) {
             sPairAddress = val;
@@ -123,6 +182,16 @@
             sA2dpAddress = val;
         }
 
+        val = arguments.getString("input_address");
+        if (val != null) {
+            sInputAddress = val;
+        }
+
+        val = arguments.getString("pan_address");
+        if (val != null) {
+            sPanAddress = val;
+        }
+
         val = arguments.getString("pair_pin");
         if (val != null) {
             sPairPin = BluetoothDevice.convertPinToBytes(val);
@@ -143,9 +212,13 @@
         Log.i(TAG, String.format("pair_iterations=%d", sPairIterations));
         Log.i(TAG, String.format("connect_a2dp_iterations=%d", sConnectA2dpIterations));
         Log.i(TAG, String.format("connect_headset_iterations=%d", sConnectHeadsetIterations));
+        Log.i(TAG, String.format("connect_input_iterations=%d", sConnectInputIterations));
+        Log.i(TAG, String.format("connect_pan_iterations=%d", sConnectPanIterations));
         Log.i(TAG, String.format("pair_address=%s", sPairAddress));
         Log.i(TAG, String.format("a2dp_address=%s", sA2dpAddress));
         Log.i(TAG, String.format("headset_address=%s", sHeadsetAddress));
+        Log.i(TAG, String.format("input_address=%s", sInputAddress));
+        Log.i(TAG, String.format("pan_address=%s", sPanAddress));
         Log.i(TAG, String.format("pair_pin=%s", new String(sPairPin)));
         Log.i(TAG, String.format("pair_passkey=%d", sPairPasskey));
 
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
index 6da38a7..effed76 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
@@ -35,49 +35,29 @@
 public class BluetoothTestUtils extends Assert {
 
     /**
-     * Timeout for {@link BluetoothAdapter#disable()} in ms.
+     * Timeout for enable/disable in ms.
      */
-    private static final int DISABLE_TIMEOUT = 20000;
+    private static final int ENABLE_DISABLE_TIMEOUT = 20000;
 
     /**
-     * Timeout for {@link BluetoothAdapter#enable()} in ms.
+     * Timeout for discoverable/undiscoverable in ms.
      */
-    private static final int ENABLE_TIMEOUT = 20000;
+    private static final int DISCOVERABLE_UNDISCOVERABLE_TIMEOUT = 5000;
 
     /**
-     * Timeout for {@link BluetoothAdapter#setScanMode(int)} in ms.
+     * Timeout for starting/stopping a scan in ms.
      */
-    private static final int SET_SCAN_MODE_TIMEOUT = 5000;
+    private static final int START_STOP_SCAN_TIMEOUT = 5000;
 
     /**
-     * Timeout for {@link BluetoothAdapter#startDiscovery()} in ms.
+     * Timeout for pair/unpair in ms.
      */
-    private static final int START_DISCOVERY_TIMEOUT = 5000;
+    private static final int PAIR_UNPAIR_TIMEOUT = 20000;
 
     /**
-     * Timeout for {@link BluetoothAdapter#cancelDiscovery()} in ms.
+     * Timeout for connecting/disconnecting a profile in ms.
      */
-    private static final int CANCEL_DISCOVERY_TIMEOUT = 5000;
-
-    /**
-     * Timeout for {@link BluetoothDevice#createBond()} in ms.
-     */
-    private static final int PAIR_TIMEOUT = 20000;
-
-    /**
-     * Timeout for {@link BluetoothDevice#removeBond()} in ms.
-     */
-    private static final int UNPAIR_TIMEOUT = 20000;
-
-    /**
-     * Timeout for {@link BluetoothProfile#connect(BluetoothDevice)} in ms.
-     */
-    private static final int CONNECT_PROFILE_TIMEOUT = 20000;
-
-    /**
-     * Timeout for {@link BluetoothProfile#disconnect(BluetoothDevice)} in ms.
-     */
-    private static final int DISCONNECT_PROFILE_TIMEOUT = 20000;
+    private static final int CONNECT_DISCONNECT_PROFILE_TIMEOUT = 20000;
 
     /**
      * Timeout to connect a profile proxy in ms.
@@ -265,7 +245,6 @@
 
         @Override
         public void onReceive(Context context, Intent intent) {
-
             if (mConnectionAction != null && mConnectionAction.equals(intent.getAction())) {
                 if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
                     return;
@@ -291,6 +270,91 @@
         }
     }
 
+    private class ConnectInputReceiver extends FlagReceiver {
+        private static final int STATE_DISCONNECTED_FLAG = 1;
+        private static final int STATE_CONNECTING_FLAG = 1 << 1;
+        private static final int STATE_CONNECTED_FLAG = 1 << 2;
+        private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
+
+        private BluetoothDevice mDevice;
+
+        public ConnectInputReceiver(BluetoothDevice device, int expectedFlags) {
+            super(expectedFlags);
+
+            mDevice = device;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
+                return;
+            }
+
+            if (BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED.equals(intent.getAction())) {
+                int state = intent.getIntExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, -1);
+                assertNotSame(-1, state);
+                switch (state) {
+                    case BluetoothInputDevice.STATE_DISCONNECTED:
+                        setFiredFlag(STATE_DISCONNECTED_FLAG);
+                        break;
+                    case BluetoothInputDevice.STATE_CONNECTING:
+                        setFiredFlag(STATE_CONNECTING_FLAG);
+                        break;
+                    case BluetoothInputDevice.STATE_CONNECTED:
+                        setFiredFlag(STATE_CONNECTED_FLAG);
+                        break;
+                    case BluetoothInputDevice.STATE_DISCONNECTING:
+                        setFiredFlag(STATE_DISCONNECTING_FLAG);
+                        break;
+                }
+            }
+        }
+    }
+
+    private class ConnectPanReceiver extends FlagReceiver {
+        private static final int STATE_DISCONNECTED_FLAG = 1;
+        private static final int STATE_CONNECTING_FLAG = 1 << 1;
+        private static final int STATE_CONNECTED_FLAG = 1 << 2;
+        private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
+
+        private BluetoothDevice mDevice;
+        private int mRole;
+
+        public ConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags) {
+            super (expectedFlags);
+
+            mDevice = device;
+            mRole = role;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))
+                    || mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
+                return;
+            }
+
+            if (BluetoothPan.ACTION_PAN_STATE_CHANGED.equals(intent.getAction())) {
+                int state = intent.getIntExtra(BluetoothPan.EXTRA_PAN_STATE, -1);
+                assertNotSame(-1, state);
+                switch (state) {
+                    case BluetoothPan.STATE_DISCONNECTED:
+                        setFiredFlag(STATE_DISCONNECTED_FLAG);
+                        break;
+                    case BluetoothPan.STATE_CONNECTING:
+                        setFiredFlag(STATE_CONNECTING_FLAG);
+                        break;
+                    case BluetoothPan.STATE_CONNECTED:
+                        setFiredFlag(STATE_CONNECTED_FLAG);
+                        break;
+                    case BluetoothPan.STATE_DISCONNECTING:
+                        setFiredFlag(STATE_DISCONNECTING_FLAG);
+                        break;
+                }
+            }
+        }
+    }
+
     private BluetoothProfile.ServiceListener mServiceListener =
             new BluetoothProfile.ServiceListener() {
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
@@ -330,10 +394,24 @@
     private BluetoothA2dp mA2dp;
     private BluetoothHeadset mHeadset;
 
+    /**
+     * Creates a utility instance for testing Bluetooth.
+     *
+     * @param context The context of the application using the utility.
+     * @param tag The log tag of the application using the utility.
+     */
     public BluetoothTestUtils(Context context, String tag) {
         this(context, tag, null);
     }
 
+    /**
+     * Creates a utility instance for testing Bluetooth.
+     *
+     * @param context The context of the application using the utility.
+     * @param tag The log tag of the application using the utility.
+     * @param outputFile The path to an output file if the utility is to write results to a
+     *        separate file.
+     */
     public BluetoothTestUtils(Context context, String tag, String outputFile) {
         mContext = context;
         mTag = tag;
@@ -352,6 +430,9 @@
         }
     }
 
+    /**
+     * Closes the utility instance and unregisters any BroadcastReceivers.
+     */
     public void close() {
         while (!mReceivers.isEmpty()) {
             mContext.unregisterReceiver(mReceivers.remove(0));
@@ -366,6 +447,12 @@
         }
     }
 
+    /**
+     * Enables Bluetooth and checks to make sure that Bluetooth was turned on and that the correct
+     * actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void enable(BluetoothAdapter adapter) {
         int mask = (BluetoothReceiver.STATE_TURNING_ON_FLAG | BluetoothReceiver.STATE_ON_FLAG
                 | BluetoothReceiver.SCAN_MODE_CONNECTABLE_FLAG);
@@ -397,22 +484,19 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < ENABLE_TIMEOUT) {
+        while (System.currentTimeMillis() - s < ENABLE_DISABLE_TIMEOUT) {
             state = adapter.getState();
-            if (state == BluetoothAdapter.STATE_ON) {
+            if (state == BluetoothAdapter.STATE_ON
+                    && (receiver.getFiredFlags() & mask) == mask) {
                 assertTrue(adapter.isEnabled());
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("enable() completed in %d ms", (finish - start)));
-                    } else {
-                        writeOutput("enable() completed");
-                    }
-                    removeReceiver(receiver);
-                    return;
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("enable() completed in %d ms", (finish - start)));
+                } else {
+                    writeOutput("enable() completed");
                 }
-            } else {
-                assertEquals(BluetoothAdapter.STATE_TURNING_ON, state);
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -423,6 +507,12 @@
                 state, BluetoothAdapter.STATE_ON, firedFlags, mask));
     }
 
+    /**
+     * Disables Bluetooth and checks to make sure that Bluetooth was turned off and that the correct
+     * actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void disable(BluetoothAdapter adapter) {
         int mask = (BluetoothReceiver.STATE_TURNING_OFF_FLAG | BluetoothReceiver.STATE_OFF_FLAG
                 | BluetoothReceiver.SCAN_MODE_NONE_FLAG);
@@ -454,23 +544,19 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < DISABLE_TIMEOUT) {
+        while (System.currentTimeMillis() - s < ENABLE_DISABLE_TIMEOUT) {
             state = adapter.getState();
-            if (state == BluetoothAdapter.STATE_OFF) {
+            if (state == BluetoothAdapter.STATE_OFF
+                    && (receiver.getFiredFlags() & mask) == mask) {
                 assertFalse(adapter.isEnabled());
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("disable() completed in %d ms",
-                                (finish - start)));
-                    } else {
-                        writeOutput("disable() completed");
-                    }
-                    removeReceiver(receiver);
-                    return;
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("disable() completed in %d ms", (finish - start)));
+                } else {
+                    writeOutput("disable() completed");
                 }
-            } else {
-                assertEquals(BluetoothAdapter.STATE_TURNING_OFF, state);
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -481,6 +567,12 @@
                 state, BluetoothAdapter.STATE_OFF, firedFlags, mask));
     }
 
+    /**
+     * Puts the local device into discoverable mode and checks to make sure that the local device
+     * is in discoverable mode and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void discoverable(BluetoothAdapter adapter) {
         int mask = BluetoothReceiver.SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG;
 
@@ -499,17 +591,14 @@
         long start = System.currentTimeMillis();
         assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
 
-        while (System.currentTimeMillis() - start < SET_SCAN_MODE_TIMEOUT) {
+        while (System.currentTimeMillis() - start < DISCOVERABLE_UNDISCOVERABLE_TIMEOUT) {
             scanMode = adapter.getScanMode();
-            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    writeOutput(String.format("discoverable() completed in %d ms",
-                            (receiver.getCompletedTime() - start)));
-                    removeReceiver(receiver);
-                    return;
-                }
-            } else {
-                assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE, scanMode);
+            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                writeOutput(String.format("discoverable() completed in %d ms",
+                        (receiver.getCompletedTime() - start)));
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -521,6 +610,12 @@
                 firedFlags, mask));
     }
 
+    /**
+     * Puts the local device into connectable only mode and checks to make sure that the local
+     * device is in in connectable mode and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void undiscoverable(BluetoothAdapter adapter) {
         int mask = BluetoothReceiver.SCAN_MODE_CONNECTABLE_FLAG;
 
@@ -539,17 +634,14 @@
         long start = System.currentTimeMillis();
         assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));
 
-        while (System.currentTimeMillis() - start < SET_SCAN_MODE_TIMEOUT) {
+        while (System.currentTimeMillis() - start < DISCOVERABLE_UNDISCOVERABLE_TIMEOUT) {
             scanMode = adapter.getScanMode();
-            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    writeOutput(String.format("undiscoverable() completed in %d ms",
-                            (receiver.getCompletedTime() - start)));
-                    removeReceiver(receiver);
-                    return;
-                }
-            } else {
-                assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, scanMode);
+            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                writeOutput(String.format("undiscoverable() completed in %d ms",
+                        (receiver.getCompletedTime() - start)));
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -561,6 +653,12 @@
                 mask));
     }
 
+    /**
+     * Starts a scan for remote devices and checks to make sure that the local device is scanning
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void startScan(BluetoothAdapter adapter) {
         int mask = BluetoothReceiver.DISCOVERY_STARTED_FLAG;
 
@@ -577,7 +675,7 @@
         long start = System.currentTimeMillis();
         assertTrue(adapter.startDiscovery());
 
-        while (System.currentTimeMillis() - start < START_DISCOVERY_TIMEOUT) {
+        while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
             if (adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
                 writeOutput(String.format("startScan() completed in %d ms",
                         (receiver.getCompletedTime() - start)));
@@ -593,6 +691,12 @@
                 adapter.isDiscovering(), firedFlags, mask));
     }
 
+    /**
+     * Stops a scan for remote devices and checks to make sure that the local device is not scanning
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void stopScan(BluetoothAdapter adapter) {
         int mask = BluetoothReceiver.DISCOVERY_FINISHED_FLAG;
 
@@ -610,7 +714,7 @@
         // TODO: put assertTrue() around cancelDiscovery() once it starts returning true.
         adapter.cancelDiscovery();
 
-        while (System.currentTimeMillis() - start < CANCEL_DISCOVERY_TIMEOUT) {
+        while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
             if (!adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
                 writeOutput(String.format("stopScan() completed in %d ms",
                         (receiver.getCompletedTime() - start)));
@@ -627,20 +731,84 @@
 
     }
 
+    /**
+     * Enables PAN tethering on the local device and checks to make sure that tethering is enabled.
+     *
+     * @param adapter The BT adapter.
+     */
+    public void enablePan(BluetoothAdapter adapter) {
+        BluetoothPan pan = new BluetoothPan(mContext);
+        assertNotNull(pan);
+
+        long start = System.currentTimeMillis();
+        pan.setBluetoothTethering(true);
+        long stop = System.currentTimeMillis();
+        assertTrue(pan.isTetheringOn());
+
+        writeOutput(String.format("enablePan() completed in %d ms", (stop - start)));
+    }
+
+    /**
+     * Disables PAN tethering on the local device and checks to make sure that tethering is
+     * disabled.
+     *
+     * @param adapter The BT adapter.
+     */
+    public void disablePan(BluetoothAdapter adapter) {
+        BluetoothPan pan = new BluetoothPan(mContext);
+        assertNotNull(pan);
+
+        long start = System.currentTimeMillis();
+        pan.setBluetoothTethering(false);
+        long stop = System.currentTimeMillis();
+        assertFalse(pan.isTetheringOn());
+
+        writeOutput(String.format("disablePan() completed in %d ms", (stop - start)));
+    }
+
+    /**
+     * Initiates a pairing with a remote device and checks to make sure that the devices are paired
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
+     * @param pin The pairing pin if pairing requires a pin. Any value if not.
+     */
     public void pair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, byte[] pin) {
         pairOrAcceptPair(adapter, device, passkey, pin, true);
     }
 
+    /**
+     * Accepts a pairing with a remote device and checks to make sure that the devices are paired
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
+     * @param pin The pairing pin if pairing requires a pin. Any value if not.
+     */
     public void acceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
             byte[] pin) {
         pairOrAcceptPair(adapter, device, passkey, pin, false);
     }
 
+    /**
+     * Helper method used by {@link #pair(BluetoothAdapter, BluetoothDevice, int, byte[])} and
+     * {@link #acceptPair(BluetoothAdapter, BluetoothDevice, int, byte[])} to either pair or accept
+     * a pairing request.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
+     * @param pin The pairing pin if pairing requires a pin. Any value if not.
+     * @param shouldPair Whether to pair or accept the pair.
+     */
     private void pairOrAcceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
-            byte[] pin, boolean pair) {
+            byte[] pin, boolean shouldPair) {
         int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG;
         long start = -1;
-        String methodName = pair ? "pair()" : "acceptPair()";
+        String methodName = shouldPair ? "pair()" : "acceptPair()";
 
         if (!adapter.isEnabled()) {
             fail(methodName + " bluetooth not enabled");
@@ -653,7 +821,7 @@
             case BluetoothDevice.BOND_NONE:
                 assertFalse(adapter.getBondedDevices().contains(device));
                 start = System.currentTimeMillis();
-                if (pair) {
+                if (shouldPair) {
                     assertTrue(device.createBond());
                 }
                 break;
@@ -670,21 +838,19 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < PAIR_TIMEOUT) {
+        while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
             state = device.getBondState();
-            if (state == BluetoothDevice.BOND_BONDED) {
+            if (state == BluetoothDevice.BOND_BONDED && (receiver.getFiredFlags() & mask) == mask) {
                 assertTrue(adapter.getBondedDevices().contains(device));
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
-                                (finish - start), device));
-                    } else {
-                        writeOutput(String.format("%s completed: device=%s", methodName, device));
-                    }
-                    removeReceiver(receiver);
-                    return;
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("%s completed: device=%s", methodName, device));
                 }
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -696,6 +862,13 @@
                 BluetoothDevice.BOND_BONDED, firedFlags, mask));
     }
 
+    /**
+     * Deletes a pairing with a remote device and checks to make sure that the devices are unpaired
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
     public void unpair(BluetoothAdapter adapter, BluetoothDevice device) {
         int mask = PairReceiver.STATE_NONE_FLAG;
         long start = -1;
@@ -727,20 +900,19 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < UNPAIR_TIMEOUT) {
-            if (device.getBondState() == BluetoothDevice.BOND_NONE) {
+        while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
+            if (device.getBondState() == BluetoothDevice.BOND_NONE
+                    && (receiver.getFiredFlags() & mask) == mask) {
                 assertFalse(adapter.getBondedDevices().contains(device));
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("unpair() completed in %d ms: device=%s",
-                                (finish - start), device));
-                    } else {
-                        writeOutput(String.format("unpair() completed: device=%s", device));
-                    }
-                    removeReceiver(receiver);
-                    return;
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("unpair() completed in %d ms: device=%s",
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("unpair() completed: device=%s", device));
                 }
+                removeReceiver(receiver);
+                return;
             }
         }
 
@@ -751,6 +923,15 @@
                 firedFlags, mask));
     }
 
+    /**
+     * Connects a profile from the local device to a remote device and checks to make sure that the
+     * profile is connected and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP} or
+     *        {@link BluetoothProfile#HEADSET}.
+     */
     public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile) {
         int mask = (ConnectProfileReceiver.STATE_CONNECTING_FLAG
                 | ConnectProfileReceiver.STATE_CONNECTED_FLAG);
@@ -794,21 +975,20 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < CONNECT_PROFILE_TIMEOUT) {
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
             state = proxy.getConnectionState(device);
-            if (state == BluetoothProfile.STATE_CONNECTED) {
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("connectProfile() completed in %d ms: "
-                                + "device=%s, profile=%d", (finish - start), device, profile));
-                    } else {
-                        writeOutput(String.format("connectProfile() completed: device=%s, "
-                                + "profile=%d", device, profile));
-                    }
-                    removeReceiver(receiver);
-                    return;
+            if (state == BluetoothProfile.STATE_CONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("connectProfile() completed in %d ms: "
+                            + "device=%s, profile=%d", (finish - start), device, profile));
+                } else {
+                    writeOutput(String.format("connectProfile() completed: device=%s, "
+                            + "profile=%d", device, profile));
                 }
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -820,6 +1000,15 @@
                 BluetoothProfile.STATE_CONNECTED, firedFlags, mask));
     }
 
+    /**
+     * Disconnects a profile between the local device and a remote device and checks to make sure
+     * that the profile is disconnected and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP} or
+     *        {@link BluetoothProfile#HEADSET}.
+     */
     public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile) {
         int mask = (ConnectProfileReceiver.STATE_DISCONNECTING_FLAG
                 | ConnectProfileReceiver.STATE_DISCONNECTED_FLAG);
@@ -863,21 +1052,20 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < DISCONNECT_PROFILE_TIMEOUT) {
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
             state = proxy.getConnectionState(device);
-            if (state == BluetoothProfile.STATE_DISCONNECTED) {
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("disconnectProfile() completed in %d ms: "
-                                + "device=%s, profile=%d", (finish - start), device, profile));
-                    } else {
-                        writeOutput(String.format("disconnectProfile() completed: device=%s, "
-                                + "profile=%d", device, profile));
-                    }
-                    removeReceiver(receiver);
-                    return;
+            if (state == BluetoothProfile.STATE_DISCONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("disconnectProfile() completed in %d ms: "
+                            + "device=%s, profile=%d", (finish - start), device, profile));
+                } else {
+                    writeOutput(String.format("disconnectProfile() completed: device=%s, "
+                            + "profile=%d", device, profile));
                 }
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -889,6 +1077,360 @@
                 BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask));
     }
 
+    /**
+     * Connects the local device with a remote HID device and checks to make sure that the profile
+     * is connected and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void connectInput(BluetoothAdapter adapter, BluetoothDevice device) {
+        int mask = (ConnectInputReceiver.STATE_CONNECTING_FLAG
+                | ConnectInputReceiver.STATE_CONNECTED_FLAG);
+        long start = -1;
+
+        if (!adapter.isEnabled()) {
+            fail(String.format("connectInput() bluetooth not enabled: device=%s", device));
+        }
+
+        if (!adapter.getBondedDevices().contains(device)) {
+            fail(String.format("connectInput() device not paired: device=%s", device));
+        }
+
+        BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext);
+        assertNotNull(inputDevice);
+        ConnectInputReceiver receiver = getConnectInputReceiver(device, mask);
+
+        int state = inputDevice.getInputDeviceState(device);
+        switch (state) {
+            case BluetoothInputDevice.STATE_CONNECTED:
+                removeReceiver(receiver);
+                return;
+            case BluetoothInputDevice.STATE_CONNECTING:
+                mask = 0; // Don't check for received intents since we might have missed them.
+                break;
+            case BluetoothInputDevice.STATE_DISCONNECTED:
+            case BluetoothInputDevice.STATE_DISCONNECTING:
+                start = System.currentTimeMillis();
+                assertTrue(inputDevice.connectInputDevice(device));
+                break;
+            default:
+                removeReceiver(receiver);
+                fail(String.format("connectInput() invalid state: device=%s, state=%d", device,
+                        state));
+        }
+
+        long s = System.currentTimeMillis();
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+            state = inputDevice.getInputDeviceState(device);
+            if (state == BluetoothInputDevice.STATE_CONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("connectInput() completed in %d ms: device=%s",
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("connectInput() completed: device=%s", device));
+                }
+                removeReceiver(receiver);
+                return;
+            }
+            sleep(POLL_TIME);
+        }
+
+        int firedFlags = receiver.getFiredFlags();
+        removeReceiver(receiver);
+        fail(String.format("connectInput() timeout: device=%s, state=%d (expected %d), "
+                + "flags=0x%x (expected 0x%s)", device, state, BluetoothInputDevice.STATE_CONNECTED,
+                firedFlags, mask));
+    }
+
+    /**
+     * Disconnects the local device with a remote HID device and checks to make sure that the
+     * profile is connected and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void disconnectInput(BluetoothAdapter adapter, BluetoothDevice device) {
+        int mask = (ConnectInputReceiver.STATE_DISCONNECTING_FLAG
+                | ConnectInputReceiver.STATE_DISCONNECTED_FLAG);
+        long start = -1;
+
+        if (!adapter.isEnabled()) {
+            fail(String.format("disconnectInput() bluetooth not enabled: device=%s", device));
+        }
+
+        if (!adapter.getBondedDevices().contains(device)) {
+            fail(String.format("disconnectInput() device not paired: device=%s", device));
+        }
+
+        BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext);
+        assertNotNull(inputDevice);
+        ConnectInputReceiver receiver = getConnectInputReceiver(device, mask);
+
+        int state = inputDevice.getInputDeviceState(device);
+        switch (state) {
+            case BluetoothInputDevice.STATE_CONNECTED:
+            case BluetoothInputDevice.STATE_CONNECTING:
+                start = System.currentTimeMillis();
+                assertTrue(inputDevice.disconnectInputDevice(device));
+                break;
+            case BluetoothInputDevice.STATE_DISCONNECTED:
+                removeReceiver(receiver);
+                return;
+            case BluetoothInputDevice.STATE_DISCONNECTING:
+                mask = 0; // Don't check for received intents since we might have missed them.
+                break;
+            default:
+                removeReceiver(receiver);
+                fail(String.format("disconnectInput() invalid state: device=%s, state=%d", device,
+                        state));
+        }
+
+        long s = System.currentTimeMillis();
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+            state = inputDevice.getInputDeviceState(device);
+            if (state == BluetoothInputDevice.STATE_DISCONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("disconnectInput() completed in %d ms: device=%s",
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("disconnectInput() completed: device=%s", device));
+                }
+                removeReceiver(receiver);
+                return;
+            }
+            sleep(POLL_TIME);
+        }
+
+        int firedFlags = receiver.getFiredFlags();
+        removeReceiver(receiver);
+        fail(String.format("disconnectInput() timeout: device=%s, state=%d (expected %d), "
+                + "flags=0x%x (expected 0x%s)", device, state,
+                BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
+    }
+
+    /**
+     * Connects the PANU to a remote NAP and checks to make sure that the PANU is connected and that
+     * the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void connectPan(BluetoothAdapter adapter, BluetoothDevice device) {
+        connectPanOrIncomingPanConnection(adapter, device, true);
+    }
+
+    /**
+     * Checks that a remote PANU connects to the local NAP correctly and that the correct actions
+     * were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void incomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device) {
+        connectPanOrIncomingPanConnection(adapter, device, false);
+    }
+
+    /**
+     * Helper method used by {@link #connectPan(BluetoothAdapter, BluetoothDevice)} and
+     * {@link #incomingPanConnection(BluetoothAdapter, BluetoothDevice)} to either connect to a
+     * remote NAP or verify that a remote device connected to the local NAP.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param connect If the method should initiate the connection (is PANU)
+     */
+    private void connectPanOrIncomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device,
+            boolean connect) {
+        long start = -1;
+        int mask, role;
+        String methodName;
+
+        if (connect) {
+            methodName = "connectPan()";
+            mask = (ConnectPanReceiver.STATE_CONNECTED_FLAG |
+                    ConnectPanReceiver.STATE_CONNECTING_FLAG);
+            role = BluetoothPan.LOCAL_PANU_ROLE;
+        } else {
+            methodName = "incomingPanConnection()";
+            mask = ConnectPanReceiver.STATE_CONNECTED_FLAG;
+            role = BluetoothPan.LOCAL_NAP_ROLE;
+        }
+
+        if (!adapter.isEnabled()) {
+            fail(String.format("%s bluetooth not enabled: device=%s", methodName, device));
+        }
+
+        if (!adapter.getBondedDevices().contains(device)) {
+            fail(String.format("%s device not paired: device=%s", methodName, device));
+        }
+
+        BluetoothPan pan = new BluetoothPan(mContext);
+        assertNotNull(pan);
+        ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
+
+        int state = pan.getPanDeviceState(device);
+        switch (state) {
+            case BluetoothPan.STATE_CONNECTED:
+                removeReceiver(receiver);
+                return;
+            case BluetoothPan.STATE_CONNECTING:
+                mask = 0; // Don't check for received intents since we might have missed them.
+                break;
+            case BluetoothPan.STATE_DISCONNECTED:
+            case BluetoothPan.STATE_DISCONNECTING:
+                start = System.currentTimeMillis();
+                if (role == BluetoothPan.LOCAL_PANU_ROLE) {
+                    Log.i("BT", "connect to pan");
+                    assertTrue(pan.connect(device));
+                }
+                break;
+            default:
+                removeReceiver(receiver);
+                fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
+                        state));
+        }
+
+        long s = System.currentTimeMillis();
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+            state = pan.getPanDeviceState(device);
+            if (state == BluetoothPan.STATE_CONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("%s completed: device=%s", methodName, device));
+                }
+                removeReceiver(receiver);
+                return;
+            }
+            sleep(POLL_TIME);
+        }
+
+        int firedFlags = receiver.getFiredFlags();
+        removeReceiver(receiver);
+        fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
+                + "flags=0x%x (expected 0x%s)", methodName, device, state,
+                BluetoothPan.STATE_CONNECTED, firedFlags, mask));
+    }
+
+    /**
+     * Disconnects the PANU from a remote NAP and checks to make sure that the PANU is disconnected
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void disconnectPan(BluetoothAdapter adapter, BluetoothDevice device) {
+        disconnectFromRemoteOrVerifyConnectNap(adapter, device, true);
+    }
+
+    /**
+     * Checks that a remote PANU disconnects from the local NAP correctly and that the correct
+     * actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void incomingPanDisconnection(BluetoothAdapter adapter, BluetoothDevice device) {
+        disconnectFromRemoteOrVerifyConnectNap(adapter, device, false);
+    }
+
+    /**
+     * Helper method used by {@link #disconnectPan(BluetoothAdapter, BluetoothDevice)} and
+     * {@link #incomingPanDisconnection(BluetoothAdapter, BluetoothDevice)} to either disconnect
+     * from a remote NAP or verify that a remote device disconnected from the local NAP.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param disconnect Whether the method should connect or verify.
+     */
+    private void disconnectFromRemoteOrVerifyConnectNap(BluetoothAdapter adapter,
+            BluetoothDevice device, boolean disconnect) {
+        long start = -1;
+        int mask, role;
+        String methodName;
+
+        if (disconnect) {
+            methodName = "disconnectPan()";
+            mask = (ConnectPanReceiver.STATE_DISCONNECTED_FLAG |
+                    ConnectPanReceiver.STATE_DISCONNECTING_FLAG);
+            role = BluetoothPan.LOCAL_PANU_ROLE;
+        } else {
+            methodName = "incomingPanDisconnection()";
+            mask = ConnectPanReceiver.STATE_DISCONNECTED_FLAG;
+            role = BluetoothPan.LOCAL_NAP_ROLE;
+        }
+
+        if (!adapter.isEnabled()) {
+            fail(String.format("%s bluetooth not enabled: device=%s", methodName, device));
+        }
+
+        if (!adapter.getBondedDevices().contains(device)) {
+            fail(String.format("%s device not paired: device=%s", methodName, device));
+        }
+
+        BluetoothPan pan = new BluetoothPan(mContext);
+        assertNotNull(pan);
+        ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
+
+        int state = pan.getPanDeviceState(device);
+        switch (state) {
+            case BluetoothInputDevice.STATE_CONNECTED:
+            case BluetoothInputDevice.STATE_CONNECTING:
+                start = System.currentTimeMillis();
+                if (role == BluetoothPan.LOCAL_PANU_ROLE) {
+                    assertTrue(pan.disconnect(device));
+                }
+                break;
+            case BluetoothInputDevice.STATE_DISCONNECTED:
+                removeReceiver(receiver);
+                return;
+            case BluetoothInputDevice.STATE_DISCONNECTING:
+                mask = 0; // Don't check for received intents since we might have missed them.
+                break;
+            default:
+                removeReceiver(receiver);
+                fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
+                        state));
+        }
+
+        long s = System.currentTimeMillis();
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+            state = pan.getPanDeviceState(device);
+            if (state == BluetoothInputDevice.STATE_DISCONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("%s completed: device=%s", methodName, device));
+                }
+                removeReceiver(receiver);
+                return;
+            }
+            sleep(POLL_TIME);
+        }
+
+        int firedFlags = receiver.getFiredFlags();
+        removeReceiver(receiver);
+        fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
+                + "flags=0x%x (expected 0x%s)", methodName, device, state,
+                BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
+    }
+
+    /**
+     * Writes a string to the logcat and a file if a file has been specified in the constructor.
+     *
+     * @param s The string to be written.
+     */
     public void writeOutput(String s) {
         Log.i(mTag, s);
         if (mOutputWriter == null) {
@@ -902,38 +1444,60 @@
         }
     }
 
-    private BluetoothReceiver getBluetoothReceiver(int expectedFlags) {
-        BluetoothReceiver receiver = new BluetoothReceiver(expectedFlags);
+    private void addReceiver(BroadcastReceiver receiver, String[] actions) {
         IntentFilter filter = new IntentFilter();
-        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
-        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
-        filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
-        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+        for (String action: actions) {
+            filter.addAction(action);
+        }
         mContext.registerReceiver(receiver, filter);
         mReceivers.add(receiver);
+    }
+
+    private BluetoothReceiver getBluetoothReceiver(int expectedFlags) {
+        String[] actions = {
+                BluetoothAdapter.ACTION_DISCOVERY_FINISHED,
+                BluetoothAdapter.ACTION_DISCOVERY_STARTED,
+                BluetoothAdapter.ACTION_SCAN_MODE_CHANGED,
+                BluetoothAdapter.ACTION_STATE_CHANGED};
+        BluetoothReceiver receiver = new BluetoothReceiver(expectedFlags);
+        addReceiver(receiver, actions);
         return receiver;
     }
 
     private PairReceiver getPairReceiver(BluetoothDevice device, int passkey, byte[] pin,
             int expectedFlags) {
+        String[] actions = {
+                BluetoothDevice.ACTION_PAIRING_REQUEST,
+                BluetoothDevice.ACTION_BOND_STATE_CHANGED};
         PairReceiver receiver = new PairReceiver(device, passkey, pin, expectedFlags);
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
-        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
-        mContext.registerReceiver(receiver, filter);
-        mReceivers.add(receiver);
+        addReceiver(receiver, actions);
         return receiver;
     }
 
     private ConnectProfileReceiver getConnectProfileReceiver(BluetoothDevice device, int profile,
             int expectedFlags) {
+        String[] actions = {
+                BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED,
+                BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED};
         ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile,
                 expectedFlags);
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
-        filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
-        mContext.registerReceiver(receiver, filter);
-        mReceivers.add(receiver);
+        addReceiver(receiver, actions);
+        return receiver;
+    }
+
+    private ConnectInputReceiver getConnectInputReceiver(BluetoothDevice device,
+            int expectedFlags) {
+        String[] actions = {BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED};
+        ConnectInputReceiver receiver = new ConnectInputReceiver(device, expectedFlags);
+        addReceiver(receiver, actions);
+        return receiver;
+    }
+
+    private ConnectPanReceiver getConnectPanReceiver(BluetoothDevice device, int role,
+            int expectedFlags) {
+        String[] actions = {BluetoothPan.ACTION_PAN_STATE_CHANGED};
+        ConnectPanReceiver receiver = new ConnectPanReceiver(device, role, expectedFlags);
+        addReceiver(receiver, actions);
         return receiver;
     }
 
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 2126529..0e65df5 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -48,7 +48,6 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Arrays;
 
 public class PackageManagerTests extends AndroidTestCase {
     private static final boolean localLOGV = true;
@@ -3106,164 +3105,6 @@
                 PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
     }
 
-    @LargeTest
-    public void testPackageObbPaths_Nonexistent() {
-        try {
-            final PackageManager pm = getPm();
-
-            // Invalid Java package name.
-            pm.getPackageObbPaths("=non-existent");
-
-            fail("Should not be able to get package OBB paths for non-existent package");
-        } catch (IllegalArgumentException e) {
-            // pass
-        }
-    }
-
-    @LargeTest
-    public void testPackageObbPaths_Initial() {
-        InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false);
-
-        try {
-            final PackageManager pm = getPm();
-
-            assertEquals("Initial obb paths should be null",
-                    null, pm.getPackageObbPaths(ip.pkg.packageName));
-        } finally {
-            cleanUpInstall(ip);
-        }
-    }
-
-    @LargeTest
-    public void testPackageObbPaths_Null() {
-        InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false);
-
-        try {
-            final PackageManager pm = getPm();
-
-            pm.setPackageObbPaths(ip.pkg.packageName, null);
-
-            assertEquals("Returned paths should be null",
-                    null, pm.getPackageObbPaths(ip.pkg.packageName));
-        } finally {
-            cleanUpInstall(ip);
-        }
-    }
-
-    @LargeTest
-    public void testPackageObbPaths_Empty() {
-        InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false);
-
-        try {
-            final PackageManager pm = getPm();
-
-            final String[] paths = new String[0];
-
-            pm.setPackageObbPaths(ip.pkg.packageName, paths);
-
-            assertEquals("Empty list should be interpreted as null",
-                    null, pm.getPackageObbPaths(ip.pkg.packageName));
-        } finally {
-            cleanUpInstall(ip);
-        }
-    }
-
-    @LargeTest
-    public void testPackageObbPaths_Single() {
-        InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false);
-
-        try {
-            final PackageManager pm = getPm();
-
-            final String[] paths = new String[] {
-                "/example/test",
-            };
-
-            pm.setPackageObbPaths(ip.pkg.packageName, paths.clone());
-
-            assertTrue("Previously set paths should be the same as the returned paths.",
-                    Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName)));
-        } finally {
-            cleanUpInstall(ip);
-        }
-    }
-
-    @LargeTest
-    public void testPackageObbPaths_Multiple() {
-        InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false);
-
-        try {
-            final PackageManager pm = getPm();
-
-            final String[] paths = new String[] {
-                    "/example/test1",
-                    "/example/test2",
-            };
-
-            pm.setPackageObbPaths(ip.pkg.packageName, paths.clone());
-
-            assertTrue("Previously set paths should be the same as the returned paths.",
-                    Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName)));
-        } finally {
-            cleanUpInstall(ip);
-        }
-    }
-
-    @LargeTest
-    public void testPackageObbPaths_Twice() {
-        InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false);
-
-        try {
-            final PackageManager pm = getPm();
-
-            final String[] paths = new String[] {
-                    "/example/test1",
-                    "/example/test2",
-            };
-
-            pm.setPackageObbPaths(ip.pkg.packageName, paths.clone());
-
-            assertTrue("Previously set paths should be the same as the returned paths.",
-                    Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName)));
-
-            paths[0] = "/example/test3";
-            pm.setPackageObbPaths(ip.pkg.packageName, paths.clone());
-
-            assertTrue("Previously set paths should be the same as the returned paths.",
-                    Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName)));
-        } finally {
-            cleanUpInstall(ip);
-        }
-    }
-
-    @LargeTest
-    public void testPackageObbPaths_ReplacePackage() {
-        InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false);
-
-        try {
-            final PackageManager pm = getPm();
-
-            final String[] paths = new String[] {
-                    "/example/test1",
-                    "/example/test2",
-            };
-
-            pm.setPackageObbPaths(ip.pkg.packageName, paths.clone());
-
-            Log.i(TAG, "Creating replaceReceiver");
-            final GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName);
-
-            final int flags = PackageManager.INSTALL_REPLACE_EXISTING;
-            invokeInstallPackage(ip.packageURI, flags, receiver);
-            assertInstall(ip.pkg, flags, ip.pkg.installLocation);
-
-            assertTrue("Previously set paths should be the same as the returned paths.",
-                    Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName)));
-        } finally {
-            cleanUpInstall(ip);
-        }
-    }
-
     /*---------- Recommended install location tests ----*/
     /*
      * TODO's
diff --git a/docs/html/guide/developing/index.html b/docs/html/guide/developing/index.html
deleted file mode 100644
index 4881acf..0000000
--- a/docs/html/guide/developing/index.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<html>
-<head>
-<meta http-equiv="refresh" content="0;url=../index.html">
-</head>
-<body>
-<a href="../index.html">click here</a> if you are not redirected.
-</body>
-</html>
\ No newline at end of file
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index a984acd..67f1fec 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -58,6 +58,9 @@
             <span class="zh-TW" style="display:none">應用程式基本原理</span>
 
           </a></li>
+      <li><a href="<?cs var:toroot ?>guide/topics/fundamentals/fragments.html">
+            <span class="en">Fragments</span>
+          </a> <span class="new">new!</span></li>
     </ul>
     <ul>
       <li class="toggle-list">
@@ -199,9 +202,6 @@
       </li>
     </ul>
     <ul>
-      <li><a href="<?cs var:toroot ?>guide/topics/fragments/index.html">
-            <span class="en">Fragments</span>
-          </a> <span class="new">new!</span></li>
       <li class="toggle-list">
         <div><a href="<?cs var:toroot ?>guide/topics/graphics/index.html">
                <span class="en">Graphics</span>
diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index 97b31cf..fe69d7d 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -8,14 +8,13 @@
 <ol>
   <li><a href="#intro">Introduction</a></li>
   <li><a href="#optimize_judiciously">Optimize Judiciously</a></li>
-  <li><a href="#object_creation">Avoid Creating Objects</a></li>
+  <li><a href="#object_creation">Avoid Creating Unnecessary Objects</a></li>
   <li><a href="#myths">Performance Myths</a></li>
   <li><a href="#prefer_static">Prefer Static Over Virtual</a></li>
   <li><a href="#internal_get_set">Avoid Internal Getters/Setters</a></li>
   <li><a href="#use_final">Use Static Final For Constants</a></li>
   <li><a href="#foreach">Use Enhanced For Loop Syntax</a></li>
-  <li><a href="#avoid_enums">Avoid Enums Where You Only Need Ints</a></li>
-  <li><a href="#package_inner">Use Package Scope with Inner Classes</a></li>
+  <li><a href="#package_inner">Consider Package Instead of Private Access with Inner Classes</a></li>
   <li><a href="#avoidfloat">Use Floating-Point Judiciously</a> </li>
   <li><a href="#library">Know And Use The Libraries</a></li>
   <li><a href="#native_methods">Use Native Methods Judiciously</a></li>
@@ -83,27 +82,31 @@
 test on that device.</p>
 
 <a name="object_creation"></a>
-<h2>Avoid Creating Objects</h2>
+<h2>Avoid Creating Unnecessary Objects</h2>
 
 <p>Object creation is never free. A generational GC with per-thread allocation
 pools for temporary objects can make allocation cheaper, but allocating memory
 is always more expensive than not allocating memory.</p>
 
 <p>If you allocate objects in a user interface loop, you will force a periodic
-garbage collection, creating little "hiccups" in the user experience.</p>
+garbage collection, creating little "hiccups" in the user experience. The
+concurrent collector introduced in Gingerbread helps, but unnecessary work
+should always be avoided.</p>
 
 <p>Thus, you should avoid creating object instances you don't need to.  Some
 examples of things that can help:</p>
 
 <ul>
-    <li>When extracting strings from a set of input data, try 
-    to return a substring of the original data, instead of creating a copy.
-    You will create a new String object, but it will share the char[]
-    with the data.</li>
     <li>If you have a method returning a string, and you know that its result
     will always be appended to a StringBuffer anyway, change your signature
     and implementation so that the function does the append directly,
     instead of creating a short-lived temporary object.</li>
+    <li>When extracting strings from a set of input data, try
+    to return a substring of the original data, instead of creating a copy.
+    You will create a new String object, but it will share the char[]
+    with the data. (The trade-off being that if you're only using a small
+    part of the original input, you'll be keeping it all around in memory
+    anyway if you go this route.)</li>
 </ul>
 
 <p>A somewhat more radical idea is to slice up multidimensional arrays into
@@ -119,7 +122,7 @@
     generally much better than a single array of custom (Foo,Bar) objects.
     (The exception to this, of course, is when you're designing an API for
     other code to access;  in those cases, it's usually better to trade
-    correct API design for a small hit in speed. But in your own internal 
+    good API design for a small hit in speed. But in your own internal
     code, you should try and be as efficient as possible.)</li>
 </ul>
 
@@ -127,6 +130,7 @@
 can.  Fewer objects created mean less-frequent garbage collection, which has
 a direct impact on user experience.</p>
 
+<a name="avoid_enums" id="avoid_enums"></a>
 <a name="myths" id="myths"></a>
 <h2>Performance Myths</h2>
 
@@ -265,43 +269,18 @@
 
 <p>(See also <em>Effective Java</em> item 46.)</p>
 
-<a name="avoid_enums" id="avoid_enums"></a>
-<h2>Avoid Enums Where You Only Need Ints</h2>
-
-<p>Enums are very convenient, but unfortunately can be painful when size
-and speed matter.  For example, this:</p>
-
-<pre>public enum Shrubbery { GROUND, CRAWLING, HANGING }</pre>
-
-<p>adds 740 bytes to your .dex file compared to the equivalent class
-with three public static final ints. On first use, the
-class initializer invokes the &lt;init&gt; method on objects representing each
-of the enumerated values. Each object gets its own static field, and the full
-set is stored in an array (a static field called "$VALUES"). That's a lot of
-code and data, just for three integers. Additionally, this:</p>
-
-<pre>Shrubbery shrub = Shrubbery.GROUND;</pre>
-
-<p>causes a static field lookup.  If "GROUND" were a static final int,
-the compiler would treat it as a known constant and inline it.</p>
-
-<p>The flip side, of course, is that with enums you get nicer APIs and
-some compile-time value checking.  So, the usual trade-off applies: you should
-by all means use enums for public APIs, but try to avoid them when performance
-matters.</p>
-
-<p>If you're using <code>Enum.ordinal</code>, that's usually a sign that you
-should be using ints instead. As a rule of thumb, if an enum doesn't have a
-constructor and doesn't define its own methods, and it's used in
-performance-critical code, you should consider <code>static final int</code>
-constants instead.</p>
-
 <a name="package_inner" id="package_inner"></a>
-<h2>Use Package Scope with Inner Classes</h2>
+<h2>Consider Package Instead of Private Access with Private Inner Classes</h2>
 
 <p>Consider the following class definition:</p>
 
 <pre>public class Foo {
+    private class Inner {
+        void stuff() {
+            Foo.this.doStuff(Foo.this.mValue);
+        }
+    }
+
     private int mValue;
 
     public void run() {
@@ -313,24 +292,19 @@
     private void doStuff(int value) {
         System.out.println("Value is " + value);
     }
-
-    private class Inner {
-        void stuff() {
-            Foo.this.doStuff(Foo.this.mValue);
-        }
-    }
 }</pre>
 
-<p>The key things to note here are that we define an inner class (Foo$Inner)
-that directly accesses a private method and a private instance field
-in the outer class.  This is legal, and the code prints "Value is 27" as
-expected.</p>
+<p>The key things to note here are that we define a private inner class
+(<code>Foo$Inner</code>) that directly accesses a private method and a private
+instance field in the outer class. This is legal, and the code prints "Value is
+27" as expected.</p>
 
-<p>The problem is that the VM considers direct access to Foo's private members
-from Foo$Inner to be illegal because Foo and Foo$Inner are different classes,
-even though the Java language allows an inner class to access an outer class'
-private members. To bridge the gap, the compiler generates a couple of
-synthetic methods:</p>
+<p>The problem is that the VM considers direct access to <code>Foo</code>'s
+private members from <code>Foo$Inner</code> to be illegal because
+<code>Foo</code> and <code>Foo$Inner</code> are different classes, even though
+the Java language allows an inner class to access an outer class' private
+members. To bridge the gap, the compiler generates a couple of synthetic
+methods:</p>
 
 <pre>/*package*/ static int Foo.access$100(Foo foo) {
     return foo.mValue;
@@ -339,22 +313,19 @@
     foo.doStuff(value);
 }</pre>
 
-<p>The inner-class code calls these static methods whenever it needs to
-access the "mValue" field or invoke the "doStuff" method in the outer
-class. What this means is that the code above really boils down to a case
-where you're accessing member fields through accessor methods instead of
-directly.  Earlier we talked about how accessors are slower than direct field
+<p>The inner class code calls these static methods whenever it needs to
+access the <code>mValue</code> field or invoke the <code>doStuff</code> method
+in the outer class. What this means is that the code above really boils down to
+a case where you're accessing member fields through accessor methods.
+Earlier we talked about how accessors are slower than direct field
 accesses, so this is an example of a certain language idiom resulting in an
 "invisible" performance hit.</p>
 
-<p>We can avoid this problem by declaring fields and methods accessed
-by inner classes to have package scope, rather than private scope.
-This runs faster and removes the overhead of the generated methods.
-(Unfortunately it also means the fields could be accessed directly by other
-classes in the same package, which runs counter to the standard
-practice of making all fields private. Once again, if you're
-designing a public API you might want to carefully consider using this
-optimization.)</p>
+<p>If you're using code like this in a performance hotspot, you can avoid the
+overhead by declaring fields and methods accessed by inner classes to have
+package access, rather than private access. Unfortunately this means the fields
+can be accessed directly by other classes in the same package, so you shouldn't
+use this in public API.</p>
 
 <a name="avoidfloat" id="avoidfloat"></a>
 <h2>Use Floating-Point Judiciously</h2>
diff --git a/docs/html/guide/topics/fragments/index.jd b/docs/html/guide/topics/fragments/index.jd
deleted file mode 100644
index d07daf4..0000000
--- a/docs/html/guide/topics/fragments/index.jd
+++ /dev/null
@@ -1,648 +0,0 @@
-page.title=Fragments
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-  <h2>Quickview</h2>
-  <ul>
-    <li>Decompose application functionality and UI into reusable modules</li>
-    <li>Add multiple fragments to a screen to avoid switching activities</li>
-    <li>Fragments have their own lifecycle, state, and back stack</li>
-    <li>Fragments require API Level HONEYCOMB or greater</li>
-  </ul>
-
-  <h2>In this document</h2>
-  <ol>
-    <li><a href="#Creating">Creating fragments</a></li>
-    <li><a href="#Adding">Adding a fragment to an activity</a></li>
-    <li><a href="#Managing">Managing fragments</a></li>
-    <li><a href="#Lifecycle">Handling the lifecycle</a></li>
-    <li><a href="#Integrating">Integrating with the activity</a></li>
-    <li><a href="#Menus">Adding menus</a></li>
-  </ol>
-
-  <h2>Key classes</h2>
-  <ol>
-    <li>{@link android.app.Fragment}</li>
-    <li>{@link android.app.FragmentManager}</li>
-    <li>{@link android.app.FragmentTransaction}</li>
-  </ol>
-
-  <!--
-  <h2>Related samples</h2>
-  <ol>
-    <li><a
-href="{@docRoot}resources/samples/NotePad/index.html">NotePad</a></li>
-  </ol>
-  -->
-</div>
-</div>
-
-
-<p>An {@link android.app.Activity} is always the window in which users interact with your
-application, but a {@link android.app.Fragment} can be responsible for distinct operations and UI
-that's embedded in an activity. So, when using fragments, your activity becomes more like a
-container for fragments that define the activity's behavior and UI.</p>
-
-<p>Fragments have their own
-set of lifecylce callback methods and recieve their own user input events. A fragment must always be
-embedded in an activity and the fragment's lifecycle is directly affected by the activity's
-lifecycle. For example, when the activity is stopped, so are all fragments in it, and when
-the activity is destroyed, so are all fragments. However, while an activity
-is active (in the "resumed" lifecycle stage), you can manipulate the lifecycle of each fragment
-independently. For example, you can add and remove fragments while the activity is active and you
-can add each fragment to a back stack within the activity&mdash;each back stack entry in the
-activity is actually a record of a "transaction" that occurred with the activity's fragments, so
-that the user can reverse the transaction with the BACK key (this is discussed more later).</p>
-
-<div class="figure" style="width:314px">
-<img src="{@docRoot}images/fragment_lifecycle.png" alt="" />
-<p class="img-caption"><strong>Figure 1.</strong> The lifecycle of a fragment (while its
-activity is running).</p>
-</div>
-
-<p>Android introduced fragments in Android X.X (API Level HONEYCOMB), with the primary intention to
-support more dynamic and flexible UI designs on large screen devices, such as tablets. Because a
-tablet has a much larger screen than a mobile phone, there's more room to interchange UI
-elements. Fragments allow that without the need for you to start a new activity or manage complex
-changes to the view hierarchy. By dividing the layout of an activity into fragments, the code
-that defines your activity becomes more modular and interchangable, allowing you to modify the
-activity's appearance at runtime and for different types of screens.</p>
-
-<p>For example, a news application can use one fragment to show a list of articles on the
-left and another fragment to display an article on the right&mdash;both fragments appear in one
-activity, side by side, and each fragment has its own set of lifecycle callback methods and handle
-their own user input events. Thus, instead using one activity to select an article and another
-activity to read the article, the user can select an article and read it all within the same
-activity.</p>
-
-<!-- ** TODO: Save this for later or move it down in the doc so the intro isn't overwhelming **
-     
-<p>A fragment can be a modular and reusable component in your application. That is, because
-the fragment defines its own behavior using its own set of lifecycle callbacks, you can
-include one fragment in multiple activities. This also enables you to create one version of your
-application for multiple screen sizes. For instance, on an extra large screen (<em>xlarge</em>
-screen configuration), you can embed two or more fragments in one activity, but on a normal-sized
-screen (<em>normal</em> screen configuration), you can embed just one fragment in an activity and
-then start other activities in order to display the other fragments.</p>
--->
-
-<p>When you use a fragment as a part of your layout, it technically lives within a {@link
-android.view.View} of the activity's layout and defines its own layout of views. You can insert a
-fragment into your activity layout by declaring the fragment in the activity's XML layout file, as
-a {@code &lt;fragment&gt;} element, or from your application code by adding it to an existing {@link
-android.view.View}. However, a fragment is not required to be a part of the activity
-layout&mdash;you might use a fragment as an invisible worker for the activity (more about that
-later).</p>
-
-<p>The rest of this document describes how to build your application to use fragments, including
-how fragments can contribute to the activity options menu and action bar, create context menus,
-maintain their state when added to the activity's back stack, and more.</p>
-
-
-
-<h2 id="Creating">Creating a Fragment</h2>
-
-<p>An implementation of the {@link android.app.Fragment} class contains code that looks a lot like
-the code in an {@link android.app.Activity}. In fact, if you're
-converting an existing Android application to use fragments, you'll move code
-from your {@link android.app.Activity} implementation into your {@link android.app.Fragment} class
-implementation, and into some of the same callback methods. A fragment contains callback methods
-similar to an activity, such as {@link android.app.Fragment#onCreate onCreate()}, {@link
-android.app.Fragment#onStart onStart()}, {@link android.app.Fragment#onPause onPause()}, and {@link
-android.app.Fragment#onStop onStop()}.</p>
-
-<p>If you're creating a fragment to be a modular piece of an activity UI, then your
-implementation of {@link android.app.Fragment} should include most of the same lifecycle
-callback methods traditionally implemented by the activity to initialize elements of the UI and
-save and restore state information. Usually, you'll want to implement the following methods:</p>
-
-<dl>
-  <dt>{@link android.app.Fragment#onCreate onCreate()}</dt>
-  <dd>The system calls this when creating the fragment. Within your implementation, you should
-initialize the essential components of the fragment that should be retained when the fragment is
-paused or stopped.</dd>
-  <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt>
-  <dd>The system calls this when it's time for the fragment to draw its user interface for the
-first time. To draw a UI for your fragment, you must return a {@link android.view.View} from this
-method that is the root of your fragment's layout. You can return null if the fragment does not
-provide a UI.</dd>
-  <dt>{@link android.app.Activity#onPause onPause()}</dt>
-  <dd>The system calls this method as the first indication that the user is leaving the
-fragment (though it does not always mean the fragment is being destroyed). This is usually where you
-should commit any changes that should be persisted beyond the current user session (because
-the user might not come back).</dd>
-</dl>
-
-<p>Most applications should implement at least these three methods for each fragment, but there are
-several other lifecycle callback methods that you should also use in order to provide the best
-user experience when switching fragments and when the activity is paused or stopped. All of the
-lifecycle callback methods are discussed more later, in
-the section about <a href="#Lifecycle">Handling the Lifecycle</a>.</p>
-
-
-<p>There are also a few different subclasses of {@link android.app.Fragment} that you might want 
-to use:</p>
-
-<dl>
-  <dt>{@link android.app.DialogFragment}</dt>
-  <dd>Displays a floating dialog. Using this class to create a dialog is a good alternative to using
-the dialog helper methods in the {@link android.app.Activity} class, because the dialog can be
-incorporated into the fragment back stack managed by the activity.</dd>
-
-  <dt>{@link android.app.ListFragment}</dt>
-  <dd>Displays a list of items that are managed by an adapter (such as a {@link
-android.widget.SimpleCursorAdapter}), similar to {@link android.app.ListActivity}. Provides methods
-for managing a list, such as the {@link
-android.app.ListFragment#onListItemClick(ListView,View,int,long) onListItemClick()} callback to
-handle click events on list items.</dd>
-
-  <dt>{@link android.preference.PreferenceFragment}</dt>
-  <dd>Displays a hierarchy of {@link android.preference.Preference} objects as a list, similar to
-{@link android.preference.PreferenceActivity}. </dd>
-</dl>
-
-<p>However, subclassing the standard {@link android.app.Fragment} class is most common, if
-you're not creating a dialog, a list, or displaying preferences.</p>
-
-
-<h3 id="UI">Providing a user interface</h3>
-
-<p>To provide a UI layout for a fragment, you must implement
-the {@link android.app.Fragment#onCreateView onCreateView()}
-callback method in your {@link android.app.Fragment} (unless your fragment is a subclass of
-{@link android.app.ListFragment}, which returns a {@link android.widget.ListView} from this method
-by default). The Android system calls {@link android.app.Fragment#onCreateView onCreateView()} when
-it's time for the fragment to draw its layout. Your implementation of this method must return a
-{@link android.view.View} that is the root of your fragment's layout.</p>
-
-<p>The easiest way to provide your layout is to inflate it from a <a
-href="{@docRoot}guide/topics/resources/layout-resource.html">layout resource</a>. To help you
-inflate a layout, the {@link android.app.Fragment#onCreateView onCreateView()} method passes a
-{@link android.view.LayoutInflater} that you can use to get your layout. For example, here's a
-simple subclass of {@link android.app.Fragment} that contains an implementation of {@link
-android.app.Fragment#onCreateView onCreateView()} that loads the fragment's layout from a
-resource:</p>
-
-<pre>
-public static class SimpleFragment extends Fragment {
-    &#64;Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-                             Bundle savedInstanceState) {
-        // Inflate the layout for this fragment
-        return inflater.inflate(R.layout.simple_fragment, container, false);
-    }
-}
-</pre>
-
-<p>The {@link android.view.LayoutInflater#inflate(int,ViewGroup,boolean) inflate()} method takes
-three arguments:</p>
-<ul>
-  <li>The resource ID of the layout you want to inflate</li>
-  <li>The {@link android.view.ViewGroup} to be the parent of the
-inflated layout (supplying this is important in order to apply layout parameters from the parent
-view)</li>
-  <li>And a boolean indicating whether the inflated layout should be attached to the {@link
-android.view.ViewGroup} (from the second parameter) during inflation (in this case, this
-is false because the system is already going to insert the layout into the appropriate parent
-view&mdash;doing otherwise would create a redundant view group in the final layout)</li>
-</ul>
-
-<p>The {@code container} parameter passed to {@link android.app.Fragment#onCreateView
-onCreateView()} provides the parent {@link android.view.ViewGroup} in which your fragment layout
-will be inserted, which you can use to generate layout parameters for your
-fragment layout. The {@code savedInstanceState} parameter is a {@link android.os.Bundle} that
-provides data about the previous instance of the fragment, if the fragment is being resumed
-(restoring state is discussed more in the section about <a href="#Lifecycle">Handling the
-Lifecycle</a>.</p>
-
-
-<h3 id="Adding">Adding a Fragment to an Activity</h3>
-
-<p>Each fragment is embedded into the layout of its container activity as a part of the overall view
-hierarchy, whether or not it actually provides a UI. If a fragment is not embedded into the activity
-layout, then it is never created (it does not receive any lifecycle callbacks). There are two ways
-you can add a fragment to the activity layout:</p>
-
-<ul>
-  <li><b>Declare the fragment inside the activity's layout XML file.</b>
-<p>In this case, you can
-specify layout properties for the fragment as if it were a view itself and the fragment's layout
-fills that space. For example:</p>
-<pre>
-&lt;?xml version="1.0" encoding="utf-8"?&gt;
-&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"&gt;
-    &lt;fragment android:name="com.example.news.ArticleListFragment"
-            android:id="@+id/list"
-            android:layout_weight="1"
-            android:layout_width="0dp"
-            android:layout_height="match_parent" /&gt;
-    &lt;fragment android:name="com.example.news.ArticleReaderFragment"
-            android:id="@+id/viewer"
-            android:layout_weight="2"
-            android:layout_width="0dp"
-            android:layout_height="match_parent" /&gt;
-&lt;/LinearLayout&gt;
-</pre>
-  <p>The {@code &lt;fragment&gt;} element uses the {@code android:name} attribute to specify the
-{@link android.app.Fragment} class to instantiate and insert into the layout. When the activity
-layout is created, the system instantiates each fragment in the layout and calls its {@link
-android.app.Fragment#onCreateView onCreateView()} method in order to retrieve the fragment's
-layout. The {@link android.view.View} object returned by {@link
-android.app.Fragment#onCreateView onCreateView()} is then
-placed directly in the activity layout in place of the {@code &lt;fragment&gt;} element.</p>
-
-<div class="note">
-  <p><strong>Note:</strong> Each fragment requires a unique identifier that
-the system can use to restore the fragment if the activity is restarted (and which you can use to
-perform fragment transactions). There are three ways to identify a fragment:</p>
-  <ul>
-    <li>Supply the {@code android:id} attribute with a unique ID, in the {@code
-&lt;fragment&gt;}</li>
-    <li>Supply the {@code android:tag} attribute with a unique string ID, in the {@code
-  &lt;fragment&gt;}</li>
-    <li>If neither of the previous two are provided, the system uses the ID of the container
-  view.</li>
-  </ul>
-</div>
-  </li>
-
-  <li><b>Or, programmatically add the fragment to an existing {@link android.view.ViewGroup}.</b>
-<p>At any time while your activity is running (in the "resumed" state), you can add (and remove)
-fragments to your activity layout. You simply need to specify a {@link android.view.ViewGroup} in
-which to place the fragment.</p>
-  <p>To make any fragment transactions in your activity (such as add, remove, or replace a
-fragment), you must use APIs from {@link android.app.FragmentTransaction}. You can get an instance
-of {@link android.app.FragmentTransaction} from your {@link android.app.FragmentManager} using {@link
-android.app.FragmentManager#openTransaction()}. You can then add a fragment using the {@link
-android.app.FragmentTransaction#add add()} method, specifying the fragment to add and the view in
-which to insert it. For example:</p>
-<pre>
-MyFragment fragment = new MyFragment();
-getFragmentManager().openTransaction().add(R.id.fragment_container, fragment).commit();
-</pre>
-  <p>The first argument passed to {@link android.app.FragmentTransaction#add add()}
-is the {@link android.view.ViewGroup} in which the fragment should be placed, specified by
-resource ID, and the second parameter is the fragment object.</p>
-  <p>Once you've made your changes using
-{@link android.app.FragmentTransaction}, you must
-call {@link android.app.FragmentTransaction#commit} in order for the changes to take effect.</p>
-  </li>
-</ul>
-
-
-<h3 id="Example1">Example: simple fragments</h3>
-
-<p>In the last couple sections, you saw how to declare layout for a fragment and add it to an
-activity. What follows is some code that brings it all together, like a "Hello World" for
-fragments.</p>
-
-<p>First, here's a layout file for a fragment:</p>
-<pre>
-&lt;?xml version="1.0" encoding="utf-8"?&gt;
-&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent" &gt;
-&lt;TextView  
-    android:layout_width="match_parent" 
-    android:layout_height="wrap_content"
-    android:text="@string/hello" /&gt;
-&lt;TextView  
-    android:layout_width="match_parent" 
-    android:layout_height="wrap_content"
-    android:text="@string/hello" /&gt;
-&lt;/LinearLayout&gt;
-</pre>
-
-<p>With that file saved at {@code res/layout/simple_fragment.xml}, the following {@link
-android.app.Fragment} uses it for its layout:</p>
-
-<pre>
-public static class SimpleFragment extends Fragment {
-    &#64;Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-                             Bundle savedInstanceState) {
-        // Inflate the layout for this fragment
-        return inflater.inflate(R.layout.simple_fragment, null);
-    }
-}
-</pre>
-
-<p>And the following layout for an activity applies the fragment twice, side by side:</p>
-
-<pre>
-&lt;?xml version="1.0" encoding="utf-8"?&gt;
-&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"&gt;
-    &lt;fragment android:name="com.example.SimpleFragment"
-            android:id="@+id/list"
-            android:layout_weight="1"
-            android:layout_width="0dp"
-            android:layout_height="match_parent" /&gt;
-    &lt;fragment android:name="com.example.SimpleFragment"
-            android:id="@+id/viewer"
-            android:layout_weight="1"
-            android:layout_width="0dp"
-            android:layout_height="match_parent" /&gt;
-&lt;/LinearLayout&gt;
-</pre>
-
-<p>That's it. When an activity applies the previous layout as its content, the {@code
-SimpleFragment} class is instantiated for each occurence in the layout, applying the fragment
-layout when it receives the call to  {@link android.app.Fragment#onCreateView onCreateView()}.</p>
-
-<p>Although the fragment in this example implements only the {@link
-android.app.Fragment#onCreateView onCreateView()} callback, there are several other lifecycle
-callback methods that you should implement in your application. For example, {@link
-android.app.Fragment#onCreate onCreate()}, {@link android.app.Fragment#onPause onPause()}, {@link
-android.app.Fragment#onStop onStop()} and others that coincide with the fragment's lifecycle.</p>
-
-
-
-<h2 id="Managing">Managing Fragments</h2>
-
-<p>A useful feature of fragments is the ability to add, remove, replace, and perform other
-operations on a fragment as the user interacts with the activity, alowing for more rich user
-experiences without changing activities. In order to perform these operations, you must use {@link
-android.app.FragmentTransaction} to perform fragment "transactions." You can acquire {@link
-android.app.FragmentTransaction} from your FragmentManager with {@link
-android.app.FragmentManager#openTransaction}.</p>
-
-<p>Common transactions you can perform with fragments include:</p>
-
-<dl>
-  <dt>{@link android.app.FragmentTransaction#add add()}</dt>
-    <dd>Add a {@link android.app.Fragment} to the {@link android.app.Activity} layout.</dd>
-  <dt>{@link android.app.FragmentTransaction#remove remove()}</dt>
-    <dd>Remove a {@link android.app.Fragment} from the {@link android.app.Activity} layout.</dd>
-  <dt>{@link android.app.FragmentTransaction#replace replace()}</dt>
-    <dd>Replace an existing {@link android.app.Fragment} with another one.</dd>
-</dl>
-
-<p>For every transaction (or set of transactions) you perform, you must call {@link
-android.app.FragmentTransaction#commit} in order for the transactions made with {@link
-android.app.FragmentTransaction} to be applied. Before you do, however, you can call {@link
-android.app.FragmentTransaction#addToBackStack} to add the current fragment state to the
-activity's back stack, so that the user can return to the previous fragment state with the BACK key.
-For example, here's how a new fragment can replace another one, but keep the previous fragment
-in the back stack:</p>
-
-<pre>
-// Create new fragment
-Fragment newFragment = new MyFragment();
-FragmentTransaction ft = getFragmentManager().openTransaction();
-// Replace and add to back stack
-ft.replace(R.id.myfragment, newFragment);
-ft.addToBackStack(null);
-// Apply changes
-ft.commit();
-</pre>
-
-<p>In this example, {@code newFragment} replaces whatever fragment is currently in the
-layout container identified by the {@code R.id.myfragment} ID. By calling {@link
-android.app.FragmentTransaction#addToBackStack addToBackStack()}, this transaction (the replace) is
-saved to the activity's back stack so that the user can reverse this change and bring back the
-previous fragment by pressing the BACK key.</p>
-
-<p>If you perform multiple transactions and call {@link
-android.app.FragmentTransaction#addToBackStack addToBackStack()}, then all transactions performed
-before {@link android.app.FragmentTransaction#commit} are added to the activity's back stack as a
-single event and the BACK key will reverse them all together.</p>
-
-
-
-<h2 id="Lifecycle">Handling the Lifecycle</h2>
-
-<p>A fragment has a lifecycle that corresponds to the lifecycle of the activity in which it
-resides. For example, a fragment has callback methods {@link
-android.app.Fragment#onCreate onCreate()}, {@link android.app.Fragment#onStart onStart()}, {@link
-android.app.Fragment#onPause onPause()}, {@link android.app.Fragment#onStop onStop()}, and more.</p>
-
-<p>The lifecycle of the activity directly affects the lifecycle of the fragment, such that each
-lifecycle callback for the activity results in a similar callback for each fragment (for
-example, when the activity receives {@link android.app.Activity#onPause}, each fragment receives
-{@link android.app.Fragment#onPause}). However, the
-fragment's lifecycle can also change independently&mdash;but only while the activity is
-resumed (while it is in the foreground)&mdash;because you can dynamically
-add, remove, and replace fragments without any change to the lifecycle of the activity.</p>
-
-<p>To accomodate backward navigation with the
-BACK key, you can optionally maintain a back stack of fragment transactions, as described in the
-previous section. So, if you
-replace one fragment with another, the user can press the BACK key and view the previous
-fragment. Additionally, each fragment can maintain its own state, such that
-when the user navigates back to a previous fragment, the state of that fragment can be restored in
-the same manner as the state of an activity is restored when it is stopped and restarted.</p>
-
-<p>Managing the lifecycle of a fragment is a lot like managing the lifecycle of an activity. A
-fragment and an activity both have an "resumed," "paused," and "stopped" state, and they can both
-retain their state using a {@link android.os.Bundle}. The only significant difference is that an
-activity is placed into a the task's back stack by default (so that the user can navigate to
-the previous activity with the BACK key), but a fragment is placed into the activity's back stack
-only when you explicitly call {@link android.app.FragmentTransaction#addToBackStack(String)
-addToBackStack()} before you {@link android.app.FragmentTransaction#commit()} a fragment
-transaction.</p>
-
-<p>The order in which you perform transactions with {@link android.app.FragmentTransaction} doesn't
-matter, except:</p>
-<ul>
-  <li>You must call {@link android.app.FragmentTransaction#commit()} last</li>
-  <li>If you're adding multiple fragments to the same container, then the order in which
-you add them determines the order they appear</li>
-</ul>
-<p>If you do not call {@link android.app.FragmentTransaction#addToBackStack(String)
-addToBackStack()} when you perform a transaction that removes a fragment, then that fragment is
-destroyed when the transaction is committed.</p>
-
-
-<h3 id="CoordinatingWithTheActivity">Coordinating with the activity lifecycle</h3>
-
-<p>The lifecycle of an activity directly affects the lifecycle of a {@link android.app.Fragment}
-embedded in that activity. The {@link android.app.Fragment} class has lifecycle callback
-methods that match those in the {@link android.app.Activity} class.</p>
-
-<p>Fragments have a few extra lifecycle callbacks, however, that handle unique interaction with the
-activity in order to perform actions such as build and destroy the fragment's UI. These additional
-callback methods are:</p>
-
-<dl>
-  <dt>{@link android.app.Fragment#onAttach onAttach()}</dt>
-    <dd>Called when the fragment has been associated with the activity (the {@link
-android.app.Activity} is passed in here).</dd>
-  <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt>
-    <dd>Called to create the view hierarchy associated with the fragment.</dd>
-  <dt>{@link android.app.Fragment#onActivityCreated onActivityCreated()}</dt>
-    <dd>Called when the activity's own {@link android.app.Activity#onCreate
-onCreate()} has finished.</dd>
-  <dt>{@link android.app.Fragment#onDestroyView onDestroyView()}</dt>
-    <dd>Called when the view hierarchy associated with the fragment is being removed.</dd>
-  <dt>{@link android.app.Fragment#onDetach onDetach()}</dt>
-    <dd>Called when the fragment is being disassociated from the activity.</dd>
-</dl>
-
-<p>The flow of a fragment's lifecycle, as it is affected by its container activity, is illustrated
-by figure 3. In this figure, you can see how each successive state of the activity determines which
-callback methods the fragment may receive. For example, when the activity has received
-its {@link android.app.Activity#onCreate onCreate()} callback, the fragment receives no more
-than the {@link android.app.Fragment#onActivityCreated onActivityCreated()} callback. However,
-once the activity reaches the resumed state, you can freely add and remove fragments to the
-activity, so the fragment lifecycle is no longer inhibitted by the state of the activity. Yet,
-when the activity leaves the resumed state, the fragment again is pushed through its lifecycle by
-the activity (unless you explicitly destroy the fragment sooner).</p>
-
-
-<img src="{@docRoot}images/activity_fragment_lifecycle.png" alt=""/>
-<p class="img-caption"><strong>Figure 3.</strong> The activity lifecycle's affect on the lifecycle
-of a fragment.</p>
-
-
-<h3 id="Integrating">Integrating with the Activity</h3>
-
-<p>Although a {@link android.app.Fragment} is implemented separate from an {@link
-android.app.Activity} and can be used inside multiple activities, a fragment is directly tied to its
-container activity and can access the Activity instance with {@link
-android.app.Fragment#getActivity()}. So, a fragment can
-easily perform tasks such as find a view in the activity:</p>
-
-<pre>
-View listView = {@link android.app.Fragment#getActivity()}.{@link android.app.Activity#findViewById findViewById}(R.id.list);
-</pre>
-
-<p>This makes it easy for your fragment to call public methods in the activity.</p>
-
-<p>Likewise, your activity can call public methods in the fragment when you have a reference to the
-{@link android.app.Fragment}. You can acquire a reference to the fragment with {@link
-android.app.FragmentManager#findFragmentById findFragmentById()} and cast it to your implementation of
-{@link android.app.Fragment}. For example:</p>
-
-<pre>
-MyFragment fragment = (MyFragment) findFragmentById(R.id.myfragment);
-fragment.refreshList();
-</pre>
-
-
-<h4 id="Callbacks">Creating event callbacks to the activity</h4>
-
-<p>In some cases, you might need a fragment to share events with the activity. A good way to do that
-is to define a callback interface inside the fragment and require that the host activity implement
-it. When the activity receives a callback, it can share the information with other fragments in the layout as
-necessary.</p>
-
-<p>For example, if a news application has two fragments in an activity&mdash;one to show a list of
-articles (fragment A) and another to display an article (fragment B)&mdash;then fragment A must tell
-the activity when a list item is selected so that it can tell fragment B to display the article. In
-this case, the following interface is defined inside fragment A:</p>
-
-<pre>
-public static class FragmentA extends ListFragment {
-    ...
-    // Container Activity must implement this interface
-    public interface SelectedCallback {
-        public void onArticleSelected(Uri articleUri);
-    }
-    ...
-}
-</pre>
-
-<p>Then the activity that hosts the fragment implements the {@code SelectedCallback} interface and
-overrides {@code onArticleSelected()} to notify fragment B of the event from fragment A. To ensure
-that the host activity implements this interface, fragment A's {@link
-android.app.Fragment#onAttach onAttach()} callback method (called when
-the fragment is added to the activity) instantiates an instance of {@code SelectedCallback} by
-casting the {@link android.app.Activity} that is passed into {@link android.app.Fragment#onAttach
-onAttach()}:</p>
-
-<pre>
-public static class FragmentA extends ListFragment {
-    ...
-    &#64;Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
-        try {
-            mCallback = (SelectedCallback) activity;
-        } catch (ClassCastException e) {
-            activity.finish();
-            throw new ClassCastException(activity.toString() + " must implement SelectedCallback");
-        }
-    }
-    ...
-}
-</pre>
-
-<p>If the activity has not implemented the interface, then a {@link java.lang.ClassCastException} is
-thrown and the activity is shut down. On success, the {@code mCallback} member holds a reference to
-the {@link android.app.Activity}, so that fragment A can share events with the activity by calling
-methods defined by the {@code SelectedCallback} interface. For example, if fragment A is an
-extension of {@link android.app.ListFragment}, each time
-the user clicks a list item, the system calls {@link android.app.ListFragment#onListItemClick
-onListItemClick()} in the fragment, which then calls {@code onArticleSelected()} to share
-the event with the activity:</p>
-
-<pre>
-public static class FragmentA extends ListFragment {
-    ...
-    &#64;Override
-    public void onListItemClick(ListView l, View v, int position, long id) {
-        // Append the clicked item's row ID with the content provider Uri
-        Uri noteUri = ContentUris.{@link android.content.ContentUris#withAppendedId withAppendedId}(ArticleColumns.CONTENT_URI, id);
-        // Send the event and Uri to the host activity
-        mCallback.onArticleSelected(noteUri);
-    }
-    ...
-}
-</pre>
-
-<p>The {@code id} parameter passed to {@link
-android.app.ListFragment#onListItemClick onListItemClick()} is the row ID of the clicked item,
-which the activity (or other fragment) uses to fetch the article from the application's {@link
-android.content.ContentProvider}.</p>
-
-<p><!--To see a complete implementation of this kind of callback interface, see the <a
-href="{@docRoot}resources/samples/NotePad/index.html">NotePad sample</a>. -->More information about
-using a content provider is available in the <a
-href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> document.</p>
-
-
-
-
-
-
-<h2 id="Menus">Adding Action Items to the Activity</h2>
-
-<p>Your fragments can contribute action items to the activity's <a
-href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a> (and menu items to the options menu)
-using the callback methods
-{@link android.app.Fragment#onCreateOptionsMenu(Menu,MenuInflater) onCreateOptionsMenu()}. In order
-for this method to receive calls, however, you must call {@link
-android.app.Fragment#setHasOptionsMenu(boolean) setHasOptionsMenu()} during the {@link
-android.app.Fragment#onCreate(Bundle) onCreate()} callback in order to indicate that the fragment
-would like to receive a call to {@link android.app.Fragment#onCreateOptionsMenu(Menu,MenuInflater)
-onCreateOptionsMenu()}. Any action or menu items that you add from the fragment are appended to the
-existing
-items for the options menu (including those added by other fragments in the activity). The
-fragment also receives item-selected events with the {@link
-android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} callback method.</p>
-
-<p>The {@link android.app.Fragment} class also contains methods to handle context menus. You can
-register a view to provide a context menu with {@link
-android.app.Fragment#registerForContextMenu(View) registerForContextMenu()}. When the user opens
-the context menu, the fragment receives a call to {@link
-android.app.Fragment#onCreateContextMenu(ContextMenu,View,ContextMenu.ContextMenuInfo)
-onCreateContextMenu()}. When the user selects an item, the fragment receives a call to {@link
-android.app.Fragment#onContextItemSelected(MenuItem) onContextItemSelected()}.</p>
-
-<p>For more information, see <a href="{@docRoot}guide/topics/ui/menus.html">Creating
-Menus</a> and <a href="{@docRoot}guide/topics/ui/actionbar.html">Using the Action Bar</a>.</p>
-
-
-
-
-
-
diff --git a/docs/html/guide/topics/fundamentals/fragments.jd b/docs/html/guide/topics/fundamentals/fragments.jd
new file mode 100644
index 0000000..0972805
--- /dev/null
+++ b/docs/html/guide/topics/fundamentals/fragments.jd
@@ -0,0 +1,815 @@
+page.title=Fragments
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+  <h2>Quickview</h2>
+  <ul>
+    <li>Fragments decompose application functionality and UI into reusable modules</li>
+    <li>Add multiple fragments to a screen to avoid switching activities</li>
+    <li>Fragments have their own lifecycle, state, and back stack</li>
+    <li>Fragments require API Level HONEYCOMB or greater</li>
+  </ul>
+
+  <h2>In this document</h2>
+  <ol>
+    <li><a href="#Design">Design Philosophy</a></li>
+    <li><a href="#Creating">Creating a Fragment</a>
+      <ol>
+        <li><a href="#UI">Adding a user interface</a></li>
+        <li><a href="#Adding">Adding a fragment to an activity</a></li>
+      </ol>
+    </li>
+    <li><a href="#Managing">Managing Fragments</a></li>
+    <li><a href="#Transactions">Performing Fragment Transactions</a></li>
+    <li><a href="#CommunicatingWithActivity">Communicating with the Activity</a>
+      <ol>
+        <li><a href="#EventCallbacks">Creating event callbacks to the activity</a></li>
+        <li><a href="#ActionBar">Adding items to the Action Bar</a></li>
+      </ol>
+    </li>
+    <li><a href="#Lifecycle">Handling the Fragment Lifecycle</a>
+      <ol>
+        <li><a href="#CoordinadingWithActivity">Coordinating with the activity lifecycle</a></li>
+      </ol>
+    </li>
+    <li><a href="#Example">Example</a></li>
+  </ol>
+
+  <h2>Key classes</h2>
+  <ol>
+    <li>{@link android.app.Fragment}</li>
+    <li>{@link android.app.FragmentManager}</li>
+    <li>{@link android.app.FragmentTransaction}</li>
+  </ol>
+
+  <h2>Related samples</h2>
+  <ol>
+    <li><a
+href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/index.html#Fragment">ApiDemos</a></li>
+  </ol>
+</div>
+</div>
+
+<p>A {@link android.app.Fragment} represents a behavior or a portion of user interface in an
+{@link android.app.Activity}. You can combine multiple fragments in a single activity to build a
+multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a
+modular section of an activity, which has its own lifecycle, receives its own input events, and
+which you can add or remove while the activity is running.</p>
+
+<p>A fragment must always be embedded in an activity and the fragment's lifecycle is directly
+affected by the activity's lifecycle. For example, when the activity is paused, so are all
+fragments in it, and when the activity is destroyed, so are all fragments. However, while an
+activity is running (it is in the <em>resumed</em> <a
+href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">lifecycle state</a>), you can
+manipulate each fragment independently, such as add or remove them. When you perform such a
+fragment transaction, you can it to a back stack managed by the
+activity&mdash;each back stack entry in the activity is a record of the fragment transaction that
+occurred. The back stack allows the user to reverse a fragment transaction (navigate backwards),
+by pressing the BACK key.</p>
+
+<p>When you add a fragment as a part of your activity layout, it lives in a {@link
+android.view.ViewGroup} inside the activity's view hierarchy and defines its own layout of views.
+You can insert a fragment into your activity layout by declaring the fragment in the activity's
+layout file, as a {@code &lt;fragment&gt;} element, or from your application code by adding it to an
+existing {@link android.view.ViewGroup}. However, a fragment is not required to be a part of the
+activity layout; you may also use a fragment as an invisible worker for the activity.</p>
+
+<p>This document describes how to build your application to use fragments, including
+how fragments can maintain their state when added to the activity's back stack, share
+events with the activity and other fragments in the activity, contribute to the activity's action
+bar, and more.</p>
+
+
+<h2 id="Design">Design Philosophy</h2>
+
+<p>Android introduced fragments in Android 3.0 (API Level "Honeycomb"), primarily to support more
+dynamic and flexible UI designs on large screens, such as tablets. Because a
+tablet's screen is much larger than that of a mobile phone, there's more room to combine and
+interchange UI components. Fragments allow such designs without the need for you to manage complex
+changes to the view hierarchy. By dividing the layout of an activity into fragments, you become able
+to modify the activity's appearance at runtime and preserve those changes in a back stack
+that's managed by the activity.</p>
+
+<p>For example, a news application can use one fragment to show a list of articles on the
+left and another fragment to display an article on the right&mdash;both fragments appear in one
+activity, side by side, and each fragment has its own set of lifecycle callback methods and handle
+their own user input events. Thus, instead of using one activity to select an article and another
+activity to read the article, the user can select an article and read it all within the same
+activity, as illustrated in figure 1.</p>
+
+<img src="{@docRoot}images/fundamentals/fragments.png" alt="" />
+<p class="img-caption"><strong>Figure 1.</strong> An example of how two UI modules that are
+typically separated into two activities can be combined into one activity, using fragments.</p>
+
+
+<p>A fragment should be a modular and reusable component in your application. That is, because the
+fragment defines its own layout and its own behavior using its own lifecycle callbacks, you
+can include one fragment in multiple activities. This is especially important because it allows you
+to adapt your user experience to different screen sizes. For instance, you might include multiple
+fragments in an activity only when the screen size is sufficiently large, and, when it is not,
+launch separate activities that use different fragments.</p>
+
+<p>For example&mdash;to continue with the news application example&mdash;the application can embed
+two
+fragments in <em>Activity A</em>, when running on an extra large screen (a tablet, for example).
+However, on a normal-sized screen (a phone, for example),
+there's not be enough room for both fragments, so <em>Activity A</em> includes only the fragment for
+the list of articles, and when the user selects an article, it starts <em>Activity B</em>, which
+includes the fragment to read the article. Thus, the application supports both design patterns
+suggested in figure 1.</p>
+
+
+
+<h2 id="Creating">Creating a Fragment</h2>
+
+<div class="figure" style="width:314px">
+<img src="{@docRoot}images/fragment_lifecycle.png" alt="" />
+<p class="img-caption"><strong>Figure 2.</strong> The lifecycle of a fragment (while its
+activity is running).</p>
+</div>
+
+<p>To create a fragment, you must create a subclass of {@link android.app.Fragment} (or an existing
+subclass of it). The {@link android.app.Fragment} class has code that looks a lot like
+an {@link android.app.Activity}. It contains callback methods similar to an activity, such
+as {@link android.app.Fragment#onCreate onCreate()}, {@link android.app.Fragment#onStart onStart()},
+{@link android.app.Fragment#onPause onPause()}, and {@link android.app.Fragment#onStop onStop()}. In
+fact, if you're converting an existing Android application to use fragments, you might simply move
+code from your activity's callback methods into the respective callback methods of your
+fragment.</p>
+
+<p>Usually, you should implement at least the following lifecycle methods:</p>
+
+<dl>
+  <dt>{@link android.app.Fragment#onCreate onCreate()}</dt>
+  <dd>The system calls this when creating the fragment. Within your implementation, you should
+initialize essential components of the fragment that you want to retain when the fragment is
+paused or stopped, then resumed.</dd>
+  <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt>
+  <dd>The system calls this when it's time for the fragment to draw its user interface for the
+first time. To draw a UI for your fragment, you must return a {@link android.view.View} from this
+method that is the root of your fragment's layout. You can return null if the fragment does not
+provide a UI.</dd>
+  <dt>{@link android.app.Activity#onPause onPause()}</dt>
+  <dd>The system calls this method as the first indication that the user is leaving the
+fragment (though it does not always mean the fragment is being destroyed). This is usually where you
+should commit any changes that should be persisted beyond the current user session (because
+the user might not come back).</dd>
+</dl>
+
+<p>Most applications should implement at least these three methods for every fragment, but there are
+several other callback methods you should also use to handle various stages of the
+fragment lifecycle. All the lifecycle callback methods are discussed more later, in the section
+about <a href="#Lifecycle">Handling the Fragment Lifecycle</a>.</p>
+
+
+<p>There are also a few subclasses that you might want to extend, instead of the base {@link
+android.app.Fragment} class:</p>
+
+<dl>
+  <dt>{@link android.app.DialogFragment}</dt>
+  <dd>Displays a floating dialog. Using this class to create a dialog is a good alternative to using
+the dialog helper methods in the {@link android.app.Activity} class, because you can
+incorporate a fragment dialog into the back stack of fragments managed by the activity,
+allowing the user to return to a dismissed fragment.</dd>
+
+  <dt>{@link android.app.ListFragment}</dt>
+  <dd>Displays a list of items that are managed by an adapter (such as a {@link
+android.widget.SimpleCursorAdapter}), similar to {@link android.app.ListActivity}. It provides
+several methods for managing a list view, such as the {@link
+android.app.ListFragment#onListItemClick(ListView,View,int,long) onListItemClick()} callback to
+handle click events.</dd>
+
+  <dt>{@link android.preference.PreferenceFragment}</dt>
+  <dd>Displays a hierarchy of {@link android.preference.Preference} objects as a list, similar to
+{@link android.preference.PreferenceActivity}. This is useful when creating a "settings"
+activity for your application.</dd>
+</dl>
+
+
+<h3 id="UI">Adding a user interface</h3>
+
+<p>A fragment is usually used as part of an activity's user interface and contributes its own
+layout to the activity.</p>
+
+<p>To provide a layout for a fragment, you must implement the {@link
+android.app.Fragment#onCreateView onCreateView()} callback method, which the Android system calls
+when it's time for the fragment to draw its layout. Your implementation of this method must return a
+{@link android.view.View} that is the root of your fragment's layout.</p>
+
+<p class="note"><strong>Note:</strong> If your fragment is a subclass of {@link
+android.app.ListFragment}, the default implementation returns a {@link android.widget.ListView} from
+{@link android.app.Fragment#onCreateView onCreateView()}, so you don't need to implement it.</p>
+
+<p>To return a layout from {@link
+android.app.Fragment#onCreateView onCreateView()}, you can inflate it from a <a
+href="{@docRoot}guide/topics/resources/layout-resource.html">layout resource</a> defined in XML. To
+help you do so, {@link android.app.Fragment#onCreateView onCreateView()} provides a
+{@link android.view.LayoutInflater} object.</p>
+
+<p>For example, here's a subclass of {@link android.app.Fragment} that loads a layout from the
+{@code example_fragment.xml} file:</p>
+
+<pre>
+public static class ExampleFragment extends Fragment {
+    &#64;Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        // Inflate the layout for this fragment
+        return inflater.inflate(R.layout.example_fragment, container, false);
+    }
+}
+</pre>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+  <h3>Creating a layout</h3>
+  <p>In the sample above, {@code R.layout.example_fragment} is a reference to a layout resource
+named {@code example_fragment.xml} saved in the application resources. For information about how to
+create a layout in XML, see the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a>
+documentation.</p>
+</div>
+</div>
+
+<p>The {@code container} parameter passed to {@link android.app.Fragment#onCreateView
+onCreateView()} is the parent {@link android.view.ViewGroup} (from the activity's layout) in which
+your fragment layout
+will be inserted. The {@code savedInstanceState} parameter is a {@link android.os.Bundle} that
+provides data about the previous instance of the fragment, if the fragment is being resumed
+(restoring state is discussed more in the section about <a href="#Lifecycle">Handling the
+Fragment Lifecycle</a>).</p>
+
+<p>The {@link android.view.LayoutInflater#inflate(int,ViewGroup,boolean) inflate()} method takes
+three arguments:</p>
+<ul>
+  <li>The resource ID of the layout you want to inflate.</li>
+  <li>The {@link android.view.ViewGroup} to be the parent of the inflated layout. Passing the {@code
+container} is important in order for the system to apply layout parameters to the root view of the
+inflated layout, specified by the parent view in which it's going.</li>
+  <li>A boolean indicating whether the inflated layout should be attached to the {@link
+android.view.ViewGroup} (the second parameter) during inflation. (In this case, this
+is false because the system is already inserting the inflated layout into the {@code
+container}&mdash;passing true would create a redundant view group in the final layout.)</li>
+</ul>
+
+<p>Now you've seen how to create a fragment that provides a layout. Next, you need to add
+the fragment to your activity.</p>
+
+
+
+<h3 id="Adding">Adding a fragment to an activity</h3>
+
+<p>Usually, a fragment contributes a portion of UI to the host activity, which is embedded as a part
+of the activity's overall view hierarchy. There are two ways you can add a fragment to the activity
+layout:</p>
+
+<ul>
+  <li><b>Declare the fragment inside the activity's layout file.</b>
+<p>In this case, you can
+specify layout properties for the fragment as if it were a view. For example, here's the layout
+file for an activity with two fragments:</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"&gt;
+    &lt;fragment android:name="com.example.news.ArticleListFragment"
+            android:id="@+id/list"
+            android:layout_weight="1"
+            android:layout_width="0dp"
+            android:layout_height="match_parent" /&gt;
+    &lt;fragment android:name="com.example.news.ArticleReaderFragment"
+            android:id="@+id/viewer"
+            android:layout_weight="2"
+            android:layout_width="0dp"
+            android:layout_height="match_parent" /&gt;
+&lt;/LinearLayout&gt;
+</pre>
+  <p>The {@code android:name} attribute in the {@code &lt;fragment&gt;} specifies the {@link
+android.app.Fragment} class to instantiate in the layout.</p>
+
+<p>When the system creates this activity layout, it instantiates each fragment specified in the
+layout and calls the {@link android.app.Fragment#onCreateView onCreateView()} method for each one,
+to retrieve each fragment's layout. The system inserts the {@link android.view.View} returned by the
+fragment directly in place of the {@code &lt;fragment&gt;} element.</p>
+
+<div class="note">
+  <p><strong>Note:</strong> Each fragment requires a unique identifier that
+the system can use to restore the fragment if the activity is restarted (and which you can use to
+capture the fragment to perform transactions, such as remove it). There are three ways to provide an
+ID for a fragment:</p>
+  <ul>
+    <li>Supply the {@code android:id} attribute with a unique ID.</li>
+    <li>Supply the {@code android:tag} attribute with a unique string.</li>
+    <li>If you provide neither of the previous two, the system uses the ID of the container 
+view.</li>
+  </ul>
+</div>
+  </li>
+
+  <li><b>Or, programmatically add the fragment to an existing {@link android.view.ViewGroup}.</b>
+<p>At any time while your activity is running, you can add fragments to your activity layout. You
+simply need to specify a {@link
+android.view.ViewGroup} in which to place the fragment.</p>
+  <p>To make fragment transactions in your activity (such as add, remove, or replace a
+fragment), you must use APIs from {@link android.app.FragmentTransaction}. You can get an instance
+of {@link android.app.FragmentTransaction} from your {@link android.app.Activity} like this:</p>
+
+<pre>
+FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()}
+FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()};
+</pre>
+
+<p>You can then add a fragment using the {@link
+android.app.FragmentTransaction#add(int,Fragment) add()} method, specifying the fragment to add and
+the view in which to insert it. For example:</p>
+
+<pre>
+ExampleFragment fragment = new ExampleFragment();
+fragmentTransaction.add(R.id.fragment_container, fragment);
+fragmentTransaction.commit();
+</pre>
+
+  <p>The first argument passed to {@link android.app.FragmentTransaction#add(int,Fragment) add()}
+is the {@link android.view.ViewGroup} in which the fragment should be placed, specified by
+resource ID, and the second parameter is the fragment to add.</p>
+  <p>Once you've made your changes with
+{@link android.app.FragmentTransaction}, you must
+call {@link android.app.FragmentTransaction#commit} for the changes to take effect.</p>
+  </li>
+</ul>
+
+
+<h4 id="AddingWithoutUI">Adding a fragment without a UI</h4>
+
+<p>The examples above show how to add a fragment to your activity in order to provide a UI. However,
+you can also use a fragment to provide a background behavior for the activity without presenting
+additional UI.</p>
+
+<p>To add a fragment without a UI, add the fragment from the activity using {@link
+android.app.FragmentTransaction#add(Fragment,String)} (supplying a unique string "tag" for the
+fragment, rather than a view ID). This adds the fragment, but, because it's not associated with a
+view in the activity layout, it does not receive a call to {@link
+android.app.Fragment#onCreateView onCreateView()}. So you don't need to implement that method.</p>
+
+<p>Supplying a string tag for the fragment isn't strictly for non-UI fragments&mdash;you can also
+supply string tags to fragments that do have a UI&mdash;but if the fragment does not have a
+UI, then the string tag is the only way to identify it. If you want to get the fragment from the
+activity later, you need to use {@link android.app.FragmentManager#findFragmentByTag
+findFragmentByTag()}.</p>
+
+<p>For an example activity that uses a fragment as a background worker, without a UI, see the <a
+href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentRetainInstance.html">{@code
+FragmentRetainInstance.java}</a> sample.</p>
+
+
+
+<h2 id="Managing">Managing Fragments</h2>
+
+<p>To manage the fragments in your activity, you need to use {@link android.app.FragmentManager}. To
+get it, call {@link android.app.Activity#getFragmentManager()} from your activity.</p>
+
+<p>Some things that you can do with {@link android.app.FragmentManager} include:</p>
+
+<ul>
+  <li>Get fragments that exist in the activity, with {@link
+android.app.FragmentManager#findFragmentById findFragmentById()} (for fragments that provide a UI in
+the activity layout) or {@link android.app.FragmentManager#findFragmentByTag
+findFragmentByTag()} (for fragments that do or don't provide a UI).</li> 
+  <li>Pop fragments off the back stack, with {@link
+android.app.FragmentManager#popBackStack()} (simulating a BACK command by the user).</li>
+  <li>Register a listener for changes to the back stack, with {@link
+android.app.FragmentManager#addOnBackStackChangedListener addOnBackStackChangedListener()}.</li>
+</ul>
+
+<p>For more information about these methods and others, refer to the {@link
+android.app.FragmentManager} class documentation.</p>
+
+<p>As demonstrated in the previous section, you can also use {@link android.app.FragmentManager}
+to open a {@link android.app.FragmentTransaction}, which allows you to perform transactions, such as
+add and remove fragments.</p>
+
+
+<h2 id="Transactions">Performing Fragment Transactions</h2>
+
+<p>A great feature about using fragments in your activity is the ability to add, remove, replace,
+and perform other actions with them, in response to user interaction. Each set of changes that you
+commit to the activity is called a transaction and you can perform one using APIs in {@link
+android.app.FragmentTransaction}. You can also save each transaction to a back stack managed by the
+activity, allowing the user to navigate backward through the fragment changes (similar to navigating
+backward through activities).</p>
+
+<p>You can acquire an instance of {@link android.app.FragmentTransaction} from the {@link
+android.app.FragmentManager} like this:</p>
+
+<pre>
+FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()};
+FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()};
+</pre>
+
+<p>Each transaction is a set of changes that you want to perform at the same time. You can set
+up all the changes you want to perform for a given transaction using methods such as {@link
+android.app.FragmentTransaction#add add()}, {@link android.app.FragmentTransaction#remove remove()},
+and {@link android.app.FragmentTransaction#replace replace()}. Then, to apply the transaction
+to the activity, you must call {@link android.app.FragmentTransaction#commit()}.</p>
+</dl>
+
+<p>Before you call {@link
+android.app.FragmentTransaction#commit()}, however, you might want to call {@link
+android.app.FragmentTransaction#addToBackStack addToBackStack()}, in order to add the transaction
+to a back stack of fragment transactions. This back stack is managed by the activity and allows
+the user to return to the previous fragment state, by pressing the BACK key.</p>
+
+<p>For example, here's how you can replace one fragment with another, and preserve the previous
+state in the back stack:</p>
+
+<pre>
+// Create new fragment and transaction
+Fragment newFragment = new ExampleFragment();
+FragmentTransaction transaction = getFragmentManager().beginTransaction();
+
+// Replace whatever is in the fragment_container view with this fragment,
+// and add the transaction to the back stack
+transaction.replace(R.id.fragment_container, newFragment);
+transaction.addToBackStack(null);
+
+// Commit the transaction
+transaction.commit();
+</pre>
+
+<p>In this example, {@code newFragment} replaces whatever fragment (if any) is currently in the
+layout container identified by the {@code R.id.fragment_container} ID. By calling {@link
+android.app.FragmentTransaction#addToBackStack addToBackStack()}, the replace transaction is
+saved to the back stack so the user can reverse the transaction and bring back the
+previous fragment by pressing the BACK key.</p>
+
+<p>If you add multiple changes to the transaction (such as another {@link
+android.app.FragmentTransaction#add add()} or {@link android.app.FragmentTransaction#remove
+remove()}) and call {@link
+android.app.FragmentTransaction#addToBackStack addToBackStack()}, then all changes applied
+before you call {@link android.app.FragmentTransaction#commit commit()} are added to the
+back stack as a single transaction and the BACK key will reverse them all together.</p>
+
+<p>The order in which you add changes to a {@link android.app.FragmentTransaction} doesn't matter,
+except:</p>
+<ul>
+  <li>You must call {@link android.app.FragmentTransaction#commit()} last</li>
+  <li>If you're adding multiple fragments to the same container, then the order in which
+you add them determines the order they appear in the view hierarchy</li>
+</ul>
+
+<p>If you do not call {@link android.app.FragmentTransaction#addToBackStack(String)
+addToBackStack()} when you perform a transaction that removes a fragment, then that fragment is
+destroyed when the transaction is committed and the user cannot navigate back to it. Whereas, if you
+do call {@link android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} when
+removing a fragment, then the fragment is <em>stopped</em> and will be resumed if the user navigates
+back.</p>
+
+<p class="note"><strong>Tip:</strong> For each fragment transaction, you can apply a transition
+animation, by calling {@link android.app.FragmentTransaction#setTransition setTransition()} before
+you commit.</p>
+
+<p>Calling {@link android.app.FragmentTransaction#commit()} does not perform the transaction
+immediately. Rather, it schedules it to run on the activity's UI thread (the "main" thread) as soon
+as the thread is able to do so. If necessary, however, you may call {@link
+android.app.FragmentManager#executePendingTransactions()} from your UI thread to immediately execute
+transactions submitted by {@link android.app.FragmentTransaction#commit()}. Doing so is
+usually not necessary unless the transaction is a dependency for jobs in other threads.</p>
+
+<p class="caution"><strong>Caution:</strong> You can commit a transaction using {@link
+android.app.FragmentTransaction#commit commit()} only prior to the activity <a
+href="{@docRoot}guide/topics/fundamentals/activities.html#SavingActivityState">saving its
+state</a> (when the user leaves the activity). If you attempt to commit after that point, an
+exception will be thrown. This is because the state after the commit can be lost if the activity
+needs to be restored. For situations in which its okay that you lose the commit, use {@link
+android.app.FragmentTransaction#commitAllowingStateLoss()}.</p>
+
+
+
+
+<h2 id="CommunicatingWithActivity">Communicating with the Activity</h2>
+
+<p>Although a {@link android.app.Fragment} is implemented as an object that's independent from an
+{@link android.app.Activity} and can be used inside multiple activities, a given instance of
+a fragment is directly tied to the activity that contains it.</p>
+
+<p>Specifically, the fragment can access the {@link android.app.Activity} instance with {@link
+android.app.Fragment#getActivity()} and easily perform tasks such as find a view in the
+activity layout:</p>
+
+<pre>
+View listView = {@link android.app.Fragment#getActivity()}.{@link android.app.Activity#findViewById findViewById}(R.id.list);
+</pre>
+
+<p>Likewise, your activity can call methods in the fragment by acquiring a reference to the
+{@link android.app.Fragment} from {@link android.app.FragmentManager}, using {@link
+android.app.FragmentManager#findFragmentById findFragmentById()} or {@link
+android.app.FragmentManager#findFragmentByTag findFragmentByTag()}. For example:</p>
+
+<pre>
+ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
+</pre>
+
+
+<h4 id="EventCallbacks">Creating event callbacks to the activity</h4>
+
+<p>In some cases, you might need a fragment to share events with the activity. A good way to do that
+is to define a callback interface inside the fragment and require that the host activity implement
+it. When the activity receives a callback through the interface, it can share the information with
+other fragments in the layout as necessary.</p>
+
+<p>For example, if a news application has two fragments in an activity&mdash;one to show a list of
+articles (fragment A) and another to display an article (fragment B)&mdash;then fragment A must tell
+the activity when a list item is selected so that it can tell fragment B to display the article. In
+this case, the {@code OnArticleSelectedListener} interface is declared inside fragment A:</p>
+
+<pre>
+public static class FragmentA extends ListFragment {
+    ...
+    // Container Activity must implement this interface
+    public interface OnArticleSelectedListener {
+        public void onArticleSelected(Uri articleUri);
+    }
+    ...
+}
+</pre>
+
+<p>Then the activity that hosts the fragment implements the {@code OnArticleSelectedListener}
+interface and
+overrides {@code onArticleSelected()} to notify fragment B of the event from fragment A. To ensure
+that the host activity implements this interface, fragment A's {@link
+android.app.Fragment#onAttach onAttach()} callback method (which the system calls when adding
+the fragment to the activity) instantiates an instance of {@code OnArticleSelectedListener} by
+casting the {@link android.app.Activity} that is passed into {@link android.app.Fragment#onAttach
+onAttach()}:</p>
+
+<pre>
+public static class FragmentA extends ListFragment {
+    OnArticleSelectedListener mListener;
+    ...
+    &#64;Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        try {
+            mListener = (OnArticleSelectedListener) activity;
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
+        }
+    }
+    ...
+}
+</pre>
+
+<p>If the activity has not implemented the interface, then the fragment throws a
+{@link java.lang.ClassCastException}.
+On success, the {@code mListener} member holds a reference to activity's implementation of 
+{@code OnArticleSelectedListener}, so that fragment A can share events with the activity by calling
+methods defined by the {@code OnArticleSelectedListener} interface. For example, if fragment A is an
+extension of {@link android.app.ListFragment}, each time
+the user clicks a list item, the system calls {@link android.app.ListFragment#onListItemClick
+onListItemClick()} in the fragment, which then calls {@code onArticleSelected()} to share
+the event with the activity:</p>
+
+<pre>
+public static class FragmentA extends ListFragment {
+    OnArticleSelectedListener mListener;
+    ...
+    &#64;Override
+    public void onListItemClick(ListView l, View v, int position, long id) {
+        // Append the clicked item's row ID with the content provider Uri
+        Uri noteUri = ContentUris.{@link android.content.ContentUris#withAppendedId withAppendedId}(ArticleColumns.CONTENT_URI, id);
+        // Send the event and Uri to the host activity
+        mListener.onArticleSelected(noteUri);
+    }
+    ...
+}
+</pre>
+
+<p>The {@code id} parameter passed to {@link
+android.app.ListFragment#onListItemClick onListItemClick()} is the row ID of the clicked item,
+which the activity (or other fragment) uses to fetch the article from the application's {@link
+android.content.ContentProvider}.</p>
+
+<p><!--To see a complete implementation of this kind of callback interface, see the <a
+href="{@docRoot}resources/samples/NotePad/index.html">NotePad sample</a>. -->More information about
+using a content provider is available in the <a
+href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> document.</p>
+
+
+
+<h3 id="ActionBar">Adding items to the Action Bar</h3>
+
+<p>Your fragments can contribute menu items to the activity's <a
+href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options Menu</a> (and, consequently, the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>) by implementing
+{@link android.app.Fragment#onCreateOptionsMenu(Menu,MenuInflater) onCreateOptionsMenu()}. In order
+for this method to receive calls, however, you must call {@link
+android.app.Fragment#setHasOptionsMenu(boolean) setHasOptionsMenu()} during {@link
+android.app.Fragment#onCreate(Bundle) onCreate()}, to indicate that the fragment
+would like to add items to the Options Menu (otherwise, the fragment will not receive a call to
+{@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()}).</p>
+
+<p>Any items that you then add to the Options Menu from the fragment are appended to the existing
+menu items. The fragment also receives callbacks to {@link
+android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} when a menu item
+is selected.</p>
+
+<p>You can also register a view in your fragment layout to provide a context menu by calling {@link
+android.app.Fragment#registerForContextMenu(View) registerForContextMenu()}. When the user opens
+the context menu, the fragment receives a call to {@link
+android.app.Fragment#onCreateContextMenu(ContextMenu,View,ContextMenu.ContextMenuInfo)
+onCreateContextMenu()}. When the user selects an item, the fragment receives a call to {@link
+android.app.Fragment#onContextItemSelected(MenuItem) onContextItemSelected()}.</p>
+
+<p class="note"><strong>Note:</strong> Although your fragment receives an on-item-selected callback
+for each menu item it adds, the activity is first to receive the respective callback when the user
+selects a menu item. If the activity's implementation of the on-item-selected callback does not
+handle the selected item, then the event is passed to the fragment's callback. This is true for
+the Options Menu and context menus.</p>
+
+<p>For more information about menus, see <a href="{@docRoot}guide/topics/ui/menus.html">Creating
+Menus</a> and <a href="{@docRoot}guide/topics/ui/actionbar.html">Using the Action Bar</a>.</p>
+
+
+
+
+<h2 id="Lifecycle">Handling the Fragment Lifecycle</h2>
+
+<div class="figure" style="width:403px">
+<img src="{@docRoot}images/activity_fragment_lifecycle.png" alt=""/>
+<p class="img-caption"><strong>Figure 3.</strong> The activity lifecycle's affect on the fragment
+lifecycle.</p>
+</div>
+
+<p>Managing the lifecycle of a fragment is a lot like managing the lifecycle of an activity. Like
+an activity, a fragment can exist in three states:</p>
+
+<dl>
+  <dt><i>Resumed</i></dt>
+    <dd>The fragment is visible in the running activity.</dd>
+
+  <dt><i>Paused</i></dt>
+    <dd>Another activity is in the foreground and has focus, but the activity in which this
+fragment lives is still visible (the foreground activity is partially transparent or doesn't
+cover the entire screen).</dd>
+
+  <dt><i>Stopped</i></dt>
+    <dd>The fragment is not visible. Either the host activity has been stopped or the
+fragment has been removed from the activity but added to the back stack. A stopped fragment is
+still alive (all state and member information is retained by the system). However, it is no longer
+visible to the user and will be killed if the activity is killed.</dd>
+</dl>
+
+<p>Also like an activity, you can retain the state of a fragment using a {@link
+android.os.Bundle}, in case the activity's process is killed and you need to restore the
+fragment state when the activity is recreated. You can save the state during the fragment's {@link
+android.app.Fragment#onSaveInstanceState onSaveInstanceState()} callback and restore it during
+either {@link android.app.Fragment#onCreate onCreate()}, {@link
+android.app.Fragment#onCreateView onCreateView()}, or {@link
+android.app.Fragment#onActivityCreated onActivityCreated()}. For more information about saving
+state, see the <a
+href="{@docRoot}guide/topics/fundamentals/activities.html#SavingActivityState">Activities</a>
+document.</p>
+
+<p>The most significant difference in lifecycle between an activity and a fragment is how one is
+stored in its respective back stack. An activity is placed into a back stack of activities
+that's managed by the system when it's stopped, by default (so that the user can navigate back
+to it with the BACK key, as discussed in <a
+href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a>).
+However, a fragment is placed into a back stack managed by the host activity only when you
+explicitly request that the instance be saved by calling {@link
+android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} during a transaction that
+removes the fragment.</p>
+
+<p>Otherwise, managing the fragment lifecycle is very similar to managing the activity
+lifecycle. So, the same practices for <a
+href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">managing the activity
+lifecycle</a> also apply to fragments. What you also need to understand, though, is how the life
+of the activity affects the life of the fragment.</p>
+
+
+<h3 id="CoordinatingWithActivity">Coordinating with the activity lifecycle</h3>
+
+<p>The lifecycle of the activity in which the fragment lives directly affects the lifecycle of the
+fragment, such that each lifecycle callback for the activity results in a similar callback for each
+fragment. For example, when the activity receives {@link android.app.Activity#onPause}, each
+fragment in the activity receives {@link android.app.Fragment#onPause}.</p>
+
+<p>Fragments have a few extra lifecycle callbacks, however, that handle unique interaction with the
+activity in order to perform actions such as build and destroy the fragment's UI. These additional
+callback methods are:</p>
+
+<dl>
+  <dt>{@link android.app.Fragment#onAttach onAttach()}</dt>
+    <dd>Called when the fragment has been associated with the activity (the {@link
+android.app.Activity} is passed in here).</dd>
+  <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt>
+    <dd>Called to create the view hierarchy associated with the fragment.</dd>
+  <dt>{@link android.app.Fragment#onActivityCreated onActivityCreated()}</dt>
+    <dd>Called when the activity's {@link android.app.Activity#onCreate
+onCreate()} method has returned.</dd>
+  <dt>{@link android.app.Fragment#onDestroyView onDestroyView()}</dt>
+    <dd>Called when the view hierarchy associated with the fragment is being removed.</dd>
+  <dt>{@link android.app.Fragment#onDetach onDetach()}</dt>
+    <dd>Called when the fragment is being disassociated from the activity.</dd>
+</dl>
+
+<p>The flow of a fragment's lifecycle, as it is affected by its host activity, is illustrated
+by figure 3. In this figure, you can see how each successive state of the activity determines which
+callback methods a fragment may receive. For example, when the activity has received its {@link
+android.app.Activity#onCreate onCreate()} callback, a fragment in the activity receives no more than
+the {@link android.app.Fragment#onActivityCreated onActivityCreated()} callback.</p>
+
+<p>Once the activity reaches the resumed state, you can freely add and remove fragments to the
+activity. Thus, only while the activity is in the resumed state can the lifecycle of a fragment
+change independently.</p>
+
+<p>However, when the activity leaves the resumed state, the fragment again is pushed through its
+lifecycle by the activity.</p>
+
+
+
+
+<h2 id="Example">Example</h2>
+
+<p>To bring everything discussed in this document together, here's an example of an activity
+using two fragments to create a two-pane layout. The activity below includes one fragment to
+show a list of Shakespeare play titles and another to show a summary of the play when selected
+from the list. It also demonstrates how to provide different configurations of the fragments,
+based on the screen configuration.</p>
+
+<p class="note"><strong>Note:</strong> The complete source code for this activity is available in
+<a href="resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.html">{@code
+FragmentLayout.java}</a>.</p>
+
+<p>The main activity applies a layout in the usual way, during {@link
+android.app.Activity#onCreate onCreate()}:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java main}
+
+<p>The layout applied is {@code fragment_layout.xml}:</p>
+
+{@sample development/samples/ApiDemos/res/layout-land/fragment_layout.xml layout}
+
+<p>Using this layout, the system instantiates the {@code TitlesFragment} (which lists the play
+titles) as soon as the activity loads the layout, while the {@link android.widget.FrameLayout}
+(where the fragment for showing the play summary will go) consumes space on the right side of the
+screen, but remains empty at first. As you'll see below, it's not until the user selects an item
+from the list that a fragment is placed into the {@link android.widget.FrameLayout}.</p>
+
+<p>However, not all screen configurations are wide enough to show both the list of
+plays and the summary, side by side. So, the layout above is used only for the landscape
+screen configuration, by saving it at {@code res/layout-land/fragment_layout.xml}.</p>
+
+<p>Thus, when the screen is in portrait orientation, the system applies the following layout, which
+is saved at {@code res/layout/fragment_layout.xml}:</p>
+
+{@sample development/samples/ApiDemos/res/layout/fragment_layout.xml layout}
+
+<p>This layout includes only {@code TitlesFragment}. This means that, when the device is in
+portrait orientation, only the list of play titles is visible. So, when the user clicks a list
+item in this configuration, the application will start a new activity to show the summary,
+instead of loading a second fragment.</p>
+
+<p>Next, you can see how this is accomplished in the fragment classes. First is {@code
+TitlesFragment}, which shows the list of Shakespeare play titles. This fragment extends {@link
+android.app.ListFragment} and relies on it to handle most of the list view work.</p>
+
+<p>As you inspect this code, notice that there are two possible behaviors when the user clicks a
+list item: depending on which of the two layouts is active, it can either create and display a new
+fragment to show the details in the same activity (adding the fragment to the {@link
+android.widget.FrameLayout}), or start a new activity (where the fragment can be shown).</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java titles}
+
+<p>The second fragment, {@code DetailsFragment} shows the play summary for the item selected from
+the list from {@code TitlesFragment}:</p>
+ 
+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java details}
+
+<p>Recall from the {@code TitlesFragment} class, that, if the user clicks a list item and the
+current layout does <em>not</em> include the {@code R.id.details} view (which is where the
+{@code DetailsFragment} belongs), then the application starts the {@code DetailsActivity}
+activity to display the content of the item.</p>
+
+<p>Here is the {@code DetailsActivity}, which simply embeds the {@code DetailsFragment} to display
+the selected play summary when the screen is in portrait orientation:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java
+details_activity}
+ 
+<p>Notice that this activity finishes itself if the configuration is landscape, so that the main
+activity can take over and display the {@code DetailsFragment} alongside the {@code TitlesFragment}.
+This can happen if the user begins the {@code DetailsActivity} while in portrait orientation, but
+then rotates to landscape (which restarts the current activity).</p>
+
+
+<p>For more samples using fragments (and complete source files for this example),
+see the sample code available in <a
+href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/index.html#Fragment">
+ApiDemos</a> (available for download from the <a
+href="{@docRoot}resources/samples/get.html">Samples SDK component</a>).</p>
+
+
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index 44d75c1..c17fc3c 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -53,7 +53,7 @@
 items"&mdash;providing instant access to key user actions. (Menu items not appearing as action
 items are placed in the Overflow Menu, revealed by a drop-down in the Action Bar.)</li>
   <li>Provide tabs for navigating between <a
-href="{@docRoot}guide/topics/fragments/index.html">fragments</a>.</li>
+href="{@docRoot}guide/topics/fundamentals/fragments.html">fragments</a>.</li>
   <li>Provide drop-down navigation items.</li>
   <li>Provide interactive "action views" in place of action items.</li>
   <li>Use the application logo as a "return home" or "up" navigation action.</li>
@@ -432,7 +432,7 @@
 the state of each fragment as necessary, so when the user switches fragments with the tabs,
 then returns to a previous fragment, it appears the way they left. For information about saving
 the state of your fragment, see the <a
-href="{@docRoot}guide/topics/fragments/index.html">Fragments</a> developer guide.</p>
+href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
 
 
 
diff --git a/docs/html/images/fundamentals/fragments.png b/docs/html/images/fundamentals/fragments.png
new file mode 100644
index 0000000..b3b7b23
--- /dev/null
+++ b/docs/html/images/fundamentals/fragments.png
Binary files differ
diff --git a/docs/html/offline.jd b/docs/html/offline.jd
index fe70d50..1064a99 100644
--- a/docs/html/offline.jd
+++ b/docs/html/offline.jd
@@ -2,48 +2,59 @@
 page.title=Welcome
 @jd:body
 
+<style type="text/css">
+#qv h2 {
+  font-size:1.5em;
+  font-weight:bold;
+  margin:12px 0 .5em 0;
+  padding:5px;
+  color:#7BB026;
+  border:none;
+}
+#qv ul li {
+  padding: 0 5px 1em 0;
+}
+</style>
 <div id="mainBodyFluid">
 
 <h1>Welcome to the Android SDK!</h1>
 
-<img src="{@docRoot}assets/images/home/sdk-large.png" style="float:right; margin:-2em 3em 3em;" />
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>Get Started</h2>
+  <ul>
+    <li>Create a <a href="{@docRoot}resources/tutorials/hello-world.html">Hello World</a>
+application</li>
+    <li>Read <a href="{@docRoot}resources/browser.html?tag=sample">Sample Code</a>,
+especially <a href="{@docRoot}resources/samples/ApiDemos/index.html">API Demos</a></li>
+    <li>Read the <a href="{@docRoot}guide/topics/fundamentals/index.html">Application
+Fundamentals</a></li>
+    <li>Read the <a href="{@docRoot}guide/developing/index.html">Overview</a> for using the SDK
+tools</li>
+  </ul>
+</div>
+</div>
 
-<h3>If you've downloaded the Android SDK for the first time...</h3>
+<h3>If you've downloaded the Android SDK for the first time</h3>
 
-<p>Follow the online guide to 
-<a href="{@docRoot}sdk/installing.html">Installing 
-the Android SDK</a>, which will help you setup your development environment
-(including the Android Development Tools plugin for Eclipse) 
-so you can start developing Android apps.</p>
+<p>Follow the guide to <a href="{@docRoot}sdk/installing.html">Installing the Android SDK</a>, which
+will help you setup your development environment.</p>
 
-<p>Once your environment is setup, look at the
-<a href="{@docRoot}sdk/installing.html#NextSteps">Next
-Steps</a> for some suggestions on how to begin learning about Android.</p>
-
-<h3>If you've just installed new SDK components using the <em>SDK and AVD Manager</em>...</h3>
+<h3>If you've installed new SDK components using the SDK and AVD Manager</h3>
 
 <p>There's no additional setup.</p>
 
-<p>Newly installed Android platforms are automatically saved in the 
-<code><em>&lt;sdk_dir>/</em>platforms/</code> directory of your existing SDK;
-new add-ons are saved in the <code><em>&lt;sdk_dir>/</em>add-ons/</code>
-directory; and new documentation is saved in the existing
-<code><em>&lt;sdk_dir>/</em>docs/</code> directory (old docs are replaced).</p>
+<p>New Android platforms are saved in the <code>&lt;sdk>/platforms/</code> directory of
+your existing SDK and new add-ons are saved in the <code>&lt;sdk>/add-ons/</code> directory.</p>
 
 
-<hr style="margin:2em 0;" />
+<div class="note">
+<p><strong>Note:</strong> You are currently viewing the offline version of the Android developer
+documentation. Because some features such as search and videos are network-based, not everything
+will work if you are not connected to the Internet. Additionally, the online version may contain
+more recently updated documents.</p>
 
-<p>Note that you are currently viewing a local, offline version of the
-Android developer documentation. The offline documentation offers almost all the same
-content and features as the online documentation. Because some features
-such as search and videos are network-based, not everything will work if you
-are not connected to the Internet.</p>
-
-<p>For the most current documentation and a fully-functional experience, please visit:</p>
-<p style="margin-left:2em;">
-<a href="http://developer.android.com">http://developer.android.com</a></strong>.
+<p>For the latest documentation, please visit
+<b><a href="http://developer.android.com">developer.android.com</a></b>.
 </p>
-
-
-
 </div>
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 9e1ff9c..2780135 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -35,18 +35,20 @@
         </a></li>
 
     </ul>
-  </li><?cs
-  /if ?>
-  <?cs
+  </li>
+  <?cs /if ?><?cs
   if:sdk.preview ?>
-  <li><h2>Android Preview SDK</h2></li>
+  <li><h2>Android 3.0 Preview SDK</h2>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/preview/features.html">Introduction
-to Honeycomb</a></li>
-<!--
-      <li><a href="<?cs var:toroot ?>sdk/preview/installing.html">Getting
-Started</a></li>
--->
+      <li><a href="<?cs var:toroot ?>sdk/preview/start.html">Getting Started</a> <span class="new">new!</span></li>
+      <li class="toggle-list">
+        <div><a href="<?cs var:toroot ?>sdk/preview/platform.html">
+        <span class="en">Android 3.0 Platform</span></a> <span class="new">new!</span></div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>sdk/preview/highlights.html">Platform Highlights</a></li> 
+          <li><a href="<?cs var:toroot ?>sdk/api_diff/honeycomb/changes.html">API Differences Report &raquo;</a></li>
+        </ul>
+      </li>
     </ul>
   </li><?cs
   /if ?>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index a8efd00..e67ceed 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -53,6 +53,7 @@
      */
     public byte[] mBuffer;
 
+    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources
     private final BitmapFinalizer mFinalizer;
 
     private final boolean mIsMutable;
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 8309f7a..cffee5f 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -64,6 +64,14 @@
         public Bitmap inBitmap;
 
         /**
+         * If set, decode methods will always return a mutable Bitmap instead of
+         * an immutable one. This can be used for instance to programmatically apply
+         * effects to a Bitmap loaded through BitmapFactory.
+         */
+        @SuppressWarnings({"UnusedDeclaration"}) // used in native code
+        public boolean inMutable;
+
+        /**
          * If set to true, the decoder will return null (no bitmap), but
          * the out... fields will still be set, allowing the caller to query
          * the bitmap without having to allocate the memory for its pixels.
@@ -523,7 +531,7 @@
             }
             bm.setDensity(targetDensity);
         }
-        
+
         return bm;
     }
     
@@ -556,11 +564,22 @@
      * @return the decoded bitmap, or null
      */
     public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
-        Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
-        if (bm == null && opts != null && opts.inBitmap != null) {
-            throw new IllegalArgumentException("Problem decoding into existing bitmap");
+        if (nativeIsSeekable(fd)) {
+            Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
+            if (bm == null && opts != null && opts.inBitmap != null) {
+                throw new IllegalArgumentException("Problem decoding into existing bitmap");
+            }
+            return finishDecode(bm, outPadding, opts);
+        } else {
+            FileInputStream fis = new FileInputStream(fd);
+            try {
+                return decodeStream(fis, outPadding, opts);
+            } finally {
+                try {
+                    fis.close();
+                } catch (Throwable t) {/* ignore */}
+            }
         }
-        return finishDecode(bm, outPadding, opts);
     }
 
     /**
@@ -607,4 +626,5 @@
     private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
             int length, Options opts);
     private static native byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad);
+    private static native boolean nativeIsSeekable(FileDescriptor fd);
 }
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 852aabf..1789891 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -121,6 +121,58 @@
         mType = t;
     }
 
+    private void validateIsInt32() {
+        if ((mType.mElement.mType == Element.DataType.SIGNED_32) ||
+            (mType.mElement.mType == Element.DataType.UNSIGNED_32)) {
+            return;
+        }
+        throw new RSIllegalArgumentException(
+            "32 bit integer source does not match allocation type " + mType.mElement.mType);
+    }
+
+    private void validateIsInt16() {
+        if ((mType.mElement.mType == Element.DataType.SIGNED_16) ||
+            (mType.mElement.mType == Element.DataType.UNSIGNED_16)) {
+            return;
+        }
+        throw new RSIllegalArgumentException(
+            "16 bit integer source does not match allocation type " + mType.mElement.mType);
+    }
+
+    private void validateIsInt8() {
+        if ((mType.mElement.mType == Element.DataType.SIGNED_8) ||
+            (mType.mElement.mType == Element.DataType.UNSIGNED_8)) {
+            return;
+        }
+        throw new RSIllegalArgumentException(
+            "8 bit integer source does not match allocation type " + mType.mElement.mType);
+    }
+
+    private void validateIsFloat32() {
+        if (mType.mElement.mType == Element.DataType.FLOAT_32) {
+            return;
+        }
+        throw new RSIllegalArgumentException(
+            "32 bit float source does not match allocation type " + mType.mElement.mType);
+    }
+
+    private void validateIsObject() {
+        if ((mType.mElement.mType == Element.DataType.RS_ELEMENT) ||
+            (mType.mElement.mType == Element.DataType.RS_TYPE) ||
+            (mType.mElement.mType == Element.DataType.RS_ALLOCATION) ||
+            (mType.mElement.mType == Element.DataType.RS_SAMPLER) ||
+            (mType.mElement.mType == Element.DataType.RS_SCRIPT) ||
+            (mType.mElement.mType == Element.DataType.RS_MESH) ||
+            (mType.mElement.mType == Element.DataType.RS_PROGRAM_FRAGMENT) ||
+            (mType.mElement.mType == Element.DataType.RS_PROGRAM_VERTEX) ||
+            (mType.mElement.mType == Element.DataType.RS_PROGRAM_RASTER) ||
+            (mType.mElement.mType == Element.DataType.RS_PROGRAM_STORE)) {
+            return;
+        }
+        throw new RSIllegalArgumentException(
+            "Object source does not match allocation type " + mType.mElement.mType);
+    }
+
     @Override
     void updateFromNative() {
         super.updateFromNative();
@@ -151,6 +203,7 @@
 
     public void copyFrom(BaseObj[] d) {
         mRS.validate();
+        validateIsObject();
         if (d.length != mType.getCount()) {
             throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " +
                                                  mType.getCount() + ", array length = " + d.length);
@@ -258,7 +311,6 @@
         mRS.nAllocationData1D(getID(), xoff, 0, count, data, data.length);
     }
 
-
     /**
      * This is only intended to be used by auto-generate code reflected from the
      * renderscript script files.
@@ -317,27 +369,44 @@
         mRS.nAllocationGenerateMipmaps(getID());
     }
 
-    public void copy1DRangeFrom(int off, int count, int[] d) {
+    void copy1DRangeFromUnchecked(int off, int count, int[] d) {
         int dataSize = mType.mElement.getSizeBytes() * count;
         data1DChecks(off, count, d.length * 4, dataSize);
         mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
     }
-    public void copy1DRangeFrom(int off, int count, short[] d) {
+    void copy1DRangeFromUnchecked(int off, int count, short[] d) {
         int dataSize = mType.mElement.getSizeBytes() * count;
         data1DChecks(off, count, d.length * 2, dataSize);
         mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
     }
-    public void copy1DRangeFrom(int off, int count, byte[] d) {
+    void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
         int dataSize = mType.mElement.getSizeBytes() * count;
         data1DChecks(off, count, d.length, dataSize);
         mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
     }
-    public void copy1DRangeFrom(int off, int count, float[] d) {
+    void copy1DRangeFromUnchecked(int off, int count, float[] d) {
         int dataSize = mType.mElement.getSizeBytes() * count;
         data1DChecks(off, count, d.length * 4, dataSize);
         mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
     }
 
+    public void copy1DRangeFrom(int off, int count, int[] d) {
+        validateIsInt32();
+        copy1DRangeFromUnchecked(off, count, d);
+    }
+    public void copy1DRangeFrom(int off, int count, short[] d) {
+        validateIsInt16();
+        copy1DRangeFromUnchecked(off, count, d);
+    }
+    public void copy1DRangeFrom(int off, int count, byte[] d) {
+        validateIsInt8();
+        copy1DRangeFromUnchecked(off, count, d);
+    }
+    public void copy1DRangeFrom(int off, int count, float[] d) {
+        validateIsFloat32();
+        copy1DRangeFromUnchecked(off, count, d);
+    }
+
     private void validate2DRange(int xoff, int yoff, int w, int h) {
         if (xoff < 0 || yoff < 0) {
             throw new RSIllegalArgumentException("Offset cannot be negative.");
@@ -411,21 +480,25 @@
     }
 
     public void copyTo(byte[] d) {
+        validateIsInt8();
         mRS.validate();
         mRS.nAllocationRead(getID(), d);
     }
 
     public void copyTo(short[] d) {
+        validateIsInt16();
         mRS.validate();
         mRS.nAllocationRead(getID(), d);
     }
 
     public void copyTo(int[] d) {
+        validateIsInt32();
         mRS.validate();
         mRS.nAllocationRead(getID(), d);
     }
 
     public void copyTo(float[] d) {
+        validateIsFloat32();
         mRS.validate();
         mRS.nAllocationRead(getID(), d);
     }
diff --git a/graphics/java/android/renderscript/FileA3D.java b/graphics/java/android/renderscript/FileA3D.java
index fe3971a..79ee997 100644
--- a/graphics/java/android/renderscript/FileA3D.java
+++ b/graphics/java/android/renderscript/FileA3D.java
@@ -46,7 +46,13 @@
     **/
     public enum EntryType {
 
+        /**
+        * Unknown or or invalid object, nothing will be loaded
+        **/
         UNKNOWN (0),
+        /**
+        * Renderscript Mesh object
+        **/
         MESH (1);
 
         int mID;
@@ -74,14 +80,20 @@
         BaseObj mLoadedObj;
 
         /**
+        * Returns the name of a renderscript object the index entry
+        * describes
+        *
         * @return name of a renderscript object the index entry
-        *         describes
+        * describes
+        *
         */
         public String getName() {
             return mName;
         }
 
         /**
+        * Returns the type of a renderscript object the index entry
+        * describes
         * @return type of a renderscript object the index entry
         *         describes
         */
@@ -90,7 +102,8 @@
         }
 
         /**
-        * @return renderscript object described by the entry
+        * Used to load the object described by the index entry
+        * @return base renderscript object described by the entry
         */
         public BaseObj getObject() {
             mRS.validate();
@@ -99,6 +112,9 @@
         }
 
         /**
+        * Used to load the mesh described by the index entry, object
+        * described by the index entry must be a renderscript mesh
+        *
         * @return renderscript mesh object described by the entry
         */
         public Mesh getMesh() {
@@ -166,7 +182,9 @@
     }
 
     /**
-    * @return the numberof objects stored inside a FileA3D
+    * Returns the number of objects stored inside the a3d file
+    *
+    * @return the number of objects stored inside the a3d file
     */
     public int getIndexEntryCount() {
         if(mFileEntries == null) {
@@ -180,6 +198,8 @@
     * FileA3D
     *
     * @param index number of the entry from the list to return
+    *
+    * @return entry in the a3d file described by the index
     */
     public IndexEntry getIndexEntry(int index) {
         if(getIndexEntryCount() == 0 || index < 0 || index >= mFileEntries.length) {
@@ -195,6 +215,7 @@
     * @param mgr asset manager used to load asset
     * @param path location of the file to load
     *
+    * @return a3d file containing renderscript objects
     */
     static public FileA3D createFromAsset(RenderScript rs, AssetManager mgr, String path) {
         rs.validate();
@@ -214,6 +235,7 @@
     * @param rs Context to which the object will belong.
     * @param path location of the file to load
     *
+    * @return a3d file containing renderscript objects
     */
     static public FileA3D createFromFile(RenderScript rs, String path) {
         int fileId = rs.nFileA3DCreateFromFile(path);
@@ -232,6 +254,7 @@
     * @param rs Context to which the object will belong.
     * @param path location of the file to load
     *
+    * @return a3d file containing renderscript objects
     */
     static public FileA3D createFromFile(RenderScript rs, File path) {
         return createFromFile(rs, path.getAbsolutePath());
@@ -244,6 +267,7 @@
     * @param res resource manager used for loading
     * @param id resource to create FileA3D from
     *
+    * @return a3d file containing renderscript objects
     */
     static public FileA3D createFromResource(RenderScript rs, Resources res, int id) {
 
diff --git a/graphics/java/android/renderscript/Matrix2f.java b/graphics/java/android/renderscript/Matrix2f.java
index 2fffe8c..c9a0ea8 100644
--- a/graphics/java/android/renderscript/Matrix2f.java
+++ b/graphics/java/android/renderscript/Matrix2f.java
@@ -26,28 +26,61 @@
  **/
 public class Matrix2f {
 
+    /**
+    * Creates a new identity 2x2 matrix
+    */
     public Matrix2f() {
         mMat = new float[4];
         loadIdentity();
     }
 
+    /**
+    * Creates a new matrix and sets its values from the given
+    * parameter
+    *
+    * @param dataArray values to set the matrix to, must be 4
+    *                  floats long
+    */
     public Matrix2f(float[] dataArray) {
         mMat = new float[2];
         System.arraycopy(dataArray, 0, mMat, 0, mMat.length);
     }
 
+    /**
+    * Return a reference to the internal array representing matrix
+    * values. Modifying this array will also change the matrix
+    *
+    * @return internal array representing the matrix
+    */
     public float[] getArray() {
         return mMat;
     }
 
+    /**
+    * Returns the value for a given row and column
+    *
+    * @param i row of the value to return
+    * @param j column of the value to return
+    *
+    * @return value in the ith row and jth column
+    */
     public float get(int i, int j) {
         return mMat[i*2 + j];
     }
 
+    /**
+    * Sets the value for a given row and column
+    *
+    * @param i row of the value to set
+    * @param j column of the value to set
+    */
     public void set(int i, int j, float v) {
         mMat[i*2 + j] = v;
     }
 
+    /**
+    * Sets the matrix values to identity
+    */
     public void loadIdentity() {
         mMat[0] = 1;
         mMat[1] = 0;
@@ -56,10 +89,20 @@
         mMat[3] = 1;
     }
 
+    /**
+    * Sets the values of the matrix to those of the parameter
+    *
+    * @param src matrix to load the values from
+    */
     public void load(Matrix2f src) {
         System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length);
     }
 
+    /**
+    * Sets current values to be a rotation matrix of given angle
+    *
+    * @param rot rotation angle
+    */
     public void loadRotate(float rot) {
         float c, s;
         rot *= (float)(java.lang.Math.PI / 180.0f);
@@ -71,11 +114,25 @@
         mMat[3] = c;
     }
 
+    /**
+    * Sets current values to be a scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    */
     public void loadScale(float x, float y) {
         loadIdentity();
         mMat[0] = x;
         mMat[3] = y;
     }
+
+    /**
+    * Sets current values to be the result of multiplying two given
+    * matrices
+    *
+    * @param lhs left hand side matrix
+    * @param rhs right hand side matrix
+    */
     public void loadMultiply(Matrix2f lhs, Matrix2f rhs) {
         for (int i=0 ; i<2 ; i++) {
             float ri0 = 0;
@@ -90,21 +147,42 @@
         }
     }
 
+    /**
+    * Post-multiplies the current matrix by a given parameter
+    *
+    * @param rhs right hand side to multiply by
+    */
     public void multiply(Matrix2f rhs) {
         Matrix2f tmp = new Matrix2f();
         tmp.loadMultiply(this, rhs);
         load(tmp);
     }
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * rotation matrix of given angle
+    *
+    * @param rot angle of rotation
+    */
     public void rotate(float rot) {
         Matrix2f tmp = new Matrix2f();
         tmp.loadRotate(rot);
         multiply(tmp);
     }
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    */
     public void scale(float x, float y) {
         Matrix2f tmp = new Matrix2f();
         tmp.loadScale(x, y);
         multiply(tmp);
     }
+    /**
+    * Sets the current matrix to its transpose
+    */
     public void transpose() {
         float temp = mMat[1];
         mMat[1] = mMat[2];
diff --git a/graphics/java/android/renderscript/Matrix3f.java b/graphics/java/android/renderscript/Matrix3f.java
index e4c5e00..2ec8c62 100644
--- a/graphics/java/android/renderscript/Matrix3f.java
+++ b/graphics/java/android/renderscript/Matrix3f.java
@@ -26,28 +26,61 @@
  **/
 public class Matrix3f {
 
+    /**
+    * Creates a new identity 3x3 matrix
+    */
     public Matrix3f() {
         mMat = new float[9];
         loadIdentity();
     }
 
+    /**
+    * Creates a new matrix and sets its values from the given
+    * parameter
+    *
+    * @param dataArray values to set the matrix to, must be 9
+    *                  floats long
+    */
     public Matrix3f(float[] dataArray) {
         mMat = new float[9];
         System.arraycopy(dataArray, 0, mMat, 0, mMat.length);
     }
 
+    /**
+    * Return a reference to the internal array representing matrix
+    * values. Modifying this array will also change the matrix
+    *
+    * @return internal array representing the matrix
+    */
     public float[] getArray() {
         return mMat;
     }
 
+    /**
+    * Returns the value for a given row and column
+    *
+    * @param i row of the value to return
+    * @param j column of the value to return
+    *
+    * @return value in the ith row and jth column
+    */
     public float get(int i, int j) {
         return mMat[i*3 + j];
     }
 
+    /**
+    * Sets the value for a given row and column
+    *
+    * @param i row of the value to set
+    * @param j column of the value to set
+    */
     public void set(int i, int j, float v) {
         mMat[i*3 + j] = v;
     }
 
+    /**
+    * Sets the matrix values to identity
+    */
     public void loadIdentity() {
         mMat[0] = 1;
         mMat[1] = 0;
@@ -62,10 +95,24 @@
         mMat[8] = 1;
     }
 
+    /**
+    * Sets the values of the matrix to those of the parameter
+    *
+    * @param src matrix to load the values from
+    */
     public void load(Matrix3f src) {
         System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length);
     }
 
+    /**
+    * Sets current values to be a rotation matrix of certain angle
+    * about a given axis
+    *
+    * @param rot angle of rotation
+    * @param x rotation axis x
+    * @param y rotation axis y
+    * @param z rotation axis z
+    */
     public void loadRotate(float rot, float x, float y, float z) {
         float c, s;
         rot *= (float)(java.lang.Math.PI / 180.0f);
@@ -97,7 +144,13 @@
         mMat[8] = z*z*nc +  c;
     }
 
+    /**
+    * Makes the upper 2x2 a rotation matrix of the given angle
+    *
+    * @param rot rotation angle
+    */
     public void loadRotate(float rot) {
+        loadIdentity();
         float c, s;
         rot *= (float)(java.lang.Math.PI / 180.0f);
         c = (float)java.lang.Math.cos(rot);
@@ -108,12 +161,25 @@
         mMat[4] = c;
     }
 
+    /**
+    * Makes the upper 2x2 a scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    */
     public void loadScale(float x, float y) {
         loadIdentity();
         mMat[0] = x;
         mMat[4] = y;
     }
 
+    /**
+    * Sets current values to be a scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    * @param z scale component z
+    */
     public void loadScale(float x, float y, float z) {
         loadIdentity();
         mMat[0] = x;
@@ -121,12 +187,26 @@
         mMat[8] = z;
     }
 
+    /**
+    * Sets current values to be a translation matrix of given
+    * dimensions
+    *
+    * @param x translation component x
+    * @param y translation component y
+    */
     public void loadTranslate(float x, float y) {
         loadIdentity();
         mMat[6] = x;
         mMat[7] = y;
     }
 
+    /**
+    * Sets current values to be the result of multiplying two given
+    * matrices
+    *
+    * @param lhs left hand side matrix
+    * @param rhs right hand side matrix
+    */
     public void loadMultiply(Matrix3f lhs, Matrix3f rhs) {
         for (int i=0 ; i<3 ; i++) {
             float ri0 = 0;
@@ -144,36 +224,87 @@
         }
     }
 
+    /**
+    * Post-multiplies the current matrix by a given parameter
+    *
+    * @param rhs right hand side to multiply by
+    */
     public void multiply(Matrix3f rhs) {
         Matrix3f tmp = new Matrix3f();
         tmp.loadMultiply(this, rhs);
         load(tmp);
     }
+
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * rotation matrix of certain angle about a given axis
+    *
+    * @param rot angle of rotation
+    * @param x rotation axis x
+    * @param y rotation axis y
+    * @param z rotation axis z
+    */
     public void rotate(float rot, float x, float y, float z) {
         Matrix3f tmp = new Matrix3f();
         tmp.loadRotate(rot, x, y, z);
         multiply(tmp);
     }
+
+    /**
+    * Modifies the upper 2x2 of the current matrix by
+    * post-multiplying it with a rotation matrix of given angle
+    *
+    * @param rot angle of rotation
+    */
     public void rotate(float rot) {
         Matrix3f tmp = new Matrix3f();
         tmp.loadRotate(rot);
         multiply(tmp);
     }
+
+    /**
+    * Modifies the upper 2x2 of the current matrix by
+    * post-multiplying it with a scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    */
     public void scale(float x, float y) {
         Matrix3f tmp = new Matrix3f();
         tmp.loadScale(x, y);
         multiply(tmp);
     }
+
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    * @param z scale component z
+    */
     public void scale(float x, float y, float z) {
         Matrix3f tmp = new Matrix3f();
         tmp.loadScale(x, y, z);
         multiply(tmp);
     }
+
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * translation matrix of given dimensions
+    *
+    * @param x translation component x
+    * @param y translation component y
+    */
     public void translate(float x, float y) {
         Matrix3f tmp = new Matrix3f();
         tmp.loadTranslate(x, y);
         multiply(tmp);
     }
+
+    /**
+    * Sets the current matrix to its transpose
+    */
     public void transpose() {
         for(int i = 0; i < 2; ++i) {
             for(int j = i + 1; j < 3; ++j) {
diff --git a/graphics/java/android/renderscript/Matrix4f.java b/graphics/java/android/renderscript/Matrix4f.java
index ec07cd5..2afd72e 100644
--- a/graphics/java/android/renderscript/Matrix4f.java
+++ b/graphics/java/android/renderscript/Matrix4f.java
@@ -26,28 +26,61 @@
  **/
 public class Matrix4f {
 
+    /**
+    * Creates a new identity 4x4 matrix
+    */
     public Matrix4f() {
         mMat = new float[16];
         loadIdentity();
     }
 
+    /**
+    * Creates a new matrix and sets its values from the given
+    * parameter
+    *
+    * @param dataArray values to set the matrix to, must be 16
+    *                  floats long
+    */
     public Matrix4f(float[] dataArray) {
         mMat = new float[16];
         System.arraycopy(dataArray, 0, mMat, 0, mMat.length);
     }
 
+    /**
+    * Return a reference to the internal array representing matrix
+    * values. Modifying this array will also change the matrix
+    *
+    * @return internal array representing the matrix
+    */
     public float[] getArray() {
         return mMat;
     }
 
+    /**
+    * Returns the value for a given row and column
+    *
+    * @param i row of the value to return
+    * @param j column of the value to return
+    *
+    * @return value in the ith row and jth column
+    */
     public float get(int i, int j) {
         return mMat[i*4 + j];
     }
 
+    /**
+    * Sets the value for a given row and column
+    *
+    * @param i row of the value to set
+    * @param j column of the value to set
+    */
     public void set(int i, int j, float v) {
         mMat[i*4 + j] = v;
     }
 
+    /**
+    * Sets the matrix values to identity
+    */
     public void loadIdentity() {
         mMat[0] = 1;
         mMat[1] = 0;
@@ -70,10 +103,24 @@
         mMat[15] = 1;
     }
 
+    /**
+    * Sets the values of the matrix to those of the parameter
+    *
+    * @param src matrix to load the values from
+    */
     public void load(Matrix4f src) {
         System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length);
     }
 
+    /**
+    * Sets current values to be a rotation matrix of certain angle
+    * about a given axis
+    *
+    * @param rot angle of rotation
+    * @param x rotation axis x
+    * @param y rotation axis y
+    * @param z rotation axis z
+    */
     public void loadRotate(float rot, float x, float y, float z) {
         float c, s;
         mMat[3] = 0;
@@ -112,6 +159,13 @@
         mMat[10] = z*z*nc +  c;
     }
 
+    /**
+    * Sets current values to be a scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    * @param z scale component z
+    */
     public void loadScale(float x, float y, float z) {
         loadIdentity();
         mMat[0] = x;
@@ -119,6 +173,14 @@
         mMat[10] = z;
     }
 
+    /**
+    * Sets current values to be a translation matrix of given
+    * dimensions
+    *
+    * @param x translation component x
+    * @param y translation component y
+    * @param z translation component z
+    */
     public void loadTranslate(float x, float y, float z) {
         loadIdentity();
         mMat[12] = x;
@@ -126,6 +188,13 @@
         mMat[14] = z;
     }
 
+    /**
+    * Sets current values to be the result of multiplying two given
+    * matrices
+    *
+    * @param lhs left hand side matrix
+    * @param rhs right hand side matrix
+    */
     public void loadMultiply(Matrix4f lhs, Matrix4f rhs) {
         for (int i=0 ; i<4 ; i++) {
             float ri0 = 0;
@@ -146,6 +215,16 @@
         }
     }
 
+    /**
+    * Set current values to be an orthographic projection matrix
+    *
+    * @param l location of the left vertical clipping plane
+    * @param r location of the right vertical clipping plane
+    * @param b location of the bottom horizontal clipping plane
+    * @param t location of the top horizontal clipping plane
+    * @param n location of the near clipping plane
+    * @param f location of the far clipping plane
+    */
     public void loadOrtho(float l, float r, float b, float t, float n, float f) {
         loadIdentity();
         mMat[0] = 2 / (r - l);
@@ -156,10 +235,31 @@
         mMat[14]= -(f + n) / (f - n);
     }
 
+    /**
+    * Set current values to be an orthographic projection matrix
+    * with the right and bottom clipping planes set to the given
+    * values. Left and top clipping planes are set to 0. Near and
+    * far are set to -1, 1 respectively
+    *
+    * @param w location of the right vertical clipping plane
+    * @param h location of the bottom horizontal clipping plane
+    *
+    */
     public void loadOrthoWindow(int w, int h) {
         loadOrtho(0,w, h,0, -1,1);
     }
 
+    /**
+    * Sets current values to be a perspective projection matrix
+    *
+    * @param l location of the left vertical clipping plane
+    * @param r location of the right vertical clipping plane
+    * @param b location of the bottom horizontal clipping plane
+    * @param t location of the top horizontal clipping plane
+    * @param n location of the near clipping plane, must be positive
+    * @param f location of the far clipping plane, must be positive
+    *
+    */
     public void loadFrustum(float l, float r, float b, float t, float n, float f) {
         loadIdentity();
         mMat[0] = 2 * n / (r - l);
@@ -172,6 +272,14 @@
         mMat[15]= 0;
     }
 
+    /**
+    * Sets current values to be a perspective projection matrix
+    *
+    * @param fovy vertical field of view angle in degrees
+    * @param aspect aspect ratio of the screen
+    * @param near near cliping plane, must be positive
+    * @param far far clipping plane, must be positive
+    */
     public void loadPerspective(float fovy, float aspect, float near, float far) {
         float top = near * (float)Math.tan((float) (fovy * Math.PI / 360.0f));
         float bottom = -top;
@@ -180,6 +288,14 @@
         loadFrustum(left, right, bottom, top, near, far);
     }
 
+    /**
+    * Helper function to set the current values to a perspective
+    * projection matrix with aspect ratio defined by the parameters
+    * and (near, far), (bottom, top) mapping to (-1, 1) at z = 0
+    *
+    * @param w screen width
+    * @param h screen height
+    */
     public void loadProjectionNormalized(int w, int h) {
         // range -1,1 in the narrow axis at z = 0.
         Matrix4f m1 = new Matrix4f();
@@ -205,22 +321,53 @@
         load(m1);
     }
 
-
+    /**
+    * Post-multiplies the current matrix by a given parameter
+    *
+    * @param rhs right hand side to multiply by
+    */
     public void multiply(Matrix4f rhs) {
         Matrix4f tmp = new Matrix4f();
         tmp.loadMultiply(this, rhs);
         load(tmp);
     }
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * rotation matrix of certain angle about a given axis
+    *
+    * @param rot angle of rotation
+    * @param x rotation axis x
+    * @param y rotation axis y
+    * @param z rotation axis z
+    */
     public void rotate(float rot, float x, float y, float z) {
         Matrix4f tmp = new Matrix4f();
         tmp.loadRotate(rot, x, y, z);
         multiply(tmp);
     }
+
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    * @param z scale component z
+    */
     public void scale(float x, float y, float z) {
         Matrix4f tmp = new Matrix4f();
         tmp.loadScale(x, y, z);
         multiply(tmp);
     }
+
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * translation matrix of given dimensions
+    *
+    * @param x translation component x
+    * @param y translation component y
+    * @param z translation component z
+    */
     public void translate(float x, float y, float z) {
         Matrix4f tmp = new Matrix4f();
         tmp.loadTranslate(x, y, z);
@@ -245,6 +392,9 @@
         return cofactor;
     }
 
+    /**
+    * Sets the current matrix to its inverse
+    */
     public boolean inverse() {
 
         Matrix4f result = new Matrix4f();
@@ -271,6 +421,9 @@
         return true;
     }
 
+    /**
+    * Sets the current matrix to its inverse transpose
+    */
     public boolean inverseTranspose() {
 
         Matrix4f result = new Matrix4f();
@@ -296,6 +449,9 @@
         return true;
     }
 
+    /**
+    * Sets the current matrix to its transpose
+    */
     public void transpose() {
         for(int i = 0; i < 3; ++i) {
             for(int j = i + 1; j < 4; ++j) {
@@ -308,8 +464,3 @@
 
     final float[] mMat;
 }
-
-
-
-
-
diff --git a/graphics/java/android/renderscript/Mesh.java b/graphics/java/android/renderscript/Mesh.java
index fcf8178..7269cea 100644
--- a/graphics/java/android/renderscript/Mesh.java
+++ b/graphics/java/android/renderscript/Mesh.java
@@ -46,11 +46,32 @@
     *
     **/
     public enum Primitive {
+        /**
+        * Vertex data will be rendered as a series of points
+        */
         POINT (0),
+        /**
+        * Vertex pairs will be rendered as lines
+        */
         LINE (1),
+        /**
+        * Vertex data will be rendered as a connected line strip
+        */
         LINE_STRIP (2),
+        /**
+        * Vertices will be rendered as individual triangles
+        */
         TRIANGLE (3),
+        /**
+        * Vertices will be rendered as a connected triangle strip
+        * defined by the first three vertices with each additional
+        * triangle defined by a new vertex
+        */
         TRIANGLE_STRIP (4),
+        /**
+        * Vertices will be rendered as a sequence of triangles that all
+        * share first vertex as the origin
+        */
         TRIANGLE_FAN (5);
 
         int mID;
@@ -733,14 +754,14 @@
 
             Mesh sm = smb.create();
 
-            sm.getVertexAllocation(0).copyFrom(mVtxData);
+            sm.getVertexAllocation(0).copy1DRangeFromUnchecked(0, mVtxCount / floatCount, mVtxData);
             if(uploadToBufferObject) {
                 if (uploadToBufferObject) {
                     sm.getVertexAllocation(0).syncAll(Allocation.USAGE_SCRIPT);
                 }
             }
 
-            sm.getIndexSetAllocation(0).copyFrom(mIndexData);
+            sm.getIndexSetAllocation(0).copy1DRangeFromUnchecked(0, mIndexCount, mIndexData);
             if (uploadToBufferObject) {
                 sm.getIndexSetAllocation(0).syncAll(Allocation.USAGE_SCRIPT);
             }
diff --git a/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java b/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java
index 1af31f8..666a3e6 100644
--- a/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java
+++ b/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java
@@ -280,9 +280,10 @@
             pf.mTextureCount = MAX_TEXTURE;
             if (!mVaryingColorEnable) {
                 Allocation constantData = Allocation.createTyped(mRS,constType);
-                float[] data = new float[4];
-                data[0] = data[1] = data[2] = data[3] = 1.0f;
-                constantData.copyFrom(data);
+                FieldPacker fp = new FieldPacker(16);
+                Float4 f4 = new Float4(1.f, 1.f, 1.f, 1.f);
+                fp.addF32(f4);
+                constantData.setFromFieldPacker(0, fp);
                 pf.bindConstants(constantData, 0);
             }
             return pf;
diff --git a/graphics/java/android/renderscript/ProgramVertexFixedFunction.java b/graphics/java/android/renderscript/ProgramVertexFixedFunction.java
index 666c7ec..556964a 100644
--- a/graphics/java/android/renderscript/ProgramVertexFixedFunction.java
+++ b/graphics/java/android/renderscript/ProgramVertexFixedFunction.java
@@ -229,7 +229,7 @@
             for(int i = 0; i < 16; i ++) {
                 mIOBuffer.addF32(m.mMat[i]);
             }
-            mAlloc.copyFrom(mIOBuffer.getData());
+            mAlloc.setFromFieldPacker(0, mIOBuffer);
         }
 
         /**
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 28b32d5..bb9fb78 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -101,414 +101,515 @@
     }
     native void rsnContextDestroy(int con);
     synchronized void nContextDestroy() {
+        validate();
         rsnContextDestroy(mContext);
     }
     native void rsnContextSetSurface(int con, int w, int h, Surface sur);
     synchronized void nContextSetSurface(int w, int h, Surface sur) {
+        validate();
         rsnContextSetSurface(mContext, w, h, sur);
     }
     native void rsnContextSetPriority(int con, int p);
     synchronized void nContextSetPriority(int p) {
+        validate();
         rsnContextSetPriority(mContext, p);
     }
     native void rsnContextDump(int con, int bits);
     synchronized void nContextDump(int bits) {
+        validate();
         rsnContextDump(mContext, bits);
     }
     native void rsnContextFinish(int con);
     synchronized void nContextFinish() {
+        validate();
         rsnContextFinish(mContext);
     }
 
     native void rsnContextBindRootScript(int con, int script);
     synchronized void nContextBindRootScript(int script) {
+        validate();
         rsnContextBindRootScript(mContext, script);
     }
     native void rsnContextBindSampler(int con, int sampler, int slot);
     synchronized void nContextBindSampler(int sampler, int slot) {
+        validate();
         rsnContextBindSampler(mContext, sampler, slot);
     }
     native void rsnContextBindProgramStore(int con, int pfs);
     synchronized void nContextBindProgramStore(int pfs) {
+        validate();
         rsnContextBindProgramStore(mContext, pfs);
     }
     native void rsnContextBindProgramFragment(int con, int pf);
     synchronized void nContextBindProgramFragment(int pf) {
+        validate();
         rsnContextBindProgramFragment(mContext, pf);
     }
     native void rsnContextBindProgramVertex(int con, int pv);
     synchronized void nContextBindProgramVertex(int pv) {
+        validate();
         rsnContextBindProgramVertex(mContext, pv);
     }
     native void rsnContextBindProgramRaster(int con, int pr);
     synchronized void nContextBindProgramRaster(int pr) {
+        validate();
         rsnContextBindProgramRaster(mContext, pr);
     }
     native void rsnContextPause(int con);
     synchronized void nContextPause() {
+        validate();
         rsnContextPause(mContext);
     }
     native void rsnContextResume(int con);
     synchronized void nContextResume() {
+        validate();
         rsnContextResume(mContext);
     }
 
     native void rsnAssignName(int con, int obj, byte[] name);
     synchronized void nAssignName(int obj, byte[] name) {
+        validate();
         rsnAssignName(mContext, obj, name);
     }
     native String rsnGetName(int con, int obj);
     synchronized String nGetName(int obj) {
+        validate();
         return rsnGetName(mContext, obj);
     }
     native void rsnObjDestroy(int con, int id);
     synchronized void nObjDestroy(int id) {
-        rsnObjDestroy(mContext, id);
+        // There is a race condition here.  The calling code may be run
+        // by the gc while teardown is occuring.  This protects againts
+        // deleting dead objects.
+        if (mContext != 0) {
+            rsnObjDestroy(mContext, id);
+        }
     }
 
     native int  rsnElementCreate(int con, int type, int kind, boolean norm, int vecSize);
     synchronized int nElementCreate(int type, int kind, boolean norm, int vecSize) {
+        validate();
         return rsnElementCreate(mContext, type, kind, norm, vecSize);
     }
     native int  rsnElementCreate2(int con, int[] elements, String[] names, int[] arraySizes);
     synchronized int nElementCreate2(int[] elements, String[] names, int[] arraySizes) {
+        validate();
         return rsnElementCreate2(mContext, elements, names, arraySizes);
     }
     native void rsnElementGetNativeData(int con, int id, int[] elementData);
     synchronized void nElementGetNativeData(int id, int[] elementData) {
+        validate();
         rsnElementGetNativeData(mContext, id, elementData);
     }
     native void rsnElementGetSubElements(int con, int id, int[] IDs, String[] names);
     synchronized void nElementGetSubElements(int id, int[] IDs, String[] names) {
+        validate();
         rsnElementGetSubElements(mContext, id, IDs, names);
     }
 
     native int rsnTypeCreate(int con, int eid, int x, int y, int z, boolean mips, boolean faces);
     synchronized int nTypeCreate(int eid, int x, int y, int z, boolean mips, boolean faces) {
+        validate();
         return rsnTypeCreate(mContext, eid, x, y, z, mips, faces);
     }
     native void rsnTypeGetNativeData(int con, int id, int[] typeData);
     synchronized void nTypeGetNativeData(int id, int[] typeData) {
+        validate();
         rsnTypeGetNativeData(mContext, id, typeData);
     }
 
     native int  rsnAllocationCreateTyped(int con, int type, int mip, int usage);
     synchronized int nAllocationCreateTyped(int type, int mip, int usage) {
+        validate();
         return rsnAllocationCreateTyped(mContext, type, mip, usage);
     }
     native int  rsnAllocationCreateFromBitmap(int con, int type, int mip, Bitmap bmp, int usage);
     synchronized int nAllocationCreateFromBitmap(int type, int mip, Bitmap bmp, int usage) {
+        validate();
         return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp, usage);
     }
     native int  rsnAllocationCubeCreateFromBitmap(int con, int type, int mip, Bitmap bmp, int usage);
     synchronized int nAllocationCubeCreateFromBitmap(int type, int mip, Bitmap bmp, int usage) {
+        validate();
         return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp, usage);
     }
     native int  rsnAllocationCreateBitmapRef(int con, int type, Bitmap bmp);
     synchronized int nAllocationCreateBitmapRef(int type, Bitmap bmp) {
+        validate();
         return rsnAllocationCreateBitmapRef(mContext, type, bmp);
     }
     native int  rsnAllocationCreateFromAssetStream(int con, int mips, int assetStream, int usage);
     synchronized int nAllocationCreateFromAssetStream(int mips, int assetStream, int usage) {
+        validate();
         return rsnAllocationCreateFromAssetStream(mContext, mips, assetStream, usage);
     }
 
     native void  rsnAllocationCopyToBitmap(int con, int alloc, Bitmap bmp);
     synchronized void nAllocationCopyToBitmap(int alloc, Bitmap bmp) {
+        validate();
         rsnAllocationCopyToBitmap(mContext, alloc, bmp);
     }
 
 
     native void rsnAllocationSyncAll(int con, int alloc, int src);
     synchronized void nAllocationSyncAll(int alloc, int src) {
+        validate();
         rsnAllocationSyncAll(mContext, alloc, src);
     }
     native void rsnAllocationGenerateMipmaps(int con, int alloc);
     synchronized void nAllocationGenerateMipmaps(int alloc) {
+        validate();
         rsnAllocationGenerateMipmaps(mContext, alloc);
     }
     native void  rsnAllocationCopyFromBitmap(int con, int alloc, Bitmap bmp);
     synchronized void nAllocationCopyFromBitmap(int alloc, Bitmap bmp) {
+        validate();
         rsnAllocationCopyFromBitmap(mContext, alloc, bmp);
     }
 
 
     native void rsnAllocationData1D(int con, int id, int off, int mip, int count, int[] d, int sizeBytes);
     synchronized void nAllocationData1D(int id, int off, int mip, int count, int[] d, int sizeBytes) {
+        validate();
         rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
     }
     native void rsnAllocationData1D(int con, int id, int off, int mip, int count, short[] d, int sizeBytes);
     synchronized void nAllocationData1D(int id, int off, int mip, int count, short[] d, int sizeBytes) {
+        validate();
         rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
     }
     native void rsnAllocationData1D(int con, int id, int off, int mip, int count, byte[] d, int sizeBytes);
     synchronized void nAllocationData1D(int id, int off, int mip, int count, byte[] d, int sizeBytes) {
+        validate();
         rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
     }
     native void rsnAllocationData1D(int con, int id, int off, int mip, int count, float[] d, int sizeBytes);
     synchronized void nAllocationData1D(int id, int off, int mip, int count, float[] d, int sizeBytes) {
+        validate();
         rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
     }
 
     native void rsnAllocationElementData1D(int con, int id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes);
     synchronized void nAllocationElementData1D(int id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes) {
+        validate();
         rsnAllocationElementData1D(mContext, id, xoff, mip, compIdx, d, sizeBytes);
     }
 
     native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, byte[] d, int sizeBytes);
     synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, byte[] d, int sizeBytes) {
+        validate();
         rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
     }
     native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, short[] d, int sizeBytes);
     synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, short[] d, int sizeBytes) {
+        validate();
         rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
     }
     native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, int[] d, int sizeBytes);
     synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, int[] d, int sizeBytes) {
+        validate();
         rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
     }
     native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, float[] d, int sizeBytes);
     synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, float[] d, int sizeBytes) {
+        validate();
         rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
     }
     native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, Bitmap b);
     synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, Bitmap b) {
+        validate();
         rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, b);
     }
 
     native void rsnAllocationRead(int con, int id, byte[] d);
     synchronized void nAllocationRead(int id, byte[] d) {
+        validate();
         rsnAllocationRead(mContext, id, d);
     }
     native void rsnAllocationRead(int con, int id, short[] d);
     synchronized void nAllocationRead(int id, short[] d) {
+        validate();
         rsnAllocationRead(mContext, id, d);
     }
     native void rsnAllocationRead(int con, int id, int[] d);
     synchronized void nAllocationRead(int id, int[] d) {
+        validate();
         rsnAllocationRead(mContext, id, d);
     }
     native void rsnAllocationRead(int con, int id, float[] d);
     synchronized void nAllocationRead(int id, float[] d) {
+        validate();
         rsnAllocationRead(mContext, id, d);
     }
     native int  rsnAllocationGetType(int con, int id);
     synchronized int nAllocationGetType(int id) {
+        validate();
         return rsnAllocationGetType(mContext, id);
     }
 
     native void rsnAllocationResize1D(int con, int id, int dimX);
     synchronized void nAllocationResize1D(int id, int dimX) {
+        validate();
         rsnAllocationResize1D(mContext, id, dimX);
     }
     native void rsnAllocationResize2D(int con, int id, int dimX, int dimY);
     synchronized void nAllocationResize2D(int id, int dimX, int dimY) {
+        validate();
         rsnAllocationResize2D(mContext, id, dimX, dimY);
     }
 
     native int  rsnFileA3DCreateFromAssetStream(int con, int assetStream);
     synchronized int nFileA3DCreateFromAssetStream(int assetStream) {
+        validate();
         return rsnFileA3DCreateFromAssetStream(mContext, assetStream);
     }
     native int  rsnFileA3DCreateFromFile(int con, String path);
     synchronized int nFileA3DCreateFromFile(String path) {
+        validate();
         return rsnFileA3DCreateFromFile(mContext, path);
     }
     native int  rsnFileA3DCreateFromAsset(int con, AssetManager mgr, String path);
     synchronized int nFileA3DCreateFromAsset(AssetManager mgr, String path) {
+        validate();
         return rsnFileA3DCreateFromAsset(mContext, mgr, path);
     }
     native int  rsnFileA3DGetNumIndexEntries(int con, int fileA3D);
     synchronized int nFileA3DGetNumIndexEntries(int fileA3D) {
+        validate();
         return rsnFileA3DGetNumIndexEntries(mContext, fileA3D);
     }
     native void rsnFileA3DGetIndexEntries(int con, int fileA3D, int numEntries, int[] IDs, String[] names);
     synchronized void nFileA3DGetIndexEntries(int fileA3D, int numEntries, int[] IDs, String[] names) {
+        validate();
         rsnFileA3DGetIndexEntries(mContext, fileA3D, numEntries, IDs, names);
     }
     native int  rsnFileA3DGetEntryByIndex(int con, int fileA3D, int index);
     synchronized int nFileA3DGetEntryByIndex(int fileA3D, int index) {
+        validate();
         return rsnFileA3DGetEntryByIndex(mContext, fileA3D, index);
     }
 
     native int  rsnFontCreateFromFile(int con, String fileName, float size, int dpi);
     synchronized int nFontCreateFromFile(String fileName, float size, int dpi) {
+        validate();
         return rsnFontCreateFromFile(mContext, fileName, size, dpi);
     }
     native int  rsnFontCreateFromAssetStream(int con, String name, float size, int dpi, int assetStream);
     synchronized int nFontCreateFromAssetStream(String name, float size, int dpi, int assetStream) {
+        validate();
         return rsnFontCreateFromAssetStream(mContext, name, size, dpi, assetStream);
     }
     native int  rsnFontCreateFromAsset(int con, AssetManager mgr, String path, float size, int dpi);
     synchronized int nFontCreateFromAsset(AssetManager mgr, String path, float size, int dpi) {
+        validate();
         return rsnFontCreateFromAsset(mContext, mgr, path, size, dpi);
     }
 
 
     native void rsnScriptBindAllocation(int con, int script, int alloc, int slot);
     synchronized void nScriptBindAllocation(int script, int alloc, int slot) {
+        validate();
         rsnScriptBindAllocation(mContext, script, alloc, slot);
     }
     native void rsnScriptSetTimeZone(int con, int script, byte[] timeZone);
     synchronized void nScriptSetTimeZone(int script, byte[] timeZone) {
+        validate();
         rsnScriptSetTimeZone(mContext, script, timeZone);
     }
     native void rsnScriptInvoke(int con, int id, int slot);
     synchronized void nScriptInvoke(int id, int slot) {
+        validate();
         rsnScriptInvoke(mContext, id, slot);
     }
     native void rsnScriptInvokeV(int con, int id, int slot, byte[] params);
     synchronized void nScriptInvokeV(int id, int slot, byte[] params) {
+        validate();
         rsnScriptInvokeV(mContext, id, slot, params);
     }
     native void rsnScriptSetVarI(int con, int id, int slot, int val);
     synchronized void nScriptSetVarI(int id, int slot, int val) {
+        validate();
         rsnScriptSetVarI(mContext, id, slot, val);
     }
     native void rsnScriptSetVarJ(int con, int id, int slot, long val);
     synchronized void nScriptSetVarJ(int id, int slot, long val) {
+        validate();
         rsnScriptSetVarJ(mContext, id, slot, val);
     }
     native void rsnScriptSetVarF(int con, int id, int slot, float val);
     synchronized void nScriptSetVarF(int id, int slot, float val) {
+        validate();
         rsnScriptSetVarF(mContext, id, slot, val);
     }
     native void rsnScriptSetVarD(int con, int id, int slot, double val);
     synchronized void nScriptSetVarD(int id, int slot, double val) {
+        validate();
         rsnScriptSetVarD(mContext, id, slot, val);
     }
     native void rsnScriptSetVarV(int con, int id, int slot, byte[] val);
     synchronized void nScriptSetVarV(int id, int slot, byte[] val) {
+        validate();
         rsnScriptSetVarV(mContext, id, slot, val);
     }
     native void rsnScriptSetVarObj(int con, int id, int slot, int val);
     synchronized void nScriptSetVarObj(int id, int slot, int val) {
+        validate();
         rsnScriptSetVarObj(mContext, id, slot, val);
     }
 
     native void rsnScriptCBegin(int con);
     synchronized void nScriptCBegin() {
+        validate();
         rsnScriptCBegin(mContext);
     }
     native void rsnScriptCSetScript(int con, byte[] script, int offset, int length);
     synchronized void nScriptCSetScript(byte[] script, int offset, int length) {
+        validate();
         rsnScriptCSetScript(mContext, script, offset, length);
     }
     native int  rsnScriptCCreate(int con, String packageName, String resName, String cacheDir);
     synchronized int nScriptCCreate(String packageName, String resName, String cacheDir) {
+        validate();
         return rsnScriptCCreate(mContext, packageName, resName, cacheDir);
     }
 
     native void rsnSamplerBegin(int con);
     synchronized void nSamplerBegin() {
+        validate();
         rsnSamplerBegin(mContext);
     }
     native void rsnSamplerSet(int con, int param, int value);
     synchronized void nSamplerSet(int param, int value) {
+        validate();
         rsnSamplerSet(mContext, param, value);
     }
     native void rsnSamplerSet2(int con, int param, float value);
     synchronized void nSamplerSet2(int param, float value) {
+        validate();
         rsnSamplerSet2(mContext, param, value);
     }
     native int  rsnSamplerCreate(int con);
     synchronized int nSamplerCreate() {
+        validate();
         return rsnSamplerCreate(mContext);
     }
 
     native void rsnProgramStoreBegin(int con, int in, int out);
     synchronized void nProgramStoreBegin(int in, int out) {
+        validate();
         rsnProgramStoreBegin(mContext, in, out);
     }
     native void rsnProgramStoreDepthFunc(int con, int func);
     synchronized void nProgramStoreDepthFunc(int func) {
+        validate();
         rsnProgramStoreDepthFunc(mContext, func);
     }
     native void rsnProgramStoreDepthMask(int con, boolean enable);
     synchronized void nProgramStoreDepthMask(boolean enable) {
+        validate();
         rsnProgramStoreDepthMask(mContext, enable);
     }
     native void rsnProgramStoreColorMask(int con, boolean r, boolean g, boolean b, boolean a);
     synchronized void nProgramStoreColorMask(boolean r, boolean g, boolean b, boolean a) {
+        validate();
         rsnProgramStoreColorMask(mContext, r, g, b, a);
     }
     native void rsnProgramStoreBlendFunc(int con, int src, int dst);
     synchronized void nProgramStoreBlendFunc(int src, int dst) {
+        validate();
         rsnProgramStoreBlendFunc(mContext, src, dst);
     }
     native void rsnProgramStoreDither(int con, boolean enable);
     synchronized void nProgramStoreDither(boolean enable) {
+        validate();
         rsnProgramStoreDither(mContext, enable);
     }
     native int  rsnProgramStoreCreate(int con);
     synchronized int nProgramStoreCreate() {
+        validate();
         return rsnProgramStoreCreate(mContext);
     }
 
     native int  rsnProgramRasterCreate(int con, boolean pointSmooth, boolean lineSmooth, boolean pointSprite);
     synchronized int nProgramRasterCreate(boolean pointSmooth, boolean lineSmooth, boolean pointSprite) {
+        validate();
         return rsnProgramRasterCreate(mContext, pointSmooth, lineSmooth, pointSprite);
     }
     native void rsnProgramRasterSetLineWidth(int con, int pr, float v);
     synchronized void nProgramRasterSetLineWidth(int pr, float v) {
+        validate();
         rsnProgramRasterSetLineWidth(mContext, pr, v);
     }
     native void rsnProgramRasterSetCullMode(int con, int pr, int mode);
     synchronized void nProgramRasterSetCullMode(int pr, int mode) {
+        validate();
         rsnProgramRasterSetCullMode(mContext, pr, mode);
     }
 
     native void rsnProgramBindConstants(int con, int pv, int slot, int mID);
     synchronized void nProgramBindConstants(int pv, int slot, int mID) {
+        validate();
         rsnProgramBindConstants(mContext, pv, slot, mID);
     }
     native void rsnProgramBindTexture(int con, int vpf, int slot, int a);
     synchronized void nProgramBindTexture(int vpf, int slot, int a) {
+        validate();
         rsnProgramBindTexture(mContext, vpf, slot, a);
     }
     native void rsnProgramBindSampler(int con, int vpf, int slot, int s);
     synchronized void nProgramBindSampler(int vpf, int slot, int s) {
+        validate();
         rsnProgramBindSampler(mContext, vpf, slot, s);
     }
     native int  rsnProgramFragmentCreate(int con, String shader, int[] params);
     synchronized int nProgramFragmentCreate(String shader, int[] params) {
+        validate();
         return rsnProgramFragmentCreate(mContext, shader, params);
     }
     native int  rsnProgramVertexCreate(int con, String shader, int[] params);
     synchronized int nProgramVertexCreate(String shader, int[] params) {
+        validate();
         return rsnProgramVertexCreate(mContext, shader, params);
     }
 
     native int  rsnMeshCreate(int con, int vtxCount, int indexCount);
     synchronized int nMeshCreate(int vtxCount, int indexCount) {
+        validate();
         return rsnMeshCreate(mContext, vtxCount, indexCount);
     }
     native void rsnMeshBindVertex(int con, int id, int alloc, int slot);
     synchronized void nMeshBindVertex(int id, int alloc, int slot) {
+        validate();
         rsnMeshBindVertex(mContext, id, alloc, slot);
     }
     native void rsnMeshBindIndex(int con, int id, int alloc, int prim, int slot);
     synchronized void nMeshBindIndex(int id, int alloc, int prim, int slot) {
+        validate();
         rsnMeshBindIndex(mContext, id, alloc, prim, slot);
     }
     native void rsnMeshInitVertexAttribs(int con, int id);
     synchronized void nMeshInitVertexAttribs(int id) {
+        validate();
         rsnMeshInitVertexAttribs(mContext, id);
     }
     native int  rsnMeshGetVertexBufferCount(int con, int id);
     synchronized int nMeshGetVertexBufferCount(int id) {
+        validate();
         return rsnMeshGetVertexBufferCount(mContext, id);
     }
     native int  rsnMeshGetIndexCount(int con, int id);
     synchronized int nMeshGetIndexCount(int id) {
+        validate();
         return rsnMeshGetIndexCount(mContext, id);
     }
     native void rsnMeshGetVertices(int con, int id, int[] vtxIds, int vtxIdCount);
     synchronized void nMeshGetVertices(int id, int[] vtxIds, int vtxIdCount) {
+        validate();
         rsnMeshGetVertices(mContext, id, vtxIds, vtxIdCount);
     }
     native void rsnMeshGetIndices(int con, int id, int[] idxIds, int[] primitives, int vtxIdCount);
     synchronized void nMeshGetIndices(int id, int[] idxIds, int[] primitives, int vtxIdCount) {
+        validate();
         rsnMeshGetIndices(mContext, id, idxIds, primitives, vtxIdCount);
     }
 
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 35db786..f86343a 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -991,7 +991,7 @@
     jint *paramPtr = _env->GetIntArrayElements(params, NULL);
     jint paramLen = _env->GetArrayLength(params);
 
-    LOG_API("nProgramFragmentCreate, con(%p), shaderLen(%i), paramLen(%i)", con, shaderLen, paramLen);
+    LOG_API("nProgramFragmentCreate, con(%p), paramLen(%i)", con, paramLen);
 
     jint ret = (jint)rsProgramFragmentCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen);
     _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
@@ -1008,7 +1008,7 @@
     jint *paramPtr = _env->GetIntArrayElements(params, NULL);
     jint paramLen = _env->GetArrayLength(params);
 
-    LOG_API("nProgramVertexCreate, con(%p), shaderLen(%i), paramLen(%i)", con, shaderLen, paramLen);
+    LOG_API("nProgramVertexCreate, con(%p), paramLen(%i)", con, paramLen);
 
     jint ret = (jint)rsProgramVertexCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen);
     _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 37af032..d12ee9c 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -65,6 +65,7 @@
     bool reachedEOS(status_t *finalStatus);
 
 private:
+    friend class VideoEditorAudioPlayer;
     sp<MediaSource> mSource;
     AudioTrack *mAudioTrack;
 
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 5170a2c..18fd90e 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -30,8 +30,10 @@
 // The following keys map to int32_t data unless indicated otherwise.
 enum {
     kKeyMIMEType          = 'mime',  // cstring
-    kKeyWidth             = 'widt',  // int32_t
-    kKeyHeight            = 'heig',  // int32_t
+    kKeyWidth             = 'widt',  // int32_t, image pixel
+    kKeyHeight            = 'heig',  // int32_t, image pixel
+    kKeyDisplayWidth      = 'dWid',  // int32_t, display/presentation
+    kKeyDisplayHeight     = 'dHgt',  // int32_t, display/presentation
 
     // a rectangle, if absent assumed to be (0, 0, width - 1, height - 1)
     kKeyCropRect          = 'crop',
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 5532052..d783caf 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -100,6 +100,9 @@
     friend class MediaPlayer;
     // for testing
     friend class Test;
+    // videoEditor preview classes
+    friend class VideoEditorPreviewController;
+
     const sp<ISurface>& getISurface() const { return mSurface; }
     
 
@@ -181,6 +184,9 @@
     friend class SoftwareRenderer;
     // this is just to be able to write some unit tests
     friend class Test;
+    // videoEditor preview classes
+    friend class VideoEditorPreviewController;
+    friend class PreviewRenderer;
 
 private:
     friend class SurfaceComposerClient;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index e3593da..ade85e5 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -268,6 +268,10 @@
                 renderer.scale(getFloat(), getFloat());
             }
             break;
+            case Skew: {
+                renderer.skew(getFloat(), getFloat());
+            }
+            break;
             case SetMatrix: {
                 renderer.setMatrix(getMatrix());
             }
@@ -508,6 +512,12 @@
     OpenGLRenderer::scale(sx, sy);
 }
 
+void DisplayListRenderer::skew(float sx, float sy) {
+    addOp(DisplayList::Skew);
+    addPoint(sx, sy);
+    OpenGLRenderer::skew(sx, sy);
+}
+
 void DisplayListRenderer::setMatrix(SkMatrix* matrix) {
     addOp(DisplayList::SetMatrix);
     addMatrix(matrix);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 7152334..05864ec 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -98,6 +98,7 @@
         Translate,
         Rotate,
         Scale,
+        Skew,
         SetMatrix,
         ConcatMatrix,
         ClipRect,
@@ -250,6 +251,7 @@
     void translate(float dx, float dy);
     void rotate(float degrees);
     void scale(float sx, float sy);
+    void skew(float sx, float sy);
 
     void setMatrix(SkMatrix* matrix);
     void concatMatrix(SkMatrix* matrix);
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index d1fbfba..c080501 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -38,8 +38,10 @@
 // Font
 ///////////////////////////////////////////////////////////////////////////////
 
-Font::Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags) :
-    mState(state), mFontId(fontId), mFontSize(fontSize), mFlags(flags) {
+Font::Font(FontRenderer* state, uint32_t fontId, float fontSize,
+        int flags, uint32_t italicStyle) :
+        mState(state), mFontId(fontId), mFontSize(fontSize),
+        mFlags(flags), mItalicStyle(italicStyle) {
 }
 
 
@@ -275,17 +277,19 @@
     return newGlyph;
 }
 
-Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize, int flags) {
+Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
+        int flags, uint32_t italicStyle) {
     Vector<Font*> &activeFonts = state->mActiveFonts;
 
     for (uint32_t i = 0; i < activeFonts.size(); i++) {
         Font* font = activeFonts[i];
-        if (font->mFontId == fontId && font->mFontSize == fontSize && font->mFlags == flags) {
+        if (font->mFontId == fontId && font->mFontSize == fontSize &&
+                font->mFlags == flags && font->mItalicStyle == italicStyle) {
             return font;
         }
     }
 
-    Font* newFont = new Font(state, fontId, fontSize, flags);
+    Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle);
     activeFonts.push(newFont);
     return newFont;
 }
@@ -638,7 +642,10 @@
     if (paint->isFakeBoldText()) {
         flags |= Font::kFakeBold;
     }
-    mCurrentFont = Font::create(this, fontId, fontSize, flags);
+
+    const float skewX = paint->getTextSkewX();
+    uint32_t italicStyle = *(uint32_t*) &skewX;
+    mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle);
 
     const float maxPrecacheFontSize = 40.0f;
     bool isNewFont = currentNumFonts != mActiveFonts.size();
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 40572c6..1005812 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -57,7 +57,8 @@
     /**
      * Creates a new font associated with the specified font state.
      */
-    static Font* create(FontRenderer* state, uint32_t fontId, float fontSize, int flags);
+    static Font* create(FontRenderer* state, uint32_t fontId, float fontSize,
+            int flags, uint32_t italicStyle);
 
 protected:
     friend class FontRenderer;
@@ -103,7 +104,7 @@
         SkFixed mRsbDelta;
     };
 
-    Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags);
+    Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle);
 
     DefaultKeyedVector<int32_t, CachedGlyphInfo*> mCachedGlyphs;
 
@@ -122,6 +123,7 @@
     uint32_t mFontId;
     float mFontSize;
     int mFlags;
+    uint32_t mItalicStyle;
 };
 
 class FontRenderer {
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index fe7f883..e7c0fe3 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -178,6 +178,24 @@
     data[kScaleZ] = sz;
 }
 
+void Matrix4::loadSkew(float sx, float sy) {
+    loadIdentity();
+
+    data[kScaleX]       = 1.0f;
+    data[kSkewX]        = sx;
+    data[kTranslateX]   = 0.0f;
+
+    data[kSkewY]        = sy;
+    data[kScaleY]       = 1.0f;
+    data[kTranslateY]   = 0.0f;
+
+    data[kPerspective0] = 0.0f;
+    data[kPerspective1] = 0.0f;
+    data[kPerspective2] = 1.0f;
+
+    mSimpleMatrix = false;
+}
+
 void Matrix4::loadRotate(float angle, float x, float y, float z) {
     data[kPerspective0]  = 0.0f;
     data[kPerspective1]  = 0.0f;
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 23fc6c3..08f5d77 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -72,6 +72,7 @@
 
     void loadTranslate(float x, float y, float z);
     void loadScale(float sx, float sy, float sz);
+    void loadSkew(float sx, float sy);
     void loadRotate(float angle, float x, float y, float z);
     void loadMultiply(const Matrix4& u, const Matrix4& v);
 
@@ -97,6 +98,12 @@
         multiply(u);
     }
 
+    void skew(float sx, float sy) {
+        Matrix4 u;
+        u.loadSkew(sx, sy);
+        multiply(u);
+    }
+
     void rotate(float angle, float x, float y, float z) {
         Matrix4 u;
         u.loadRotate(angle, x, y, z);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 16a1de7..2067acc1 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -766,6 +766,10 @@
     mSnapshot->transform->scale(sx, sy, 1.0f);
 }
 
+void OpenGLRenderer::skew(float sx, float sy) {
+    mSnapshot->transform->skew(sx, sy);
+}
+
 void OpenGLRenderer::setMatrix(SkMatrix* matrix) {
     mSnapshot->transform->load(*matrix);
 }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 7387b92..272c5c2 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -84,6 +84,7 @@
     virtual void translate(float dx, float dy);
     virtual void rotate(float degrees);
     virtual void scale(float sx, float sy);
+    virtual void skew(float sx, float sy);
 
     const float* getMatrix() const;
     void getMatrix(SkMatrix* matrix);
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 77cbb80..999e4ea 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -166,7 +166,14 @@
         }
         float v2 = fmax(0.0f, stepY - 0.5f) / bitmapHeight;
 
-        generateRow(vertex, y1, y2, v1, v2, stretchX, right - left, bitmapWidth, quadCount);
+        if (stepY > 0.0f) {
+            if (i == mYCount - 1 && mYDivs[i] == bitmapHeight) {
+                y2 = bottom - top;
+                v2 = 1.0f;
+            }
+            generateRow(vertex, y1, y2, v1, v2, stretchX, right - left,
+                    bitmapWidth, quadCount);
+        }
 
         y1 = y2;
         v1 = (stepY + 0.5f) / bitmapHeight;
@@ -174,8 +181,10 @@
         previousStepY = stepY;
     }
 
-    generateRow(vertex, y1, bottom - top, v1, 1.0f, stretchX, right - left,
-            bitmapWidth, quadCount);
+    if (previousStepY != bitmapHeight) {
+        generateRow(vertex, y1, bottom - top, v1, 1.0f, stretchX, right - left,
+                bitmapWidth, quadCount);
+    }
 
     if (verticesCount > 0) {
         Caches::getInstance().bindMeshBuffer(meshBuffer);
@@ -212,7 +221,13 @@
         }
         float u2 = fmax(0.0f, stepX - 0.5f) / bitmapWidth;
 
-        bool valid = generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount);
+        if (stepX > 0.0f) {
+            if (i == mXCount - 1 && mXDivs[i] == bitmapWidth) {
+                x2 = bitmapWidth;
+                u2 = 1.0f;
+            }
+            generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount);
+        }
 
         x1 = x2;
         u1 = (stepX + 0.5f) / bitmapWidth;
@@ -220,25 +235,24 @@
         previousStepX = stepX;
     }
 
-    generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount);
+    if (previousStepX != bitmapWidth) {
+        generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount);
+    }
 }
 
-bool Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
+void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
             float u1, float v1, float u2, float v2, uint32_t& quadCount) {
     const uint32_t oldQuadCount = quadCount;
-    const bool valid = x2 >= x1 && y2 >= y1;
-    if (valid) {
-        quadCount++;
-    }
+    quadCount++;
 
     // Skip degenerate and transparent (empty) quads
-    if (!valid || ((mColorKey >> oldQuadCount) & 0x1) == 1) {
+    if ((mColorKey >> oldQuadCount) & 0x1) {
 #if DEBUG_PATCHES_EMPTY_VERTICES
         PATCH_LOGD("    quad %d (empty)", oldQuadCount);
         PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.2f, %.2f", x1, y1, u1, v1);
         PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.2f, %.2f", x2, y2, u2, v2);
 #endif
-        return false;
+        return;
     }
 
 #if RENDER_LAYERS_AS_REGIONS
@@ -267,8 +281,6 @@
     PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.2f, %.2f", x1, y1, u1, v1);
     PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.2f, %.2f", x2, y2, u2, v2);
 #endif
-
-    return true;
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index 45ce998..0f0ffa2 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -71,7 +71,7 @@
     void generateRow(TextureVertex*& vertex, float y1, float y2,
             float v1, float v2, float stretchX, float width, float bitmapWidth,
             uint32_t& quadCount);
-    bool generateQuad(TextureVertex*& vertex,
+    void generateQuad(TextureVertex*& vertex,
             float x1, float y1, float x2, float y2,
             float u1, float v1, float u2, float v2,
             uint32_t& quadCount);
diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
index fc3a065..541bf22 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
@@ -68,6 +68,7 @@
         unitTests.add(new UT_rsdebug(this, mRes, mCtx));
         unitTests.add(new UT_rstime(this, mRes, mCtx));
         unitTests.add(new UT_rstypes(this, mRes, mCtx));
+        unitTests.add(new UT_math(this, mRes, mCtx));
         unitTests.add(new UT_fp_mad(this, mRes, mCtx));
         /*
         unitTests.add(new UnitTest(null, "<Pass>", 1));
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_math.java b/libs/rs/java/tests/src/com/android/rs/test/UT_math.java
new file mode 100644
index 0000000..bf133be
--- /dev/null
+++ b/libs/rs/java/tests/src/com/android/rs/test/UT_math.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_math extends UnitTest {
+    private Resources mRes;
+
+    protected UT_math(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Math", ctx);
+        mRes = res;
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_math s = new ScriptC_math(pRS, mRes, R.raw.math);
+        pRS.setMessageHandler(mRsMessage);
+        s.invoke_math_test(0, 0);
+        pRS.finish();
+        waitForMessage();
+        pRS.destroy();
+    }
+}
diff --git a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs
index 4133fda..b02f85d 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs
+++ b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs
@@ -102,7 +102,8 @@
     start();
 
     // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100; ct++) {
+    int ct;
+    for (ct=0; ct < 1000 * 100; ct++) {
         for (int i=0; i < (1000); i++) {
             data_f1[i] = clamp(data_f1[i], -1.f, 1.f);
         }
@@ -129,7 +130,8 @@
 
     float total = 0;
     // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100 /4; ct++) {
+    int ct;
+    for (ct=0; ct < 1000 * 100 /4; ct++) {
         for (int i=0; i < (1000); i++) {
             data_f4[i] = clamp(data_f4[i], -1.f, 1.f);
         }
@@ -140,7 +142,8 @@
 }
 
 void fp_mad_test(uint32_t index, int test_num) {
-    for (int x=0; x < 1025; x++) {
+    int x;
+    for (x=0; x < 1025; x++) {
         data_f1[x] = (x & 0xf) * 0.1f;
         data_f4[x].x = (x & 0xf) * 0.1f;
         data_f4[x].y = (x & 0xf0) * 0.1f;
diff --git a/libs/rs/java/tests/src/com/android/rs/test/math.rs b/libs/rs/java/tests/src/com/android/rs/test/math.rs
new file mode 100644
index 0000000..5b1ad15
--- /dev/null
+++ b/libs/rs/java/tests/src/com/android/rs/test/math.rs
@@ -0,0 +1,65 @@
+#include "shared.rsh"
+
+// Testing math library
+
+volatile float f1;
+volatile float2 f2;
+volatile float3 f3;
+volatile float4 f4;
+
+#define TEST_F(fnc, var)            \
+    rsDebug("Testing " #fnc, 0);    \
+    var##1 = fnc(var##1);           \
+    var##2 = fnc(var##2);           \
+    var##3 = fnc(var##3);           \
+    var##4 = fnc(var##4);
+
+#define TEST_FP(fnc, var)           \
+    rsDebug("Testing " #fnc, 0);    \
+    var##1 = fnc(var##1, (float*) &f1);  \
+    var##2 = fnc(var##2, (float2*) &f2);  \
+    var##3 = fnc(var##3, (float3*) &f3);  \
+    var##4 = fnc(var##4, (float4*) &f4);
+
+#define TEST_F2(fnc, var)           \
+    rsDebug("Testing " #fnc, 0);    \
+    var##1 = fnc(var##1, var##1);   \
+    var##2 = fnc(var##2, var##2);   \
+    var##3 = fnc(var##3, var##3);   \
+    var##4 = fnc(var##4, var##4);
+
+static bool test_math(uint32_t index) {
+    bool failed = false;
+    start();
+
+    TEST_F(cos, f);
+    TEST_FP(modf, f);
+    TEST_F2(pow, f);
+    TEST_F(sin, f);
+    TEST_F(sqrt, f);
+
+
+    float time = end(index);
+
+    if (failed) {
+        rsDebug("test_math FAILED", time);
+    }
+    else {
+        rsDebug("test_math PASSED", time);
+    }
+
+    return failed;
+}
+
+void math_test(uint32_t index, int test_num) {
+    bool failed = false;
+    failed |= test_math(index);
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
index 804c767..eb2af1c 100644
--- a/libs/rs/rsLocklessFifo.cpp
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -210,3 +210,19 @@
 void LocklessCommandFifo::dumpState(const char *s) const {
     LOGV("%s %p  put %p, get %p,  buf %p,  end %p", s, this, mPut, mGet, mBuffer, mEnd);
 }
+
+void LocklessCommandFifo::printDebugData() const {
+    dumpState("printing fifo debug");
+    const uint32_t *pptr = (const uint32_t *)mGet;
+    pptr -= 8 * 4;
+    if (mGet < mBuffer) {
+        pptr = (const uint32_t *)mBuffer;
+    }
+
+
+    for (int ct=0; ct < 16; ct++) {
+        LOGV("fifo %p = 0x%08x  0x%08x  0x%08x  0x%08x", pptr, pptr[0], pptr[1], pptr[2], pptr[3]);
+        pptr += 4;
+    }
+
+}
diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h
index c963963..eabdc3e 100644
--- a/libs/rs/rsLocklessFifo.h
+++ b/libs/rs/rsLocklessFifo.h
@@ -35,6 +35,8 @@
     bool init(uint32_t size);
     void shutdown();
 
+    void printDebugData() const;
+
     LocklessCommandFifo();
     ~LocklessCommandFifo();
 
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 1ab2109..9f730bf 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -471,45 +471,42 @@
                                ScriptC *s,
                                const char *resName,
                                const char *cacheDir) {
-    {
-        s->mBccScript = bccCreateScript();
+    s->mBccScript = bccCreateScript();
 
-        s->mEnviroment.mIsThreadable = true;
+    s->mEnviroment.mIsThreadable = true;
 
-        bccRegisterSymbolCallback(s->mBccScript, symbolLookup, s);
+    bccRegisterSymbolCallback(s->mBccScript, symbolLookup, s);
 
-        if (bccReadBC(s->mBccScript,
-                      resName,
-                      s->mEnviroment.mScriptText,
-                      s->mEnviroment.mScriptTextLength, 0) != 0) {
-            LOGE("bcc: FAILS to read bitcode");
-            // Handle Fatal Error
-        }
+    if (bccReadBC(s->mBccScript,
+                  resName,
+                  s->mEnviroment.mScriptText,
+                  s->mEnviroment.mScriptTextLength, 0) != 0) {
+        LOGE("bcc: FAILS to read bitcode");
+        // Handle Fatal Error
+    }
 
 #if 1
-        if (bccLinkBC(s->mBccScript,
-                      resName,
-                      NULL /*rs_runtime_lib_bc*/,
-                      1 /*rs_runtime_lib_bc_size*/
-                        /*"1" means skip buffer here, and let libbcc decide*/,
-                      0) != 0) {
-            LOGE("bcc: FAILS to link bitcode");
-            // Handle Fatal Error
-        }
-#endif
-        char *cachePath = genCacheFileName(cacheDir, resName, ".oBCC");
-
-        if (bccPrepareExecutable(s->mBccScript, cachePath, 0) != 0) {
-            LOGE("bcc: FAILS to prepare executable");
-            // Handle Fatal Error
-        }
-
-        free(cachePath);
-
-        s->mProgram.mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(s->mBccScript, "root"));
-        s->mProgram.mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(s->mBccScript, "init"));
+    if (bccLinkBC(s->mBccScript,
+                  resName,
+                  NULL /*rs_runtime_lib_bc*/,
+                  1 /*rs_runtime_lib_bc_size*/
+                    /*"1" means skip buffer here, and let libbcc decide*/,
+                  0) != 0) {
+        LOGE("bcc: FAILS to link bitcode");
+        // Handle Fatal Error
     }
-    LOGV("%p ScriptCState::runCompiler root %p,  init %p", rsc, s->mProgram.mRoot, s->mProgram.mInit);
+#endif
+    char *cachePath = genCacheFileName(cacheDir, resName, ".oBCC");
+
+    if (bccPrepareExecutable(s->mBccScript, cachePath, 0) != 0) {
+        LOGE("bcc: FAILS to prepare executable");
+        // Handle Fatal Error
+    }
+
+    free(cachePath);
+
+    s->mProgram.mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(s->mBccScript, "root"));
+    s->mProgram.mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(s->mBccScript, "init"));
 
     if (s->mProgram.mInit) {
         s->mProgram.mInit();
@@ -537,66 +534,69 @@
     s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore());
     s->mEnviroment.mRaster.set(rsc->getDefaultProgramRaster());
 
-    if (s->mProgram.mRoot) {
-        const static int pragmaMax = 16;
-        size_t pragmaCount = bccGetPragmaCount(s->mBccScript);
-        char const *keys[pragmaMax];
-        char const *values[pragmaMax];
-        bccGetPragmaList(s->mBccScript, pragmaMax, keys, values);
+    const static int pragmaMax = 16;
+    size_t pragmaCount = bccGetPragmaCount(s->mBccScript);
+    char const *keys[pragmaMax];
+    char const *values[pragmaMax];
+    bccGetPragmaList(s->mBccScript, pragmaMax, keys, values);
 
-        for (size_t i=0; i < pragmaCount; ++i) {
-            //LOGE("pragma %s %s", keys[i], values[i]);
-            if (!strcmp(keys[i], "version")) {
+    for (size_t i=0; i < pragmaCount; ++i) {
+        //LOGE("pragma %s %s", keys[i], values[i]);
+        if (!strcmp(keys[i], "version")) {
+            if (!strcmp(values[i], "1")) {
                 continue;
             }
-
-            if (!strcmp(keys[i], "stateVertex")) {
-                if (!strcmp(values[i], "default")) {
-                    continue;
-                }
-                if (!strcmp(values[i], "parent")) {
-                    s->mEnviroment.mVertex.clear();
-                    continue;
-                }
-                LOGE("Unreconized value %s passed to stateVertex", values[i]);
-            }
-
-            if (!strcmp(keys[i], "stateRaster")) {
-                if (!strcmp(values[i], "default")) {
-                    continue;
-                }
-                if (!strcmp(values[i], "parent")) {
-                    s->mEnviroment.mRaster.clear();
-                    continue;
-                }
-                LOGE("Unreconized value %s passed to stateRaster", values[i]);
-            }
-
-            if (!strcmp(keys[i], "stateFragment")) {
-                if (!strcmp(values[i], "default")) {
-                    continue;
-                }
-                if (!strcmp(values[i], "parent")) {
-                    s->mEnviroment.mFragment.clear();
-                    continue;
-                }
-                LOGE("Unreconized value %s passed to stateFragment", values[i]);
-            }
-
-            if (!strcmp(keys[i], "stateStore")) {
-                if (!strcmp(values[i], "default")) {
-                    continue;
-                }
-                if (!strcmp(values[i], "parent")) {
-                    s->mEnviroment.mFragmentStore.clear();
-                    continue;
-                }
-                LOGE("Unreconized value %s passed to stateStore", values[i]);
-            }
+            LOGE("Invalid version pragma value: %s\n", values[i]);
+            // Handle Fatal Error
         }
-    } else {
-        LOGE("bcc: FAILS to prepare executable");
-        // Handle Fatal Error
+
+        if (!strcmp(keys[i], "stateVertex")) {
+            if (!strcmp(values[i], "default")) {
+                continue;
+            }
+            if (!strcmp(values[i], "parent")) {
+                s->mEnviroment.mVertex.clear();
+                continue;
+            }
+            LOGE("Unrecognized value %s passed to stateVertex", values[i]);
+            // Handle Fatal Error
+        }
+
+        if (!strcmp(keys[i], "stateRaster")) {
+            if (!strcmp(values[i], "default")) {
+                continue;
+            }
+            if (!strcmp(values[i], "parent")) {
+                s->mEnviroment.mRaster.clear();
+                continue;
+            }
+            LOGE("Unrecognized value %s passed to stateRaster", values[i]);
+            // Handle Fatal Error
+        }
+
+        if (!strcmp(keys[i], "stateFragment")) {
+            if (!strcmp(values[i], "default")) {
+                continue;
+            }
+            if (!strcmp(values[i], "parent")) {
+                s->mEnviroment.mFragment.clear();
+                continue;
+            }
+            LOGE("Unrecognized value %s passed to stateFragment", values[i]);
+            // Handle Fatal Error
+        }
+
+        if (!strcmp(keys[i], "stateStore")) {
+            if (!strcmp(values[i], "default")) {
+                continue;
+            }
+            if (!strcmp(values[i], "parent")) {
+                s->mEnviroment.mFragmentStore.clear();
+                continue;
+            }
+            LOGE("Unrecognized value %s passed to stateStore", values[i]);
+            // Handle Fatal Error
+        }
     }
 }
 
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 0b21669..f550d98 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -226,51 +226,51 @@
 }
 
 static void SC_debugF(const char *s, float f) {
-    LOGE("%s %f, 0x%08x", s, f, *((int *) (&f)));
+    LOGD("%s %f, 0x%08x", s, f, *((int *) (&f)));
 }
 static void SC_debugFv2(const char *s, float f1, float f2) {
-    LOGE("%s {%f, %f}", s, f1, f2);
+    LOGD("%s {%f, %f}", s, f1, f2);
 }
 static void SC_debugFv3(const char *s, float f1, float f2, float f3) {
-    LOGE("%s {%f, %f, %f}", s, f1, f2, f3);
+    LOGD("%s {%f, %f, %f}", s, f1, f2, f3);
 }
 static void SC_debugFv4(const char *s, float f1, float f2, float f3, float f4) {
-    LOGE("%s {%f, %f, %f, %f}", s, f1, f2, f3, f4);
+    LOGD("%s {%f, %f, %f, %f}", s, f1, f2, f3, f4);
 }
 static void SC_debugD(const char *s, double d) {
-    LOGE("%s %f, 0x%08llx", s, d, *((long long *) (&d)));
+    LOGD("%s %f, 0x%08llx", s, d, *((long long *) (&d)));
 }
 static void SC_debugFM4v4(const char *s, const float *f) {
-    LOGE("%s {%f, %f, %f, %f", s, f[0], f[4], f[8], f[12]);
-    LOGE("%s  %f, %f, %f, %f", s, f[1], f[5], f[9], f[13]);
-    LOGE("%s  %f, %f, %f, %f", s, f[2], f[6], f[10], f[14]);
-    LOGE("%s  %f, %f, %f, %f}", s, f[3], f[7], f[11], f[15]);
+    LOGD("%s {%f, %f, %f, %f", s, f[0], f[4], f[8], f[12]);
+    LOGD("%s  %f, %f, %f, %f", s, f[1], f[5], f[9], f[13]);
+    LOGD("%s  %f, %f, %f, %f", s, f[2], f[6], f[10], f[14]);
+    LOGD("%s  %f, %f, %f, %f}", s, f[3], f[7], f[11], f[15]);
 }
 static void SC_debugFM3v3(const char *s, const float *f) {
-    LOGE("%s {%f, %f, %f", s, f[0], f[3], f[6]);
-    LOGE("%s  %f, %f, %f", s, f[1], f[4], f[7]);
-    LOGE("%s  %f, %f, %f}",s, f[2], f[5], f[8]);
+    LOGD("%s {%f, %f, %f", s, f[0], f[3], f[6]);
+    LOGD("%s  %f, %f, %f", s, f[1], f[4], f[7]);
+    LOGD("%s  %f, %f, %f}",s, f[2], f[5], f[8]);
 }
 static void SC_debugFM2v2(const char *s, const float *f) {
-    LOGE("%s {%f, %f", s, f[0], f[2]);
-    LOGE("%s  %f, %f}",s, f[1], f[3]);
+    LOGD("%s {%f, %f", s, f[0], f[2]);
+    LOGD("%s  %f, %f}",s, f[1], f[3]);
 }
 
 static void SC_debugI32(const char *s, int32_t i) {
-    LOGE("%s %i  0x%x", s, i, i);
+    LOGD("%s %i  0x%x", s, i, i);
 }
 static void SC_debugU32(const char *s, uint32_t i) {
-    LOGE("%s %u  0x%x", s, i, i);
+    LOGD("%s %u  0x%x", s, i, i);
 }
 static void SC_debugLL64(const char *s, long long ll) {
-    LOGE("%s %lld  0x%llx", s, ll, ll);
+    LOGD("%s %lld  0x%llx", s, ll, ll);
 }
 static void SC_debugULL64(const char *s, unsigned long long ll) {
-    LOGE("%s %llu  0x%llx", s, ll, ll);
+    LOGD("%s %llu  0x%llx", s, ll, ll);
 }
 
 static void SC_debugP(const char *s, const void *p) {
-    LOGE("%s %p", s, p);
+    LOGD("%s %p", s, p);
 }
 
 static uint32_t SC_toClient2(int cmdID, void *data, int len) {
diff --git a/libs/rs/rsScriptC_LibCL.cpp b/libs/rs/rsScriptC_LibCL.cpp
index 6c0e164..28c558d 100644
--- a/libs/rs/rsScriptC_LibCL.cpp
+++ b/libs/rs/rsScriptC_LibCL.cpp
@@ -221,7 +221,7 @@
     { "_Z5log1pf", (void *)&log1pf, true },
     //{ "logb", (void *)&, true },
     //{ "mad", (void *)&, true },
-    { "modf", (void *)&modff, true },
+    { "_Z4modffPf", (void *)&modff, true },
     //{ "nan", (void *)&, true },
     { "_Z9nextafterff", (void *)&nextafterf, true },
     { "_Z3powff", (void *)&powf, true },
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 001ac55..6cf07de7 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -56,6 +56,7 @@
         if (cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) {
             rsAssert(cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *)));
             LOGE("playCoreCommands error con %p, cmd %i", con, cmdID);
+            mToCore.printDebugData();
         }
         gPlaybackFuncs[cmdID](con, data);
         mToCore.next();
diff --git a/libs/rs/scriptc/rs_cl.rsh b/libs/rs/scriptc/rs_cl.rsh
index a5092b3..ab8270f40 100644
--- a/libs/rs/scriptc/rs_cl.rsh
+++ b/libs/rs/scriptc/rs_cl.rsh
@@ -1,20 +1,23 @@
 #ifndef __RS_CL_RSH__
 #define __RS_CL_RSH__
 
-#define M_PI        3.14159265358979323846264338327950288f   /* pi */
-
+#ifdef BCC_PREPARE_BC
+#define _RS_STATIC  extern
+#else
+#define _RS_STATIC  static
+#endif
 
 // Conversions
 #define CVT_FUNC_2(typeout, typein) \
-static typeout##2 __attribute__((overloadable)) convert_##typeout##2(typein##2 v) { \
+_RS_STATIC typeout##2 __attribute__((overloadable)) convert_##typeout##2(typein##2 v) { \
     typeout##2 r = {(typeout)v.x, (typeout)v.y}; \
     return r; \
 } \
-static typeout##3 __attribute__((overloadable)) convert_##typeout##3(typein##3 v) { \
+_RS_STATIC typeout##3 __attribute__((overloadable)) convert_##typeout##3(typein##3 v) { \
     typeout##3 r = {(typeout)v.x, (typeout)v.y, (typeout)v.z}; \
     return r; \
 } \
-static typeout##4 __attribute__((overloadable)) convert_##typeout##4(typein##4 v) { \
+_RS_STATIC typeout##4 __attribute__((overloadable)) convert_##typeout##4(typein##4 v) { \
     typeout##4 r = {(typeout)v.x, (typeout)v.y, (typeout)v.z, (typeout)v.w}; \
     return r; \
 }
@@ -40,20 +43,20 @@
 // Float ops, 6.11.2
 
 #define DEF_FUNC_1(fnc) \
-static float2 __attribute__((overloadable)) fnc(float2 v) { \
+_RS_STATIC float2 __attribute__((overloadable)) fnc(float2 v) { \
     float2 r; \
     r.x = fnc(v.x); \
     r.y = fnc(v.y); \
     return r; \
 } \
-static float3 __attribute__((overloadable)) fnc(float3 v) { \
+_RS_STATIC float3 __attribute__((overloadable)) fnc(float3 v) { \
     float3 r; \
     r.x = fnc(v.x); \
     r.y = fnc(v.y); \
     r.z = fnc(v.z); \
     return r; \
 } \
-static float4 __attribute__((overloadable)) fnc(float4 v) { \
+_RS_STATIC float4 __attribute__((overloadable)) fnc(float4 v) { \
     float4 r; \
     r.x = fnc(v.x); \
     r.y = fnc(v.y); \
@@ -63,20 +66,20 @@
 }
 
 #define DEF_FUNC_1_RI(fnc) \
-static int2 __attribute__((overloadable)) fnc(float2 v) { \
+_RS_STATIC int2 __attribute__((overloadable)) fnc(float2 v) { \
     int2 r; \
     r.x = fnc(v.x); \
     r.y = fnc(v.y); \
     return r; \
 } \
-static int3 __attribute__((overloadable)) fnc(float3 v) { \
+_RS_STATIC int3 __attribute__((overloadable)) fnc(float3 v) { \
     int3 r; \
     r.x = fnc(v.x); \
     r.y = fnc(v.y); \
     r.z = fnc(v.z); \
     return r; \
 } \
-static int4 __attribute__((overloadable)) fnc(float4 v) { \
+_RS_STATIC int4 __attribute__((overloadable)) fnc(float4 v) { \
     int4 r; \
     r.x = fnc(v.x); \
     r.y = fnc(v.y); \
@@ -86,43 +89,43 @@
 }
 
 #define DEF_FUNC_2(fnc) \
-static float2 __attribute__((overloadable)) fnc(float2 v1, float2 v2) { \
+_RS_STATIC float2 __attribute__((overloadable)) fnc(float2 v1, float2 v2) { \
     float2 r; \
     r.x = fnc(v1.x, v2.x); \
     r.y = fnc(v1.y, v2.y); \
     return r; \
 } \
-static float3 __attribute__((overloadable)) fnc(float3 v1, float3 v2) { \
+_RS_STATIC float3 __attribute__((overloadable)) fnc(float3 v1, float3 v2) { \
     float3 r; \
     r.x = fnc(v1.x, v2.x); \
     r.y = fnc(v1.y, v2.y); \
     r.z = fnc(v1.z, v2.z); \
     return r; \
 } \
-static float4 __attribute__((overloadable)) fnc(float4 v1, float4 v2) { \
+_RS_STATIC float4 __attribute__((overloadable)) fnc(float4 v1, float4 v2) { \
     float4 r; \
     r.x = fnc(v1.x, v2.x); \
     r.y = fnc(v1.y, v2.y); \
     r.z = fnc(v1.z, v2.z); \
-    r.w = fnc(v1.w, v2.z); \
+    r.w = fnc(v1.w, v2.w); \
     return r; \
 }
 
 #define DEF_FUNC_2F(fnc) \
-static float2 __attribute__((overloadable)) fnc(float2 v1, float v2) { \
+_RS_STATIC float2 __attribute__((overloadable)) fnc(float2 v1, float v2) { \
     float2 r; \
     r.x = fnc(v1.x, v2); \
     r.y = fnc(v1.y, v2); \
     return r; \
 } \
-static float3 __attribute__((overloadable)) fnc(float3 v1, float v2) { \
+_RS_STATIC float3 __attribute__((overloadable)) fnc(float3 v1, float v2) { \
     float3 r; \
     r.x = fnc(v1.x, v2); \
     r.y = fnc(v1.y, v2); \
     r.z = fnc(v1.z, v2); \
     return r; \
 } \
-static float4 __attribute__((overloadable)) fnc(float4 v1, float v2) { \
+_RS_STATIC float4 __attribute__((overloadable)) fnc(float4 v1, float v2) { \
     float4 r; \
     r.x = fnc(v1.x, v2); \
     r.y = fnc(v1.y, v2); \
@@ -131,6 +134,40 @@
     return r; \
 }
 
+#define DEF_FUNC_2P(fnc) \
+_RS_STATIC float2 __attribute__((overloadable)) fnc(float2 v1, float2 *v2) { \
+    float2 r; \
+    float q; \
+    r.x = fnc(v1.x, &q); \
+    v2->x = q; \
+    r.y = fnc(v1.y, &q); \
+    v2->y = q; \
+    return r; \
+} \
+_RS_STATIC float3 __attribute__((overloadable)) fnc(float3 v1, float3 *v2) { \
+    float3 r; \
+    float q; \
+    r.x = fnc(v1.x, &q); \
+    v2->x = q; \
+    r.y = fnc(v1.y, &q); \
+    v2->y = q; \
+    r.z = fnc(v1.z, &q); \
+    v2->z = q; \
+    return r; \
+} \
+_RS_STATIC float4 __attribute__((overloadable)) fnc(float4 v1, float4 *v2) { \
+    float4 r; \
+    float q; \
+    r.x = fnc(v1.x, &q); \
+    v2->x = q; \
+    r.y = fnc(v1.y, &q); \
+    v2->y = q; \
+    r.z = fnc(v1.z, &q); \
+    v2->z = q; \
+    r.w = fnc(v1.w, &q); \
+    v2->w = q; \
+    return r; \
+}
 
 extern float __attribute__((overloadable)) acos(float);
 DEF_FUNC_1(acos)
@@ -138,7 +175,7 @@
 extern float __attribute__((overloadable)) acosh(float);
 DEF_FUNC_1(acosh)
 
-static float __attribute__((overloadable)) acospi(float v) {
+_RS_STATIC float __attribute__((overloadable)) acospi(float v) {
     return acos(v) / M_PI;
 }
 DEF_FUNC_1(acospi)
@@ -149,7 +186,7 @@
 extern float __attribute__((overloadable)) asinh(float);
 DEF_FUNC_1(asinh)
 
-static float __attribute__((overloadable)) asinpi(float v) {
+_RS_STATIC float __attribute__((overloadable)) asinpi(float v) {
     return asin(v) / M_PI;
 }
 DEF_FUNC_1(asinpi)
@@ -163,12 +200,12 @@
 extern float __attribute__((overloadable)) atanh(float);
 DEF_FUNC_1(atanh)
 
-static float __attribute__((overloadable)) atanpi(float v) {
+_RS_STATIC float __attribute__((overloadable)) atanpi(float v) {
     return atan(v) / M_PI;
 }
 DEF_FUNC_1(atanpi)
 
-static float __attribute__((overloadable)) atan2pi(float y, float x) {
+_RS_STATIC float __attribute__((overloadable)) atan2pi(float y, float x) {
     return atan2(y, x) / M_PI;
 }
 DEF_FUNC_2(atan2pi)
@@ -188,7 +225,7 @@
 extern float __attribute__((overloadable)) cosh(float);
 DEF_FUNC_1(cosh)
 
-static float __attribute__((overloadable)) cospi(float v) {
+_RS_STATIC float __attribute__((overloadable)) cospi(float v) {
     return cos(v * M_PI);
 }
 DEF_FUNC_1(cospi)
@@ -206,7 +243,7 @@
 DEF_FUNC_1(exp2)
 
 extern float __attribute__((overloadable)) pow(float, float);
-static float __attribute__((overloadable)) exp10(float v) {
+_RS_STATIC float __attribute__((overloadable)) exp10(float v) {
     return pow(10.f, v);
 }
 DEF_FUNC_1(exp10)
@@ -239,12 +276,12 @@
 extern float __attribute__((overloadable)) fmod(float, float);
 DEF_FUNC_2(fmod)
 
-static float __attribute__((overloadable)) fract(float v, float *iptr) {
+_RS_STATIC float __attribute__((overloadable)) fract(float v, float *iptr) {
     int i = (int)floor(v);
     iptr[0] = i;
     return fmin(v - i, 0x1.fffffep-1f);
 }
-static float2 __attribute__((overloadable)) fract(float2 v, float2 *iptr) {
+_RS_STATIC float2 __attribute__((overloadable)) fract(float2 v, float2 *iptr) {
     float t[2];
     float2 r;
     r.x = fract(v.x, &t[0]);
@@ -253,7 +290,7 @@
     iptr[1] = t[1];
     return r;
 }
-static float3 __attribute__((overloadable)) fract(float3 v, float3 *iptr) {
+_RS_STATIC float3 __attribute__((overloadable)) fract(float3 v, float3 *iptr) {
     float t[3];
     float3 r;
     r.x = fract(v.x, &t[0]);
@@ -264,7 +301,7 @@
     iptr[2] = t[2];
     return r;
 }
-static float4 __attribute__((overloadable)) fract(float4 v, float4 *iptr) {
+_RS_STATIC float4 __attribute__((overloadable)) fract(float4 v, float4 *iptr) {
     float t[4];
     float4 r;
     r.x = fract(v.x, &t[0]);
@@ -311,7 +348,7 @@
 extern float __attribute__((overloadable)) log10(float);
 DEF_FUNC_1(log10)
 
-static float __attribute__((overloadable)) log2(float v) {
+_RS_STATIC float __attribute__((overloadable)) log2(float v) {
     return log10(v) / log10(2.f);
 }
 DEF_FUNC_1(log2)
@@ -328,9 +365,7 @@
 extern float4 __attribute__((overloadable)) mad(float4, float4, float4);
 
 extern float __attribute__((overloadable)) modf(float, float *);
-extern float2 __attribute__((overloadable)) modf(float2, float2 *);
-extern float3 __attribute__((overloadable)) modf(float3, float3 *);
-extern float4 __attribute__((overloadable)) modf(float4, float4 *);
+DEF_FUNC_2P(modf);
 
 //extern float __attribute__((overloadable)) nan(uint);
 
@@ -339,29 +374,29 @@
 
 DEF_FUNC_2(pow)
 
-static float __attribute__((overloadable)) pown(float v, int p) {
+_RS_STATIC float __attribute__((overloadable)) pown(float v, int p) {
     return pow(v, (float)p);
 }
-static float2 __attribute__((overloadable)) pown(float2 v, int2 p) {
+_RS_STATIC float2 __attribute__((overloadable)) pown(float2 v, int2 p) {
     return pow(v, (float2)p);
 }
-static float3 __attribute__((overloadable)) pown(float3 v, int3 p) {
+_RS_STATIC float3 __attribute__((overloadable)) pown(float3 v, int3 p) {
     return pow(v, (float3)p);
 }
-static float4 __attribute__((overloadable)) pown(float4 v, int4 p) {
+_RS_STATIC float4 __attribute__((overloadable)) pown(float4 v, int4 p) {
     return pow(v, (float4)p);
 }
 
-static float __attribute__((overloadable)) powr(float v, float p) {
+_RS_STATIC float __attribute__((overloadable)) powr(float v, float p) {
     return pow(v, p);
 }
-static float2 __attribute__((overloadable)) powr(float2 v, float2 p) {
+_RS_STATIC float2 __attribute__((overloadable)) powr(float2 v, float2 p) {
     return pow(v, p);
 }
-static float3 __attribute__((overloadable)) powr(float3 v, float3 p) {
+_RS_STATIC float3 __attribute__((overloadable)) powr(float3 v, float3 p) {
     return pow(v, p);
 }
-static float4 __attribute__((overloadable)) powr(float4 v, float4 p) {
+_RS_STATIC float4 __attribute__((overloadable)) powr(float4 v, float4 p) {
     return pow(v, p);
 }
 
@@ -376,18 +411,18 @@
 extern float __attribute__((overloadable)) rint(float);
 DEF_FUNC_1(rint)
 
-static float __attribute__((overloadable)) rootn(float v, int r) {
+_RS_STATIC float __attribute__((overloadable)) rootn(float v, int r) {
     return pow(v, 1.f / r);
 }
-static float2 __attribute__((overloadable)) rootn(float2 v, int2 r) {
+_RS_STATIC float2 __attribute__((overloadable)) rootn(float2 v, int2 r) {
     float2 t = {1.f / r.x, 1.f / r.y};
     return pow(v, t);
 }
-static float3 __attribute__((overloadable)) rootn(float3 v, int3 r) {
+_RS_STATIC float3 __attribute__((overloadable)) rootn(float3 v, int3 r) {
     float3 t = {1.f / r.x, 1.f / r.y, 1.f / r.z};
     return pow(v, t);
 }
-static float4 __attribute__((overloadable)) rootn(float4 v, int4 r) {
+_RS_STATIC float4 __attribute__((overloadable)) rootn(float4 v, int4 r) {
     float4 t = {1.f / r.x, 1.f / r.y, 1.f / r.z, 1.f / r.w};
     return pow(v, t);
 }
@@ -396,7 +431,7 @@
 DEF_FUNC_1(round)
 
 extern float __attribute__((overloadable)) sqrt(float);
-static float __attribute__((overloadable)) rsqrt(float v) {
+_RS_STATIC float __attribute__((overloadable)) rsqrt(float v) {
     return 1.f / sqrt(v);
 }
 DEF_FUNC_1(rsqrt)
@@ -404,19 +439,19 @@
 extern float __attribute__((overloadable)) sin(float);
 DEF_FUNC_1(sin)
 
-static float __attribute__((overloadable)) sincos(float v, float *cosptr) {
+_RS_STATIC float __attribute__((overloadable)) sincos(float v, float *cosptr) {
     *cosptr = cos(v);
     return sin(v);
 }
-static float2 __attribute__((overloadable)) sincos(float2 v, float2 *cosptr) {
+_RS_STATIC float2 __attribute__((overloadable)) sincos(float2 v, float2 *cosptr) {
     *cosptr = cos(v);
     return sin(v);
 }
-static float3 __attribute__((overloadable)) sincos(float3 v, float3 *cosptr) {
+_RS_STATIC float3 __attribute__((overloadable)) sincos(float3 v, float3 *cosptr) {
     *cosptr = cos(v);
     return sin(v);
 }
-static float4 __attribute__((overloadable)) sincos(float4 v, float4 *cosptr) {
+_RS_STATIC float4 __attribute__((overloadable)) sincos(float4 v, float4 *cosptr) {
     *cosptr = cos(v);
     return sin(v);
 }
@@ -424,7 +459,7 @@
 extern float __attribute__((overloadable)) sinh(float);
 DEF_FUNC_1(sinh)
 
-static float __attribute__((overloadable)) sinpi(float v) {
+_RS_STATIC float __attribute__((overloadable)) sinpi(float v) {
     return sin(v * M_PI);
 }
 DEF_FUNC_1(sinpi)
@@ -437,7 +472,7 @@
 extern float __attribute__((overloadable)) tanh(float);
 DEF_FUNC_1(tanh)
 
-static float __attribute__((overloadable)) tanpi(float v) {
+_RS_STATIC float __attribute__((overloadable)) tanpi(float v) {
     return tan(v * M_PI);
 }
 DEF_FUNC_1(tanpi)
@@ -449,77 +484,107 @@
 DEF_FUNC_1(trunc)
 
 // Int ops (partial), 6.11.3
-extern uint __attribute__((overloadable)) abs(int);
-extern ushort __attribute__((overloadable)) abs(short);
-extern uchar __attribute__((overloadable)) abs(char);
 
-extern uint __attribute__((overloadable)) clz(uint);
-extern int __attribute__((overloadable)) clz(int);
-extern ushort __attribute__((overloadable)) clz(ushort);
-extern short __attribute__((overloadable)) clz(short);
-extern uchar __attribute__((overloadable)) clz(uchar);
-extern char __attribute__((overloadable)) clz(char);
-
-static uint __attribute__((overloadable)) min(uint v1, uint v2) {
-    return v1 < v2 ? v1 : v2;
-}
-static int __attribute__((overloadable)) min(int v1, int v2) {
-    return v1 < v2 ? v1 : v2;
-}
-static ushort __attribute__((overloadable)) min(ushort v1, ushort v2) {
-    return v1 < v2 ? v1 : v2;
-}
-static short __attribute__((overloadable)) min(short v1, short v2) {
-    return v1 < v2 ? v1 : v2;
-}
-static uchar __attribute__((overloadable)) min(uchar v1, uchar v2) {
-    return v1 < v2 ? v1 : v2;
-}
-static char __attribute__((overloadable)) min(char v1, char v2) {
-    return v1 < v2 ? v1 : v2;
+#define DEF_RIFUNC_1(typeout, typein, fnc)                          \
+extern typeout __attribute__((overloadable)) fnc(typein);           \
+_RS_STATIC typeout##2 __attribute__((overloadable)) fnc(typein##2 v) {  \
+    typeout##2 r;                                                   \
+    r.x = fnc(v.x);                                                 \
+    r.y = fnc(v.y);                                                 \
+    return r;                                                       \
+}                                                                   \
+_RS_STATIC typeout##3 __attribute__((overloadable)) fnc(typein##3 v) {  \
+    typeout##3 r;                                                   \
+    r.x = fnc(v.x);                                                 \
+    r.y = fnc(v.y);                                                 \
+    r.z = fnc(v.z);                                                 \
+    return r;                                                       \
+}                                                                   \
+_RS_STATIC typeout##4 __attribute__((overloadable)) fnc(typein##4 v) {  \
+    typeout##4 r;                                                   \
+    r.x = fnc(v.x);                                                 \
+    r.y = fnc(v.y);                                                 \
+    r.z = fnc(v.z);                                                 \
+    r.w = fnc(v.w);                                                 \
+    return r;                                                       \
 }
 
-static uint __attribute__((overloadable)) max(uint v1, uint v2) {
-    return v1 > v2 ? v1 : v2;
-}
-static int __attribute__((overloadable)) max(int v1, int v2) {
-    return v1 > v2 ? v1 : v2;
-}
-static ushort __attribute__((overloadable)) max(ushort v1, ushort v2) {
-    return v1 > v2 ? v1 : v2;
-}
-static short __attribute__((overloadable)) max(short v1, short v2) {
-    return v1 > v2 ? v1 : v2;
-}
-static uchar __attribute__((overloadable)) max(uchar v1, uchar v2) {
-    return v1 > v2 ? v1 : v2;
-}
-static char __attribute__((overloadable)) max(char v1, char v2) {
-    return v1 > v2 ? v1 : v2;
-}
+#define DEF_UIFUNC_1(fnc)           \
+DEF_RIFUNC_1(uchar, char, fnc)      \
+DEF_RIFUNC_1(ushort, short, fnc)    \
+DEF_RIFUNC_1(uint, int, fnc)
 
+#define DEF_IFUNC_1(fnc)            \
+DEF_RIFUNC_1(uchar, uchar, fnc)     \
+DEF_RIFUNC_1(char, char, fnc)       \
+DEF_RIFUNC_1(ushort, ushort, fnc)   \
+DEF_RIFUNC_1(short, short, fnc)     \
+DEF_RIFUNC_1(uint, uint, fnc)       \
+DEF_RIFUNC_1(int, int, fnc)
 
+#define DEF_RIFUNC_2(type, fnc, body)                                       \
+_RS_STATIC type __attribute__((overloadable)) fnc(type v1, type v2) {           \
+    return body;                                                            \
+}                                                                           \
+_RS_STATIC type##2 __attribute__((overloadable)) fnc(type##2 v1, type##2 v2) {  \
+    type##2 r;                                                              \
+    r.x = fnc(v1.x, v2.x);                                                  \
+    r.y = fnc(v1.y, v2.y);                                                  \
+    return r;                                                               \
+}                                                                           \
+_RS_STATIC type##3 __attribute__((overloadable)) fnc(type##3 v1, type##3 v2) {  \
+    type##3 r;                                                              \
+    r.x = fnc(v1.x, v2.x);                                                  \
+    r.y = fnc(v1.y, v2.y);                                                  \
+    r.z = fnc(v1.z, v2.z);                                                  \
+    return r;                                                               \
+}                                                                           \
+_RS_STATIC type##4 __attribute__((overloadable)) fnc(type##4 v1, type##4 v2) {  \
+    type##4 r;                                                              \
+    r.x = fnc(v1.x, v2.x);                                                  \
+    r.y = fnc(v1.y, v2.y);                                                  \
+    r.z = fnc(v1.z, v2.z);                                                  \
+    r.w = fnc(v1.w, v2.w);                                                  \
+    return r;                                                               \
+}                                                                           \
 
+#define DEF_IFUNC_2(fnc, body)  \
+DEF_RIFUNC_2(uchar, fnc, body)  \
+DEF_RIFUNC_2(char, fnc, body)   \
+DEF_RIFUNC_2(ushort, fnc, body) \
+DEF_RIFUNC_2(short, fnc, body)  \
+DEF_RIFUNC_2(uint, fnc, body)   \
+DEF_RIFUNC_2(int, fnc, body)    \
+DEF_RIFUNC_2(float, fnc, body)
+
+DEF_UIFUNC_1(abs)
+DEF_IFUNC_1(clz)
+
+DEF_IFUNC_2(min, (v1 < v2 ? v1 : v2))
+DEF_FUNC_2F(min)
+
+DEF_IFUNC_2(max, (v1 > v2 ? v1 : v2))
+DEF_FUNC_2F(max)
 
 // 6.11.4
 
-static float __attribute__((overloadable)) clamp(float amount, float low, float high) {
+_RS_STATIC float __attribute__((overloadable)) clamp(float amount, float low, float high) {
     return amount < low ? low : (amount > high ? high : amount);
 }
-static float2 __attribute__((overloadable)) clamp(float2 amount, float2 low, float2 high) {
+_RS_STATIC float2 __attribute__((overloadable)) clamp(float2 amount, float2 low, float2 high) {
     float2 r;
     r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x);
     r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y);
     return r;
 }
-static float3 __attribute__((overloadable)) clamp(float3 amount, float3 low, float3 high) {
+_RS_STATIC float3 __attribute__((overloadable)) clamp(float3 amount, float3 low, float3 high) {
     float3 r;
     r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x);
     r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y);
     r.z = amount.z < low.z ? low.z : (amount.z > high.z ? high.z : amount.z);
     return r;
 }
-static float4 __attribute__((overloadable)) clamp(float4 amount, float4 low, float4 high) {
+_RS_STATIC float4 __attribute__((overloadable)) clamp(float4 amount, float4 low, float4 high) {
     float4 r;
     r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x);
     r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y);
@@ -527,20 +592,20 @@
     r.w = amount.w < low.w ? low.w : (amount.w > high.w ? high.w : amount.w);
     return r;
 }
-static float2 __attribute__((overloadable)) clamp(float2 amount, float low, float high) {
+_RS_STATIC float2 __attribute__((overloadable)) clamp(float2 amount, float low, float high) {
     float2 r;
     r.x = amount.x < low ? low : (amount.x > high ? high : amount.x);
     r.y = amount.y < low ? low : (amount.y > high ? high : amount.y);
     return r;
 }
-static float3 __attribute__((overloadable)) clamp(float3 amount, float low, float high) {
+_RS_STATIC float3 __attribute__((overloadable)) clamp(float3 amount, float low, float high) {
     float3 r;
     r.x = amount.x < low ? low : (amount.x > high ? high : amount.x);
     r.y = amount.y < low ? low : (amount.y > high ? high : amount.y);
     r.z = amount.z < low ? low : (amount.z > high ? high : amount.z);
     return r;
 }
-static float4 __attribute__((overloadable)) clamp(float4 amount, float low, float high) {
+_RS_STATIC float4 __attribute__((overloadable)) clamp(float4 amount, float low, float high) {
     float4 r;
     r.x = amount.x < low ? low : (amount.x > high ? high : amount.x);
     r.y = amount.y < low ? low : (amount.y > high ? high : amount.y);
@@ -549,147 +614,55 @@
     return r;
 }
 
-static float __attribute__((overloadable)) degrees(float radians) {
+_RS_STATIC float __attribute__((overloadable)) degrees(float radians) {
     return radians * (180.f / M_PI);
 }
 DEF_FUNC_1(degrees)
 
-static float __attribute__((overloadable)) max(float v1, float v2) {
-    return v1 > v2 ? v1 : v2;
-}
-static float2 __attribute__((overloadable)) max(float2 v1, float2 v2) {
-    float2 r;
-    r.x = v1.x > v2.x ? v1.x : v2.x;
-    r.y = v1.y > v2.y ? v1.y : v2.y;
-    return r;
-}
-static float3 __attribute__((overloadable)) max(float3 v1, float3 v2) {
-    float3 r;
-    r.x = v1.x > v2.x ? v1.x : v2.x;
-    r.y = v1.y > v2.y ? v1.y : v2.y;
-    r.z = v1.z > v2.z ? v1.z : v2.z;
-    return r;
-}
-static float4 __attribute__((overloadable)) max(float4 v1, float4 v2) {
-    float4 r;
-    r.x = v1.x > v2.x ? v1.x : v2.x;
-    r.y = v1.y > v2.y ? v1.y : v2.y;
-    r.z = v1.z > v2.z ? v1.z : v2.z;
-    r.w = v1.w > v2.w ? v1.w : v2.w;
-    return r;
-}
-static float2 __attribute__((overloadable)) max(float2 v1, float v2) {
-    float2 r;
-    r.x = v1.x > v2 ? v1.x : v2;
-    r.y = v1.y > v2 ? v1.y : v2;
-    return r;
-}
-static float3 __attribute__((overloadable)) max(float3 v1, float v2) {
-    float3 r;
-    r.x = v1.x > v2 ? v1.x : v2;
-    r.y = v1.y > v2 ? v1.y : v2;
-    r.z = v1.z > v2 ? v1.z : v2;
-    return r;
-}
-static float4 __attribute__((overloadable)) max(float4 v1, float v2) {
-    float4 r;
-    r.x = v1.x > v2 ? v1.x : v2;
-    r.y = v1.y > v2 ? v1.y : v2;
-    r.z = v1.z > v2 ? v1.z : v2;
-    r.w = v1.w > v2 ? v1.w : v2;
-    return r;
-}
-
-static float __attribute__((overloadable)) min(float v1, float v2) {
-    return v1 < v2 ? v1 : v2;
-}
-static float2 __attribute__((overloadable)) min(float2 v1, float2 v2) {
-    float2 r;
-    r.x = v1.x < v2.x ? v1.x : v2.x;
-    r.y = v1.y < v2.y ? v1.y : v2.y;
-    return r;
-}
-static float3 __attribute__((overloadable)) min(float3 v1, float3 v2) {
-    float3 r;
-    r.x = v1.x < v2.x ? v1.x : v2.x;
-    r.y = v1.y < v2.y ? v1.y : v2.y;
-    r.z = v1.z < v2.z ? v1.z : v2.z;
-    return r;
-}
-static float4 __attribute__((overloadable)) min(float4 v1, float4 v2) {
-    float4 r;
-    r.x = v1.x < v2.x ? v1.x : v2.x;
-    r.y = v1.y < v2.y ? v1.y : v2.y;
-    r.z = v1.z < v2.z ? v1.z : v2.z;
-    r.w = v1.w < v2.w ? v1.w : v2.w;
-    return r;
-}
-static float2 __attribute__((overloadable)) min(float2 v1, float v2) {
-    float2 r;
-    r.x = v1.x < v2 ? v1.x : v2;
-    r.y = v1.y < v2 ? v1.y : v2;
-    return r;
-}
-static float3 __attribute__((overloadable)) min(float3 v1, float v2) {
-    float3 r;
-    r.x = v1.x < v2 ? v1.x : v2;
-    r.y = v1.y < v2 ? v1.y : v2;
-    r.z = v1.z < v2 ? v1.z : v2;
-    return r;
-}
-static float4 __attribute__((overloadable)) min(float4 v1, float v2) {
-    float4 r;
-    r.x = v1.x < v2 ? v1.x : v2;
-    r.y = v1.y < v2 ? v1.y : v2;
-    r.z = v1.z < v2 ? v1.z : v2;
-    r.w = v1.w < v2 ? v1.w : v2;
-    return r;
-}
-
-static float __attribute__((overloadable)) mix(float start, float stop, float amount) {
+_RS_STATIC float __attribute__((overloadable)) mix(float start, float stop, float amount) {
     return start + (stop - start) * amount;
 }
-static float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float2 amount) {
+_RS_STATIC float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float2 amount) {
     return start + (stop - start) * amount;
 }
-static float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float3 amount) {
+_RS_STATIC float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float3 amount) {
     return start + (stop - start) * amount;
 }
-static float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float4 amount) {
+_RS_STATIC float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float4 amount) {
     return start + (stop - start) * amount;
 }
-static float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float amount) {
+_RS_STATIC float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float amount) {
     return start + (stop - start) * amount;
 }
-static float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float amount) {
+_RS_STATIC float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float amount) {
     return start + (stop - start) * amount;
 }
-static float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float amount) {
+_RS_STATIC float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float amount) {
     return start + (stop - start) * amount;
 }
 
-static float __attribute__((overloadable)) radians(float degrees) {
+_RS_STATIC float __attribute__((overloadable)) radians(float degrees) {
     return degrees * (M_PI / 180.f);
 }
 DEF_FUNC_1(radians)
 
-static float __attribute__((overloadable)) step(float edge, float v) {
+_RS_STATIC float __attribute__((overloadable)) step(float edge, float v) {
     return (v < edge) ? 0.f : 1.f;
 }
-static float2 __attribute__((overloadable)) step(float2 edge, float2 v) {
+_RS_STATIC float2 __attribute__((overloadable)) step(float2 edge, float2 v) {
     float2 r;
     r.x = (v.x < edge.x) ? 0.f : 1.f;
     r.y = (v.y < edge.y) ? 0.f : 1.f;
     return r;
 }
-static float3 __attribute__((overloadable)) step(float3 edge, float3 v) {
+_RS_STATIC float3 __attribute__((overloadable)) step(float3 edge, float3 v) {
     float3 r;
     r.x = (v.x < edge.x) ? 0.f : 1.f;
     r.y = (v.y < edge.y) ? 0.f : 1.f;
     r.z = (v.z < edge.z) ? 0.f : 1.f;
     return r;
 }
-static float4 __attribute__((overloadable)) step(float4 edge, float4 v) {
+_RS_STATIC float4 __attribute__((overloadable)) step(float4 edge, float4 v) {
     float4 r;
     r.x = (v.x < edge.x) ? 0.f : 1.f;
     r.y = (v.y < edge.y) ? 0.f : 1.f;
@@ -697,20 +670,20 @@
     r.w = (v.w < edge.w) ? 0.f : 1.f;
     return r;
 }
-static float2 __attribute__((overloadable)) step(float2 edge, float v) {
+_RS_STATIC float2 __attribute__((overloadable)) step(float2 edge, float v) {
     float2 r;
     r.x = (v < edge.x) ? 0.f : 1.f;
     r.y = (v < edge.y) ? 0.f : 1.f;
     return r;
 }
-static float3 __attribute__((overloadable)) step(float3 edge, float v) {
+_RS_STATIC float3 __attribute__((overloadable)) step(float3 edge, float v) {
     float3 r;
     r.x = (v < edge.x) ? 0.f : 1.f;
     r.y = (v < edge.y) ? 0.f : 1.f;
     r.z = (v < edge.z) ? 0.f : 1.f;
     return r;
 }
-static float4 __attribute__((overloadable)) step(float4 edge, float v) {
+_RS_STATIC float4 __attribute__((overloadable)) step(float4 edge, float v) {
     float4 r;
     r.x = (v < edge.x) ? 0.f : 1.f;
     r.y = (v < edge.y) ? 0.f : 1.f;
@@ -727,7 +700,7 @@
 extern float3 __attribute__((overloadable)) smoothstep(float, float, float3);
 extern float4 __attribute__((overloadable)) smoothstep(float, float, float4);
 
-static float __attribute__((overloadable)) sign(float v) {
+_RS_STATIC float __attribute__((overloadable)) sign(float v) {
     if (v > 0) return 1.f;
     if (v < 0) return -1.f;
     return v;
@@ -735,7 +708,7 @@
 DEF_FUNC_1(sign)
 
 // 6.11.5
-static float3 __attribute__((overloadable)) cross(float3 lhs, float3 rhs) {
+_RS_STATIC float3 __attribute__((overloadable)) cross(float3 lhs, float3 rhs) {
     float3 r;
     r.x = lhs.y * rhs.z  - lhs.z * rhs.y;
     r.y = lhs.z * rhs.x  - lhs.x * rhs.z;
@@ -743,7 +716,7 @@
     return r;
 }
 
-static float4 __attribute__((overloadable)) cross(float4 lhs, float4 rhs) {
+_RS_STATIC float4 __attribute__((overloadable)) cross(float4 lhs, float4 rhs) {
     float4 r;
     r.x = lhs.y * rhs.z  - lhs.z * rhs.y;
     r.y = lhs.z * rhs.x  - lhs.x * rhs.z;
@@ -752,55 +725,55 @@
     return r;
 }
 
-static float __attribute__((overloadable)) dot(float lhs, float rhs) {
+_RS_STATIC float __attribute__((overloadable)) dot(float lhs, float rhs) {
     return lhs * rhs;
 }
-static float __attribute__((overloadable)) dot(float2 lhs, float2 rhs) {
+_RS_STATIC float __attribute__((overloadable)) dot(float2 lhs, float2 rhs) {
     return lhs.x*rhs.x + lhs.y*rhs.y;
 }
-static float __attribute__((overloadable)) dot(float3 lhs, float3 rhs) {
+_RS_STATIC float __attribute__((overloadable)) dot(float3 lhs, float3 rhs) {
     return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z;
 }
-static float __attribute__((overloadable)) dot(float4 lhs, float4 rhs) {
+_RS_STATIC float __attribute__((overloadable)) dot(float4 lhs, float4 rhs) {
     return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z + lhs.w*rhs.w;
 }
 
-static float __attribute__((overloadable)) length(float v) {
+_RS_STATIC float __attribute__((overloadable)) length(float v) {
     return v;
 }
-static float __attribute__((overloadable)) length(float2 v) {
+_RS_STATIC float __attribute__((overloadable)) length(float2 v) {
     return sqrt(v.x*v.x + v.y*v.y);
 }
-static float __attribute__((overloadable)) length(float3 v) {
+_RS_STATIC float __attribute__((overloadable)) length(float3 v) {
     return sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
 }
-static float __attribute__((overloadable)) length(float4 v) {
+_RS_STATIC float __attribute__((overloadable)) length(float4 v) {
     return sqrt(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w);
 }
 
-static float __attribute__((overloadable)) distance(float lhs, float rhs) {
+_RS_STATIC float __attribute__((overloadable)) distance(float lhs, float rhs) {
     return length(lhs - rhs);
 }
-static float __attribute__((overloadable)) distance(float2 lhs, float2 rhs) {
+_RS_STATIC float __attribute__((overloadable)) distance(float2 lhs, float2 rhs) {
     return length(lhs - rhs);
 }
-static float __attribute__((overloadable)) distance(float3 lhs, float3 rhs) {
+_RS_STATIC float __attribute__((overloadable)) distance(float3 lhs, float3 rhs) {
     return length(lhs - rhs);
 }
-static float __attribute__((overloadable)) distance(float4 lhs, float4 rhs) {
+_RS_STATIC float __attribute__((overloadable)) distance(float4 lhs, float4 rhs) {
     return length(lhs - rhs);
 }
 
-static float __attribute__((overloadable)) normalize(float v) {
+_RS_STATIC float __attribute__((overloadable)) normalize(float v) {
     return 1.f;
 }
-static float2 __attribute__((overloadable)) normalize(float2 v) {
+_RS_STATIC float2 __attribute__((overloadable)) normalize(float2 v) {
     return v / length(v);
 }
-static float3 __attribute__((overloadable)) normalize(float3 v) {
+_RS_STATIC float3 __attribute__((overloadable)) normalize(float3 v) {
     return v / length(v);
 }
-static float4 __attribute__((overloadable)) normalize(float4 v) {
+_RS_STATIC float4 __attribute__((overloadable)) normalize(float4 v) {
     return v / length(v);
 }
 
@@ -810,5 +783,11 @@
 #undef DEF_FUNC_1_RI
 #undef DEF_FUNC_2
 #undef DEF_FUNC_2F
+#undef DEF_RIFUNC_1
+#undef DEF_UIFUNC_1
+#undef DEF_IFUNC_1
+#undef DEF_RIFUNC_2
+#undef DEF_IFUNC_2
+#undef _RS_STATIC
 
 #endif
diff --git a/libs/rs/scriptc/rs_core.rsh b/libs/rs/scriptc/rs_core.rsh
index 16482c1..f3e0ab0 100644
--- a/libs/rs/scriptc/rs_core.rsh
+++ b/libs/rs/scriptc/rs_core.rsh
@@ -1,6 +1,12 @@
 #ifndef __RS_CORE_RSH__
 #define __RS_CORE_RSH__
 
+#ifdef BCC_PREPARE_BC
+#define _RS_STATIC  extern
+#else
+#define _RS_STATIC  static
+#endif
+
 // Debugging, print to the LOG a description string and a value.
 extern void __attribute__((overloadable))
     rsDebug(const char *, float);
@@ -35,17 +41,17 @@
 #define RS_DEBUG(a) rsDebug(#a, a)
 #define RS_DEBUG_MARKER rsDebug(__FILE__, __LINE__)
 
-static void __attribute__((overloadable)) rsDebug(const char *s, float2 v) {
+_RS_STATIC void __attribute__((overloadable)) rsDebug(const char *s, float2 v) {
     rsDebug(s, v.x, v.y);
 }
-static void __attribute__((overloadable)) rsDebug(const char *s, float3 v) {
+_RS_STATIC void __attribute__((overloadable)) rsDebug(const char *s, float3 v) {
     rsDebug(s, v.x, v.y, v.z);
 }
-static void __attribute__((overloadable)) rsDebug(const char *s, float4 v) {
+_RS_STATIC void __attribute__((overloadable)) rsDebug(const char *s, float4 v) {
     rsDebug(s, v.x, v.y, v.z, v.w);
 }
 
-static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b)
+_RS_STATIC uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b)
 {
     uchar4 c;
     c.x = (uchar)(r * 255.f);
@@ -55,7 +61,7 @@
     return c;
 }
 
-static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b, float a)
+_RS_STATIC uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b, float a)
 {
     uchar4 c;
     c.x = (uchar)(r * 255.f);
@@ -65,21 +71,21 @@
     return c;
 }
 
-static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float3 color)
+_RS_STATIC uchar4 __attribute__((overloadable)) rsPackColorTo8888(float3 color)
 {
     color *= 255.f;
     uchar4 c = {color.x, color.y, color.z, 255};
     return c;
 }
 
-static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float4 color)
+_RS_STATIC uchar4 __attribute__((overloadable)) rsPackColorTo8888(float4 color)
 {
     color *= 255.f;
     uchar4 c = {color.x, color.y, color.z, color.w};
     return c;
 }
 
-static float4 rsUnpackColor8888(uchar4 c)
+_RS_STATIC float4 rsUnpackColor8888(uchar4 c)
 {
     float4 ret = (float4)0.0039156862745f;
     ret *= convert_float4(c);
@@ -95,37 +101,37 @@
 // Matrix ops
 /////////////////////////////////////////////////////
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixSet(rs_matrix4x4 *m, uint32_t row, uint32_t col, float v) {
     m->m[row * 4 + col] = v;
 }
 
-static float __attribute__((overloadable))
+_RS_STATIC float __attribute__((overloadable))
 rsMatrixGet(const rs_matrix4x4 *m, uint32_t row, uint32_t col) {
     return m->m[row * 4 + col];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixSet(rs_matrix3x3 *m, uint32_t row, uint32_t col, float v) {
     m->m[row * 3 + col] = v;
 }
 
-static float __attribute__((overloadable))
+_RS_STATIC float __attribute__((overloadable))
 rsMatrixGet(const rs_matrix3x3 *m, uint32_t row, uint32_t col) {
     return m->m[row * 3 + col];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixSet(rs_matrix2x2 *m, uint32_t row, uint32_t col, float v) {
     m->m[row * 2 + col] = v;
 }
 
-static float __attribute__((overloadable))
+_RS_STATIC float __attribute__((overloadable))
 rsMatrixGet(const rs_matrix2x2 *m, uint32_t row, uint32_t col) {
     return m->m[row * 2 + col];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadIdentity(rs_matrix4x4 *m) {
     m->m[0] = 1.f;
     m->m[1] = 0.f;
@@ -145,7 +151,7 @@
     m->m[15] = 1.f;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadIdentity(rs_matrix3x3 *m) {
     m->m[0] = 1.f;
     m->m[1] = 0.f;
@@ -158,7 +164,7 @@
     m->m[8] = 1.f;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadIdentity(rs_matrix2x2 *m) {
     m->m[0] = 1.f;
     m->m[1] = 0.f;
@@ -166,7 +172,7 @@
     m->m[3] = 1.f;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix4x4 *m, const float *v) {
     m->m[0] = v[0];
     m->m[1] = v[1];
@@ -186,7 +192,7 @@
     m->m[15] = v[15];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix3x3 *m, const float *v) {
     m->m[0] = v[0];
     m->m[1] = v[1];
@@ -199,7 +205,7 @@
     m->m[8] = v[8];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix2x2 *m, const float *v) {
     m->m[0] = v[0];
     m->m[1] = v[1];
@@ -207,7 +213,7 @@
     m->m[3] = v[3];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix4x4 *v) {
     m->m[0] = v->m[0];
     m->m[1] = v->m[1];
@@ -227,7 +233,7 @@
     m->m[15] = v->m[15];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix3x3 *v) {
     m->m[0] = v->m[0];
     m->m[1] = v->m[1];
@@ -247,7 +253,7 @@
     m->m[15] = 1.f;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix2x2 *v) {
     m->m[0] = v->m[0];
     m->m[1] = v->m[1];
@@ -267,7 +273,7 @@
     m->m[15] = 1.f;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix3x3 *m, const rs_matrix3x3 *v) {
     m->m[0] = v->m[0];
     m->m[1] = v->m[1];
@@ -280,7 +286,7 @@
     m->m[8] = v->m[8];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix2x2 *m, const rs_matrix2x2 *v) {
     m->m[0] = v->m[0];
     m->m[1] = v->m[1];
@@ -288,7 +294,7 @@
     m->m[3] = v->m[3];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) {
     float c, s;
     m->m[3] = 0;
@@ -327,7 +333,7 @@
     m->m[10] = z*z*nc +  c;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadScale(rs_matrix4x4 *m, float x, float y, float z) {
     rsMatrixLoadIdentity(m);
     m->m[0] = x;
@@ -335,7 +341,7 @@
     m->m[10] = z;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadTranslate(rs_matrix4x4 *m, float x, float y, float z) {
     rsMatrixLoadIdentity(m);
     m->m[12] = x;
@@ -343,7 +349,7 @@
     m->m[14] = z;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadMultiply(rs_matrix4x4 *m, const rs_matrix4x4 *lhs, const rs_matrix4x4 *rhs) {
     for (int i=0 ; i<4 ; i++) {
         float ri0 = 0;
@@ -364,14 +370,14 @@
     }
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix4x4 *m, const rs_matrix4x4 *rhs) {
     rs_matrix4x4 mt;
     rsMatrixLoadMultiply(&mt, m, rhs);
     rsMatrixLoad(m, &mt);
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadMultiply(rs_matrix3x3 *m, const rs_matrix3x3 *lhs, const rs_matrix3x3 *rhs) {
     for (int i=0 ; i<3 ; i++) {
         float ri0 = 0;
@@ -389,14 +395,14 @@
     }
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix3x3 *m, const rs_matrix3x3 *rhs) {
     rs_matrix3x3 mt;
     rsMatrixLoadMultiply(&mt, m, rhs);
     rsMatrixLoad(m, &mt);
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadMultiply(rs_matrix2x2 *m, const rs_matrix2x2 *lhs, const rs_matrix2x2 *rhs) {
     for (int i=0 ; i<2 ; i++) {
         float ri0 = 0;
@@ -411,35 +417,35 @@
     }
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix2x2 *m, const rs_matrix2x2 *rhs) {
     rs_matrix2x2 mt;
     rsMatrixLoadMultiply(&mt, m, rhs);
     rsMatrixLoad(m, &mt);
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) {
     rs_matrix4x4 m1;
     rsMatrixLoadRotate(&m1, rot, x, y, z);
     rsMatrixMultiply(m, &m1);
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixScale(rs_matrix4x4 *m, float x, float y, float z) {
     rs_matrix4x4 m1;
     rsMatrixLoadScale(&m1, x, y, z);
     rsMatrixMultiply(m, &m1);
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixTranslate(rs_matrix4x4 *m, float x, float y, float z) {
     rs_matrix4x4 m1;
     rsMatrixLoadTranslate(&m1, x, y, z);
     rsMatrixMultiply(m, &m1);
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadOrtho(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) {
     rsMatrixLoadIdentity(m);
     m->m[0] = 2.f / (right - left);
@@ -450,7 +456,7 @@
     m->m[14]= -(far + near) / (far - near);
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadFrustum(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) {
     rsMatrixLoadIdentity(m);
     m->m[0] = 2.f * near / (right - left);
@@ -463,7 +469,7 @@
     m->m[15]= 0.f;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadPerspective(rs_matrix4x4* m, float fovy, float aspect, float near, float far) {
     float top = near * tan((float) (fovy * M_PI / 360.0f));
     float bottom = -top;
@@ -472,7 +478,7 @@
     rsMatrixLoadFrustum(m, left, right, bottom, top, near, far);
 }
 
-static float4 __attribute__((overloadable))
+_RS_STATIC float4 __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix4x4 *m, float4 in) {
     float4 ret;
     ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + (m->m[8] * in.z) + (m->m[12] * in.w);
@@ -482,7 +488,7 @@
     return ret;
 }
 
-static float4 __attribute__((overloadable))
+_RS_STATIC float4 __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix4x4 *m, float3 in) {
     float4 ret;
     ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + (m->m[8] * in.z) + m->m[12];
@@ -492,7 +498,7 @@
     return ret;
 }
 
-static float4 __attribute__((overloadable))
+_RS_STATIC float4 __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix4x4 *m, float2 in) {
     float4 ret;
     ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + m->m[12];
@@ -502,7 +508,7 @@
     return ret;
 }
 
-static float3 __attribute__((overloadable))
+_RS_STATIC float3 __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix3x3 *m, float3 in) {
     float3 ret;
     ret.x = (m->m[0] * in.x) + (m->m[3] * in.y) + (m->m[6] * in.z);
@@ -511,7 +517,7 @@
     return ret;
 }
 
-static float3 __attribute__((overloadable))
+_RS_STATIC float3 __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix3x3 *m, float2 in) {
     float3 ret;
     ret.x = (m->m[0] * in.x) + (m->m[3] * in.y);
@@ -520,7 +526,7 @@
     return ret;
 }
 
-static float2 __attribute__((overloadable))
+_RS_STATIC float2 __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix2x2 *m, float2 in) {
     float2 ret;
     ret.x = (m->m[0] * in.x) + (m->m[2] * in.y);
@@ -529,7 +535,7 @@
 }
 
 // Returns true if the matrix was successfully inversed
-static bool __attribute__((overloadable))
+_RS_STATIC bool __attribute__((overloadable))
 rsMatrixInverse(rs_matrix4x4 *m) {
     rs_matrix4x4 result;
 
@@ -571,7 +577,7 @@
 }
 
 // Returns true if the matrix was successfully inversed
-static bool __attribute__((overloadable))
+_RS_STATIC bool __attribute__((overloadable))
 rsMatrixInverseTranspose(rs_matrix4x4 *m) {
     rs_matrix4x4 result;
 
@@ -612,7 +618,7 @@
     return true;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixTranspose(rs_matrix4x4 *m) {
     int i, j;
     float temp;
@@ -625,7 +631,7 @@
     }
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixTranspose(rs_matrix3x3 *m) {
     int i, j;
     float temp;
@@ -638,7 +644,7 @@
     }
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixTranspose(rs_matrix2x2 *m) {
     float temp = m->m[1];
     m->m[1] = m->m[2];
@@ -649,7 +655,7 @@
 // quaternion ops
 /////////////////////////////////////////////////////
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsQuaternionSet(rs_quaternion *q, float w, float x, float y, float z) {
     q->w = w;
     q->x = x;
@@ -657,7 +663,7 @@
     q->z = z;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsQuaternionSet(rs_quaternion *q, const rs_quaternion *rhs) {
     q->w = rhs->w;
     q->x = rhs->x;
@@ -665,7 +671,7 @@
     q->z = rhs->z;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsQuaternionMultiply(rs_quaternion *q, float s) {
     q->w *= s;
     q->x *= s;
@@ -673,7 +679,7 @@
     q->z *= s;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsQuaternionMultiply(rs_quaternion *q, const rs_quaternion *rhs) {
     q->w = -q->x*rhs->x - q->y*rhs->y - q->z*rhs->z + q->w*rhs->w;
     q->x =  q->x*rhs->w + q->y*rhs->z - q->z*rhs->y + q->w*rhs->x;
@@ -681,7 +687,7 @@
     q->z =  q->x*rhs->y - q->y*rhs->x + q->z*rhs->w + q->w*rhs->z;
 }
 
-static void
+_RS_STATIC void
 rsQuaternionAdd(rs_quaternion *q, const rs_quaternion *rhs) {
     q->w *= rhs->w;
     q->x *= rhs->x;
@@ -689,7 +695,7 @@
     q->z *= rhs->z;
 }
 
-static void
+_RS_STATIC void
 rsQuaternionLoadRotateUnit(rs_quaternion *q, float rot, float x, float y, float z) {
     rot *= (float)(M_PI / 180.0f) * 0.5f;
     float c = cos(rot);
@@ -701,7 +707,7 @@
     q->z = z * s;
 }
 
-static void
+_RS_STATIC void
 rsQuaternionLoadRotate(rs_quaternion *q, float rot, float x, float y, float z) {
     const float len = x*x + y*y + z*z;
     if (len != 1) {
@@ -713,19 +719,19 @@
     rsQuaternionLoadRotateUnit(q, rot, x, y, z);
 }
 
-static void
+_RS_STATIC void
 rsQuaternionConjugate(rs_quaternion *q) {
     q->x = -q->x;
     q->y = -q->y;
     q->z = -q->z;
 }
 
-static float
+_RS_STATIC float
 rsQuaternionDot(const rs_quaternion *q0, const rs_quaternion *q1) {
     return q0->w*q1->w + q0->x*q1->x + q0->y*q1->y + q0->z*q1->z;
 }
 
-static void
+_RS_STATIC void
 rsQuaternionNormalize(rs_quaternion *q) {
     const float len = rsQuaternionDot(q, q);
     if (len != 1) {
@@ -734,7 +740,7 @@
     }
 }
 
-static void
+_RS_STATIC void
 rsQuaternionSlerp(rs_quaternion *q, const rs_quaternion *q0, const rs_quaternion *q1, float t) {
     if (t <= 0.0f) {
         rsQuaternionSet(q, q0);
@@ -776,7 +782,7 @@
                         tempq0.y*scale + tempq1.y*invScale, tempq0.z*scale + tempq1.z*invScale);
 }
 
-static void rsQuaternionGetMatrixUnit(rs_matrix4x4 *m, const rs_quaternion *q) {
+_RS_STATIC void rsQuaternionGetMatrixUnit(rs_matrix4x4 *m, const rs_quaternion *q) {
     float x2 = 2.0f * q->x * q->x;
     float y2 = 2.0f * q->y * q->y;
     float z2 = 2.0f * q->z * q->z;
@@ -811,7 +817,7 @@
 /////////////////////////////////////////////////////
 // utility funcs
 /////////////////////////////////////////////////////
-__inline__ static void __attribute__((overloadable, always_inline))
+__inline__ _RS_STATIC void __attribute__((overloadable, always_inline))
 rsExtractFrustumPlanes(const rs_matrix4x4 *modelViewProj,
                          float4 *left, float4 *right,
                          float4 *top, float4 *bottom,
@@ -861,7 +867,7 @@
     *far /= len;
 }
 
-__inline__ static bool __attribute__((overloadable, always_inline))
+__inline__ _RS_STATIC bool __attribute__((overloadable, always_inline))
 rsIsSphereInFrustum(float4 *sphere,
                       float4 *left, float4 *right,
                       float4 *top, float4 *bottom,
@@ -899,26 +905,26 @@
 // int ops
 /////////////////////////////////////////////////////
 
-__inline__ static uint __attribute__((overloadable, always_inline)) rsClamp(uint amount, uint low, uint high) {
+__inline__ _RS_STATIC uint __attribute__((overloadable, always_inline)) rsClamp(uint amount, uint low, uint high) {
     return amount < low ? low : (amount > high ? high : amount);
 }
-__inline__ static int __attribute__((overloadable, always_inline)) rsClamp(int amount, int low, int high) {
+__inline__ _RS_STATIC int __attribute__((overloadable, always_inline)) rsClamp(int amount, int low, int high) {
     return amount < low ? low : (amount > high ? high : amount);
 }
-__inline__ static ushort __attribute__((overloadable, always_inline)) rsClamp(ushort amount, ushort low, ushort high) {
+__inline__ _RS_STATIC ushort __attribute__((overloadable, always_inline)) rsClamp(ushort amount, ushort low, ushort high) {
     return amount < low ? low : (amount > high ? high : amount);
 }
-__inline__ static short __attribute__((overloadable, always_inline)) rsClamp(short amount, short low, short high) {
+__inline__ _RS_STATIC short __attribute__((overloadable, always_inline)) rsClamp(short amount, short low, short high) {
     return amount < low ? low : (amount > high ? high : amount);
 }
-__inline__ static uchar __attribute__((overloadable, always_inline)) rsClamp(uchar amount, uchar low, uchar high) {
+__inline__ _RS_STATIC uchar __attribute__((overloadable, always_inline)) rsClamp(uchar amount, uchar low, uchar high) {
     return amount < low ? low : (amount > high ? high : amount);
 }
-__inline__ static char __attribute__((overloadable, always_inline)) rsClamp(char amount, char low, char high) {
+__inline__ _RS_STATIC char __attribute__((overloadable, always_inline)) rsClamp(char amount, char low, char high) {
     return amount < low ? low : (amount > high ? high : amount);
 }
 
-
+#undef _RS_STATIC
 
 #endif
 
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index 212eb83..0f8717f 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -1,6 +1,14 @@
 #ifndef __RS_TYPES_RSH__
 #define __RS_TYPES_RSH__
 
+#define M_PI        3.14159265358979323846264338327950288f   /* pi */
+
+//#include "external/clang/lib/Headers/stdbool.h"
+#define bool _Bool
+#define true 1
+#define false 0
+#define __bool_true_false_are_defined 1
+
 typedef char int8_t;
 typedef short int16_t;
 typedef int int32_t;
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index 3b2ef84..af11f97 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -261,8 +261,7 @@
     // NOTE: if stack.head is messed up, we could crash the client
     // or cause some drawing artifacts. This is okay, as long as it is
     // limited to the client.
-    return (buf != stack.index[stack.head] ||
-            (stack.queued > 0 && stack.inUse != buf));
+    return (buf != stack.index[stack.head]);
 }
 
 SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition(
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 6a79384..e404b05 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -109,6 +109,7 @@
     private static final int MSG_MEDIA_SERVER_STARTED = 6;
     private static final int MSG_PLAY_SOUND_EFFECT = 7;
     private static final int MSG_BTA2DP_DOCK_TIMEOUT = 8;
+    private static final int MSG_LOAD_SOUND_EFFECTS = 9;
 
     private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
 
@@ -930,6 +931,7 @@
              * this indicates we have a valid sample loaded for this effect.
              */
 
+            int lastSample = 0;
             for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
                 // Do not load sample if this effect uses the MediaPlayer
                 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
@@ -940,23 +942,32 @@
                             + SOUND_EFFECTS_PATH
                             + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]];
                     int sampleId = mSoundPool.load(filePath, 0);
-                    SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
-                    poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
                     if (sampleId <= 0) {
                         Log.w(TAG, "Soundpool could not load file: "+filePath);
+                    } else {
+                        SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
+                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
+                        lastSample = sampleId;
                     }
-                    mSoundPoolCallBack.setLastSample(sampleId);
                 } else {
                     SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
                 }
             }
             // wait for all samples to be loaded
-            try {
-                mSoundEffectsLock.wait();
-                status = mSoundPoolCallBack.status();
-            } catch (java.lang.InterruptedException e) {
+            if (lastSample != 0) {
+                mSoundPoolCallBack.setLastSample(lastSample);
+
+                try {
+                    mSoundEffectsLock.wait();
+                    status = mSoundPoolCallBack.status();
+                } catch (java.lang.InterruptedException e) {
+                    Log.w(TAG, "Interrupted while waiting sound pool callback.");
+                    status = -1;
+                }
+            } else {
                 status = -1;
             }
+
             if (mSoundPoolLooper != null) {
                 mSoundPoolLooper.quit();
                 mSoundPoolLooper = null;
@@ -965,8 +976,14 @@
             if (status != 0) {
                 Log.w(TAG,
                         "loadSoundEffects(), Error "
-                                + mSoundPoolCallBack.status()
+                                + ((lastSample != 0) ? mSoundPoolCallBack.status() : -1)
                                 + " while loading samples");
+                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
+                    if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
+                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
+                    }
+                }
+
                 mSoundPool.release();
                 mSoundPool = null;
             }
@@ -985,6 +1002,7 @@
                 return;
             }
 
+            mAudioHandler.removeMessages(MSG_LOAD_SOUND_EFFECTS);
             mAudioHandler.removeMessages(MSG_PLAY_SOUND_EFFECT);
 
             int[] poolId = new int[SOUND_EFFECT_FILES.length];
@@ -1049,7 +1067,6 @@
                     mStatus = status;
                 }
                 if (sampleId == mLastSample) {
-                    Log.e(TAG, "onLoadComplete last sample loaded");
                     mSoundEffectsLock.notify();
                 }
             }
@@ -1918,6 +1935,10 @@
                     AudioSystem.setParameters("restarting=false");
                     break;
 
+                case MSG_LOAD_SOUND_EFFECTS:
+                    loadSoundEffects();
+                    break;
+
                 case MSG_PLAY_SOUND_EFFECT:
                     playSoundEffect(msg.arg1, msg.arg2);
                     break;
@@ -2245,7 +2266,8 @@
                 }
             } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
                 mBootCompleted = true;
-                loadSoundEffects();
+                sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SHARED_MSG, SENDMSG_NOOP,
+                        0, 0, null, 0);
                 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
                 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
                         AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 8929393..33c6385 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1177,7 +1177,8 @@
             long lastModifiedSeconds = file.lastModified() / 1000;
 
             // always scan the file, so we can return the content://media Uri for existing files
-            return mClient.doScanFile(path, mimeType, lastModifiedSeconds, file.length(),false, true);
+            return mClient.doScanFile(path, mimeType, lastModifiedSeconds, file.length(),
+                    false, true);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
             return null;
@@ -1185,17 +1186,30 @@
     }
 
     public void scanMtpFile(String path, String volumeName, int objectHandle, int format) {
+        initialize(volumeName);
         MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
         int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
+        File file = new File(path);
+        long lastModifiedSeconds = file.lastModified() / 1000;
 
         if (!MediaFile.isAudioFileType(fileType) && !MediaFile.isVideoFileType(fileType) &&
             !MediaFile.isImageFileType(fileType) && !MediaFile.isPlayListFileType(fileType)) {
-            // nothing to do
+
+            // no need to use the media scanner, but we need to update last modified and file size
+            ContentValues values = new ContentValues();
+            values.put(Files.FileColumns.SIZE, file.length());
+            values.put(Files.FileColumns.DATE_MODIFIED, lastModifiedSeconds);
+            try {
+                String[] whereArgs = new String[] {  Integer.toString(objectHandle) };
+                mMediaProvider.update(Files.getMtpObjectsUri(volumeName), values, "_id=?",
+                        whereArgs);
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException in scanMtpFile", e);
+            }
             return;
         }
 
         mMtpObjectHandle = objectHandle;
-        initialize(volumeName);
         try {
             if (MediaFile.isPlayListFileType(fileType)) {
                 // build file cache so we can look up tracks in the playlist
@@ -1213,11 +1227,6 @@
                 // MTP will create a file entry for us so we don't want to do it in prescan
                 prescan(path, false);
 
-                File file = new File(path);
-
-                // lastModified is in milliseconds on Files.
-                long lastModifiedSeconds = file.lastModified() / 1000;
-
                 // always scan the file, so we can return the content://media Uri for existing files
                 mClient.doScanFile(path, mediaFileType.mimeType, lastModifiedSeconds, file.length(),
                     (format == MtpConstants.FORMAT_ASSOCIATION), true);
@@ -1453,22 +1462,29 @@
         if (lastSlash < 0) throw new IllegalArgumentException("bad path " + path);
         Uri uri, membersUri;
         long rowId = entry.mRowId;
-        if (rowId == 0) {
-            // Create a new playlist
 
-            int lastDot = path.lastIndexOf('.');
-            String name = (lastDot < 0 ? path.substring(lastSlash + 1) : path.substring(lastSlash + 1, lastDot));
-            values.put(MediaStore.Audio.Playlists.NAME, name);
+        // make sure we have a name
+        String name = values.getAsString(MediaStore.Audio.Playlists.NAME);
+        if (name == null) {
+            name = values.getAsString(MediaStore.MediaColumns.TITLE);
+            if (name == null) {
+                // extract name from file name
+                int lastDot = path.lastIndexOf('.');
+                name = (lastDot < 0 ? path.substring(lastSlash + 1)
+                        : path.substring(lastSlash + 1, lastDot));
+            }
+        }
+
+        values.put(MediaStore.Audio.Playlists.NAME, name);
+        values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified);
+
+        if (rowId == 0) {
             values.put(MediaStore.Audio.Playlists.DATA, path);
-            values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified);
             uri = mMediaProvider.insert(mPlaylistsUri, values);
             rowId = ContentUris.parseId(uri);
             membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
         } else {
             uri = ContentUris.withAppendedId(mPlaylistsUri, rowId);
-
-            // update lastModified value of existing playlist
-            values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified);
             mMediaProvider.update(uri, values, null, null);
 
             // delete members of existing playlist
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 3e54627..d3e9a49 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -150,7 +150,7 @@
      */
     public static final int ERROR = -1;
     /**
-     * Internal opreation status. Not returned by any method.
+     * Internal operation status. Not returned by any method.
      */
     public static final int ALREADY_EXISTS = -2;
     /**
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index 41309dc..bcf7b89 100755
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -95,7 +95,7 @@
      */
     public  static final int ERROR                = -1;
     /**
-     * Internal opreation status. Not returned by any method.
+     * Internal operation status. Not returned by any method.
      */
     public  static final int ALREADY_EXISTS       = -2;
     /**
diff --git a/media/java/android/media/videoeditor/AudioTrack.java b/media/java/android/media/videoeditor/AudioTrack.java
index e95ef35..9e68a5d 100755
--- a/media/java/android/media/videoeditor/AudioTrack.java
+++ b/media/java/android/media/videoeditor/AudioTrack.java
@@ -1,481 +1,647 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-import java.io.IOException;

-import java.lang.ref.SoftReference;

-

-/**

- * This class allows to handle an audio track. This audio file is mixed with the

- * audio samples of the media items.

- * {@hide}

- */

-public class AudioTrack {

-    // Instance variables

-    private final String mUniqueId;

-    private final String mFilename;

-    private long mStartTimeMs;

-    private long mTimelineDurationMs;

-    private int mVolumePercent;

-    private long mBeginBoundaryTimeMs;

-    private long mEndBoundaryTimeMs;

-    private boolean mLoop;

-    private boolean mMuted;

-

-    private final long mDurationMs;

-    private final int mAudioChannels;

-    private final int mAudioType;

-    private final int mAudioBitrate;

-    private final int mAudioSamplingFrequency;

-

-    // Ducking variables

-    private int mDuckingThreshold;

-    private int mDuckedTrackVolume;

-    private boolean mIsDuckingEnabled;

-

-    // The audio waveform filename

-    private String mAudioWaveformFilename;

-    // The audio waveform data

-    private SoftReference<WaveformData> mWaveformData;

-

-    /**

-     * An object of this type cannot be instantiated by using the default

-     * constructor

-     */

-    @SuppressWarnings("unused")

-    private AudioTrack() throws IOException {

-        this(null, null, null);

-    }

-

-    /**

-     * Constructor

-     *

-     * @param editor The video editor reference

-     * @param audioTrackId The audio track id

-     * @param filename The absolute file name

-     *

-     * @throws IOException if file is not found

-     * @throws IllegalArgumentException if file format is not supported or if

-     *             the codec is not supported

-     */

-    public AudioTrack(VideoEditor editor, String audioTrackId, String filename)

-            throws IOException {

-        mUniqueId = audioTrackId;

-        mFilename = filename;

-        mStartTimeMs = 0;

-        // TODO: This value represents to the duration of the audio file

-        mDurationMs = 300000;

-        // TODO: This value needs to be read from the audio track of the source

-        // file

-        mAudioChannels = 2;

-        mAudioType = MediaProperties.ACODEC_AAC_LC;

-        mAudioBitrate = 128000;

-        mAudioSamplingFrequency = 44100;

-

-        mTimelineDurationMs = mDurationMs;

-        mVolumePercent = 100;

-

-        // Play the entire audio track

-        mBeginBoundaryTimeMs = 0;

-        mEndBoundaryTimeMs = mDurationMs;

-

-        // By default loop is disabled

-        mLoop = false;

-

-        // By default the audio track is not muted

-        mMuted = false;

-

-        // Ducking is enabled by default

-        mDuckingThreshold = 0;

-        mDuckedTrackVolume = 0;

-        mIsDuckingEnabled = false;

-

-        // The audio waveform file is generated later

-        mAudioWaveformFilename = null;

-        mWaveformData = null;

-    }

-

-    /**

-     * Constructor

-     *

-     * @param editor The video editor reference

-     * @param audioTrackId The audio track id

-     * @param filename The audio filename

-     * @param startTimeMs the start time in milliseconds (relative to the

-     *              timeline)

-     * @param beginMs start time in the audio track in milliseconds (relative to

-     *            the beginning of the audio track)

-     * @param endMs end time in the audio track in milliseconds (relative to the

-     *            beginning of the audio track)

-     * @param loop true to loop the audio track

-     * @param volume The volume in percentage

-     * @param muted true if the audio track is muted

-     * @param threshold Ducking will be activated when the relative energy in

-     *      the media items audio signal goes above this value. The valid

-     *      range of values is 0 to 100.

-     * @param duckedTrackVolume The relative volume of the audio track when ducking

-     *      is active. The valid range of values is 0 to 100.

-     * @param audioWaveformFilename The name of the waveform file

-     *

-     * @throws IOException if file is not found

-     */

-    AudioTrack(VideoEditor editor, String audioTrackId, String filename, long startTimeMs,

-            long beginMs, long endMs, boolean loop, int volume, boolean muted,

-            boolean duckingEnabled, int duckThreshold, int duckedTrackVolume,

-            String audioWaveformFilename) throws IOException {

-        mUniqueId = audioTrackId;

-        mFilename = filename;

-        mStartTimeMs = startTimeMs;

-

-        // TODO: This value represents to the duration of the audio file

-        mDurationMs = 300000;

-

-        // TODO: This value needs to be read from the audio track of the source

-        // file

-        mAudioChannels = 2;

-        mAudioType = MediaProperties.ACODEC_AAC_LC;

-        mAudioBitrate = 128000;

-        mAudioSamplingFrequency = 44100;

-

-        mTimelineDurationMs = endMs - beginMs;

-        mVolumePercent = volume;

-

-        mBeginBoundaryTimeMs = beginMs;

-        mEndBoundaryTimeMs = endMs;

-

-        mLoop = loop;

-        mMuted = muted;

-

-        mIsDuckingEnabled = duckingEnabled;

-        mDuckingThreshold = duckThreshold;

-        mDuckedTrackVolume = duckedTrackVolume;

-

-        mAudioWaveformFilename = audioWaveformFilename;

-        if (audioWaveformFilename != null) {

-            mWaveformData =

-                new SoftReference<WaveformData>(new WaveformData(audioWaveformFilename));

-        } else {

-            mWaveformData = null;

-        }

-    }

-

-    /**

-     * @return The id of the audio track

-     */

-    public String getId() {

-        return mUniqueId;

-    }

-

-    /**

-     * Get the filename source for this audio track.

-     *

-     * @return The filename as an absolute file name

-     */

-    public String getFilename() {

-        return mFilename;

-    }

-

-    /**

-     * @return The number of audio channels in the source of this audio track

-     */

-    public int getAudioChannels() {

-        return mAudioChannels;

-    }

-

-    /**

-     * @return The audio codec of the source of this audio track

-     */

-    public int getAudioType() {

-        return mAudioType;

-    }

-

-    /**

-     * @return The audio sample frequency of the audio track

-     */

-    public int getAudioSamplingFrequency() {

-        return mAudioSamplingFrequency;

-    }

-

-    /**

-     * @return The audio bitrate of the audio track

-     */

-    public int getAudioBitrate() {

-        return mAudioBitrate;

-    }

-

-    /**

-     * Set the volume of this audio track as percentage of the volume in the

-     * original audio source file.

-     *

-     * @param volumePercent Percentage of the volume to apply. If it is set to

-     *            0, then volume becomes mute. It it is set to 100, then volume

-     *            is same as original volume. It it is set to 200, then volume

-     *            is doubled (provided that volume amplification is supported)

-     *

-     * @throws UnsupportedOperationException if volume amplification is

-     *             requested and is not supported.

-     */

-    public void setVolume(int volumePercent) {

-        mVolumePercent = volumePercent;

-    }

-

-    /**

-     * Get the volume of the audio track as percentage of the volume in the

-     * original audio source file.

-     *

-     * @return The volume in percentage

-     */

-    public int getVolume() {

-        return mVolumePercent;

-    }

-

-    /**

-     * @param muted true to mute the audio track

-     */

-    public void setMute(boolean muted) {

-        mMuted = muted;

-    }

-

-    /**

-     * @return true if the audio track is muted

-     */

-    public boolean isMuted() {

-        return mMuted;

-    }

-

-    /**

-     * Set the start time of this audio track relative to the storyboard

-     * timeline. Default value is 0.

-     *

-     * @param startTimeMs the start time in milliseconds

-     */

-    public void setStartTime(long startTimeMs) {

-        mStartTimeMs = startTimeMs;

-    }

-

-    /**

-     * Get the start time of this audio track relative to the storyboard

-     * timeline.

-     *

-     * @return The start time in milliseconds

-     */

-    public long getStartTime() {

-        return mStartTimeMs;

-    }

-

-    /**

-     * @return The duration in milliseconds. This value represents the audio

-     *         track duration (not looped)

-     */

-    public long getDuration() {

-        return mDurationMs;

-    }

-

-    /**

-     * @return The timeline duration as defined by the begin and end boundaries

-     */

-    public long getTimelineDuration() {

-        return mTimelineDurationMs;

-    }

-

-    /**

-     * Sets the start and end marks for trimming an audio track

-     *

-     * @param beginMs start time in the audio track in milliseconds (relative to

-     *            the beginning of the audio track)

-     * @param endMs end time in the audio track in milliseconds (relative to the

-     *            beginning of the audio track)

-     */

-    public void setExtractBoundaries(long beginMs, long endMs) {

-        if (beginMs > mDurationMs) {

-            throw new IllegalArgumentException("Invalid start time");

-        }

-        if (endMs > mDurationMs) {

-            throw new IllegalArgumentException("Invalid end time");

-        }

-

-        mBeginBoundaryTimeMs = beginMs;

-        mEndBoundaryTimeMs = endMs;

-

-        mTimelineDurationMs = mEndBoundaryTimeMs - mBeginBoundaryTimeMs;

-    }

-

-    /**

-     * @return The boundary begin time

-     */

-    public long getBoundaryBeginTime() {

-        return mBeginBoundaryTimeMs;

-    }

-

-    /**

-     * @return The boundary end time

-     */

-    public long getBoundaryEndTime() {

-        return mEndBoundaryTimeMs;

-    }

-

-    /**

-     * Enable the loop mode for this audio track. Note that only one of the

-     * audio tracks in the timeline can have the loop mode enabled. When looping

-     * is enabled the samples between mBeginBoundaryTimeMs and

-     * mEndBoundaryTimeMs are looped.

-     */

-    public void enableLoop() {

-        mLoop = true;

-    }

-

-    /**

-     * Disable the loop mode

-     */

-    public void disableLoop() {

-        mLoop = false;

-    }

-

-    /**

-     * @return true if looping is enabled

-     */

-    public boolean isLooping() {

-        return mLoop;

-    }

-

-    /**

-     * Disable the audio duck effect

-     */

-    public void disableDucking() {

-        mIsDuckingEnabled = false;

-    }

-

-    /**

-     * Enable ducking by specifying the required parameters

-     *

-     * @param threshold Ducking will be activated when the energy in

-     *      the media items audio signal goes above this value. The valid

-     *      range of values is 0db to 90dB. 0dB is equivalent to disabling

-     *      ducking.

-     * @param duckedTrackVolume The relative volume of the audio track when ducking

-     *      is active. The valid range of values is 0 to 100.

-     */

-    public void enableDucking(int threshold, int duckedTrackVolume) {

-        if (threshold < 0 || threshold > 90) {

-            throw new IllegalArgumentException("Invalid threshold value: " + threshold);

-        }

-

-        if (duckedTrackVolume < 0 || duckedTrackVolume > 100) {

-            throw new IllegalArgumentException("Invalid duckedTrackVolume value: "

-                    + duckedTrackVolume);

-        }

-

-        mDuckingThreshold = threshold;

-        mDuckedTrackVolume = duckedTrackVolume;

-        mIsDuckingEnabled = true;

-    }

-

-    /**

-     * @return true if ducking is enabled

-     */

-    public boolean isDuckingEnabled() {

-        return mIsDuckingEnabled;

-    }

-

-    /**

-     * @return The ducking threshold

-     */

-    public int getDuckingThreshhold() {

-        return mDuckingThreshold;

-    }

-

-    /**

-     * @return The ducked track volume

-     */

-    public int getDuckedTrackVolume() {

-        return mDuckedTrackVolume;

-    }

-

-    /**

-     * This API allows to generate a file containing the sample volume levels of

-     * this audio track object. This function may take significant time and is

-     * blocking. The filename can be retrieved using getAudioWaveformFilename().

-     *

-     * @param listener The progress listener

-     *

-     * @throws IOException if the output file cannot be created

-     * @throws IllegalArgumentException if the audio file does not have a valid

-     *             audio track

-     */

-    public void extractAudioWaveform(ExtractAudioWaveformProgressListener listener)

-            throws IOException {

-        // TODO: Set mAudioWaveformFilename at the end once the extract is

-        // complete

-        mWaveformData = new SoftReference<WaveformData>(new WaveformData(mAudioWaveformFilename));

-    }

-

-    /**

-     * Get the audio waveform file name if extractAudioWaveform was successful.

-     * The file format is as following:

-     * <ul>

-     * <li>first 4 bytes provide the number of samples for each value, as

-     * big-endian signed</li>

-     * <li>4 following bytes is the total number of values in the file, as

-     * big-endian signed</li>

-     * <li>then, all values follow as bytes</li>

-     * </ul>

-     *

-     * @return the name of the file, null if the file does not exist

-     */

-    String getAudioWaveformFilename() {

-        return mAudioWaveformFilename;

-    }

-

-    /**

-     * @return The waveform data

-     */

-    public WaveformData getWaveformData() throws IOException {

-        if (mWaveformData == null) {

-            return null;

-        }

-

-        WaveformData waveformData = mWaveformData.get();

-        if (waveformData != null) {

-            return waveformData;

-        } else if (mAudioWaveformFilename != null) {

-            waveformData = new WaveformData(mAudioWaveformFilename);

-            mWaveformData = new SoftReference<WaveformData>(waveformData);

-            return waveformData;

-        } else {

-            return null;

-        }

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public boolean equals(Object object) {

-        if (!(object instanceof AudioTrack)) {

-            return false;

-        }

-        return mUniqueId.equals(((AudioTrack)object).mUniqueId);

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public int hashCode() {

-        return mUniqueId.hashCode();

-    }

-}

+/*
+ * 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.
+ */
+
+
+package android.media.videoeditor;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.ref.SoftReference;
+
+import android.media.videoeditor.MediaArtistNativeHelper.Properties;
+
+/**
+ * This class allows to handle an audio track. This audio file is mixed with the
+ * audio samples of the media items.
+ * {@hide}
+ */
+public class AudioTrack {
+
+    /**
+     *  Instance variables
+     *  Private object for calling native methods via MediaArtistNativeHelper
+     */
+    private final MediaArtistNativeHelper mMANativeHelper;
+    private final String mUniqueId;
+    private final String mFilename;
+    private long mStartTimeMs;
+    private long mTimelineDurationMs;
+    private int mVolumePercent;
+    private long mBeginBoundaryTimeMs;
+    private long mEndBoundaryTimeMs;
+    private boolean mLoop;
+    private boolean mMuted;
+    private final long mDurationMs;
+    private final int mAudioChannels;
+    private final int mAudioType;
+    private final int mAudioBitrate;
+    private final int mAudioSamplingFrequency;
+
+    /**
+     *  Ducking variables
+     */
+    private int mDuckingThreshold;
+    private int mDuckedTrackVolume;
+    private boolean mIsDuckingEnabled;
+
+    /**
+     *  The audio waveform filename
+     */
+    private String mAudioWaveformFilename;
+
+    /**
+     *  The audio waveform data
+     */
+    private SoftReference<WaveformData> mWaveformData;
+
+    /**
+     * An object of this type cannot be instantiated by using the default
+     * constructor
+     */
+    @SuppressWarnings("unused")
+    private AudioTrack() throws IOException {
+        this(null, null, null);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param editor The video editor reference
+     * @param audioTrackId The audio track id
+     * @param filename The absolute file name
+     *
+     * @throws IOException if file is not found
+     * @throws IllegalArgumentException if file format is not supported or if
+     *         the codec is not supported or if editor is not of type
+     *         VideoEditorImpl.
+     */
+    public AudioTrack(VideoEditor editor, String audioTrackId, String filename) throws IOException {
+        this(editor, audioTrackId, filename, 0, 0, MediaItem.END_OF_FILE, false, 100, false, false,
+                0, 0, null);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param editor The video editor reference
+     * @param audioTrackId The audio track id
+     * @param filename The audio filename. In case file contains Audio and Video,
+     *         only the Audio stream will be used as Audio Track.
+     * @param startTimeMs the start time in milliseconds (relative to the
+     *         timeline)
+     * @param beginMs start time in the audio track in milliseconds (relative to
+     *         the beginning of the audio track)
+     * @param endMs end time in the audio track in milliseconds (relative to the
+     *         beginning of the audio track)
+     * @param loop true to loop the audio track
+     * @param volume The volume in percentage
+     * @param muted true if the audio track is muted
+     * @param threshold Ducking will be activated when the relative energy in
+     *         the media items audio signal goes above this value. The valid
+     *         range of values is 0 to 90.
+     * @param duckedTrackVolume The relative volume of the audio track when
+     *         ducking is active. The valid range of values is 0 to 100.
+     * @param audioWaveformFilename The name of the waveform file
+     *
+     * @throws IOException if file is not found
+     * @throws IllegalArgumentException if file format is not supported or if
+     *             the codec is not supported or if editor is not of type
+     *             VideoEditorImpl.
+     */
+    AudioTrack(VideoEditor editor, String audioTrackId, String filename,
+               long startTimeMs,long beginMs, long endMs, boolean loop,
+               int volume, boolean muted,boolean duckingEnabled,
+               int duckThreshold, int duckedTrackVolume,
+            String audioWaveformFilename) throws IOException {
+        Properties properties = null;
+        File file = new File(filename);
+        if (!file.exists()) {
+            throw new IOException(filename + " not found ! ");
+        }
+
+        if (editor instanceof VideoEditorImpl) {
+            mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
+        } else {
+            throw new IllegalArgumentException("editor is not of type VideoEditorImpl");
+        }
+        try {
+          properties = mMANativeHelper.getMediaProperties(filename);
+        } catch (Exception e) {
+            throw new IllegalArgumentException("Unsupported file or file not found");
+        }
+        switch (mMANativeHelper.getFileType(properties.fileType)) {
+            case MediaProperties.FILE_3GP:
+            case MediaProperties.FILE_MP4:
+            case MediaProperties.FILE_MP3:
+                break;
+
+            default: {
+                throw new IllegalArgumentException("Unsupported input file type");
+            }
+        }
+        switch (mMANativeHelper.getAudioCodecType(properties.audioFormat)) {
+            case MediaProperties.ACODEC_AMRNB:
+            case MediaProperties.ACODEC_AMRWB:
+            case MediaProperties.ACODEC_AAC_LC:
+            case MediaProperties.ACODEC_MP3:
+                break;
+            default:
+                throw new IllegalArgumentException("Unsupported Audio Codec Format in Input File");
+        }
+
+        if (endMs == MediaItem.END_OF_FILE) {
+            endMs = properties.audioDuration;
+        }
+
+        mUniqueId = audioTrackId;
+        mFilename = filename;
+        mStartTimeMs = startTimeMs;
+        mDurationMs = properties.audioDuration;
+        mAudioChannels = properties.audioChannels;
+        mAudioBitrate = properties.audioBitrate;
+        mAudioSamplingFrequency = properties.audioSamplingFrequency;
+        mAudioType = properties.audioFormat;
+        mTimelineDurationMs = endMs - beginMs;
+        mVolumePercent = volume;
+
+        mBeginBoundaryTimeMs = beginMs;
+        mEndBoundaryTimeMs = endMs;
+
+        mLoop = loop;
+        mMuted = muted;
+        mIsDuckingEnabled = duckingEnabled;
+        mDuckingThreshold = duckThreshold;
+        mDuckedTrackVolume = duckedTrackVolume;
+
+        mAudioWaveformFilename = audioWaveformFilename;
+        if (audioWaveformFilename != null) {
+            mWaveformData =
+                new SoftReference<WaveformData>(new WaveformData(audioWaveformFilename));
+        } else {
+            mWaveformData = null;
+        }
+    }
+
+    /**
+     * Get the id of the audio track
+     *
+     * @return The id of the audio track
+     */
+    public String getId() {
+        return mUniqueId;
+    }
+
+    /**
+     * Get the filename for this audio track source.
+     *
+     * @return The filename as an absolute file name
+     */
+    public String getFilename() {
+        return mFilename;
+    }
+
+    /**
+     * Get the number of audio channels in the source of this audio track
+     *
+     * @return The number of audio channels in the source of this audio track
+     */
+    public int getAudioChannels() {
+        return mAudioChannels;
+    }
+
+    /**
+     * Get the audio codec of the source of this audio track
+     *
+     * @return The audio codec of the source of this audio track
+     * {@link android.media.videoeditor.MediaProperties}
+     */
+    public int getAudioType() {
+        return mAudioType;
+    }
+
+    /**
+     * Get the audio sample frequency of the audio track
+     *
+     * @return The audio sample frequency of the audio track
+     */
+    public int getAudioSamplingFrequency() {
+        return mAudioSamplingFrequency;
+    }
+
+    /**
+     * Get the audio bitrate of the audio track
+     *
+     * @return The audio bitrate of the audio track
+     */
+    public int getAudioBitrate() {
+        return mAudioBitrate;
+    }
+
+    /**
+     * Set the volume of this audio track as percentage of the volume in the
+     * original audio source file.
+     *
+     * @param volumePercent Percentage of the volume to apply. If it is set to
+     *         0, then volume becomes mute. It it is set to 100, then volume
+     *         is same as original volume. It it is set to 200, then volume
+     *         is doubled (provided that volume amplification is supported)
+     *
+     * @throws UnsupportedOperationException if volume amplification is
+     *         requested and is not supported.
+     */
+    public void setVolume(int volumePercent) {
+        if (volumePercent > MediaProperties.AUDIO_MAX_VOLUME_PERCENT) {
+            throw new IllegalArgumentException("Volume set exceeds maximum allowed value");
+        }
+
+         if (volumePercent < 0) {
+            throw new IllegalArgumentException("Invalid Volume ");
+        }
+        mVolumePercent = volumePercent;
+        /**
+         *  Force update of preview settings
+         */
+        mMANativeHelper.setGeneratePreview(true);
+    }
+
+    /**
+     * Get the volume of the audio track as percentage of the volume in the
+     * original audio source file.
+     *
+     * @return The volume in percentage
+     */
+    public int getVolume() {
+        return mVolumePercent;
+    }
+
+    /**
+     * Mute/Unmute the audio track
+     *
+     * @param muted true to mute the audio track. SetMute(true) will make
+     *         the volume of this Audio Track to 0.
+     */
+    public void setMute(boolean muted) {
+        mMuted = muted;
+        /**
+         *  Force update of preview settings
+         */
+        mMANativeHelper.setGeneratePreview(true);
+    }
+
+    /**
+     * Check if the audio track is muted
+     *
+     * @return true if the audio track is muted
+     */
+    public boolean isMuted() {
+        return mMuted;
+    }
+
+    /**
+     * Get the start time of this audio track relative to the storyboard
+     * timeline.
+     *
+     * @return The start time in milliseconds
+     */
+
+    public long getStartTime() {
+        return mStartTimeMs;
+    }
+
+    /**
+     * Get the audio track duration
+     *
+     * @return The duration in milliseconds. This value represents actual audio
+     *         track duration. This value is not effected by 'enableLoop' or
+     *         'setExtractBoundaries'.
+     */
+    public long getDuration() {
+        return mDurationMs;
+    }
+
+    /**
+     * Get the audio track timeline duration
+     *
+     * @return The timeline duration as defined by the begin and end boundaries
+     */
+    public long getTimelineDuration() {
+        return mTimelineDurationMs;
+    }
+
+    /**
+     * Sets the start and end marks for trimming an audio track
+     *
+     * @param beginMs start time in the audio track in milliseconds (relative to
+     *         the beginning of the audio track)
+     * @param endMs end time in the audio track in milliseconds (relative to the
+     *         beginning of the audio track)
+     */
+    public void setExtractBoundaries(long beginMs, long endMs) {
+        if (beginMs > mDurationMs) {
+            throw new IllegalArgumentException("Invalid start time");
+        }
+        if (endMs > mDurationMs) {
+            throw new IllegalArgumentException("Invalid end time");
+        }
+        if (beginMs < 0) {
+            throw new IllegalArgumentException("Invalid start time; is < 0");
+        }
+        if (endMs < 0) {
+            throw new IllegalArgumentException("Invalid end time; is < 0");
+        }
+
+        mBeginBoundaryTimeMs = beginMs;
+        mEndBoundaryTimeMs = endMs;
+
+        mTimelineDurationMs = mEndBoundaryTimeMs - mBeginBoundaryTimeMs;
+        /**
+         *  Force update of preview settings
+         */
+        mMANativeHelper.setGeneratePreview(true);
+    }
+
+    /**
+     * Get the boundary begin time
+     *
+     * @return The boundary begin time
+     */
+    public long getBoundaryBeginTime() {
+        return mBeginBoundaryTimeMs;
+    }
+
+    /**
+     * Get the boundary end time
+     *
+     * @return The boundary end time
+     */
+    public long getBoundaryEndTime() {
+        return mEndBoundaryTimeMs;
+    }
+
+    /**
+     * Enable the loop mode for this audio track. Note that only one of the
+     * audio tracks in the timeline can have the loop mode enabled. When looping
+     * is enabled the samples between mBeginBoundaryTimeMs and
+     * mEndBoundaryTimeMs are looped.
+     */
+    public void enableLoop() {
+        if (!mLoop) {
+            mLoop = true;
+            /**
+             *  Force update of preview settings
+             */
+            mMANativeHelper.setGeneratePreview(true);
+        }
+    }
+
+    /**
+     * Disable the loop mode
+     */
+    public void disableLoop() {
+        if (mLoop) {
+            mLoop = false;
+            /**
+             *  Force update of preview settings
+             */
+            mMANativeHelper.setGeneratePreview(true);
+        }
+    }
+
+    /**
+     * Check if looping is enabled
+     *
+     * @return true if looping is enabled
+     */
+    public boolean isLooping() {
+        return mLoop;
+    }
+
+    /**
+     * Disable the audio duck effect
+     */
+    public void disableDucking() {
+        if (mIsDuckingEnabled) {
+            mIsDuckingEnabled = false;
+            /**
+             *  Force update of preview settings
+             */
+            mMANativeHelper.setGeneratePreview(true);
+        }
+    }
+
+    /**
+     * Enable ducking by specifying the required parameters
+     *
+     * @param threshold Ducking will be activated when the energy in
+     *         the media items audio signal goes above this value. The valid
+     *         range of values is 0db to 90dB. 0dB is equivalent to disabling
+     *         ducking.
+     * @param duckedTrackVolume The relative volume of the audio track when ducking
+     *         is active. The valid range of values is 0 to 100.
+     */
+    public void enableDucking(int threshold, int duckedTrackVolume) {
+        if (threshold < 0 || threshold > 90) {
+            throw new IllegalArgumentException("Invalid threshold value: " + threshold);
+        }
+
+        if (duckedTrackVolume < 0 || duckedTrackVolume > 100) {
+            throw new IllegalArgumentException("Invalid duckedTrackVolume value: "
+                    + duckedTrackVolume);
+        }
+
+        mDuckingThreshold = threshold;
+        mDuckedTrackVolume = duckedTrackVolume;
+        mIsDuckingEnabled = true;
+        /**
+         *  Force update of preview settings
+         */
+        mMANativeHelper.setGeneratePreview(true);
+    }
+
+    /**
+     * Check if ducking is enabled
+     *
+     * @return true if ducking is enabled
+     */
+    public boolean isDuckingEnabled() {
+        return mIsDuckingEnabled;
+    }
+
+    /**
+     * Get the ducking threshold.
+     *
+     * @return The ducking threshold
+     */
+    public int getDuckingThreshhold() {
+        return mDuckingThreshold;
+    }
+
+    /**
+     * Get the ducked track volume.
+     *
+     * @return The ducked track volume
+     */
+    public int getDuckedTrackVolume() {
+        return mDuckedTrackVolume;
+    }
+
+    /**
+     * This API allows to generate a file containing the sample volume levels of
+     * this audio track object. This function may take significant time and is
+     * blocking. The filename can be retrieved using getAudioWaveformFilename().
+     *
+     * @param listener The progress listener
+     *
+     * @throws IOException if the output file cannot be created
+     * @throws IllegalArgumentException if the audio file does not have a valid
+     *         audio track
+     * @throws IllegalStateException if the codec type is unsupported
+     */
+    public void extractAudioWaveform(ExtractAudioWaveformProgressListener listener)
+    throws IOException {
+        if (mAudioWaveformFilename == null) {
+            /**
+             *  AudioWaveformFilename is generated
+             */
+            final String projectPath = mMANativeHelper.getProjectPath();
+            final String audioWaveFilename = String.format(projectPath + "/audioWaveformFile-"
+                    + getId() + ".dat");
+
+            /**
+             * Logic to get frame duration = (no. of frames per sample * 1000)/
+             * sampling frequency
+             */
+            final int frameDuration;
+            final int sampleCount;
+            final int codecType = mMANativeHelper.getAudioCodecType(mAudioType);
+            switch (codecType) {
+                case MediaProperties.ACODEC_AMRNB: {
+                    frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRNB * 1000)
+                    / MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
+                    sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRNB;
+                    break;
+                }
+
+                case MediaProperties.ACODEC_AMRWB: {
+                    frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRWB * 1000)
+                    / MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
+                    sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRWB;
+                    break;
+                }
+
+                case MediaProperties.ACODEC_AAC_LC: {
+                    frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AAC * 1000)
+                    / MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
+                    sampleCount = MediaProperties.SAMPLES_PER_FRAME_AAC;
+                    break;
+                }
+
+                case MediaProperties.ACODEC_MP3: {
+                    frameDuration = (MediaProperties.SAMPLES_PER_FRAME_MP3 * 1000)
+                    / MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
+                    sampleCount = MediaProperties.SAMPLES_PER_FRAME_MP3;
+                    break;
+                }
+
+                default: {
+                    throw new IllegalStateException("Unsupported codec type: "
+                                                                   + codecType);
+                }
+            }
+
+            mMANativeHelper.generateAudioGraph( mUniqueId,
+                    mFilename,
+                    audioWaveFilename,
+                    frameDuration,
+                    MediaProperties.DEFAULT_CHANNEL_COUNT,
+                    sampleCount,
+                    listener,
+                    false);
+            /**
+             *  Record the generated file name
+             */
+            mAudioWaveformFilename = audioWaveFilename;
+        }
+        mWaveformData = new SoftReference<WaveformData>(new WaveformData(mAudioWaveformFilename));
+    }
+
+    /**
+     * Get the audio waveform file name if extractAudioWaveform was successful.
+     *
+     * @return the name of the file, null if the file does not exist
+     */
+    String getAudioWaveformFilename() {
+        return mAudioWaveformFilename;
+    }
+
+    /**
+     * Delete the waveform file
+     */
+    void invalidate() {
+        if (mAudioWaveformFilename != null) {
+            new File(mAudioWaveformFilename).delete();
+            mAudioWaveformFilename = null;
+            mWaveformData = null;
+        }
+    }
+
+    /**
+     * Get the audio waveform data.
+     *
+     * @return The waveform data
+     *
+     * @throws IOException if the waveform file cannot be found
+     */
+    public WaveformData getWaveformData() throws IOException {
+        if (mWaveformData == null) {
+            return null;
+        }
+
+        WaveformData waveformData = mWaveformData.get();
+        if (waveformData != null) {
+            return waveformData;
+        } else if (mAudioWaveformFilename != null) {
+            try {
+                waveformData = new WaveformData(mAudioWaveformFilename);
+            } catch (IOException e) {
+                throw e;
+            }
+            mWaveformData = new SoftReference<WaveformData>(waveformData);
+            return waveformData;
+        } else {
+            return null;
+        }
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (!(object instanceof AudioTrack)) {
+            return false;
+        }
+        return mUniqueId.equals(((AudioTrack)object).mUniqueId);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return mUniqueId.hashCode();
+    }
+}
diff --git a/media/java/android/media/videoeditor/Effect.java b/media/java/android/media/videoeditor/Effect.java
index 8fd0d27..3362d47 100755
--- a/media/java/android/media/videoeditor/Effect.java
+++ b/media/java/android/media/videoeditor/Effect.java
@@ -1,173 +1,197 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-/**

- * This is the super class for all effects. An effect can only be applied to a

- * single media item. If one wants to apply the same effect to multiple media

- * items, multiple @{MediaItem.addEffect(Effect)} call must be invoked on each

- * of the MediaItem objects.

- * {@hide}

- */

-public abstract class Effect {

-    // Instance variables

-    private final String mUniqueId;

-    // The effect owner

-    private final MediaItem mMediaItem;

-    protected long mDurationMs;

-    // The start time of the effect relative to the media item timeline

-    protected long mStartTimeMs;

-

-    /**

-     * Default constructor

-     */

-    @SuppressWarnings("unused")

-    private Effect() {

-        mMediaItem = null;

-        mUniqueId = null;

-        mStartTimeMs = 0;

-        mDurationMs = 0;

-    }

-

-    /**

-     * Constructor

-     *

-     * @param mediaItem The media item owner

-     * @param effectId The effect id

-     * @param startTimeMs The start time relative to the media item to which it

-     *            is applied

-     * @param durationMs The effect duration in milliseconds

-     */

-    public Effect(MediaItem mediaItem, String effectId, long startTimeMs, long durationMs) {

-        if (mediaItem == null) {

-            throw new IllegalArgumentException("Media item cannot be null");

-        }

-

-        if (startTimeMs + durationMs > mediaItem.getDuration()) {

-            throw new IllegalArgumentException("Invalid start time and duration");

-        }

-

-        mMediaItem = mediaItem;

-        mUniqueId = effectId;

-        mStartTimeMs = startTimeMs;

-        mDurationMs = durationMs;

-    }

-

-    /**

-     * @return The id of the effect

-     */

-    public String getId() {

-        return mUniqueId;

-    }

-

-    /**

-     * Set the duration of the effect. If a preview or export is in progress,

-     * then this change is effective for next preview or export session.

-     *

-     * @param durationMs of the effect in milliseconds

-     */

-    public void setDuration(long durationMs) {

-        if (mStartTimeMs + durationMs > mMediaItem.getDuration()) {

-            throw new IllegalArgumentException("Duration is too large");

-        }

-

-        final long oldDurationMs = mDurationMs;

-        mDurationMs = durationMs;

-

-        mMediaItem.invalidateTransitions(mStartTimeMs, oldDurationMs, mStartTimeMs, mDurationMs);

-    }

-

-    /**

-     * Get the duration of the effect

-     *

-     * @return The duration of the effect in milliseconds

-     */

-    public long getDuration() {

-        return mDurationMs;

-    }

-

-    /**

-     * Set start time of the effect. If a preview or export is in progress, then

-     * this change is effective for next preview or export session.

-     *

-     * @param startTimeMs The start time of the effect relative to the beginning

-     *            of the media item in milliseconds

-     */

-    public void setStartTime(long startTimeMs) {

-        if (startTimeMs + mDurationMs > mMediaItem.getDuration()) {

-            throw new IllegalArgumentException("Start time is too large");

-        }

-

-        final long oldStartTimeMs = mStartTimeMs;

-        mStartTimeMs = startTimeMs;

-

-        mMediaItem.invalidateTransitions(oldStartTimeMs, mDurationMs, mStartTimeMs, mDurationMs);

-    }

-

-    /**

-     * @return The start time in milliseconds

-     */

-    public long getStartTime() {

-        return mStartTimeMs;

-    }

-

-    /**

-     * Set the start time and duration

-     *

-     * @param startTimeMs start time in milliseconds

-     * @param durationMs The duration in milliseconds

-     */

-    public void setStartTimeAndDuration(long startTimeMs, long durationMs) {

-        if (startTimeMs + durationMs > mMediaItem.getDuration()) {

-            throw new IllegalArgumentException("Invalid start time or duration");

-        }

-

-        final long oldStartTimeMs = mStartTimeMs;

-        final long oldDurationMs = mDurationMs;

-

-        mStartTimeMs = startTimeMs;

-        mDurationMs = durationMs;

-

-        mMediaItem.invalidateTransitions(oldStartTimeMs, oldDurationMs, mStartTimeMs, mDurationMs);

-    }

-

-    /**

-     * @return The media item owner

-     */

-    public MediaItem getMediaItem() {

-        return mMediaItem;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public boolean equals(Object object) {

-        if (!(object instanceof Effect)) {

-            return false;

-        }

-        return mUniqueId.equals(((Effect)object).mUniqueId);

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public int hashCode() {

-        return mUniqueId.hashCode();

-    }

-}

+/*
+ * 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.
+ */
+
+
+package android.media.videoeditor;
+
+/**
+ * This is the super class for all effects. An effect can only be applied to a
+ * single media item.
+ * {@hide}
+ */
+public abstract class Effect {
+    /**
+     *  Instance variables
+     */
+    private final String mUniqueId;
+    /**
+     *  The effect owner
+     */
+    private final MediaItem mMediaItem;
+
+    protected long mDurationMs;
+    /**
+     *  The start time of the effect relative to the beginning
+     *  of the media item
+     */
+    protected long mStartTimeMs;
+
+    /**
+     * Default constructor
+     */
+    @SuppressWarnings("unused")
+    private Effect() {
+        mMediaItem = null;
+        mUniqueId = null;
+        mStartTimeMs = 0;
+        mDurationMs = 0;
+    }
+
+    /**
+     * Constructor
+     *
+     * @param mediaItem The media item owner
+     * @param effectId The effect id
+     * @param startTimeMs The start time relative to the media item to which it
+     *            is applied
+     * @param durationMs The effect duration in milliseconds
+     */
+    public Effect(MediaItem mediaItem, String effectId, long startTimeMs,
+                  long durationMs) {
+        if (mediaItem == null) {
+            throw new IllegalArgumentException("Media item cannot be null");
+        }
+
+        if ((startTimeMs < 0) || (durationMs < 0)) {
+             throw new IllegalArgumentException("Invalid start time Or/And Duration");
+        }
+        if (startTimeMs + durationMs > mediaItem.getDuration()) {
+            throw new IllegalArgumentException("Invalid start time and duration");
+        }
+
+        mMediaItem = mediaItem;
+        mUniqueId = effectId;
+        mStartTimeMs = startTimeMs;
+        mDurationMs = durationMs;
+    }
+
+    /**
+     * Get the id of the effect.
+     *
+     * @return The id of the effect
+     */
+    public String getId() {
+        return mUniqueId;
+    }
+
+    /**
+     * Set the duration of the effect. If a preview or export is in progress,
+     * then this change is effective for next preview or export session.
+     *
+     * @param durationMs of the effect in milliseconds
+     */
+    public void setDuration(long durationMs) {
+        if (durationMs <0) {
+            throw new IllegalArgumentException("Invalid duration");
+        }
+
+        if (mStartTimeMs + durationMs > mMediaItem.getDuration()) {
+            throw new IllegalArgumentException("Duration is too large");
+        }
+
+        final long oldDurationMs = mDurationMs;
+        mDurationMs = durationMs;
+
+        mMediaItem.invalidateTransitions(mStartTimeMs, oldDurationMs,
+                                         mStartTimeMs, mDurationMs);
+    }
+
+    /**
+     * Get the duration of the effect
+     *
+     * @return The duration of the effect in milliseconds
+     */
+    public long getDuration() {
+        return mDurationMs;
+    }
+
+    /**
+     * Set start time of the effect. If a preview or export is in progress, then
+     * this change is effective for next preview or export session.
+     *
+     * @param startTimeMs The start time of the effect relative to the beginning
+     *            of the media item in milliseconds
+     */
+    public void setStartTime(long startTimeMs) {
+        if (startTimeMs + mDurationMs > mMediaItem.getDuration()) {
+            throw new IllegalArgumentException("Start time is too large");
+        }
+
+        final long oldStartTimeMs = mStartTimeMs;
+        mStartTimeMs = startTimeMs;
+
+        mMediaItem.invalidateTransitions(oldStartTimeMs, mDurationMs,
+                                         mStartTimeMs, mDurationMs);
+    }
+
+    /**
+     * Get the start time of the effect
+     *
+     * @return The start time in milliseconds
+     */
+    public long getStartTime() {
+        return mStartTimeMs;
+    }
+
+    /**
+     * Set the start time and duration
+     *
+     * @param startTimeMs start time in milliseconds
+     * @param durationMs The duration in milliseconds
+     */
+    public void setStartTimeAndDuration(long startTimeMs, long durationMs) {
+        if (startTimeMs + durationMs > mMediaItem.getDuration()) {
+            throw new IllegalArgumentException("Invalid start time or duration");
+        }
+
+        final long oldStartTimeMs = mStartTimeMs;
+        final long oldDurationMs = mDurationMs;
+
+        mStartTimeMs = startTimeMs;
+        mDurationMs = durationMs;
+
+        mMediaItem.invalidateTransitions(oldStartTimeMs, oldDurationMs,
+                                         mStartTimeMs, mDurationMs);
+    }
+
+    /**
+     * Get the media item owner.
+     *
+     * @return The media item owner
+     */
+    public MediaItem getMediaItem() {
+        return mMediaItem;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (!(object instanceof Effect)) {
+            return false;
+        }
+        return mUniqueId.equals(((Effect)object).mUniqueId);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return mUniqueId.hashCode();
+    }
+}
diff --git a/media/java/android/media/videoeditor/EffectColor.java b/media/java/android/media/videoeditor/EffectColor.java
index ac48e37..6c5ac2d 100755
--- a/media/java/android/media/videoeditor/EffectColor.java
+++ b/media/java/android/media/videoeditor/EffectColor.java
@@ -1,119 +1,142 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-/**

- * This class allows to apply color on a media item.

- * {@hide}

- */

-public class EffectColor extends Effect {

-

-    /**

-     * Change the video frame color to the RGB color value provided

-     */

-    public static final int TYPE_COLOR = 1;

-    /**

-     * Change the video frame color to a gradation from RGB color (at the top of

-     * the frame) to black (at the bottom of the frame).

-     */

-    public static final int TYPE_GRADIENT = 2;

-    /**

-     * Change the video frame color to sepia

-     */

-    public static final int TYPE_SEPIA = 3;

-    /**

-     * Invert the video frame color

-     */

-    public static final int TYPE_NEGATIVE = 4;

-    /**

-     * Make the video look like as if it was recorded in 50's

-     */

-    public static final int TYPE_FIFTIES = 5;

-

-    // Predefined colors

-    public static final int GREEN = 0x0000ff00;

-    public static final int PINK = 0x00ff66cc;

-    public static final int GRAY = 0x007f7f7f;

-

-    // The effect type

-    private final int mType;

-

-    // The effect color

-    private final int mColor;

-

-    /**

-     * An object of this type cannot be instantiated by using the default

-     * constructor

-     */

-    @SuppressWarnings("unused")

-    private EffectColor() {

-        this(null, null, 0, 0, 0, 0);

-    }

-

-    /**

-     * Constructor

-     *

-     * @param mediaItem The media item owner

-     * @param effectId The effect id

-     * @param startTimeMs The start time relative to the media item to which it

-     *            is applied

-     * @param durationMs The duration of this effect in milliseconds

-     * @param type type of the effect. type is one of: TYPE_COLOR,

-     *            TYPE_GRADIENT, TYPE_SEPIA, TYPE_NEGATIVE, TYPE_FIFTIES.

-     * @param color If type is TYPE_COLOR, color is the RGB color as 888.

-     *              If type is TYPE_GRADIENT, color is the RGB color at the

-     *              top of the frame. Otherwise, color is ignored

-     */

-    public EffectColor(MediaItem mediaItem, String effectId, long startTimeMs, long durationMs,

-            int type, int color) {

-        super(mediaItem, effectId, startTimeMs, durationMs);

-        switch (type) {

-            case TYPE_COLOR:

-            case TYPE_GRADIENT: {

-                mColor = color;

-                break;

-            }

-

-            case TYPE_SEPIA:

-            case TYPE_NEGATIVE:

-            case TYPE_FIFTIES: {

-                mColor = -1;

-                break;

-            }

-

-            default: {

-                throw new IllegalArgumentException("Invalid type: " + type);

-            }

-        }

-

-        mType = type;

-    }

-

-    /**

-     * @return The effect type

-     */

-    public int getType() {

-        return mType;

-    }

-

-    /**

-     * @return the color as RGB 888 if type is TYPE_COLOR or TYPE_GRADIENT.

-     */

-    public int getColor() {

-        return mColor;

-    }

-}

+/*
+ * 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.
+ */
+
+
+package android.media.videoeditor;
+
+/**
+ * This class allows to apply color effect on a media item.
+ * {@hide}
+ */
+public class EffectColor extends Effect {
+
+    /**
+     * Change the video frame color to the RGB color value provided
+     */
+    public static final int TYPE_COLOR = 1;
+    /**
+     * Change the video frame color to a gradation from RGB color (at the top of
+     * the frame) to black (at the bottom of the frame).
+     */
+    public static final int TYPE_GRADIENT = 2;
+    /**
+     * Change the video frame color to sepia
+     */
+    public static final int TYPE_SEPIA = 3;
+    /**
+     * Invert the video frame color
+     */
+    public static final int TYPE_NEGATIVE = 4;
+    /**
+     * Make the video look like as if it was recorded in 50's
+     */
+    public static final int TYPE_FIFTIES = 5;
+    /**
+     * Change the video frame color to the RGB color value GREEN
+     */
+    public static final int GREEN = 0x0000ff00;
+    /**
+     * Change the video frame color to the RGB color value PINK
+     */
+    public static final int PINK = 0x00ff66cc;
+    /**
+     * Change the video frame color to the RGB color value GRAY
+     */
+    public static final int GRAY = 0x007f7f7f;
+
+    /**
+     *  The effect type
+     */
+    private final int mType;
+
+    /**
+     *  The effect color
+     */
+    private final int mColor;
+
+    /**
+     * An object of this type cannot be instantiated by using the default
+     * constructor
+     */
+    @SuppressWarnings("unused")
+    private EffectColor() {
+        this(null, null, 0, 0, 0, 0);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param mediaItem The media item owner
+     * @param effectId The effect id
+     * @param startTimeMs The start time relative to the media item to which it
+     *            is applied
+     * @param durationMs The duration of this effect in milliseconds
+     * @param type type of the effect. type is one of: TYPE_COLOR,
+     *            TYPE_GRADIENT, TYPE_SEPIA, TYPE_NEGATIVE, TYPE_FIFTIES.
+     * @param color If type is TYPE_COLOR, color is the RGB color as 888.
+     *              If type is TYPE_GRADIENT, color is the RGB color at the
+     *              top of the frame. Otherwise, color is ignored
+     */
+    public EffectColor(MediaItem mediaItem, String effectId, long startTimeMs,
+                      long durationMs, int type, int color) {
+        super(mediaItem, effectId, startTimeMs, durationMs);
+        switch (type) {
+            case TYPE_COLOR:
+            case TYPE_GRADIENT: {
+                switch (color) {
+                    case GREEN:
+                    case PINK:
+                    case GRAY:
+                        mColor = color;
+                        break;
+
+                    default:
+                        throw new IllegalArgumentException("Invalid Color: " + color);
+                    }
+                    break;
+            }
+            case TYPE_SEPIA:
+            case TYPE_NEGATIVE:
+            case TYPE_FIFTIES: {
+                mColor = -1;
+                break;
+            }
+
+            default: {
+                throw new IllegalArgumentException("Invalid type: " + type);
+            }
+        }
+        mType = type;
+    }
+
+    /**
+     * Get the effect type.
+     *
+     * @return The effect type
+     */
+    public int getType() {
+        return mType;
+    }
+
+    /**
+     * Get the color if effect type is TYPE_COLOR or TYPE_GRADIENT.
+     *
+     * @return the color as RGB 888 if type is TYPE_COLOR or TYPE_GRADIENT.
+     */
+    public int getColor() {
+        return mColor;
+    }
+}
diff --git a/media/java/android/media/videoeditor/EffectKenBurns.java b/media/java/android/media/videoeditor/EffectKenBurns.java
index ae2e70d..66c9e86 100755
--- a/media/java/android/media/videoeditor/EffectKenBurns.java
+++ b/media/java/android/media/videoeditor/EffectKenBurns.java
@@ -1,88 +1,128 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-import android.graphics.Rect;

-

-/**

- * This class represents a Ken Burns effect.

- * {@hide}

- */

-public class EffectKenBurns extends Effect {

-    // Instance variables

-    private Rect mStartRect;

-    private Rect mEndRect;

-

-    /**

-     * Objects of this type cannot be instantiated by using the default

-     * constructor

-     */

-    @SuppressWarnings("unused")

-    private EffectKenBurns() {

-        this(null, null, null, null, 0, 0);

-    }

-

-    /**

-     * Constructor

-     *

-     * @param mediaItem The media item owner

-     * @param effectId The effect id

-     * @param startRect The start rectangle

-     * @param endRect The end rectangle

-     * @param startTimeMs The start time

-     * @param durationMs The duration of the Ken Burns effect in milliseconds

-     */

-    public EffectKenBurns(MediaItem mediaItem, String effectId, Rect startRect, Rect endRect,

-            long startTimeMs, long durationMs) {

-        super(mediaItem, effectId, startTimeMs, durationMs);

-

-        mStartRect = startRect;

-        mEndRect = endRect;

-    }

-

-    /**

-     * @param startRect The start rectangle

-     *

-     * @throws IllegalArgumentException if start rectangle is incorrectly set.

-     */

-    public void setStartRect(Rect startRect) {

-        mStartRect = startRect;

-    }

-

-    /**

-     * @return The start rectangle

-     */

-    public Rect getStartRect() {

-        return mStartRect;

-    }

-

-    /**

-     * @param endRect The end rectangle

-     *

-     * @throws IllegalArgumentException if end rectangle is incorrectly set.

-     */

-    public void setEndRect(Rect endRect) {

-        mEndRect = endRect;

-    }

-

-    /**

-     * @return The end rectangle

-     */

-    public Rect getEndRect() {

-        return mEndRect;

-    }

-}

+/*
+ * 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.
+ */
+
+
+package android.media.videoeditor;
+
+import android.graphics.Rect;
+
+/**
+ * This class represents a Ken Burns effect.
+ * {@hide}
+ */
+public class EffectKenBurns extends Effect {
+    /**
+     *  Instance variables
+     */
+    private Rect mStartRect;
+    private Rect mEndRect;
+
+    /**
+     * Objects of this type cannot be instantiated by using the default
+     * constructor
+     */
+    @SuppressWarnings("unused")
+    private EffectKenBurns() {
+        this(null, null, null, null, 0, 0);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param mediaItem The media item owner
+     * @param effectId The effect id
+     * @param startRect The start rectangle
+     * @param endRect The end rectangle
+     * @param startTimeMs The start time
+     * @param durationMs The duration of the Ken Burns effect in milliseconds
+     */
+    public EffectKenBurns(MediaItem mediaItem, String effectId, Rect startRect,
+                         Rect endRect, long startTimeMs, long durationMs) {
+        super(mediaItem, effectId, startTimeMs, durationMs);
+
+        mStartRect = startRect;
+        mEndRect = endRect;
+    }
+
+    /**
+     * Set the start rectangle.
+     *
+     * @param startRect The start rectangle
+     *
+     * @throws IllegalArgumentException if start rectangle is incorrectly set.
+     */
+    public void setStartRect(Rect startRect) {
+        if ( (startRect.left == 0) && (startRect.right == 0)
+            && (startRect.bottom == 0) && (startRect.top == 0) ) {
+            throw new IllegalArgumentException("Invalid Rectangle");
+        }
+
+        mStartRect = startRect;
+    }
+
+    /**
+     * Get the start rectangle.
+     *
+     * @return The start rectangle
+     */
+    public Rect getStartRect() {
+        return mStartRect;
+    }
+
+    /**
+     * Set the end rectangle.
+     *
+     * @param endRect The end rectangle
+     *
+     * @throws IllegalArgumentException if end rectangle is incorrectly set.
+     */
+    public void setEndRect(Rect endRect) {
+        if ( (endRect.left == 0) && (endRect.right == 0)
+           && (endRect.bottom == 0) && (endRect.top == 0) ) {
+            throw new IllegalArgumentException("Invalid Rectangle");
+        }
+
+        mEndRect = endRect;
+    }
+
+    /**
+     * Get the end rectangle.
+     *
+     * @return The end rectangle
+     */
+    public Rect getEndRect() {
+        return mEndRect;
+    }
+
+    /**
+     * Get the KenBurn effect start and end rectangle coordinates
+     * @param start The rect object to be populated with start
+     * rectangle coordinates
+     *
+     * @param end The rect object to be populated with end
+     * rectangle coordinates
+     */
+    void getKenBurnsSettings(Rect start, Rect end) {
+        start.left = getStartRect().left;
+        start.top = getStartRect().top;
+        start.right = getStartRect().right;
+        start.bottom = getStartRect().bottom;
+        end.left = getEndRect().left;
+        end.top = getEndRect().top;
+        end.right = getEndRect().right;
+        end.bottom = getEndRect().bottom;
+    }
+}
diff --git a/media/java/android/media/videoeditor/ExtractAudioWaveformProgressListener.java b/media/java/android/media/videoeditor/ExtractAudioWaveformProgressListener.java
old mode 100644
new mode 100755
index 1cce148..7ba7de3
--- a/media/java/android/media/videoeditor/ExtractAudioWaveformProgressListener.java
+++ b/media/java/android/media/videoeditor/ExtractAudioWaveformProgressListener.java
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+
 package android.media.videoeditor;
 
 /**
diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
new file mode 100755
index 0000000..c3862e2
--- /dev/null
+++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
@@ -0,0 +1,4028 @@
+/*
+ * 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.
+ */
+
+package android.media.videoeditor;
+
+import java.io.File;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.nio.IntBuffer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import android.graphics.Bitmap;
+import android.media.videoeditor.VideoEditor.ExportProgressListener;
+import android.media.videoeditor.VideoEditor.PreviewProgressListener;
+import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
+import android.util.Log;
+import android.util.Pair;
+import android.view.Surface;
+
+/**
+ *This class provide Native methods to be used by MediaArtist {@hide}
+ */
+class MediaArtistNativeHelper {
+
+    static {
+        System.loadLibrary("videoeditor_jni");
+    }
+
+    private final int MAX_THUMBNAIL_PERMITTED = 8;
+
+    private final VideoEditor mVideoEditor;
+
+    public EditSettings mStoryBoardSettings;
+
+    private String mOutputFilename;
+
+    EditSettings mEditSettings = null;
+
+    PreviewClipProperties mClipProperties = null;
+
+    private EditSettings mPreviewEditSettings;
+
+    private AudioSettings mAudioSettings = null;
+
+    private AudioTrack mAudioTrack = null;
+
+    public boolean mInvalidatePreviewArray = true;
+
+    private boolean mRegenerateAudio = true;
+
+    private String mExportFilename = null;
+
+    private boolean mExportDone = false;
+
+    private int mProgressToApp;
+
+
+    public static final int TASK_LOADING_SETTINGS = 1;
+
+    public static final int TASK_ENCODING = 2;
+
+    private static final String AUDIO_TRACK_PCM_FILE = "AudioPcm.pcm";
+
+    // Processing indication
+    public static final int PROCESSING_NONE          = 0;
+    public static final int PROCESSING_AUDIO_PCM     = 1;
+    public static final int PROCESSING_TRANSITION    = 2;
+    public static final int PROCESSING_KENBURNS      = 3;
+    public static final int PROCESSING_INTERMEDIATE1 = 11;
+    public static final int PROCESSING_INTERMEDIATE2 = 12;
+    public static final int PROCESSING_INTERMEDIATE3 = 13;
+    public static final int PROCESSING_EXPORT        = 20;
+
+    private int    mProcessingState;
+    private Object mProcessingObject;
+
+    private PreviewProgressListener mPreviewProgressListener;
+    private ExportProgressListener mExportProgressListener;
+    private ExtractAudioWaveformProgressListener mExtractAudioWaveformProgressListener;
+    private MediaProcessingProgressListener      mMediaProcessingProgressListener;
+    private final String mProjectPath;
+
+    private long mPreviewProgress;
+
+    private String mAudioTrackPCMFilePath;
+
+    int mTotalClips = 0;
+
+    int mPreviewEffectsSize = 0;
+
+    private boolean mErrorFlagSet = false;
+
+    @SuppressWarnings("unused")
+    private int mManualEditContext;
+
+
+    List<Effect> mMediaEffectList;
+
+    List<Overlay> mMediaOverLayList;
+
+    /* Listeners */
+
+    /**
+     * Interface definition for a listener to be invoked when there is an update
+     * in a running task.
+     */
+    public interface OnProgressUpdateListener {
+        /**
+         * Called when there is an update.
+         *
+         * @param taskId id of the task reporting an update.
+         * @param progress progress of the task [0..100].
+         * @see BasicEdit#TASK_ENCODING
+         */
+        public void OnProgressUpdate(int taskId, int progress);
+    }
+
+    /** Defines the version. */
+    public final class Version {
+
+        /** Major version number */
+        public int major;
+
+        /** Minor version number */
+        public int minor;
+
+        /** Revision number */
+        public int revision;
+
+        /** VIDEOEDITOR major version number */
+        private static final int VIDEOEDITOR_MAJOR_VERSION = 0;
+
+        /** VIDEOEDITOR minor version number */
+        private static final int VIDEOEDITOR_MINOR_VERSION = 0;
+
+        /** VIDEOEDITOR revision number */
+        private static final int VIDEOEDITOR_REVISION_VERSION = 1;
+
+        /** Method which returns the current VIDEOEDITOR version */
+        public Version getVersion() {
+            Version version = new Version();
+
+            version.major = Version.VIDEOEDITOR_MAJOR_VERSION;
+            version.minor = Version.VIDEOEDITOR_MINOR_VERSION;
+            version.revision = Version.VIDEOEDITOR_REVISION_VERSION;
+
+            return version;
+        }
+    }
+
+    /**
+     * Defines output audio formats.
+     */
+    public final class AudioFormat {
+        /** No audio present in output clip. Used to generate video only clip */
+        public static final int NO_AUDIO = 0;
+
+        /** AMR Narrow Band. */
+        public static final int AMR_NB = 1;
+
+        /** Advanced Audio Coding (AAC). */
+        public static final int AAC = 2;
+
+        /** Advanced Audio Codec Plus (HE-AAC v1). */
+        public static final int AAC_PLUS = 3;
+
+        /** Advanced Audio Codec Plus (HE-AAC v2). */
+        public static final int ENHANCED_AAC_PLUS = 4;
+
+        /** MPEG layer 3 (MP3). */
+        public static final int MP3 = 5;
+
+        /** Enhanced Variable RateCodec (EVRC). */
+        public static final int EVRC = 6;
+
+        /** PCM (PCM). */
+        public static final int PCM = 7;
+
+        /** No transcoding. Output audio format is same as input audio format */
+        public static final int NULL_AUDIO = 254;
+
+        /** Unsupported audio format. */
+        public static final int UNSUPPORTED_AUDIO = 255;
+    }
+
+    /**
+     * Defines audio sampling frequencies.
+     */
+    public final class AudioSamplingFrequency {
+        /**
+         * Default sampling frequency. Uses the default frequency for a specific
+         * audio format. For AAC the only supported (and thus default) sampling
+         * frequency is 16 kHz. For this audio format the sampling frequency in
+         * the OutputParams.
+         **/
+        public static final int FREQ_DEFAULT = 0;
+
+        /** Audio sampling frequency of 8000 Hz. */
+        public static final int FREQ_8000 = 8000;
+
+        /** Audio sampling frequency of 11025 Hz. */
+        public static final int FREQ_11025 = 11025;
+
+        /** Audio sampling frequency of 12000 Hz. */
+        public static final int FREQ_12000 = 12000;
+
+        /** Audio sampling frequency of 16000 Hz. */
+        public static final int FREQ_16000 = 16000;
+
+        /** Audio sampling frequency of 22050 Hz. */
+        public static final int FREQ_22050 = 22050;
+
+        /** Audio sampling frequency of 24000 Hz. */
+        public static final int FREQ_24000 = 24000;
+
+        /** Audio sampling frequency of 32000 Hz. */
+        public static final int FREQ_32000 = 32000;
+
+        /** Audio sampling frequency of 44100 Hz. */
+        public static final int FREQ_44100 = 44100;
+
+        /** Audio sampling frequency of 48000 Hz. Not available for output file. */
+        public static final int FREQ_48000 = 48000;
+    }
+
+    /**
+     * Defines the supported fixed audio and video bitrates. These values are
+     * for output audio video only.
+     */
+    public final class Bitrate {
+        /** Variable bitrate. Means no bitrate regulation */
+        public static final int VARIABLE = -1;
+
+        /** An undefined bitrate. */
+        public static final int UNDEFINED = 0;
+
+        /** A bitrate of 9.2 kbits/s. */
+        public static final int BR_9_2_KBPS = 9200;
+
+        /** A bitrate of 12.2 kbits/s. */
+        public static final int BR_12_2_KBPS = 12200;
+
+        /** A bitrate of 16 kbits/s. */
+        public static final int BR_16_KBPS = 16000;
+
+        /** A bitrate of 24 kbits/s. */
+        public static final int BR_24_KBPS = 24000;
+
+        /** A bitrate of 32 kbits/s. */
+        public static final int BR_32_KBPS = 32000;
+
+        /** A bitrate of 48 kbits/s. */
+        public static final int BR_48_KBPS = 48000;
+
+        /** A bitrate of 64 kbits/s. */
+        public static final int BR_64_KBPS = 64000;
+
+        /** A bitrate of 96 kbits/s. */
+        public static final int BR_96_KBPS = 96000;
+
+        /** A bitrate of 128 kbits/s. */
+        public static final int BR_128_KBPS = 128000;
+
+        /** A bitrate of 192 kbits/s. */
+        public static final int BR_192_KBPS = 192000;
+
+        /** A bitrate of 256 kbits/s. */
+        public static final int BR_256_KBPS = 256000;
+
+        /** A bitrate of 288 kbits/s. */
+        public static final int BR_288_KBPS = 288000;
+
+        /** A bitrate of 384 kbits/s. */
+        public static final int BR_384_KBPS = 384000;
+
+        /** A bitrate of 512 kbits/s. */
+        public static final int BR_512_KBPS = 512000;
+
+        /** A bitrate of 800 kbits/s. */
+        public static final int BR_800_KBPS = 800000;
+
+        /** A bitrate of 2 Mbits/s. */
+        public static final int BR_2_MBPS = 2000000;
+
+        /** A bitrate of 5 Mbits/s. */
+        public static final int BR_5_MBPS = 5000000;
+
+        /** A bitrate of 8 Mbits/s. */
+        public static final int BR_8_MBPS = 8000000;
+    }
+
+    /**
+     * Defines all supported file types.
+     */
+    public final class FileType {
+        /** 3GPP file type. */
+        public static final int THREE_GPP = 0;
+
+        /** MP4 file type. */
+        public static final int MP4 = 1;
+
+        /** AMR file type. */
+        public static final int AMR = 2;
+
+        /** MP3 audio file type. */
+        public static final int MP3 = 3;
+
+        /** PCM audio file type. */
+        public static final int PCM = 4;
+
+        /** JPEG image file type. */
+        public static final int JPG = 5;
+
+        /** GIF image file type. */
+        public static final int GIF = 6;
+
+        /** PNG image file type. */
+        public static final int PNG = 7;
+
+        /** Unsupported file type. */
+        public static final int UNSUPPORTED = 255;
+    }
+
+    /**
+     * Defines rendering types. Rendering can only be applied to files
+     * containing video streams.
+     **/
+    public final class MediaRendering {
+        /**
+         * Resize to fit the output video with changing the aspect ratio if
+         * needed.
+         */
+        public static final int RESIZING = 0;
+
+        /**
+         * Crop the input video to fit it with the output video resolution.
+         **/
+        public static final int CROPPING = 1;
+
+        /**
+         * Resize to fit the output video resolution but maintain the aspect
+         * ratio. This framing type adds black borders if needed.
+         */
+        public static final int BLACK_BORDERS = 2;
+    }
+
+    /**
+     * Defines the results.
+     */
+    public final class Result {
+        /** No error. result OK */
+        public static final int NO_ERROR = 0;
+
+        /** File not found */
+        public static final int ERR_FILE_NOT_FOUND = 1;
+
+        /**
+         * In case of UTF8 conversion, the size of the converted path will be
+         * more than the corresponding allocated buffer.
+         */
+        public static final int ERR_BUFFER_OUT_TOO_SMALL = 2;
+
+        /** Invalid file type. */
+        public static final int ERR_INVALID_FILE_TYPE = 3;
+
+        /** Invalid effect kind. */
+        public static final int ERR_INVALID_EFFECT_KIND = 4;
+
+        /** Invalid video effect. */
+        public static final int ERR_INVALID_VIDEO_EFFECT_TYPE = 5;
+
+        /** Invalid audio effect. */
+        public static final int ERR_INVALID_AUDIO_EFFECT_TYPE = 6;
+
+        /** Invalid video transition. */
+        public static final int ERR_INVALID_VIDEO_TRANSITION_TYPE = 7;
+
+        /** Invalid audio transition. */
+        public static final int ERR_INVALID_AUDIO_TRANSITION_TYPE = 8;
+
+        /** Invalid encoding frame rate. */
+        public static final int ERR_INVALID_VIDEO_ENCODING_FRAME_RATE = 9;
+
+        /** External effect is called but this function is not set. */
+        public static final int ERR_EXTERNAL_EFFECT_NULL = 10;
+
+        /** External transition is called but this function is not set. */
+        public static final int ERR_EXTERNAL_TRANSITION_NULL = 11;
+
+        /** Begin time cut is larger than the video clip duration. */
+        public static final int ERR_BEGIN_CUT_LARGER_THAN_DURATION = 12;
+
+        /** Begin cut time is larger or equal than end cut. */
+        public static final int ERR_BEGIN_CUT_LARGER_THAN_END_CUT = 13;
+
+        /** Two consecutive transitions are overlapping on one clip. */
+        public static final int ERR_OVERLAPPING_TRANSITIONS = 14;
+
+        /** Internal error, type size mismatch. */
+        public static final int ERR_ANALYSIS_DATA_SIZE_TOO_SMALL = 15;
+
+        /** An input 3GPP file is invalid/corrupted. */
+        public static final int ERR_INVALID_3GPP_FILE = 16;
+
+        /** A file contains an unsupported video format. */
+        public static final int ERR_UNSUPPORTED_INPUT_VIDEO_FORMAT = 17;
+
+        /** A file contains an unsupported audio format. */
+        public static final int ERR_UNSUPPORTED_INPUT_AUDIO_FORMAT = 18;
+
+        /** A file format is not supported. */
+        public static final int ERR_AMR_EDITING_UNSUPPORTED = 19;
+
+        /** An input clip has an unexpectedly large Video AU. */
+        public static final int ERR_INPUT_VIDEO_AU_TOO_LARGE = 20;
+
+        /** An input clip has an unexpectedly large Audio AU. */
+        public static final int ERR_INPUT_AUDIO_AU_TOO_LARGE = 21;
+
+        /** An input clip has a corrupted Audio AU. */
+        public static final int ERR_INPUT_AUDIO_CORRUPTED_AU = 22;
+
+        /** The video encoder encountered an Access Unit error. */
+        public static final int ERR_ENCODER_ACCES_UNIT_ERROR = 23;
+
+        /** Unsupported video format for Video Editing. */
+        public static final int ERR_EDITING_UNSUPPORTED_VIDEO_FORMAT = 24;
+
+        /** Unsupported H263 profile for Video Editing. */
+        public static final int ERR_EDITING_UNSUPPORTED_H263_PROFILE = 25;
+
+        /** Unsupported MPEG-4 profile for Video Editing. */
+        public static final int ERR_EDITING_UNSUPPORTED_MPEG4_PROFILE = 26;
+
+        /** Unsupported MPEG-4 RVLC tool for Video Editing. */
+        public static final int ERR_EDITING_UNSUPPORTED_MPEG4_RVLC = 27;
+
+        /** Unsupported audio format for Video Editing. */
+        public static final int ERR_EDITING_UNSUPPORTED_AUDIO_FORMAT = 28;
+
+        /** File contains no supported stream. */
+        public static final int ERR_EDITING_NO_SUPPORTED_STREAM_IN_FILE = 29;
+
+        /** File contains no video stream or an unsupported video stream. */
+        public static final int ERR_EDITING_NO_SUPPORTED_VIDEO_STREAM_IN_FILE = 30;
+
+        /** Internal error, clip analysis version mismatch. */
+        public static final int ERR_INVALID_CLIP_ANALYSIS_VERSION = 31;
+
+        /**
+         * At least one of the clip analysis has been generated on another
+         * platform (WIN32, ARM, etc.).
+         */
+        public static final int ERR_INVALID_CLIP_ANALYSIS_PLATFORM = 32;
+
+        /** Clips don't have the same video format (H263 or MPEG4). */
+        public static final int ERR_INCOMPATIBLE_VIDEO_FORMAT = 33;
+
+        /** Clips don't have the same frame size. */
+        public static final int ERR_INCOMPATIBLE_VIDEO_FRAME_SIZE = 34;
+
+        /** Clips don't have the same MPEG-4 time scale. */
+        public static final int ERR_INCOMPATIBLE_VIDEO_TIME_SCALE = 35;
+
+        /** Clips don't have the same use of MPEG-4 data partitioning. */
+        public static final int ERR_INCOMPATIBLE_VIDEO_DATA_PARTITIONING = 36;
+
+        /** MP3 clips can't be assembled. */
+        public static final int ERR_UNSUPPORTED_MP3_ASSEMBLY = 37;
+
+        /**
+         * The input 3GPP file does not contain any supported audio or video
+         * track.
+         */
+        public static final int ERR_NO_SUPPORTED_STREAM_IN_FILE = 38;
+
+        /**
+         * The Volume of the added audio track (AddVolume) must be strictly
+         * superior than zero.
+         */
+        public static final int ERR_ADDVOLUME_EQUALS_ZERO = 39;
+
+        /**
+         * The time at which an audio track is added can't be higher than the
+         * input video track duration..
+         */
+        public static final int ERR_ADDCTS_HIGHER_THAN_VIDEO_DURATION = 40;
+
+        /** The audio track file format setting is undefined. */
+        public static final int ERR_UNDEFINED_AUDIO_TRACK_FILE_FORMAT = 41;
+
+        /** The added audio track stream has an unsupported format. */
+        public static final int ERR_UNSUPPORTED_ADDED_AUDIO_STREAM = 42;
+
+        /** The audio mixing feature doesn't support the audio track type. */
+        public static final int ERR_AUDIO_MIXING_UNSUPPORTED = 43;
+
+        /** The audio mixing feature doesn't support MP3 audio tracks. */
+        public static final int ERR_AUDIO_MIXING_MP3_UNSUPPORTED = 44;
+
+        /**
+         * An added audio track limits the available features: uiAddCts must be
+         * 0 and bRemoveOriginal must be true.
+         */
+        public static final int ERR_FEATURE_UNSUPPORTED_WITH_AUDIO_TRACK = 45;
+
+        /**
+         * An added audio track limits the available features: uiAddCts must be
+         * 0 and bRemoveOriginal must be true.
+         */
+        public static final int ERR_FEATURE_UNSUPPORTED_WITH_AAC = 46;
+
+        /** Input audio track is not of a type that can be mixed with output. */
+        public static final int ERR_AUDIO_CANNOT_BE_MIXED = 47;
+
+        /** Input audio track is not AMR-NB, so it can't be mixed with output. */
+        public static final int ERR_ONLY_AMRNB_INPUT_CAN_BE_MIXED = 48;
+
+        /**
+         * An added EVRC audio track limit the available features: uiAddCts must
+         * be 0 and bRemoveOriginal must be true.
+         */
+        public static final int ERR_FEATURE_UNSUPPORTED_WITH_EVRC = 49;
+
+        /** H263 profiles other than 0 are not supported. */
+        public static final int ERR_H263_PROFILE_NOT_SUPPORTED = 51;
+
+        /** File contains no video stream or an unsupported video stream. */
+        public static final int ERR_NO_SUPPORTED_VIDEO_STREAM_IN_FILE = 52;
+
+        /** Transcoding of the input file(s) is necessary. */
+        public static final int WAR_TRANSCODING_NECESSARY = 53;
+
+        /**
+         * The size of the output file will exceed the maximum configured value.
+         */
+        public static final int WAR_MAX_OUTPUT_SIZE_EXCEEDED = 54;
+
+        /** The time scale is too big. */
+        public static final int WAR_TIMESCALE_TOO_BIG = 55;
+
+        /** The year is out of range */
+        public static final int ERR_CLOCK_BAD_REF_YEAR = 56;
+
+        /** The directory could not be opened */
+        public static final int ERR_DIR_OPEN_FAILED = 57;
+
+        /** The directory could not be read */
+        public static final int ERR_DIR_READ_FAILED = 58;
+
+        /** There are no more entries in the current directory */
+        public static final int ERR_DIR_NO_MORE_ENTRY = 59;
+
+        /** The input parameter/s has error */
+        public static final int ERR_PARAMETER = 60;
+
+        /** There is a state machine error */
+        public static final int ERR_STATE = 61;
+
+        /** Memory allocation failed */
+        public static final int ERR_ALLOC = 62;
+
+        /** Context is invalid */
+        public static final int ERR_BAD_CONTEXT = 63;
+
+        /** Context creation failed */
+        public static final int ERR_CONTEXT_FAILED = 64;
+
+        /** Invalid stream ID */
+        public static final int ERR_BAD_STREAM_ID = 65;
+
+        /** Invalid option ID */
+        public static final int ERR_BAD_OPTION_ID = 66;
+
+        /** The option is write only */
+        public static final int ERR_WRITE_ONLY = 67;
+
+        /** The option is read only */
+        public static final int ERR_READ_ONLY = 68;
+
+        /** The feature is not implemented in this version */
+        public static final int ERR_NOT_IMPLEMENTED = 69;
+
+        /** The media type is not supported */
+        public static final int ERR_UNSUPPORTED_MEDIA_TYPE = 70;
+
+        /** No data to be encoded */
+        public static final int WAR_NO_DATA_YET = 71;
+
+        /** No data to be decoded */
+        public static final int WAR_NO_MORE_STREAM = 72;
+
+        /** Time stamp is invalid */
+        public static final int WAR_INVALID_TIME = 73;
+
+        /** No more data to be decoded */
+        public static final int WAR_NO_MORE_AU = 74;
+
+        /** Semaphore timed out */
+        public static final int WAR_TIME_OUT = 75;
+
+        /** Memory buffer is full */
+        public static final int WAR_BUFFER_FULL = 76;
+
+        /** Server has asked for redirection */
+        public static final int WAR_REDIRECT = 77;
+
+        /** Too many streams in input */
+        public static final int WAR_TOO_MUCH_STREAMS = 78;
+
+        /** The file cannot be opened/ written into as it is locked */
+        public static final int ERR_FILE_LOCKED = 79;
+
+        /** The file access mode is invalid */
+        public static final int ERR_FILE_BAD_MODE_ACCESS = 80;
+
+        /** The file pointer points to an invalid location */
+        public static final int ERR_FILE_INVALID_POSITION = 81;
+
+        /** Invalid string */
+        public static final int ERR_STR_BAD_STRING = 94;
+
+        /** The input string cannot be converted */
+        public static final int ERR_STR_CONV_FAILED = 95;
+
+        /** The string size is too large */
+        public static final int ERR_STR_OVERFLOW = 96;
+
+        /** Bad string arguments */
+        public static final int ERR_STR_BAD_ARGS = 97;
+
+        /** The string value is larger than maximum size allowed */
+        public static final int WAR_STR_OVERFLOW = 98;
+
+        /** The string value is not present in this comparison operation */
+        public static final int WAR_STR_NOT_FOUND = 99;
+
+        /** The thread is not started */
+        public static final int ERR_THREAD_NOT_STARTED = 100;
+
+        /** Trancoding done warning */
+        public static final int WAR_TRANSCODING_DONE = 101;
+
+        /** Unsupported mediatype */
+        public static final int WAR_MEDIATYPE_NOT_SUPPORTED = 102;
+
+        /** Input file contains invalid/unsupported streams */
+        public static final int ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM = 103;
+
+        /** Invalid input file */
+        public static final int ERR_INVALID_INPUT_FILE = 104;
+
+        /** Invalid output video format */
+        public static final int ERR_UNDEFINED_OUTPUT_VIDEO_FORMAT = 105;
+
+        /** Invalid output video frame size */
+        public static final int ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_SIZE = 106;
+
+        /** Invalid output video frame rate */
+        public static final int ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_RATE = 107;
+
+        /** Invalid output audio format */
+        public static final int ERR_UNDEFINED_OUTPUT_AUDIO_FORMAT = 108;
+
+        /** Invalid video frame size for H.263 */
+        public static final int ERR_INVALID_VIDEO_FRAME_SIZE_FOR_H263 = 109;
+
+        /** Invalid video frame rate for H.263 */
+        public static final int ERR_INVALID_VIDEO_FRAME_RATE_FOR_H263 = 110;
+
+        /** invalid playback duration */
+        public static final int ERR_DURATION_IS_NULL = 111;
+
+        /** Invalid H.263 profile in file */
+        public static final int ERR_H263_FORBIDDEN_IN_MP4_FILE = 112;
+
+        /** Invalid AAC sampling frequency */
+        public static final int ERR_INVALID_AAC_SAMPLING_FREQUENCY = 113;
+
+        /** Audio conversion failure */
+        public static final int ERR_AUDIO_CONVERSION_FAILED = 114;
+
+        /** Invalid trim start and end times */
+        public static final int ERR_BEGIN_CUT_EQUALS_END_CUT = 115;
+
+        /** End time smaller than start time for trim */
+        public static final int ERR_END_CUT_SMALLER_THAN_BEGIN_CUT = 116;
+
+        /** Output file size is small */
+        public static final int ERR_MAXFILESIZE_TOO_SMALL = 117;
+
+        /** Output video bitrate is too low */
+        public static final int ERR_VIDEOBITRATE_TOO_LOW = 118;
+
+        /** Output audio bitrate is too low */
+        public static final int ERR_AUDIOBITRATE_TOO_LOW = 119;
+
+        /** Output video bitrate is too high */
+        public static final int ERR_VIDEOBITRATE_TOO_HIGH = 120;
+
+        /** Output audio bitrate is too high */
+        public static final int ERR_AUDIOBITRATE_TOO_HIGH = 121;
+
+        /** Output file size is too small */
+        public static final int ERR_OUTPUT_FILE_SIZE_TOO_SMALL = 122;
+
+        /** Unknown stream type */
+        public static final int ERR_READER_UNKNOWN_STREAM_TYPE = 123;
+
+        /** Invalid metadata in input stream */
+        public static final int WAR_READER_NO_METADATA = 124;
+
+        /** Invalid file reader info warning */
+        public static final int WAR_READER_INFORMATION_NOT_PRESENT = 125;
+
+        /** Warning to indicate the the writer is being stopped */
+        public static final int WAR_WRITER_STOP_REQ = 131;
+
+        /** Video decoder failed to provide frame for transcoding */
+        public static final int WAR_VIDEORENDERER_NO_NEW_FRAME = 132;
+
+        /** Video deblocking filter is not implemented */
+        public static final int WAR_DEBLOCKING_FILTER_NOT_IMPLEMENTED = 133;
+
+        /** H.263 decoder profile not supported */
+        public static final int ERR_DECODER_H263_PROFILE_NOT_SUPPORTED = 134;
+
+        /** The input file contains unsupported H.263 profile */
+        public static final int ERR_DECODER_H263_NOT_BASELINE = 135;
+
+        /** There is no more space to store the output file */
+        public static final int ERR_NOMORE_SPACE_FOR_FILE = 136;
+
+        /** Internal error. */
+        public static final int ERR_INTERNAL = 255;
+
+    }
+
+    /**
+     * Defines output video formats.
+     */
+    public final class VideoFormat {
+        /** No video present in output clip. Used to generate audio only clip */
+        public static final int NO_VIDEO = 0;
+
+        /** H263 baseline format. */
+        public static final int H263 = 1;
+
+        /** MPEG4 video Simple Profile format. */
+        public static final int MPEG4 = 2;
+
+        /** MPEG4 video Simple Profile format with support for EMP. */
+        public static final int MPEG4_EMP = 3;
+
+        /** H264 video */
+        public static final int H264 = 4;
+
+        /** No transcoding. Output video format is same as input video format */
+        public static final int NULL_VIDEO = 254;
+
+        /** Unsupported video format. */
+        public static final int UNSUPPORTED = 255;
+    }
+
+    /** Defines video profiles and levels. */
+    public final class VideoProfile {
+        /** MPEG4, Simple Profile, Level 0. */
+        public static final int MPEG4_SP_LEVEL_0 = 0;
+
+        /** MPEG4, Simple Profile, Level 0B. */
+        public static final int MPEG4_SP_LEVEL_0B = 1;
+
+        /** MPEG4, Simple Profile, Level 1. */
+        public static final int MPEG4_SP_LEVEL_1 = 2;
+
+        /** MPEG4, Simple Profile, Level 2. */
+        public static final int MPEG4_SP_LEVEL_2 = 3;
+
+        /** MPEG4, Simple Profile, Level 3. */
+        public static final int MPEG4_SP_LEVEL_3 = 4;
+
+        /** H263, Profile 0, Level 10. */
+        public static final int H263_PROFILE_0_LEVEL_10 = 5;
+
+        /** H263, Profile 0, Level 20. */
+        public static final int H263_PROFILE_0_LEVEL_20 = 6;
+
+        /** H263, Profile 0, Level 30. */
+        public static final int H263_PROFILE_0_LEVEL_30 = 7;
+
+        /** H263, Profile 0, Level 40. */
+        public static final int H263_PROFILE_0_LEVEL_40 = 8;
+
+        /** H263, Profile 0, Level 45. */
+        public static final int H263_PROFILE_0_LEVEL_45 = 9;
+
+        /** MPEG4, Simple Profile, Level 4A. */
+        public static final int MPEG4_SP_LEVEL_4A = 10;
+
+        /** MPEG4, Simple Profile, Level 0. */
+        public static final int MPEG4_SP_LEVEL_5 = 11;
+
+        /** H264, Profile 0, Level 1. */
+        public static final int H264_PROFILE_0_LEVEL_1 = 12;
+
+        /** H264, Profile 0, Level 1b. */
+        public static final int H264_PROFILE_0_LEVEL_1b = 13;
+
+        /** H264, Profile 0, Level 1.1 */
+        public static final int H264_PROFILE_0_LEVEL_1_1 = 14;
+
+        /** H264, Profile 0, Level 1.2 */
+        public static final int H264_PROFILE_0_LEVEL_1_2 = 15;
+
+        /** H264, Profile 0, Level 1.3 */
+        public static final int H264_PROFILE_0_LEVEL_1_3 = 16;
+
+        /** H264, Profile 0, Level 2. */
+        public static final int H264_PROFILE_0_LEVEL_2 = 17;
+
+        /** H264, Profile 0, Level 2.1 */
+        public static final int H264_PROFILE_0_LEVEL_2_1 = 18;
+
+        /** H264, Profile 0, Level 2.2 */
+        public static final int H264_PROFILE_0_LEVEL_2_2 = 19;
+
+        /** H264, Profile 0, Level 3. */
+        public static final int H264_PROFILE_0_LEVEL_3 = 20;
+
+        /** H264, Profile 0, Level 3.1 */
+        public static final int H264_PROFILE_0_LEVEL_3_1 = 21;
+
+        /** H264, Profile 0, Level 3.2 */
+        public static final int H264_PROFILE_0_LEVEL_3_2 = 22;
+
+        /** H264, Profile 0, Level 4. */
+        public static final int H264_PROFILE_0_LEVEL_4 = 23;
+
+        /** H264, Profile 0, Level 4.1 */
+        public static final int H264_PROFILE_0_LEVEL_4_1 = 24;
+
+        /** H264, Profile 0, Level 4.2 */
+        public static final int H264_PROFILE_0_LEVEL_4_2 = 25;
+
+        /** H264, Profile 0, Level 5. */
+        public static final int H264_PROFILE_0_LEVEL_5 = 26;
+
+        /** H264, Profile 0, Level 5.1 */
+        public static final int H264_PROFILE_0_LEVEL_5_1 = 27;
+
+        /** Profile out of range. */
+        public static final int OUT_OF_RANGE = 255;
+    }
+
+    /** Defines video frame sizes. */
+    public final class VideoFrameSize {
+
+        public static final int SIZE_UNDEFINED = -1;
+
+        /** SQCIF 128 x 96 pixels. */
+        public static final int SQCIF = 0;
+
+        /** QQVGA 160 x 120 pixels. */
+        public static final int QQVGA = 1;
+
+        /** QCIF 176 x 144 pixels. */
+        public static final int QCIF = 2;
+
+        /** QVGA 320 x 240 pixels. */
+        public static final int QVGA = 3;
+
+        /** CIF 352 x 288 pixels. */
+        public static final int CIF = 4;
+
+        /** VGA 640 x 480 pixels. */
+        public static final int VGA = 5;
+
+        /** WVGA 800 X 480 pixels */
+        public static final int WVGA = 6;
+
+        /** NTSC 720 X 480 pixels */
+        public static final int NTSC = 7;
+
+        /** 640 x 360 */
+        public static final int nHD = 8;
+
+        /** 854 x 480 */
+        public static final int WVGA16x9 = 9;
+
+        /** 720p 1280 X 720 */
+        public static final int V720p = 10;
+
+        /** 1080 x 720 */
+        public static final int W720p = 11;
+
+        /** 1080 960 x 720 */
+        public static final int S720p = 12;
+    }
+
+    /**
+     * Defines output video frame rates.
+     */
+    public final class VideoFrameRate {
+        /** Frame rate of 5 frames per second. */
+        public static final int FR_5_FPS = 0;
+
+        /** Frame rate of 7.5 frames per second. */
+        public static final int FR_7_5_FPS = 1;
+
+        /** Frame rate of 10 frames per second. */
+        public static final int FR_10_FPS = 2;
+
+        /** Frame rate of 12.5 frames per second. */
+        public static final int FR_12_5_FPS = 3;
+
+        /** Frame rate of 15 frames per second. */
+        public static final int FR_15_FPS = 4;
+
+        /** Frame rate of 20 frames per second. */
+        public static final int FR_20_FPS = 5;
+
+        /** Frame rate of 25 frames per second. */
+        public static final int FR_25_FPS = 6;
+
+        /** Frame rate of 30 frames per second. */
+        public static final int FR_30_FPS = 7;
+    }
+
+    /**
+     * Defines Video Effect Types.
+     */
+    public static class VideoEffect {
+
+        public static final int NONE = 0;
+
+        public static final int FADE_FROM_BLACK = 8;
+
+        public static final int CURTAIN_OPENING = 9;
+
+        public static final int FADE_TO_BLACK = 16;
+
+        public static final int CURTAIN_CLOSING = 17;
+
+        public static final int EXTERNAL = 256;
+
+        public static final int BLACK_AND_WHITE = 257;
+
+        public static final int PINK = 258;
+
+        public static final int GREEN = 259;
+
+        public static final int SEPIA = 260;
+
+        public static final int NEGATIVE = 261;
+
+        public static final int FRAMING = 262;
+
+        public static final int TEXT = 263;
+
+        public static final int ZOOM_IN = 264;
+
+        public static final int ZOOM_OUT = 265;
+
+        public static final int FIFTIES = 266;
+
+        public static final int COLORRGB16 = 267;
+
+        public static final int GRADIENT = 268;
+    }
+
+    /**
+     * Defines the video transitions.
+     */
+    public static class VideoTransition {
+        /** No transition */
+        public static final int NONE = 0;
+
+        /** Cross fade transition */
+        public static final int CROSS_FADE = 1;
+
+        /** External transition. Currently not available. */
+        public static final int EXTERNAL = 256;
+
+        /** AlphaMagic transition. */
+        public static final int ALPHA_MAGIC = 257;
+
+        /** Slide transition. */
+        public static final int SLIDE_TRANSITION = 258;
+
+        /** Fade to black transition. */
+        public static final int FADE_BLACK = 259;
+    }
+
+    /**
+     * Defines settings for the AlphaMagic transition
+     */
+    public static class AlphaMagicSettings {
+        /** Name of the alpha file (JPEG file). */
+        public String file;
+
+        /** Blending percentage [0..100] 0 = no blending. */
+        public int blendingPercent;
+
+        /** Invert the default rotation direction of the AlphaMagic effect. */
+        public boolean invertRotation;
+
+        public int rgbWidth;
+        public int rgbHeight;
+    }
+
+    /** Defines the direction of the Slide transition. */
+    public static final class SlideDirection {
+
+        /** Right out left in. */
+        public static final int RIGHT_OUT_LEFT_IN = 0;
+
+        /** Left out right in. */
+        public static final int LEFT_OUT_RIGTH_IN = 1;
+
+        /** Top out bottom in. */
+        public static final int TOP_OUT_BOTTOM_IN = 2;
+
+        /** Bottom out top in */
+        public static final int BOTTOM_OUT_TOP_IN = 3;
+    }
+
+    /** Defines the Slide transition settings. */
+    public static class SlideTransitionSettings {
+        /**
+         * Direction of the slide transition. See {@link SlideDirection
+         * SlideDirection} for valid values.
+         */
+        public int direction;
+    }
+
+    /**
+     * Defines the settings of a single clip.
+     */
+    public static class ClipSettings {
+
+        /**
+         * The path to the clip file.
+         * <p>
+         * File format of the clip, it can be:
+         * <ul>
+         * <li>3GP file containing MPEG4/H263/H264 video and AAC/AMR audio
+         * <li>JPG file
+         * </ul>
+         */
+
+        public String clipPath;
+
+        /**
+         * The path of the decoded file. This is used only for image files.
+         */
+        public String clipDecodedPath;
+
+        /**
+         * The path of the Original file. This is used only for image files.
+         */
+        public String clipOriginalPath;
+
+        /**
+         * File type of the clip. See {@link FileType FileType} for valid
+         * values.
+         */
+        public int fileType;
+
+        /** Begin of the cut in the clip in milliseconds. */
+        public int beginCutTime;
+
+        /**
+         * End of the cut in the clip in milliseconds. Set both
+         * <code>beginCutTime</code> and <code>endCutTime</code> to
+         * <code>0</code> to get the full length of the clip without a cut. In
+         * case of JPG clip, this is the duration of the JPEG file.
+         */
+        public int endCutTime;
+
+        /**
+         * Begin of the cut in the clip in percentage of the file duration.
+         */
+        public int beginCutPercent;
+
+        /**
+         * End of the cut in the clip in percentage of the file duration. Set
+         * both <code>beginCutPercent</code> and <code>endCutPercent</code> to
+         * <code>0</code> to get the full length of the clip without a cut.
+         */
+        public int endCutPercent;
+
+        /** Enable panning and zooming. */
+        public boolean panZoomEnabled;
+
+        /** Zoom percentage at start of clip. 0 = no zoom, 100 = full zoom */
+        public int panZoomPercentStart;
+
+        /** Top left X coordinate at start of clip. */
+        public int panZoomTopLeftXStart;
+
+        /** Top left Y coordinate at start of clip. */
+        public int panZoomTopLeftYStart;
+
+        /** Zoom percentage at start of clip. 0 = no zoom, 100 = full zoom */
+        public int panZoomPercentEnd;
+
+        /** Top left X coordinate at end of clip. */
+        public int panZoomTopLeftXEnd;
+
+        /** Top left Y coordinate at end of clip. */
+        public int panZoomTopLeftYEnd;
+
+        /**
+         * Set The media rendering. See {@link MediaRendering MediaRendering}
+         * for valid values.
+         */
+        public int mediaRendering;
+
+        /**
+         * RGB width and Height
+         */
+         public int rgbWidth;
+         public int rgbHeight;
+    }
+
+    /**
+     * Defines settings for a transition.
+     */
+    public static class TransitionSettings {
+
+        /** Duration of the transition in msec. */
+        public int duration;
+
+        /**
+         * Transition type for video. See {@link VideoTransition
+         * VideoTransition} for valid values.
+         */
+        public int videoTransitionType;
+
+        /**
+         * Transition type for audio. See {@link AudioTransition
+         * AudioTransition} for valid values.
+         */
+        public int audioTransitionType;
+
+        /**
+         * Transition behaviour. See {@link TransitionBehaviour
+         * TransitionBehaviour} for valid values.
+         */
+        public int transitionBehaviour;
+
+        /**
+         * Settings for AlphaMagic transition. Only needs to be set if
+         * <code>videoTransitionType</code> is set to
+         * <code>VideoTransition.ALPHA_MAGIC</code>. See
+         * {@link AlphaMagicSettings AlphaMagicSettings}.
+         */
+        public AlphaMagicSettings alphaSettings;
+
+        /**
+         * Settings for the Slide transition. See
+         * {@link SlideTransitionSettings SlideTransitionSettings}.
+         */
+        public SlideTransitionSettings slideSettings;
+    }
+
+    public static final class AudioTransition {
+        /** No audio transition. */
+        public static final int NONE = 0;
+
+        /** Cross-fade audio transition. */
+        public static final int CROSS_FADE = 1;
+    }
+
+    /**
+     * Defines transition behaviours.
+     **/
+
+    public static final class TransitionBehaviour {
+
+        /** The transition uses an increasing speed. */
+        public static final int SPEED_UP = 0;
+
+        /** The transition uses a linear (constant) speed. */
+        public static final int LINEAR = 1;
+
+        /** The transition uses a decreasing speed. */
+        public static final int SPEED_DOWN = 2;
+
+        /**
+         * The transition uses a constant speed, but slows down in the middle
+         * section.
+         */
+        public static final int SLOW_MIDDLE = 3;
+
+        /**
+         * The transition uses a constant speed, but increases speed in the
+         * middle section.
+         */
+        public static final int FAST_MIDDLE = 4;
+    }
+
+    /** Defines settings for the background music. */
+    public static class BackgroundMusicSettings {
+
+        /** Background music file. */
+        public String file;
+
+        /** File type. See {@link FileType FileType} for valid values. */
+        public int fileType;
+
+        /**
+         * Insertion time in milliseconds, in the output video where the
+         * background music must be inserted.
+         */
+        public long insertionTime;
+
+        /**
+         * Volume, as a percentage of the background music track, to use. If
+         * this field is set to 100, the background music will replace the audio
+         * from the video input file(s).
+         */
+        public int volumePercent;
+
+        /**
+         * Start time in milliseconds in the background muisc file from where
+         * the background music should loop. Set both <code>beginLoop</code> and
+         * <code>endLoop</code> to <code>0</code> to disable looping.
+         */
+        public long beginLoop;
+
+        /**
+         * End time in milliseconds in the background music file to where the
+         * background music should loop. Set both <code>beginLoop</code> and
+         * <code>endLoop</code> to <code>0</code> to disable looping.
+         */
+        public long endLoop;
+
+        public boolean enableDucking;
+
+        public int duckingThreshold;
+
+        public int lowVolume;
+
+        public boolean isLooping;
+
+    }
+
+    /** Defines settings for an effect. */
+    public static class AudioEffect {
+        /** No audio effect. */
+        public static final int NONE = 0;
+
+        /** Fade-in effect. */
+        public static final int FADE_IN = 8;
+
+        /** Fade-out effect. */
+        public static final int FADE_OUT = 16;
+    }
+
+    /** Defines the effect settings. */
+    public static class EffectSettings {
+
+        /** Start time of the effect in milliseconds. */
+        public int startTime;
+
+        /** Duration of the effect in milliseconds. */
+        public int duration;
+
+        /**
+         * Video effect type. See {@link VideoEffect VideoEffect} for valid
+         * values.
+         */
+        public int videoEffectType;
+
+        /**
+         * Audio effect type. See {@link AudioEffect AudioEffect} for valid
+         * values.
+         */
+        public int audioEffectType;
+
+        /**
+         * Start time of the effect in percents of the duration of the clip. A
+         * value of 0 percent means start time is from the beginning of the
+         * clip.
+         */
+        public int startPercent;
+
+        /**
+         * Duration of the effect in percents of the duration of the clip.
+         */
+        public int durationPercent;
+
+        /**
+         * Framing file.
+         * <p>
+         * This field is only used when the field <code>videoEffectType</code>
+         * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise
+         * this field is ignored.
+         */
+        public String framingFile;
+
+        /**
+         * Framing buffer.
+         * <p>
+         * This field is only used when the field <code>videoEffectType</code>
+         * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise
+         * this field is ignored.
+         */
+        public int[] framingBuffer;
+
+        /**
+         * Bitmap type Can be from RGB_565 (4), ARGB_4444 (5), ARGB_8888 (6);
+         **/
+
+        public int bitmapType;
+
+        public int width;
+
+        public int height;
+
+        /**
+         * Top left x coordinate. This coordinate is used to set the x
+         * coordinate of the picture in the framing file when the framing file
+         * is selected. The x coordinate is also used to set the location of the
+         * text in the text effect.
+         * <p>
+         * This field is only used when the field <code>videoEffectType</code>
+         * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING} or
+         * {@link VideoEffect#TEXT VideoEffect.TEXT}. Otherwise this field is
+         * ignored.
+         */
+        public int topLeftX;
+
+        /**
+         * Top left y coordinate. This coordinate is used to set the y
+         * coordinate of the picture in the framing file when the framing file
+         * is selected. The y coordinate is also used to set the location of the
+         * text in the text effect.
+         * <p>
+         * This field is only used when the field <code>videoEffectType</code>
+         * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING} or
+         * {@link VideoEffect#TEXT VideoEffect.TEXT}. Otherwise this field is
+         * ignored.
+         */
+        public int topLeftY;
+
+        /**
+         * Should the frame be resized or not. If this field is set to
+         * <link>true</code> then the frame size is matched with the output
+         * video size.
+         * <p>
+         * This field is only used when the field <code>videoEffectType</code>
+         * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise
+         * this field is ignored.
+         */
+        public boolean framingResize;
+
+        /**
+         * Size to which the framing buffer needs to be resized to
+         * This is valid only if framingResize is true
+         */
+        public int framingScaledSize;
+        /**
+         * Text to insert in the video.
+         * <p>
+         * This field is only used when the field <code>videoEffectType</code>
+         * is set to {@link VideoEffect#TEXT VideoEffect.TEXT}. Otherwise this
+         * field is ignored.
+         */
+        public String text;
+
+        /**
+         * Text attributes for the text to insert in the video.
+         * <p>
+         * This field is only used when the field <code>videoEffectType</code>
+         * is set to {@link VideoEffect#TEXT VideoEffect.TEXT}. Otherwise this
+         * field is ignored. For more details about this field see the
+         * integration guide.
+         */
+        public String textRenderingData;
+
+        /** Width of the text buffer in pixels. */
+        public int textBufferWidth;
+
+        /** Height of the text buffer in pixels. */
+        public int textBufferHeight;
+
+        /**
+         * Processing rate for the fifties effect. A high value (e.g. 30)
+         * results in high effect strength.
+         * <p>
+         * This field is only used when the field <code>videoEffectType</code>
+         * is set to {@link VideoEffect#FIFTIES VideoEffect.FIFTIES}. Otherwise
+         * this field is ignored.
+         */
+        public int fiftiesFrameRate;
+
+        /**
+         * RGB 16 color of the RGB16 and gradient color effect.
+         * <p>
+         * This field is only used when the field <code>videoEffectType</code>
+         * is set to {@link VideoEffect#COLORRGB16 VideoEffect.COLORRGB16} or
+         * {@link VideoEffect#GRADIENT VideoEffect.GRADIENT}. Otherwise this
+         * field is ignored.
+         */
+        public int rgb16InputColor;
+
+        /**
+         * Start alpha blending percentage.
+         * <p>
+         * This field is only used when the field <code>videoEffectType</code>
+         * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
+         * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
+         * is ignored.
+         */
+        public int alphaBlendingStartPercent;
+
+        /**
+         * Middle alpha blending percentage.
+         * <p>
+         * This field is only used when the field <code>videoEffectType</code>
+         * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
+         * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
+         * is ignored.
+         */
+        public int alphaBlendingMiddlePercent;
+
+        /**
+         * End alpha blending percentage.
+         * <p>
+         * This field is only used when the field <code>videoEffectType</code>
+         * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
+         * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
+         * is ignored.
+         */
+        public int alphaBlendingEndPercent;
+
+        /**
+         * Duration, in percentage of effect duration of the fade-in phase.
+         * <p>
+         * This field is only used when the field <code>videoEffectType</code>
+         * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
+         * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
+         * is ignored.
+         */
+        public int alphaBlendingFadeInTimePercent;
+
+        /**
+         * Duration, in percentage of effect duration of the fade-out phase.
+         * <p>
+         * This field is only used when the field <code>videoEffectType</code>
+         * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
+         * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
+         * is ignored.
+         */
+        public int alphaBlendingFadeOutTimePercent;
+    }
+
+    /** Defines the clip properties for preview */
+    public static class PreviewClips {
+
+        /**
+         * The path to the clip file.
+         * <p>
+         * File format of the clip, it can be:
+         * <ul>
+         * <li>3GP file containing MPEG4/H263 video and AAC/AMR audio
+         * <li>JPG file
+         * </ul>
+         */
+
+        public String clipPath;
+
+        /**
+         * File type of the clip. See {@link FileType FileType} for valid
+         * values.
+         */
+        public int fileType;
+
+        /** Begin of the cut in the clip in milliseconds. */
+        public long beginPlayTime;
+
+        public long endPlayTime;
+
+        /**
+         * Set The media rendering. See {@link MediaRendering MediaRendering}
+         * for valid values.
+         */
+        public int mediaRendering;
+
+    }
+
+    /** Defines the audio settings. */
+    public static class AudioSettings {
+
+        String pFile;
+
+        /** < PCM file path */
+        String Id;
+
+        boolean bRemoveOriginal;
+
+        /** < If true, the original audio track is not taken into account */
+        int channels;
+
+        /** < Number of channels (1=mono, 2=stereo) of BGM clip */
+        int Fs;
+
+        /**
+         * < Sampling audio frequency (8000 for amr, 16000 or more for aac) of
+         * BGM clip
+         */
+        int ExtendedFs;
+
+        /** < Extended frequency for AAC+, eAAC+ streams of BGM clip */
+        long startMs;
+
+        /** < Time, in milliseconds, at which the added audio track is inserted */
+        long beginCutTime;
+
+        long endCutTime;
+
+        int fileType;
+
+        int volume;
+
+        /** < Volume, in percentage, of the added audio track */
+        boolean loop;
+
+        /** < Looping on/off > **/
+
+        /** Audio mix and Duck **/
+        int ducking_threshold;
+
+        int ducking_lowVolume;
+
+        boolean bInDucking_enable;
+
+        String pcmFilePath;
+
+    }
+
+    /** Encapsulates preview clips and effect settings */
+    public static class PreviewSettings {
+
+        public PreviewClips[] previewClipsArray;
+
+        /** The effect settings. */
+        public EffectSettings[] effectSettingsArray;
+
+    }
+
+    /** Encapsulates clip properties */
+    public static class PreviewClipProperties {
+
+        public Properties[] clipProperties;
+
+    }
+
+    /** Defines the editing settings. */
+    public static class EditSettings {
+
+        /**
+         * Array of clip settings. There is one <code>clipSetting</code> for
+         * each clip.
+         */
+        public ClipSettings[] clipSettingsArray;
+
+        /**
+         * Array of transition settings. If there are n clips (and thus n
+         * <code>clipSettings</code>) then there are (n-1) transitions and (n-1)
+         * <code>transistionSettings</code> in
+         * <code>transistionSettingsArray</code>.
+         */
+        public TransitionSettings[] transitionSettingsArray;
+
+        /** The effect settings. */
+        public EffectSettings[] effectSettingsArray;
+
+        /**
+         * Video frame rate of the output clip. See {@link VideoFrameRate
+         * VideoFrameRate} for valid values.
+         */
+        public int videoFrameRate;
+
+        /** Output file name. Must be an absolute path. */
+        public String outputFile;
+
+        /**
+         * Size of the video frames in the output clip. See
+         * {@link VideoFrameSize VideoFrameSize} for valid values.
+         */
+        public int videoFrameSize;
+
+        /**
+         * Format of the video stream in the output clip. See
+         * {@link VideoFormat VideoFormat} for valid values.
+         */
+        public int videoFormat;
+
+        /**
+         * Format of the audio stream in the output clip. See
+         * {@link AudioFormat AudioFormat} for valid values.
+         */
+        public int audioFormat;
+
+        /**
+         * Sampling frequency of the audio stream in the output clip. See
+         * {@link AudioSamplingFrequency AudioSamplingFrequency} for valid
+         * values.
+         */
+        public int audioSamplingFreq;
+
+        /**
+         * Maximum file size. By setting this you can set the maximum size of
+         * the output clip. Set it to <code>0</code> to let the class ignore
+         * this filed.
+         */
+        public int maxFileSize;
+
+        /**
+         * Number of audio channels in output clip. Use <code>0</code> for none,
+         * <code>1</code> for mono or <code>2</code> for stereo. None is only
+         * allowed when the <code>audioFormat</code> field is set to
+         * {@link AudioFormat#NO_AUDIO AudioFormat.NO_AUDIO} or
+         * {@link AudioFormat#NULL_AUDIO AudioFormat.NULL_AUDIO} Mono is only
+         * allowed when the <code>audioFormat</code> field is set to
+         * {@link AudioFormat#AAC AudioFormat.AAC}
+         */
+        public int audioChannels;
+
+        /** Video bitrate. See {@link Bitrate Bitrate} for valid values. */
+        public int videoBitrate;
+
+        /** Audio bitrate. See {@link Bitrate Bitrate} for valid values. */
+        public int audioBitrate;
+
+        /**
+         * Background music settings. See {@link BackgroundMusicSettings
+         * BackgroundMusicSettings} for valid values.
+         */
+        public BackgroundMusicSettings backgroundMusicSettings;
+
+        public int primaryTrackVolume;
+
+    }
+
+    /**
+     * Defines the media properties.
+     **/
+
+    public static class Properties {
+
+        /**
+         * Duration of the media in milliseconds.
+         */
+
+        public int duration;
+
+        /**
+         * File type.
+         */
+
+        public int fileType;
+
+        /**
+         * Video format.
+         */
+
+        public int videoFormat;
+
+        /**
+         * Duration of the video stream of the media in milliseconds.
+         */
+
+        public int videoDuration;
+
+        /**
+         * Bitrate of the video stream of the media.
+         */
+
+        public int videoBitrate;
+
+        /**
+         * Width of the video frames or the width of the still picture in
+         * pixels.
+         */
+
+        public int width;
+
+        /**
+         * Height of the video frames or the height of the still picture in
+         * pixels.
+         */
+
+        public int height;
+
+        /**
+         * Average frame rate of video in the media in frames per second.
+         */
+
+        public float averageFrameRate;
+
+        /**
+         * Profile and level of the video in the media.
+         */
+
+        public int profileAndLevel;
+
+        /**
+         * Audio format.
+         */
+
+        public int audioFormat;
+
+        /**
+         * Duration of the audio stream of the media in milliseconds.
+         */
+
+        public int audioDuration;
+
+        /**
+         * Bitrate of the audio stream of the media.
+         */
+
+        public int audioBitrate;
+
+        /**
+         * Number of audio channels in the media.
+         */
+
+        public int audioChannels;
+
+        /**
+         * Sampling frequency of the audio stream in the media in samples per
+         * second.
+         */
+
+        public int audioSamplingFrequency;
+
+        /**
+         * Volume value of the audio track as percentage.
+         */
+        public int audioVolumeValue;
+
+        public String Id;
+
+    }
+
+    /**
+     * Constructor
+     *
+     * @param projectPath The path where the VideoEditor stores all files
+     *        related to the project
+     * @param veObj The video editor reference
+     */
+    public MediaArtistNativeHelper(String projectPath, VideoEditor veObj) {
+        mProjectPath = projectPath;
+        if (veObj != null) {
+            mVideoEditor = veObj;
+        } else {
+            mVideoEditor = null;
+            throw new IllegalArgumentException("video editor object is null");
+        }
+        if (mStoryBoardSettings == null)
+            mStoryBoardSettings = new EditSettings();
+
+        mMediaEffectList = new ArrayList<Effect>();
+        mMediaOverLayList = new ArrayList<Overlay>();
+        _init(mProjectPath, "null");
+        mAudioTrackPCMFilePath = null;
+    }
+
+    /**
+     * @return The project path
+     */
+    String getProjectPath() {
+        return mProjectPath;
+    }
+
+    /**
+     * @return The Audio Track PCM file path
+     */
+    String getProjectAudioTrackPCMFilePath() {
+        return mAudioTrackPCMFilePath;
+    }
+
+    /**
+     * Invalidates the PCM file
+     */
+    void invalidatePcmFile() {
+        if (mAudioTrackPCMFilePath != null) {
+            new File(mAudioTrackPCMFilePath).delete();
+            mAudioTrackPCMFilePath = null;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private void onProgressUpdate(int taskId, int progress) {
+        if (mProcessingState == PROCESSING_EXPORT) {
+            if (mExportProgressListener != null) {
+                if ((progress % 2) == 0) {
+                    mProgressToApp++;
+                    mExportProgressListener.onProgress(mVideoEditor, mOutputFilename, mProgressToApp);
+                }
+            }
+        }
+        else {
+            // Adapt progress depending on current state
+            int actualProgress = 0;
+            int action = 0;
+
+            if (mProcessingState == PROCESSING_AUDIO_PCM) {
+                action = MediaProcessingProgressListener.ACTION_DECODE;
+            } else {
+                action = MediaProcessingProgressListener.ACTION_ENCODE;
+            }
+
+            switch (mProcessingState) {
+                case PROCESSING_AUDIO_PCM:
+                    actualProgress = progress;
+                    break;
+                case PROCESSING_TRANSITION:
+                    actualProgress = progress;
+                    break;
+                case PROCESSING_KENBURNS:
+                    actualProgress = progress;
+                    break;
+                case PROCESSING_INTERMEDIATE1:
+                    if ((progress == 0) && (mProgressToApp != 0)) {
+                        mProgressToApp = 0;
+                    }
+                    if ((progress != 0) || (mProgressToApp != 0)) {
+                        actualProgress = progress/4;
+                    }
+                    break;
+                case PROCESSING_INTERMEDIATE2:
+                    if ((progress != 0) || (mProgressToApp != 0)) {
+                        actualProgress = 25 + progress/4;
+                    }
+                    break;
+                case PROCESSING_INTERMEDIATE3:
+                    if ((progress != 0) || (mProgressToApp != 0)) {
+                        actualProgress = 50 + progress/2;
+                    }
+                    break;
+                case PROCESSING_NONE:
+
+                default:
+                    Log.e("MediaArtistNativeHelper", "ERROR unexpected State=" + mProcessingState);
+                    return;
+            }
+            if ((mProgressToApp != actualProgress) && (actualProgress != 0)) {
+
+                mProgressToApp = actualProgress;
+
+                if (mMediaProcessingProgressListener != null) {
+                    // Send the progress indication
+                    mMediaProcessingProgressListener.onProgress(mProcessingObject,
+                                                                action,
+                                                                actualProgress);
+                }
+            }
+            /* avoid 0 in next intermediate call */
+            if (mProgressToApp == 0) {
+                if (mMediaProcessingProgressListener != null) {
+                    /*
+                     *  Send the progress indication
+                     */
+                    mMediaProcessingProgressListener.onProgress(mProcessingObject,
+                                                                action,
+                                                                actualProgress);
+                }
+                mProgressToApp = 1;
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private void onPreviewProgressUpdate(int progress, boolean isFinished) {
+        if (mPreviewProgressListener != null) {
+            mPreviewProgressListener.onProgress(mVideoEditor, progress, isFinished);
+            mPreviewProgress = progress;
+        }
+    }
+
+    /**
+     * Release the native helper object
+     */
+    public void releaseNativeHelper() {
+        try {
+            release();
+        } catch (IllegalStateException ex) {
+            Log.e("MediaArtistNativeHelper",
+            "Illegal State exeption caught in releaseNativeHelper");
+            throw ex;
+        } catch (RuntimeException ex) {
+            Log.e("MediaArtistNativeHelper", "Runtime exeption caught in releaseNativeHelper");
+            throw ex;
+        }
+    }
+
+    /**
+     * Release the native helper to end the Audio Graph process
+     */
+    @SuppressWarnings("unused")
+    private void onAudioGraphExtractProgressUpdate(int progress, boolean isVideo) {
+
+        if ((mExtractAudioWaveformProgressListener != null) && (progress > 0))
+        {
+            mExtractAudioWaveformProgressListener.onProgress(progress);
+        }
+    }
+
+    /**
+     * Populates the Effect Settings in EffectSettings
+     *
+     * @param effects The reference of EffectColor
+     *
+     * @return The populated effect settings in EffectSettings
+     * reference
+     */
+    EffectSettings getEffectSettings(EffectColor effects) {
+        EffectSettings effectSettings = new EffectSettings();
+        effectSettings.startTime = (int)effects.getStartTime();
+        effectSettings.duration = (int)effects.getDuration();
+        effectSettings.videoEffectType = getEffectColorType(effects);
+        effectSettings.audioEffectType = 0;
+        effectSettings.startPercent = 0;
+        effectSettings.durationPercent = 0;
+        effectSettings.framingFile = null;
+        effectSettings.topLeftX = 0;
+        effectSettings.topLeftY = 0;
+        effectSettings.framingResize = false;
+        effectSettings.text = null;
+        effectSettings.textRenderingData = null;
+        effectSettings.textBufferWidth = 0;
+        effectSettings.textBufferHeight = 0;
+        if (effects.getType() == EffectColor.TYPE_FIFTIES) {
+            effectSettings.fiftiesFrameRate = 15;
+        } else {
+            effectSettings.fiftiesFrameRate = 0;
+        }
+
+        if ((effectSettings.videoEffectType == VideoEffect.COLORRGB16)
+                || (effectSettings.videoEffectType == VideoEffect.GRADIENT)) {
+            effectSettings.rgb16InputColor = effects.getColor();
+        }
+
+        effectSettings.alphaBlendingStartPercent = 0;
+        effectSettings.alphaBlendingMiddlePercent = 0;
+        effectSettings.alphaBlendingEndPercent = 0;
+        effectSettings.alphaBlendingFadeInTimePercent = 0;
+        effectSettings.alphaBlendingFadeOutTimePercent = 0;
+        return effectSettings;
+    }
+
+    /**
+     * Populates the Overlay Settings in EffectSettings
+     *
+     * @param overlay The reference of OverlayFrame
+     *
+     * @return The populated overlay settings in EffectSettings
+     * reference
+     */
+    EffectSettings getOverlaySettings(OverlayFrame overlay) {
+        EffectSettings effectSettings = new EffectSettings();
+        Bitmap bitmap = null;
+
+        effectSettings.startTime = (int)overlay.getStartTime();
+        effectSettings.duration = (int)overlay.getDuration();
+        effectSettings.videoEffectType = VideoEffect.FRAMING;
+        effectSettings.audioEffectType = 0;
+        effectSettings.startPercent = 0;
+        effectSettings.durationPercent = 0;
+        effectSettings.framingFile = null;
+
+        if ((bitmap = overlay.getBitmap()) != null) {
+            effectSettings.framingFile = overlay.getFilename();
+
+            if (effectSettings.framingFile == null) {
+                try {
+                    (overlay).save(mProjectPath);
+                } catch (IOException e) {
+                    Log.e("MediaArtistNativeHelper","getOverlaySettings : File not found");
+                }
+                effectSettings.framingFile = overlay.getFilename();
+            }
+            if (bitmap.getConfig() == Bitmap.Config.ARGB_8888)
+                effectSettings.bitmapType = 6;
+            else if (bitmap.getConfig() == Bitmap.Config.ARGB_4444)
+                effectSettings.bitmapType = 5;
+            else if (bitmap.getConfig() == Bitmap.Config.RGB_565)
+                effectSettings.bitmapType = 4;
+            else if (bitmap.getConfig() == Bitmap.Config.ALPHA_8)
+                throw new RuntimeException("Bitmap config not supported");
+
+            effectSettings.width = bitmap.getWidth();
+            effectSettings.height = bitmap.getHeight();
+            effectSettings.framingBuffer = new int[effectSettings.width];
+            int tmp = 0;
+            short maxAlpha = 0;
+            short minAlpha = (short)0xFF;
+            short alpha = 0;
+            while (tmp < effectSettings.height) {
+                bitmap.getPixels(effectSettings.framingBuffer, 0,
+                                 effectSettings.width, 0, tmp,
+                                 effectSettings.width, 1);
+                for (int i = 0; i < effectSettings.width; i++) {
+                    alpha = (short)((effectSettings.framingBuffer[i] >> 24) & 0xFF);
+                    if (alpha > maxAlpha) {
+                        maxAlpha = alpha;
+                    }
+                    if (alpha < minAlpha) {
+                        minAlpha = alpha;
+                    }
+                }
+                tmp += 1;
+            }
+            alpha = (short)((maxAlpha + minAlpha) / 2);
+            alpha = (short)((alpha * 100) / 256);
+            effectSettings.alphaBlendingEndPercent = alpha;
+            effectSettings.alphaBlendingMiddlePercent = alpha;
+            effectSettings.alphaBlendingStartPercent = alpha;
+            effectSettings.alphaBlendingFadeInTimePercent = 100;
+            effectSettings.alphaBlendingFadeOutTimePercent = 100;
+            effectSettings.framingBuffer = null;
+        }
+
+        effectSettings.topLeftX = 0;
+        effectSettings.topLeftY = 0;
+
+        effectSettings.framingResize = true;
+        effectSettings.text = null;
+        effectSettings.textRenderingData = null;
+        effectSettings.textBufferWidth = 0;
+        effectSettings.textBufferHeight = 0;
+        effectSettings.fiftiesFrameRate = 0;
+        effectSettings.rgb16InputColor = 0;
+        int mediaItemHeight;
+        int aspectRatio;
+        if (overlay.getMediaItem() instanceof MediaImageItem) {
+            if (((MediaImageItem)overlay.getMediaItem()).getGeneratedImageClip() != null) {
+                //Kenburns was applied
+                mediaItemHeight = ((MediaImageItem)overlay.getMediaItem()).getGeneratedClipHeight();
+                aspectRatio = getAspectRatio(
+                    ((MediaImageItem)overlay.getMediaItem()).getGeneratedClipWidth()
+                    , mediaItemHeight);
+            }
+            else {
+                //For image get the scaled height. Aspect ratio would remain the same
+                mediaItemHeight = ((MediaImageItem)overlay.getMediaItem()).getScaledHeight();
+                aspectRatio = overlay.getMediaItem().getAspectRatio();
+                effectSettings.framingResize = false; //since the image can be of odd size.
+            }
+        } else {
+            aspectRatio = overlay.getMediaItem().getAspectRatio();
+            mediaItemHeight = overlay.getMediaItem().getHeight();
+        }
+        effectSettings.framingScaledSize = findVideoResolution(aspectRatio, mediaItemHeight);
+        return effectSettings;
+    }
+
+    /**
+     * Sets the audio regenerate flag
+     *
+     * @param flag The boolean to set the audio regenerate flag
+     *
+     */
+    void setAudioflag(boolean flag) {
+        //check if the file exists.
+        if (!(new File(String.format(mProjectPath + "/" + AUDIO_TRACK_PCM_FILE)).exists())) {
+            flag = true;
+        }
+        mRegenerateAudio = flag;
+    }
+
+    /**
+     * Gets the audio regenerate flag
+     *
+     * @param return The boolean to get the audio regenerate flag
+     *
+     */
+    boolean getAudioflag() {
+        return mRegenerateAudio;
+    }
+
+    /**
+     * Maps the average frame rate to one of the defined enum values
+     *
+     * @param averageFrameRate The average frame rate of video item
+     *
+     * @return The frame rate from one of the defined enum values
+     */
+    public int GetClosestVideoFrameRate(int averageFrameRate) {
+        if (averageFrameRate >= 25) {
+            return VideoFrameRate.FR_30_FPS;
+        } else if (averageFrameRate >= 20) {
+            return VideoFrameRate.FR_25_FPS;
+        } else if (averageFrameRate >= 15) {
+            return VideoFrameRate.FR_20_FPS;
+        } else if (averageFrameRate >= 12) {
+            return VideoFrameRate.FR_15_FPS;
+        } else if (averageFrameRate >= 10) {
+            return VideoFrameRate.FR_12_5_FPS;
+        } else if (averageFrameRate >= 7) {
+            return VideoFrameRate.FR_10_FPS;
+        } else if (averageFrameRate >= 5) {
+            return VideoFrameRate.FR_7_5_FPS;
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * Helper function to adjust the effect or overlay start time
+     * depending on the begin and end boundary time of meddia item
+     */
+    public void adjustEffectsStartTimeAndDuration(EffectSettings lEffect,
+                                                  int beginCutTime,
+                                                  int endCutTime) {
+
+        int effectStartTime = 0;
+        int effectDuration = 0;
+
+        /**
+         * cbct -> clip begin cut time
+         * cect -> clip end cut time
+         ****************************************
+         *  |                                 |
+         *  |         cbct        cect        |
+         *  | <-1-->   |           |          |
+         *  |       <--|-2->       |          |
+         *  |          | <---3---> |          |
+         *  |          |        <--|-4--->    |
+         *  |          |           | <--5-->  |
+         *  |      <---|------6----|---->     |
+         *  |                                 |
+         *  < : effectStart
+         *  > : effectStart + effectDuration
+         ****************************************
+         **/
+
+        /** 1 & 5 */
+        /**
+         * Effect falls out side the trim duration. In such a case effects shall
+         * not be applied.
+         */
+        if ((lEffect.startTime > endCutTime)
+                || ((lEffect.startTime + lEffect.duration) <= beginCutTime)) {
+
+            effectStartTime = 0;
+            effectDuration = 0;
+
+            lEffect.startTime = effectStartTime;
+            lEffect.duration = effectDuration;
+            return;
+        }
+
+        /** 2 */
+        if ((lEffect.startTime < beginCutTime)
+                && ((lEffect.startTime + lEffect.duration) > beginCutTime)
+                && ((lEffect.startTime + lEffect.duration) <= endCutTime)) {
+            effectStartTime = 0;
+            effectDuration = lEffect.duration;
+
+            effectDuration -= (beginCutTime - lEffect.startTime);
+            lEffect.startTime = effectStartTime;
+            lEffect.duration = effectDuration;
+            return;
+        }
+
+        /** 3 */
+        if ((lEffect.startTime >= beginCutTime)
+                && ((lEffect.startTime + lEffect.duration) <= endCutTime)) {
+            effectStartTime = lEffect.startTime - beginCutTime;
+            lEffect.startTime = effectStartTime;
+            lEffect.duration = lEffect.duration;
+            return;
+        }
+
+        /** 4 */
+        if ((lEffect.startTime >= beginCutTime)
+                && ((lEffect.startTime + lEffect.duration) > endCutTime)) {
+            effectStartTime = lEffect.startTime - beginCutTime;
+            effectDuration = endCutTime - lEffect.startTime;
+            lEffect.startTime = effectStartTime;
+            lEffect.duration = effectDuration;
+            return;
+        }
+
+        /** 6 */
+        if ((lEffect.startTime < beginCutTime)
+                && ((lEffect.startTime + lEffect.duration) > endCutTime)) {
+            effectStartTime = 0;
+            effectDuration = endCutTime - beginCutTime;
+            lEffect.startTime = effectStartTime;
+            lEffect.duration = effectDuration;
+            return;
+        }
+
+    }
+
+    /**
+     * Generates the clip for preview or export
+     *
+     * @param editSettings The EditSettings reference for generating
+     * a clip for preview or export
+     *
+     * @return error value
+     */
+    public int generateClip(EditSettings editSettings) {
+        int err = 0;
+
+        try {
+            err = nativeGenerateClip(editSettings);
+        } catch (IllegalArgumentException ex) {
+            Log.e("MediaArtistNativeHelper","Illegal Argument exception in load settings");
+            return -1;
+        } catch (IllegalStateException ex) {
+            Log.e("MediaArtistNativeHelper","Illegal state exception in load settings");
+            return -1;
+        } catch (RuntimeException ex) {
+            Log.e("MediaArtistNativeHelper", "Runtime exception in load settings");
+            return -1;
+        }
+        return err;
+    }
+
+    /**
+     * Init function to initialise the  ClipSettings reference to
+     * default values
+     *
+     * @param lclipSettings The ClipSettings reference
+     */
+    void initClipSettings(ClipSettings lclipSettings) {
+        lclipSettings.clipPath = null;
+        lclipSettings.clipDecodedPath = null;
+        lclipSettings.clipOriginalPath = null;
+        lclipSettings.fileType = 0;
+        lclipSettings.endCutTime = 0;
+        lclipSettings.beginCutTime = 0;
+        lclipSettings.beginCutPercent = 0;
+        lclipSettings.endCutPercent = 0;
+        lclipSettings.panZoomEnabled = false;
+        lclipSettings.panZoomPercentStart = 0;
+        lclipSettings.panZoomTopLeftXStart = 0;
+        lclipSettings.panZoomTopLeftYStart = 0;
+        lclipSettings.panZoomPercentEnd = 0;
+        lclipSettings.panZoomTopLeftXEnd = 0;
+        lclipSettings.panZoomTopLeftYEnd = 0;
+        lclipSettings.mediaRendering = 0;
+    }
+
+
+    /**
+     * Populates the settings for generating an effect clip
+     *
+     * @param lMediaItem The media item for which the effect clip
+     * needs to be generated
+     * @param lclipSettings The ClipSettings reference containing
+     * clips data
+     * @param e The EditSettings reference containing effect specific data
+     * @param uniqueId The unique id used in the name of the output clip
+     * @param clipNo Used for internal purpose
+     *
+     * @return The name and path of generated clip
+     */
+    String generateEffectClip(MediaItem lMediaItem, ClipSettings lclipSettings,
+            EditSettings e,String uniqueId,int clipNo) {
+        int err = 0;
+        EditSettings editSettings = null;
+        String EffectClipPath = null;
+
+        editSettings = new EditSettings();
+
+        editSettings.clipSettingsArray = new ClipSettings[1];
+        editSettings.clipSettingsArray[0] = lclipSettings;
+
+        editSettings.backgroundMusicSettings = null;
+        editSettings.transitionSettingsArray = null;
+        editSettings.effectSettingsArray = e.effectSettingsArray;
+
+        EffectClipPath = String.format(mProjectPath + "/" + "ClipEffectIntermediate" + "_"
+                + lMediaItem.getId() + uniqueId + ".3gp");
+
+        File tmpFile = new File(EffectClipPath);
+        if (tmpFile.exists()) {
+            tmpFile.delete();
+        }
+
+        if (lMediaItem instanceof MediaVideoItem) {
+            MediaVideoItem m = (MediaVideoItem)lMediaItem;
+
+            editSettings.audioFormat = AudioFormat.AAC;
+            editSettings.audioChannels = 2;
+            editSettings.audioBitrate = Bitrate.BR_64_KBPS;
+            editSettings.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;
+
+            editSettings.videoBitrate = Bitrate.BR_5_MBPS;
+            //editSettings.videoFormat = VideoFormat.MPEG4;
+            editSettings.videoFormat = VideoFormat.H264;
+            editSettings.videoFrameRate = VideoFrameRate.FR_30_FPS;
+            editSettings.videoFrameSize = findVideoResolution(mVideoEditor.getAspectRatio(), m
+                    .getHeight());
+
+        } else {
+            MediaImageItem m = (MediaImageItem)lMediaItem;
+            editSettings.audioBitrate = Bitrate.BR_64_KBPS;
+            editSettings.audioChannels = 2;
+            editSettings.audioFormat = AudioFormat.AAC;
+            editSettings.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;
+
+            editSettings.videoBitrate = Bitrate.BR_5_MBPS;
+            editSettings.videoFormat = VideoFormat.H264;
+            editSettings.videoFrameRate = VideoFrameRate.FR_30_FPS;
+            editSettings.videoFrameSize = findVideoResolution(mVideoEditor.getAspectRatio(), m
+                    .getScaledHeight());
+        }
+
+        editSettings.outputFile = EffectClipPath;
+
+        if (clipNo == 1) {
+            mProcessingState  = PROCESSING_INTERMEDIATE1;
+        } else if (clipNo == 2) {
+            mProcessingState  = PROCESSING_INTERMEDIATE2;
+        }
+        mProcessingObject = lMediaItem;
+        err = generateClip(editSettings);
+        mProcessingState  = PROCESSING_NONE;
+
+        if (err == 0) {
+            lclipSettings.clipPath = EffectClipPath;
+            lclipSettings.fileType = FileType.THREE_GPP;
+            return EffectClipPath;
+        } else {
+            throw new RuntimeException("preview generation cannot be completed");
+        }
+    }
+
+
+    /**
+     * Populates the settings for generating a Ken Burn effect clip
+     *
+     * @param m The media image item for which the Ken Burn effect clip
+     * needs to be generated
+     * @param e The EditSettings reference clip specific data
+     *
+     * @return The name and path of generated clip
+     */
+    String generateKenBurnsClip(EditSettings e, MediaImageItem m) {
+        String output = null;
+        int err = 0;
+
+        e.backgroundMusicSettings = null;
+        e.transitionSettingsArray = null;
+        e.effectSettingsArray = null;
+        output = String.format(mProjectPath + "/" + "ImageClip-" + m.getId() + ".3gp");
+
+        File tmpFile = new File(output);
+        if (tmpFile.exists()) {
+            tmpFile.delete();
+        }
+
+        e.outputFile = output;
+        e.audioBitrate = Bitrate.BR_64_KBPS;
+        e.audioChannels = 2;
+        e.audioFormat = AudioFormat.AAC;
+        e.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;
+
+        e.videoBitrate = Bitrate.BR_5_MBPS;
+        e.videoFormat = VideoFormat.H264;
+        e.videoFrameRate = VideoFrameRate.FR_30_FPS;
+        e.videoFrameSize = findVideoResolution(mVideoEditor.getAspectRatio(),
+                                                           m.getScaledHeight());
+        mProcessingState  = PROCESSING_KENBURNS;
+        mProcessingObject = m;
+        err = generateClip(e);
+        // Reset the processing state and check for errors
+        mProcessingState  = PROCESSING_NONE;
+        if (err != 0) {
+            throw new RuntimeException("preview generation cannot be completed");
+        }
+        return output;
+    }
+
+
+    /**
+     * Calculates the output resolution for transition clip
+     *
+     * @param m1 First media item associated with transition
+     * @param m2 Second media item associated with transition
+     *
+     * @return The transition resolution
+     */
+    private int getTransitionResolution(MediaItem m1, MediaItem m2) {
+        int clip1Height = 0;
+        int clip2Height = 0;
+        int videoSize = 0;
+
+        if (m1 != null && m2 != null) {
+            if (m1 instanceof MediaVideoItem) {
+                clip1Height = m1.getHeight();
+            } else if (m1 instanceof MediaImageItem) {
+                clip1Height = ((MediaImageItem)m1).getScaledHeight();
+            }
+            if (m2 instanceof MediaVideoItem) {
+                clip2Height = m2.getHeight();
+            } else if (m2 instanceof MediaImageItem) {
+                clip2Height = ((MediaImageItem)m2).getScaledHeight();
+            }
+            if (clip1Height > clip2Height) {
+                videoSize = findVideoResolution(mVideoEditor.getAspectRatio(),
+                                                                   clip1Height);
+            } else {
+                videoSize = findVideoResolution(mVideoEditor.getAspectRatio(),
+                                                                   clip2Height);
+            }
+        } else if (m1 == null && m2 != null) {
+            if (m2 instanceof MediaVideoItem) {
+                clip2Height = m2.getHeight();
+            } else if (m2 instanceof MediaImageItem) {
+                clip2Height = ((MediaImageItem)m2).getScaledHeight();
+            }
+            videoSize = findVideoResolution(mVideoEditor.getAspectRatio(),
+                                                                   clip2Height);
+        } else if (m1 != null && m2 == null) {
+            if (m1 instanceof MediaVideoItem) {
+                clip1Height = m1.getHeight();
+            } else if (m1 instanceof MediaImageItem) {
+                clip1Height = ((MediaImageItem)m1).getScaledHeight();
+            }
+            videoSize = findVideoResolution(mVideoEditor.getAspectRatio(),
+                                                                   clip1Height);
+        }
+        return videoSize;
+    }
+
+    /**
+     * Populates the settings for generating an transition clip
+     *
+     * @param m1 First media item associated with transition
+     * @param m2 Second media item associated with transition
+     * @param e The EditSettings reference containing
+     * clip specific data
+     * @param uniqueId The unique id used in the name of the output clip
+     * @param t The Transition specific data
+     *
+     * @return The name and path of generated clip
+     */
+    String generateTransitionClip(EditSettings e, String uniqueId,
+            MediaItem m1, MediaItem m2,Transition t) {
+        String outputFilename = null;
+        int err = 0;
+
+        outputFilename = String.format(mProjectPath + "/" + uniqueId + ".3gp");
+        e.outputFile = outputFilename;
+        e.audioBitrate = Bitrate.BR_64_KBPS;
+        e.audioChannels = 2;
+        e.audioFormat = AudioFormat.AAC;
+        e.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;
+
+        e.videoBitrate = Bitrate.BR_5_MBPS;
+        e.videoFormat = VideoFormat.H264;
+        e.videoFrameRate = VideoFrameRate.FR_30_FPS;
+        e.videoFrameSize = getTransitionResolution(m1, m2);
+
+        if (new File(outputFilename).exists()) {
+            new File(outputFilename).delete();
+        }
+        mProcessingState  = PROCESSING_INTERMEDIATE3;
+        mProcessingObject = t;
+        err = generateClip(e);
+        // Reset the processing state and check for errors
+        mProcessingState  = PROCESSING_NONE;
+        if (err != 0) {
+            throw new RuntimeException("preview generation cannot be completed");
+        }
+        return outputFilename;
+    }
+
+    /**
+     * Populates effects and overlays in EffectSettings structure
+     * and also adjust the start time and duration of effects and overlays
+     * w.r.t to total story board time
+     *
+     * @param m1 Media item associated with effect
+     * @param effectSettings The EffectSettings reference containing
+     * effect specific data
+     * @param beginCutTime The begin cut time of the clip associated with effect
+     * @param endCutTime The end cut time of the clip associated with effect
+     * @param storyBoardTime The current story board time
+     *
+     * @return The updated index
+     */
+    private int populateEffects(MediaItem m, EffectSettings[] effectSettings, int i,
+            int beginCutTime, int endCutTime, int storyBoardTime) {
+        List<Effect> effects = m.getAllEffects();
+        List<Overlay> overlays = m.getAllOverlays();
+
+        if (m.getBeginTransition() != null && m.getBeginTransition().getDuration() > 0
+                && m.getEndTransition() != null && m.getEndTransition().getDuration() > 0) {
+            beginCutTime += m.getBeginTransition().getDuration();
+            endCutTime -= m.getEndTransition().getDuration();
+        } else if (m.getBeginTransition() == null && m.getEndTransition() != null
+                && m.getEndTransition().getDuration() > 0) {
+            endCutTime -= m.getEndTransition().getDuration();
+        } else if (m.getEndTransition() == null && m.getBeginTransition() != null
+                && m.getBeginTransition().getDuration() > 0) {
+            beginCutTime += m.getBeginTransition().getDuration();
+        }
+
+        for (Effect effect : effects) {
+            if (effect instanceof EffectColor) {
+                effectSettings[i] = getEffectSettings((EffectColor)effect);
+                adjustEffectsStartTimeAndDuration(effectSettings[i],
+                                                      beginCutTime, endCutTime);
+                effectSettings[i].startTime += storyBoardTime;
+                i++;
+            }
+        }
+        for (Overlay overlay : overlays) {
+            effectSettings[i] = getOverlaySettings((OverlayFrame)overlay);
+            adjustEffectsStartTimeAndDuration(effectSettings[i],
+                                                      beginCutTime, endCutTime);
+            effectSettings[i].startTime += storyBoardTime;
+            i++;
+        }
+        return i;
+    }
+
+    /**
+     * Adjusts the media item boundaries for use in export or preview
+     *
+     * @param clipSettings The ClipSettings reference
+     * @param clipProperties The Properties reference
+     * @param m The media item
+     */
+    private void adjustMediaItemBoundary(ClipSettings clipSettings,
+                                         Properties clipProperties, MediaItem m) {
+        if (m.getBeginTransition() != null && m.getBeginTransition().getDuration() > 0
+                && m.getEndTransition() != null && m.getEndTransition().getDuration() > 0) {
+
+            clipSettings.beginCutTime += m.getBeginTransition().getDuration();
+            clipSettings.endCutTime -= m.getEndTransition().getDuration();
+
+        } else if (m.getBeginTransition() == null && m.getEndTransition() != null
+                && m.getEndTransition().getDuration() > 0) {
+
+            clipSettings.endCutTime -= m.getEndTransition().getDuration();
+
+        } else if (m.getEndTransition() == null && m.getBeginTransition() != null
+                && m.getBeginTransition().getDuration() > 0) {
+
+            clipSettings.beginCutTime += m.getBeginTransition().getDuration();
+        }
+        clipProperties.duration = clipSettings.endCutTime -
+                                                      clipSettings.beginCutTime;
+
+        if (clipProperties.videoDuration != 0) {
+            clipProperties.videoDuration = clipSettings.endCutTime -
+                                                      clipSettings.beginCutTime;
+        }
+
+        if (clipProperties.audioDuration != 0) {
+            clipProperties.audioDuration = clipSettings.endCutTime -
+                                                      clipSettings.beginCutTime;
+        }
+    }
+
+    /**
+     * Generates the transition if transition is present
+     * and is in invalidated state
+     *
+     * @param transition The Transition reference
+     * @param editSettings The EditSettings reference
+     * @param clipPropertiesArray The clip Properties array
+     * @param i The index in clip Properties array for current clip
+     */
+    private void generateTransition(Transition transition, EditSettings editSettings,
+            PreviewClipProperties clipPropertiesArray, int index) {
+        if (!(transition.isGenerated())) {
+            transition.generate();
+        }
+        editSettings.clipSettingsArray[index] = new ClipSettings();
+        editSettings.clipSettingsArray[index].clipPath = transition.getFilename();
+        editSettings.clipSettingsArray[index].fileType = FileType.THREE_GPP;
+        editSettings.clipSettingsArray[index].beginCutTime = 0;
+        editSettings.clipSettingsArray[index].endCutTime =
+                                                  (int)transition.getDuration();
+        editSettings.clipSettingsArray[index].mediaRendering =
+                                                   MediaRendering.BLACK_BORDERS;
+        try {
+            clipPropertiesArray.clipProperties[index] =
+                                   getMediaProperties(transition.getFilename());
+        } catch (Exception e) {
+            throw new IllegalArgumentException("Unsupported file or file not found");
+        }
+        clipPropertiesArray.clipProperties[index].Id = null;
+        clipPropertiesArray.clipProperties[index].audioVolumeValue = 100;
+        clipPropertiesArray.clipProperties[index].duration =
+                                                  (int)transition.getDuration();
+        if (clipPropertiesArray.clipProperties[index].videoDuration != 0) {
+            clipPropertiesArray.clipProperties[index].videoDuration =
+                                                  (int)transition.getDuration();
+        }
+        if (clipPropertiesArray.clipProperties[index].audioDuration != 0) {
+            clipPropertiesArray.clipProperties[index].audioDuration =
+                                                  (int)transition.getDuration();
+        }
+    }
+
+    /**
+     * Sets the volume for current media item in clip properties array
+     *
+     * @param m The media item
+     * @param clipProperties The clip properties array reference
+     * @param i The index in clip Properties array for current clip
+     */
+    private void adjustVolume(MediaItem m, PreviewClipProperties clipProperties,
+                              int index) {
+        if (m instanceof MediaVideoItem) {
+            boolean videoMuted = ((MediaVideoItem)m).isMuted();
+            if (videoMuted == false) {
+                mClipProperties.clipProperties[index].audioVolumeValue = ((MediaVideoItem)m)
+                .getVolume();
+            } else {
+                mClipProperties.clipProperties[index].audioVolumeValue = 0;
+            }
+        } else if (m instanceof MediaImageItem) {
+            mClipProperties.clipProperties[index].audioVolumeValue = 0;
+        }
+    }
+
+    /**
+     * Checks for odd size image width and height
+     *
+     * @param m The media item
+     * @param clipProperties The clip properties array reference
+     * @param i The index in clip Properties array for current clip
+     */
+    private void checkOddSizeImage(MediaItem m, PreviewClipProperties clipProperties, int index) {
+        if (m instanceof MediaImageItem) {
+            int width = mClipProperties.clipProperties[index].width;
+            int height = mClipProperties.clipProperties[index].height;
+
+            if ((width % 2) != 0) {
+                width -= 1;
+            }
+            if ((height % 2) != 0) {
+                height -= 1;
+            }
+            mClipProperties.clipProperties[index].width = width;
+            mClipProperties.clipProperties[index].height = height;
+        }
+    }
+
+    /**
+     * Populates the media item properties and calculates the maximum
+     * height among all the clips
+     *
+     * @param m The media item
+     * @param i The index in clip Properties array for current clip
+     * @param maxHeight The max height from the clip properties
+     *
+     * @return Updates the max height if current clip's height is greater
+     * than all previous clips height
+     */
+    private int populateMediaItemProperties(MediaItem m, int index, int maxHeight) {
+        mPreviewEditSettings.clipSettingsArray[index] = new ClipSettings();
+        if (m instanceof MediaVideoItem) {
+            mPreviewEditSettings.clipSettingsArray[index] = ((MediaVideoItem)m)
+            .getVideoClipProperties();
+            if (((MediaVideoItem)m).getHeight() > maxHeight) {
+                maxHeight = ((MediaVideoItem)m).getHeight();
+            }
+        } else if (m instanceof MediaImageItem) {
+            mPreviewEditSettings.clipSettingsArray[index] = ((MediaImageItem)m)
+            .getImageClipProperties();
+            if (((MediaImageItem)m).getScaledHeight() > maxHeight) {
+                maxHeight = ((MediaImageItem)m).getScaledHeight();
+            }
+        }
+        /** + Handle the image files here */
+        if (mPreviewEditSettings.clipSettingsArray[index].fileType == FileType.JPG) {
+            mPreviewEditSettings.clipSettingsArray[index].clipDecodedPath = ((MediaImageItem)m)
+            .getDecodedImageFileName();
+
+            mPreviewEditSettings.clipSettingsArray[index].clipOriginalPath =
+                         mPreviewEditSettings.clipSettingsArray[index].clipPath;
+        }
+        return maxHeight;
+    }
+
+    /**
+     * Populates the background music track properties
+     *
+     * @param mediaBGMList The background music list
+     *
+     */
+    private void populateBackgroundMusicProperties(List<AudioTrack> mediaBGMList) {
+
+        if (mediaBGMList.size() == 1) {
+            mAudioTrack = mediaBGMList.get(0);
+        } else
+        {
+            mAudioTrack = null;
+        }
+
+        if (mAudioTrack != null) {
+            mAudioSettings = new AudioSettings();
+            Properties mAudioProperties = new Properties();
+            mAudioSettings.pFile = null;
+            mAudioSettings.Id = mAudioTrack.getId();
+            try {
+                mAudioProperties = getMediaProperties(mAudioTrack.getFilename());
+            } catch (Exception e) {
+               throw new IllegalArgumentException("Unsupported file or file not found");
+            }
+            mAudioSettings.bRemoveOriginal = false;
+            mAudioSettings.channels = mAudioProperties.audioChannels;
+            mAudioSettings.Fs = mAudioProperties.audioSamplingFrequency;
+            mAudioSettings.loop = mAudioTrack.isLooping();
+            mAudioSettings.ExtendedFs = 0;
+            mAudioSettings.pFile = mAudioTrack.getFilename();
+            mAudioSettings.startMs = mAudioTrack.getStartTime();
+            mAudioSettings.beginCutTime = mAudioTrack.getBoundaryBeginTime();
+            mAudioSettings.endCutTime = mAudioTrack.getBoundaryEndTime();
+            if (mAudioTrack.isMuted()) {
+                mAudioSettings.volume = 0;
+            } else {
+                mAudioSettings.volume = mAudioTrack.getVolume();
+            }
+            mAudioSettings.fileType = mAudioProperties.fileType;
+            mAudioSettings.ducking_lowVolume = mAudioTrack.getDuckedTrackVolume();
+            mAudioSettings.ducking_threshold = mAudioTrack.getDuckingThreshhold();
+            mAudioSettings.bInDucking_enable = mAudioTrack.isDuckingEnabled();
+            mAudioTrackPCMFilePath = String.format(mProjectPath + "/" + AUDIO_TRACK_PCM_FILE);
+            //String.format(mProjectPath + "/" + "AudioPcm" + ".pcm");
+            mAudioSettings.pcmFilePath = mAudioTrackPCMFilePath;
+
+            mPreviewEditSettings.backgroundMusicSettings =
+                                                  new BackgroundMusicSettings();
+            mPreviewEditSettings.backgroundMusicSettings.file =
+                                                         mAudioTrackPCMFilePath;
+            mPreviewEditSettings.backgroundMusicSettings.fileType =
+                                                      mAudioProperties.fileType;
+            mPreviewEditSettings.backgroundMusicSettings.insertionTime =
+                                                     mAudioTrack.getStartTime();
+            mPreviewEditSettings.backgroundMusicSettings.volumePercent =
+                                                        mAudioTrack.getVolume();
+            mPreviewEditSettings.backgroundMusicSettings.beginLoop = mAudioTrack
+            .getBoundaryBeginTime();
+            mPreviewEditSettings.backgroundMusicSettings.endLoop =
+                                               mAudioTrack.getBoundaryEndTime();
+            mPreviewEditSettings.backgroundMusicSettings.enableDucking = mAudioTrack
+            .isDuckingEnabled();
+            mPreviewEditSettings.backgroundMusicSettings.duckingThreshold = mAudioTrack
+            .getDuckingThreshhold();
+            mPreviewEditSettings.backgroundMusicSettings.lowVolume = mAudioTrack
+            .getDuckedTrackVolume();
+            mPreviewEditSettings.backgroundMusicSettings.isLooping =
+                                                        mAudioTrack.isLooping();
+            mPreviewEditSettings.primaryTrackVolume = 100;
+            mProcessingState  = PROCESSING_AUDIO_PCM;
+            mProcessingObject = mAudioTrack;
+        } else {
+            if (mAudioSettings != null) {
+                mAudioSettings = null;
+            }
+            if (mPreviewEditSettings.backgroundMusicSettings != null) {
+                mPreviewEditSettings.backgroundMusicSettings = null;
+            }
+            mAudioTrackPCMFilePath = null;
+        }
+    }
+
+    /**
+     * Calculates all the effects in all the media items
+     * in media items list
+     *
+     * @param mediaItemsList The media item list
+     *
+     * @return The total number of effects
+     *
+     */
+    private int getTotalEffects(List<MediaItem> mediaItemsList) {
+        int totalEffects = 0;
+        final Iterator<MediaItem> it = mediaItemsList.iterator();
+        while (it.hasNext()) {
+            final MediaItem t = it.next();
+            totalEffects += t.getAllEffects().size();
+            totalEffects += t.getAllOverlays().size();
+            final Iterator<Effect> ef = t.getAllEffects().iterator();
+            while (ef.hasNext()) {
+                final Effect e = ef.next();
+                if (e instanceof EffectKenBurns)
+                    totalEffects--;
+            }
+        }
+        return totalEffects;
+    }
+
+    /**
+     * This function is responsible for forming clip settings
+     * array and clip properties array including transition clips
+     * and effect settings for preview purpose or export.
+     *
+     *
+     * @param mediaItemsList The media item list
+     * @param mediaTransitionList The transitions list
+     * @param mediaBGMList The background music list
+     * @param listener The MediaProcessingProgressListener
+     *
+     */
+    public void previewStoryBoard(List<MediaItem> mediaItemsList,
+            List<Transition> mediaTransitionList, List<AudioTrack> mediaBGMList,
+            MediaProcessingProgressListener listener) {
+        if (mInvalidatePreviewArray) {
+            int previewIndex = 0;
+            int totalEffects = 0;
+            int storyBoardTime = 0;
+            int maxHeight = 0;
+            int beginCutTime = 0;
+            int endCutTime = 0;
+            int effectIndex = 0;
+            Transition lTransition = null;
+            MediaItem lMediaItem = null;
+            mPreviewEditSettings = new EditSettings();
+            mClipProperties = new PreviewClipProperties();
+            mTotalClips = 0;
+
+            mTotalClips = mediaItemsList.size();
+            for (Transition transition : mediaTransitionList) {
+                if (transition.getDuration() > 0)
+                    mTotalClips++;
+            }
+
+            totalEffects = getTotalEffects(mediaItemsList);
+
+            mPreviewEditSettings.clipSettingsArray = new ClipSettings[mTotalClips];
+            mPreviewEditSettings.effectSettingsArray = new EffectSettings[totalEffects];
+            mClipProperties.clipProperties = new Properties[mTotalClips];
+
+            /** record the call back progress listner */
+            if (listener != null)
+            {
+                mMediaProcessingProgressListener = listener;
+                mProgressToApp = 0;
+            }
+
+            if (mediaItemsList.size() > 0) {
+                for (int i = 0; i < mediaItemsList.size(); i++) {
+                    /* Get the Media Item from the list */
+                    lMediaItem = mediaItemsList.get(i);
+                    if (lMediaItem instanceof MediaVideoItem) {
+                        beginCutTime = (int)((MediaVideoItem)lMediaItem).getBoundaryBeginTime();
+                        endCutTime = (int)((MediaVideoItem)lMediaItem).getBoundaryEndTime();
+                    } else if (lMediaItem instanceof MediaImageItem) {
+                        beginCutTime = 0;
+                        endCutTime = (int)((MediaImageItem)lMediaItem).getTimelineDuration();
+                    }
+                    /* Get the transition associated with Media Item */
+                    lTransition = lMediaItem.getBeginTransition();
+                    if (lTransition != null && (lTransition.getDuration() > 0)) {
+                        /* generate transition clip */
+                        generateTransition(lTransition, mPreviewEditSettings,
+                                           mClipProperties, previewIndex);
+                        storyBoardTime += mClipProperties.clipProperties[previewIndex].duration;
+                        previewIndex++;
+                    }
+                    /* Populate media item properties */
+                    maxHeight = populateMediaItemProperties(lMediaItem,
+                                                            previewIndex,
+                                                            maxHeight);
+                    if (lMediaItem instanceof MediaImageItem)
+                    {
+                        int tmpCnt = 0;
+                        boolean bEffectKbPresent = false;
+                        List<Effect> effectList = lMediaItem.getAllEffects();
+                        /**
+                         * check if Kenburns effect is present
+                         */
+                        while ( tmpCnt < effectList.size()) {
+                            if (effectList.get(tmpCnt) instanceof EffectKenBurns) {
+                                bEffectKbPresent = true;
+                                break;
+                            }
+                            tmpCnt++;
+                        }
+
+                        if (bEffectKbPresent) {
+                            try {
+                                mClipProperties.clipProperties[previewIndex]
+                                    = getMediaProperties(((MediaImageItem)lMediaItem).getGeneratedImageClip());
+                            } catch (Exception e) {
+                                throw new IllegalArgumentException("Unsupported file or file not found");
+                            }
+                        } else {
+                            try {
+                                mClipProperties.clipProperties[previewIndex]
+                                    = getMediaProperties(((MediaImageItem)lMediaItem).getScaledImageFileName());
+                            } catch (Exception e) {
+                                throw new IllegalArgumentException("Unsupported file or file not found");
+                            }
+                            mClipProperties.clipProperties[previewIndex].width = ((MediaImageItem)lMediaItem).getScaledWidth();
+                            mClipProperties.clipProperties[previewIndex].height = ((MediaImageItem)lMediaItem).getScaledHeight();
+                        }
+
+                    }else
+                    {
+                        try {
+                            mClipProperties.clipProperties[previewIndex]
+                                 = getMediaProperties(lMediaItem.getFilename());
+                        } catch (Exception e) {
+                            throw new IllegalArgumentException("Unsupported file or file not found");
+                        }
+                    }
+                    mClipProperties.clipProperties[previewIndex].Id = lMediaItem.getId();
+                    checkOddSizeImage(lMediaItem, mClipProperties, previewIndex);
+                    adjustVolume(lMediaItem, mClipProperties, previewIndex);
+
+                    /*
+                     * Adjust media item start time and end time w.r.t to begin
+                     * and end transitions associated with media item
+                     */
+
+                    adjustMediaItemBoundary(mPreviewEditSettings.clipSettingsArray[previewIndex],
+                            mClipProperties.clipProperties[previewIndex], lMediaItem);
+
+                    /*
+                     * Get all the effects and overlays for that media item and
+                     * adjust start time and duration of effects
+                     */
+
+                    effectIndex = populateEffects(lMediaItem,
+                            mPreviewEditSettings.effectSettingsArray, effectIndex, beginCutTime,
+                            endCutTime, storyBoardTime);
+                    storyBoardTime += mClipProperties.clipProperties[previewIndex].duration;
+                    previewIndex++;
+
+                    /* Check if there is any end transition at last media item */
+
+                    if (i == (mediaItemsList.size() - 1)) {
+                        lTransition = lMediaItem.getEndTransition();
+                        if (lTransition != null && (lTransition.getDuration() > 0)) {
+                            generateTransition(lTransition, mPreviewEditSettings, mClipProperties,
+                                    previewIndex);
+                            break;
+                        }
+                    }
+                }
+            }
+            if (!mErrorFlagSet) {
+                mPreviewEditSettings.videoFrameSize = findVideoResolution(mVideoEditor
+                        .getAspectRatio(), maxHeight);
+                /*if (mediaBGMList.size() == 1) //for remove Audio check */ {
+                    populateBackgroundMusicProperties(mediaBGMList);
+                }
+                /** call to native populate settings */
+                try {
+                    nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);
+                } catch (IllegalArgumentException ex) {
+                    Log.e("MediaArtistNativeHelper",
+                    "Illegal argument exception in nativePopulateSettings");
+                    throw ex;
+                } catch (IllegalStateException ex) {
+                    Log.e("MediaArtistNativeHelper",
+                    "Illegal state exception in nativePopulateSettings");
+                    throw ex;
+                } catch (RuntimeException ex) {
+                    Log.e("MediaArtistNativeHelper", "Runtime exception in nativePopulateSettings");
+                    throw ex;
+                }
+                mInvalidatePreviewArray = false;
+                mProcessingState  = PROCESSING_NONE;
+            }
+            if (mErrorFlagSet) {
+                mErrorFlagSet = false;
+                throw new RuntimeException("preview generation cannot be completed");
+            }
+        }
+    } /* END of previewStoryBoard */
+
+    /**
+     * This function is responsible for starting the preview
+     *
+     *
+     * @param surface The surface on which preview has to be displayed
+     * @param fromMs The time in ms from which preview has to be started
+     * @param toMs The time in ms till preview has to be played
+     * @param loop To loop the preview or not
+     * @param callbackAfterFrameCount INdicated after how many frames
+     * the callback is needed
+     * @param listener The PreviewProgressListener
+     *
+     */
+    public void doPreview(Surface surface, long fromMs, long toMs, boolean loop,
+            int callbackAfterFrameCount, PreviewProgressListener listener) {
+        mPreviewProgress = 0;
+        if (listener != null) {
+            mPreviewProgressListener = listener;
+        }
+        if (!mInvalidatePreviewArray) {
+            try {
+                /** Modify the image files names to rgb image files. */
+                for (int clipCnt = 0; clipCnt < mPreviewEditSettings.clipSettingsArray.length; clipCnt++) {
+                    if (mPreviewEditSettings.clipSettingsArray[clipCnt].fileType == FileType.JPG) {
+                        mPreviewEditSettings.clipSettingsArray[clipCnt].clipPath = mPreviewEditSettings.clipSettingsArray[clipCnt].clipDecodedPath;
+                    }
+                }
+                nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);
+                nativeStartPreview(surface, fromMs, toMs, callbackAfterFrameCount, loop);
+            } catch (IllegalArgumentException ex) {
+                Log.e("MediaArtistNativeHelper",
+                "Illegal argument exception in nativeStartPreview");
+                throw ex;
+            } catch (IllegalStateException ex) {
+                Log.e("MediaArtistNativeHelper", "Illegal state exception in nativeStartPreview");
+                throw ex;
+            } catch (RuntimeException ex) {
+                Log.e("MediaArtistNativeHelper", "Runtime exception in nativeStartPreview");
+                throw ex;
+            }
+
+        } else {
+            return;
+        }
+    }
+
+    /**
+     * This function is responsible for stopping the preview
+     */
+    public long stopPreview() {
+        nativeStopPreview();
+        return mPreviewProgress;
+    }
+
+    /**
+     * This function is responsible for rendering a single frame
+     * from the complete story board on the surface
+     *
+     * @param surface The surface on which frame has to be rendered
+     * @param time The time in ms at which the frame has to be rendered
+     * @param surfaceWidth The surface width
+     * @param surfaceHeight The surface height
+     *
+     * @return The actual time from the story board at which the  frame was extracted
+     * and rendered
+     */
+    public long renderPreviewFrame(Surface surface, long time, int surfaceWidth,
+                                   int surfaceHeight) {
+        long timeMs = 0;
+        if (!mInvalidatePreviewArray) {
+            try {
+                for (int clipCnt = 0; clipCnt < mPreviewEditSettings.clipSettingsArray.length; clipCnt++) {
+                    if (mPreviewEditSettings.clipSettingsArray[clipCnt].fileType == FileType.JPG) {
+                        mPreviewEditSettings.clipSettingsArray[clipCnt].clipPath = mPreviewEditSettings.clipSettingsArray[clipCnt].clipDecodedPath;
+                    }
+                }
+                nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);
+                timeMs = (long)nativeRenderPreviewFrame(surface, time, surfaceWidth, surfaceHeight);
+            } catch (IllegalArgumentException ex) {
+                Log.e("MediaArtistNativeHelper",
+                "Illegal Argument exception in nativeRenderPreviewFrame");
+                throw ex;
+            } catch (IllegalStateException ex) {
+                Log.e("MediaArtistNativeHelper",
+                "Illegal state exception in nativeRenderPreviewFrame");
+                throw ex;
+            } catch (RuntimeException ex) {
+                Log.e("MediaArtistNativeHelper", "Runtime exception in nativeRenderPreviewFrame");
+                throw ex;
+            }
+            return timeMs;
+        } else {
+
+            throw new RuntimeException("Call generate preview first");
+        }
+    }
+
+    /**
+     * This function is responsible for rendering a single frame
+     * from a single media item on the surface
+     *
+     * @param surface The surface on which frame has to be rendered
+     * @param filepath The file path for which the frame needs to be displayed
+     * @param time The time in ms at which the frame has to be rendered
+     * @param framewidth The frame width
+     * @param framewidth The frame height
+     *
+     * @return The actual time from media item at which the  frame was extracted
+     * and rendered
+     */
+    public long renderMediaItemPreviewFrame(Surface surface, String filepath,
+                                            long time, int framewidth,
+                                            int frameheight) {
+        long timeMs = 0;
+        try {
+
+            timeMs = (long)nativeRenderMediaItemPreviewFrame(surface, filepath, framewidth,
+                    frameheight, 0, 0, time);
+        } catch (IllegalArgumentException ex) {
+            Log.e("MediaArtistNativeHelper",
+            "Illegal Argument exception in renderMediaItemPreviewFrame");
+            throw ex;
+        } catch (IllegalStateException ex) {
+            Log.e("MediaArtistNativeHelper",
+            "Illegal state exception in renderMediaItemPreviewFrame");
+            throw ex;
+        } catch (RuntimeException ex) {
+            Log.e("MediaArtistNativeHelper", "Runtime exception in renderMediaItemPreviewFrame");
+            throw ex;
+        }
+
+        return timeMs;
+    }
+
+    /**
+     * This function sets the flag to invalidate the preview array
+     * and for generating the preview again
+     */
+    void setGeneratePreview(boolean isRequired) {
+        mInvalidatePreviewArray = isRequired;
+    }
+
+    /**
+     * @return Returns the current status of preview invalidation
+     * flag
+     */
+    boolean getGeneratePreview() {
+        return mInvalidatePreviewArray;
+    }
+
+    /**
+     * Calculates the aspect ratio from widht and height
+     *
+     * @param w The width of media item
+     * @param h The height of media item
+     *
+     * @return The calculated aspect ratio
+     */
+    public int getAspectRatio(int w, int h) {
+        double apRatio = (double)(w) / (double)(h);
+        BigDecimal bd = new BigDecimal(apRatio);
+        bd = bd.setScale(3, BigDecimal.ROUND_HALF_UP);
+        apRatio = bd.doubleValue();
+        int var = MediaProperties.ASPECT_RATIO_16_9;
+        if (apRatio >= 1.7) {
+            var = MediaProperties.ASPECT_RATIO_16_9;
+        } else if (apRatio >= 1.6) {
+            var = MediaProperties.ASPECT_RATIO_5_3;
+        } else if (apRatio >= 1.5) {
+            var = MediaProperties.ASPECT_RATIO_3_2;
+        } else if (apRatio > 1.3) {
+            var = MediaProperties.ASPECT_RATIO_4_3;
+        } else if (apRatio >= 1.2) {
+            var = MediaProperties.ASPECT_RATIO_11_9;
+        }
+        return var;
+    }
+
+    /**
+     * Maps the file type used in native layer
+     * to file type used in JAVA layer
+     *
+     * @param fileType The file type in native layer
+     *
+     * @return The File type in JAVA layer
+     */
+    public int getFileType(int fileType) {
+        int retValue = -1;
+        switch (fileType) {
+            case FileType.UNSUPPORTED:
+                retValue = MediaProperties.FILE_UNSUPPORTED;
+                break;
+            case FileType.THREE_GPP:
+                retValue = MediaProperties.FILE_3GP;
+                break;
+            case FileType.MP4:
+                retValue = MediaProperties.FILE_MP4;
+                break;
+            case FileType.JPG:
+                retValue = MediaProperties.FILE_JPEG;
+                break;
+            case FileType.PNG:
+                retValue = MediaProperties.FILE_PNG;
+                break;
+            case FileType.MP3:
+                retValue = MediaProperties.FILE_MP3;
+                break;
+
+            default:
+                retValue = -1;
+        }
+        return retValue;
+    }
+
+    /**
+     * Maps the video codec type used in native layer
+     * to video codec type used in JAVA layer
+     *
+     * @param codecType The video codec type in native layer
+     *
+     * @return The video codec type in JAVA layer
+     */
+    public int getVideoCodecType(int codecType) {
+        int retValue = -1;
+        switch (codecType) {
+            case VideoFormat.H263:
+                retValue = MediaProperties.VCODEC_H263;
+                break;
+            case VideoFormat.H264:
+                retValue = MediaProperties.VCODEC_H264BP;
+                break;
+            case VideoFormat.MPEG4:
+                retValue = MediaProperties.VCODEC_MPEG4;
+                break;
+            case VideoFormat.UNSUPPORTED:
+
+            default:
+                retValue = -1;
+        }
+        return retValue;
+    }
+
+    /**
+     * Maps the audio codec type used in native layer
+     * to audio codec type used in JAVA layer
+     *
+     * @param audioType The audio codec type in native layer
+     *
+     * @return The audio codec type in JAVA layer
+     */
+    public int getAudioCodecType(int codecType) {
+        int retValue = -1;
+        switch (codecType) {
+            case AudioFormat.AMR_NB:
+                retValue = MediaProperties.ACODEC_AMRNB;
+                break;
+            case AudioFormat.AAC:
+                retValue = MediaProperties.ACODEC_AAC_LC;
+                break;
+            case AudioFormat.MP3:
+                retValue = MediaProperties.ACODEC_MP3;
+                break;
+
+            default:
+                retValue = -1;
+        }
+        return retValue;
+    }
+
+    /**
+     * Returns the frame rate as integer
+     *
+     * @param fps The fps as enum
+     *
+     * @return The frame rate as integer
+     */
+    public int getFrameRate(int fps) {
+        int retValue = -1;
+        switch (fps) {
+            case VideoFrameRate.FR_5_FPS:
+                retValue = 5;
+                break;
+            case VideoFrameRate.FR_7_5_FPS:
+                retValue = 8;
+                break;
+            case VideoFrameRate.FR_10_FPS:
+                retValue = 10;
+                break;
+            case VideoFrameRate.FR_12_5_FPS:
+                retValue = 13;
+                break;
+            case VideoFrameRate.FR_15_FPS:
+                retValue = 15;
+                break;
+            case VideoFrameRate.FR_20_FPS:
+                retValue = 20;
+                break;
+            case VideoFrameRate.FR_25_FPS:
+                retValue = 25;
+                break;
+            case VideoFrameRate.FR_30_FPS:
+                retValue = 30;
+                break;
+
+            default:
+                retValue = -1;
+        }
+        return retValue;
+    }
+
+    /**
+     * Maps the file type used in JAVA layer
+     * to file type used in native layer
+     *
+     * @param fileType The file type in JAVA layer
+     *
+     * @return The File type in native layer
+     */
+    int getMediaItemFileType(int fileType) {
+        int retValue = -1;
+
+        switch (fileType) {
+            case MediaProperties.FILE_UNSUPPORTED:
+                retValue = FileType.UNSUPPORTED;
+                break;
+            case MediaProperties.FILE_3GP:
+                retValue = FileType.THREE_GPP;
+                break;
+            case MediaProperties.FILE_MP4:
+                retValue = FileType.MP4;
+                break;
+            case MediaProperties.FILE_JPEG:
+                retValue = FileType.JPG;
+                break;
+            case MediaProperties.FILE_PNG:
+                retValue = FileType.PNG;
+                break;
+
+            default:
+                retValue = -1;
+        }
+        return retValue;
+
+    }
+
+    /**
+     * Maps the rendering mode used in native layer
+     * to rendering mode used in JAVA layer
+     *
+     * @param renderingMode The rendering mode in JAVA layer
+     *
+     * @return The rendering mode in native layer
+     */
+    int getMediaItemRenderingMode(int renderingMode) {
+        int retValue = -1;
+        switch (renderingMode) {
+            case MediaItem.RENDERING_MODE_BLACK_BORDER:
+                retValue = MediaRendering.BLACK_BORDERS;
+                break;
+            case MediaItem.RENDERING_MODE_STRETCH:
+                retValue = MediaRendering.RESIZING;
+                break;
+            case MediaItem.RENDERING_MODE_CROPPING:
+                retValue = MediaRendering.CROPPING;
+                break;
+
+            default:
+                retValue = -1;
+        }
+        return retValue;
+    }
+
+    /**
+     * Maps the transition behavior used in JAVA layer
+     * to transition behavior used in native layer
+     *
+     * @param transitionType The transition behavior in JAVA layer
+     *
+     * @return The transition behavior in native layer
+     */
+    int getVideoTransitionBehaviour(int transitionType) {
+        int retValue = -1;
+        switch (transitionType) {
+            case Transition.BEHAVIOR_SPEED_UP:
+                retValue = TransitionBehaviour.SPEED_UP;
+                break;
+            case Transition.BEHAVIOR_SPEED_DOWN:
+                retValue = TransitionBehaviour.SPEED_DOWN;
+                break;
+            case Transition.BEHAVIOR_LINEAR:
+                retValue = TransitionBehaviour.LINEAR;
+                break;
+            case Transition.BEHAVIOR_MIDDLE_SLOW:
+                retValue = TransitionBehaviour.SLOW_MIDDLE;
+                break;
+            case Transition.BEHAVIOR_MIDDLE_FAST:
+                retValue = TransitionBehaviour.FAST_MIDDLE;
+                break;
+
+            default:
+                retValue = -1;
+        }
+        return retValue;
+    }
+
+    /**
+     * Maps the transition slide direction used in JAVA layer
+     * to transition slide direction used in native layer
+     *
+     * @param slideDirection The transition slide direction
+     * in JAVA layer
+     *
+     * @return The transition slide direction in native layer
+     */
+    int getSlideSettingsDirection(int slideDirection) {
+        int retValue = -1;
+        switch (slideDirection) {
+            case TransitionSliding.DIRECTION_RIGHT_OUT_LEFT_IN:
+                retValue = SlideDirection.RIGHT_OUT_LEFT_IN;
+                break;
+            case TransitionSliding.DIRECTION_LEFT_OUT_RIGHT_IN:
+                retValue = SlideDirection.LEFT_OUT_RIGTH_IN;
+                break;
+            case TransitionSliding.DIRECTION_TOP_OUT_BOTTOM_IN:
+                retValue = SlideDirection.TOP_OUT_BOTTOM_IN;
+                break;
+            case TransitionSliding.DIRECTION_BOTTOM_OUT_TOP_IN:
+                retValue = SlideDirection.BOTTOM_OUT_TOP_IN;
+                break;
+
+            default:
+                retValue = -1;
+        }
+        return retValue;
+    }
+
+    /**
+     * Maps the effect color type used in JAVA layer
+     * to effect color type used in native layer
+     *
+     * @param effect The EffectColor reference
+     *
+     * @return The color effect value from native layer
+     */
+    private int getEffectColorType(EffectColor effect) {
+        int retValue = -1;
+        switch (effect.getType()) {
+            case EffectColor.TYPE_COLOR:
+                if (effect.getColor() == EffectColor.GREEN) {
+                    retValue = VideoEffect.GREEN;
+                } else if (effect.getColor() == EffectColor.PINK) {
+                    retValue = VideoEffect.PINK;
+                } else if (effect.getColor() == EffectColor.GRAY) {
+                    retValue = VideoEffect.BLACK_AND_WHITE;
+                } else {
+                    retValue = VideoEffect.COLORRGB16;
+                }
+                break;
+            case EffectColor.TYPE_GRADIENT:
+                retValue = VideoEffect.GRADIENT;
+                break;
+            case EffectColor.TYPE_SEPIA:
+                retValue = VideoEffect.SEPIA;
+                break;
+            case EffectColor.TYPE_NEGATIVE:
+                retValue = VideoEffect.NEGATIVE;
+                break;
+            case EffectColor.TYPE_FIFTIES:
+                retValue = VideoEffect.FIFTIES;
+                break;
+
+            default:
+                retValue = -1;
+        }
+        return retValue;
+    }
+
+    /**
+     * Calculates videdo resolution for output clip
+     * based on clip's height and aspect ratio of storyboard
+     *
+     * @param aspectRatio The aspect ratio of story board
+     * @param height The height of clip
+     *
+     * @return The video resolution
+     */
+    private int findVideoResolution(int aspectRatio, int height) {
+        final Pair<Integer, Integer>[] resolutions;
+        final Pair<Integer, Integer> maxResolution;
+        int retValue = VideoFrameSize.SIZE_UNDEFINED;
+        switch (aspectRatio) {
+            case MediaProperties.ASPECT_RATIO_3_2:
+                if (height == MediaProperties.HEIGHT_480)
+                    retValue = VideoFrameSize.NTSC;
+                else if (height == MediaProperties.HEIGHT_720)
+                    retValue = VideoFrameSize.W720p;
+                break;
+            case MediaProperties.ASPECT_RATIO_16_9:
+                if (height == MediaProperties.HEIGHT_480)
+                    retValue = VideoFrameSize.WVGA16x9;
+                else if (height == MediaProperties.HEIGHT_720)
+                    retValue = VideoFrameSize.V720p;
+                break;
+            case MediaProperties.ASPECT_RATIO_4_3:
+                if (height == MediaProperties.HEIGHT_480)
+                    retValue = VideoFrameSize.VGA;
+                if (height == MediaProperties.HEIGHT_720)
+                    retValue = VideoFrameSize.S720p;
+                break;
+            case MediaProperties.ASPECT_RATIO_5_3:
+                if (height == MediaProperties.HEIGHT_480)
+                    retValue = VideoFrameSize.WVGA;
+                break;
+            case MediaProperties.ASPECT_RATIO_11_9:
+                if (height == MediaProperties.HEIGHT_144)
+                    retValue = VideoFrameSize.QCIF;
+                break;
+        }
+        if (retValue == VideoFrameSize.SIZE_UNDEFINED) {
+            resolutions = MediaProperties.getSupportedResolutions(mVideoEditor.getAspectRatio());
+            // Get the highest resolution
+            maxResolution = resolutions[resolutions.length - 1];
+            retValue = findVideoResolution(mVideoEditor.getAspectRatio(),
+                                           maxResolution.second);
+        }
+
+        return retValue;
+    }
+
+    /**
+     * This method is responsible for exporting a movie
+     *
+     * @param filePath The output file path
+     * @param projectDir The output project directory
+     * @param height The height of clip
+     * @param bitrate The bitrate at which the movie should be exported
+     * @param mediaItemsList The media items list
+     * @param mediaTransitionList The transitons list
+     * @param mediaBGMList The background track list
+     * @param listener The ExportProgressListener
+     *
+     */
+    public void export(String filePath, String projectDir, int height, int bitrate,
+            List<MediaItem> mediaItemsList, List<Transition> mediaTransitionList,
+            List<AudioTrack> mediaBGMList, ExportProgressListener listener) {
+
+        int outBitrate = 0;
+        mExportFilename = filePath;
+        previewStoryBoard(mediaItemsList, mediaTransitionList, mediaBGMList,null);
+        if (listener != null) {
+            mExportProgressListener = listener;
+        }
+        mProgressToApp = 0;
+
+        switch (bitrate) {
+            case MediaProperties.BITRATE_28K:
+                outBitrate = Bitrate.BR_32_KBPS;
+                break;
+            case MediaProperties.BITRATE_40K:
+                outBitrate = Bitrate.BR_48_KBPS;
+                break;
+            case MediaProperties.BITRATE_64K:
+                outBitrate = Bitrate.BR_64_KBPS;
+                break;
+            case MediaProperties.BITRATE_96K:
+                outBitrate = Bitrate.BR_96_KBPS;
+                break;
+            case MediaProperties.BITRATE_128K:
+                outBitrate = Bitrate.BR_128_KBPS;
+                break;
+            case MediaProperties.BITRATE_192K:
+                outBitrate = Bitrate.BR_192_KBPS;
+                break;
+            case MediaProperties.BITRATE_256K:
+                outBitrate = Bitrate.BR_256_KBPS;
+                break;
+            case MediaProperties.BITRATE_384K:
+                outBitrate = Bitrate.BR_384_KBPS;
+                break;
+            case MediaProperties.BITRATE_512K:
+                outBitrate = Bitrate.BR_512_KBPS;
+                break;
+            case MediaProperties.BITRATE_800K:
+                outBitrate = Bitrate.BR_800_KBPS;
+                break;
+            case MediaProperties.BITRATE_2M:
+                outBitrate = Bitrate.BR_2_MBPS;
+                break;
+
+            case MediaProperties.BITRATE_5M:
+                outBitrate = Bitrate.BR_5_MBPS;
+                break;
+            case MediaProperties.BITRATE_8M:
+                outBitrate = Bitrate.BR_8_MBPS;
+                break;
+
+            default:
+                throw new IllegalArgumentException("Argument Bitrate incorrect");
+        }
+        mPreviewEditSettings.videoFrameRate = VideoFrameRate.FR_30_FPS;
+        mPreviewEditSettings.outputFile = mOutputFilename = filePath;
+
+        int aspectRatio = mVideoEditor.getAspectRatio();
+        mPreviewEditSettings.videoFrameSize = findVideoResolution(aspectRatio, height);
+        mPreviewEditSettings.videoFormat = VideoFormat.H264;
+        mPreviewEditSettings.audioFormat = AudioFormat.AAC;
+        mPreviewEditSettings.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;
+        mPreviewEditSettings.maxFileSize = 0;
+        mPreviewEditSettings.audioChannels = 2;
+        mPreviewEditSettings.videoBitrate = outBitrate;
+        mPreviewEditSettings.audioBitrate = Bitrate.BR_96_KBPS;
+
+        mPreviewEditSettings.transitionSettingsArray = new TransitionSettings[mTotalClips - 1];
+        for (int index = 0; index < mTotalClips - 1; index++) {
+            mPreviewEditSettings.transitionSettingsArray[index] = new TransitionSettings();
+            mPreviewEditSettings.transitionSettingsArray[index].videoTransitionType = VideoTransition.NONE;
+            mPreviewEditSettings.transitionSettingsArray[index].audioTransitionType = AudioTransition.NONE;
+        }
+        for (int clipCnt = 0; clipCnt < mPreviewEditSettings.clipSettingsArray.length; clipCnt++) {
+            if (mPreviewEditSettings.clipSettingsArray[clipCnt].fileType == FileType.JPG) {
+                mPreviewEditSettings.clipSettingsArray[clipCnt].clipPath =
+                mPreviewEditSettings.clipSettingsArray[clipCnt].clipOriginalPath;
+            }
+        }
+        nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);
+
+        int err = 0;
+        try {
+            mProcessingState  = PROCESSING_EXPORT;
+            mProcessingObject = null;
+            err = generateClip(mPreviewEditSettings);
+            mProcessingState  = PROCESSING_NONE;
+        } catch (IllegalArgumentException ex) {
+            Log.e("MediaArtistNativeHelper", "IllegalArgument for generateClip");
+            throw ex;
+        } catch (IllegalStateException ex) {
+            Log.e("MediaArtistNativeHelper", "IllegalStateExceptiont for generateClip");
+            throw ex;
+        } catch (RuntimeException ex) {
+            Log.e("MediaArtistNativeHelper", "RuntimeException for generateClip");
+            throw ex;
+        }
+
+        if (err != 0) {
+            Log.e("MediaArtistNativeHelper", "RuntimeException for generateClip");
+            throw new RuntimeException("generateClip failed with error="+err );
+        }
+
+        mExportDone = true;
+        setGeneratePreview(true);
+        mExportProgressListener = null;
+    }
+
+    /**
+     * This method is responsible for exporting a movie
+     *
+     * @param filePath The output file path
+     * @param projectDir The output project directory
+     * @param height The height of clip
+     * @param bitrate The bitrate at which the movie should be exported
+     * @param audioCodec The audio codec to use
+     * @param videoCodec The video codec to use
+     * @param mediaItemsList The media items list
+     * @param mediaTransitionList The transitons list
+     * @param mediaBGMList The background track list
+     * @param listener The ExportProgressListener
+     *
+     */
+    public void export(String filePath, String projectDir,int height,int bitrate,
+            int audioCodec,int videoCodec,List<MediaItem> mediaItemsList,
+            List<Transition> mediaTransitionList,List<AudioTrack> mediaBGMList,
+            ExportProgressListener listener) {
+
+        int outBitrate = 0;
+        mExportFilename = filePath;
+        previewStoryBoard(mediaItemsList, mediaTransitionList, mediaBGMList,null);
+        if (listener != null) {
+            mExportProgressListener = listener;
+        }
+        mProgressToApp = 0;
+
+        switch (bitrate) {
+            case MediaProperties.BITRATE_28K:
+                outBitrate = Bitrate.BR_32_KBPS;
+                break;
+            case MediaProperties.BITRATE_40K:
+                outBitrate = Bitrate.BR_48_KBPS;
+                break;
+            case MediaProperties.BITRATE_64K:
+                outBitrate = Bitrate.BR_64_KBPS;
+                break;
+            case MediaProperties.BITRATE_96K:
+                outBitrate = Bitrate.BR_96_KBPS;
+                break;
+            case MediaProperties.BITRATE_128K:
+                outBitrate = Bitrate.BR_128_KBPS;
+                break;
+            case MediaProperties.BITRATE_192K:
+                outBitrate = Bitrate.BR_192_KBPS;
+                break;
+            case MediaProperties.BITRATE_256K:
+                outBitrate = Bitrate.BR_256_KBPS;
+                break;
+            case MediaProperties.BITRATE_384K:
+                outBitrate = Bitrate.BR_384_KBPS;
+                break;
+            case MediaProperties.BITRATE_512K:
+                outBitrate = Bitrate.BR_512_KBPS;
+                break;
+            case MediaProperties.BITRATE_800K:
+                outBitrate = Bitrate.BR_800_KBPS;
+                break;
+            case MediaProperties.BITRATE_2M:
+                outBitrate = Bitrate.BR_2_MBPS;
+                break;
+            case MediaProperties.BITRATE_5M:
+                outBitrate = Bitrate.BR_5_MBPS;
+                break;
+            case MediaProperties.BITRATE_8M:
+                outBitrate = Bitrate.BR_8_MBPS;
+                break;
+
+            default:
+                throw new IllegalArgumentException("Argument Bitrate incorrect");
+        }
+        mPreviewEditSettings.videoFrameRate = VideoFrameRate.FR_30_FPS;
+        mPreviewEditSettings.outputFile = mOutputFilename = filePath;
+
+        int aspectRatio = mVideoEditor.getAspectRatio();
+        mPreviewEditSettings.videoFrameSize = findVideoResolution(aspectRatio, height);
+        switch (audioCodec) {
+            case MediaProperties.ACODEC_AAC_LC:
+                mPreviewEditSettings.audioFormat = AudioFormat.AAC;
+                break;
+            case MediaProperties.ACODEC_AMRNB:
+                mPreviewEditSettings.audioFormat = AudioFormat.AMR_NB;
+                break;
+        }
+
+        switch (videoCodec) {
+            case MediaProperties.VCODEC_H263:
+                mPreviewEditSettings.videoFormat = VideoFormat.H263;
+                break;
+            case MediaProperties.VCODEC_H264BP:
+                mPreviewEditSettings.videoFormat = VideoFormat.H264;
+                break;
+            case MediaProperties.VCODEC_MPEG4:
+                mPreviewEditSettings.videoFormat = VideoFormat.MPEG4;
+                break;
+        }
+
+        mPreviewEditSettings.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;
+        mPreviewEditSettings.maxFileSize = 0;
+        mPreviewEditSettings.audioChannels = 2;
+        mPreviewEditSettings.videoBitrate = outBitrate;
+        mPreviewEditSettings.audioBitrate = Bitrate.BR_96_KBPS;
+
+        mPreviewEditSettings.transitionSettingsArray =
+                                        new TransitionSettings[mTotalClips - 1];
+        for (int index = 0; index < mTotalClips - 1; index++) {
+            mPreviewEditSettings.transitionSettingsArray[index] =
+                                                       new TransitionSettings();
+            mPreviewEditSettings.transitionSettingsArray[index].videoTransitionType =
+                                                                      VideoTransition.NONE;
+            mPreviewEditSettings.transitionSettingsArray[index].audioTransitionType =
+                                                                      AudioTransition.NONE;
+        }
+        for (int clipCnt = 0; clipCnt < mPreviewEditSettings.clipSettingsArray.length; clipCnt++) {
+            if (mPreviewEditSettings.clipSettingsArray[clipCnt].fileType == FileType.JPG) {
+                mPreviewEditSettings.clipSettingsArray[clipCnt].clipPath =
+                  mPreviewEditSettings.clipSettingsArray[clipCnt].clipOriginalPath;
+            }
+        }
+        nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);
+
+        int err = 0;
+        try {
+            mProcessingState  = PROCESSING_EXPORT;
+            mProcessingObject = null;
+            err = generateClip(mPreviewEditSettings);
+            mProcessingState  = PROCESSING_NONE;
+        } catch (IllegalArgumentException ex) {
+            Log.e("MediaArtistNativeHelper", "IllegalArgument for generateClip");
+            throw ex;
+        } catch (IllegalStateException ex) {
+            Log.e("MediaArtistNativeHelper", "IllegalStateExceptiont for generateClip");
+            throw ex;
+        } catch (RuntimeException ex) {
+            Log.e("MediaArtistNativeHelper", "RuntimeException for generateClip");
+            throw ex;
+        }
+
+        if (err != 0) {
+            Log.e("MediaArtistNativeHelper", "RuntimeException for generateClip");
+            throw new RuntimeException("generateClip failed with error="+err );
+        }
+
+        mExportDone = true;
+        setGeneratePreview(true);
+        mExportProgressListener = null;
+    }
+
+
+    /**
+     * This methods takes care of stopping the Export process
+     *
+     * @param The input file name for which export has to be stopped
+     */
+    public void stop(String filename) {
+        if (!mExportDone) {
+            try {
+                stopEncoding();
+            } catch (IllegalStateException ex) {
+                Log.e("MediaArtistNativeHelper", "Illegal state exception in unload settings");
+                throw ex;
+            } catch (RuntimeException ex) {
+                Log.e("MediaArtistNativeHelper", "Runtime exception in unload settings");
+                throw ex;
+            }
+
+            new File(mExportFilename).delete();
+        }
+    }
+
+    /**
+     * This method extracts a frame from the input file
+     * and returns the frame as a bitmap
+     *
+     * @param inputFile The inputFile
+     * @param width The width of the output frame
+     * @param height The height of the output frame
+     * @param timeMS The time in ms at which the frame hass to be extracted
+     */
+    public Bitmap getPixels(String inputFile, int width, int height, long timeMS) {
+        if (inputFile == null) {
+            throw new IllegalArgumentException();
+        }
+
+        IntBuffer rgb888 = IntBuffer.allocate(width * height * 4);
+        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        nativeGetPixels(inputFile, rgb888.array(), width, height, timeMS);
+        bitmap.copyPixelsFromBuffer(rgb888);
+
+        return bitmap;
+    }
+
+    /**
+     * This method extracts a list of frame from the
+     * input file and returns the frame in bitmap array
+     *
+     * @param filename The inputFile
+     * @param width The width of the output frame
+     * @param height The height of the output frame
+     * @param startMs The starting time in ms
+     * @param endMs The end time in ms
+     * @param thumbnailCount The number of frames to be extracted
+     * from startMs to endMs
+     *
+     * @return The frames as bitmaps in bitmap array
+     **/
+    public Bitmap[] getPixelsList(String filename, int width, int height, long startMs, long endMs,
+            int thumbnailCount) {
+        int[] rgb888 = null;
+        int thumbnailSize = width * height * 4;
+
+        int i = 0;
+        int deltaTime = (int)(endMs - startMs) / thumbnailCount;
+        Bitmap[] bitmap = null;
+        try {
+            // This may result in out of Memory Error
+            rgb888 = new int[thumbnailSize * thumbnailCount];
+            bitmap = new Bitmap[thumbnailCount];
+        } catch (Throwable e) {
+            // Allocating to new size with Fixed count
+            try {
+                System.gc();
+                rgb888 = new int[thumbnailSize * MAX_THUMBNAIL_PERMITTED];
+                bitmap = new Bitmap[MAX_THUMBNAIL_PERMITTED];
+                thumbnailCount = MAX_THUMBNAIL_PERMITTED;
+            } catch (Throwable ex) {
+                throw new RuntimeException("Memory allocation fails,reduce nos of thumbanail count");
+            }
+        }
+        IntBuffer tmpBuffer = IntBuffer.allocate(thumbnailSize);
+        nativeGetPixelsList(filename, rgb888, width, height, deltaTime, thumbnailCount, startMs,
+                endMs);
+        for (; i < thumbnailCount; i++) {
+            bitmap[i] = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+            tmpBuffer.put(rgb888, (i * thumbnailSize), thumbnailSize);
+            tmpBuffer.rewind();
+            bitmap[i].copyPixelsFromBuffer(tmpBuffer);
+        }
+
+        return bitmap;
+    }
+
+    /**
+     * This method generates the audio graph
+     *
+     * @param uniqueId The unique id
+     * @param inFileName The inputFile
+     * @param OutAudiGraphFileName output filename
+     * @param frameDuration The each frame duration
+     * @param audioChannels The number of audio channels
+     * @param samplesCount Total number of samples count
+     * @param listener ExtractAudioWaveformProgressListener reference
+     * @param isVideo The flag to indicate if the file is video file or not
+     *
+     **/
+    public void generateAudioGraph(String uniqueId, String inFileName, String OutAudiGraphFileName,
+            int frameDuration, int audioChannels, int samplesCount,
+            ExtractAudioWaveformProgressListener listener, boolean isVideo) {
+        String tempPCMFileName;
+
+        if (listener != null) {
+            mExtractAudioWaveformProgressListener = listener;
+        }
+        /**
+         * in case of Video , first call will generate the PCM file to make the
+         * audio graph
+         */
+        if (isVideo) {
+            tempPCMFileName = String.format(mProjectPath + "/" + uniqueId + ".pcm");
+        } else {
+            tempPCMFileName = mAudioTrackPCMFilePath;
+        }
+        /**
+         * For Video item, generate the PCM
+         */
+        if (isVideo) {
+            nativeGenerateRawAudio(inFileName, tempPCMFileName);
+        }
+
+        nativeGenerateAudioGraph(tempPCMFileName, OutAudiGraphFileName, frameDuration,
+                audioChannels, samplesCount);
+
+        /* once the audio graph file is generated, delete the pcm file */
+        if (isVideo) {
+            new File(tempPCMFileName).delete();
+        }
+    }
+
+    /**     Native Methods        */
+
+    public native Properties getMediaProperties(String file) throws IllegalArgumentException,
+    IllegalStateException, RuntimeException, Exception;
+
+    /**
+     * Get the version of ManualEdit.
+     *
+     * @return version of ManualEdit
+     * @throws RuntimeException if an error occurred
+     * @see Version
+     */
+    public static native Version getVersion() throws RuntimeException;
+
+    /**
+     * Returns the video thumbnail in an array of integers. Output format is
+     * ARGB8888.
+     *
+     * @param pixelArray the array that receives the pixelvalues
+     * @param width width of the video thumbnail
+     * @param height height of the video thumbnail
+     * @param timeMS desired time of the thumbnail in ms
+     * @return actual time in ms of the thumbnail generated
+     * @throws IllegalStateException if the class has not been initialized
+     * @throws IllegalArgumentException if the pixelArray is not available or
+     *             one of the dimensions is negative or zero or the time is
+     *             negative
+     * @throws RuntimeException on runtime errors in native code
+     */
+    public native int nativeGetPixels(String fileName, int[] pixelArray, int width, int height,
+            long timeMS);
+
+    public native int nativeGetPixelsList(String fileName, int[] pixelArray, int width, int height,
+            int timeMS, int nosofTN, long startTimeMs, long endTimeMs);
+
+    /**
+     * Releases the JNI and cleans up the core native module.. Should be called
+     * only after init( )
+     *
+     * @throws IllegalStateException if the method could not be called
+     */
+    public native void release() throws IllegalStateException, RuntimeException;
+
+
+
+
+    /**
+     * Stops the encoding. This method should only be called after encoding has
+     * started using method <code> startEncoding</code>
+     *
+     * @throws IllegalStateException if the method could not be called
+     */
+    public native void stopEncoding() throws IllegalStateException, RuntimeException;
+
+
+
+    private native void _init(String tempPath, String libraryPath)
+            throws IllegalArgumentException, IllegalStateException, RuntimeException;
+
+    private native void nativeStartPreview(Surface mSurface, long fromMs, long toMs,
+            int callbackAfterFrameCount, boolean loop) throws IllegalArgumentException,
+            IllegalStateException, RuntimeException;
+
+    private native void nativePopulateSettings(EditSettings mEditSettings,
+            PreviewClipProperties mProperties, AudioSettings mAudioSettings)
+    throws IllegalArgumentException, IllegalStateException, RuntimeException;
+
+    private native int nativeRenderPreviewFrame(Surface mSurface, long timeMs,
+                                                 int surfaceWidth, int surfaceHeight)
+                                                 throws IllegalArgumentException,
+                                                 IllegalStateException, RuntimeException;
+
+    private native int nativeRenderMediaItemPreviewFrame(Surface mSurface, String filepath,
+            int framewidth, int frameheight, int surfacewidth, int surfaceheight, long timeMs)
+    throws IllegalArgumentException, IllegalStateException, RuntimeException;
+
+    private native void nativeStopPreview();
+
+    public native int nativeGenerateAudioGraph(String pcmFilePath, String outGraphPath,
+            int frameDuration, int channels, int sampleCount);
+
+    public native int nativeGenerateRawAudio(String InFileName, String PCMFileName);
+
+    public native int nativeGenerateClip(EditSettings editSettings)
+    throws IllegalArgumentException, IllegalStateException, RuntimeException;
+
+}
diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java
index e6e9bc2..b03588f 100755
--- a/media/java/android/media/videoeditor/MediaImageItem.java
+++ b/media/java/android/media/videoeditor/MediaImageItem.java
@@ -1,492 +1,1033 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-import java.io.IOException;

-import java.util.ArrayList;

-import java.util.List;

-

-import android.graphics.Bitmap;

-import android.graphics.BitmapFactory;

-import android.graphics.Canvas;

-import android.graphics.Paint;

-import android.graphics.Rect;

-import android.util.Log;

-import android.util.Pair;

-

-/**

- * This class represents an image item on the storyboard. Note that images are

- * scaled down to the maximum supported resolution by preserving the native

- * aspect ratio. To learn the scaled image dimensions use

- * {@link #getScaledWidth()} and {@link #getScaledHeight()} respectively.

- *

- * {@hide}

- */

-public class MediaImageItem extends MediaItem {

-    // Logging

-    private static final String TAG = "MediaImageItem";

-

-    // The resize paint

-    private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG);

-

-    // Instance variables

-    private final int mWidth;

-    private final int mHeight;

-    private final int mAspectRatio;

-    private long mDurationMs;

-    private int mScaledWidth, mScaledHeight;

-

-    /**

-     * This class cannot be instantiated by using the default constructor

-     */

-    @SuppressWarnings("unused")

-    private MediaImageItem() throws IOException {

-        this(null, null, null, 0, RENDERING_MODE_BLACK_BORDER);

-    }

-

-    /**

-     * Constructor

-     *

-     * @param editor The video editor reference

-     * @param mediaItemId The media item id

-     * @param filename The image file name

-     * @param durationMs The duration of the image on the storyboard

-     * @param renderingMode The rendering mode

-     *

-     * @throws IOException

-     */

-    public MediaImageItem(VideoEditor editor, String mediaItemId, String filename, long durationMs,

-            int renderingMode)

-            throws IOException {

-        super(editor, mediaItemId, filename, renderingMode);

-

-        // Determine the dimensions of the image

-        final BitmapFactory.Options dbo = new BitmapFactory.Options();

-        dbo.inJustDecodeBounds = true;

-        BitmapFactory.decodeFile(filename, dbo);

-

-        mWidth = dbo.outWidth;

-        mHeight = dbo.outHeight;

-        mDurationMs = durationMs;

-

-        // TODO: Determine the aspect ratio from the width and height

-        mAspectRatio = MediaProperties.ASPECT_RATIO_4_3;

-

-        // Images are stored in memory scaled to the maximum resolution to

-        // save memory.

-        final Pair<Integer, Integer>[] resolutions =

-            MediaProperties.getSupportedResolutions(mAspectRatio);

-        // Get the highest resolution

-        final Pair<Integer, Integer> maxResolution = resolutions[resolutions.length - 1];

-        if (mHeight > maxResolution.second) {

-            // We need to scale the image

-            scaleImage(filename, maxResolution.first, maxResolution.second);

-            mScaledWidth = maxResolution.first;

-            mScaledHeight = maxResolution.second;

-        } else {

-            mScaledWidth = mWidth;

-            mScaledHeight = mHeight;

-        }

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public int getFileType() {

-        if (mFilename.endsWith(".jpg") || mFilename.endsWith(".jpeg")) {

-            return MediaProperties.FILE_JPEG;

-        } else if (mFilename.endsWith(".png")) {

-            return MediaProperties.FILE_PNG;

-        } else {

-            return MediaProperties.FILE_UNSUPPORTED;

-        }

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public int getWidth() {

-        return mWidth;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public int getHeight() {

-        return mHeight;

-    }

-

-    /**

-     * @return The scaled width of the image.

-     */

-    public int getScaledWidth() {

-        return mScaledWidth;

-    }

-

-    /**

-     * @return The scaled height of the image.

-     */

-    public int getScaledHeight() {

-        return mScaledHeight;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public int getAspectRatio() {

-        return mAspectRatio;

-    }

-

-    /**

-     * This method will adjust the duration of bounding transitions, effects

-     * and overlays if the current duration of the transactions become greater

-     * than the maximum allowable duration.

-     *

-     * @param durationMs The duration of the image in the storyboard timeline

-     */

-    public void setDuration(long durationMs) {

-        if (durationMs == mDurationMs) {

-            return;

-        }

-

-        // Invalidate the end transitions if necessary.

-        // This invalidation is necessary for the case in which an effect or

-        // an overlay is overlapping with the end transition

-        // (before the duration is changed) and it no longer overlaps with the

-        // transition after the duration is increased.

-

-        // The beginning transition does not need to be invalidated at this time

-        // because an effect or an overlay overlaps with the beginning

-        // transition, the begin transition is unaffected by a media item

-        // duration change.

-        invalidateEndTransition();

-

-        mDurationMs = durationMs;

-

-        adjustTransitions();

-        final List<Overlay> adjustedOverlays = adjustOverlays();

-        final List<Effect> adjustedEffects = adjustEffects();

-

-        // Invalidate the beginning and end transitions after adjustments.

-        // This invalidation is necessary for the case in which an effect or

-        // an overlay was not overlapping with the beginning or end transitions

-        // before the setDuration reduces the duration of the media item and

-        // causes an overlap of the beginning and/or end transition with the

-        // effect.

-        invalidateBeginTransition(adjustedEffects, adjustedOverlays);

-        invalidateEndTransition();

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public long getDuration() {

-        return mDurationMs;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public long getTimelineDuration() {

-        return mDurationMs;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public Bitmap getThumbnail(int width, int height, long timeMs) throws IOException {

-        return scaleImage(mFilename, width, height);

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public Bitmap[] getThumbnailList(int width, int height, long startMs, long endMs,

-            int thumbnailCount) throws IOException {

-        final Bitmap thumbnail = scaleImage(mFilename, width, height);

-        final Bitmap[] thumbnailArray = new Bitmap[thumbnailCount];

-        for (int i = 0; i < thumbnailCount; i++) {

-            thumbnailArray[i] = thumbnail;

-        }

-        return thumbnailArray;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    void invalidateTransitions(long startTimeMs, long durationMs) {

-        // Check if the item overlaps with the beginning and end transitions

-        if (mBeginTransition != null) {

-            if (isOverlapping(startTimeMs, durationMs, 0, mBeginTransition.getDuration())) {

-                mBeginTransition.invalidate();

-            }

-        }

-

-        if (mEndTransition != null) {

-            final long transitionDurationMs = mEndTransition.getDuration();

-            if (isOverlapping(startTimeMs, durationMs,

-                    getDuration() - transitionDurationMs, transitionDurationMs)) {

-                mEndTransition.invalidate();

-            }

-        }

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    void invalidateTransitions(long oldStartTimeMs, long oldDurationMs, long newStartTimeMs,

-            long newDurationMs) {

-        // Check if the item overlaps with the beginning and end transitions

-        if (mBeginTransition != null) {

-            final long transitionDurationMs = mBeginTransition.getDuration();

-            // If the start time has changed and if the old or the new item

-            // overlaps with the begin transition, invalidate the transition.

-            if (oldStartTimeMs != newStartTimeMs &&

-                    (isOverlapping(oldStartTimeMs, oldDurationMs, 0, transitionDurationMs) ||

-                    isOverlapping(newStartTimeMs, newDurationMs, 0, transitionDurationMs))) {

-                mBeginTransition.invalidate();

-            }

-        }

-

-        if (mEndTransition != null) {

-            final long transitionDurationMs = mEndTransition.getDuration();

-            // If the start time + duration has changed and if the old or the new

-            // item overlaps the end transition, invalidate the transition/

-            if (oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs &&

-                    (isOverlapping(oldStartTimeMs, oldDurationMs,

-                            mDurationMs - transitionDurationMs, transitionDurationMs) ||

-                    isOverlapping(newStartTimeMs, newDurationMs,

-                            mDurationMs - transitionDurationMs, transitionDurationMs))) {

-                mEndTransition.invalidate();

-            }

-        }

-    }

-

-    /**

-     * Invalidate the begin transition if any effects and overlays overlap

-     * with the begin transition.

-     *

-     * @param effects List of effects to check for transition overlap

-     * @param overlays List of overlays to check for transition overlap

-     */

-    private void invalidateBeginTransition(List<Effect> effects, List<Overlay> overlays) {

-        if (mBeginTransition != null && mBeginTransition.isGenerated()) {

-            final long transitionDurationMs = mBeginTransition.getDuration();

-

-            // The begin transition must be invalidated if it overlaps with

-            // an effect.

-            for (Effect effect : effects) {

-                // Check if the effect overlaps with the begin transition

-                if (effect.getStartTime() < transitionDurationMs) {

-                    mBeginTransition.invalidate();

-                    break;

-                }

-            }

-

-            if (mBeginTransition.isGenerated()) {

-                // The end transition must be invalidated if it overlaps with

-                // an overlay.

-                for (Overlay overlay : overlays) {

-                    // Check if the overlay overlaps with the end transition

-                    if (overlay.getStartTime() < transitionDurationMs) {

-                        mBeginTransition.invalidate();

-                        break;

-                    }

-                }

-            }

-        }

-    }

-

-    /**

-     * Invalidate the end transition if any effects and overlays overlap

-     * with the end transition.

-     */

-    private void invalidateEndTransition() {

-        if (mEndTransition != null && mEndTransition.isGenerated()) {

-            final long transitionDurationMs = mEndTransition.getDuration();

-

-            // The end transition must be invalidated if it overlaps with

-            // an effect.

-            final List<Effect> effects = getAllEffects();

-            for (Effect effect : effects) {

-                // Check if the effect overlaps with the end transition

-                if (effect.getStartTime() + effect.getDuration() >

-                            mDurationMs - transitionDurationMs) {

-                    mEndTransition.invalidate();

-                    break;

-                }

-            }

-

-            if (mEndTransition.isGenerated()) {

-                // The end transition must be invalidated if it overlaps with

-                // an overlay.

-                final List<Overlay> overlays = getAllOverlays();

-                for (Overlay overlay : overlays) {

-                    // Check if the overlay overlaps with the end transition

-                    if (overlay.getStartTime() + overlay.getDuration() >

-                                mDurationMs - transitionDurationMs) {

-                        mEndTransition.invalidate();

-                        break;

-                    }

-                }

-            }

-        }

-    }

-

-    /**

-     * Adjust the start time and/or duration of effects.

-     *

-     * @return The list of effects which were adjusted

-     */

-    private List<Effect> adjustEffects() {

-        final List<Effect> adjustedEffects = new ArrayList<Effect>();

-        final List<Effect> effects = getAllEffects();

-        for (Effect effect : effects) {

-            // Adjust the start time if necessary

-            final long effectStartTimeMs;

-            if (effect.getStartTime() > getDuration()) {

-                effectStartTimeMs = 0;

-            } else {

-                effectStartTimeMs = effect.getStartTime();

-            }

-

-            // Adjust the duration if necessary

-            final long effectDurationMs;

-            if (effectStartTimeMs + effect.getDuration() > getDuration()) {

-                effectDurationMs = getDuration() - effectStartTimeMs;

-            } else {

-                effectDurationMs = effect.getDuration();

-            }

-

-            if (effectStartTimeMs != effect.getStartTime() ||

-                    effectDurationMs != effect.getDuration()) {

-                effect.setStartTimeAndDuration(effectStartTimeMs, effectDurationMs);

-                adjustedEffects.add(effect);

-            }

-        }

-

-        return adjustedEffects;

-    }

-

-    /**

-     * Adjust the start time and/or duration of overlays.

-     *

-     * @return The list of overlays which were adjusted

-     */

-    private List<Overlay> adjustOverlays() {

-        final List<Overlay> adjustedOverlays = new ArrayList<Overlay>();

-        final List<Overlay> overlays = getAllOverlays();

-        for (Overlay overlay : overlays) {

-            // Adjust the start time if necessary

-            final long overlayStartTimeMs;

-            if (overlay.getStartTime() > getDuration()) {

-                overlayStartTimeMs = 0;

-            } else {

-                overlayStartTimeMs = overlay.getStartTime();

-            }

-

-            // Adjust the duration if necessary

-            final long overlayDurationMs;

-            if (overlayStartTimeMs + overlay.getDuration() > getDuration()) {

-                overlayDurationMs = getDuration() - overlayStartTimeMs;

-            } else {

-                overlayDurationMs = overlay.getDuration();

-            }

-

-            if (overlayStartTimeMs != overlay.getStartTime() ||

-                    overlayDurationMs != overlay.getDuration()) {

-                overlay.setStartTimeAndDuration(overlayStartTimeMs, overlayDurationMs);

-                adjustedOverlays.add(overlay);

-            }

-        }

-

-        return adjustedOverlays;

-    }

-

-    /**

-     * Resize a bitmap to the specified width and height

-     *

-     * @param filename The filename

-     * @param width The thumbnail width

-     * @param height The thumbnail height

-     *

-     * @return The resized bitmap

-     */

-    private Bitmap scaleImage(String filename, int width, int height) throws IOException {

-        final BitmapFactory.Options dbo = new BitmapFactory.Options();

-        dbo.inJustDecodeBounds = true;

-        BitmapFactory.decodeFile(filename, dbo);

-

-        final int nativeWidth = dbo.outWidth;

-        final int nativeHeight = dbo.outHeight;

-        if (Log.isLoggable(TAG, Log.DEBUG)) {

-            Log.d(TAG, "generateThumbnail: Input: " + nativeWidth + "x" + nativeHeight

-                    + ", resize to: " + width + "x" + height);

-        }

-

-        final Bitmap srcBitmap;

-        float bitmapWidth, bitmapHeight;

-        if (nativeWidth > width || nativeHeight > height) {

-            float dx = ((float)nativeWidth) / ((float)width);

-            float dy = ((float)nativeHeight) / ((float)height);

-            if (dx > dy) {

-                bitmapWidth = width;

-                bitmapHeight = nativeHeight / dx;

-            } else {

-                bitmapWidth = nativeWidth / dy;

-                bitmapHeight = height;

-            }

-            // Create the bitmap from file

-            if (nativeWidth / bitmapWidth > 1) {

-                final BitmapFactory.Options options = new BitmapFactory.Options();

-                options.inSampleSize = nativeWidth / (int)bitmapWidth;

-                srcBitmap = BitmapFactory.decodeFile(filename, options);

-            } else {

-                srcBitmap = BitmapFactory.decodeFile(filename);

-            }

-        } else {

-            bitmapWidth = width;

-            bitmapHeight = height;

-            srcBitmap = BitmapFactory.decodeFile(filename);

-        }

-

-        if (srcBitmap == null) {

-            Log.e(TAG, "generateThumbnail: Cannot decode image bytes");

-            throw new IOException("Cannot decode file: " + mFilename);

-        }

-

-        // Create the canvas bitmap

-        final Bitmap bitmap = Bitmap.createBitmap((int)bitmapWidth, (int)bitmapHeight,

-                Bitmap.Config.ARGB_8888);

-        final Canvas canvas = new Canvas(bitmap);

-        canvas.drawBitmap(srcBitmap, new Rect(0, 0, srcBitmap.getWidth(), srcBitmap.getHeight()),

-                new Rect(0, 0, (int)bitmapWidth, (int)bitmapHeight), sResizePaint);

-        // Release the source bitmap

-        srcBitmap.recycle();

-        return bitmap;

-    }

-}

+/*
+ * 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.
+ */
+
+
+package android.media.videoeditor;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import java.util.ArrayList;
+import android.media.videoeditor.MediaArtistNativeHelper.ClipSettings;
+import android.media.videoeditor.MediaArtistNativeHelper.EditSettings;
+import android.media.videoeditor.MediaArtistNativeHelper.FileType;
+import android.media.videoeditor.MediaArtistNativeHelper.Properties;
+import android.util.Log;
+import android.util.Pair;
+
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.lang.Math;
+import java.util.List;
+
+/**
+ * This class represents an image item on the storyboard. Note that images are
+ * scaled down to the maximum supported resolution by preserving the native
+ * aspect ratio. To learn the scaled image dimensions use
+ * {@link #getScaledWidth()} and {@link #getScaledHeight()} respectively.
+ *
+ * {@hide}
+ */
+public class MediaImageItem extends MediaItem {
+    /**
+     *  Logging
+     */
+    private static final String TAG = "MediaImageItem";
+
+    /**
+     *  The resize paint
+     */
+    private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+
+    /**
+     *  Instance variables
+     */
+    private final int mWidth;
+    private final int mHeight;
+    private final int mAspectRatio;
+    private long mDurationMs;
+    private int mScaledWidth, mScaledHeight;
+    private String mScaledFilename;
+    private final VideoEditorImpl mVideoEditor;
+    private String mDecodedFilename;
+    private int mGeneratedClipHeight;
+    private int mGeneratedClipWidth;
+
+    private final MediaArtistNativeHelper mMANativeHelper;
+
+    /**
+     * This class cannot be instantiated by using the default constructor
+     */
+    @SuppressWarnings("unused")
+    private MediaImageItem() throws IOException {
+        this(null, null, null, 0, RENDERING_MODE_BLACK_BORDER);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param editor The video editor reference
+     * @param mediaItemId The media item id
+     * @param filename The image file name
+     * @param durationMs The duration of the image on the storyboard
+     * @param renderingMode The rendering mode
+     *
+     * @throws IOException
+     */
+    public MediaImageItem(VideoEditor editor, String mediaItemId,
+                         String filename, long durationMs,
+                         int renderingMode) throws IOException {
+
+        super(editor, mediaItemId, filename, renderingMode);
+
+        mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
+        mVideoEditor = ((VideoEditorImpl)editor);
+        try {
+            final Properties properties =
+                                   mMANativeHelper.getMediaProperties(filename);
+
+            switch (mMANativeHelper.getFileType(properties.fileType)) {
+                case MediaProperties.FILE_JPEG:
+                    break;
+                case MediaProperties.FILE_PNG:
+                    break;
+
+                default:
+                throw new IllegalArgumentException("Unsupported Input File Type");
+            }
+        } catch (Exception e) {
+            throw new IllegalArgumentException("Unsupported file or file not found");
+        }
+
+        /**
+         *  Determine the dimensions of the image
+         */
+        final BitmapFactory.Options dbo = new BitmapFactory.Options();
+        dbo.inJustDecodeBounds = true;
+        BitmapFactory.decodeFile(filename, dbo);
+
+        mWidth = dbo.outWidth;
+        mHeight = dbo.outHeight;
+        mDurationMs = durationMs;
+        mDecodedFilename = String.format(mMANativeHelper.getProjectPath() +
+                "/" + "decoded" + getId()+ ".rgb");
+        final FileOutputStream fl = new FileOutputStream(mDecodedFilename);
+        final DataOutputStream dos = new DataOutputStream(fl);
+        try {
+            mAspectRatio = mMANativeHelper.getAspectRatio(mWidth, mHeight);
+        } catch(IllegalArgumentException e) {
+            throw new IllegalArgumentException ("Null width and height");
+        }
+        mGeneratedClipHeight = 0;
+        mGeneratedClipWidth = 0;
+
+        /**
+         *  Images are stored in memory scaled to the maximum resolution to
+         *  save memory.
+         */
+        final Pair<Integer, Integer>[] resolutions =
+            MediaProperties.getSupportedResolutions(mAspectRatio);
+        /**
+         *  Get the highest resolution
+         */
+        final Pair<Integer, Integer> maxResolution = resolutions[resolutions.length - 1];
+        if (mHeight > maxResolution.second) {
+            /**
+             *  We need to scale the image
+             */
+            final Bitmap scaledImage = scaleImage(filename, maxResolution.first,
+                                                          maxResolution.second);
+            mScaledFilename = String.format(mMANativeHelper.getProjectPath() +
+                    "/" + "scaled" + getId()+ ".JPG");
+            if (!((new File(mScaledFilename)).exists())) {
+                super.mRegenerateClip = true;
+                final FileOutputStream f1 = new FileOutputStream(mScaledFilename);
+                scaledImage.compress(Bitmap.CompressFormat.JPEG, 50,f1);
+                f1.close();
+            }
+            mScaledWidth = scaledImage.getWidth();
+            mScaledHeight = scaledImage.getHeight();
+
+            int mNewWidth = 0;
+            int mNewHeight = 0;
+            if ((mScaledWidth % 2 ) != 0) {
+                mNewWidth = mScaledWidth - 1;
+            }
+            else {
+                mNewWidth = mScaledWidth;
+            }
+            if ((mScaledHeight % 2 ) != 0) {
+                mNewHeight = mScaledHeight - 1;
+            }
+            else {
+                mNewHeight = mScaledHeight;
+            }
+            final int [] framingBuffer = new int[mNewWidth];
+            final ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
+            IntBuffer intBuffer;
+
+            final byte[] array = byteBuffer.array();
+            int tmp = 0;
+            while (tmp < mNewHeight) {
+                scaledImage.getPixels(framingBuffer,0,mScaledWidth,0,
+                                                               tmp,mNewWidth,1);
+                intBuffer = byteBuffer.asIntBuffer();
+                intBuffer.put(framingBuffer,0,mNewWidth);
+                dos.write(array);
+                tmp += 1;
+            }
+            mScaledWidth = mNewWidth;
+            mScaledHeight = mNewHeight;
+            scaledImage.recycle();
+        } else {
+            final Bitmap scaledImage = BitmapFactory.decodeFile(filename);
+            mScaledFilename = String.format(mMANativeHelper.getProjectPath()
+                                + "/" + "scaled" + getId()+ ".JPG");
+            if (!((new File(mScaledFilename)).exists())) {
+                super.mRegenerateClip = true;
+                FileOutputStream f1 = new FileOutputStream(mScaledFilename);
+                scaledImage.compress(Bitmap.CompressFormat.JPEG, 50,f1);
+                f1.close();
+            }
+            mScaledWidth = scaledImage.getWidth();
+            mScaledHeight = scaledImage.getHeight();
+
+            int mNewWidth = 0;
+            int mNewheight = 0;
+            if ((mScaledWidth % 2 ) != 0) {
+                mNewWidth = mScaledWidth - 1;
+            }
+            else {
+                mNewWidth = mScaledWidth;
+            }
+            if ((mScaledHeight % 2 ) != 0) {
+                mNewheight = mScaledHeight - 1;
+            }
+            else {
+                mNewheight = mScaledHeight;
+            }
+            Bitmap imageBitmap = BitmapFactory.decodeFile(mScaledFilename);
+            final int [] framingBuffer = new int[mNewWidth];
+            ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
+            IntBuffer intBuffer;
+
+            byte[] array = byteBuffer.array();
+            int tmp = 0;
+            while (tmp < mNewheight) {
+                imageBitmap.getPixels(framingBuffer,0,mScaledWidth,0,
+                                                               tmp,mNewWidth,1);
+                intBuffer = byteBuffer.asIntBuffer();
+                intBuffer.put(framingBuffer,0,mNewWidth);
+                dos.write(array);
+                tmp += 1;
+            }
+            mScaledWidth = mNewWidth;
+            mScaledHeight = mNewheight;
+            imageBitmap.recycle();
+        }
+        fl.close();
+        System.gc();
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public int getFileType() {
+        if (mFilename.endsWith(".jpg") || mFilename.endsWith(".jpeg")
+                || mFilename.endsWith(".JPG") || mFilename.endsWith(".JPEG")) {
+            return MediaProperties.FILE_JPEG;
+        } else if (mFilename.endsWith(".png") || mFilename.endsWith(".PNG")) {
+            return MediaProperties.FILE_PNG;
+        } else {
+            return MediaProperties.FILE_UNSUPPORTED;
+        }
+    }
+
+    /**
+     * @return The scaled image file name
+     */
+    String getScaledImageFileName() {
+        return mScaledFilename;
+    }
+
+    /**
+     * @return The generated Kenburns clip height.
+     */
+    int getGeneratedClipHeight() {
+        return mGeneratedClipHeight;
+    }
+
+    /**
+     * @return The generated Kenburns clip width.
+     */
+    int getGeneratedClipWidth() {
+        return mGeneratedClipWidth;
+    }
+
+    /**
+     * @return The file name of image which is decoded and stored
+     * in rgb format
+     */
+    String getDecodedImageFileName() {
+        return mDecodedFilename;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public int getWidth() {
+        return mWidth;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public int getHeight() {
+        return mHeight;
+    }
+
+    /**
+     * @return The scaled width of the image.
+     */
+    public int getScaledWidth() {
+        return mScaledWidth;
+    }
+
+    /**
+     * @return The scaled height of the image.
+     */
+    public int getScaledHeight() {
+        return mScaledHeight;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public int getAspectRatio() {
+        return mAspectRatio;
+    }
+
+    /**
+     * This method will adjust the duration of bounding transitions, effects
+     * and overlays if the current duration of the transactions become greater
+     * than the maximum allowable duration.
+     *
+     * @param durationMs The duration of the image in the storyboard timeline
+     */
+    public void setDuration(long durationMs) {
+        if (durationMs == mDurationMs) {
+            return;
+        }
+
+        /**
+         * Invalidate the end transitions if necessary.
+         * This invalidation is necessary for the case in which an effect or
+         * an overlay is overlapping with the end transition
+         * (before the duration is changed) and it no longer overlaps with the
+         * transition after the duration is increased.
+         *
+         * The beginning transition does not need to be invalidated at this time
+         * because an effect or an overlay overlaps with the beginning
+         * transition, the begin transition is unaffected by a media item
+         * duration change.
+         */
+        invalidateEndTransition();
+
+        mDurationMs = durationMs;
+
+        adjustTransitions();
+        final List<Overlay> adjustedOverlays = adjustOverlays();
+        final List<Effect> adjustedEffects = adjustEffects();
+
+        /**
+         * Invalidate the beginning and end transitions after adjustments.
+         * This invalidation is necessary for the case in which an effect or
+         * an overlay was not overlapping with the beginning or end transitions
+         * before the setDuration reduces the duration of the media item and
+         * causes an overlap of the beginning and/or end transition with the
+         * effect.
+         */
+        invalidateBeginTransition(adjustedEffects, adjustedOverlays);
+        invalidateEndTransition();
+        if (getGeneratedImageClip() != null) {
+            /*
+             *  Delete the file
+             */
+            new File(getGeneratedImageClip()).delete();
+            /*
+             *  Invalidate the filename
+             */
+            setGeneratedImageClip(null);
+            super.setRegenerateClip(true);
+        }
+        mVideoEditor.updateTimelineDuration();
+    }
+
+    /**
+     * Invalidate the begin transition if any effects and overlays overlap
+     * with the begin transition.
+     *
+     * @param effects List of effects to check for transition overlap
+     * @param overlays List of overlays to check for transition overlap
+     */
+    private void invalidateBeginTransition(List<Effect> effects, List<Overlay> overlays) {
+        if (mBeginTransition != null && mBeginTransition.isGenerated()) {
+            final long transitionDurationMs = mBeginTransition.getDuration();
+
+            /**
+             *  The begin transition must be invalidated if it overlaps with
+             *  an effect.
+             */
+            for (Effect effect : effects) {
+                /**
+                 *  Check if the effect overlaps with the begin transition
+                 */
+                if (effect.getStartTime() < transitionDurationMs) {
+                    mBeginTransition.invalidate();
+                    break;
+                }
+            }
+
+            if (mBeginTransition.isGenerated()) {
+                /**
+                 *  The end transition must be invalidated if it overlaps with
+                 *  an overlay.
+                 */
+                for (Overlay overlay : overlays) {
+                    /**
+                     *  Check if the overlay overlaps with the end transition
+                     */
+                    if (overlay.getStartTime() < transitionDurationMs) {
+                        mBeginTransition.invalidate();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Invalidate the end transition if any effects and overlays overlap
+     * with the end transition.
+     */
+    private void invalidateEndTransition() {
+        if (mEndTransition != null && mEndTransition.isGenerated()) {
+            final long transitionDurationMs = mEndTransition.getDuration();
+
+            /**
+             *  The end transition must be invalidated if it overlaps with
+             *  an effect.
+             */
+            final List<Effect> effects = getAllEffects();
+            for (Effect effect : effects) {
+                /**
+                 *  Check if the effect overlaps with the end transition
+                 */
+                if (effect.getStartTime() + effect.getDuration() >
+                mDurationMs - transitionDurationMs) {
+                    mEndTransition.invalidate();
+                    break;
+                }
+            }
+
+            if (mEndTransition.isGenerated()) {
+                /**
+                 *  The end transition must be invalidated if it overlaps with
+                 *  an overlay.
+                 */
+                final List<Overlay> overlays = getAllOverlays();
+                for (Overlay overlay : overlays) {
+                    /**
+                     *  Check if the overlay overlaps with the end transition
+                     */
+                    if (overlay.getStartTime() + overlay.getDuration() >
+                    mDurationMs - transitionDurationMs) {
+                        mEndTransition.invalidate();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Adjust the start time and/or duration of effects.
+     *
+     * @return The list of effects which were adjusted
+     */
+    private List<Effect> adjustEffects() {
+        final List<Effect> adjustedEffects = new ArrayList<Effect>();
+        final List<Effect> effects = getAllEffects();
+        for (Effect effect : effects) {
+            /**
+             *  Adjust the start time if necessary
+             */
+            final long effectStartTimeMs;
+            if (effect.getStartTime() > getDuration()) {
+                effectStartTimeMs = 0;
+            } else {
+                effectStartTimeMs = effect.getStartTime();
+            }
+
+            /**
+             *  Adjust the duration if necessary
+             */
+            final long effectDurationMs;
+            if (effectStartTimeMs + effect.getDuration() > getDuration()) {
+                effectDurationMs = getDuration() - effectStartTimeMs;
+            } else {
+                effectDurationMs = effect.getDuration();
+            }
+
+            if (effectStartTimeMs != effect.getStartTime() ||
+                    effectDurationMs != effect.getDuration()) {
+                effect.setStartTimeAndDuration(effectStartTimeMs, effectDurationMs);
+                adjustedEffects.add(effect);
+            }
+        }
+
+        return adjustedEffects;
+    }
+
+    /**
+     * Adjust the start time and/or duration of overlays.
+     *
+     * @return The list of overlays which were adjusted
+     */
+    private List<Overlay> adjustOverlays() {
+        final List<Overlay> adjustedOverlays = new ArrayList<Overlay>();
+        final List<Overlay> overlays = getAllOverlays();
+        for (Overlay overlay : overlays) {
+            /**
+             *  Adjust the start time if necessary
+             */
+            final long overlayStartTimeMs;
+            if (overlay.getStartTime() > getDuration()) {
+                overlayStartTimeMs = 0;
+            } else {
+                overlayStartTimeMs = overlay.getStartTime();
+            }
+
+            /**
+             *  Adjust the duration if necessary
+             */
+            final long overlayDurationMs;
+            if (overlayStartTimeMs + overlay.getDuration() > getDuration()) {
+                overlayDurationMs = getDuration() - overlayStartTimeMs;
+            } else {
+                overlayDurationMs = overlay.getDuration();
+            }
+
+            if (overlayStartTimeMs != overlay.getStartTime() ||
+                    overlayDurationMs != overlay.getDuration()) {
+                overlay.setStartTimeAndDuration(overlayStartTimeMs, overlayDurationMs);
+                adjustedOverlays.add(overlay);
+            }
+        }
+
+        return adjustedOverlays;
+    }
+
+
+    /**
+     * This function sets the Ken Burn effect generated clip
+     * name.
+     *
+     * @param generatedFilePath The name of the generated clip
+     */
+    @Override
+    void setGeneratedImageClip(String generatedFilePath) {
+        super.setGeneratedImageClip(generatedFilePath);
+
+
+        // set the Kenburns clip width and height
+        mGeneratedClipHeight = getScaledHeight();
+        switch (mVideoEditor.getAspectRatio()) {
+            case MediaProperties.ASPECT_RATIO_3_2:
+                if (mGeneratedClipHeight == MediaProperties.HEIGHT_480)
+                    mGeneratedClipWidth = 720;
+                else if (mGeneratedClipHeight == MediaProperties.HEIGHT_720)
+                    mGeneratedClipWidth = 1080;
+                break;
+            case MediaProperties.ASPECT_RATIO_16_9:
+                if (mGeneratedClipHeight == MediaProperties.HEIGHT_360)
+                    mGeneratedClipWidth = 640;
+                else if (mGeneratedClipHeight == MediaProperties.HEIGHT_480)
+                    mGeneratedClipWidth = 854;
+                else if (mGeneratedClipHeight == MediaProperties.HEIGHT_720)
+                    mGeneratedClipWidth = 1280;
+                break;
+            case MediaProperties.ASPECT_RATIO_4_3:
+                if (mGeneratedClipHeight == MediaProperties.HEIGHT_480)
+                    mGeneratedClipWidth = 640;
+                if (mGeneratedClipHeight == MediaProperties.HEIGHT_720)
+                    mGeneratedClipWidth = 960;
+                break;
+            case MediaProperties.ASPECT_RATIO_5_3:
+                if (mGeneratedClipHeight == MediaProperties.HEIGHT_480)
+                    mGeneratedClipWidth = 800;
+                break;
+            case MediaProperties.ASPECT_RATIO_11_9:
+                if (mGeneratedClipHeight == MediaProperties.HEIGHT_144)
+                    mGeneratedClipWidth = 176;
+                break;
+        }
+    }
+
+    /**
+     * @return The name of the image clip
+     * generated with ken burns effect.
+     */
+    @Override
+    String getGeneratedImageClip() {
+        return super.getGeneratedImageClip();
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public long getDuration() {
+        return mDurationMs;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public long getTimelineDuration() {
+        return mDurationMs;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public Bitmap getThumbnail(int width, int height, long timeMs) throws IOException {
+        if (getGeneratedImageClip() != null) {
+            return mMANativeHelper.getPixels(getGeneratedImageClip(),
+                width, height,timeMs);
+        } else {
+            return scaleImage(mFilename, width, height);
+        }
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public Bitmap[] getThumbnailList(int width, int height, long startMs, long endMs,
+        int thumbnailCount) throws IOException {
+        //KenBurns was not applied on this.
+        if (getGeneratedImageClip() == null) {
+            final Bitmap thumbnail = scaleImage(mFilename, width, height);
+            final Bitmap[] thumbnailArray = new Bitmap[thumbnailCount];
+            for (int i = 0; i < thumbnailCount; i++) {
+                thumbnailArray[i] = thumbnail;
+            }
+            return thumbnailArray;
+
+
+        }
+        else {
+            if (startMs > endMs) {
+                throw new IllegalArgumentException("Start time is greater than end time");
+            }
+            if (endMs > mDurationMs) {
+                throw new IllegalArgumentException("End time is greater than file duration");
+            }
+            if (startMs == endMs) {
+                Bitmap[] bitmap = new Bitmap[1];
+                bitmap[0] = mMANativeHelper.getPixels(getGeneratedImageClip(),
+                    width, height,startMs);
+                return bitmap;
+            }
+            return mMANativeHelper.getPixelsList(getGeneratedImageClip(), width,
+                height,startMs,endMs,thumbnailCount);
+        }
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    void invalidateTransitions(long startTimeMs, long durationMs) {
+        /**
+         *  Check if the item overlaps with the beginning and end transitions
+         */
+        if (mBeginTransition != null) {
+            if (isOverlapping(startTimeMs, durationMs, 0, mBeginTransition.getDuration())) {
+                mBeginTransition.invalidate();
+            }
+        }
+
+        if (mEndTransition != null) {
+            final long transitionDurationMs = mEndTransition.getDuration();
+            if (isOverlapping(startTimeMs, durationMs,
+                    getDuration() - transitionDurationMs, transitionDurationMs)) {
+                mEndTransition.invalidate();
+            }
+        }
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    void invalidateTransitions(long oldStartTimeMs, long oldDurationMs, long newStartTimeMs,
+            long newDurationMs) {
+        /**
+         *  Check if the item overlaps with the beginning and end transitions
+         */
+        if (mBeginTransition != null) {
+            final long transitionDurationMs = mBeginTransition.getDuration();
+            /**
+             *  If the start time has changed and if the old or the new item
+             *  overlaps with the begin transition, invalidate the transition.
+             */
+            if (((oldStartTimeMs != newStartTimeMs)
+                    || (oldDurationMs != newDurationMs) )&&
+                    (isOverlapping(oldStartTimeMs, oldDurationMs, 0, transitionDurationMs) ||
+                    isOverlapping(newStartTimeMs, newDurationMs, 0,
+                    transitionDurationMs))) {
+                mBeginTransition.invalidate();
+            }
+        }
+
+        if (mEndTransition != null) {
+            final long transitionDurationMs = mEndTransition.getDuration();
+            /**
+             *  If the start time + duration has changed and if the old or the new
+             *  item overlaps the end transition, invalidate the transition
+             */
+            if (oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs &&
+                    (isOverlapping(oldStartTimeMs, oldDurationMs,
+                    mDurationMs - transitionDurationMs, transitionDurationMs) ||
+                    isOverlapping(newStartTimeMs, newDurationMs,
+                    mDurationMs - transitionDurationMs, transitionDurationMs))) {
+                mEndTransition.invalidate();
+            }
+        }
+    }
+
+    /**
+     * This function invalidates the rgb image clip,ken burns effect clip,
+     * and scaled image clip
+     */
+    void invalidate() {
+        if (getGeneratedImageClip() != null) {
+            new File(getGeneratedImageClip()).delete();
+            setGeneratedImageClip(null);
+            setRegenerateClip(true);
+        }
+        if (mScaledFilename != null) {
+            new File(mScaledFilename).delete();
+            mScaledFilename = null;
+        }
+        if (mDecodedFilename != null) {
+            new File(mDecodedFilename).delete();
+            mDecodedFilename = null;
+        }
+    }
+
+    /**
+     * @param KenBurnEffect object.
+     * @return an Object of {@link ClipSettings} with Ken Burn settings
+     * needed to generate the clip
+     */
+    private ClipSettings getKenBurns(EffectKenBurns effectKB) {
+        int PanZoomXa;
+        int PanZoomXb;
+        int width = 0, height = 0;
+        Rect start = new Rect();
+        Rect end = new Rect();
+        ClipSettings clipSettings = null;
+        clipSettings = new ClipSettings();
+        /**
+         *  image:
+        ---------------------------------------
+       |    Xa                                  |
+       | Ya ---------------                     |
+       |    |                |                  |
+       |    |                |                  |
+       |     ---------------    Xb       ratioB |
+       |        ratioA           -------        |
+       |                  Yb    |        |      |
+       |                        |        |      |
+       |                         -------        |
+        ---------------------------------------
+         */
+
+        effectKB.getKenBurnsSettings(start, end);
+        width = getWidth();
+        height = getHeight();
+        if ((start.left < 0) || (start.left > width) || (start.right < 0) || (start.right > width)
+                || (start.top < 0) || (start.top > height) || (start.bottom < 0)
+                || (start.bottom > height) || (end.left < 0) || (end.left > width)
+                || (end.right < 0) || (end.right > width) || (end.top < 0) || (end.top > height)
+                || (end.bottom < 0) || (end.bottom > height)) {
+            throw new IllegalArgumentException("Illegal arguments for KebBurns");
+        }
+
+        if (((width - (start.right - start.left) == 0) || (height - (start.bottom - start.top) == 0))
+                && ((width - (end.right - end.left) == 0) || (height - (end.bottom - end.top) == 0))) {
+            setRegenerateClip(false);
+            clipSettings.clipPath = getDecodedImageFileName();
+            clipSettings.fileType = FileType.JPG;
+            clipSettings.beginCutTime = 0;
+            clipSettings.endCutTime = (int)getTimelineDuration();
+            clipSettings.beginCutPercent = 0;
+            clipSettings.endCutPercent = 0;
+            clipSettings.panZoomEnabled = false;
+            clipSettings.panZoomPercentStart = 0;
+            clipSettings.panZoomTopLeftXStart = 0;
+            clipSettings.panZoomTopLeftYStart = 0;
+            clipSettings.panZoomPercentEnd = 0;
+            clipSettings.panZoomTopLeftXEnd = 0;
+            clipSettings.panZoomTopLeftYEnd = 0;
+            clipSettings.mediaRendering = mMANativeHelper
+            .getMediaItemRenderingMode(getRenderingMode());
+
+            clipSettings.rgbWidth = getScaledWidth();
+            clipSettings.rgbHeight = getScaledHeight();
+
+            return clipSettings;
+        }
+
+        PanZoomXa = (100 * start.width()) / width;
+        PanZoomXb = (100 * end.width()) / width;
+
+        clipSettings.clipPath = getDecodedImageFileName();
+        clipSettings.fileType = mMANativeHelper.getMediaItemFileType(getFileType());
+        clipSettings.beginCutTime = 0;
+        clipSettings.endCutTime = (int)getTimelineDuration();
+        clipSettings.beginCutPercent = 0;
+        clipSettings.endCutPercent = 0;
+        clipSettings.panZoomEnabled = true;
+        clipSettings.panZoomPercentStart = PanZoomXa;
+        clipSettings.panZoomTopLeftXStart = (start.left * 100) / width;
+        clipSettings.panZoomTopLeftYStart = (start.top * 100) / height;
+        clipSettings.panZoomPercentEnd = PanZoomXb;
+        clipSettings.panZoomTopLeftXEnd = (end.left * 100) / width;
+        clipSettings.panZoomTopLeftYEnd = (end.top * 100) / height;
+        clipSettings.mediaRendering
+            = mMANativeHelper.getMediaItemRenderingMode(getRenderingMode());
+
+        clipSettings.rgbWidth = getScaledWidth();
+        clipSettings.rgbHeight = getScaledHeight();
+
+        return clipSettings;
+    }
+
+
+    /**
+     * @param KenBurnEffect object.
+     * @return an Object of {@link ClipSettings} with Ken Burns
+     * generated clip name
+     */
+    ClipSettings generateKenburnsClip(EffectKenBurns effectKB) {
+        EditSettings editSettings = new EditSettings();
+        editSettings.clipSettingsArray = new ClipSettings[1];
+        String output = null;
+        ClipSettings clipSettings = new ClipSettings();
+        initClipSettings(clipSettings);
+        editSettings.clipSettingsArray[0] = getKenBurns(effectKB);
+        if ((getGeneratedImageClip() == null) && (getRegenerateClip())) {
+            output = mMANativeHelper.generateKenBurnsClip(editSettings, this);
+            setGeneratedImageClip(output);
+            setRegenerateClip(false);
+            clipSettings.clipPath = output;
+            clipSettings.fileType = FileType.THREE_GPP;
+
+            mGeneratedClipHeight = getScaledHeight();
+            switch (mVideoEditor.getAspectRatio()) {
+                case MediaProperties.ASPECT_RATIO_3_2:
+                    if (mGeneratedClipHeight == MediaProperties.HEIGHT_480)
+                        mGeneratedClipWidth = 720;
+                    else if (mGeneratedClipHeight == MediaProperties.HEIGHT_720)
+                        mGeneratedClipWidth = 1080;
+                    break;
+                case MediaProperties.ASPECT_RATIO_16_9:
+                    if (mGeneratedClipHeight == MediaProperties.HEIGHT_360)
+                        mGeneratedClipWidth = 640;
+                    else if (mGeneratedClipHeight == MediaProperties.HEIGHT_480)
+                        mGeneratedClipWidth = 854;
+                    else if (mGeneratedClipHeight == MediaProperties.HEIGHT_720)
+                        mGeneratedClipWidth = 1280;
+                    break;
+                case MediaProperties.ASPECT_RATIO_4_3:
+                    if (mGeneratedClipHeight == MediaProperties.HEIGHT_480)
+                        mGeneratedClipWidth = 640;
+                    if (mGeneratedClipHeight == MediaProperties.HEIGHT_720)
+                        mGeneratedClipWidth = 960;
+                    break;
+                case MediaProperties.ASPECT_RATIO_5_3:
+                    if (mGeneratedClipHeight == MediaProperties.HEIGHT_480)
+                        mGeneratedClipWidth = 800;
+                    break;
+                case MediaProperties.ASPECT_RATIO_11_9:
+                    if (mGeneratedClipHeight == MediaProperties.HEIGHT_144)
+                        mGeneratedClipWidth = 176;
+                    break;
+            }
+
+        } else {
+            if (getGeneratedImageClip() == null) {
+                clipSettings.clipPath = getDecodedImageFileName();
+                clipSettings.fileType = FileType.JPG;
+
+                clipSettings.rgbWidth = getScaledWidth();
+                clipSettings.rgbHeight = getScaledHeight();
+
+            } else {
+                clipSettings.clipPath = getGeneratedImageClip();
+                clipSettings.fileType = FileType.THREE_GPP;
+            }
+        }
+        clipSettings.mediaRendering = mMANativeHelper.getMediaItemRenderingMode(getRenderingMode());
+        clipSettings.beginCutTime = 0;
+        clipSettings.endCutTime = (int)getTimelineDuration();
+
+        return clipSettings;
+    }
+
+    /**
+     * @return an Object of {@link ClipSettings} with Image Clip
+     * properties data populated.If the image has Ken Burns effect applied,
+     * then file path contains generated image clip name with Ken Burns effect
+     */
+    ClipSettings getImageClipProperties() {
+        ClipSettings clipSettings = new ClipSettings();
+        List<Effect> effects = null;
+        EffectKenBurns effectKB = null;
+        boolean effectKBPresent = false;
+
+        effects = getAllEffects();
+        for (Effect effect : effects) {
+            if (effect instanceof EffectKenBurns) {
+                effectKB = (EffectKenBurns)effect;
+                effectKBPresent = true;
+                break;
+            }
+        }
+
+        if (effectKBPresent) {
+            clipSettings = generateKenburnsClip(effectKB);
+        } else {
+            /**
+             * Init the clip settings object
+             */
+            initClipSettings(clipSettings);
+            clipSettings.clipPath = getDecodedImageFileName();
+            clipSettings.fileType = FileType.JPG;
+            clipSettings.beginCutTime = 0;
+            clipSettings.endCutTime = (int)getTimelineDuration();
+            clipSettings.mediaRendering = mMANativeHelper
+                .getMediaItemRenderingMode(getRenderingMode());
+            clipSettings.rgbWidth = getScaledWidth();
+            clipSettings.rgbHeight = getScaledHeight();
+
+        }
+        return clipSettings;
+    }
+
+    /**
+     * Resize a bitmap to the specified width and height
+     *
+     * @param filename The filename
+     * @param width The thumbnail width
+     * @param height The thumbnail height
+     *
+     * @return The resized bitmap
+     */
+    private Bitmap scaleImage(String filename, int width, int height)
+    throws IOException {
+        final BitmapFactory.Options dbo = new BitmapFactory.Options();
+        dbo.inJustDecodeBounds = true;
+        BitmapFactory.decodeFile(filename, dbo);
+
+        final int nativeWidth = dbo.outWidth;
+        final int nativeHeight = dbo.outHeight;
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "generateThumbnail: Input: " + nativeWidth + "x" + nativeHeight
+                    + ", resize to: " + width + "x" + height);
+        }
+
+        final Bitmap srcBitmap;
+        float bitmapWidth, bitmapHeight;
+        if (nativeWidth > width || nativeHeight > height) {
+            float dx = ((float)nativeWidth) / ((float)width);
+            float dy = ((float)nativeHeight) / ((float)height);
+
+            if (dx > dy) {
+                bitmapWidth = width;
+                bitmapHeight = Math.round(nativeHeight / dx);
+            } else {
+                bitmapWidth = Math.round(nativeWidth / dy);
+                bitmapHeight = height;
+            }
+
+            /**
+             *  Create the bitmap from file
+             */
+            if (nativeWidth / bitmapWidth > 1) {
+
+                final BitmapFactory.Options options = new BitmapFactory.Options();
+                options.inSampleSize = nativeWidth / (int)bitmapWidth;
+                srcBitmap = BitmapFactory.decodeFile(filename, options);
+            } else {
+                srcBitmap = BitmapFactory.decodeFile(filename);
+            }
+        } else {
+            bitmapWidth = width;
+            bitmapHeight = height;
+            srcBitmap = BitmapFactory.decodeFile(filename);
+
+        }
+
+        if (srcBitmap == null) {
+            Log.e(TAG, "generateThumbnail: Cannot decode image bytes");
+            throw new IOException("Cannot decode file: " + mFilename);
+        }
+
+        /**
+         *  Create the canvas bitmap
+         */
+        final Bitmap bitmap = Bitmap.createBitmap((int)bitmapWidth,
+                                                  (int)bitmapHeight,
+                                                  Bitmap.Config.ARGB_8888);
+        final Canvas canvas = new Canvas(bitmap);
+        canvas.drawBitmap(srcBitmap, new Rect(0, 0, srcBitmap.getWidth(),
+                                              srcBitmap.getHeight()),
+                                              new Rect(0, 0, (int)bitmapWidth,
+                                              (int)bitmapHeight), sResizePaint);
+        /**
+         *  Release the source bitmap
+         */
+        srcBitmap.recycle();
+        return bitmap;
+    }
+}
diff --git a/media/java/android/media/videoeditor/MediaItem.java b/media/java/android/media/videoeditor/MediaItem.java
index 20fd6c9..a24b46e 100755
--- a/media/java/android/media/videoeditor/MediaItem.java
+++ b/media/java/android/media/videoeditor/MediaItem.java
@@ -1,510 +1,775 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-import java.io.IOException;

-import java.util.ArrayList;

-import java.util.List;

-

-import android.graphics.Bitmap;

-

-/**

- * This abstract class describes the base class for any MediaItem. Objects are

- * defined with a file path as a source data.

- * {@hide}

-s */

-public abstract class MediaItem {

-    // A constant which can be used to specify the end of the file (instead of

-    // providing the actual duration of the media item).

-    public final static int END_OF_FILE = -1;

-

-    // Rendering modes

-    /**

-     * When using the RENDERING_MODE_BLACK_BORDER rendering mode video frames

-     * are resized by preserving the aspect ratio until the movie matches one of

-     * the dimensions of the output movie. The areas outside the resized video

-     * clip are rendered black.

-     */

-    public static final int RENDERING_MODE_BLACK_BORDER = 0;

-

-    /**

-     * When using the RENDERING_MODE_STRETCH rendering mode video frames are

-     * stretched horizontally or vertically to match the current aspect ratio of

-     * the video editor.

-     */

-    public static final int RENDERING_MODE_STRETCH = 1;

-

-    /**

-     * When using the RENDERING_MODE_CROPPING rendering mode video frames are

-     * scaled horizontally or vertically by preserving the original aspect

-     * ratio of the media item.

-     */

-    public static final int RENDERING_MODE_CROPPING = 2;

-

-

-    // The unique id of the MediaItem

-    private final String mUniqueId;

-

-    // The name of the file associated with the MediaItem

-    protected final String mFilename;

-

-    // List of effects

-    private final List<Effect> mEffects;

-

-    // List of overlays

-    private final List<Overlay> mOverlays;

-

-    // The rendering mode

-    private int mRenderingMode;

-

-    // Beginning and end transitions

-    protected Transition mBeginTransition;

-    protected Transition mEndTransition;

-

-    /**

-     * Constructor

-     *

-     * @param editor The video editor reference

-     * @param mediaItemId The MediaItem id

-     * @param filename name of the media file.

-     * @param renderingMode The rendering mode

-     *

-     * @throws IOException if file is not found

-     * @throws IllegalArgumentException if a capability such as file format is not

-     *             supported the exception object contains the unsupported

-     *             capability

-     */

-    protected MediaItem(VideoEditor editor, String mediaItemId, String filename,

-            int renderingMode) throws IOException {

-        mUniqueId = mediaItemId;

-        mFilename = filename;

-        mRenderingMode = renderingMode;

-        mEffects = new ArrayList<Effect>();

-        mOverlays = new ArrayList<Overlay>();

-        mBeginTransition = null;

-        mEndTransition = null;

-    }

-

-    /**

-     * @return The id of the media item

-     */

-    public String getId() {

-        return mUniqueId;

-    }

-

-    /**

-     * @return The media source file name

-     */

-    public String getFilename() {

-        return mFilename;

-    }

-

-    /**

-     * If aspect ratio of the MediaItem is different from the aspect ratio of

-     * the editor then this API controls the rendering mode.

-     *

-     * @param renderingMode rendering mode. It is one of:

-     *            {@link #RENDERING_MODE_BLACK_BORDER},

-     *            {@link #RENDERING_MODE_STRETCH}

-     */

-    public void setRenderingMode(int renderingMode) {

-        mRenderingMode = renderingMode;

-        if (mBeginTransition != null) {

-            mBeginTransition.invalidate();

-        }

-

-        if (mEndTransition != null) {

-            mEndTransition.invalidate();

-        }

-    }

-

-    /**

-     * @return The rendering mode

-     */

-    public int getRenderingMode() {

-        return mRenderingMode;

-    }

-

-    /**

-     * @param transition The beginning transition

-     */

-    void setBeginTransition(Transition transition) {

-        mBeginTransition = transition;

-    }

-

-    /**

-     * @return The begin transition

-     */

-    public Transition getBeginTransition() {

-        return mBeginTransition;

-    }

-

-    /**

-     * @param transition The end transition

-     */

-    void setEndTransition(Transition transition) {

-        mEndTransition = transition;

-    }

-

-    /**

-     * @return The end transition

-     */

-    public Transition getEndTransition() {

-        return mEndTransition;

-    }

-

-    /**

-     * @return The timeline duration. This is the actual duration in the

-     *      timeline (trimmed duration)

-     */

-    public abstract long getTimelineDuration();

-

-    /**

-     * @return The is the full duration of the media item (not trimmed)

-     */

-    public abstract long getDuration();

-

-    /**

-     * @return The source file type

-     */

-    public abstract int getFileType();

-

-    /**

-     * @return Get the native width of the media item

-     */

-    public abstract int getWidth();

-

-    /**

-     * @return Get the native height of the media item

-     */

-    public abstract int getHeight();

-

-    /**

-     * Get aspect ratio of the source media item.

-     *

-     * @return the aspect ratio as described in MediaProperties.

-     *  MediaProperties.ASPECT_RATIO_UNDEFINED if aspect ratio is not

-     *  supported as in MediaProperties

-     */

-    public abstract int getAspectRatio();

-

-    /**

-     * Add the specified effect to this media item.

-     *

-     * Note that certain types of effects cannot be applied to video and to

-     * image media items. For example in certain implementation a Ken Burns

-     * implementation cannot be applied to video media item.

-     *

-     * This method invalidates transition video clips if the

-     * effect overlaps with the beginning and/or the end transition.

-     *

-     * @param effect The effect to apply

-     * @throws IllegalStateException if a preview or an export is in progress

-     * @throws IllegalArgumentException if the effect start and/or duration are

-     *      invalid or if the effect cannot be applied to this type of media

-     *      item or if the effect id is not unique across all the Effects

-     *      added.

-     */

-    public void addEffect(Effect effect) {

-        if (effect.getMediaItem() != this) {

-            throw new IllegalArgumentException("Media item mismatch");

-        }

-

-        if (mEffects.contains(effect)) {

-            throw new IllegalArgumentException("Effect already exists: " + effect.getId());

-        }

-

-        if (effect.getStartTime() + effect.getDuration() > getDuration()) {

-            throw new IllegalArgumentException(

-                    "Effect start time + effect duration > media clip duration");

-        }

-

-        mEffects.add(effect);

-        invalidateTransitions(effect.getStartTime(), effect.getDuration());

-    }

-

-    /**

-     * Remove the effect with the specified id.

-     *

-     * This method invalidates a transition video clip if the effect overlaps

-     * with a transition.

-     *

-     * @param effectId The id of the effect to be removed

-     *

-     * @return The effect that was removed

-     * @throws IllegalStateException if a preview or an export is in progress

-     */

-    public Effect removeEffect(String effectId) {

-        for (Effect effect : mEffects) {

-            if (effect.getId().equals(effectId)) {

-                mEffects.remove(effect);

-                invalidateTransitions(effect.getStartTime(), effect.getDuration());

-                return effect;

-            }

-        }

-

-        return null;

-    }

-

-    /**

-     * Find the effect with the specified id

-     *

-     * @param effectId The effect id

-     *

-     * @return The effect with the specified id (null if it does not exist)

-     */

-    public Effect getEffect(String effectId) {

-        for (Effect effect : mEffects) {

-            if (effect.getId().equals(effectId)) {

-                return effect;

-            }

-        }

-

-        return null;

-    }

-

-    /**

-     * Get the list of effects.

-     *

-     * @return the effects list. If no effects exist an empty list will be returned.

-     */

-    public List<Effect> getAllEffects() {

-        return mEffects;

-    }

-

-    /**

-     * Add an overlay to the storyboard. This method invalidates a transition

-     * video clip if the overlay overlaps with a transition.

-     *

-     * @param overlay The overlay to add

-     * @throws IllegalStateException if a preview or an export is in progress or

-     *             if the overlay id is not unique across all the overlays

-     *             added or if the bitmap is not specified or if the dimensions of

-     *             the bitmap do not match the dimensions of the media item

-     */

-    public void addOverlay(Overlay overlay) {

-        if (overlay.getMediaItem() != this) {

-            throw new IllegalArgumentException("Media item mismatch");

-        }

-

-        if (mOverlays.contains(overlay)) {

-            throw new IllegalArgumentException("Overlay already exists: " + overlay.getId());

-        }

-

-        if (overlay.getStartTime() + overlay.getDuration() > getDuration()) {

-            throw new IllegalArgumentException(

-                    "Overlay start time + overlay duration > media clip duration");

-        }

-

-        if (overlay instanceof OverlayFrame) {

-            final OverlayFrame frame = (OverlayFrame)overlay;

-            final Bitmap bitmap = frame.getBitmap();

-            if (bitmap == null) {

-                throw new IllegalArgumentException("Overlay bitmap not specified");

-            }

-

-            final int scaledWidth, scaledHeight;

-            if (this instanceof MediaVideoItem) {

-                scaledWidth = getWidth();

-                scaledHeight = getHeight();

-            } else {

-                scaledWidth = ((MediaImageItem)this).getScaledWidth();

-                scaledHeight = ((MediaImageItem)this).getScaledHeight();

-            }

-

-            // The dimensions of the overlay bitmap must be the same as the

-            // media item dimensions

-            if (bitmap.getWidth() != scaledWidth || bitmap.getHeight() != scaledHeight) {

-                throw new IllegalArgumentException(

-                        "Bitmap dimensions must match media item dimensions");

-            }

-        } else {

-            throw new IllegalArgumentException("Overlay not supported");

-        }

-

-        mOverlays.add(overlay);

-        invalidateTransitions(overlay.getStartTime(), overlay.getDuration());

-    }

-

-    /**

-     * Remove the overlay with the specified id.

-     *

-     * This method invalidates a transition video clip if the overlay overlaps

-     * with a transition.

-     *

-     * @param overlayId The id of the overlay to be removed

-     *

-     * @return The overlay that was removed

-     * @throws IllegalStateException if a preview or an export is in progress

-     */

-    public Overlay removeOverlay(String overlayId) {

-        for (Overlay overlay : mOverlays) {

-            if (overlay.getId().equals(overlayId)) {

-                mOverlays.remove(overlay);

-                if (overlay instanceof OverlayFrame) {

-                    ((OverlayFrame)overlay).invalidate();

-                }

-                invalidateTransitions(overlay.getStartTime(), overlay.getDuration());

-                return overlay;

-            }

-        }

-

-        return null;

-    }

-

-    /**

-     * Find the overlay with the specified id

-     *

-     * @param overlayId The overlay id

-     *

-     * @return The overlay with the specified id (null if it does not exist)

-     */

-    public Overlay getOverlay(String overlayId) {

-        for (Overlay overlay : mOverlays) {

-            if (overlay.getId().equals(overlayId)) {

-                return overlay;

-            }

-        }

-

-        return null;

-    }

-

-    /**

-     * Get the list of overlays associated with this media item

-     *

-     * Note that if any overlay source files are not accessible anymore,

-     * this method will still provide the full list of overlays.

-     *

-     * @return The list of overlays. If no overlays exist an empty list will

-     *  be returned.

-     */

-    public List<Overlay> getAllOverlays() {

-        return mOverlays;

-    }

-

-    /**

-     * Create a thumbnail at specified time in a video stream in Bitmap format

-     *

-     * @param width width of the thumbnail in pixels

-     * @param height height of the thumbnail in pixels

-     * @param timeMs The time in the source video file at which the thumbnail is

-     *            requested (even if trimmed).

-     *

-     * @return The thumbnail as a Bitmap.

-     *

-     * @throws IOException if a file error occurs

-     * @throws IllegalArgumentException if time is out of video duration

-     */

-    public abstract Bitmap getThumbnail(int width, int height, long timeMs) throws IOException;

-

-    /**

-     * Get the array of Bitmap thumbnails between start and end.

-     *

-     * @param width width of the thumbnail in pixels

-     * @param height height of the thumbnail in pixels

-     * @param startMs The start of time range in milliseconds

-     * @param endMs The end of the time range in milliseconds

-     * @param thumbnailCount The thumbnail count

-     *

-     * @return The array of Bitmaps

-     *

-     * @throws IOException if a file error occurs

-     */

-    public abstract Bitmap[] getThumbnailList(int width, int height, long startMs, long endMs,

-            int thumbnailCount) throws IOException;

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public boolean equals(Object object) {

-        if (!(object instanceof MediaItem)) {

-            return false;

-        }

-        return mUniqueId.equals(((MediaItem)object).mUniqueId);

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public int hashCode() {

-        return mUniqueId.hashCode();

-    }

-

-    /**

-     * Invalidate the start and end transitions if necessary

-     *

-     * @param startTimeMs The start time of the effect or overlay

-     * @param durationMs The duration of the effect or overlay

-     */

-    abstract void invalidateTransitions(long startTimeMs, long durationMs);

-

-    /**

-     * Invalidate the start and end transitions if necessary. This method is

-     * typically called when the start time and/or duration of an overlay or

-     * effect is changing.

-     *

-     * @param oldStartTimeMs The old start time of the effect or overlay

-     * @param oldDurationMs The old duration of the effect or overlay

-     * @param newStartTimeMs The new start time of the effect or overlay

-     * @param newDurationMs The new duration of the effect or overlay

-     */

-    abstract void invalidateTransitions(long oldStartTimeMs, long oldDurationMs,

-            long newStartTimeMs, long newDurationMs);

-

-    /**

-     * Check if two items overlap in time

-     *

-     * @param startTimeMs1 Item 1 start time

-     * @param durationMs1 Item 1 duration

-     * @param startTimeMs2 Item 2 start time

-     * @param durationMs2 Item 2 end time

-     *

-     * @return true if the two items overlap

-     */

-    protected boolean isOverlapping(long startTimeMs1, long durationMs1,

-            long startTimeMs2, long durationMs2) {

-       if (startTimeMs1 + durationMs1 <= startTimeMs2) {

-           return false;

-       } else if (startTimeMs1 >= startTimeMs2 + durationMs2) {

-           return false;

-       }

-

-       return true;

-    }

-

-    /**

-     * Adjust the duration transitions.

-     */

-    protected void adjustTransitions() {

-        // Check if the duration of transitions need to be adjusted

-        if (mBeginTransition != null) {

-            final long maxDurationMs = mBeginTransition.getMaximumDuration();

-            if (mBeginTransition.getDuration() > maxDurationMs) {

-                mBeginTransition.setDuration(maxDurationMs);

-            }

-        }

-

-        if (mEndTransition != null) {

-            final long maxDurationMs = mEndTransition.getMaximumDuration();

-            if (mEndTransition.getDuration() > maxDurationMs) {

-                mEndTransition.setDuration(maxDurationMs);

-            }

-        }

-    }

-}

+/*
+ * 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.
+ */
+
+
+package android.media.videoeditor;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import java.io.DataOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
+import android.graphics.Bitmap;
+import android.media.videoeditor.MediaArtistNativeHelper.ClipSettings;
+import android.media.videoeditor.MediaArtistNativeHelper.FileType;
+import android.media.videoeditor.MediaArtistNativeHelper.MediaRendering;
+
+/**
+ * This abstract class describes the base class for any MediaItem. Objects are
+ * defined with a file path as a source data.
+ * {@hide}
+ */
+public abstract class MediaItem {
+    /**
+     *  A constant which can be used to specify the end of the file (instead of
+     *  providing the actual duration of the media item).
+     */
+    public final static int END_OF_FILE = -1;
+
+    /**
+     *  Rendering modes
+     */
+    /**
+     * When using the RENDERING_MODE_BLACK_BORDER rendering mode video frames
+     * are resized by preserving the aspect ratio until the movie matches one of
+     * the dimensions of the output movie. The areas outside the resized video
+     * clip are rendered black.
+     */
+    public static final int RENDERING_MODE_BLACK_BORDER = 0;
+
+    /**
+     * When using the RENDERING_MODE_STRETCH rendering mode video frames are
+     * stretched horizontally or vertically to match the current aspect ratio of
+     * the video editor.
+     */
+    public static final int RENDERING_MODE_STRETCH = 1;
+
+    /**
+     * When using the RENDERING_MODE_CROPPING rendering mode video frames are
+     * scaled horizontally or vertically by preserving the original aspect ratio
+     * of the media item.
+     */
+    public static final int RENDERING_MODE_CROPPING = 2;
+
+    /**
+     *  The unique id of the MediaItem
+     */
+    private final String mUniqueId;
+
+    /**
+     *  The name of the file associated with the MediaItem
+     */
+    protected final String mFilename;
+
+    /**
+     *  List of effects
+     */
+    private final List<Effect> mEffects;
+
+    /**
+     *  List of overlays
+     */
+    private final List<Overlay> mOverlays;
+
+    /**
+     *  The rendering mode
+     */
+    private int mRenderingMode;
+
+    private final MediaArtistNativeHelper mMANativeHelper;
+
+    private final String mProjectPath;
+
+    /**
+     *  Beginning and end transitions
+     */
+    protected Transition mBeginTransition;
+
+    protected Transition mEndTransition;
+
+    protected String mGeneratedImageClip;
+
+    protected boolean mRegenerateClip;
+
+    private boolean mBlankFrameGenerated = false;
+
+    private String mBlankFrameFilename = null;
+
+    /**
+     * Constructor
+     *
+     * @param editor The video editor reference
+     * @param mediaItemId The MediaItem id
+     * @param filename name of the media file.
+     * @param renderingMode The rendering mode
+     * @throws IOException if file is not found
+     * @throws IllegalArgumentException if a capability such as file format is
+     *             not supported the exception object contains the unsupported
+     *             capability
+     */
+    protected MediaItem(VideoEditor editor, String mediaItemId, String filename,
+                        int renderingMode) throws IOException {
+        if (filename == null) {
+            throw new IllegalArgumentException("MediaItem : filename is null");
+        }
+        mUniqueId = mediaItemId;
+        mFilename = filename;
+        mRenderingMode = renderingMode;
+        mEffects = new ArrayList<Effect>();
+        mOverlays = new ArrayList<Overlay>();
+        mBeginTransition = null;
+        mEndTransition = null;
+        mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
+        mProjectPath = editor.getPath();
+        mRegenerateClip = false;
+        mGeneratedImageClip = null;
+    }
+
+    /**
+     * @return The id of the media item
+     */
+    public String getId() {
+        return mUniqueId;
+    }
+
+    /**
+     * @return The media source file name
+     */
+    public String getFilename() {
+        return mFilename;
+    }
+
+    /**
+     * If aspect ratio of the MediaItem is different from the aspect ratio of
+     * the editor then this API controls the rendering mode.
+     *
+     * @param renderingMode rendering mode. It is one of:
+     *            {@link #RENDERING_MODE_BLACK_BORDER},
+     *            {@link #RENDERING_MODE_STRETCH}
+     */
+    public void setRenderingMode(int renderingMode) {
+        switch (renderingMode) {
+            case RENDERING_MODE_BLACK_BORDER:
+            case RENDERING_MODE_STRETCH:
+            case RENDERING_MODE_CROPPING:
+                break;
+
+            default:
+                throw new IllegalArgumentException("Invalid Rendering Mode");
+        }
+        mRenderingMode = renderingMode;
+        if (mBeginTransition != null) {
+            mBeginTransition.invalidate();
+        }
+
+        if (mEndTransition != null) {
+            mEndTransition.invalidate();
+        }
+        mMANativeHelper.setGeneratePreview(true);
+    }
+
+    /**
+     * @return The rendering mode
+     */
+    public int getRenderingMode() {
+        return mRenderingMode;
+    }
+
+    /**
+     * @param transition The beginning transition
+     */
+    void setBeginTransition(Transition transition) {
+        mBeginTransition = transition;
+    }
+
+    /**
+     * @return The begin transition
+     */
+    public Transition getBeginTransition() {
+        return mBeginTransition;
+    }
+
+    /**
+     * @param transition The end transition
+     */
+    void setEndTransition(Transition transition) {
+        mEndTransition = transition;
+    }
+
+    /**
+     * @return The end transition
+     */
+    public Transition getEndTransition() {
+        return mEndTransition;
+    }
+
+    /**
+     * @return The timeline duration. This is the actual duration in the
+     *         timeline (trimmed duration)
+     */
+    public abstract long getTimelineDuration();
+
+    /**
+     * @return The is the full duration of the media item (not trimmed)
+     */
+    public abstract long getDuration();
+
+    /**
+     * @return The source file type
+     */
+    public abstract int getFileType();
+
+    /**
+     * @return Get the native width of the media item
+     */
+    public abstract int getWidth();
+
+    /**
+     * @return Get the native height of the media item
+     */
+    public abstract int getHeight();
+
+    /**
+     * Get aspect ratio of the source media item.
+     *
+     * @return the aspect ratio as described in MediaProperties.
+     *         MediaProperties.ASPECT_RATIO_UNDEFINED if aspect ratio is not
+     *         supported as in MediaProperties
+     */
+    public abstract int getAspectRatio();
+
+    /**
+     * Add the specified effect to this media item.
+     *
+     * Note that certain types of effects cannot be applied to video and to
+     * image media items. For example in certain implementation a Ken Burns
+     * implementation cannot be applied to video media item.
+     *
+     * This method invalidates transition video clips if the
+     * effect overlaps with the beginning and/or the end transition.
+     *
+     * @param effect The effect to apply
+     * @throws IllegalStateException if a preview or an export is in progress
+     * @throws IllegalArgumentException if the effect start and/or duration are
+     *      invalid or if the effect cannot be applied to this type of media
+     *      item or if the effect id is not unique across all the Effects
+     *      added.
+     */
+    public void addEffect(Effect effect) {
+
+        if (effect == null) {
+            throw new IllegalArgumentException("NULL effect cannot be applied");
+        }
+
+        if (effect.getMediaItem() != this) {
+            throw new IllegalArgumentException("Media item mismatch");
+        }
+
+        if (mEffects.contains(effect)) {
+            throw new IllegalArgumentException("Effect already exists: " + effect.getId());
+        }
+
+        if (effect.getStartTime() + effect.getDuration() > getDuration()) {
+            throw new IllegalArgumentException(
+            "Effect start time + effect duration > media clip duration");
+        }
+
+        mEffects.add(effect);
+
+        invalidateTransitions(effect.getStartTime(), effect.getDuration());
+        if (mMANativeHelper != null) {
+            if (effect instanceof EffectKenBurns) {
+                mRegenerateClip = true;
+            }
+            mMANativeHelper.setGeneratePreview(true);
+        }
+    }
+
+    /**
+     * Remove the effect with the specified id.
+     *
+     * This method invalidates a transition video clip if the effect overlaps
+     * with a transition.
+     *
+     * @param effectId The id of the effect to be removed
+     *
+     * @return The effect that was removed
+     * @throws IllegalStateException if a preview or an export is in progress
+     */
+    public Effect removeEffect(String effectId) {
+        for (Effect effect : mEffects) {
+            if (effect.getId().equals(effectId)) {
+                mEffects.remove(effect);
+                invalidateTransitions(effect.getStartTime(), effect.getDuration());
+                if (mMANativeHelper != null) {
+                    if (effect instanceof EffectKenBurns) {
+                        if (mGeneratedImageClip != null) {
+                            /**
+                             *  Delete the file
+                             */
+                            new File(mGeneratedImageClip).delete();
+                            /**
+                             *  Invalidate the filename
+                             */
+                            mGeneratedImageClip = null;
+                        }
+                        mRegenerateClip = false;
+                    }
+                    mMANativeHelper.setGeneratePreview(true);
+                }
+                return effect;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Set the filepath of the generated image clip when the effect is added.
+     *
+     * @param The filepath of the generated image clip.
+     */
+    void setGeneratedImageClip(String generatedFilePath) {
+        mGeneratedImageClip = generatedFilePath;
+    }
+
+    /**
+     * Get the filepath of the generated image clip when the effect is added.
+     *
+     * @return The filepath of the generated image clip (null if it does not
+     *         exist)
+     */
+    String getGeneratedImageClip() {
+        return mGeneratedImageClip;
+    }
+
+    /**
+     * Find the effect with the specified id
+     *
+     * @param effectId The effect id
+     * @return The effect with the specified id (null if it does not exist)
+     */
+    public Effect getEffect(String effectId) {
+        for (Effect effect : mEffects) {
+            if (effect.getId().equals(effectId)) {
+                return effect;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Get the list of effects.
+     *
+     * @return the effects list. If no effects exist an empty list will be
+     *         returned.
+     */
+    public List<Effect> getAllEffects() {
+        return mEffects;
+    }
+
+    /**
+     * Add an overlay to the storyboard. This method invalidates a transition
+     * video clip if the overlay overlaps with a transition.
+     *
+     * @param overlay The overlay to add
+     * @throws IllegalStateException if a preview or an export is in progress or
+     *             if the overlay id is not unique across all the overlays added
+     *             or if the bitmap is not specified or if the dimensions of the
+     *             bitmap do not match the dimensions of the media item
+     * @throws FileNotFoundException, IOException if overlay could not be saved
+     *             to project path
+     */
+    public void addOverlay(Overlay overlay) throws FileNotFoundException, IOException {
+        if (overlay == null) {
+            throw new IllegalArgumentException("NULL Overlay cannot be applied");
+        }
+
+        if (overlay.getMediaItem() != this) {
+            throw new IllegalArgumentException("Media item mismatch");
+        }
+
+        if (mOverlays.contains(overlay)) {
+            throw new IllegalArgumentException("Overlay already exists: " + overlay.getId());
+        }
+
+        if (overlay.getStartTime() + overlay.getDuration() > getDuration()) {
+            throw new IllegalArgumentException(
+            "Overlay start time + overlay duration > media clip duration");
+        }
+
+        if (overlay instanceof OverlayFrame) {
+            final OverlayFrame frame = (OverlayFrame)overlay;
+            final Bitmap bitmap = frame.getBitmap();
+            if (bitmap == null) {
+                throw new IllegalArgumentException("Overlay bitmap not specified");
+            }
+
+            ((OverlayFrame)overlay).save(mProjectPath);
+
+            final int scaledWidth, scaledHeight;
+            if (this instanceof MediaVideoItem) {
+                scaledWidth = getWidth();
+                scaledHeight = getHeight();
+            } else {
+                scaledWidth = ((MediaImageItem)this).getScaledWidth();
+                scaledHeight = ((MediaImageItem)this).getScaledHeight();
+            }
+
+            /**
+             * The dimensions of the overlay bitmap must be the same as the
+             * media item dimensions
+             */
+            if (bitmap.getWidth() != scaledWidth || bitmap.getHeight() != scaledHeight) {
+                throw new IllegalArgumentException(
+                "Bitmap dimensions must match media item dimensions");
+            }
+        } else {
+            throw new IllegalArgumentException("Overlay not supported");
+        }
+
+        mOverlays.add(overlay);
+        invalidateTransitions(overlay.getStartTime(), overlay.getDuration());
+        if (mMANativeHelper != null) {
+            mMANativeHelper.setGeneratePreview(true);
+        }
+    }
+
+    /**
+     * @param flag The flag to indicate if regeneration of clip is true or
+     *            false.
+     */
+    void setRegenerateClip(boolean flag) {
+        mRegenerateClip = flag;
+    }
+
+    /**
+     * @return flag The flag to indicate if regeneration of clip is true or
+     *         false.
+     */
+    boolean getRegenerateClip() {
+        return mRegenerateClip;
+    }
+
+    /**
+     * Remove the overlay with the specified id.
+     *
+     * This method invalidates a transition video clip if the overlay overlaps
+     * with a transition.
+     *
+     * @param overlayId The id of the overlay to be removed
+     *
+     * @return The overlay that was removed
+     * @throws IllegalStateException if a preview or an export is in progress
+     */
+    public Overlay removeOverlay(String overlayId) {
+        for (Overlay overlay : mOverlays) {
+            if (overlay.getId().equals(overlayId)) {
+                mOverlays.remove(overlay);
+                if (mMANativeHelper != null) {
+                    mMANativeHelper.setGeneratePreview(true);
+                }
+                if (overlay instanceof OverlayFrame) {
+                    ((OverlayFrame)overlay).invalidate();
+                }
+                invalidateTransitions(overlay.getStartTime(), overlay.getDuration());
+                return overlay;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Find the overlay with the specified id
+     *
+     * @param overlayId The overlay id
+     *
+     * @return The overlay with the specified id (null if it does not exist)
+     */
+    public Overlay getOverlay(String overlayId) {
+        for (Overlay overlay : mOverlays) {
+            if (overlay.getId().equals(overlayId)) {
+                return overlay;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Get the list of overlays associated with this media item
+     *
+     * Note that if any overlay source files are not accessible anymore,
+     * this method will still provide the full list of overlays.
+     *
+     * @return The list of overlays. If no overlays exist an empty list will
+     *         be returned.
+     */
+    public List<Overlay> getAllOverlays() {
+        return mOverlays;
+    }
+
+    /**
+     * Create a thumbnail at specified time in a video stream in Bitmap format
+     *
+     * @param width width of the thumbnail in pixels
+     * @param height height of the thumbnail in pixels
+     * @param timeMs The time in the source video file at which the thumbnail is
+     *            requested (even if trimmed).
+     *
+     * @return The thumbnail as a Bitmap.
+     *
+     * @throws IOException if a file error occurs
+     * @throws IllegalArgumentException if time is out of video duration
+     */
+    public abstract Bitmap getThumbnail(int width, int height, long timeMs)
+                                        throws IOException;
+
+    /**
+     * Get the array of Bitmap thumbnails between start and end.
+     *
+     * @param width width of the thumbnail in pixels
+     * @param height height of the thumbnail in pixels
+     * @param startMs The start of time range in milliseconds
+     * @param endMs The end of the time range in milliseconds
+     * @param thumbnailCount The thumbnail count
+     *
+     * @return The array of Bitmaps
+     *
+     * @throws IOException if a file error occurs
+     */
+    public abstract Bitmap[] getThumbnailList(int width, int height,
+                                              long startMs, long endMs,
+                                              int thumbnailCount)
+                                              throws IOException;
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (!(object instanceof MediaItem)) {
+            return false;
+        }
+        return mUniqueId.equals(((MediaItem)object).mUniqueId);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return mUniqueId.hashCode();
+    }
+
+    /**
+     * Invalidate the start and end transitions if necessary
+     *
+     * @param startTimeMs The start time of the effect or overlay
+     * @param durationMs The duration of the effect or overlay
+     */
+    abstract void invalidateTransitions(long startTimeMs, long durationMs);
+
+    /**
+     * Invalidate the start and end transitions if necessary. This method is
+     * typically called when the start time and/or duration of an overlay or
+     * effect is changing.
+     *
+     * @param oldStartTimeMs The old start time of the effect or overlay
+     * @param oldDurationMs The old duration of the effect or overlay
+     * @param newStartTimeMs The new start time of the effect or overlay
+     * @param newDurationMs The new duration of the effect or overlay
+     */
+    abstract void invalidateTransitions(long oldStartTimeMs, long oldDurationMs,
+            long newStartTimeMs, long newDurationMs);
+
+    /**
+     * Check if two items overlap in time
+     *
+     * @param startTimeMs1 Item 1 start time
+     * @param durationMs1 Item 1 duration
+     * @param startTimeMs2 Item 2 start time
+     * @param durationMs2 Item 2 end time
+     * @return true if the two items overlap
+     */
+    protected boolean isOverlapping(long startTimeMs1, long durationMs1,
+                                    long startTimeMs2, long durationMs2) {
+        if (startTimeMs1 + durationMs1 <= startTimeMs2) {
+            return false;
+        } else if (startTimeMs1 >= startTimeMs2 + durationMs2) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Adjust the duration transitions.
+     */
+    protected void adjustTransitions() {
+        /**
+         *  Check if the duration of transitions need to be adjusted
+         */
+        if (mBeginTransition != null) {
+            final long maxDurationMs = mBeginTransition.getMaximumDuration();
+            if (mBeginTransition.getDuration() > maxDurationMs) {
+                mBeginTransition.setDuration(maxDurationMs);
+            }
+        }
+
+        if (mEndTransition != null) {
+            final long maxDurationMs = mEndTransition.getMaximumDuration();
+            if (mEndTransition.getDuration() > maxDurationMs) {
+                mEndTransition.setDuration(maxDurationMs);
+            }
+        }
+    }
+
+    /**
+     * @return MediaArtistNativeHleper context
+     */
+    MediaArtistNativeHelper getNativeContext() {
+        return mMANativeHelper;
+    }
+
+    /**
+     * Initialises ClipSettings fields to default value
+     *
+     * @param ClipSettings object
+     *{@link android.media.videoeditor.MediaArtistNativeHelper.ClipSettings}
+     */
+    void initClipSettings(ClipSettings clipSettings) {
+        clipSettings.clipPath = null;
+        clipSettings.clipDecodedPath = null;
+        clipSettings.clipOriginalPath = null;
+        clipSettings.fileType = 0;
+        clipSettings.endCutTime = 0;
+        clipSettings.beginCutTime = 0;
+        clipSettings.beginCutPercent = 0;
+        clipSettings.endCutPercent = 0;
+        clipSettings.panZoomEnabled = false;
+        clipSettings.panZoomPercentStart = 0;
+        clipSettings.panZoomTopLeftXStart = 0;
+        clipSettings.panZoomTopLeftYStart = 0;
+        clipSettings.panZoomPercentEnd = 0;
+        clipSettings.panZoomTopLeftXEnd = 0;
+        clipSettings.panZoomTopLeftYEnd = 0;
+        clipSettings.mediaRendering = 0;
+        clipSettings.rgbWidth = 0;
+        clipSettings.rgbHeight = 0;
+    }
+
+    /**
+     * @return ClipSettings object with populated data
+     *{@link android.media.videoeditor.MediaArtistNativeHelper.ClipSettings}
+     */
+    ClipSettings getClipSettings() {
+        MediaVideoItem mVI = null;
+        MediaImageItem mII = null;
+        ClipSettings clipSettings = new ClipSettings();
+        initClipSettings(clipSettings);
+        if (this instanceof MediaVideoItem) {
+            mVI = (MediaVideoItem)this;
+            clipSettings.clipPath = mVI.getFilename();
+            clipSettings.fileType = mMANativeHelper.getMediaItemFileType(mVI.
+                                                                 getFileType());
+            clipSettings.beginCutTime = (int)mVI.getBoundaryBeginTime();
+            clipSettings.endCutTime = (int)mVI.getBoundaryEndTime();
+            clipSettings.mediaRendering = mMANativeHelper.
+                                          getMediaItemRenderingMode(mVI
+                                          .getRenderingMode());
+        } else if (this instanceof MediaImageItem) {
+            mII = (MediaImageItem)this;
+            clipSettings = mII.getImageClipProperties();
+        }
+        return clipSettings;
+    }
+
+    /**
+     * Generates a black frame to be used for generating
+     * begin transition at first media item in storyboard
+     * or end transition at last media item in storyboard
+     *
+     * @param ClipSettings object
+     *{@link android.media.videoeditor.MediaArtistNativeHelper.ClipSettings}
+     */
+    void generateBlankFrame(ClipSettings clipSettings) {
+        if (!mBlankFrameGenerated) {
+            int mWidth = 64;
+            int mHeight = 64;
+            mBlankFrameFilename = String.format(mProjectPath + "/" + "ghost.rgb");
+            FileOutputStream fl = null;
+            try {
+                 fl = new FileOutputStream(mBlankFrameFilename);
+            } catch (IOException e) {
+                /* catch IO exception */
+            }
+            final DataOutputStream dos = new DataOutputStream(fl);
+
+            final int [] framingBuffer = new int[mWidth];
+
+            ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
+            IntBuffer intBuffer;
+
+            byte[] array = byteBuffer.array();
+            int tmp = 0;
+            while(tmp < mHeight) {
+                intBuffer = byteBuffer.asIntBuffer();
+                intBuffer.put(framingBuffer,0,mWidth);
+                try {
+                    dos.write(array);
+                } catch (IOException e) {
+                    /* catch file write error */
+                }
+                tmp += 1;
+            }
+
+            try {
+                fl.close();
+            } catch (IOException e) {
+                /* file close error */
+            }
+            mBlankFrameGenerated = true;
+        }
+
+        clipSettings.clipPath = mBlankFrameFilename;
+        clipSettings.fileType = FileType.JPG;
+        clipSettings.beginCutTime = 0;
+        clipSettings.endCutTime = 0;
+        clipSettings.mediaRendering = MediaRendering.RESIZING;
+
+        clipSettings.rgbWidth = 64;
+        clipSettings.rgbHeight = 64;
+    }
+
+    /**
+     * Invalidates the blank frame generated
+     */
+    void invalidateBlankFrame() {
+        if (mBlankFrameFilename != null) {
+            if (new File(mBlankFrameFilename).exists()) {
+                new File(mBlankFrameFilename).delete();
+                mBlankFrameFilename = null;
+            }
+        }
+    }
+
+}
diff --git a/media/java/android/media/videoeditor/MediaProperties.java b/media/java/android/media/videoeditor/MediaProperties.java
index 0bb83eb..9654a6a 100755
--- a/media/java/android/media/videoeditor/MediaProperties.java
+++ b/media/java/android/media/videoeditor/MediaProperties.java
@@ -1,260 +1,311 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-import android.util.Pair;

-

-/**

- * This class defines all properties of a media file such as supported height, aspect ratio,

- * bitrate for export function.

- * {@hide}

- */

-public class MediaProperties {

-    // Supported heights

-    public static final int HEIGHT_144 = 144;

-    public static final int HEIGHT_360 = 360;

-    public static final int HEIGHT_480 = 480;

-    public static final int HEIGHT_720 = 720;

-    public static final int HEIGHT_1080 = 1080;

-

-    // Supported aspect ratios

-    public static final int ASPECT_RATIO_UNDEFINED = 0;

-    public static final int ASPECT_RATIO_3_2 = 1;

-    public static final int ASPECT_RATIO_16_9 = 2;

-    public static final int ASPECT_RATIO_4_3 = 3;

-    public static final int ASPECT_RATIO_5_3 = 4;

-    public static final int ASPECT_RATIO_11_9 = 5;

-

-    // The array of supported aspect ratios

-    private static final int[] ASPECT_RATIOS = new int[] {

-        ASPECT_RATIO_3_2,

-        ASPECT_RATIO_16_9,

-        ASPECT_RATIO_4_3,

-        ASPECT_RATIO_5_3,

-        ASPECT_RATIO_11_9

-    };

-

-    // Supported resolutions for specific aspect ratios

-    @SuppressWarnings({"unchecked"})

-    private static final Pair<Integer, Integer>[] ASPECT_RATIO_3_2_RESOLUTIONS =

-        new Pair[] {

-        new Pair<Integer, Integer>(720, HEIGHT_480),

-        new Pair<Integer, Integer>(1080, HEIGHT_720)

-    };

-

-    @SuppressWarnings({"unchecked"})

-    private static final Pair<Integer, Integer>[] ASPECT_RATIO_4_3_RESOLUTIONS =

-        new Pair[] {

-        new Pair<Integer, Integer>(640, HEIGHT_480),

-        new Pair<Integer, Integer>(960, HEIGHT_720)

-    };

-

-    @SuppressWarnings({"unchecked"})

-    private static final Pair<Integer, Integer>[] ASPECT_RATIO_5_3_RESOLUTIONS =

-        new Pair[] {

-        new Pair<Integer, Integer>(800, HEIGHT_480)

-    };

-

-    @SuppressWarnings({"unchecked"})

-    private static final Pair<Integer, Integer>[] ASPECT_RATIO_11_9_RESOLUTIONS =

-        new Pair[] {

-        new Pair<Integer, Integer>(176, HEIGHT_144)

-    };

-

-    @SuppressWarnings({"unchecked"})

-    private static final Pair<Integer, Integer>[] ASPECT_RATIO_16_9_RESOLUTIONS =

-        new Pair[] {

-        new Pair<Integer, Integer>(640, HEIGHT_360),

-        new Pair<Integer, Integer>(854, HEIGHT_480),

-        new Pair<Integer, Integer>(1280, HEIGHT_720),

-    };

-

-

-    // Bitrate values (in bits per second)

-    public static final int BITRATE_28K = 28000;

-    public static final int BITRATE_40K = 40000;

-    public static final int BITRATE_64K = 64000;

-    public static final int BITRATE_96K = 96000;

-    public static final int BITRATE_128K = 128000;

-    public static final int BITRATE_192K = 192000;

-    public static final int BITRATE_256K = 256000;

-    public static final int BITRATE_384K = 384000;

-    public static final int BITRATE_512K = 512000;

-    public static final int BITRATE_800K = 800000;

-    public static final int BITRATE_2M = 2000000;

-    public static final int BITRATE_5M = 5000000;

-    public static final int BITRATE_8M = 8000000;

-

-    // The array of supported bitrates

-    private static final int[] SUPPORTED_BITRATES = new int[] {

-        BITRATE_28K,

-        BITRATE_40K,

-        BITRATE_64K,

-        BITRATE_96K,

-        BITRATE_128K,

-        BITRATE_192K,

-        BITRATE_256K,

-        BITRATE_384K,

-        BITRATE_512K,

-        BITRATE_800K

-    };

-

-    // Video codec types

-    public static final int VCODEC_H264BP = 1;

-    public static final int VCODEC_H264MP = 2;

-    public static final int VCODEC_H263 = 3;

-    public static final int VCODEC_MPEG4 = 4;

-

-    // The array of supported video codecs

-    private static final int[] SUPPORTED_VCODECS = new int[] {

-        VCODEC_H264BP,

-        VCODEC_H263,

-        VCODEC_MPEG4,

-    };

-

-    // Audio codec types

-    public static final int ACODEC_AAC_LC = 1;

-    public static final int ACODEC_AMRNB = 2;

-    public static final int ACODEC_AMRWB = 3;

-    public static final int ACODEC_MP3 = 4;

-    public static final int ACODEC_OGG = 5;

-

-    // The array of supported video codecs

-    private static final int[] SUPPORTED_ACODECS = new int[] {

-        ACODEC_AAC_LC,

-        ACODEC_AMRNB,

-        ACODEC_AMRWB

-    };

-

-    // File format types

-    public static final int FILE_UNSUPPORTED = 0;

-    public static final int FILE_3GP = 1;

-    public static final int FILE_MP4 = 2;

-    public static final int FILE_JPEG = 3;

-    public static final int FILE_PNG = 4;

-

-    // The array of the supported file formats

-    private static final int[] SUPPORTED_VIDEO_FILE_FORMATS = new int[] {

-        FILE_3GP,

-        FILE_MP4

-    };

-

-    // The maximum count of audio tracks supported

-    public static final int AUDIO_MAX_TRACK_COUNT = 1;

-

-    // The maximum volume supported (100 means that no amplification is

-    // supported, i.e. attenuation only)

-    public static final int AUDIO_MAX_VOLUME_PERCENT = 100;

-

-    /**

-     * This class cannot be instantiated

-     */

-    private MediaProperties() {

-    }

-

-    /**

-     * @return The array of supported aspect ratios

-     */

-    public static int[] getAllSupportedAspectRatios() {

-        return ASPECT_RATIOS;

-    }

-

-    /**

-     * Get the supported resolutions for the specified aspect ratio.

-     *

-     * @param aspectRatio The aspect ratio for which the resolutions are requested

-     *

-     * @return The array of width and height pairs

-     */

-    public static Pair<Integer, Integer>[] getSupportedResolutions(int aspectRatio) {

-        final Pair<Integer, Integer>[] resolutions;

-        switch(aspectRatio) {

-            case ASPECT_RATIO_3_2: {

-                resolutions = ASPECT_RATIO_3_2_RESOLUTIONS;

-                break;

-            }

-

-            case ASPECT_RATIO_4_3: {

-                resolutions = ASPECT_RATIO_4_3_RESOLUTIONS;

-                break;

-            }

-

-            case ASPECT_RATIO_5_3: {

-                resolutions = ASPECT_RATIO_5_3_RESOLUTIONS;

-                break;

-            }

-

-            case ASPECT_RATIO_11_9: {

-                resolutions = ASPECT_RATIO_11_9_RESOLUTIONS;

-                break;

-            }

-

-            case ASPECT_RATIO_16_9: {

-                resolutions = ASPECT_RATIO_16_9_RESOLUTIONS;

-                break;

-            }

-

-            default: {

-                throw new IllegalArgumentException("Unknown aspect ratio: " + aspectRatio);

-            }

-        }

-

-        return resolutions;

-    }

-

-    /**

-     * @return The array of supported video codecs

-     */

-    public static int[] getSupportedVideoCodecs() {

-        return SUPPORTED_VCODECS;

-    }

-

-    /**

-     * @return The array of supported audio codecs

-     */

-    public static int[] getSupportedAudioCodecs() {

-        return SUPPORTED_ACODECS;

-    }

-

-    /**

-     * @return The array of supported file formats

-     */

-    public static int[] getSupportedVideoFileFormat() {

-        return SUPPORTED_VIDEO_FILE_FORMATS;

-    }

-

-    /**

-     * @return The array of supported video bitrates

-     */

-    public static int[] getSupportedVideoBitrates() {

-        return SUPPORTED_BITRATES;

-    }

-

-    /**

-     * @return The maximum value for the audio volume

-     */

-    public static int getSupportedMaxVolume() {

-        return MediaProperties.AUDIO_MAX_VOLUME_PERCENT;

-    }

-

-    /**

-     * @return The maximum number of audio tracks supported

-     */

-    public static int getSupportedAudioTrackCount() {

-        return MediaProperties.AUDIO_MAX_TRACK_COUNT;

-    }

-}

+/*
+ * 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.
+ */
+
+
+package android.media.videoeditor;
+
+import android.util.Pair;
+
+/**
+ * This class defines all properties of a media file such as supported height,
+ * aspect ratio, bitrate for export function.
+ * {@hide}
+ */
+public class MediaProperties {
+    /**
+     *  Supported heights
+     */
+    public static final int HEIGHT_144 = 144;
+    public static final int HEIGHT_360 = 360;
+    public static final int HEIGHT_480 = 480;
+    public static final int HEIGHT_720 = 720;
+    public static final int HEIGHT_1088 = 1088;
+
+    /**
+     *  Supported aspect ratios
+     */
+    public static final int ASPECT_RATIO_UNDEFINED = 0;
+    public static final int ASPECT_RATIO_3_2 = 1;
+    public static final int ASPECT_RATIO_16_9 = 2;
+    public static final int ASPECT_RATIO_4_3 = 3;
+    public static final int ASPECT_RATIO_5_3 = 4;
+    public static final int ASPECT_RATIO_11_9 = 5;
+
+    /**
+     *  The array of supported aspect ratios
+     */
+    private static final int[] ASPECT_RATIOS = new int[] {
+        ASPECT_RATIO_3_2,
+        ASPECT_RATIO_16_9,
+        ASPECT_RATIO_4_3,
+        ASPECT_RATIO_5_3,
+        ASPECT_RATIO_11_9
+    };
+
+    /**
+     *  Supported resolutions for specific aspect ratios
+     */
+    @SuppressWarnings({"unchecked"})
+    private static final Pair<Integer, Integer>[] ASPECT_RATIO_3_2_RESOLUTIONS =
+        new Pair[] {
+        new Pair<Integer, Integer>(720, HEIGHT_480),
+//*tmpLSA*/        new Pair<Integer, Integer>(1080, HEIGHT_720)
+/*tmpLSA*/        new Pair<Integer, Integer>(1088, HEIGHT_720)
+    };
+
+    @SuppressWarnings({"unchecked"})
+    private static final Pair<Integer, Integer>[] ASPECT_RATIO_4_3_RESOLUTIONS =
+        new Pair[] {
+        new Pair<Integer, Integer>(640, HEIGHT_480),
+        new Pair<Integer, Integer>(960, HEIGHT_720)
+    };
+
+    @SuppressWarnings({"unchecked"})
+    private static final Pair<Integer, Integer>[] ASPECT_RATIO_5_3_RESOLUTIONS =
+        new Pair[] {
+        new Pair<Integer, Integer>(800, HEIGHT_480)
+    };
+
+    @SuppressWarnings({"unchecked"})
+    private static final Pair<Integer, Integer>[] ASPECT_RATIO_11_9_RESOLUTIONS =
+        new Pair[] {
+        new Pair<Integer, Integer>(176, HEIGHT_144)
+    };
+
+    @SuppressWarnings({"unchecked"})
+    private static final Pair<Integer, Integer>[] ASPECT_RATIO_16_9_RESOLUTIONS =
+        new Pair[] {
+        new Pair<Integer, Integer>(848, HEIGHT_480),
+        new Pair<Integer, Integer>(1280, HEIGHT_720),
+    };
+
+    /**
+     *  Bitrate values (in bits per second)
+     */
+    public static final int BITRATE_28K = 28000;
+    public static final int BITRATE_40K = 40000;
+    public static final int BITRATE_64K = 64000;
+    public static final int BITRATE_96K = 96000;
+    public static final int BITRATE_128K = 128000;
+    public static final int BITRATE_192K = 192000;
+    public static final int BITRATE_256K = 256000;
+    public static final int BITRATE_384K = 384000;
+    public static final int BITRATE_512K = 512000;
+    public static final int BITRATE_800K = 800000;
+    public static final int BITRATE_2M = 2000000;
+    public static final int BITRATE_5M = 5000000;
+    public static final int BITRATE_8M = 8000000;
+
+    /**
+     *  The array of supported bitrates
+     */
+    private static final int[] SUPPORTED_BITRATES = new int[] {
+        BITRATE_28K,
+        BITRATE_40K,
+        BITRATE_64K,
+        BITRATE_96K,
+        BITRATE_128K,
+        BITRATE_192K,
+        BITRATE_256K,
+        BITRATE_384K,
+        BITRATE_512K,
+        BITRATE_800K,
+        BITRATE_2M,
+        BITRATE_5M,
+        BITRATE_8M
+    };
+
+    /**
+     *  Video codec types
+     */
+    public static final int VCODEC_H263 = 1;
+    public static final int VCODEC_MPEG4 = 2;
+    // 3 Value is used for MPEG4_EMP
+    public static final int VCODEC_H264BP = 4;
+    public static final int VCODEC_H264MP = 5;  // Unsupported
+
+    /**
+     *  The array of supported video codecs
+     */
+    private static final int[] SUPPORTED_VCODECS = new int[] {
+        VCODEC_H264BP,
+        VCODEC_H263,
+        VCODEC_MPEG4,
+    };
+
+    /**
+     *  Audio codec types
+     */
+    public static final int ACODEC_NO_AUDIO = 0;
+    public static final int ACODEC_AMRNB = 1;
+    public static final int ACODEC_AAC_LC = 2;
+    public static final int ACODEC_AAC_PLUS = 3;
+    public static final int ACODEC_ENHANCED_AAC_PLUS = 4;
+    public static final int ACODEC_MP3 = 5;
+    public static final int ACODEC_EVRC = 6;
+    // 7 value is used for PCM
+    public static final int ACODEC_AMRWB = 8;
+    public static final int ACODEC_OGG = 9;
+
+    /**
+     *  The array of supported video codecs
+     */
+    private static final int[] SUPPORTED_ACODECS = new int[] {
+        ACODEC_AAC_LC,
+        ACODEC_AMRNB,
+        ACODEC_AMRWB
+    };
+
+
+    /**
+     *  Samples per frame for each audio codec
+     */
+    public static final int SAMPLES_PER_FRAME_AAC = 1024;
+    public static final int SAMPLES_PER_FRAME_MP3 = 1152;
+    public static final int SAMPLES_PER_FRAME_AMRNB = 160;
+    public static final int SAMPLES_PER_FRAME_AMRWB = 320;
+
+    public static final int DEFAULT_SAMPLING_FREQUENCY = 32000;
+    public static final int DEFAULT_CHANNEL_COUNT = 2;
+
+    /**
+     *  File format types
+     */
+    public static final int FILE_3GP = 0;
+    public static final int FILE_MP4 = 1;
+    // 2 is for AMRNB
+    public static final int FILE_MP3 = 3;
+    // 4 is for PCM
+    public static final int FILE_JPEG = 5;
+    // 6 is for GIF
+    public static final int FILE_PNG = 7;
+    public static final int FILE_UNSUPPORTED = 255;
+    /**
+     * The array of the supported file formats
+     */
+    private static final int[] SUPPORTED_VIDEO_FILE_FORMATS = new int[] {
+        FILE_3GP,
+        FILE_MP4
+    };
+
+    /**
+     * The maximum count of audio tracks supported
+     */
+    public static final int AUDIO_MAX_TRACK_COUNT = 1;
+
+    /** The maximum volume supported (100 means that no amplification is
+     * supported, i.e. attenuation only)
+     */
+    public static final int AUDIO_MAX_VOLUME_PERCENT = 100;
+
+    /**
+     * This class cannot be instantiated
+     */
+    private MediaProperties() {
+    }
+
+    /**
+     * @return The array of supported aspect ratios
+     */
+    public static int[] getAllSupportedAspectRatios() {
+        return ASPECT_RATIOS;
+    }
+
+    /**
+     * Get the supported resolutions for the specified aspect ratio.
+     *
+     * @param aspectRatio The aspect ratio for which the resolutions are
+     *        requested
+     * @return The array of width and height pairs
+     */
+    public static Pair<Integer, Integer>[] getSupportedResolutions(int aspectRatio) {
+        final Pair<Integer, Integer>[] resolutions;
+        switch (aspectRatio) {
+            case ASPECT_RATIO_3_2: {
+                resolutions = ASPECT_RATIO_3_2_RESOLUTIONS;
+                break;
+            }
+
+            case ASPECT_RATIO_4_3: {
+                resolutions = ASPECT_RATIO_4_3_RESOLUTIONS;
+                break;
+            }
+
+            case ASPECT_RATIO_5_3: {
+                resolutions = ASPECT_RATIO_5_3_RESOLUTIONS;
+                break;
+            }
+
+            case ASPECT_RATIO_11_9: {
+                resolutions = ASPECT_RATIO_11_9_RESOLUTIONS;
+                break;
+            }
+
+            case ASPECT_RATIO_16_9: {
+                resolutions = ASPECT_RATIO_16_9_RESOLUTIONS;
+                break;
+            }
+
+            default: {
+                throw new IllegalArgumentException("Unknown aspect ratio: " + aspectRatio);
+            }
+        }
+
+        return resolutions;
+    }
+
+    /**
+     * @return The array of supported video codecs
+     */
+    public static int[] getSupportedVideoCodecs() {
+        return SUPPORTED_VCODECS;
+    }
+
+    /**
+     * @return The array of supported audio codecs
+     */
+    public static int[] getSupportedAudioCodecs() {
+        return SUPPORTED_ACODECS;
+    }
+
+    /**
+     * @return The array of supported file formats
+     */
+    public static int[] getSupportedVideoFileFormat() {
+        return SUPPORTED_VIDEO_FILE_FORMATS;
+    }
+
+    /**
+     * @return The array of supported video bitrates
+     */
+    public static int[] getSupportedVideoBitrates() {
+        return SUPPORTED_BITRATES;
+    }
+
+    /**
+     * @return The maximum value for the audio volume
+     */
+    public static int getSupportedMaxVolume() {
+        return MediaProperties.AUDIO_MAX_VOLUME_PERCENT;
+    }
+
+    /**
+     * @return The maximum number of audio tracks supported
+     */
+    public static int getSupportedAudioTrackCount() {
+        return MediaProperties.AUDIO_MAX_TRACK_COUNT;
+    }
+}
diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java
index 5fcfe3c..772b360 100755
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ b/media/java/android/media/videoeditor/MediaVideoItem.java
@@ -1,482 +1,686 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-import java.io.IOException;

-import java.lang.ref.SoftReference;

-

-import android.graphics.Bitmap;

-import android.view.SurfaceHolder;

-

-/**

- * This class represents a video clip item on the storyboard

- * {@hide}

- */

-public class MediaVideoItem extends MediaItem {

-    // Instance variables

-    private final int mWidth;

-    private final int mHeight;

-    private final int mAspectRatio;

-    private final int mFileType;

-    private final int mVideoType;

-    private final int mVideoProfile;

-    private final int mVideoBitrate;

-    private final long mDurationMs;

-    private final int mAudioBitrate;

-    private final int mFps;

-    private final int mAudioType;

-    private final int mAudioChannels;

-    private final int mAudioSamplingFrequency;

-

-    private long mBeginBoundaryTimeMs;

-    private long mEndBoundaryTimeMs;

-    private int mVolumePercentage;

-    private boolean mMuted;

-    private String mAudioWaveformFilename;

-    // The audio waveform data

-    private SoftReference<WaveformData> mWaveformData;

-

-    /**

-     * An object of this type cannot be instantiated with a default constructor

-     */

-    @SuppressWarnings("unused")

-    private MediaVideoItem() throws IOException {

-        this(null, null, null, RENDERING_MODE_BLACK_BORDER);

-    }

-

-    /**

-     * Constructor

-     *

-     * @param editor The video editor reference

-     * @param mediaItemId The MediaItem id

-     * @param filename The image file name

-     * @param renderingMode The rendering mode

-     *

-     * @throws IOException if the file cannot be opened for reading

-     */

-    public MediaVideoItem(VideoEditor editor, String mediaItemId, String filename,

-            int renderingMode)

-        throws IOException {

-        this(editor, mediaItemId, filename, renderingMode, 0, END_OF_FILE, 100, false, null);

-    }

-

-    /**

-     * Constructor

-     *

-     * @param editor The video editor reference

-     * @param mediaItemId The MediaItem id

-     * @param filename The image file name

-     * @param renderingMode The rendering mode

-     * @param beginMs Start time in milliseconds. Set to 0 to extract from the

-     *           beginning

-     * @param endMs End time in milliseconds. Set to {@link #END_OF_FILE} to

-     *           extract until the end

-     * @param volumePercent in %/. 100% means no change; 50% means half value, 200%

-     *            means double, 0% means silent.

-     * @param muted true if the audio is muted

-     * @param audioWaveformFilename The name of the audio waveform file

-     *

-     * @throws IOException if the file cannot be opened for reading

-     */

-    MediaVideoItem(VideoEditor editor, String mediaItemId, String filename, int renderingMode,

-            long beginMs, long endMs, int volumePercent, boolean muted,

-            String audioWaveformFilename)  throws IOException {

-        super(editor, mediaItemId, filename, renderingMode);

-        // TODO: Set these variables correctly

-        mWidth = 1080;

-        mHeight = 720;

-        mAspectRatio = MediaProperties.ASPECT_RATIO_3_2;

-        mFileType = MediaProperties.FILE_MP4;

-        mVideoType = MediaProperties.VCODEC_H264BP;

-        // Do we have predefined values for this variable?

-        mVideoProfile = 0;

-        // Can video and audio duration be different?

-        mDurationMs = 10000;

-        mVideoBitrate = 800000;

-        mAudioBitrate = 30000;

-        mFps = 30;

-        mAudioType = MediaProperties.ACODEC_AAC_LC;

-        mAudioChannels = 2;

-        mAudioSamplingFrequency = 16000;

-

-        mBeginBoundaryTimeMs = beginMs;

-        mEndBoundaryTimeMs = endMs == END_OF_FILE ? mDurationMs : endMs;

-        mVolumePercentage = volumePercent;

-        mMuted = muted;

-        mAudioWaveformFilename = audioWaveformFilename;

-        if (audioWaveformFilename != null) {

-            mWaveformData =

-                new SoftReference<WaveformData>(new WaveformData(audioWaveformFilename));

-        } else {

-            mWaveformData = null;

-        }

-    }

-

-    /**

-     * Sets the start and end marks for trimming a video media item.

-     * This method will adjust the duration of bounding transitions, effects

-     * and overlays if the current duration of the transactions become greater

-     * than the maximum allowable duration.

-     *

-     * @param beginMs Start time in milliseconds. Set to 0 to extract from the

-     *           beginning

-     * @param endMs End time in milliseconds. Set to {@link #END_OF_FILE} to

-     *           extract until the end

-     *

-     * @throws IllegalArgumentException if the start time is greater or equal than

-     *           end time, the end time is beyond the file duration, the start time

-     *           is negative

-     */

-    public void setExtractBoundaries(long beginMs, long endMs) {

-        if (beginMs > mDurationMs) {

-            throw new IllegalArgumentException("Invalid start time");

-        }

-        if (endMs > mDurationMs) {

-            throw new IllegalArgumentException("Invalid end time");

-        }

-

-        if (beginMs != mBeginBoundaryTimeMs) {

-            if (mBeginTransition != null) {

-                mBeginTransition.invalidate();

-            }

-        }

-

-        if (endMs != mEndBoundaryTimeMs) {

-            if (mEndTransition != null) {

-                mEndTransition.invalidate();

-            }

-        }

-

-        mBeginBoundaryTimeMs = beginMs;

-        mEndBoundaryTimeMs = endMs;

-

-        adjustTransitions();

-

-        // Note that the start and duration of any effects and overlays are

-        // not adjusted nor are they automatically removed if they fall

-        // outside the new boundaries.

-    }

-

-    /**

-     * @return The boundary begin time

-     */

-    public long getBoundaryBeginTime() {

-        return mBeginBoundaryTimeMs;

-    }

-

-    /**

-     * @return The boundary end time

-     */

-    public long getBoundaryEndTime() {

-        return mEndBoundaryTimeMs;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public void addEffect(Effect effect) {

-        if (effect instanceof EffectKenBurns) {

-            throw new IllegalArgumentException("Ken Burns effects cannot be applied to MediaVideoItem");

-        }

-        super.addEffect(effect);

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public Bitmap getThumbnail(int width, int height, long timeMs) {

-        return null;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public Bitmap[] getThumbnailList(int width, int height, long startMs, long endMs,

-            int thumbnailCount) throws IOException {

-        return null;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    void invalidateTransitions(long startTimeMs, long durationMs) {

-        // Check if the item overlaps with the beginning and end transitions

-        if (mBeginTransition != null) {

-            if (isOverlapping(startTimeMs, durationMs,

-                    mBeginBoundaryTimeMs, mBeginTransition.getDuration())) {

-                mBeginTransition.invalidate();

-            }

-        }

-

-        if (mEndTransition != null) {

-            final long transitionDurationMs = mEndTransition.getDuration();

-            if (isOverlapping(startTimeMs, durationMs,

-                    mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs)) {

-                mEndTransition.invalidate();

-            }

-        }

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    void invalidateTransitions(long oldStartTimeMs, long oldDurationMs, long newStartTimeMs,

-            long newDurationMs) {

-        // Check if the item overlaps with the beginning and end transitions

-        if (mBeginTransition != null) {

-            final long transitionDurationMs = mBeginTransition.getDuration();

-            // If the start time has changed and if the old or the new item

-            // overlaps with the begin transition, invalidate the transition.

-            if (oldStartTimeMs != newStartTimeMs &&

-                    (isOverlapping(oldStartTimeMs, oldDurationMs,

-                            mBeginBoundaryTimeMs, transitionDurationMs) ||

-                    isOverlapping(newStartTimeMs, newDurationMs,

-                            mBeginBoundaryTimeMs, transitionDurationMs))) {

-                mBeginTransition.invalidate();

-            }

-        }

-

-        if (mEndTransition != null) {

-            final long transitionDurationMs = mEndTransition.getDuration();

-            // If the start time + duration has changed and if the old or the new

-            // item overlaps the end transition, invalidate the transition/

-            if (oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs &&

-                    (isOverlapping(oldStartTimeMs, oldDurationMs,

-                            mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs) ||

-                    isOverlapping(newStartTimeMs, newDurationMs,

-                            mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs))) {

-                mEndTransition.invalidate();

-            }

-        }

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public int getAspectRatio() {

-        return mAspectRatio;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public int getFileType() {

-        return mFileType;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public int getWidth() {

-        return mWidth;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public int getHeight() {

-        return mHeight;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public long getDuration() {

-        return mDurationMs;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public long getTimelineDuration() {

-        return mEndBoundaryTimeMs - mBeginBoundaryTimeMs;

-    }

-

-    /**

-     * Render a frame according to the playback (in the native aspect ratio) for

-     * the specified media item. All effects and overlays applied to the media

-     * item are ignored. The extract boundaries are also ignored. This method

-     * can be used to playback frames when implementing trimming functionality.

-     *

-     * @param surfaceHolder SurfaceHolder used by the application

-     * @param timeMs time corresponding to the frame to display (relative to the

-     *            the beginning of the media item).

-     * @return The accurate time stamp of the frame that is rendered .

-     * @throws IllegalStateException if a playback, preview or an export is

-     *             already in progress

-     * @throws IllegalArgumentException if time is negative or greater than the

-     *             media item duration

-     */

-    public long renderFrame(SurfaceHolder surfaceHolder, long timeMs) {

-        return timeMs;

-    }

-

-    /**

-     * This API allows to generate a file containing the sample volume levels of

-     * the Audio track of this media item. This function may take significant

-     * time and is blocking. The file can be retrieved using

-     * getAudioWaveformFilename().

-     *

-     * @param listener The progress listener

-     *

-     * @throws IOException if the output file cannot be created

-     * @throws IllegalArgumentException if the mediaItem does not have a valid

-     *             Audio track

-     */

-    public void extractAudioWaveform(ExtractAudioWaveformProgressListener listener)

-            throws IOException {

-        // TODO: Set mAudioWaveformFilename at the end once the export is complete

-        mWaveformData = new SoftReference<WaveformData>(new WaveformData(mAudioWaveformFilename));

-    }

-

-    /**

-     * Get the audio waveform file name if {@link #extractAudioWaveform()} was

-     * successful. The file format is as following:

-     * <ul>

-     *  <li>first 4 bytes provide the number of samples for each value, as big-endian signed</li>

-     *  <li>4 following bytes is the total number of values in the file, as big-endian signed</li>

-     *  <li>all values follow as bytes Name is unique.</li>

-     *</ul>

-     * @return the name of the file, null if the file has not been computed or

-     *         if there is no Audio track in the mediaItem

-     */

-    String getAudioWaveformFilename() {

-        return mAudioWaveformFilename;

-    }

-

-    /**

-     * @return The waveform data

-     */

-    public WaveformData getWaveformData() throws IOException {

-        if (mWaveformData == null) {

-            return null;

-        }

-

-        WaveformData waveformData = mWaveformData.get();

-        if (waveformData != null) {

-            return waveformData;

-        } else if (mAudioWaveformFilename != null) {

-            waveformData = new WaveformData(mAudioWaveformFilename);

-            mWaveformData = new SoftReference<WaveformData>(waveformData);

-            return waveformData;

-        } else {

-            return null;

-        }

-    }

-

-    /**

-     * Set volume of the Audio track of this mediaItem

-     *

-     * @param volumePercent in %/. 100% means no change; 50% means half value, 200%

-     *            means double, 0% means silent.

-     * @throws UsupportedOperationException if volume value is not supported

-     */

-    public void setVolume(int volumePercent) {

-        mVolumePercentage = volumePercent;

-    }

-

-    /**

-     * Get the volume value of the audio track as percentage. Call of this

-     * method before calling setVolume will always return 100%

-     *

-     * @return the volume in percentage

-     */

-    public int getVolume() {

-        return mVolumePercentage;

-    }

-

-    /**

-     * @param muted true to mute the media item

-     */

-    public void setMute(boolean muted) {

-        mMuted = muted;

-    }

-

-    /**

-     * @return true if the media item is muted

-     */

-    public boolean isMuted() {

-        return mMuted;

-    }

-

-    /**

-     * @return The video type

-     */

-    public int getVideoType() {

-        return mVideoType;

-    }

-

-    /**

-     * @return The video profile

-     */

-    public int getVideoProfile() {

-        return mVideoProfile;

-    }

-

-    /**

-     * @return The video bitrate

-     */

-    public int getVideoBitrate() {

-        return mVideoBitrate;

-    }

-

-    /**

-     * @return The audio bitrate

-     */

-    public int getAudioBitrate() {

-        return mAudioBitrate;

-    }

-

-    /**

-     * @return The number of frames per second

-     */

-    public int getFps() {

-        return mFps;

-    }

-

-    /**

-     * @return The audio codec

-     */

-    public int getAudioType() {

-        return mAudioType;

-    }

-

-    /**

-     * @return The number of audio channels

-     */

-    public int getAudioChannels() {

-        return mAudioChannels;

-    }

-

-    /**

-     * @return The audio sample frequency

-     */

-    public int getAudioSamplingFrequency() {

-        return mAudioSamplingFrequency;

-    }

-}

+/*
+ * 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.
+ */
+
+
+package android.media.videoeditor;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.ref.SoftReference;
+import android.graphics.Bitmap;
+import android.media.videoeditor.MediaArtistNativeHelper.ClipSettings;
+import android.media.videoeditor.MediaArtistNativeHelper.Properties;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+
+/**
+ * This class represents a video clip item on the storyboard
+ * {@hide}
+ */
+public class MediaVideoItem extends MediaItem {
+
+    /**
+     *  Instance variables
+     */
+    private final int mWidth;
+    private final int mHeight;
+    private final int mAspectRatio;
+    private final int mFileType;
+    private final int mVideoType;
+    private final int mVideoProfile;
+    private final int mVideoBitrate;
+    private final long mDurationMs;
+    private final int mAudioBitrate;
+    private final int mFps;
+    private final int mAudioType;
+    private final int mAudioChannels;
+    private final int mAudioSamplingFrequency;
+    private long mBeginBoundaryTimeMs;
+    private long mEndBoundaryTimeMs;
+    private int mVolumePercentage;
+    private boolean mMuted;
+    private String mAudioWaveformFilename;
+    private MediaArtistNativeHelper mMANativeHelper;
+    private VideoEditorImpl mVideoEditor;
+    /**
+     *  The audio waveform data
+     */
+    private SoftReference<WaveformData> mWaveformData;
+
+    /**
+     * An object of this type cannot be instantiated with a default constructor
+     */
+    @SuppressWarnings("unused")
+    private MediaVideoItem() throws IOException {
+        this(null, null, null, RENDERING_MODE_BLACK_BORDER);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param editor The video editor reference
+     * @param mediaItemId The MediaItem id
+     * @param filename The image file name
+     * @param renderingMode The rendering mode
+     *
+     * @throws IOException if the file cannot be opened for reading
+     */
+    public MediaVideoItem(VideoEditor editor, String mediaItemId,
+            String filename,
+            int renderingMode)
+    throws IOException {
+        this(editor, mediaItemId, filename, renderingMode, 0, END_OF_FILE,
+                100, false, null);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param editor The video editor reference
+     * @param mediaItemId The MediaItem id
+     * @param filename The image file name
+     * @param renderingMode The rendering mode
+     * @param beginMs Start time in milliseconds. Set to 0 to extract from the
+     *           beginning
+     * @param endMs End time in milliseconds. Set to {@link #END_OF_FILE} to
+     *           extract until the end
+     * @param volumePercent in %/. 100% means no change; 50% means half value, 200%
+     *            means double, 0% means silent.
+     * @param muted true if the audio is muted
+     * @param audioWaveformFilename The name of the audio waveform file
+     *
+     * @throws IOException if the file cannot be opened for reading
+     */
+    MediaVideoItem(VideoEditor editor, String mediaItemId, String filename,
+            int renderingMode,
+            long beginMs, long endMs, int volumePercent, boolean muted,
+            String audioWaveformFilename)  throws IOException {
+        super(editor, mediaItemId, filename, renderingMode);
+        if (editor instanceof VideoEditorImpl) {
+            mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
+            mVideoEditor = ((VideoEditorImpl)editor);
+        }
+        Properties properties = null;
+        try {
+             properties = mMANativeHelper.getMediaProperties(filename);
+        } catch ( Exception e) {
+            throw new IllegalArgumentException("Unsupported file or file not found");
+        }
+        switch (mMANativeHelper.getFileType(properties.fileType)) {
+            case MediaProperties.FILE_3GP:
+                break;
+            case MediaProperties.FILE_MP4:
+                break;
+
+            default:
+                throw new IllegalArgumentException("Unsupported Input File Type");
+        }
+
+        switch (mMANativeHelper.getVideoCodecType(properties.videoFormat)) {
+            case MediaProperties.VCODEC_H263:
+                break;
+            case MediaProperties.VCODEC_H264BP:
+                break;
+            case MediaProperties.VCODEC_H264MP:
+                break;
+            case MediaProperties.VCODEC_MPEG4:
+                break;
+
+            default:
+                throw new IllegalArgumentException("Unsupported Video Codec Format in Input File");
+        }
+
+        mWidth = properties.width;
+        mHeight = properties.height;
+        mAspectRatio = mMANativeHelper.getAspectRatio(properties.width,
+                properties.height);
+        mFileType = mMANativeHelper.getFileType(properties.fileType);
+        mVideoType = mMANativeHelper.getVideoCodecType(properties.videoFormat);
+        mVideoProfile = 0;
+        mDurationMs = properties.videoDuration;
+        mVideoBitrate = properties.videoBitrate;
+        mAudioBitrate = properties.audioBitrate;
+        mFps = (int)properties.averageFrameRate;
+        mAudioType = mMANativeHelper.getAudioCodecType(properties.audioFormat);
+        mAudioChannels = properties.audioChannels;
+        mAudioSamplingFrequency =  properties.audioSamplingFrequency;
+        mBeginBoundaryTimeMs = beginMs;
+        mEndBoundaryTimeMs = endMs == END_OF_FILE ? mDurationMs : endMs;
+        mVolumePercentage = volumePercent;
+        mMuted = muted;
+        mAudioWaveformFilename = audioWaveformFilename;
+        if (audioWaveformFilename != null) {
+            mWaveformData =
+                new SoftReference<WaveformData>(
+                        new WaveformData(audioWaveformFilename));
+        } else {
+            mWaveformData = null;
+        }
+    }
+
+    /**
+     * Sets the start and end marks for trimming a video media item.
+     * This method will adjust the duration of bounding transitions, effects
+     * and overlays if the current duration of the transactions become greater
+     * than the maximum allowable duration.
+     *
+     * @param beginMs Start time in milliseconds. Set to 0 to extract from the
+     *           beginning
+     * @param endMs End time in milliseconds. Set to {@link #END_OF_FILE} to
+     *           extract until the end
+     *
+     * @throws IllegalArgumentException if the start time is greater or equal than
+     *           end time, the end time is beyond the file duration, the start time
+     *           is negative
+     */
+    public void setExtractBoundaries(long beginMs, long endMs) {
+        if (beginMs > mDurationMs) {
+            throw new IllegalArgumentException("setExtractBoundaries: Invalid start time");
+        }
+        if (endMs > mDurationMs) {
+            throw new IllegalArgumentException("setExtractBoundaries: Invalid end time");
+        }
+        if ((endMs != -1) && (beginMs >= endMs) ) {
+            throw new IllegalArgumentException("setExtractBoundaries: Start time is greater than end time");
+        }
+
+        if ((beginMs < 0) || ((endMs != -1) && (endMs < 0))) {
+            throw new IllegalArgumentException("setExtractBoundaries: Start time or end time is negative");
+        }
+
+        if (beginMs != mBeginBoundaryTimeMs) {
+            if (mBeginTransition != null) {
+                mBeginTransition.invalidate();
+            }
+        }
+
+        if (endMs != mEndBoundaryTimeMs) {
+            if (mEndTransition != null) {
+                mEndTransition.invalidate();
+            }
+        }
+
+        mBeginBoundaryTimeMs = beginMs;
+        mEndBoundaryTimeMs = endMs;
+        mMANativeHelper.setGeneratePreview(true);
+        adjustTransitions();
+        mVideoEditor.updateTimelineDuration();
+        /**
+         *  Note that the start and duration of any effects and overlays are
+         *  not adjusted nor are they automatically removed if they fall
+         *  outside the new boundaries.
+         */
+    }
+
+    /**
+     * @return The boundary begin time
+     */
+    public long getBoundaryBeginTime() {
+        return mBeginBoundaryTimeMs;
+    }
+
+    /**
+     * @return The boundary end time
+     */
+    public long getBoundaryEndTime() {
+        return mEndBoundaryTimeMs;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public void addEffect(Effect effect) {
+        if (effect instanceof EffectKenBurns) {
+            throw new IllegalArgumentException("Ken Burns effects cannot be applied to MediaVideoItem");
+        }
+        super.addEffect(effect);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public Bitmap getThumbnail(int width, int height, long timeMs) {
+        if (timeMs > mDurationMs)
+        {
+            throw new IllegalArgumentException("Time Exceeds duration");
+        }
+        if (timeMs < 0)
+        {
+            throw new IllegalArgumentException("Invalid Time duration");
+        }
+        if ((width <=0) || (height <= 0))
+        {
+            throw new IllegalArgumentException("Invalid Dimensions");
+        }
+        return mMANativeHelper.getPixels(super.getFilename(),
+                width, height,timeMs);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public Bitmap[] getThumbnailList(int width, int height, long startMs,
+            long endMs, int thumbnailCount) throws IOException {
+        if (startMs > endMs) {
+            throw new IllegalArgumentException("Start time is greater than end time");
+        }
+        if (endMs > mDurationMs) {
+            throw new IllegalArgumentException("End time is greater than file duration");
+        }
+        if ((height <= 0) || (width <= 0)) {
+            throw new IllegalArgumentException("Invalid dimension");
+        }
+        if (startMs == endMs) {
+            Bitmap[] bitmap = new Bitmap[1];
+            bitmap[0] = mMANativeHelper.getPixels(super.getFilename(),
+                    width, height,startMs);
+            return bitmap;
+        }
+        return mMANativeHelper.getPixelsList(super.getFilename(), width,
+                height,startMs,endMs,thumbnailCount);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    void invalidateTransitions(long startTimeMs, long durationMs) {
+        /**
+         *  Check if the item overlaps with the beginning and end transitions
+         */
+        if (mBeginTransition != null) {
+            if (isOverlapping(startTimeMs, durationMs,
+                    mBeginBoundaryTimeMs, mBeginTransition.getDuration())) {
+                mBeginTransition.invalidate();
+            }
+        }
+
+        if (mEndTransition != null) {
+            final long transitionDurationMs = mEndTransition.getDuration();
+            if (isOverlapping(startTimeMs, durationMs,
+                    mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs)) {
+                mEndTransition.invalidate();
+            }
+        }
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    void invalidateTransitions(long oldStartTimeMs, long oldDurationMs,
+            long newStartTimeMs,
+            long newDurationMs) {
+        /**
+         *  Check if the item overlaps with the beginning and end transitions
+         */
+        if (mBeginTransition != null) {
+            final long transitionDurationMs = mBeginTransition.getDuration();
+            /**
+             *  If the start time has changed and if the old or the new item
+             *  overlaps with the begin transition, invalidate the transition.
+             */
+            if (((oldStartTimeMs != newStartTimeMs)
+                    || (oldDurationMs != newDurationMs) )&&
+                    (isOverlapping(oldStartTimeMs, oldDurationMs,
+                            mBeginBoundaryTimeMs, transitionDurationMs) ||
+                            isOverlapping(newStartTimeMs, newDurationMs,
+                                    mBeginBoundaryTimeMs, transitionDurationMs))) {
+                mBeginTransition.invalidate();
+            }
+        }
+
+        if (mEndTransition != null) {
+            final long transitionDurationMs = mEndTransition.getDuration();
+            /**
+             *  If the start time + duration has changed and if the old or the new
+             *  item overlaps the end transition, invalidate the transition
+             */
+            if (oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs &&
+                    (isOverlapping(oldStartTimeMs, oldDurationMs,
+                            mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs) ||
+                            isOverlapping(newStartTimeMs, newDurationMs,
+                                    mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs))) {
+                mEndTransition.invalidate();
+            }
+        }
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public int getAspectRatio() {
+        return mAspectRatio;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public int getFileType() {
+        return mFileType;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public int getWidth() {
+        return mWidth;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public int getHeight() {
+        return mHeight;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public long getDuration() {
+        return mDurationMs;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public long getTimelineDuration() {
+        return mEndBoundaryTimeMs - mBeginBoundaryTimeMs;
+    }
+
+    /**
+     * Render a frame according to the playback (in the native aspect ratio) for
+     * the specified media item. All effects and overlays applied to the media
+     * item are ignored. The extract boundaries are also ignored. This method
+     * can be used to playback frames when implementing trimming functionality.
+     *
+     * @param surfaceHolder SurfaceHolder used by the application
+     * @param timeMs time corresponding to the frame to display (relative to the
+     *            the beginning of the media item).
+     * @return The accurate time stamp of the frame that is rendered .
+     * @throws IllegalStateException if a playback, preview or an export is
+     *             already in progress
+     * @throws IllegalArgumentException if time is negative or greater than the
+     *             media item duration
+     */
+    public long renderFrame(SurfaceHolder surfaceHolder, long timeMs) {
+        if (surfaceHolder == null) {
+            throw new IllegalArgumentException("Surface Holder is null");
+        }
+
+        if (timeMs > mDurationMs || timeMs < 0) {
+            throw new IllegalArgumentException("requested time not correct");
+        }
+
+        Surface surface = surfaceHolder.getSurface();
+        if (surface == null) {
+            throw new RuntimeException("Surface could not be retrieved from Surface holder");
+        }
+
+        if (mFilename != null) {
+            return mMANativeHelper.renderMediaItemPreviewFrame(surface,
+                    mFilename,timeMs,mWidth,mHeight);
+        }
+        else {
+            return 0;
+        }
+    }
+
+
+    /**
+     * This API allows to generate a file containing the sample volume levels of
+     * the Audio track of this media item. This function may take significant
+     * time and is blocking. The file can be retrieved using
+     * getAudioWaveformFilename().
+     *
+     * @param listener The progress listener
+     *
+     * @throws IOException if the output file cannot be created
+     * @throws IllegalArgumentException if the mediaItem does not have a valid
+     *             Audio track
+     */
+    public void extractAudioWaveform(ExtractAudioWaveformProgressListener listener)
+    throws IOException {
+        int frameDuration = 0;
+        int sampleCount = 0;
+        final String projectPath = mMANativeHelper.getProjectPath();
+        /**
+         *  Waveform file does not exist
+         */
+        if (mAudioWaveformFilename == null ) {
+            /**
+             * Since audioWaveformFilename will not be supplied,it is  generated
+             */
+            String mAudioWaveFileName = null;
+
+            mAudioWaveFileName =
+                String.format(projectPath + "/" + "audioWaveformFile-"+ getId() + ".dat");
+            /**
+             * Logic to get frame duration = (no. of frames per sample * 1000)/
+             * sampling frequency
+             */
+            if ( mMANativeHelper.getAudioCodecType(mAudioType) ==
+                MediaProperties.ACODEC_AMRNB ) {
+                frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRNB*1000)/
+                MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
+                sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRNB;
+            }
+            else if ( mMANativeHelper.getAudioCodecType(mAudioType) ==
+                MediaProperties.ACODEC_AMRWB ) {
+                frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRWB * 1000)/
+                MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
+                sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRWB;
+            }
+            else if ( mMANativeHelper.getAudioCodecType(mAudioType) ==
+                MediaProperties.ACODEC_AAC_LC ) {
+                frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AAC * 1000)/
+                MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
+                sampleCount = MediaProperties.SAMPLES_PER_FRAME_AAC;
+            }
+
+            mMANativeHelper.generateAudioGraph( getId(),
+                    mFilename,
+                    mAudioWaveFileName,
+                    frameDuration,
+                    MediaProperties.DEFAULT_CHANNEL_COUNT,
+                    sampleCount,
+                    listener,
+                    true);
+            /**
+             * Record the generated file name
+             */
+            mAudioWaveformFilename = mAudioWaveFileName;
+        }
+        mWaveformData =
+            new SoftReference<WaveformData>(new WaveformData(mAudioWaveformFilename));
+    }
+
+    /**
+     * Get the audio waveform file name if {@link #extractAudioWaveform()} was
+     * successful. The file format is as following:
+     * <ul>
+     *  <li>first 4 bytes provide the number of samples for each value, as big-endian signed</li>
+     *  <li>4 following bytes is the total number of values in the file, as big-endian signed</li>
+     *  <li>all values follow as bytes Name is unique.</li>
+     *</ul>
+     * @return the name of the file, null if the file has not been computed or
+     *         if there is no Audio track in the mediaItem
+     */
+    String getAudioWaveformFilename() {
+        return mAudioWaveformFilename;
+    }
+
+    /**
+     * Invalidate the AudioWaveform File
+     */
+    void invalidate() {
+        if (mAudioWaveformFilename != null) {
+            new File(mAudioWaveformFilename).delete();
+            mAudioWaveformFilename = null;
+        }
+    }
+
+    /**
+     * @return The waveform data
+     */
+    public WaveformData getWaveformData() throws IOException {
+        if (mWaveformData == null) {
+            return null;
+        }
+
+        WaveformData waveformData = mWaveformData.get();
+        if (waveformData != null) {
+            return waveformData;
+        } else if (mAudioWaveformFilename != null) {
+            try {
+                waveformData = new WaveformData(mAudioWaveformFilename);
+            } catch(IOException e) {
+                throw e;
+            }
+            mWaveformData = new SoftReference<WaveformData>(waveformData);
+            return waveformData;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Set volume of the Audio track of this mediaItem
+     *
+     * @param volumePercent in %/. 100% means no change; 50% means half value, 200%
+     *            means double, 0% means silent.
+     * @throws UsupportedOperationException if volume value is not supported
+     */
+    public void setVolume(int volumePercent) {
+        if ((volumePercent <0) || (volumePercent >100)) {
+            throw new IllegalArgumentException("Invalid volume");
+        }
+
+        mVolumePercentage = volumePercent;
+    }
+
+    /**
+     * Get the volume value of the audio track as percentage. Call of this
+     * method before calling setVolume will always return 100%
+     *
+     * @return the volume in percentage
+     */
+    public int getVolume() {
+        return mVolumePercentage;
+    }
+
+    /**
+     * @param muted true to mute the media item
+     */
+    public void setMute(boolean muted) {
+        mMuted = muted;
+        if (mBeginTransition != null) {
+            mBeginTransition.invalidate();
+        }
+        if (mEndTransition != null) {
+            mEndTransition.invalidate();
+        }
+        mMANativeHelper.setGeneratePreview(true);
+    }
+
+    /**
+     * @return true if the media item is muted
+     */
+    public boolean isMuted() {
+        return mMuted;
+    }
+
+    /**
+     * @return The video type
+     */
+    public int getVideoType() {
+        return mVideoType;
+    }
+
+    /**
+     * @return The video profile
+     */
+    public int getVideoProfile() {
+        return mVideoProfile;
+    }
+
+    /**
+     * @return The video bitrate
+     */
+    public int getVideoBitrate() {
+        return mVideoBitrate;
+    }
+
+    /**
+     * @return The audio bitrate
+     */
+    public int getAudioBitrate() {
+        return mAudioBitrate;
+    }
+
+    /**
+     * @return The number of frames per second
+     */
+    public int getFps() {
+        return mFps;
+    }
+
+    /**
+     * @return The audio codec
+     */
+    public int getAudioType() {
+        return mAudioType;
+    }
+
+    /**
+     * @return The number of audio channels
+     */
+    public int getAudioChannels() {
+        return mAudioChannels;
+    }
+
+    /**
+     * @return The audio sample frequency
+     */
+    public int getAudioSamplingFrequency() {
+        return mAudioSamplingFrequency;
+    }
+
+    /**
+     * @return The Video media item properties in ClipSettings class object
+     * {@link android.media.videoeditor.MediaArtistNativeHelper.ClipSettings}
+     */
+    ClipSettings getVideoClipProperties() {
+        ClipSettings clipSettings = new ClipSettings();
+        clipSettings.clipPath = getFilename();
+        clipSettings.fileType = mMANativeHelper.getMediaItemFileType(getFileType());
+        clipSettings.beginCutTime = (int)getBoundaryBeginTime();
+        clipSettings.endCutTime = (int)getBoundaryEndTime();
+        clipSettings.mediaRendering = mMANativeHelper.getMediaItemRenderingMode(getRenderingMode());
+
+        return clipSettings;
+    }
+
+}
diff --git a/media/java/android/media/videoeditor/Overlay.java b/media/java/android/media/videoeditor/Overlay.java
index 0174ba8..ec03966 100755
--- a/media/java/android/media/videoeditor/Overlay.java
+++ b/media/java/android/media/videoeditor/Overlay.java
@@ -1,192 +1,220 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-import java.util.HashMap;

-import java.util.Map;

-

-

-/**

- * This is the super class for all Overlay classes.

- * {@hide}

- */

-public abstract class Overlay {

-    // Instance variables

-    private final String mUniqueId;

-    // The overlay owner

-    private final MediaItem mMediaItem;

-    // user attributes

-    private final Map<String, String> mUserAttributes;

-

-    protected long mStartTimeMs;

-    protected long mDurationMs;

-

-

-    /**

-     * Default constructor

-     */

-    @SuppressWarnings("unused")

-    private Overlay() {

-        this(null, null, 0, 0);

-    }

-

-    /**

-     * Constructor

-     *

-     * @param mediaItem The media item owner

-     * @param overlayId The overlay id

-     * @param startTimeMs The start time relative to the media item start time

-     * @param durationMs The duration

-     *

-     * @throws IllegalArgumentException if the file type is not PNG or the

-     *      startTimeMs and durationMs are incorrect.

-     */

-    public Overlay(MediaItem mediaItem, String overlayId, long startTimeMs, long durationMs) {

-        if (mediaItem == null) {

-            throw new IllegalArgumentException("Media item cannot be null");

-        }

-

-        if (startTimeMs + durationMs > mediaItem.getDuration()) {

-            throw new IllegalArgumentException("Invalid start time and duration");

-        }

-

-        mMediaItem = mediaItem;

-        mUniqueId = overlayId;

-        mStartTimeMs = startTimeMs;

-        mDurationMs = durationMs;

-        mUserAttributes = new HashMap<String, String>();

-    }

-

-    /**

-     * @return The of the overlay

-     */

-    public String getId() {

-        return mUniqueId;

-    }

-

-    /**

-     * @return The duration of the overlay effect

-     */

-    public long getDuration() {

-        return mDurationMs;

-    }

-

-    /**

-     * If a preview or export is in progress, then this change is effective for

-     * next preview or export session.

-     *

-     * @param durationMs The duration in milliseconds

-     */

-    public void setDuration(long durationMs) {

-        if (mStartTimeMs + durationMs > mMediaItem.getDuration()) {

-            throw new IllegalArgumentException("Duration is too large");

-        }

-

-        final long oldDurationMs = mDurationMs;

-        mDurationMs = durationMs;

-

-        mMediaItem.invalidateTransitions(mStartTimeMs, oldDurationMs, mStartTimeMs, mDurationMs);

-    }

-

-    /**

-     * @return the start time of the overlay

-     */

-    public long getStartTime() {

-        return mStartTimeMs;

-    }

-

-    /**

-     * Set the start time for the overlay. If a preview or export is in

-     * progress, then this change is effective for next preview or export

-     * session.

-     *

-     * @param startTimeMs start time in milliseconds

-     */

-    public void setStartTime(long startTimeMs) {

-        if (startTimeMs + mDurationMs > mMediaItem.getDuration()) {

-            throw new IllegalArgumentException("Start time is too large");

-        }

-

-        final long oldStartTimeMs = mStartTimeMs;

-        mStartTimeMs = startTimeMs;

-

-        mMediaItem.invalidateTransitions(oldStartTimeMs, mDurationMs, mStartTimeMs, mDurationMs);

-    }

-

-    /**

-     * Set the start time and duration

-     *

-     * @param startTimeMs start time in milliseconds

-     * @param durationMs The duration in milliseconds

-     */

-    public void setStartTimeAndDuration(long startTimeMs, long durationMs) {

-        if (startTimeMs + durationMs > mMediaItem.getDuration()) {

-            throw new IllegalArgumentException("Invalid start time or duration");

-        }

-

-        final long oldStartTimeMs = mStartTimeMs;

-        final long oldDurationMs = mDurationMs;

-

-        mStartTimeMs = startTimeMs;

-        mDurationMs = durationMs;

-

-        mMediaItem.invalidateTransitions(oldStartTimeMs, oldDurationMs, mStartTimeMs, mDurationMs);

-    }

-

-    /**

-     * @return The media item owner

-     */

-    public MediaItem getMediaItem() {

-        return mMediaItem;

-    }

-

-    /**

-     * Set a user attribute

-     *

-     * @param name The attribute name

-     * @param value The attribute value

-     */

-    public void setUserAttribute(String name, String value) {

-        mUserAttributes.put(name, value);

-    }

-

-    /**

-     * @return The user attributes

-     */

-    public Map<String, String> getUserAttributes() {

-        return mUserAttributes;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public boolean equals(Object object) {

-        if (!(object instanceof Overlay)) {

-            return false;

-        }

-        return mUniqueId.equals(((Overlay)object).mUniqueId);

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public int hashCode() {

-        return mUniqueId.hashCode();

-    }

-}

+/*
+ * 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.
+ */
+
+
+package android.media.videoeditor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This is the super class for all Overlay classes.
+ * {@hide}
+ */
+public abstract class Overlay {
+    /**
+     *  Instance variables
+     */
+    private final String mUniqueId;
+    /**
+     *  The overlay owner
+     */
+    private final MediaItem mMediaItem;
+    /**
+     *  user attributes
+     */
+    private final Map<String, String> mUserAttributes;
+
+    protected long mStartTimeMs;
+    protected long mDurationMs;
+
+    /**
+     * Default constructor
+     */
+    @SuppressWarnings("unused")
+    private Overlay() {
+        this(null, null, 0, 0);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param mediaItem The media item owner
+     * @param overlayId The overlay id
+     * @param startTimeMs The start time relative to the media item start time
+     * @param durationMs The duration
+     *
+     * @throws IllegalArgumentException if the file type is not PNG or the
+     *      startTimeMs and durationMs are incorrect.
+     */
+    public Overlay(MediaItem mediaItem, String overlayId, long startTimeMs,
+           long durationMs) {
+        if (mediaItem == null) {
+            throw new IllegalArgumentException("Media item cannot be null");
+        }
+
+        if ((startTimeMs<0) || (durationMs<0) ) {
+            throw new IllegalArgumentException("Invalid start time and/OR duration");
+        }
+
+        if (startTimeMs + durationMs > mediaItem.getDuration()) {
+            throw new IllegalArgumentException("Invalid start time and duration");
+        }
+
+        mMediaItem = mediaItem;
+        mUniqueId = overlayId;
+        mStartTimeMs = startTimeMs;
+        mDurationMs = durationMs;
+        mUserAttributes = new HashMap<String, String>();
+    }
+
+    /**
+     * Get the overlay ID.
+     *
+     * @return The of the overlay
+     */
+    public String getId() {
+        return mUniqueId;
+    }
+
+    /**
+     * Get the duration of overlay.
+     *
+     * @return The duration of the overlay effect
+     */
+    public long getDuration() {
+        return mDurationMs;
+    }
+
+    /**
+     * If a preview or export is in progress, then this change is effective for
+     * next preview or export session.
+     *
+     * @param durationMs The duration in milliseconds
+     */
+    public void setDuration(long durationMs) {
+
+        if (durationMs < 0) {
+            throw new IllegalArgumentException("Invalid duration");
+        }
+
+        if (mStartTimeMs + durationMs > mMediaItem.getDuration()) {
+            throw new IllegalArgumentException("Duration is too large");
+        }
+
+        final long oldDurationMs = mDurationMs;
+        mDurationMs = durationMs;
+
+        mMediaItem.invalidateTransitions(mStartTimeMs, oldDurationMs,
+                                         mStartTimeMs, mDurationMs);
+    }
+
+    /**
+     * Get the start time of overlay.
+     *
+     * @return the start time of the overlay
+     */
+    public long getStartTime() {
+        return mStartTimeMs;
+    }
+
+    /**
+     * Set the start time for the overlay. If a preview or export is in
+     * progress, then this change is effective for next preview or export
+     * session.
+     *
+     * @param startTimeMs start time in milliseconds
+     */
+    public void setStartTime(long startTimeMs) {
+        if (startTimeMs + mDurationMs > mMediaItem.getDuration()) {
+            throw new IllegalArgumentException("Start time is too large");
+        }
+
+        final long oldStartTimeMs = mStartTimeMs;
+        mStartTimeMs = startTimeMs;
+
+        mMediaItem.invalidateTransitions(oldStartTimeMs, mDurationMs,
+                                         mStartTimeMs, mDurationMs);
+    }
+
+    /**
+     * Set the start time and duration
+     *
+     * @param startTimeMs start time in milliseconds
+     * @param durationMs The duration in milliseconds
+     */
+    public void setStartTimeAndDuration(long startTimeMs, long durationMs) {
+        if (startTimeMs + durationMs > mMediaItem.getDuration()) {
+            throw new IllegalArgumentException("Invalid start time or duration");
+        }
+
+        final long oldStartTimeMs = mStartTimeMs;
+        final long oldDurationMs = mDurationMs;
+
+        mStartTimeMs = startTimeMs;
+        mDurationMs = durationMs;
+
+        mMediaItem.invalidateTransitions(oldStartTimeMs, oldDurationMs,
+                                         mStartTimeMs, mDurationMs);
+    }
+
+    /**
+     * Get the media item owner.
+     *
+     * @return The media item owner.
+     */
+    public MediaItem getMediaItem() {
+        return mMediaItem;
+    }
+
+    /**
+     * Set a user attribute
+     *
+     * @param name The attribute name
+     * @param value The attribute value
+     */
+    public void setUserAttribute(String name, String value) {
+        mUserAttributes.put(name, value);
+    }
+
+    /**
+     * Get the current user attributes set.
+     *
+     * @return The user attributes
+     */
+    public Map<String, String> getUserAttributes() {
+        return mUserAttributes;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (!(object instanceof Overlay)) {
+            return false;
+        }
+        return mUniqueId.equals(((Overlay)object).mUniqueId);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return mUniqueId.hashCode();
+    }
+}
diff --git a/media/java/android/media/videoeditor/OverlayFrame.java b/media/java/android/media/videoeditor/OverlayFrame.java
index a5511f9..834fc66 100755
--- a/media/java/android/media/videoeditor/OverlayFrame.java
+++ b/media/java/android/media/videoeditor/OverlayFrame.java
@@ -1,149 +1,248 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-import java.io.File;

-import java.io.FileNotFoundException;

-import java.io.FileOutputStream;

-import java.io.IOException;

-

-import android.graphics.Bitmap;

-import android.graphics.BitmapFactory;

-import android.graphics.Bitmap.CompressFormat;

-

-

-/**

- * This class is used to overlay an image on top of a media item.

- * {@hide}

- */

-public class OverlayFrame extends Overlay {

-    // Instance variables

-    private Bitmap mBitmap;

-    private String mFilename;

-

-    /**

-     * An object of this type cannot be instantiated by using the default

-     * constructor

-     */

-    @SuppressWarnings("unused")

-    private OverlayFrame() {

-        this(null, null, (String)null, 0, 0);

-    }

-

-    /**

-     * Constructor for an OverlayFrame

-     *

-     * @param mediaItem The media item owner

-     * @param overlayId The overlay id

-     * @param bitmap The bitmap to be used as an overlay. The size of the

-     *      bitmap must equal to the size of the media item to which it is

-     *      added. The bitmap is typically a decoded PNG file.

-     * @param startTimeMs The overlay start time in milliseconds

-     * @param durationMs The overlay duration in milliseconds

-     *

-     * @throws IllegalArgumentException if the file type is not PNG or the

-     *      startTimeMs and durationMs are incorrect.

-     */

-    public OverlayFrame(MediaItem mediaItem, String overlayId, Bitmap bitmap, long startTimeMs,

-            long durationMs) {

-        super(mediaItem, overlayId, startTimeMs, durationMs);

-        mBitmap = bitmap;

-        mFilename = null;

-    }

-

-    /**

-     * Constructor for an OverlayFrame. This constructor can be used to

-     * restore the overlay after it was saved internally by the video editor.

-     *

-     * @param mediaItem The media item owner

-     * @param overlayId The overlay id

-     * @param filename The file name that contains the overlay.

-     * @param startTimeMs The overlay start time in milliseconds

-     * @param durationMs The overlay duration in milliseconds

-     *

-     * @throws IllegalArgumentException if the file type is not PNG or the

-     *      startTimeMs and durationMs are incorrect.

-     */

-    OverlayFrame(MediaItem mediaItem, String overlayId, String filename, long startTimeMs,

-            long durationMs) {

-        super(mediaItem, overlayId, startTimeMs, durationMs);

-        mFilename = filename;

-        mBitmap = BitmapFactory.decodeFile(mFilename);

-    }

-

-    /**

-     * @return Get the overlay bitmap

-     */

-    public Bitmap getBitmap() {

-        return mBitmap;

-    }

-

-    /**

-     * @param bitmap The overlay bitmap

-     */

-    public void setBitmap(Bitmap bitmap) {

-        mBitmap = bitmap;

-        if (mFilename != null) {

-            // Delete the file

-            new File(mFilename).delete();

-            // Invalidate the filename

-            mFilename = null;

-        }

-

-        // Invalidate the transitions if necessary

-        getMediaItem().invalidateTransitions(mStartTimeMs, mDurationMs);

-    }

-

-    /**

-     * Get the file name of this overlay

-     */

-    String getFilename() {

-        return mFilename;

-    }

-

-    /**

-     * Save the overlay to the project folder

-     *

-     * @param path The path where the overlay will be saved

-     *

-     * @return The filename

-     * @throws FileNotFoundException if the bitmap cannot be saved

-     * @throws IOException if the bitmap file cannot be saved

-     */

-    String save(String path) throws FileNotFoundException, IOException {

-        if (mFilename != null) {

-            return mFilename;

-        }

-

-        mFilename = path + "/" + getId() + ".png";

-        // Save the image to a local file

-        final FileOutputStream out = new FileOutputStream(mFilename);

-        mBitmap.compress(CompressFormat.PNG, 100, out);

-        out.flush();

-        out.close();

-        return mFilename;

-    }

-

-    /**

-     * Delete the overlay file

-     */

-    void invalidate() {

-        if (mFilename != null) {

-            new File(mFilename).delete();

-        }

-    }

-}

+/*
+ * 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.
+ */
+
+
+package android.media.videoeditor;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap.CompressFormat;
+
+import java.io.DataOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * This class is used to overlay an image on top of a media item.
+ * {@hide}
+ */
+public class OverlayFrame extends Overlay {
+    /**
+     *  Instance variables
+     */
+    private Bitmap mBitmap;
+    private String mFilename;
+    private String mBitmapFileName;
+
+    private int mOFWidth;
+    private int mOFHeight;
+
+    /**
+     * An object of this type cannot be instantiated by using the default
+     * constructor
+     */
+    @SuppressWarnings("unused")
+    private OverlayFrame() {
+        this(null, null, (String)null, 0, 0);
+    }
+
+    /**
+     * Constructor for an OverlayFrame
+     *
+     * @param mediaItem The media item owner
+     * @param overlayId The overlay id
+     * @param bitmap The bitmap to be used as an overlay. The size of the
+     *      bitmap must equal to the size of the media item to which it is
+     *      added. The bitmap is typically a decoded PNG file.
+     * @param startTimeMs The overlay start time in milliseconds
+     * @param durationMs The overlay duration in milliseconds
+     *
+     * @throws IllegalArgumentException if the file type is not PNG or the
+     *      startTimeMs and durationMs are incorrect.
+     */
+    public OverlayFrame(MediaItem mediaItem, String overlayId, Bitmap bitmap,
+                        long startTimeMs,long durationMs) {
+        super(mediaItem, overlayId, startTimeMs, durationMs);
+        mBitmap = bitmap;
+        mFilename = null;
+        mBitmapFileName = null;
+    }
+
+    /**
+     * Constructor for an OverlayFrame. This constructor can be used to
+     * restore the overlay after it was saved internally by the video editor.
+     *
+     * @param mediaItem The media item owner
+     * @param overlayId The overlay id
+     * @param filename The file name that contains the overlay.
+     * @param startTimeMs The overlay start time in milliseconds
+     * @param durationMs The overlay duration in milliseconds
+     *
+     * @throws IllegalArgumentException if the file type is not PNG or the
+     *      startTimeMs and durationMs are incorrect.
+     */
+    OverlayFrame(MediaItem mediaItem, String overlayId, String filename,
+                 long startTimeMs,long durationMs) {
+        super(mediaItem, overlayId, startTimeMs, durationMs);
+        mBitmapFileName = filename;
+        mBitmap = BitmapFactory.decodeFile(mBitmapFileName);
+        mFilename = null;
+    }
+
+    /**
+     * Get the overlay bitmap.
+     *
+     * @return Get the overlay bitmap
+     */
+    public Bitmap getBitmap() {
+        return mBitmap;
+    }
+
+    /**
+     * Get the overlay bitmap.
+     *
+     * @return Get the overlay bitmap as png file.
+     */
+    String getBitmapImageFileName() {
+        return mBitmapFileName;
+    }
+    /**
+     * Set the overlay bitmap.
+     *
+     * @param bitmap The overlay bitmap.
+     */
+    public void setBitmap(Bitmap bitmap) {
+        mBitmap = bitmap;
+        if (mFilename != null) {
+            /**
+             *  Delete the file
+             */
+            new File(mFilename).delete();
+            /**
+             *  Invalidate the filename
+             */
+            mFilename = null;
+        }
+
+        /**
+         *  Invalidate the transitions if necessary
+         */
+        getMediaItem().invalidateTransitions(mStartTimeMs, mDurationMs);
+    }
+
+    /**
+     * Get the file name of this overlay
+     */
+    String getFilename() {
+        return mFilename;
+    }
+
+    /*
+     * Set the file name of this overlay
+     */
+    void setFilename(String filename) {
+        mFilename = filename;
+    }
+    /**
+     * Save the overlay to the project folder
+     *
+     * @param path The path where the overlay will be saved
+     *
+     * @return The filename
+     * @throws FileNotFoundException if the bitmap cannot be saved
+     * @throws IOException if the bitmap file cannot be saved
+     */
+    String save(String path) throws FileNotFoundException, IOException {
+        if (mFilename != null) {
+            return mFilename;
+        }
+
+        // Create the compressed PNG file
+        mBitmapFileName = path + "/" + "Overlay" + getId() + ".png";
+        if (!(new File(mBitmapFileName).exists())) {
+            final FileOutputStream out = new FileOutputStream (mBitmapFileName);
+            mBitmap.compress(CompressFormat.PNG, 100, out);
+            out.flush();
+            out.close();
+        }
+
+        mOFWidth = mBitmap.getWidth();
+        mOFHeight = mBitmap.getHeight();
+
+        mFilename = path + "/" + "Overlay" + getId() + ".rgb";
+        if (!(new File(mFilename).exists())) {
+            /**
+             * Save the image to a file ; as a rgb
+             */
+            final FileOutputStream fl = new FileOutputStream(mFilename);
+            final DataOutputStream dos = new DataOutputStream(fl);
+
+            /**
+             * populate the rgb file with bitmap data
+             */
+            final int [] framingBuffer = new int[mOFWidth];
+            ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
+            IntBuffer intBuffer;
+
+            byte[] array = byteBuffer.array();
+            int tmp = 0;
+            while(tmp < mOFHeight) {
+                mBitmap.getPixels(framingBuffer,0,mOFWidth,0,tmp,mOFWidth,1);
+                intBuffer = byteBuffer.asIntBuffer();
+                intBuffer.put(framingBuffer,0,mOFWidth);
+                dos.write(array);
+                tmp += 1;
+            }
+            fl.flush();
+            fl.close();
+        }
+        return mFilename;
+    }
+
+    /**
+     * Get the OverlayFrame Height
+     */
+     int getOverlayFrameHeight() {
+         return mOFHeight;
+     }
+
+     /**
+     * Get the OverlayFrame Width
+     */
+     int getOverlayFrameWidth() {
+         return mOFWidth;
+     }
+
+    /*
+     * Set the OverlayFrame Height
+     */
+     void setOverlayFrameHeight(int height) {
+         mOFHeight = height;
+     }
+
+    /*
+     * Set the OverlayFrame Width
+     */
+     void setOverlayFrameWidth(int width) {
+         mOFWidth = width;
+     }
+    /**
+     * Delete the overlay file
+     */
+    void invalidate() {
+        if (mFilename != null) {
+            new File(mFilename).delete();
+            mFilename = null;
+            mBitmap.recycle();
+            mBitmap = null;
+        }
+    }
+}
diff --git a/media/java/android/media/videoeditor/Transition.java b/media/java/android/media/videoeditor/Transition.java
index 1c82742..feec284 100755
--- a/media/java/android/media/videoeditor/Transition.java
+++ b/media/java/android/media/videoeditor/Transition.java
@@ -1,210 +1,483 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-import java.io.File;

-

-/**

- * This class is super class for all transitions. Transitions (with the

- * exception of TransitionAtStart and TransitioAtEnd) can only be inserted

- * between media items.

- *

- * Adding a transition between MediaItems makes the

- * duration of the storyboard shorter by the duration of the Transition itself.

- * As a result, if the duration of the transition is larger than the smaller

- * duration of the two MediaItems associated with the Transition, an exception

- * will be thrown.

- *

- * During a transition, the audio track are cross-fading

- * automatically. {@hide}

- */

-public abstract class Transition {

-    // The transition behavior

-    private static final int BEHAVIOR_MIN_VALUE = 0;

-    /** The transition starts slowly and speed up */

-    public static final int BEHAVIOR_SPEED_UP = 0;

-    /** The transition start fast and speed down */

-    public static final int BEHAVIOR_SPEED_DOWN = 1;

-    /** The transition speed is constant */

-    public static final int BEHAVIOR_LINEAR = 2;

-    /** The transition starts fast and ends fast with a slow middle */

-    public static final int BEHAVIOR_MIDDLE_SLOW = 3;

-    /** The transition starts slowly and ends slowly with a fast middle */

-    public static final int BEHAVIOR_MIDDLE_FAST = 4;

-

-    private static final int BEHAVIOR_MAX_VALUE = 4;

-

-    // The unique id of the transition

-    private final String mUniqueId;

-

-    // The transition is applied at the end of this media item

-    private final MediaItem mAfterMediaItem;

-    // The transition is applied at the beginning of this media item

-    private final MediaItem mBeforeMediaItem;

-

-    // The transition behavior

-    protected final int mBehavior;

-

-    // The transition duration

-    protected long mDurationMs;

-

-    // The transition filename

-    protected String mFilename;

-

-    /**

-     * An object of this type cannot be instantiated by using the default

-     * constructor

-     */

-    @SuppressWarnings("unused")

-    private Transition() {

-        this(null, null, null, 0, 0);

-    }

-

-    /**

-     * Constructor

-     *

-     * @param transitionId The transition id

-     * @param afterMediaItem The transition is applied to the end of this

-     *      media item

-     * @param beforeMediaItem The transition is applied to the beginning of

-     *      this media item

-     * @param durationMs The duration of the transition in milliseconds

-     * @param behavior The transition behavior

-     */

-    protected Transition(String transitionId, MediaItem afterMediaItem, MediaItem beforeMediaItem,

-            long durationMs, int behavior) {

-        if (behavior < BEHAVIOR_MIN_VALUE || behavior > BEHAVIOR_MAX_VALUE) {

-            throw new IllegalArgumentException("Invalid behavior: " + behavior);

-        }

-        mUniqueId = transitionId;

-        mAfterMediaItem = afterMediaItem;

-        mBeforeMediaItem = beforeMediaItem;

-        mDurationMs = durationMs;

-        mBehavior = behavior;

-    }

-

-    /**

-     * @return The of the transition

-     */

-    public String getId() {

-        return mUniqueId;

-    }

-

-    /**

-     * @return The media item at the end of which the transition is applied

-     */

-    public MediaItem getAfterMediaItem() {

-        return mAfterMediaItem;

-    }

-

-    /**

-     * @return The media item at the beginning of which the transition is applied

-     */

-    public MediaItem getBeforeMediaItem() {

-        return mBeforeMediaItem;

-    }

-

-    /**

-     * Set the duration of the transition.

-     *

-     * @param durationMs the duration of the transition in milliseconds

-     */

-    public void setDuration(long durationMs) {

-        if (durationMs > getMaximumDuration()) {

-            throw new IllegalArgumentException("The duration is too large");

-        }

-

-        mDurationMs = durationMs;

-        invalidate();

-    }

-

-    /**

-     * @return the duration of the transition in milliseconds

-     */

-    public long getDuration() {

-        return mDurationMs;

-    }

-

-    /**

-     * The duration of a transition cannot be greater than half of the minimum

-     * duration of the bounding media items.

-     *

-     * @return The maximum duration of this transition

-     */

-    public long getMaximumDuration() {

-        if (mAfterMediaItem == null) {

-            return mBeforeMediaItem.getTimelineDuration() / 2;

-        } else if (mBeforeMediaItem == null) {

-            return mAfterMediaItem.getTimelineDuration() / 2;

-        } else {

-            return (Math.min(mAfterMediaItem.getTimelineDuration(),

-                    mBeforeMediaItem.getTimelineDuration()) / 2);

-        }

-    }

-

-    /**

-     * @return The behavior

-     */

-    public int getBehavior() {

-        return mBehavior;

-    }

-

-    /**

-     * Generate the video clip for the specified transition.

-     * This method may block for a significant amount of time.

-     *

-     * Before the method completes execution it sets the mFilename to

-     * the name of the newly generated transition video clip file.

-     */

-    abstract void generate();

-

-    /**

-     * Remove any resources associated with this transition

-     */

-    void invalidate() {

-        if (mFilename != null) {

-            new File(mFilename).delete();

-            mFilename = null;

-        }

-    }

-

-    /**

-     * @return true if the transition is generated

-     */

-    boolean isGenerated() {

-        return (mFilename != null);

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public boolean equals(Object object) {

-        if (!(object instanceof Transition)) {

-            return false;

-        }

-        return mUniqueId.equals(((Transition)object).mUniqueId);

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public int hashCode() {

-        return mUniqueId.hashCode();

-    }

-}

+/*
+ * 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.
+ */
+
+
+package android.media.videoeditor;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.media.videoeditor.MediaArtistNativeHelper.AlphaMagicSettings;
+import android.media.videoeditor.MediaArtistNativeHelper.AudioTransition;
+import android.media.videoeditor.MediaArtistNativeHelper.ClipSettings;
+import android.media.videoeditor.MediaArtistNativeHelper.EditSettings;
+import android.media.videoeditor.MediaArtistNativeHelper.EffectSettings;
+import android.media.videoeditor.MediaArtistNativeHelper.SlideTransitionSettings;
+import android.media.videoeditor.MediaArtistNativeHelper.TransitionSettings;
+import android.media.videoeditor.MediaArtistNativeHelper.VideoTransition;
+
+/**
+ * This class is super class for all transitions. Transitions (with the
+ * exception of TransitionAtStart and TransitioAtEnd) can only be inserted
+ * between media items.
+ *
+ * Adding a transition between MediaItems makes the
+ * duration of the storyboard shorter by the duration of the Transition itself.
+ * As a result, if the duration of the transition is larger than the smaller
+ * duration of the two MediaItems associated with the Transition, an exception
+ * will be thrown.
+ *
+ * During a transition, the audio track are cross-fading
+ * automatically. {@hide}
+ */
+public abstract class Transition {
+    /**
+     *  The transition behavior
+     */
+    private static final int BEHAVIOR_MIN_VALUE = 0;
+
+    /** The transition starts slowly and speed up */
+    public static final int BEHAVIOR_SPEED_UP = 0;
+    /** The transition start fast and speed down */
+    public static final int BEHAVIOR_SPEED_DOWN = 1;
+    /** The transition speed is constant */
+    public static final int BEHAVIOR_LINEAR = 2;
+    /** The transition starts fast and ends fast with a slow middle */
+    public static final int BEHAVIOR_MIDDLE_SLOW = 3;
+    /** The transition starts slowly and ends slowly with a fast middle */
+    public static final int BEHAVIOR_MIDDLE_FAST = 4;
+
+    private static final int BEHAVIOR_MAX_VALUE = 4;
+
+    /**
+     *  The unique id of the transition
+     */
+    private final String mUniqueId;
+
+    /**
+     *  The transition is applied at the end of this media item
+     */
+    private final MediaItem mAfterMediaItem;
+    /**
+     *  The transition is applied at the beginning of this media item
+     */
+    private final MediaItem mBeforeMediaItem;
+
+    /**
+     *  The transition behavior
+     */
+    protected final int mBehavior;
+
+    /**
+     *  The transition duration
+     */
+    protected long mDurationMs;
+
+    /**
+     *  The transition filename
+     */
+    protected String mFilename;
+
+    protected MediaArtistNativeHelper mNativeHelper;
+    /**
+     * An object of this type cannot be instantiated by using the default
+     * constructor
+     */
+    @SuppressWarnings("unused")
+    private Transition() {
+        this(null, null, null, 0, 0);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param transitionId The transition id
+     * @param afterMediaItem The transition is applied to the end of this
+     *      media item
+     * @param beforeMediaItem The transition is applied to the beginning of
+     *      this media item
+     * @param durationMs The duration of the transition in milliseconds
+     * @param behavior The transition behavior
+     */
+    protected Transition(String transitionId, MediaItem afterMediaItem,
+                         MediaItem beforeMediaItem,long durationMs,
+                         int behavior) {
+        if (behavior < BEHAVIOR_MIN_VALUE || behavior > BEHAVIOR_MAX_VALUE) {
+            throw new IllegalArgumentException("Invalid behavior: " + behavior);
+        }
+        if ((afterMediaItem == null) && (beforeMediaItem == null)) {
+            throw new IllegalArgumentException("Null media items");
+        }
+        mUniqueId = transitionId;
+        mAfterMediaItem = afterMediaItem;
+        mBeforeMediaItem = beforeMediaItem;
+        mDurationMs = durationMs;
+        mBehavior = behavior;
+        mNativeHelper = null;
+        if (durationMs > getMaximumDuration()) {
+            throw new IllegalArgumentException("The duration is too large");
+        }
+    }
+
+    /**
+     * Get the ID of the transition.
+     *
+     * @return The ID of the transition
+     */
+    public String getId() {
+        return mUniqueId;
+    }
+
+    /**
+     * Get the media item at the end of which the transition is applied.
+     *
+     * @return The media item at the end of which the transition is applied
+     */
+    public MediaItem getAfterMediaItem() {
+        return mAfterMediaItem;
+    }
+
+    /**
+     * Get the media item at the beginning of which the transition is applied.
+     *
+     * @return The media item at the beginning of which the transition is
+     *      applied
+     */
+    public MediaItem getBeforeMediaItem() {
+        return mBeforeMediaItem;
+    }
+
+    /**
+     * Set the duration of the transition.
+     *
+     * @param durationMs the duration of the transition in milliseconds
+     */
+    public void setDuration(long durationMs) {
+        if (durationMs > getMaximumDuration()) {
+            throw new IllegalArgumentException("The duration is too large");
+        }
+
+        mDurationMs = durationMs;
+        invalidate();
+    }
+
+    /**
+     * Get the duration of the transition.
+     *
+     * @return the duration of the transition in milliseconds
+     */
+    public long getDuration() {
+        return mDurationMs;
+    }
+
+    /**
+     * The duration of a transition cannot be greater than half of the minimum
+     * duration of the bounding media items.
+     *
+     * @return The maximum duration of this transition
+     */
+    public long getMaximumDuration() {
+        if (mAfterMediaItem == null) {
+            return mBeforeMediaItem.getTimelineDuration() / 2;
+        } else if (mBeforeMediaItem == null) {
+            return mAfterMediaItem.getTimelineDuration() / 2;
+        } else {
+            return (Math.min(mAfterMediaItem.getTimelineDuration(),
+                    mBeforeMediaItem.getTimelineDuration()) / 2);
+        }
+    }
+
+    /**
+     * Get the behavior of the transition.
+     *
+     * @return The behavior
+     */
+    public int getBehavior() {
+        return mBehavior;
+    }
+
+    /**
+     * Get the transition data.
+     *
+     * @return The transition data in TransitionSettings object
+     * {@link android.media.videoeditor.MediaArtistNativeHelper.TransitionSettings}
+     */
+    TransitionSettings getTransitionSettings() {
+        TransitionAlpha transitionAlpha = null;
+        TransitionSliding transitionSliding = null;
+        TransitionCrossfade transitionCrossfade = null;
+        TransitionFadeBlack transitionFadeBlack = null;
+        TransitionSettings transitionSetting = null;
+        transitionSetting = new TransitionSettings();
+        transitionSetting.duration = (int)getDuration();
+        if (this instanceof TransitionAlpha) {
+            transitionAlpha = (TransitionAlpha)this;
+            transitionSetting.videoTransitionType = VideoTransition.ALPHA_MAGIC;
+            transitionSetting.audioTransitionType = AudioTransition.CROSS_FADE;
+            transitionSetting.transitionBehaviour = mNativeHelper
+            .getVideoTransitionBehaviour(transitionAlpha.getBehavior());
+            transitionSetting.alphaSettings = new AlphaMagicSettings();
+            transitionSetting.slideSettings = null;
+            transitionSetting.alphaSettings.file = transitionAlpha.getPNGMaskFilename();
+            transitionSetting.alphaSettings.blendingPercent = transitionAlpha.getBlendingPercent();
+            transitionSetting.alphaSettings.invertRotation = transitionAlpha.isInvert();
+            transitionSetting.alphaSettings.rgbWidth = transitionAlpha.getRGBFileWidth();
+            transitionSetting.alphaSettings.rgbHeight = transitionAlpha.getRGBFileHeight();
+
+        } else if (this instanceof TransitionSliding) {
+            transitionSliding = (TransitionSliding)this;
+            transitionSetting.videoTransitionType = VideoTransition.SLIDE_TRANSITION;
+            transitionSetting.audioTransitionType = AudioTransition.CROSS_FADE;
+            transitionSetting.transitionBehaviour = mNativeHelper
+            .getVideoTransitionBehaviour(transitionSliding.getBehavior());
+            transitionSetting.alphaSettings = null;
+            transitionSetting.slideSettings = new SlideTransitionSettings();
+            transitionSetting.slideSettings.direction = mNativeHelper
+            .getSlideSettingsDirection(transitionSliding.getDirection());
+        } else if (this instanceof TransitionCrossfade) {
+            transitionCrossfade = (TransitionCrossfade)this;
+            transitionSetting.videoTransitionType = VideoTransition.CROSS_FADE;
+            transitionSetting.audioTransitionType = AudioTransition.CROSS_FADE;
+            transitionSetting.transitionBehaviour = mNativeHelper
+            .getVideoTransitionBehaviour(transitionCrossfade.getBehavior());
+            transitionSetting.alphaSettings = null;
+            transitionSetting.slideSettings = null;
+        } else if (this instanceof TransitionFadeBlack) {
+            transitionFadeBlack = (TransitionFadeBlack)this;
+            transitionSetting.videoTransitionType = VideoTransition.FADE_BLACK;
+            transitionSetting.audioTransitionType = AudioTransition.CROSS_FADE;
+            transitionSetting.transitionBehaviour = mNativeHelper
+            .getVideoTransitionBehaviour(transitionFadeBlack.getBehavior());
+            transitionSetting.alphaSettings = null;
+            transitionSetting.slideSettings = null;
+        }
+
+        return transitionSetting;
+    }
+
+    /**
+     * Checks if the effect and overlay applied on a media item
+     * overlaps with the transition on media item.
+     *
+     * @param m The media item
+     * @param clipSettings The ClipSettings object
+     * @param clipNo The clip no.(out of the two media items
+     * associated with current transition)for which the effect
+     * clip should be generated
+     * @return List of effects that overlap with the transition
+     */
+
+    List<EffectSettings>  isEffectandOverlayOverlapping(MediaItem m, ClipSettings clipSettings,
+                                         int clipNo) {
+        List<Effect> effects;
+        List<Overlay> overlays;
+        List<EffectSettings> effectSettings = new ArrayList<EffectSettings>();
+        EffectSettings tmpEffectSettings;
+
+        effects = m.getAllEffects();
+        for (Effect effect : effects) {
+            if (effect instanceof EffectColor) {
+                tmpEffectSettings = mNativeHelper.getEffectSettings((EffectColor)effect);
+                mNativeHelper.adjustEffectsStartTimeAndDuration(tmpEffectSettings,
+                        clipSettings.beginCutTime, clipSettings.endCutTime);
+                if (tmpEffectSettings.duration != 0) {
+                    if (m instanceof MediaVideoItem) {
+                        tmpEffectSettings.fiftiesFrameRate = mNativeHelper
+                        .GetClosestVideoFrameRate(((MediaVideoItem)m).getFps());
+                    }
+                    effectSettings.add(tmpEffectSettings);
+                }
+            }
+        }
+        overlays = m.getAllOverlays();
+        for (Overlay overlay : overlays) {
+            tmpEffectSettings = mNativeHelper.getOverlaySettings((OverlayFrame)overlay);
+            mNativeHelper.adjustEffectsStartTimeAndDuration(tmpEffectSettings,
+                    clipSettings.beginCutTime, clipSettings.endCutTime);
+            if (tmpEffectSettings.duration != 0) {
+                effectSettings.add(tmpEffectSettings);
+            }
+        }
+         return effectSettings;
+    }
+
+    /**
+     * Generate the video clip for the specified transition. This method may
+     * block for a significant amount of time. Before the method completes
+     * execution it sets the mFilename to the name of the newly generated
+     * transition video clip file.
+     */
+    void generate() {
+        MediaItem m1 = this.getAfterMediaItem();
+        MediaItem m2 = this.getBeforeMediaItem();
+        ClipSettings clipSettings1 = new ClipSettings();
+        ClipSettings clipSettings2 = new ClipSettings();
+        TransitionSettings transitionSetting = null;
+        EditSettings editSettings = new EditSettings();
+        List<EffectSettings> effectSettings_clip1;
+        List<EffectSettings> effectSettings_clip2;
+
+        String output = null;
+        String effectClip1 = null;
+        String effectClip2 = null;
+
+        if (mNativeHelper == null) {
+            if (m1 != null)
+                mNativeHelper = m1.getNativeContext();
+            else if (m2 != null)
+                mNativeHelper = m2.getNativeContext();
+        }
+        transitionSetting = getTransitionSettings();
+        if (m1 != null && m2 != null) {
+            /* transition between media items */
+            clipSettings1 = m1.getClipSettings();
+            clipSettings2 = m2.getClipSettings();
+            clipSettings1.beginCutTime = (int)(clipSettings1.endCutTime -
+                                                              this.mDurationMs);
+            clipSettings2.endCutTime = (int)(clipSettings2.beginCutTime +
+                                                              this.mDurationMs);
+            /*
+             * Check how many effects and overlays overlap with transition and
+             * generate effect clip first if there is any overlap
+             */
+            effectSettings_clip1 = isEffectandOverlayOverlapping(m1, clipSettings1,1);
+            effectSettings_clip2 = isEffectandOverlayOverlapping(m2, clipSettings2,2);
+            for (int index = 0; index < effectSettings_clip2.size(); index++ ) {
+                effectSettings_clip2.get(index).startTime += this.mDurationMs;
+            }
+            editSettings.effectSettingsArray =
+                                              new EffectSettings[effectSettings_clip1.size()
+                                                 + effectSettings_clip2.size()];
+            int i=0,j=0;
+            while (i < effectSettings_clip1.size()) {
+                editSettings.effectSettingsArray[j] = effectSettings_clip1.get(i);
+                i++;
+                j++;
+            }
+            i=0;
+            while (i < effectSettings_clip2.size()) {
+                editSettings.effectSettingsArray[j] = effectSettings_clip2.get(i);
+                i++;
+                j++;
+            }
+        } else if (m1 == null && m2 != null) {
+            /* begin transition at first media item */
+            m2.generateBlankFrame(clipSettings1);
+            clipSettings2 = m2.getClipSettings();
+            clipSettings1.endCutTime = (int)(this.mDurationMs + 50);
+            clipSettings2.endCutTime = (int)(clipSettings2.beginCutTime +
+                                                              this.mDurationMs);
+            /*
+             * Check how many effects and overlays overlap with transition and
+             * generate effect clip first if there is any overlap
+             */
+            effectSettings_clip2 = isEffectandOverlayOverlapping(m2, clipSettings2,2);
+            for (int index = 0; index < effectSettings_clip2.size(); index++ ) {
+                effectSettings_clip2.get(index).startTime += this.mDurationMs;
+            }
+            editSettings.effectSettingsArray = new EffectSettings[effectSettings_clip2.size()];
+            int i=0, j=0;
+            while (i < effectSettings_clip2.size()) {
+                editSettings.effectSettingsArray[j] = effectSettings_clip2.get(i);
+                i++;
+                j++;
+            }
+        } else if (m1 != null && m2 == null) {
+            /* end transition at last media item */
+            clipSettings1 = m1.getClipSettings();
+            m1.generateBlankFrame(clipSettings2);
+            clipSettings1.beginCutTime = (int)(clipSettings1.endCutTime -
+                                                              this.mDurationMs);
+            clipSettings2.endCutTime = (int)(this.mDurationMs + 50);
+            /*
+             * Check how many effects and overlays overlap with transition and
+             * generate effect clip first if there is any overlap
+             */
+            effectSettings_clip1 = isEffectandOverlayOverlapping(m1, clipSettings1,1);
+            editSettings.effectSettingsArray = new EffectSettings[effectSettings_clip1.size()];
+            int i=0,j=0;
+            while (i < effectSettings_clip1.size()) {
+                editSettings.effectSettingsArray[j] = effectSettings_clip1.get(i);
+                i++;
+                j++;
+            }
+        }
+
+        editSettings.clipSettingsArray = new ClipSettings[2];
+        editSettings.clipSettingsArray[0] = clipSettings1;
+        editSettings.clipSettingsArray[1] = clipSettings2;
+        editSettings.backgroundMusicSettings = null;
+        editSettings.transitionSettingsArray = new TransitionSettings[1];
+        editSettings.transitionSettingsArray[0] = transitionSetting;
+        output = mNativeHelper.generateTransitionClip(editSettings, mUniqueId,
+                                                      m1, m2,this);
+        setFilename(output);
+    }
+
+
+    /**
+     * Set the transition filename.
+     */
+    void setFilename(String filename) {
+        mFilename = filename;
+    }
+
+    /**
+     * Get the transition filename.
+     */
+    String getFilename() {
+        return mFilename;
+    }
+
+    /**
+     * Remove any resources associated with this transition
+     */
+    void invalidate() {
+        if (mFilename != null) {
+            new File(mFilename).delete();
+            mFilename = null;
+        }
+    }
+
+    /**
+     * Check if the transition is generated.
+     *
+     * @return true if the transition is generated
+     */
+    boolean isGenerated() {
+        return (mFilename != null);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (!(object instanceof Transition)) {
+            return false;
+        }
+        return mUniqueId.equals(((Transition)object).mUniqueId);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return mUniqueId.hashCode();
+    }
+}
diff --git a/media/java/android/media/videoeditor/TransitionAlpha.java b/media/java/android/media/videoeditor/TransitionAlpha.java
index 2bb16d2..f7d17cb 100755
--- a/media/java/android/media/videoeditor/TransitionAlpha.java
+++ b/media/java/android/media/videoeditor/TransitionAlpha.java
@@ -1,122 +1,212 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-import java.io.File;

-

-

-

-/**

- * This class allows to render an "alpha blending" transition according to a

- * bitmap mask. The mask shows the shape of the transition all along the

- * duration of the transition: just before the transition, video 1 is fully

- * displayed. When the transition starts, as the time goes on, pixels of video 2

- * replace pixels of video 1 according to the gray scale pixel value of the

- * mask.

- * {@hide}

- */

-public class TransitionAlpha extends Transition {

-    /** This is the input JPEG file for the mask */

-    private final String mMaskFilename;

-

-    /**

-     * This is percentage (between 0 and 100) of blending between video 1 and

-     * video 2 if this value equals 0, then the mask is strictly applied if this

-     * value equals 100, then the mask is not at all applied (no transition

-     * effect)

-     */

-    private final int mBlendingPercent;

-

-    /**

-     * If true, this value inverts the direction of the mask: white pixels of

-     * the mask show video 2 pixels first black pixels of the mask show video 2

-     * pixels last.

-     */

-    private final boolean mIsInvert;

-

-    /**

-     * An object of this type cannot be instantiated by using the default

-     * constructor

-     */

-    @SuppressWarnings("unused")

-    private TransitionAlpha() {

-        this(null, null, null, 0, 0, null, 0, false);

-    }

-

-    /**

-     * Constructor

-     *

-     * @param transitionId The transition id

-     * @param afterMediaItem The transition is applied to the end of this media

-     *            item

-     * @param beforeMediaItem The transition is applied to the beginning of this

-     *            media item

-     * @param durationMs duration of the transition in milliseconds

-     * @param behavior behavior is one of the behavior defined in Transition

-     *            class

-     * @param maskFilename JPEG file name. The dimension of the image

-     *           corresponds to 720p (16:9 aspect ratio). Mask files are

-     *           shared between video editors and can be created in the

-     *           projects folder (the parent folder for all projects).

-     * @param blendingPercent The blending percent applied

-     * @param invert true to invert the direction of the alpha blending

-     *

-     * @throws IllegalArgumentException if behavior is not supported, or if

-     *             direction are not supported.

-     */

-    public TransitionAlpha(String transitionId, MediaItem afterMediaItem,

-            MediaItem beforeMediaItem, long durationMs, int behavior, String maskFilename,

-            int blendingPercent, boolean invert) {

-        super(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior);

-

-        if (!new File(maskFilename).exists()) {

-            throw new IllegalArgumentException("Invalid mask file name: " + maskFilename);

-        }

-

-        mMaskFilename = maskFilename;

-        mBlendingPercent = blendingPercent;

-        mIsInvert = invert;

-    }

-

-    /**

-     * @return The blending percentage

-     */

-    public int getBlendingPercent() {

-        return mBlendingPercent;

-    }

-

-    /**

-     * @return The mask filename

-     */

-    public String getMaskFilename() {

-        return mMaskFilename;

-    }

-

-    /**

-     * @return true if the direction of the alpha blending is inverted

-     */

-    public boolean isInvert() {

-        return mIsInvert;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    public void generate() {

-    }

-}

+/*
+ * 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.
+ */
+
+package android.media.videoeditor;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * This class allows to render an "alpha blending" transition according to a
+ * bitmap mask. The mask shows the shape of the transition all along the
+ * duration of the transition: just before the transition, video 1 is fully
+ * displayed. When the transition starts, as the time goes on, pixels of video 2
+ * replace pixels of video 1 according to the gray scale pixel value of the
+ * mask.
+ * {@hide}
+ */
+public class TransitionAlpha extends Transition {
+    /** This is the input JPEG file for the mask */
+    private final String mMaskFilename;
+
+    /**
+     * This is percentage (between 0 and 100) of blending between video 1 and
+     * video 2 if this value equals 0, then the mask is strictly applied if this
+     * value equals 100, then the mask is not at all applied (no transition
+     * effect)
+     */
+    private final int mBlendingPercent;
+
+    /**
+     * If true, this value inverts the direction of the mask: white pixels of
+     * the mask show video 2 pixels first black pixels of the mask show video 2
+     * pixels last.
+     */
+    private final boolean mIsInvert;
+
+
+    private int mWidth;
+    private int mHeight;
+    private String mRGBMaskFile;
+
+    /**
+     * An object of this type cannot be instantiated by using the default
+     * constructor
+     */
+    @SuppressWarnings("unused")
+    private TransitionAlpha() {
+        this(null, null, null, 0, 0, null, 0, false);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param transitionId The transition id
+     * @param afterMediaItem The transition is applied to the end of this media
+     *            item
+     * @param beforeMediaItem The transition is applied to the beginning of this
+     *            media item
+     * @param durationMs duration of the transition in milliseconds
+     * @param behavior behavior is one of the behavior defined in Transition
+     *            class
+     * @param maskFilename JPEG file name. The dimension of the image
+     *           corresponds to 720p (16:9 aspect ratio). Mask files are
+     *           shared between video editors and can be created in the
+     *           projects folder (the parent folder for all projects).
+     * @param blendingPercent The blending percent applied
+     * @param invert true to invert the direction of the alpha blending
+     * @throws IllegalArgumentException if behavior is not supported, or if
+     *             direction are not supported.
+     */
+    public TransitionAlpha(String transitionId, MediaItem afterMediaItem,
+            MediaItem beforeMediaItem, long durationMs, int behavior,
+            String maskFilename, int blendingPercent, boolean invert) {
+        super(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior);
+
+        /**
+         * Generate a RGB file for the supplied mask file
+         */
+        final BitmapFactory.Options dbo = new BitmapFactory.Options();
+        dbo.inJustDecodeBounds = true;
+        if (!new File(maskFilename).exists())
+            throw new IllegalArgumentException("File not Found " + maskFilename);
+        BitmapFactory.decodeFile(maskFilename, dbo);
+
+        mWidth = dbo.outWidth;
+        mHeight = dbo.outHeight;
+
+        if (afterMediaItem != null) {
+            mNativeHelper = afterMediaItem.getNativeContext();
+        }else {
+            mNativeHelper = beforeMediaItem.getNativeContext();
+        }
+
+
+        mRGBMaskFile = String.format(mNativeHelper.getProjectPath() +
+                "/" + "mask" + transitionId+ ".rgb");
+
+
+        FileOutputStream fl = null;
+
+        try{
+             fl = new FileOutputStream(mRGBMaskFile);
+        } catch (IOException e) {
+            /* catch IO exception */
+        }
+        final DataOutputStream dos = new DataOutputStream(fl);
+
+        if (fl != null) {
+            /**
+             * Write to rgb file
+             */
+            Bitmap imageBitmap = BitmapFactory.decodeFile(maskFilename);
+            final int [] framingBuffer = new int[mWidth];
+            ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
+            IntBuffer intBuffer;
+
+            byte[] array = byteBuffer.array();
+            int tmp = 0;
+            while (tmp < mHeight) {
+                imageBitmap.getPixels(framingBuffer, 0, mWidth, 0, tmp,mWidth, 1);
+                intBuffer = byteBuffer.asIntBuffer();
+                intBuffer.put(framingBuffer,0,mWidth);
+                try {
+                    dos.write(array);
+                } catch (IOException e) {
+                    /* catch file write error */
+                }
+                tmp += 1;
+            }
+
+            imageBitmap.recycle();
+            try{
+                fl.close();
+            }catch (IOException e) {
+                /* file close error */
+            }
+        }
+
+        /**
+         * Capture the details
+         */
+        mMaskFilename = maskFilename;
+        mBlendingPercent = blendingPercent;
+        mIsInvert = invert;
+    }
+
+    public int getRGBFileWidth() {
+        return mWidth;
+    }
+
+    public int getRGBFileHeight() {
+        return mHeight;
+    }
+
+    public String getPNGMaskFilename() {
+        return mRGBMaskFile;
+    }
+
+    /**
+     * Get the blending percentage
+     *
+     * @return The blending percentage
+     */
+    public int getBlendingPercent() {
+        return mBlendingPercent;
+    }
+
+    /**
+     * Get the filename of the mask.
+     *
+     * @return The mask filename
+     */
+    public String getMaskFilename() {
+        return mMaskFilename;
+    }
+
+    /**
+     * Check if the alpha blending direction is inverted.
+     *
+     * @return true if the direction of the alpha blending is inverted
+     */
+    public boolean isInvert() {
+        return mIsInvert;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public void generate() {
+        super.generate();
+    }
+}
diff --git a/media/java/android/media/videoeditor/TransitionCrossfade.java b/media/java/android/media/videoeditor/TransitionCrossfade.java
index f8223e8..417c64e 100755
--- a/media/java/android/media/videoeditor/TransitionCrossfade.java
+++ b/media/java/android/media/videoeditor/TransitionCrossfade.java
@@ -1,60 +1,62 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-

-/**

- * This class allows to render a crossfade (dissolve) effect transition between

- * two videos

- * {@hide}

- */

-public class TransitionCrossfade extends Transition {

-    /**

-     * An object of this type cannot be instantiated by using the default

-     * constructor

-     */

-    @SuppressWarnings("unused")

-    private TransitionCrossfade() {

-        this(null, null, null, 0, 0);

-    }

-

-    /**

-     * Constructor

-     *

-     * @param transitionId The transition id

-     * @param afterMediaItem The transition is applied to the end of this

-     *      media item

-     * @param beforeMediaItem The transition is applied to the beginning of

-     *      this media item

-     * @param durationMs duration of the transition in milliseconds

-     * @param behavior behavior is one of the behavior defined in Transition

-     *            class

-     *

-     * @throws IllegalArgumentException if behavior is not supported.

-     */

-    public TransitionCrossfade(String transitionId, MediaItem afterMediaItem,

-            MediaItem beforeMediaItem, long durationMs, int behavior) {

-        super(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior);

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    void generate() {

-    }

-}

+/*
+ * 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.
+ */
+
+
+package android.media.videoeditor;
+
+
+/**
+ * This class allows to render a crossfade (dissolve) effect transition between
+ * two videos
+ * {@hide}
+ */
+public class TransitionCrossfade extends Transition {
+    /**
+     * An object of this type cannot be instantiated by using the default
+     * constructor
+     */
+    @SuppressWarnings("unused")
+    private TransitionCrossfade() {
+        this(null, null, null, 0, 0);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param transitionId The transition id
+     * @param afterMediaItem The transition is applied to the end of this
+     *      media item
+     * @param beforeMediaItem The transition is applied to the beginning of
+     *      this media item
+     * @param durationMs duration of the transition in milliseconds
+     * @param behavior behavior is one of the behavior defined in Transition
+     *      class
+     *
+     * @throws IllegalArgumentException if behavior is not supported.
+     */
+    public TransitionCrossfade(String transitionId, MediaItem afterMediaItem,
+            MediaItem beforeMediaItem, long durationMs, int behavior) {
+        super(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    void generate() {
+        super.generate();
+    }
+}
diff --git a/media/java/android/media/videoeditor/TransitionFadeBlack.java b/media/java/android/media/videoeditor/TransitionFadeBlack.java
index a9bf4ce..da07cf0 100755
--- a/media/java/android/media/videoeditor/TransitionFadeBlack.java
+++ b/media/java/android/media/videoeditor/TransitionFadeBlack.java
@@ -1,60 +1,62 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-

-/**

- * This class is used to render a fade to black and fade from black transition

- * between two media items.

- * {@hide}

- */

-public class TransitionFadeBlack extends Transition {

-    /**

-     * An object of this type cannot be instantiated by using the default

-     * constructor

-     */

-    @SuppressWarnings("unused")

-    private TransitionFadeBlack() {

-        this(null, null, null, 0, 0);

-    }

-

-    /**

-     * Constructor

-     *

-     * @param transitionId The transition id

-     * @param afterMediaItem The transition is applied to the end of this

-     *      media item

-     * @param beforeMediaItem The transition is applied to the beginning of

-     *      this media item

-     * @param durationMs duration of the transition

-     * @param behavior behavior is one of the behavior defined in Transition

-     *            class

-     *

-     * @throws IllegalArgumentException if behavior is not supported.

-     */

-    public TransitionFadeBlack(String transitionId, MediaItem afterMediaItem,

-            MediaItem beforeMediaItem, long durationMs, int behavior) {

-        super(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior);

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    void generate() {

-    }

-}

+/*
+ * 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.
+ */
+
+
+package android.media.videoeditor;
+
+
+/**
+ * This class is used to render a fade to black and fade from black transition
+ * between two media items.
+ * {@hide}
+ */
+public class TransitionFadeBlack extends Transition {
+    /**
+     * An object of this type cannot be instantiated by using the default
+     * constructor
+     */
+    @SuppressWarnings("unused")
+    private TransitionFadeBlack() {
+        this(null, null, null, 0, 0);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param transitionId The transition id
+     * @param afterMediaItem The transition is applied to the end of this
+     *      media item
+     * @param beforeMediaItem The transition is applied to the beginning of
+     *      this media item
+     * @param durationMs duration of the transition
+     * @param behavior behavior is one of the behavior defined in Transition
+     *      class
+     *
+     * @throws IllegalArgumentException if behavior is not supported.
+     */
+    public TransitionFadeBlack(String transitionId, MediaItem afterMediaItem,
+            MediaItem beforeMediaItem, long durationMs, int behavior) {
+        super(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    void generate() {
+        super.generate();
+    }
+}
diff --git a/media/java/android/media/videoeditor/TransitionSliding.java b/media/java/android/media/videoeditor/TransitionSliding.java
index cc9f4b28..57610ab 100755
--- a/media/java/android/media/videoeditor/TransitionSliding.java
+++ b/media/java/android/media/videoeditor/TransitionSliding.java
@@ -1,82 +1,95 @@
-/*

- * 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.

- */

-

-

-package android.media.videoeditor;

-

-/**

- * This class allows to create sliding transitions

- * {@hide}

- */

-public class TransitionSliding extends Transition {

-

-    /** Video 1 is pushed to the right while video 2 is coming from left */

-    public final static int DIRECTION_RIGHT_OUT_LEFT_IN = 0;

-    /** Video 1 is pushed to the left while video 2 is coming from right */

-    public static final int DIRECTION_LEFT_OUT_RIGHT_IN = 1;

-    /** Video 1 is pushed to the top while video 2 is coming from bottom */

-    public static final int DIRECTION_TOP_OUT_BOTTOM_IN = 2;

-    /** Video 1 is pushed to the bottom while video 2 is coming from top */

-    public static final int DIRECTION_BOTTOM_OUT_TOP_IN = 3;

-

-    // The sliding transitions

-    private final int mSlidingDirection;

-

-    /**

-     * An object of this type cannot be instantiated by using the default

-     * constructor

-     */

-    @SuppressWarnings("unused")

-    private TransitionSliding() {

-        this(null, null, null, 0, 0, 0);

-    }

-

-    /**

-     * Constructor

-     *

-     * @param transitionId The transition id

-     * @param afterMediaItem The transition is applied to the end of this

-     *      media item

-     * @param beforeMediaItem The transition is applied to the beginning of

-     *      this media item

-     * @param durationMs duration of the transition in milliseconds

-     * @param behavior behavior is one of the behavior defined in Transition

-     *            class

-     * @param direction direction shall be one of the supported directions like

-     *            RIGHT_OUT_LEFT_IN

-     *

-     * @throws IllegalArgumentException if behavior is not supported.

-     */

-    public TransitionSliding(String transitionId, MediaItem afterMediaItem,

-            MediaItem beforeMediaItem, long durationMs, int behavior, int direction) {

-        super(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior);

-        mSlidingDirection = direction;

-    }

-

-    /**

-     * @return The sliding direction

-     */

-    public int getDirection() {

-        return mSlidingDirection;

-    }

-

-    /*

-     * {@inheritDoc}

-     */

-    @Override

-    void generate() {

-    }

-}

+/*
+ * 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.
+ */
+
+package android.media.videoeditor;
+
+/**
+ * This class allows to create sliding transitions
+ * {@hide}
+ */
+public class TransitionSliding extends Transition {
+
+    /** Video 1 is pushed to the right while video 2 is coming from left */
+    public final static int DIRECTION_RIGHT_OUT_LEFT_IN = 0;
+    /** Video 1 is pushed to the left while video 2 is coming from right */
+    public static final int DIRECTION_LEFT_OUT_RIGHT_IN = 1;
+    /** Video 1 is pushed to the top while video 2 is coming from bottom */
+    public static final int DIRECTION_TOP_OUT_BOTTOM_IN = 2;
+    /** Video 1 is pushed to the bottom while video 2 is coming from top */
+    public static final int DIRECTION_BOTTOM_OUT_TOP_IN = 3;
+
+    // The sliding transitions
+    private final int mSlidingDirection;
+
+    /**
+     * An object of this type cannot be instantiated by using the default
+     * constructor
+     */
+    @SuppressWarnings("unused")
+    private TransitionSliding() {
+        this(null, null, null, 0, 0, 0);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param transitionId The transition id
+     * @param afterMediaItem The transition is applied to the end of this
+     *      media item
+     * @param beforeMediaItem The transition is applied to the beginning of
+     *      this media item
+     * @param durationMs duration of the transition in milliseconds
+     * @param behavior behavior is one of the behavior defined in Transition
+     *            class
+     * @param direction direction shall be one of the supported directions like
+     *            RIGHT_OUT_LEFT_IN
+     *
+     * @throws IllegalArgumentException if behavior is not supported.
+     */
+    public TransitionSliding(String transitionId, MediaItem afterMediaItem,
+            MediaItem beforeMediaItem, long durationMs, int behavior,
+            int direction) {
+        super(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior);
+        switch (direction) {
+            case DIRECTION_RIGHT_OUT_LEFT_IN:
+            case DIRECTION_LEFT_OUT_RIGHT_IN:
+            case DIRECTION_TOP_OUT_BOTTOM_IN:
+            case DIRECTION_BOTTOM_OUT_TOP_IN:
+                break;
+
+            default:
+                throw new IllegalArgumentException("Invalid direction");
+        }
+        mSlidingDirection = direction;
+    }
+
+    /**
+     * Get the sliding direction.
+     *
+     * @return The sliding direction
+     */
+    public int getDirection() {
+        return mSlidingDirection;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    void generate() {
+        super.generate();
+    }
+}
diff --git a/media/java/android/media/videoeditor/VideoEditor.java b/media/java/android/media/videoeditor/VideoEditor.java
index 37bb661..d081e6e 100755
--- a/media/java/android/media/videoeditor/VideoEditor.java
+++ b/media/java/android/media/videoeditor/VideoEditor.java
@@ -1,564 +1,575 @@
-/*

- * 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.

- */

-

-package android.media.videoeditor;

-

-import java.io.IOException;

-import java.util.List;

-import java.util.concurrent.CancellationException;

-

-import android.view.SurfaceHolder;

-

-/**

- * This is the interface implemented by classes which provide video editing

- * functionality. The VideoEditor implementation class manages all input and

- * output files. Unless specifically mentioned, methods are blocking. A

- * typical editing session may consist of the following sequence of operations:

- *

- * <ul>

- *  <li>Add a set of MediaItems</li>

- *  <li>Apply a set of Transitions between MediaItems</li>

- *  <li>Add Effects and Overlays to media items</li>

- *  <li>Preview the movie at any time</li>

- *  <li>Save the VideoEditor implementation class internal state</li>

- *  <li>Release the VideoEditor implementation class instance by invoking

- * {@link #release()}

- * </ul>

- * The internal VideoEditor state consists of the following elements:

- * <ul>

- *  <li>Ordered & trimmed MediaItems</li>

- *  <li>Transition video clips</li>

- *  <li>Overlays</li>

- *  <li>Effects</li>

- *  <li>Audio waveform for the background audio and MediaItems</li>

- *  <li>Project thumbnail</li>

- *  <li>Last exported movie.</li>

- *  <li>Other project specific data such as the current aspect ratio.</li>

- * </ul>

- * {@hide}

- */

-public interface VideoEditor {

-    // The file name of the project thumbnail

-    public static final String THUMBNAIL_FILENAME = "thumbnail.jpg";

-

-    // Use this value instead of the specific end of the storyboard timeline

-    // value.

-    public final static int DURATION_OF_STORYBOARD = -1;

-

-    /**

-     * This listener interface is used by the VideoEditor to emit preview

-     * progress notifications. This callback should be invoked after the

-     * number of frames specified by

-     * {@link #startPreview(SurfaceHolder surfaceHolder, long fromMs,

-     *           int callbackAfterFrameCount, PreviewProgressListener listener)}

-     */

-    public interface PreviewProgressListener {

-        /**

-         * This method notifies the listener of the current time position while

-         * previewing a project.

-         *

-         * @param videoEditor The VideoEditor instance

-         * @param timeMs The current preview position (expressed in milliseconds

-         *            since the beginning of the storyboard timeline).

-         * @param end true if the end of the timeline was reached

-         */

-        public void onProgress(VideoEditor videoEditor, long timeMs, boolean end);

-    }

-

-    /**

-     * This listener interface is used by the VideoEditor to emit export status

-     * notifications.

-     * {@link #export(String filename, ExportProgressListener listener, int height, int bitrate)}

-     */

-    public interface ExportProgressListener {

-        /**

-         * This method notifies the listener of the progress status of a export

-         * operation.

-         *

-         * @param videoEditor The VideoEditor instance

-         * @param filename The name of the file which is in the process of being

-         *            exported.

-         * @param progress The progress in %. At the beginning of the export, this

-         *            value is set to 0; at the end, the value is set to 100.

-         */

-        public void onProgress(VideoEditor videoEditor, String filename, int progress);

-    }

-

-    /**

-     * This listener interface is used by the VideoEditor to emit export status

-     * notifications.

-     * {@link #generatePreview(MediaProcessingProgressListener listener)}

-     */

-    public interface MediaProcessingProgressListener {

-        // Values used for the action parameter

-        public static final int ACTION_ENCODE = 1;

-        public static final int ACTION_DECODE = 2;

-

-        /**

-         * This method notifies the listener of the progress status of

-         * processing a media object such as a Transition, AudioTrack or a

-         * media image item (when Ken Burns effect is applied).

-         * This method may be called maximum 100 times for one operation.

-         *

-         * @param object The object that is being processed such as a

-         *          Transition or AudioTrack

-         * @param action The type of processing being performed

-         * @param progress The progress in %. At the beginning of the operation,

-         *          this value is set to 0; at the end, the value is set to 100.

-         */

-        public void onProgress(Object item, int action, int progress);

-    }

-

-    /**

-     * @return The path where the VideoEditor stores all files related to the

-     * project

-     */

-    public String getPath();

-

-    /**

-     * This method releases all in-memory resources used by the VideoEditor

-     * instance. All pending operations such as preview, export and extract

-     * audio waveform must be canceled.

-     */

-    public void release();

-

-    /**

-     * Persist the current internal state of VideoEditor to the project path.

-     * The VideoEditor state may be restored by invoking the

-     * {@link VideoEditorFactory#load(String)} method. This method does not

-     * release the internal in-memory state of the VideoEditor. To release

-     * the in-memory state of the VideoEditor the {@link #release()} method

-     * must be invoked.

-     *

-     * Pending transition generations must be allowed to complete before the

-     * state is saved.

-     * Pending audio waveform generations must be allowed to complete.

-     * Pending export operations must be allowed to continue.

-     */

-    public void save() throws IOException;

-

-    /**

-     * Create the output movie based on all media items added and the applied

-     * storyboard items. This method can take a long time to execute and is

-     * blocking. The application will receive progress notifications via the

-     * ExportProgressListener. Specific implementations may not support multiple

-     * simultaneous export operations. Note that invoking methods which would

-     * change the contents of the output movie throw an IllegalStateException

-     * while an export operation is pending.

-     *

-     * The audio and video codecs are automatically selected by the underlying

-     * implementation.

-     *

-     * @param filename The output file name (including the full path)

-     * @param height The height of the output video file. The supported values

-     *            for height are described in the MediaProperties class, for

-     *            example: HEIGHT_480. The width will be automatically computed

-     *            according to the aspect ratio provided by

-     *            {@link #setAspectRatio(int)}

-     * @param bitrate The bitrate of the output video file. This is approximate

-     *            value for the output movie. Supported bitrate values are

-     *            described in the MediaProperties class for example:

-     *            BITRATE_384K

-     * @param listener The listener for progress notifications. Use null if

-     *            export progress notifications are not needed.

-     * @throws IllegalArgumentException if height or bitrate are not supported

-     *             or if the audio or video codecs are not supported

-     * @throws IOException if output file cannot be created

-     * @throws IllegalStateException if a preview or an export is in progress or

-     *             if no MediaItem has been added

-     * @throws CancellationException if export is canceled by calling

-     *             {@link #cancelExport()}

-     * @throws UnsupportOperationException if multiple simultaneous export() are

-     *             not allowed

-     */

-    public void export(String filename, int height, int bitrate, ExportProgressListener listener)

-            throws IOException;

-

-    /**

-     * Create the output movie based on all media items added and the applied

-     * storyboard items. This method can take a long time to execute and is

-     * blocking. The application will receive progress notifications via the

-     * ExportProgressListener. Specific implementations may not support multiple

-     * simultaneous export operations. Note that invoking methods which would

-     * change the contents of the output movie throw an IllegalStateException

-     * while an export operation is pending.

-     *

-     * @param filename The output file name (including the full path)

-     * @param height The height of the output video file. The supported values

-     *            for height are described in the MediaProperties class, for

-     *            example: HEIGHT_480. The width will be automatically computed

-     *            according to the aspect ratio provided by

-     *            {@link #setAspectRatio(int)}

-     * @param bitrate The bitrate of the output video file. This is approximate

-     *            value for the output movie. Supported bitrate values are

-     *            described in the MediaProperties class for example:

-     *            BITRATE_384K

-     * @param audioCodec The audio codec to be used for the export. The audio

-     *            codec values are defined in the MediaProperties class (e.g.

-     *            ACODEC_AAC_LC). Note that not all audio codec types are

-     *            supported for export purposes.

-     * @param videoCodec The video codec to be used for the export. The video

-     *            codec values are defined in the MediaProperties class (e.g.

-     *            VCODEC_H264BP). Note that not all video codec types are

-     *            supported for export purposes.

-     * @param listener The listener for progress notifications. Use null if

-     *            export progress notifications are not needed.

-     * @throws IllegalArgumentException if height or bitrate are not supported

-     *             or if the audio or video codecs are not supported

-     * @throws IOException if output file cannot be created

-     * @throws IllegalStateException if a preview or an export is in progress or

-     *             if no MediaItem has been added

-     * @throws CancellationException if export is canceled by calling

-     *             {@link #cancelExport()}

-     * @throws UnsupportOperationException if multiple simultaneous export() are

-     *             not allowed

-     */

-    public void export(String filename, int height, int bitrate, int audioCodec, int videoCodec,

-            ExportProgressListener listener) throws IOException;

-

-    /**

-     * Cancel the running export operation. This method blocks until the

-     * export is canceled and the exported file (if any) is deleted. If the

-     * export completed by the time this method is invoked, the export file

-     * will be deleted.

-     *

-     * @param filename The filename which identifies the export operation to be

-     *            canceled.

-     **/

-    public void cancelExport(String filename);

-

-    /**

-     * Add a media item at the end of the storyboard.

-     *

-     * @param mediaItem The media item object to add

-     * @throws IllegalStateException if a preview or an export is in progress or

-     *             if the media item id is not unique across all the media items

-     *             added.

-     */

-    public void addMediaItem(MediaItem mediaItem);

-

-    /**

-     * Insert a media item after the media item with the specified id.

-     *

-     * @param mediaItem The media item object to insert

-     * @param afterMediaItemId Insert the mediaItem after the media item

-     *            identified by this id. If this parameter is null, the media

-     *            item is inserted at the beginning of the timeline.

-     *

-     * @throws IllegalStateException if a preview or an export is in progress

-     * @throws IllegalArgumentException if media item with the specified id does

-     *             not exist (null is a valid value) or if the media item id is

-     *             not unique across all the media items added.

-     */

-    public void insertMediaItem(MediaItem mediaItem, String afterMediaItemId);

-

-    /**

-     * Move a media item after the media item with the specified id.

-     *

-     * Note: The project thumbnail is regenerated if the media item is or

-     * becomes the first media item in the storyboard timeline.

-     *

-     * @param mediaItemId The id of the media item to move

-     * @param afterMediaItemId Move the media item identified by mediaItemId after

-     *          the media item identified by this parameter. If this parameter

-     *          is null, the media item is moved at the beginning of the

-     *          timeline.

-     *

-     * @throws IllegalStateException if a preview or an export is in progress

-     * @throws IllegalArgumentException if one of media item ids is invalid

-     *          (null is a valid value)

-     */

-    public void moveMediaItem(String mediaItemId, String afterMediaItemId);

-

-    /**

-     * Remove the media item with the specified id. If there are transitions

-     * before or after this media item, then this/these transition(s) are

-     * removed from the storyboard. If the extraction of the audio waveform is

-     * in progress, the extraction is canceled and the file is deleted.

-     *

-     * Effects and overlays associated with the media item will also be

-     * removed.

-     *

-     * Note: The project thumbnail is regenerated if the media item which

-     * is removed is the first media item in the storyboard or if the

-     * media item is the only one in the storyboard. If the

-     * media item is the only one in the storyboard, the project thumbnail

-     * will be set to a black frame and the aspect ratio will revert to the

-     * default aspect ratio, and this method is equivalent to

-     * removeAllMediaItems() in this case.

-     *

-     * @param mediaItemId The unique id of the media item to be removed

-     *

-     * @return The media item that was removed

-     *

-     * @throws IllegalStateException if a preview or an export is in progress

-     * @throws IllegalArgumentException if media item with the specified id

-     *          does not exist

-     */

-    public MediaItem removeMediaItem(String mediaItemId);

-

-    /**

-     * Remove all media items in the storyboard. All effects, overlays and all

-     * transitions are also removed.

-     *

-     * Note: The project thumbnail will be set to a black frame and the aspect

-     * ratio will revert to the default aspect ratio.

-     *

-     * @throws IllegalStateException if a preview or an export is in progress

-     */

-    public void removeAllMediaItems();

-

-    /**

-     * Get the list of media items in the order in which it they appear in the

-     * storyboard timeline.

-     *

-     * Note that if any media item source files are no longer

-     * accessible, this method will still provide the full list of media items.

-     *

-     * @return The list of media items. If no media item exist an empty list

-     *          will be returned.

-     */

-    public List<MediaItem> getAllMediaItems();

-

-    /**

-     * Find the media item with the specified id

-     *

-     * @param mediaItemId The media item id

-     *

-     * @return The media item with the specified id (null if it does not exist)

-     */

-    public MediaItem getMediaItem(String mediaItemId);

-

-    /**

-     * Add a transition between the media items specified by the transition.

-     * If a transition existed at the same position it is invalidated and then

-     * the transition is replaced. Note that the new transition video clip is

-     * not automatically generated by this method. The

-     * {@link Transition#generate()} method must be invoked to generate

-     * the transition video clip.

-     *

-     * Note that the TransitionAtEnd and TransitionAtStart are special kinds

-     * that can not be applied between two media items.

-     *

-     * A crossfade audio transition will be automatically applied regardless of

-     * the video transition.

-     *

-     * @param transition The transition to apply

-     *

-     * @throws IllegalStateException if a preview or an export is in progress

-     * @throws IllegalArgumentException if the transition duration is larger

-     *              than the smallest duration of the two media item files or

-     *              if the two media items specified in the transition are not

-     *              adjacent

-     */

-    public void addTransition(Transition transition);

-

-    /**

-     * Remove the transition with the specified id.

-     *

-     * @param transitionId The id of the transition to be removed

-     *

-     * @return The transition that was removed

-     * @throws IllegalStateException if a preview or an export is in progress

-     * @throws IllegalArgumentException if transition with the specified id does

-     *             not exist

-     */

-    public Transition removeTransition(String transitionId);

-

-    /**

-     * Get the list of transitions

-     *

-     * @return The list of transitions. If no transitions exist an empty list

-     *  will be returned.

-     */

-    public List<Transition> getAllTransitions();

-

-    /**

-     * Find the transition with the specified transition id.

-     *

-     * @param transitionId The transition id

-     *

-     * @return The transition

-     */

-    public Transition getTransition(String transitionId);

-

-    /**

-     * Add the specified AudioTrack to the storyboard. Note: Specific

-     * implementations may support a limited number of audio tracks (e.g. only

-     * one audio track)

-     *

-     * @param audioTrack The AudioTrack to add

-     * @throws UnsupportedOperationException if the implementation supports a

-     *             limited number of audio tracks.

-     * @throws IllegalArgumentException if media item is not unique across all

-     *             the audio tracks already added.

-     */

-    public void addAudioTrack(AudioTrack audioTrack);

-

-    /**

-     * Insert an audio track after the audio track with the specified id. Use

-     * addAudioTrack to add an audio track at the end of the storyboard

-     * timeline.

-     *

-     * @param audioTrack The audio track object to insert

-     * @param afterAudioTrackId Insert the audio track after the audio track

-     *            identified by this parameter. If this parameter is null the

-     *            audio track is added at the beginning of the timeline.

-     * @throws IllegalStateException if a preview or an export is in progress

-     * @throws IllegalArgumentException if media item with the specified id does

-     *             not exist (null is a valid value). if media item is not

-     *             unique across all the audio tracks already added.

-     * @throws UnsupportedOperationException if the implementation supports a

-     *             limited number of audio tracks

-     */

-    public void insertAudioTrack(AudioTrack audioTrack, String afterAudioTrackId);

-

-    /**

-     * Move an AudioTrack after the AudioTrack with the specified id.

-     *

-     * @param audioTrackId The id of the AudioTrack to move

-     * @param afterAudioTrackId Move the AudioTrack identified by audioTrackId

-     *            after the AudioTrack identified by this parameter. If this

-     *            parameter is null the audio track is added at the beginning of

-     *            the timeline.

-     * @throws IllegalStateException if a preview or an export is in progress

-     * @throws IllegalArgumentException if one of media item ids is invalid

-     *             (null is a valid value)

-     */

-    public void moveAudioTrack(String audioTrackId, String afterAudioTrackId);

-

-    /**

-     * Remove the audio track with the specified id. If the extraction of the

-     * audio waveform is in progress, the extraction is canceled and the file is

-     * deleted.

-     *

-     * @param audioTrackId The id of the audio track to be removed

-     *

-     * @return The audio track that was removed

-     * @throws IllegalStateException if a preview or an export is in progress

-     */

-    public AudioTrack removeAudioTrack(String audioTrackId);

-

-    /**

-     * Get the list of AudioTracks in order in which they appear in the storyboard.

-     *

-     * Note that if any AudioTrack source files are not accessible anymore,

-     * this method will still provide the full list of audio tracks.

-     *

-     * @return The list of AudioTracks. If no audio tracks exist an empty list

-     *  will be returned.

-     */

-    public List<AudioTrack> getAllAudioTracks();

-

-    /**

-     * Find the AudioTrack with the specified id

-     *

-     * @param audioTrackId The AudioTrack id

-     *

-     * @return The AudioTrack with the specified id (null if it does not exist)

-     */

-    public AudioTrack getAudioTrack(String audioTrackId);

-

-    /**

-     * Set the aspect ratio used in the preview and the export movie.

-     *

-     * The default aspect ratio is ASPECTRATIO_16_9 (16:9).

-     *

-     * @param aspectRatio to apply. If aspectRatio is the same as the current

-     *            aspect ratio, then this function just returns. The supported

-     *            aspect ratio are defined in the MediaProperties class for

-     *            example: ASPECTRATIO_16_9

-     *

-     * @throws IllegalStateException if a preview or an export is in progress

-     * @throws IllegalArgumentException if aspect ratio is not supported

-     */

-    public void setAspectRatio(int aspectRatio);

-

-    /**

-     * Get current aspect ratio.

-     *

-     * @return The aspect ratio as described in MediaProperties

-     */

-    public int getAspectRatio();

-

-    /**

-     * Get the preview (and output movie) duration.

-     *

-     * @return The duration of the preview (and output movie)

-     */

-    public long getDuration();

-

-    /**

-     * Render a frame according to the preview aspect ratio and activating all

-     * storyboard items relative to the specified time.

-     *

-     * @param surfaceHolder SurfaceHolder used by the application

-     * @param timeMs time corresponding to the frame to display

-     *

-     * @return The accurate time stamp of the frame that is rendered

-     * .

-     * @throws IllegalStateException if a preview or an export is already

-     *             in progress

-     * @throws IllegalArgumentException if time is negative or beyond the

-     *             preview duration

-     */

-    public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs);

-

-    /**

-     * This method must be called after the aspect ratio of the project changes

-     * and before startPreview is called. Note that this method may block for

-     * an extensive period of time.

-     *

-     * @param listener The listener interface which will be used to notify

-     *  the caller of the progress of each storyboard item being processed.

-     */

-    public void generatePreview(MediaProcessingProgressListener listener);

-

-    /**

-     * Start the preview of all the storyboard items applied on all MediaItems

-     * This method does not block (does not wait for the preview to complete).

-     * The PreviewProgressListener allows to track the progress at the time

-     * interval determined by the callbackAfterFrameCount parameter. The

-     * SurfaceHolder has to be created and ready for use before calling this

-     * method. The method is a no-op if there are no MediaItems in the

-     * storyboard.

-     *

-     * @param surfaceHolder SurfaceHolder where the preview is rendered.

-     * @param fromMs The time (relative to the timeline) at which the preview

-     *            will start

-     * @param toMs The time (relative to the timeline) at which the preview will

-     *            stop. Use -1 to play to the end of the timeline

-     * @param loop true if the preview should be looped once it reaches the end

-     * @param callbackAfterFrameCount The listener interface should be invoked

-     *            after the number of frames specified by this parameter.

-     * @param listener The listener which will be notified of the preview

-     *            progress

-     * @throws IllegalArgumentException if fromMs is beyond the preview duration

-     * @throws IllegalStateException if a preview or an export is already in

-     *             progress

-     */

-    public void startPreview(SurfaceHolder surfaceHolder, long fromMs, long toMs, boolean loop,

-            int callbackAfterFrameCount, PreviewProgressListener listener);

-

-    /**

-     * Stop the current preview. This method blocks until ongoing preview is

-     * stopped. Ignored if there is no preview running.

-     *

-     * @return The accurate current time when stop is effective expressed in

-     *          milliseconds

-     */

-    public long stopPreview();

-}

+/*
+ * 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.
+ */
+
+
+package android.media.videoeditor;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.CancellationException;
+
+import android.view.SurfaceHolder;
+
+/**
+ * This is the interface implemented by classes which provide video editing
+ * functionality. The VideoEditor implementation class manages all input and
+ * output files. Unless specifically mentioned, methods are blocking. A typical
+ * editing session may consist of the following sequence of operations:
+ *
+ * <ul>
+ *  <li>Add a set of MediaItems</li>
+ *  <li>Apply a set of Transitions between MediaItems</li>
+ *  <li>Add Effects and Overlays to media items</li>
+ *  <li>Preview the movie at any time</li>
+ *  <li>Save the VideoEditor implementation class internal state</li>
+ *  <li>Release the VideoEditor implementation class instance by invoking
+ * {@link #release()}
+ * </ul>
+ * The internal VideoEditor state consists of the following elements:
+ * <ul>
+ *  <li>Ordered & trimmed MediaItems</li>
+ *  <li>Transition video clips</li>
+ *  <li>Overlays</li>
+ *  <li>Effects</li>
+ *  <li>Audio waveform for the background audio and MediaItems</li>
+ *  <li>Project thumbnail</li>
+ *  <li>Last exported movie.</li>
+ *  <li>Other project specific data such as the current aspect ratio.</li>
+ * </ul>
+ * {@hide}
+ */
+public interface VideoEditor {
+    /**
+     *  The file name of the project thumbnail
+     */
+    public static final String THUMBNAIL_FILENAME = "thumbnail.jpg";
+
+    /**
+     *  Use this value instead of the specific end of the storyboard timeline
+     *  value.
+     */
+    public final static int DURATION_OF_STORYBOARD = -1;
+
+    /**
+     * This listener interface is used by the VideoEditor to emit preview
+     * progress notifications. This callback should be invoked after the number
+     * of frames specified by
+     * {@link #startPreview(SurfaceHolder surfaceHolder, long fromMs,
+     *           int callbackAfterFrameCount, PreviewProgressListener listener)}
+     */
+    public interface PreviewProgressListener {
+        /**
+         * This method notifies the listener of the current time position while
+         * previewing a project.
+         *
+         * @param videoEditor The VideoEditor instance
+         * @param timeMs The current preview position (expressed in milliseconds
+         *        since the beginning of the storyboard timeline).
+         * @param end true if the end of the timeline was reached
+         */
+        public void onProgress(VideoEditor videoEditor, long timeMs, boolean end);
+    }
+
+    /**
+     * This listener interface is used by the VideoEditor to emit export status
+     * notifications.
+     * {@link #export(String filename, ExportProgressListener listener,
+     *                int height, int bitrate)}
+     */
+    public interface ExportProgressListener {
+        /**
+         * This method notifies the listener of the progress status of a export
+         * operation.
+         *
+         * @param videoEditor The VideoEditor instance
+         * @param filename The name of the file which is in the process of being
+         *        exported.
+         * @param progress The progress in %. At the beginning of the export,
+         *        this value is set to 0; at the end, the value is set to 100.
+         */
+        public void onProgress(VideoEditor videoEditor, String filename,
+                              int progress);
+    }
+
+    public interface MediaProcessingProgressListener {
+        /**
+         *  Values used for the action parameter
+         */
+        public static final int ACTION_ENCODE = 1;
+        public static final int ACTION_DECODE = 2;
+
+        /**
+         * This method notifies the listener of the progress status of
+         * processing a media object such as a Transition, AudioTrack & Kenburns
+         * This method may be called maximum 100 times for one operation.
+         *
+         * @param object The object that is being processed such as a Transition
+         *               or AudioTrack
+         * @param action The type of processing being performed
+         * @param progress The progress in %. At the beginning of the operation,
+         *          this value is set to 0; at the end, the value is set to 100.
+         */
+        public void onProgress(Object item, int action, int progress);
+    }
+
+    /**
+     * @return The path where the VideoEditor stores all files related to the
+     *         project
+     */
+    public String getPath();
+
+    /**
+     * This method releases all in-memory resources used by the VideoEditor
+     * instance. All pending operations such as preview, export and extract
+     * audio waveform must be canceled.
+     */
+    public void release();
+
+    /**
+     * Persist the current internal state of VideoEditor to the project path.
+     * The VideoEditor state may be restored by invoking the
+     * {@link VideoEditorFactory#load(String)} method. This method does not
+     * release the internal in-memory state of the VideoEditor. To release
+     * the in-memory state of the VideoEditor the {@link #release()} method
+     * must be invoked.
+     *
+     * Pending transition generations must be allowed to complete before the
+     * state is saved.
+     * Pending audio waveform generations must be allowed to complete.
+     * Pending export operations must be allowed to continue.
+     *
+     * @throws IOException if the internal state cannot be saved to project file
+     */
+    public void save() throws IOException;
+
+    /**
+     * Create the output movie based on all media items added and the applied
+     * storyboard items. This method can take a long time to execute and is
+     * blocking. The application will receive progress notifications via the
+     * ExportProgressListener. Specific implementations may not support multiple
+     * simultaneous export operations. Note that invoking methods which would
+     * change the contents of the output movie throw an IllegalStateException
+     * while an export operation is pending.
+     *
+     * The audio and video codecs are automatically selected by the underlying
+     * implementation.
+     *
+     * @param filename The output file name (including the full path)
+     * @param height The height of the output video file. The supported values
+     *        for height are described in the MediaProperties class, for
+     *        example: HEIGHT_480. The width will be automatically computed
+     *        according to the aspect ratio provided by
+     *        {@link #setAspectRatio(int)}
+     * @param bitrate The bitrate of the output video file. This is approximate
+     *        value for the output movie. Supported bitrate values are
+     *        described in the MediaProperties class for example: BITRATE_384K
+     * @param listener The listener for progress notifications. Use null if
+     *        export progress notifications are not needed.
+     *
+     * @throws IllegalArgumentException if height or bitrate are not supported
+     *        or if the audio or video codecs are not supported
+     * @throws IOException if output file cannot be created
+     * @throws IllegalStateException if a preview or an export is in progress or
+     *        if no MediaItem has been added
+     * @throws CancellationException if export is canceled by calling
+     *        {@link #cancelExport()}
+     * @throws UnsupportOperationException if multiple simultaneous export() are
+     *        not allowed
+     */
+    public void export(String filename, int height, int bitrate,
+                       ExportProgressListener listener)
+    throws IOException;
+
+    /**
+     * Create the output movie based on all media items added and the applied
+     * storyboard items. This method can take a long time to execute and is
+     * blocking. The application will receive progress notifications via the
+     * ExportProgressListener. Specific implementations may not support multiple
+     * simultaneous export operations. Note that invoking methods which would
+     * change the contents of the output movie throw an IllegalStateException
+     * while an export operation is pending.
+     *
+     * @param filename The output file name (including the full path)
+     * @param height The height of the output video file. The supported values
+     *        for height are described in the MediaProperties class, for
+     *        example: HEIGHT_480. The width will be automatically computed
+     *        according to the aspect ratio provided by
+     *        {@link #setAspectRatio(int)}
+     * @param bitrate The bitrate of the output video file. This is approximate
+     *        value for the output movie. Supported bitrate values are
+     *        described in the MediaProperties class for example: BITRATE_384K
+     * @param audioCodec The audio codec to be used for the export. The audio
+     *        codec values are defined in the MediaProperties class (e.g.
+     *        ACODEC_AAC_LC). Note that not all audio codec types are
+     *        supported for export purposes.
+     * @param videoCodec The video codec to be used for the export. The video
+     *        codec values are defined in the MediaProperties class (e.g.
+     *        VCODEC_H264BP). Note that not all video codec types are
+     *        supported for export purposes.
+     * @param listener The listener for progress notifications. Use null if
+     *        export progress notifications are not needed.
+     *
+     * @throws IllegalArgumentException if height or bitrate are not supported
+     *        or if the audio or video codecs are not supported
+     * @throws IOException if output file cannot be created
+     * @throws IllegalStateException if a preview or an export is in progress or
+     *        if no MediaItem has been added
+     * @throws CancellationException if export is cancelled by calling
+     *        {@link #cancelExport()}
+     * @throws UnsupportOperationException if multiple simultaneous export() are
+     *        not allowed
+     */
+    public void export(String filename, int height, int bitrate, int audioCodec,
+                       int videoCodec, ExportProgressListener listener)
+                           throws IOException;
+
+    /**
+     * Cancel the running export operation. This method blocks until the export
+     * is cancelled and the exported file (if any) is deleted. If the export
+     * completed by the time this method is invoked, the export file will be
+     * deleted.
+     *
+     * @param filename The filename which identifies the export operation to be
+     *            canceled.
+     **/
+    public void cancelExport(String filename);
+
+    /**
+     * Add a media item at the end of the storyboard.
+     *
+     * @param mediaItem The media item object to add
+     *
+     * @throws IllegalStateException if a preview or an export is in progress or
+     *        if the media item id is not unique across all the media items
+     *        added.
+     */
+    public void addMediaItem(MediaItem mediaItem);
+
+    /**
+     * Insert a media item after the media item with the specified id.
+     *
+     * @param mediaItem The media item object to insert
+     * @param afterMediaItemId Insert the mediaItem after the media item
+     *        identified by this id. If this parameter is null, the media
+     *        item is inserted at the beginning of the timeline.
+     *
+     * @throws IllegalStateException if a preview or an export is in progress
+     * @throws IllegalArgumentException if media item with the specified id does
+     *        not exist (null is a valid value) or if the media item id is
+     *        not unique across all the media items added.
+     */
+    public void insertMediaItem(MediaItem mediaItem, String afterMediaItemId);
+
+    /**
+     * Move a media item after the media item with the specified id.
+     *
+     * Note: The project thumbnail is regenerated if the media item is or
+     * becomes the first media item in the storyboard timeline.
+     *
+     * @param mediaItemId The id of the media item to move
+     * @param afterMediaItemId Move the media item identified by mediaItemId
+     *        after the media item identified by this parameter. If this
+     *        parameter is null, the media item is moved at the beginning of
+     *        the timeline.
+     *
+     * @throws IllegalStateException if a preview or an export is in progress
+     * @throws IllegalArgumentException if one of media item ids is invalid
+     *        (null is a valid value)
+     */
+    public void moveMediaItem(String mediaItemId, String afterMediaItemId);
+
+    /**
+     * Remove the media item with the specified id. If there are transitions
+     * before or after this media item, then this/these transition(s) are
+     * removed from the storyboard. If the extraction of the audio waveform is
+     * in progress, the extraction is canceled and the file is deleted.
+     *
+     * Effects and overlays associated with the media item will also be removed.
+     *
+     * Note: The project thumbnail is regenerated if the media item which is
+     * removed is the first media item in the storyboard or if the media item is
+     * the only one in the storyboard. If the media item is the only one in the
+     * storyboard, the project thumbnail will be set to a black frame and the
+     * aspect ratio will revert to the default aspect ratio and this method is
+     * equivalent to removeAllMediaItems() in this case.
+     *
+     * @param mediaItemId The unique id of the media item to be removed
+     *
+     * @return The media item that was removed
+     *
+     * @throws IllegalStateException if a preview or an export is in progress
+     * @throws IllegalArgumentException if media item with the specified id does
+     *        not exist
+     */
+    public MediaItem removeMediaItem(String mediaItemId);
+
+    /**
+     * Remove all media items in the storyboard. All effects, overlays and all
+     * transitions are also removed.
+     *
+     * Note: The project thumbnail will be set to a black frame and the aspect
+     * ratio will revert to the default aspect ratio.
+     *
+     * @throws IllegalStateException if a preview or an export is in progress
+     */
+    public void removeAllMediaItems();
+
+    /**
+     * Get the list of media items in the order in which it they appear in the
+     * storyboard timeline.
+     *
+     * Note that if any media item source files are no longer
+     * accessible, this method will still provide the full list of media items.
+     *
+     * @return The list of media items. If no media item exist an empty list
+     *        will be returned.
+     */
+    public List<MediaItem> getAllMediaItems();
+
+    /**
+     * Find the media item with the specified id
+     *
+     * @param mediaItemId The media item id
+     *
+     * @return The media item with the specified id (null if it does not exist)
+     */
+    public MediaItem getMediaItem(String mediaItemId);
+
+    /**
+     * Add a transition between the media items specified by the transition.
+     * If a transition existed at the same position it is invalidated and then
+     * the transition is replaced. Note that the new transition video clip is
+     * not automatically generated by this method. The
+     * {@link Transition#generate()} method must be invoked to generate
+     * the transition video clip.
+     *
+     * Note that the TransitionAtEnd and TransitionAtStart are special kinds
+     * that can not be applied between two media items.
+     *
+     * A crossfade audio transition will be automatically applied regardless of
+     * the video transition.
+     *
+     * @param transition The transition to apply
+     *
+     * @throws IllegalStateException if a preview or an export is in progress
+     * @throws IllegalArgumentException if the transition duration is larger
+     *        than the smallest duration of the two media item files or if
+     *        the two media items specified in the transition are not
+     *        adjacent
+     */
+    public void addTransition(Transition transition);
+
+    /**
+     * Remove the transition with the specified id.
+     *
+     * @param transitionId The id of the transition to be removed
+     *
+     * @return The transition that was removed
+     *
+     * @throws IllegalStateException if a preview or an export is in progress
+     * @throws IllegalArgumentException if transition with the specified id does
+     *        not exist
+     */
+    public Transition removeTransition(String transitionId);
+
+    /**
+     * Get the list of transitions
+     *
+     * @return The list of transitions. If no transitions exist an empty list
+     *        will be returned.
+     */
+    public List<Transition> getAllTransitions();
+
+    /**
+     * Find the transition with the specified transition id.
+     *
+     * @param transitionId The transition id
+     *
+     * @return The transition
+     */
+    public Transition getTransition(String transitionId);
+
+    /**
+     * Add the specified AudioTrack to the storyboard. Note: Specific
+     * implementations may support a limited number of audio tracks (e.g. only
+     * one audio track)
+     *
+     * @param audioTrack The AudioTrack to add
+     *
+     * @throws UnsupportedOperationException if the implementation supports a
+     *        limited number of audio tracks.
+     * @throws IllegalArgumentException if media item is not unique across all
+     *        the audio tracks already added.
+     */
+    public void addAudioTrack(AudioTrack audioTrack);
+
+    /**
+     * Insert an audio track after the audio track with the specified id. Use
+     * addAudioTrack to add an audio track at the end of the storyboard
+     * timeline.
+     *
+     * @param audioTrack The audio track object to insert
+     * @param afterAudioTrackId Insert the audio track after the audio track
+     *        identified by this parameter. If this parameter is null the
+     *        audio track is added at the beginning of the timeline.
+     *
+     * @throws IllegalStateException if a preview or an export is in progress
+     * @throws IllegalArgumentException if media item with the specified id does
+     *        not exist (null is a valid value). if media item is not unique
+     *        across all the audio tracks already added.
+     * @throws UnsupportedOperationException if the implementation supports a
+     *        limited number of audio tracks
+     */
+    public void insertAudioTrack(AudioTrack audioTrack, String afterAudioTrackId);
+
+    /**
+     * Move an AudioTrack after the AudioTrack with the specified id.
+     *
+     * @param audioTrackId The id of the AudioTrack to move
+     * @param afterAudioTrackId Move the AudioTrack identified by audioTrackId
+     *        after the AudioTrack identified by this parameter. If this
+     *        parameter is null the audio track is added at the beginning of
+     *        the timeline.
+     *
+     * @throws IllegalStateException if a preview or an export is in progress
+     * @throws IllegalArgumentException if one of media item ids is invalid
+     *        (null is a valid value)
+     */
+    public void moveAudioTrack(String audioTrackId, String afterAudioTrackId);
+
+    /**
+     * Remove the audio track with the specified id. If the extraction of the
+     * audio waveform is in progress, the extraction is canceled and the file is
+     * deleted.
+     *
+     * @param audioTrackId The id of the audio track to be removed
+     *
+     * @return The audio track that was removed
+     * @throws IllegalStateException if a preview or an export is in progress
+     */
+    public AudioTrack removeAudioTrack(String audioTrackId);
+
+    /**
+     * Get the list of AudioTracks in order in which they appear in the
+     * storyboard.
+     *
+     * Note that if any AudioTrack source files are not accessible anymore,
+     * this method will still provide the full list of audio tracks.
+     *
+     * @return The list of AudioTracks. If no audio tracks exist an empty list
+     *        will be returned.
+     */
+    public List<AudioTrack> getAllAudioTracks();
+
+    /**
+     * Find the AudioTrack with the specified id
+     *
+     * @param audioTrackId The AudioTrack id
+     *
+     * @return The AudioTrack with the specified id (null if it does not exist)
+     */
+    public AudioTrack getAudioTrack(String audioTrackId);
+
+    /**
+     * Set the aspect ratio used in the preview and the export movie.
+     *
+     * The default aspect ratio is ASPECTRATIO_16_9 (16:9).
+     *
+     * @param aspectRatio to apply. If aspectRatio is the same as the current
+     *        aspect ratio, then this function just returns. The supported
+     *        aspect ratio are defined in the MediaProperties class for
+     *        example: ASPECTRATIO_16_9
+     *
+     * @throws IllegalStateException if a preview or an export is in progress
+     * @throws IllegalArgumentException if aspect ratio is not supported
+     */
+    public void setAspectRatio(int aspectRatio);
+
+    /**
+     * Get current aspect ratio.
+     *
+     * @return The aspect ratio as described in MediaProperties
+     */
+    public int getAspectRatio();
+
+    /**
+     * Get the preview (and output movie) duration.
+     *
+     * @return The duration of the preview (and output movie)
+     */
+    public long getDuration();
+
+    /**
+     * Render a frame according to the preview aspect ratio and activating all
+     * storyboard items relative to the specified time.
+     *
+     * @param surfaceHolder SurfaceHolder used by the application
+     * @param timeMs time corresponding to the frame to display
+     *
+     * @return The accurate time stamp of the frame that is rendered.
+     *
+     * @throws IllegalStateException if a preview or an export is already in
+     *        progress
+     * @throws IllegalArgumentException if time is negative or beyond the
+     *        preview duration
+     */
+    public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs);
+
+    /**
+     * This method must be called after any changes made to the storyboard
+     * and before startPreview is called. Note that this method may block for an
+     * extensive period of time.
+     */
+    public void generatePreview(MediaProcessingProgressListener listener);
+
+
+    /**
+     * Start the preview of all the storyboard items applied on all MediaItems
+     * This method does not block (does not wait for the preview to complete).
+     * The PreviewProgressListener allows to track the progress at the time
+     * interval determined by the callbackAfterFrameCount parameter. The
+     * SurfaceHolder has to be created and ready for use before calling this
+     * method. The method is a no-op if there are no MediaItems in the
+     * storyboard.
+     *
+     * @param surfaceHolder SurfaceHolder where the preview is rendered.
+     * @param fromMs The time (relative to the timeline) at which the preview
+     *        will start
+     * @param toMs The time (relative to the timeline) at which the preview will
+     *        stop. Use -1 to play to the end of the timeline
+     * @param loop true if the preview should be looped once it reaches the end
+     * @param callbackAfterFrameCount The listener interface should be invoked
+     *        after the number of frames specified by this parameter.
+     * @param listener The listener which will be notified of the preview
+     *        progress
+     *
+     * @throws IllegalArgumentException if fromMs is beyond the preview duration
+     * @throws IllegalStateException if a preview or an export is already in
+     *        progress
+     */
+    public void startPreview(SurfaceHolder surfaceHolder, long fromMs, long toMs,
+                             boolean loop,int callbackAfterFrameCount,
+                             PreviewProgressListener listener);
+
+    /**
+     * Stop the current preview. This method blocks until ongoing preview is
+     * stopped. Ignored if there is no preview running.
+     *
+     * @return The accurate current time when stop is effective expressed in
+     *        milliseconds
+     */
+    public long stopPreview();
+}
diff --git a/media/java/android/media/videoeditor/VideoEditorFactory.java b/media/java/android/media/videoeditor/VideoEditorFactory.java
index 85b2666..85c329f 100755
--- a/media/java/android/media/videoeditor/VideoEditorFactory.java
+++ b/media/java/android/media/videoeditor/VideoEditorFactory.java
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+
 package android.media.videoeditor;
 
 import java.io.File;
@@ -22,7 +23,6 @@
 
 import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
 
-
 /**
  * The VideoEditorFactory class must be used to instantiate VideoEditor objects
  * by creating a new project {@link #create(String)} or by loading an
@@ -43,14 +43,19 @@
      *             not be accessed in read/write mode
      */
     public static VideoEditor create(String projectPath) throws IOException {
-        // If the project path does not exist create it
+        /*
+         *  If the project path does not exist create it
+         */
         final File dir = new File(projectPath);
         if (!dir.exists()) {
             if (!dir.mkdirs()) {
-                throw new FileNotFoundException("Cannot create project path: " + projectPath);
+                throw new FileNotFoundException("Cannot create project path: "
+                                                                 + projectPath);
             } else {
-                // Create the file which hides the media files
-                // from the media scanner
+                /*
+                 * Create the file which hides the media files
+                 * from the media scanner
+                 */
                 if (!new File(dir, ".nomedia").createNewFile()) {
                     throw new FileNotFoundException("Cannot create file .nomedia");
                 }
@@ -69,7 +74,8 @@
      *            are stored. When a project is deleted the application is
      *            responsible for deleting the path and its contents.
      * @param generatePreview if set to true the
-     *      {@link MediaEditor#generatePreview(MediaProcessingProgressListener listener)}
+     *      {@link MediaEditor#generatePreview(MediaProcessingProgressListener
+     *             listener)}
      *      will be called internally to generate any needed transitions.
      *
      * @return The VideoEditor instance
@@ -79,7 +85,7 @@
      *             media files cannot be retrieved
      */
     public static VideoEditor load(String projectPath, boolean generatePreview)
-            throws IOException {
+        throws IOException {
         final VideoEditor videoEditor = new VideoEditorImpl(projectPath);
         if (generatePreview) {
             videoEditor.generatePreview(null);
diff --git a/media/java/android/media/videoeditor/VideoEditorImpl.java b/media/java/android/media/videoeditor/VideoEditorImpl.java
old mode 100644
new mode 100755
index 1a145e6..71c2624
--- a/media/java/android/media/videoeditor/VideoEditorImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorImpl.java
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+
 package android.media.videoeditor;
 
 import java.io.File;
@@ -26,6 +27,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Semaphore;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -34,19 +36,32 @@
 import android.graphics.Rect;
 import android.util.Log;
 import android.util.Xml;
+import android.view.Surface;
 import android.view.SurfaceHolder;
 
+import android.graphics.Bitmap;
+
 /**
  * The VideoEditor implementation {@hide}
  */
 public class VideoEditorImpl implements VideoEditor {
-    // Logging
+    /*
+     *  Logging
+     */
     private static final String TAG = "VideoEditorImpl";
 
-    // The project filename
+    /*
+     *  The project filename
+     */
     private static final String PROJECT_FILENAME = "videoeditor.xml";
+    /*
+     *  Semaphore to control preview calls
+     */
+    final Semaphore mPreviewSemaphore = new Semaphore(1, true);
 
-    // XML tags
+    /*
+     *  XML tags
+     */
     private static final String TAG_PROJECT = "project";
     private static final String TAG_MEDIA_ITEMS = "media_items";
     private static final String TAG_MEDIA_ITEM = "media_item";
@@ -54,7 +69,8 @@
     private static final String TAG_TRANSITION = "transition";
     private static final String TAG_OVERLAYS = "overlays";
     private static final String TAG_OVERLAY = "overlay";
-    private static final String TAG_OVERLAY_USER_ATTRIBUTES = "overlay_user_attributes";
+    private static final String TAG_OVERLAY_USER_ATTRIBUTES =
+                                                      "overlay_user_attributes";
     private static final String TAG_EFFECTS = "effects";
     private static final String TAG_EFFECT = "effect";
     private static final String TAG_AUDIO_TRACKS = "audio_tracks";
@@ -62,9 +78,11 @@
 
     private static final String ATTR_ID = "id";
     private static final String ATTR_FILENAME = "filename";
-    private static final String ATTR_AUDIO_WAVEFORM_FILENAME = "wavefoem";
+    private static final String ATTR_AUDIO_WAVEFORM_FILENAME = "waveform";
     private static final String ATTR_RENDERING_MODE = "rendering_mode";
     private static final String ATTR_ASPECT_RATIO = "aspect_ratio";
+    private static final String ATTR_PREVIEW_PREPARE = "preview_prepare_invalid";
+    private static final String ATTR_REGENERATE_PCM = "regeneratePCMFlag";
     private static final String ATTR_TYPE = "type";
     private static final String ATTR_DURATION = "duration";
     private static final String ATTR_START_TIME = "start_time";
@@ -80,156 +98,66 @@
     private static final String ATTR_AFTER_MEDIA_ITEM_ID = "after_media_item";
     private static final String ATTR_COLOR_EFFECT_TYPE = "color_type";
     private static final String ATTR_COLOR_EFFECT_VALUE = "color_value";
-    private static final String ATTR_START_RECT_L = "start_l";
-    private static final String ATTR_START_RECT_T = "start_t";
-    private static final String ATTR_START_RECT_R = "start_r";
-    private static final String ATTR_START_RECT_B = "start_b";
-    private static final String ATTR_END_RECT_L = "end_l";
-    private static final String ATTR_END_RECT_T = "end_t";
-    private static final String ATTR_END_RECT_R = "end_r";
-    private static final String ATTR_END_RECT_B = "end_b";
+    private static final String ATTR_START_RECT_LEFT = "start_l";
+    private static final String ATTR_START_RECT_TOP = "start_t";
+    private static final String ATTR_START_RECT_RIGHT = "start_r";
+    private static final String ATTR_START_RECT_BOTTOM = "start_b";
+    private static final String ATTR_END_RECT_LEFT = "end_l";
+    private static final String ATTR_END_RECT_TOP = "end_t";
+    private static final String ATTR_END_RECT_RIGHT = "end_r";
+    private static final String ATTR_END_RECT_BOTTOM = "end_b";
     private static final String ATTR_LOOP = "loop";
     private static final String ATTR_MUTED = "muted";
     private static final String ATTR_DUCK_ENABLED = "ducking_enabled";
     private static final String ATTR_DUCK_THRESHOLD = "ducking_threshold";
     private static final String ATTR_DUCKED_TRACK_VOLUME = "ducking_volume";
+    private static final String ATTR_GENERATED_IMAGE_CLIP =
+                                                         "generated_image_clip";
+    private static final String ATTR_GENERATED_TRANSITION_CLIP =
+                                                    "generated_transition_clip";
+    private static final String ATTR_IS_TRANSITION_GENERATED =
+                                                      "is_transition_generated";
+    private static final String ATTR_OVERLAY_RGB_FILENAME =
+                                                         "overlay_rgb_filename";
+    private static final String ATTR_OVERLAY_FRAME_WIDTH =
+                                                          "overlay_frame_width";
+    private static final String ATTR_OVERLAY_FRAME_HEIGHT =
+                                                         "overlay_frame_height";
 
-    // Instance variables
+    /*
+     *  Instance variables
+     */
     private long mDurationMs;
     private final String mProjectPath;
     private final List<MediaItem> mMediaItems = new ArrayList<MediaItem>();
     private final List<AudioTrack> mAudioTracks = new ArrayList<AudioTrack>();
     private final List<Transition> mTransitions = new ArrayList<Transition>();
-    private PreviewThread mPreviewThread;
     private int mAspectRatio;
 
-    /**
-     * The preview thread
+    /*
+     * Private Object for calling native Methods via MediaArtistNativeHelper
      */
-    private class PreviewThread extends Thread {
-        // Instance variables
-        private final static long FRAME_DURATION = 33;
-
-        // Instance variables
-        private final PreviewProgressListener mListener;
-        private final int mCallbackAfterFrameCount;
-        private final long mFromMs, mToMs;
-        private boolean mRun, mLoop;
-        private long mPositionMs;
-
-        /**
-         * Constructor
-         *
-         * @param fromMs Start preview at this position
-         * @param toMs The time (relative to the timeline) at which the preview
-         *            will stop. Use -1 to play to the end of the timeline
-         * @param callbackAfterFrameCount The listener interface should be
-         *            invoked after the number of frames specified by this
-         *            parameter.
-         * @param loop true if the preview should be looped once it reaches the
-         *            end
-         * @param listener The listener
-         */
-        public PreviewThread(long fromMs, long toMs, boolean loop, int callbackAfterFrameCount,
-                PreviewProgressListener listener) {
-            mPositionMs = mFromMs = fromMs;
-            if (toMs < 0) {
-                mToMs = mDurationMs;
-            } else {
-                mToMs = toMs;
-            }
-            mLoop = loop;
-            mCallbackAfterFrameCount = callbackAfterFrameCount;
-            mListener = listener;
-            mRun = true;
-        }
-
-        /*
-         * {@inheritDoc}
-         */
-        @Override
-        public void run() {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "===> PreviewThread.run enter");
-            }
-            int frameCount = 0;
-            while (mRun) {
-                try {
-                    sleep(FRAME_DURATION);
-                } catch (InterruptedException ex) {
-                    break;
-                }
-                frameCount++;
-                mPositionMs += FRAME_DURATION;
-
-                if (mPositionMs >= mToMs) {
-                    if (!mLoop) {
-                        if (mListener != null) {
-                            mListener.onProgress(VideoEditorImpl.this, mPositionMs, true);
-                        }
-                        if (Log.isLoggable(TAG, Log.DEBUG)) {
-                            Log.d(TAG, "PreviewThread.run playback complete");
-                        }
-                        break;
-                    } else {
-                        // Fire a notification for the end of the clip
-                        if (mListener != null) {
-                            mListener.onProgress(VideoEditorImpl.this, mToMs, false);
-                        }
-
-                        // Rewind
-                        mPositionMs = mFromMs;
-                        if (mListener != null) {
-                            mListener.onProgress(VideoEditorImpl.this, mPositionMs, false);
-                        }
-                        if (Log.isLoggable(TAG, Log.DEBUG)) {
-                            Log.d(TAG, "PreviewThread.run playback complete");
-                        }
-                        frameCount = 0;
-                    }
-                } else {
-                    if (frameCount == mCallbackAfterFrameCount) {
-                        if (mListener != null) {
-                            mListener.onProgress(VideoEditorImpl.this, mPositionMs, false);
-                        }
-                        frameCount = 0;
-                    }
-                }
-            }
-
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "===> PreviewThread.run exit");
-            }
-        }
-
-        /**
-         * Stop the preview
-         *
-         * @return The stop position
-         */
-        public long stopPreview() {
-            mRun = false;
-            try {
-                join();
-            } catch (InterruptedException ex) {
-            }
-            return mPositionMs;
-        }
-    };
+    private MediaArtistNativeHelper mMANativeHelper;
+    private VideoEditor veObject = null;
+    private boolean mPreviewInProgress = false;
 
     /**
      * Constructor
      *
-     * @param projectPath
+     * @param projectPath - The path where the VideoEditor stores all files
+     *        related to the project
      */
     public VideoEditorImpl(String projectPath) throws IOException {
+
+        mMANativeHelper = new MediaArtistNativeHelper(projectPath, this);
         mProjectPath = projectPath;
         final File projectXml = new File(projectPath, PROJECT_FILENAME);
         if (projectXml.exists()) {
             try {
                 load();
             } catch (Exception ex) {
-                throw new IOException(ex);
+                ex.printStackTrace();
+                throw new IOException(ex.toString());
             }
         } else {
             mAspectRatio = MediaProperties.ASPECT_RATIO_16_9;
@@ -238,229 +166,345 @@
     }
 
     /*
+     * @return The MediaArtistNativeHelper object
+     */
+    MediaArtistNativeHelper getNativeContext() {
+        return mMANativeHelper;
+    }
+
+    /*
      * {@inheritDoc}
      */
-    public String getPath() {
-        return mProjectPath;
+    public synchronized void addAudioTrack(AudioTrack audioTrack) {
+        if (audioTrack == null) {
+            throw new IllegalArgumentException("Audio Track is null");
+        }
+        if (mAudioTracks.size() == 1) {
+            throw new IllegalArgumentException("No more tracks can be added");
+        }
+
+        /*
+         * Add the audio track to AudioTrack list
+         */
+        mAudioTracks.add(audioTrack);
+
+        /*
+         * Form the audio PCM file path
+         */
+        String audioTrackPCMFilePath = String.format(mProjectPath + "/"
+                    + "AudioPcm" + audioTrack.getId() + ".pcm");
+
+        /*
+         * Create PCM only if not generated in previous session
+         */
+        if (new File(audioTrackPCMFilePath).exists())
+        {
+            mMANativeHelper.setAudioflag(false);
+        }
+        mMANativeHelper.setGeneratePreview(true);
     }
 
     /*
      * {@inheritDoc}
      */
     public synchronized void addMediaItem(MediaItem mediaItem) {
-        if (mPreviewThread != null) {
-            throw new IllegalStateException("Previewing is in progress");
+        /*
+         * Validate Media Item
+         */
+        if (mediaItem == null) {
+            throw new IllegalArgumentException("Media item is null");
         }
-
+        /*
+         * Add the Media item to MediaItem list
+         */
         if (mMediaItems.contains(mediaItem)) {
-            throw new IllegalArgumentException("Media item already exists: " + mediaItem.getId());
+            throw new IllegalArgumentException("Media item already exists: " +
+            mediaItem.getId());
         }
 
-        // Invalidate the end transition if necessary
+        /*
+         *  Invalidate the end transition if necessary
+         */
         final int mediaItemsCount = mMediaItems.size();
         if ( mediaItemsCount > 0) {
             removeTransitionAfter(mediaItemsCount - 1);
         }
 
-        // Add the new media item
+        /*
+         *  Add the new media item
+         */
         mMediaItems.add(mediaItem);
 
         computeTimelineDuration();
-    }
-
-    /*
-     * {@inheritDoc}
-     */
-    public synchronized void insertMediaItem(MediaItem mediaItem, String afterMediaItemId) {
-        if (mPreviewThread != null) {
-            throw new IllegalStateException("Previewing is in progress");
-        }
-
-        if (mMediaItems.contains(mediaItem)) {
-            throw new IllegalArgumentException("Media item already exists: " + mediaItem.getId());
-        }
-
-        if (afterMediaItemId == null) {
-            if (mMediaItems.size() > 0) {
-                // Invalidate the transition at the beginning of the timeline
-                removeTransitionBefore(0);
-            }
-            mMediaItems.add(0, mediaItem);
-            computeTimelineDuration();
-        } else {
-            final int mediaItemCount = mMediaItems.size();
-            for (int i = 0; i < mediaItemCount; i++) {
-                final MediaItem mi = mMediaItems.get(i);
-                if (mi.getId().equals(afterMediaItemId)) {
-                    // Invalidate the transition at this position
-                    removeTransitionAfter(i);
-                    // Insert the new media item
-                    mMediaItems.add(i + 1, mediaItem);
-                    computeTimelineDuration();
-                    return;
-                }
-            }
-            throw new IllegalArgumentException("MediaItem not found: " + afterMediaItemId);
+        mMANativeHelper.setGeneratePreview(true);
+        /*
+         *  Generate project thumbnail only from first media Item on storyboard
+         */
+        if (mMediaItems.size() == 1) {
+            generateProjectThumbnail();
         }
     }
 
-    /*
-     * {@inheritDoc}
-     */
-    public synchronized void moveMediaItem(String mediaItemId, String afterMediaItemId) {
-        if (mPreviewThread != null) {
-            throw new IllegalStateException("Previewing is in progress");
-        }
-
-        final MediaItem moveMediaItem = removeMediaItem(mediaItemId);
-        if (moveMediaItem == null) {
-            throw new IllegalArgumentException("Target MediaItem not found: " + mediaItemId);
-        }
-
-        if (afterMediaItemId == null) {
-            if (mMediaItems.size() > 0) {
-                // Invalidate adjacent transitions at the insertion point
-                removeTransitionBefore(0);
-
-                // Insert the media item at the new position
-                mMediaItems.add(0, moveMediaItem);
-                computeTimelineDuration();
-            } else {
-                throw new IllegalStateException("Cannot move media item (it is the only item)");
-            }
-        } else {
-            final int mediaItemCount = mMediaItems.size();
-            for (int i = 0; i < mediaItemCount; i++) {
-                final MediaItem mi = mMediaItems.get(i);
-                if (mi.getId().equals(afterMediaItemId)) {
-                    // Invalidate adjacent transitions at the insertion point
-                    removeTransitionAfter(i);
-                    // Insert the media item at the new position
-                    mMediaItems.add(i + 1, moveMediaItem);
-                    computeTimelineDuration();
-                    return;
-                }
-            }
-
-            throw new IllegalArgumentException("MediaItem not found: " + afterMediaItemId);
-        }
-    }
-
-    /*
-     * {@inheritDoc}
-     */
-    public synchronized MediaItem removeMediaItem(String mediaItemId) {
-        if (mPreviewThread != null) {
-            throw new IllegalStateException("Previewing is in progress");
-        }
-
-        final MediaItem mediaItem = getMediaItem(mediaItemId);
-        if (mediaItem != null) {
-            // Remove the media item
-            mMediaItems.remove(mediaItem);
-            // Remove the adjacent transitions
-            removeAdjacentTransitions(mediaItem);
-            computeTimelineDuration();
-        }
-
-        return mediaItem;
-    }
-
-    /*
-     * {@inheritDoc}
-     */
-    public synchronized MediaItem getMediaItem(String mediaItemId) {
-        for (MediaItem mediaItem : mMediaItems) {
-            if (mediaItem.getId().equals(mediaItemId)) {
-                return mediaItem;
-            }
-        }
-
-        return null;
-    }
-
-    /*
-     * {@inheritDoc}
-     */
-    public synchronized List<MediaItem> getAllMediaItems() {
-        return mMediaItems;
-    }
-
-    /*
-     * {@inheritDoc}
-     */
-    public synchronized void removeAllMediaItems() {
-        mMediaItems.clear();
-
-        // Invalidate all transitions
-        for (Transition transition : mTransitions) {
-            transition.invalidate();
-        }
-        mTransitions.clear();
-
-        mDurationMs = 0;
-    }
 
     /*
      * {@inheritDoc}
      */
     public synchronized void addTransition(Transition transition) {
-        mTransitions.add(transition);
-
+        if (transition == null) {
+            throw new IllegalArgumentException("Null Transition");
+        }
         final MediaItem beforeMediaItem = transition.getBeforeMediaItem();
         final MediaItem afterMediaItem = transition.getAfterMediaItem();
+        /*
+         * Check if the MediaItems are in sequence
+         */
+        if (mMediaItems == null) {
+            throw new IllegalArgumentException("No media items are added");
+        }
+        if ((afterMediaItem != null) &&  (beforeMediaItem != null)) {
+            int afterMediaItemIndex = mMediaItems.indexOf(afterMediaItem);
+            int beforeMediaItemIndex = mMediaItems.indexOf(beforeMediaItem);
 
-        // Cross reference the transitions
+
+            if ((afterMediaItemIndex == -1) || (beforeMediaItemIndex == -1)) {
+                throw new IllegalArgumentException
+                    ("Either of the mediaItem is not found in the list");
+            }
+            if (afterMediaItemIndex != (beforeMediaItemIndex - 1) ) {
+                throw new IllegalArgumentException("MediaItems are not in sequence");
+            }
+         }
+
+        mTransitions.add(transition);
+        /*
+         *  Cross reference the transitions
+         */
         if (afterMediaItem != null) {
-            // If a transition already exists at the specified position then
-            // invalidate it.
+            /*
+             *  If a transition already exists at the specified position then
+             *  invalidate it.
+             */
             if (afterMediaItem.getEndTransition() != null) {
                 afterMediaItem.getEndTransition().invalidate();
+                mTransitions.remove(afterMediaItem.getEndTransition());
             }
             afterMediaItem.setEndTransition(transition);
         }
 
         if (beforeMediaItem != null) {
-            // If a transition already exists at the specified position then
-            // invalidate it.
+            /*
+             *  If a transition already exists at the specified position then
+             *  invalidate it.
+             */
             if (beforeMediaItem.getBeginTransition() != null) {
                 beforeMediaItem.getBeginTransition().invalidate();
+                mTransitions.remove(beforeMediaItem.getBeginTransition());
             }
             beforeMediaItem.setBeginTransition(transition);
         }
 
         computeTimelineDuration();
+        mMANativeHelper.setGeneratePreview(true);
     }
 
     /*
      * {@inheritDoc}
      */
-    public synchronized Transition removeTransition(String transitionId) {
-        if (mPreviewThread != null) {
-            throw new IllegalStateException("Previewing is in progress");
+    public void cancelExport(String filename) {
+        if (mMANativeHelper != null && filename != null) {
+            mMANativeHelper.stop(filename);
+        }
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public void export(String filename, int height, int bitrate,
+                       int audioCodec, int videoCodec,
+                       ExportProgressListener listener) throws IOException {
+        if ( filename == null) {
+            throw new IllegalArgumentException("export: filename is null");
+        }
+        File tempPathFile = new File(filename);
+        if (tempPathFile == null) {
+            throw new IOException(filename + "can not be created");
+        }
+        if (mMediaItems.size() == 0) {
+            throw new IllegalStateException("No MediaItems added");
         }
 
-        final Transition transition = getTransition(transitionId);
-        if (transition == null) {
-            throw new IllegalStateException("Transition not found: " + transitionId);
+        switch (audioCodec) {
+            case MediaProperties.ACODEC_AAC_LC:
+                break;
+            case MediaProperties.ACODEC_AMRNB:
+                break;
+
+            default :
+                throw new IllegalArgumentException("Audio codec type incorrect");
         }
 
-        // Remove the transition references
-        final MediaItem afterMediaItem = transition.getAfterMediaItem();
-        if (afterMediaItem != null) {
-            afterMediaItem.setEndTransition(null);
+        switch (videoCodec) {
+            case MediaProperties.VCODEC_H263:
+                break;
+            case MediaProperties.VCODEC_H264BP:
+                break;
+            case MediaProperties.VCODEC_MPEG4:
+                break;
+
+            default :
+                throw new IllegalArgumentException("Video codec type incorrect");
         }
 
-        final MediaItem beforeMediaItem = transition.getBeforeMediaItem();
-        if (beforeMediaItem != null) {
-            beforeMediaItem.setBeginTransition(null);
+        switch (height) {
+            case MediaProperties.HEIGHT_144:
+                break;
+            case MediaProperties.HEIGHT_360:
+                break;
+            case MediaProperties.HEIGHT_480:
+                break;
+            case MediaProperties.HEIGHT_720:
+                break;
+
+            default:
+                throw new IllegalArgumentException("Argument Height incorrect");
         }
 
-        mTransitions.remove(transition);
-        transition.invalidate();
-        computeTimelineDuration();
+        switch (bitrate) {
+            case MediaProperties.BITRATE_28K:
+                break;
+            case MediaProperties.BITRATE_40K:
+                break;
+            case MediaProperties.BITRATE_64K:
+                break;
+            case MediaProperties.BITRATE_96K:
+                break;
+            case MediaProperties.BITRATE_128K:
+                break;
+            case MediaProperties.BITRATE_192K:
+                break;
+            case MediaProperties.BITRATE_256K:
+                break;
+            case MediaProperties.BITRATE_384K:
+                break;
+            case MediaProperties.BITRATE_512K:
+                break;
+            case MediaProperties.BITRATE_800K:
+                break;
+            case MediaProperties.BITRATE_2M:
+                break;
+            case MediaProperties.BITRATE_5M:
+                break;
+            case MediaProperties.BITRATE_8M:
+                break;
 
-        return transition;
+            default:
+                throw new IllegalArgumentException("Argument Bitrate incorrect");
+        }
+
+        mMANativeHelper.export(filename, mProjectPath, height,bitrate,audioCodec,
+                videoCodec,mMediaItems, mTransitions, mAudioTracks,listener);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public void export(String filename, int height, int bitrate,
+                       ExportProgressListener listener) throws IOException {
+        if ( filename == null) {
+            throw new IllegalArgumentException("export: filename is null");
+        }
+        File tempPathFile = new File(filename);
+        if (tempPathFile == null) {
+            throw new IOException(filename + "can not be created");
+        }
+        if (mMediaItems.size() == 0) {
+            throw new IllegalStateException("No MediaItems added");
+        }
+
+        switch (height) {
+            case MediaProperties.HEIGHT_144:
+                break;
+            case MediaProperties.HEIGHT_360:
+                break;
+            case MediaProperties.HEIGHT_480:
+                break;
+            case MediaProperties.HEIGHT_720:
+                break;
+
+            default:
+                throw new IllegalArgumentException("Argument Height incorrect");
+        }
+        switch (bitrate) {
+            case MediaProperties.BITRATE_28K:
+                break;
+            case MediaProperties.BITRATE_40K:
+                break;
+            case MediaProperties.BITRATE_64K:
+                break;
+            case MediaProperties.BITRATE_96K:
+                break;
+            case MediaProperties.BITRATE_128K:
+                break;
+            case MediaProperties.BITRATE_192K:
+                break;
+            case MediaProperties.BITRATE_256K:
+                break;
+            case MediaProperties.BITRATE_384K:
+                break;
+            case MediaProperties.BITRATE_512K:
+                break;
+            case MediaProperties.BITRATE_800K:
+                break;
+            case MediaProperties.BITRATE_2M:
+                break;
+            case MediaProperties.BITRATE_5M:
+                break;
+            case MediaProperties.BITRATE_8M:
+                break;
+
+            default:
+                throw new IllegalArgumentException("Argument Bitrate incorrect");
+        }
+
+        mMANativeHelper.export(filename, mProjectPath, height,bitrate,
+                               mMediaItems, mTransitions, mAudioTracks,
+                               listener);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public void generatePreview(MediaProcessingProgressListener listener) {
+        boolean semAcquireDone = false;
+        try{
+            mPreviewSemaphore.acquire();
+            semAcquireDone = true;
+            mMANativeHelper.setGeneratePreview(true);
+            if ((mMediaItems.size() > 0) || (mAudioTracks.size() > 0)) {
+                mMANativeHelper.previewStoryBoard(mMediaItems, mTransitions,
+                        mAudioTracks, listener);
+            }
+        } catch (InterruptedException  ex) {
+            Log.e("VideoEditorImpl", "Sem acquire NOT successful in previewStoryBoard");
+        } finally {
+            if (semAcquireDone) {
+                mPreviewSemaphore.release();
+            }
+        }
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public List<AudioTrack> getAllAudioTracks() {
+        return mAudioTracks;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public List<MediaItem> getAllMediaItems() {
+        return mMediaItems;
     }
 
     /*
@@ -473,33 +517,79 @@
     /*
      * {@inheritDoc}
      */
-    public Transition getTransition(String transitionId) {
-        for (Transition transition : mTransitions) {
-            if (transition.getId().equals(transitionId)) {
-                return transition;
+    public int getAspectRatio() {
+        return mAspectRatio;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public AudioTrack getAudioTrack(String audioTrackId) {
+        for (AudioTrack at : mAudioTracks) {
+            if (at.getId().equals(audioTrackId)) {
+                return at;
             }
         }
-
         return null;
     }
 
     /*
      * {@inheritDoc}
      */
-    public synchronized void addAudioTrack(AudioTrack audioTrack) {
-        if (mPreviewThread != null) {
-            throw new IllegalStateException("Previewing is in progress");
-        }
+    public long getDuration() {
+        /**
+         *  Since MediaImageItem can change duration we need to compute the
+         *  duration here
+         */
+        computeTimelineDuration();
+        return mDurationMs;
+    }
 
-        mAudioTracks.add(audioTrack);
+    /*
+     * Force updates the timeline duration
+     */
+    void updateTimelineDuration() {
+        computeTimelineDuration();
     }
 
     /*
      * {@inheritDoc}
      */
-    public synchronized void insertAudioTrack(AudioTrack audioTrack, String afterAudioTrackId) {
-        if (mPreviewThread != null) {
-            throw new IllegalStateException("Previewing is in progress");
+    public synchronized MediaItem getMediaItem(String mediaItemId) {
+        for (MediaItem mediaItem : mMediaItems) {
+            if (mediaItem.getId().equals(mediaItemId)) {
+                return mediaItem;
+            }
+        }
+        return null;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public String getPath() {
+        return mProjectPath;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public Transition getTransition(String transitionId) {
+        for (Transition transition : mTransitions) {
+            if (transition.getId().equals(transitionId)) {
+                return transition;
+            }
+        }
+        return null;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public synchronized void insertAudioTrack(AudioTrack audioTrack,
+                                              String afterAudioTrackId) {
+        if (mAudioTracks.size() == 1) {
+            throw new IllegalArgumentException("No more tracks can be added");
         }
 
         if (afterAudioTrackId == null) {
@@ -513,245 +603,355 @@
                     return;
                 }
             }
-
-            throw new IllegalArgumentException("AudioTrack not found: " + afterAudioTrackId);
+            throw new IllegalArgumentException("AudioTrack not found: "
+                                                           + afterAudioTrackId);
         }
+        mMANativeHelper.setGeneratePreview(true);
     }
 
     /*
      * {@inheritDoc}
      */
-    public synchronized void moveAudioTrack(String audioTrackId, String afterAudioTrackId) {
+    public synchronized void insertMediaItem(MediaItem mediaItem,
+                                             String afterMediaItemId) {
+        if (mMediaItems.contains(mediaItem)) {
+            throw new IllegalArgumentException("Media item already exists: "
+                                                           + mediaItem.getId());
+        }
+
+        if (afterMediaItemId == null) {
+            if (mMediaItems.size() > 0) {
+                /**
+                 *  Invalidate the transition at the beginning of the timeline
+                 */
+                removeTransitionBefore(0);
+            }
+            mMediaItems.add(0, mediaItem);
+            computeTimelineDuration();
+            generateProjectThumbnail();
+        } else {
+            final int mediaItemCount = mMediaItems.size();
+            for (int i = 0; i < mediaItemCount; i++) {
+                final MediaItem mi = mMediaItems.get(i);
+                if (mi.getId().equals(afterMediaItemId)) {
+                    /**
+                     *  Invalidate the transition at this position
+                     */
+                    removeTransitionAfter(i);
+                    /**
+                     *  Insert the new media item
+                     */
+                    mMediaItems.add(i + 1, mediaItem);
+                    computeTimelineDuration();
+                    mMANativeHelper.setGeneratePreview(true);
+                    return;
+                }
+            }
+            throw new IllegalArgumentException("MediaItem not found: "
+                                                            + afterMediaItemId);
+        }
+        mMANativeHelper.setGeneratePreview(true);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public synchronized void moveAudioTrack(String audioTrackId,
+                                            String afterAudioTrackId) {
         throw new IllegalStateException("Not supported");
     }
 
     /*
      * {@inheritDoc}
      */
-    public synchronized AudioTrack removeAudioTrack(String audioTrackId) {
-        if (mPreviewThread != null) {
-            throw new IllegalStateException("Previewing is in progress");
+    public synchronized void moveMediaItem(String mediaItemId,
+                                           String afterMediaItemId) {
+        final MediaItem moveMediaItem = removeMediaItem(mediaItemId,true);
+        if (moveMediaItem == null) {
+            throw new IllegalArgumentException("Target MediaItem not found: "
+                                                                 + mediaItemId);
         }
 
+        if (afterMediaItemId == null) {
+            if (mMediaItems.size() > 0) {
+                /**
+                 *  Invalidate adjacent transitions at the insertion point
+                 */
+                removeTransitionBefore(0);
+
+                /**
+                 *  Insert the media item at the new position
+                 */
+                mMediaItems.add(0, moveMediaItem);
+                computeTimelineDuration();
+                generateProjectThumbnail();
+            } else {
+                throw new IllegalStateException("Cannot move media item (it is the only item)");
+            }
+        } else {
+            final int mediaItemCount = mMediaItems.size();
+            for (int i = 0; i < mediaItemCount; i++) {
+                final MediaItem mi = mMediaItems.get(i);
+                if (mi.getId().equals(afterMediaItemId)) {
+                    /**
+                     *  Invalidate adjacent transitions at the insertion point
+                     */
+                    removeTransitionAfter(i);
+                    /**
+                     *  Insert the media item at the new position
+                     */
+                    mMediaItems.add(i + 1, moveMediaItem);
+                    computeTimelineDuration();
+                    mMANativeHelper.setGeneratePreview(true);
+                    return;
+                }
+            }
+
+            throw new IllegalArgumentException("MediaItem not found: "
+                                                            + afterMediaItemId);
+        }
+        mMANativeHelper.setGeneratePreview(true);
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public void release() {
+        stopPreview();
+        mMediaItems.clear();
+        mAudioTracks.clear();
+        mTransitions.clear();
+        mMANativeHelper.releaseNativeHelper();
+        if (mMANativeHelper!= null)
+            mMANativeHelper = null;
+        if (veObject != null)
+            veObject= null;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public synchronized void removeAllMediaItems() {
+        mMediaItems.clear();
+
+        /**
+         *  Invalidate all transitions
+         */
+        for (Transition transition : mTransitions) {
+            transition.invalidate();
+        }
+        mTransitions.clear();
+
+        mDurationMs = 0;
+        mMANativeHelper.setGeneratePreview(true);
+        /**
+         * If a thumbnail already exists, then delete it
+         */
+        if ((new File(mProjectPath + "/" + THUMBNAIL_FILENAME)).exists()) {
+            (new File(mProjectPath + "/" + THUMBNAIL_FILENAME)).delete();
+        }
+
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public synchronized AudioTrack removeAudioTrack(String audioTrackId) {
         final AudioTrack audioTrack = getAudioTrack(audioTrackId);
         if (audioTrack != null) {
             mAudioTracks.remove(audioTrack);
+            audioTrack.invalidate();
+            mMANativeHelper.invalidatePcmFile();
+            mMANativeHelper.setAudioflag(true);
         }
-
+        else {
+            throw new IllegalArgumentException(" No more audio tracks");
+        }
+        mMANativeHelper.setGeneratePreview(true);
         return audioTrack;
     }
 
     /*
      * {@inheritDoc}
      */
-    public AudioTrack getAudioTrack(String audioTrackId) {
-        for (AudioTrack at : mAudioTracks) {
-            if (at.getId().equals(audioTrackId)) {
-                return at;
+    public synchronized MediaItem removeMediaItem(String mediaItemId) {
+        final String firstItemString = mMediaItems.get(0).getId();
+        final MediaItem mediaItem = getMediaItem(mediaItemId);
+        if (mediaItem != null) {
+            /**
+             *  Remove the media item
+             */
+            mMediaItems.remove(mediaItem);
+            if (mediaItem instanceof MediaImageItem) {
+                ((MediaImageItem)mediaItem).invalidate();
             }
-        }
-
-        return null;
-    }
-
-    /*
-     * {@inheritDoc}
-     */
-    public List<AudioTrack> getAllAudioTracks() {
-        return mAudioTracks;
-    }
-
-    /*
-     * {@inheritDoc}
-     */
-    public void save() throws IOException {
-        final XmlSerializer serializer = Xml.newSerializer();
-        final StringWriter writer = new StringWriter();
-        serializer.setOutput(writer);
-        serializer.startDocument("UTF-8", true);
-        serializer.startTag("", TAG_PROJECT);
-        serializer.attribute("", ATTR_ASPECT_RATIO, Integer.toString(mAspectRatio));
-
-        serializer.startTag("", TAG_MEDIA_ITEMS);
-        for (MediaItem mediaItem : mMediaItems) {
-            serializer.startTag("", TAG_MEDIA_ITEM);
-            serializer.attribute("", ATTR_ID, mediaItem.getId());
-            serializer.attribute("", ATTR_TYPE, mediaItem.getClass().getSimpleName());
-            serializer.attribute("", ATTR_FILENAME, mediaItem.getFilename());
-            serializer.attribute("", ATTR_RENDERING_MODE, Integer.toString(
-                    mediaItem.getRenderingMode()));
-            if (mediaItem instanceof MediaVideoItem) {
-                final MediaVideoItem mvi = (MediaVideoItem)mediaItem;
-                serializer
-                        .attribute("", ATTR_BEGIN_TIME, Long.toString(mvi.getBoundaryBeginTime()));
-                serializer.attribute("", ATTR_END_TIME, Long.toString(mvi.getBoundaryEndTime()));
-                serializer.attribute("", ATTR_VOLUME, Integer.toString(mvi.getVolume()));
-                serializer.attribute("", ATTR_MUTED, Boolean.toString(mvi.isMuted()));
-                if (mvi.getAudioWaveformFilename() != null) {
-                    serializer.attribute("", ATTR_AUDIO_WAVEFORM_FILENAME,
-                            mvi.getAudioWaveformFilename());
-                }
-            } else if (mediaItem instanceof MediaImageItem) {
-                serializer.attribute("", ATTR_DURATION,
-                        Long.toString(mediaItem.getTimelineDuration()));
-            }
-
             final List<Overlay> overlays = mediaItem.getAllOverlays();
             if (overlays.size() > 0) {
-                serializer.startTag("", TAG_OVERLAYS);
                 for (Overlay overlay : overlays) {
-                    serializer.startTag("", TAG_OVERLAY);
-                    serializer.attribute("", ATTR_ID, overlay.getId());
-                    serializer.attribute("", ATTR_TYPE, overlay.getClass().getSimpleName());
-                    serializer.attribute("", ATTR_BEGIN_TIME,
-                            Long.toString(overlay.getStartTime()));
-                    serializer.attribute("", ATTR_DURATION, Long.toString(overlay.getDuration()));
                     if (overlay instanceof OverlayFrame) {
                         final OverlayFrame overlayFrame = (OverlayFrame)overlay;
-                        overlayFrame.save(getPath());
-                        if (overlayFrame.getFilename() != null) {
-                            serializer.attribute("", ATTR_FILENAME, overlayFrame.getFilename());
-                        }
+                        overlayFrame.invalidate();
                     }
-
-                    // Save the user attributes
-                    serializer.startTag("", TAG_OVERLAY_USER_ATTRIBUTES);
-                    final Map<String, String> userAttributes = overlay.getUserAttributes();
-                    for (String name : userAttributes.keySet()) {
-                        final String value = userAttributes.get(name);
-                        if (value != null) {
-                            serializer.attribute("", name, value);
-                        }
-                    }
-                    serializer.endTag("", TAG_OVERLAY_USER_ATTRIBUTES);
-
-                    serializer.endTag("", TAG_OVERLAY);
-                }
-                serializer.endTag("", TAG_OVERLAYS);
-            }
-
-            final List<Effect> effects = mediaItem.getAllEffects();
-            if (effects.size() > 0) {
-                serializer.startTag("", TAG_EFFECTS);
-                for (Effect effect : effects) {
-                    serializer.startTag("", TAG_EFFECT);
-                    serializer.attribute("", ATTR_ID, effect.getId());
-                    serializer.attribute("", ATTR_TYPE, effect.getClass().getSimpleName());
-                    serializer.attribute("", ATTR_BEGIN_TIME,
-                            Long.toString(effect.getStartTime()));
-                    serializer.attribute("", ATTR_DURATION, Long.toString(effect.getDuration()));
-                    if (effect instanceof EffectColor) {
-                        final EffectColor colorEffect = (EffectColor)effect;
-                        serializer.attribute("", ATTR_COLOR_EFFECT_TYPE,
-                                Integer.toString(colorEffect.getType()));
-                        if (colorEffect.getType() == EffectColor.TYPE_COLOR ||
-                                colorEffect.getType() == EffectColor.TYPE_GRADIENT) {
-                            serializer.attribute("", ATTR_COLOR_EFFECT_VALUE,
-                                    Integer.toString(colorEffect.getColor()));
-                        }
-                    } else if (effect instanceof EffectKenBurns) {
-                        final Rect startRect = ((EffectKenBurns)effect).getStartRect();
-                        serializer.attribute("", ATTR_START_RECT_L,
-                                Integer.toString(startRect.left));
-                        serializer.attribute("", ATTR_START_RECT_T,
-                                Integer.toString(startRect.top));
-                        serializer.attribute("", ATTR_START_RECT_R,
-                                Integer.toString(startRect.right));
-                        serializer.attribute("", ATTR_START_RECT_B,
-                                Integer.toString(startRect.bottom));
-
-                        final Rect endRect = ((EffectKenBurns)effect).getEndRect();
-                        serializer.attribute("", ATTR_END_RECT_L, Integer.toString(endRect.left));
-                        serializer.attribute("", ATTR_END_RECT_T, Integer.toString(endRect.top));
-                        serializer.attribute("", ATTR_END_RECT_R, Integer.toString(endRect.right));
-                        serializer.attribute("", ATTR_END_RECT_B,
-                                Integer.toString(endRect.bottom));
-                    }
-
-                    serializer.endTag("", TAG_EFFECT);
-                }
-                serializer.endTag("", TAG_EFFECTS);
-            }
-
-            serializer.endTag("", TAG_MEDIA_ITEM);
-        }
-        serializer.endTag("", TAG_MEDIA_ITEMS);
-
-        serializer.startTag("", TAG_TRANSITIONS);
-
-        for (Transition transition : mTransitions) {
-            serializer.startTag("", TAG_TRANSITION);
-            serializer.attribute("", ATTR_ID, transition.getId());
-            serializer.attribute("", ATTR_TYPE, transition.getClass().getSimpleName());
-            serializer.attribute("", ATTR_DURATION, Long.toString(transition.getDuration()));
-            serializer.attribute("", ATTR_BEHAVIOR, Integer.toString(transition.getBehavior()));
-            final MediaItem afterMediaItem = transition.getAfterMediaItem();
-            if (afterMediaItem != null) {
-                serializer.attribute("", ATTR_AFTER_MEDIA_ITEM_ID, afterMediaItem.getId());
-            }
-
-            final MediaItem beforeMediaItem = transition.getBeforeMediaItem();
-            if (beforeMediaItem != null) {
-                serializer.attribute("", ATTR_BEFORE_MEDIA_ITEM_ID, beforeMediaItem.getId());
-            }
-
-            if (transition instanceof TransitionSliding) {
-                serializer.attribute("", ATTR_DIRECTION,
-                        Integer.toString(((TransitionSliding)transition).getDirection()));
-            } else if (transition instanceof TransitionAlpha) {
-                TransitionAlpha ta = (TransitionAlpha)transition;
-                serializer.attribute("", ATTR_BLENDING, Integer.toString(ta.getBlendingPercent()));
-                serializer.attribute("", ATTR_INVERT, Boolean.toString(ta.isInvert()));
-                if (ta.getMaskFilename() != null) {
-                    serializer.attribute("", ATTR_MASK, ta.getMaskFilename());
                 }
             }
-            serializer.endTag("", TAG_TRANSITION);
-        }
-        serializer.endTag("", TAG_TRANSITIONS);
 
-        serializer.startTag("", TAG_AUDIO_TRACKS);
-        for (AudioTrack at : mAudioTracks) {
-            serializer.startTag("", TAG_AUDIO_TRACK);
-            serializer.attribute("", ATTR_ID, at.getId());
-            serializer.attribute("", ATTR_FILENAME, at.getFilename());
-            serializer.attribute("", ATTR_START_TIME, Long.toString(at.getStartTime()));
-            serializer.attribute("", ATTR_BEGIN_TIME, Long.toString(at.getBoundaryBeginTime()));
-            serializer.attribute("", ATTR_END_TIME, Long.toString(at.getBoundaryEndTime()));
-            serializer.attribute("", ATTR_VOLUME, Integer.toString(at.getVolume()));
-            serializer.attribute("", ATTR_DUCK_ENABLED, Boolean.toString(at.isDuckingEnabled()));
-            serializer.attribute("", ATTR_DUCKED_TRACK_VOLUME, Integer.toString(at.getDuckedTrackVolume()));
-            serializer.attribute("", ATTR_DUCK_THRESHOLD, Integer.toString(at.getDuckingThreshhold()));
-            serializer.attribute("", ATTR_MUTED, Boolean.toString(at.isMuted()));
-            serializer.attribute("", ATTR_LOOP, Boolean.toString(at.isLooping()));
-            if (at.getAudioWaveformFilename() != null) {
-                serializer.attribute("", ATTR_AUDIO_WAVEFORM_FILENAME,
-                at.getAudioWaveformFilename());
+            /**
+             *  Remove the adjacent transitions
+             */
+            removeAdjacentTransitions(mediaItem);
+            computeTimelineDuration();
+        }
+        mMANativeHelper.setGeneratePreview(true);
+        /**
+         * If string equals first mediaItem, then
+         * generate Project thumbail
+         */
+        if (firstItemString.equals(mediaItemId)) {
+            generateProjectThumbnail();
+        }
+
+        if (mediaItem instanceof MediaVideoItem) {
+            /**
+             * Delete the graph file
+             */
+            ((MediaVideoItem)mediaItem).invalidate();
+        }
+        return mediaItem;
+    }
+
+    private synchronized MediaItem removeMediaItem(String mediaItemId,
+                                                   boolean flag) {
+        final String firstItemString = mMediaItems.get(0).getId();
+
+        final MediaItem mediaItem = getMediaItem(mediaItemId);
+        if (mediaItem != null) {
+            /**
+             *  Remove the media item
+             */
+            mMediaItems.remove(mediaItem);
+            /**
+             *  Remove the adjacent transitions
+             */
+            removeAdjacentTransitions(mediaItem);
+            computeTimelineDuration();
+        }
+        mMANativeHelper.setGeneratePreview(true);
+
+        /**
+         * If string equals first mediaItem, then
+         * generate Project thumbail
+         */
+        if (firstItemString.equals(mediaItemId)) {
+            generateProjectThumbnail();
+        }
+        return mediaItem;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public synchronized Transition removeTransition(String transitionId) {
+        final Transition transition = getTransition(transitionId);
+        if (transition == null) {
+            throw new IllegalStateException("Transition not found: "
+                                                                + transitionId);
+        }
+
+        /**
+         *  Remove the transition references
+         */
+        final MediaItem afterMediaItem = transition.getAfterMediaItem();
+        if (afterMediaItem != null) {
+            afterMediaItem.setEndTransition(null);
+        }
+
+        final MediaItem beforeMediaItem = transition.getBeforeMediaItem();
+        if (beforeMediaItem != null) {
+            beforeMediaItem.setBeginTransition(null);
+        }
+
+        mTransitions.remove(transition);
+        transition.invalidate();
+        computeTimelineDuration();
+        mMANativeHelper.setGeneratePreview(true);
+        return transition;
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs) {
+        long result = 0;
+        int surfaceWidth = 0;
+        int surfaceHeight = 0;
+        Rect frame;
+
+        if (surfaceHolder == null) {
+            throw new IllegalArgumentException("Surface Holder is null");
+        }
+
+        if (timeMs < 0) {
+            throw new IllegalArgumentException("requested time not correct");
+        } else if (timeMs > mDurationMs) {
+            throw new IllegalArgumentException("requested time more than duration");
+        }
+        if (mMANativeHelper != null) {
+            if (mMANativeHelper.mInvalidatePreviewArray) {
+                return -1;
+            }
+        }
+        else {
+            return -1;
+        }
+        boolean semAcquireDone = false;
+
+        try{
+            mPreviewSemaphore.acquire();
+            semAcquireDone = true;
+            Surface surface = surfaceHolder.getSurface();
+            frame = surfaceHolder.getSurfaceFrame();
+            surfaceWidth = frame.width();
+            surfaceHeight = frame.height();
+
+            if (surface == null) {
+                throw new RuntimeException("Surface could not be retrieved from Surface holder");
             }
 
-            serializer.endTag("", TAG_AUDIO_TRACK);
+            if (!mMANativeHelper.mInvalidatePreviewArray) {
+                if (mMediaItems.size() > 0) {
+                    result = mMANativeHelper.renderPreviewFrame(surface,
+                                             timeMs,surfaceWidth,surfaceHeight);
+                }
+                else {
+                    result = 0;
+                }
+            }
+            else {
+                result = -1;
+            }
+
+        } catch (InterruptedException  ex) {
+            Log.e("VideoEditorImpl", "Sem acquire NOT successful in renderPreviewFrame");
         }
-        serializer.endTag("", TAG_AUDIO_TRACKS);
-
-        serializer.endTag("", TAG_PROJECT);
-        serializer.endDocument();
-
-        // Save the metadata XML file
-        final FileOutputStream out = new FileOutputStream(new File(getPath(), PROJECT_FILENAME));
-        out.write(writer.toString().getBytes());
-        out.flush();
-        out.close();
+        finally {
+            if (semAcquireDone) {
+                mPreviewSemaphore.release();
+            }
+        }
+        return result;
     }
 
     /**
-     * Load the project form XML
+     *  the project form XML
      */
-    private void load() throws FileNotFoundException, XmlPullParserException, IOException {
+    private void load() throws FileNotFoundException, XmlPullParserException,
+                               IOException {
         final File file = new File(mProjectPath, PROJECT_FILENAME);
+        /**
+         *  Load the metadata
+         */
         final FileInputStream fis = new FileInputStream(file);
-
         try {
-            // Load the metadata
             final XmlPullParser parser = Xml.newPullParser();
             parser.setInput(fis, "UTF-8");
             int eventType = parser.getEventType();
@@ -763,44 +963,59 @@
                     case XmlPullParser.START_TAG: {
                         name = parser.getName();
                         if (TAG_PROJECT.equals(name)) {
-                            mAspectRatio = Integer.parseInt(parser.getAttributeValue("",
-                                    ATTR_ASPECT_RATIO));
+                            mAspectRatio =
+                                   Integer.parseInt(parser.getAttributeValue("",
+                                   ATTR_ASPECT_RATIO));
+                            final boolean mInvalidatePreviewArray =
+                               Boolean.parseBoolean(parser.getAttributeValue("",
+                                    ATTR_PREVIEW_PREPARE));
+                            mMANativeHelper.setGeneratePreview(mInvalidatePreviewArray);
+
+                            final boolean mRegenPCM =
+                               Boolean.parseBoolean(parser.getAttributeValue("",
+                                    ATTR_REGENERATE_PCM));
+                            mMANativeHelper.setAudioflag(mRegenPCM);
+
                         } else if (TAG_MEDIA_ITEM.equals(name)) {
-                            final String mediaItemId = parser.getAttributeValue("", ATTR_ID);
-                            final String type = parser.getAttributeValue("", ATTR_TYPE);
-                            final String filename = parser.getAttributeValue("", ATTR_FILENAME);
-                            final int renderingMode = Integer.parseInt(
-                                    parser.getAttributeValue("", ATTR_RENDERING_MODE));
+                            final String mediaItemId =
+                                          parser.getAttributeValue("", ATTR_ID);
+                            final String type =
+                                        parser.getAttributeValue("", ATTR_TYPE);
+                            final String filename =
+                                    parser.getAttributeValue("", ATTR_FILENAME);
+                            final int renderingMode =
+                                   Integer.parseInt(parser.getAttributeValue("",
+                                   ATTR_RENDERING_MODE));
 
                             if (MediaImageItem.class.getSimpleName().equals(type)) {
-                                final long durationMs = Long.parseLong(
-                                        parser.getAttributeValue("", ATTR_DURATION));
+                                final long durationMs = Long.parseLong(parser.getAttributeValue("",
+                                        ATTR_DURATION));
                                 currentMediaItem = new MediaImageItem(this, mediaItemId, filename,
                                         durationMs, renderingMode);
                             } else if (MediaVideoItem.class.getSimpleName().equals(type)) {
-                                final long beginMs = Long.parseLong(
-                                        parser.getAttributeValue("", ATTR_BEGIN_TIME));
-                                final long endMs = Long.parseLong(
-                                        parser.getAttributeValue("", ATTR_END_TIME));
-                                final int volume = Integer.parseInt(
-                                        parser.getAttributeValue("", ATTR_VOLUME));
-                                final boolean muted = Boolean.parseBoolean(
-                                        parser.getAttributeValue("", ATTR_MUTED));
-                                final String audioWaveformFilename =
-                                        parser.getAttributeValue("", ATTR_AUDIO_WAVEFORM_FILENAME);
+                                final long beginMs = Long.parseLong(parser.getAttributeValue("",
+                                        ATTR_BEGIN_TIME));
+                                final long endMs = Long.parseLong(parser.getAttributeValue("",
+                                        ATTR_END_TIME));
+                                final int volume = Integer.parseInt(parser.getAttributeValue("",
+                                        ATTR_VOLUME));
+                                final boolean muted = Boolean.parseBoolean(parser.getAttributeValue("",
+                                        ATTR_MUTED));
+                                final String audioWaveformFilename = parser.getAttributeValue("",
+                                        ATTR_AUDIO_WAVEFORM_FILENAME);
                                 currentMediaItem = new MediaVideoItem(this, mediaItemId, filename,
                                         renderingMode, beginMs, endMs, volume, muted,
                                         audioWaveformFilename);
 
-                                final long beginTimeMs = Long.parseLong(
-                                        parser.getAttributeValue("", ATTR_BEGIN_TIME));
-                                final long endTimeMs = Long.parseLong(
-                                        parser.getAttributeValue("", ATTR_END_TIME));
-                                ((MediaVideoItem)currentMediaItem).setExtractBoundaries(
-                                        beginTimeMs, endTimeMs);
+                                final long beginTimeMs = Long.parseLong(parser.getAttributeValue("",
+                                        ATTR_BEGIN_TIME));
+                                final long endTimeMs = Long.parseLong(parser.getAttributeValue("",
+                                        ATTR_END_TIME));
+                                ((MediaVideoItem)currentMediaItem).setExtractBoundaries(beginTimeMs,
+                                        endTimeMs);
 
-                                final int volumePercent = Integer.parseInt(
-                                        parser.getAttributeValue("", ATTR_VOLUME));
+                                final int volumePercent = Integer.parseInt(parser.getAttributeValue("",
+                                        ATTR_VOLUME));
                                 ((MediaVideoItem)currentMediaItem).setVolume(volumePercent);
                             } else {
                                 Log.e(TAG, "Unknown media item type: " + type);
@@ -836,6 +1051,18 @@
                                 if (effect != null) {
                                     currentMediaItem.addEffect(effect);
                                 }
+                                if (effect instanceof EffectKenBurns) {
+                                    String filename = parser.getAttributeValue("", ATTR_GENERATED_IMAGE_CLIP);
+
+                                    if (new File(filename).exists() == true) {
+                                        ((MediaImageItem)currentMediaItem).setGeneratedImageClip(filename);
+                                        ((MediaImageItem)currentMediaItem).setRegenerateClip(false);
+                                    }
+                                    else {
+                                        ((MediaImageItem)currentMediaItem).setGeneratedImageClip(null);
+                                        ((MediaImageItem)currentMediaItem).setRegenerateClip(true);
+                                    }
+                                }
                             }
                         } else if (TAG_AUDIO_TRACK.equals(name)) {
                             final AudioTrack audioTrack = parseAudioTrack(parser);
@@ -879,10 +1106,15 @@
     private Transition parseTransition(XmlPullParser parser) {
         final String transitionId = parser.getAttributeValue("", ATTR_ID);
         final String type = parser.getAttributeValue("", ATTR_TYPE);
-        final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION));
-        final int behavior = Integer.parseInt(parser.getAttributeValue("", ATTR_BEHAVIOR));
+        final long durationMs = Long.parseLong(parser.getAttributeValue("",
+                                               ATTR_DURATION));
+        final int behavior = Integer.parseInt(parser.getAttributeValue("",
+                                              ATTR_BEHAVIOR));
+        final boolean isTransitionGenerated;
 
-        final String beforeMediaItemId = parser.getAttributeValue("", ATTR_BEFORE_MEDIA_ITEM_ID);
+
+        final String beforeMediaItemId = parser.getAttributeValue("",
+                                                     ATTR_BEFORE_MEDIA_ITEM_ID);
         final MediaItem beforeMediaItem;
         if (beforeMediaItemId != null) {
             beforeMediaItem = getMediaItem(beforeMediaItemId);
@@ -890,7 +1122,8 @@
             beforeMediaItem = null;
         }
 
-        final String afterMediaItemId = parser.getAttributeValue("", ATTR_AFTER_MEDIA_ITEM_ID);
+        final String afterMediaItemId = parser.getAttributeValue("",
+                                                      ATTR_AFTER_MEDIA_ITEM_ID);
         final MediaItem afterMediaItem;
         if (afterMediaItemId != null) {
             afterMediaItem = getMediaItem(afterMediaItemId);
@@ -927,9 +1160,22 @@
             afterMediaItem.setEndTransition(transition);
         }
 
+        isTransitionGenerated = Boolean.parseBoolean(parser.getAttributeValue("",
+                                                 ATTR_IS_TRANSITION_GENERATED));
+        if (isTransitionGenerated == true) {
+            final String transitionFile = parser.getAttributeValue("",
+                                                ATTR_GENERATED_TRANSITION_CLIP);
+
+            if (new File(transitionFile).exists() == true) {
+                transition.setFilename(transitionFile);
+            } else {
+                transition.setFilename(null);
+            }
+        }
         return transition;
     }
 
+
     /**
      * Parse the overlay
      *
@@ -941,17 +1187,36 @@
     private Overlay parseOverlay(XmlPullParser parser, MediaItem mediaItem) {
         final String overlayId = parser.getAttributeValue("", ATTR_ID);
         final String type = parser.getAttributeValue("", ATTR_TYPE);
-        final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION));
-        final long startTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME));
+        final long durationMs = Long.parseLong(parser.getAttributeValue("",
+                                                                ATTR_DURATION));
+        final long startTimeMs = Long.parseLong(parser.getAttributeValue("",
+                                                              ATTR_BEGIN_TIME));
 
         final Overlay overlay;
         if (OverlayFrame.class.getSimpleName().equals(type)) {
             final String filename = parser.getAttributeValue("", ATTR_FILENAME);
-            overlay = new OverlayFrame(mediaItem, overlayId, filename, startTimeMs, durationMs);
+            overlay = new OverlayFrame(mediaItem, overlayId, filename,
+                                       startTimeMs, durationMs);
         } else {
             overlay = null;
         }
 
+        final String overlayRgbFileName = parser.getAttributeValue("",
+                                                     ATTR_OVERLAY_RGB_FILENAME);
+        if (overlayRgbFileName != null) {
+            ((OverlayFrame)overlay).setFilename(overlayRgbFileName);
+
+            final int overlayFrameWidth =
+                                   Integer.parseInt(parser.getAttributeValue("",
+                                   ATTR_OVERLAY_FRAME_WIDTH));
+            final int overlayFrameHeight =
+                                   Integer.parseInt(parser.getAttributeValue("",
+                                   ATTR_OVERLAY_FRAME_HEIGHT));
+
+            ((OverlayFrame)overlay).setOverlayFrameWidth(overlayFrameWidth);
+            ((OverlayFrame)overlay).setOverlayFrameHeight(overlayFrameHeight);
+        }
+
         return overlay;
     }
 
@@ -966,35 +1231,47 @@
     private Effect parseEffect(XmlPullParser parser, MediaItem mediaItem) {
         final String effectId = parser.getAttributeValue("", ATTR_ID);
         final String type = parser.getAttributeValue("", ATTR_TYPE);
-        final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION));
-        final long startTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME));
+        final long durationMs = Long.parseLong(parser.getAttributeValue("",
+                                                                ATTR_DURATION));
+        final long startTimeMs = Long.parseLong(parser.getAttributeValue("",
+                                                              ATTR_BEGIN_TIME));
 
         final Effect effect;
         if (EffectColor.class.getSimpleName().equals(type)) {
             final int colorEffectType =
-                Integer.parseInt(parser.getAttributeValue("", ATTR_COLOR_EFFECT_TYPE));
+                Integer.parseInt(parser.getAttributeValue("",
+                                                       ATTR_COLOR_EFFECT_TYPE));
             final int color;
             if (colorEffectType == EffectColor.TYPE_COLOR
                     || colorEffectType == EffectColor.TYPE_GRADIENT) {
-                color = Integer.parseInt(parser.getAttributeValue("", ATTR_COLOR_EFFECT_VALUE));
+                color = Integer.parseInt(parser.getAttributeValue("",
+                                                      ATTR_COLOR_EFFECT_VALUE));
             } else {
                 color = 0;
             }
-            effect = new EffectColor(mediaItem, effectId, startTimeMs, durationMs,
-                    colorEffectType, color);
+            effect = new EffectColor(mediaItem, effectId, startTimeMs,
+                    durationMs, colorEffectType, color);
         } else if (EffectKenBurns.class.getSimpleName().equals(type)) {
             final Rect startRect = new Rect(
-                    Integer.parseInt(parser.getAttributeValue("", ATTR_START_RECT_L)),
-                    Integer.parseInt(parser.getAttributeValue("", ATTR_START_RECT_T)),
-                    Integer.parseInt(parser.getAttributeValue("", ATTR_START_RECT_R)),
-                    Integer.parseInt(parser.getAttributeValue("", ATTR_START_RECT_B)));
+                    Integer.parseInt(parser.getAttributeValue("",
+                                                         ATTR_START_RECT_LEFT)),
+                    Integer.parseInt(parser.getAttributeValue("",
+                                                          ATTR_START_RECT_TOP)),
+                    Integer.parseInt(parser.getAttributeValue("",
+                                                        ATTR_START_RECT_RIGHT)),
+                    Integer.parseInt(parser.getAttributeValue("",
+                                                      ATTR_START_RECT_BOTTOM)));
             final Rect endRect = new Rect(
-                    Integer.parseInt(parser.getAttributeValue("", ATTR_END_RECT_L)),
-                    Integer.parseInt(parser.getAttributeValue("", ATTR_END_RECT_T)),
-                    Integer.parseInt(parser.getAttributeValue("", ATTR_END_RECT_R)),
-                    Integer.parseInt(parser.getAttributeValue("", ATTR_END_RECT_B)));
-            effect = new EffectKenBurns(mediaItem, effectId, startRect, endRect, startTimeMs,
-                    durationMs);
+                    Integer.parseInt(parser.getAttributeValue("",
+                                                           ATTR_END_RECT_LEFT)),
+                    Integer.parseInt(parser.getAttributeValue("",
+                                                            ATTR_END_RECT_TOP)),
+                    Integer.parseInt(parser.getAttributeValue("",
+                                                          ATTR_END_RECT_RIGHT)),
+                    Integer.parseInt(parser.getAttributeValue("",
+                                                        ATTR_END_RECT_BOTTOM)));
+            effect = new EffectKenBurns(mediaItem, effectId, startRect, endRect,
+                                        startTimeMs, durationMs);
         } else {
             effect = null;
         }
@@ -1012,19 +1289,38 @@
     private AudioTrack parseAudioTrack(XmlPullParser parser) {
         final String audioTrackId = parser.getAttributeValue("", ATTR_ID);
         final String filename = parser.getAttributeValue("", ATTR_FILENAME);
-        final long startTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_START_TIME));
-        final long beginMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME));
-        final long endMs = Long.parseLong(parser.getAttributeValue("", ATTR_END_TIME));
-        final int volume = Integer.parseInt(parser.getAttributeValue("", ATTR_VOLUME));
-        final boolean muted = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_MUTED));
-        final boolean loop = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_LOOP));
-        final boolean duckingEnabled = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_DUCK_ENABLED));
-        final int duckThreshold = Integer.parseInt(parser.getAttributeValue("", ATTR_DUCK_THRESHOLD));
-        final int duckedTrackVolume = Integer.parseInt(parser.getAttributeValue("", ATTR_DUCKED_TRACK_VOLUME));
-        final String waveformFilename = parser.getAttributeValue("", ATTR_AUDIO_WAVEFORM_FILENAME);
+        final long startTimeMs = Long.parseLong(parser.getAttributeValue("",
+                                                              ATTR_START_TIME));
+        final long beginMs = Long.parseLong(parser.getAttributeValue("",
+                                                              ATTR_BEGIN_TIME));
+        final long endMs = Long.parseLong(parser.getAttributeValue("",
+                                                                ATTR_END_TIME));
+        final int volume = Integer.parseInt(parser.getAttributeValue("",
+                                                                  ATTR_VOLUME));
+        final boolean muted = Boolean.parseBoolean(parser.getAttributeValue("",
+                                                                   ATTR_MUTED));
+        final boolean loop = Boolean.parseBoolean(parser.getAttributeValue("",
+                                                                    ATTR_LOOP));
+        final boolean duckingEnabled =
+                               Boolean.parseBoolean(parser.getAttributeValue("",
+                                                    ATTR_DUCK_ENABLED));
+        final int duckThreshold = Integer.parseInt(parser.getAttributeValue("",
+                                                          ATTR_DUCK_THRESHOLD));
+        final int duckedTrackVolume =
+                                   Integer.parseInt(parser.getAttributeValue("",
+                                                     ATTR_DUCKED_TRACK_VOLUME));
+
+        final String waveformFilename = parser.getAttributeValue("",
+                                                  ATTR_AUDIO_WAVEFORM_FILENAME);
         try {
-            final AudioTrack audioTrack = new AudioTrack(this, audioTrackId, filename, startTimeMs,
-                    beginMs, endMs, loop, volume, muted, duckingEnabled, duckThreshold, duckedTrackVolume, waveformFilename);
+            final AudioTrack audioTrack = new AudioTrack(this, audioTrackId,
+                                                         filename, startTimeMs,
+                                                         beginMs, endMs, loop,
+                                                         volume, muted,
+                                                         duckingEnabled,
+                                                         duckThreshold,
+                                                         duckedTrackVolume,
+                                                         waveformFilename);
 
             return audioTrack;
         } catch (IOException ex) {
@@ -1032,64 +1328,244 @@
         }
     }
 
-    /*
-     * {@inheritDoc}
-     */
-    public void cancelExport(String filename) {
-    }
 
     /*
      * {@inheritDoc}
      */
-    public void export(String filename, int height, int bitrate, ExportProgressListener listener)
-            throws IOException {
-    }
+    public void save() throws IOException {
+        final XmlSerializer serializer = Xml.newSerializer();
+        final StringWriter writer = new StringWriter();
+        serializer.setOutput(writer);
+        serializer.startDocument("UTF-8", true);
+        serializer.startTag("", TAG_PROJECT);
+        serializer.attribute("",
+                             ATTR_ASPECT_RATIO, Integer.toString(mAspectRatio));
+        serializer.attribute("", ATTR_PREVIEW_PREPARE,
+                        Boolean.toString(mMANativeHelper.getGeneratePreview()));
 
-    /*
-     * {@inheritDoc}
-     */
-    public void export(String filename, int height, int bitrate, int audioCodec, int videoCodec,
-            ExportProgressListener listener) throws IOException {
-    }
+        serializer.attribute("", ATTR_REGENERATE_PCM,
+                        Boolean.toString(mMANativeHelper.getAudioflag()));
 
-    /*
-     * {@inheritDoc}
-     */
-    public void generatePreview(MediaProcessingProgressListener listener) {
-        // Generate all the needed transitions
-        for (Transition transition : mTransitions) {
-            if (!transition.isGenerated()) {
-                transition.generate();
+        serializer.startTag("", TAG_MEDIA_ITEMS);
+        for (MediaItem mediaItem : mMediaItems) {
+            serializer.startTag("", TAG_MEDIA_ITEM);
+            serializer.attribute("", ATTR_ID, mediaItem.getId());
+            serializer.attribute("", ATTR_TYPE,
+                                          mediaItem.getClass().getSimpleName());
+            serializer.attribute("", ATTR_FILENAME, mediaItem.getFilename());
+            serializer.attribute("", ATTR_RENDERING_MODE, Integer.toString(
+                    mediaItem.getRenderingMode()));
+            if (mediaItem instanceof MediaVideoItem) {
+                final MediaVideoItem mvi = (MediaVideoItem)mediaItem;
+                serializer
+                .attribute("", ATTR_BEGIN_TIME,
+                                     Long.toString(mvi.getBoundaryBeginTime()));
+                serializer.attribute("", ATTR_END_TIME,
+                                       Long.toString(mvi.getBoundaryEndTime()));
+                serializer.attribute("", ATTR_VOLUME,
+                                             Integer.toString(mvi.getVolume()));
+                serializer.attribute("", ATTR_MUTED,
+                                               Boolean.toString(mvi.isMuted()));
+                if (mvi.getAudioWaveformFilename() != null) {
+                    serializer.attribute("", ATTR_AUDIO_WAVEFORM_FILENAME,
+                            mvi.getAudioWaveformFilename());
+                }
+            } else if (mediaItem instanceof MediaImageItem) {
+                serializer.attribute("", ATTR_DURATION,
+                        Long.toString(mediaItem.getTimelineDuration()));
             }
+
+            final List<Overlay> overlays = mediaItem.getAllOverlays();
+            if (overlays.size() > 0) {
+                serializer.startTag("", TAG_OVERLAYS);
+                for (Overlay overlay : overlays) {
+                    serializer.startTag("", TAG_OVERLAY);
+                    serializer.attribute("", ATTR_ID, overlay.getId());
+                    serializer.attribute("",
+                                 ATTR_TYPE, overlay.getClass().getSimpleName());
+                    serializer.attribute("", ATTR_BEGIN_TIME,
+                                         Long.toString(overlay.getStartTime()));
+                    serializer.attribute("", ATTR_DURATION,
+                                          Long.toString(overlay.getDuration()));
+                    if (overlay instanceof OverlayFrame) {
+                        final OverlayFrame overlayFrame = (OverlayFrame)overlay;
+                        overlayFrame.save(getPath());
+                        if (overlayFrame.getBitmapImageFileName() != null) {
+                            serializer.attribute("", ATTR_FILENAME,
+                                         overlayFrame.getBitmapImageFileName());
+                        }
+
+                        if (overlayFrame.getFilename() != null) {
+                            serializer.attribute("",
+                                                 ATTR_OVERLAY_RGB_FILENAME,
+                                                 overlayFrame.getFilename());
+                            serializer.attribute("", ATTR_OVERLAY_FRAME_WIDTH,
+                                                 Integer.toString(overlayFrame.getOverlayFrameWidth()));
+                            serializer.attribute("", ATTR_OVERLAY_FRAME_HEIGHT,
+                                                 Integer.toString(overlayFrame.getOverlayFrameHeight()));
+                        }
+
+                    }
+
+                    /**
+                     *  Save the user attributes
+                     */
+                    serializer.startTag("", TAG_OVERLAY_USER_ATTRIBUTES);
+                    final Map<String, String> userAttributes = overlay.getUserAttributes();
+                    for (String name : userAttributes.keySet()) {
+                        final String value = userAttributes.get(name);
+                        if (value != null) {
+                            serializer.attribute("", name, value);
+                        }
+                    }
+                    serializer.endTag("", TAG_OVERLAY_USER_ATTRIBUTES);
+
+                    serializer.endTag("", TAG_OVERLAY);
+                }
+                serializer.endTag("", TAG_OVERLAYS);
+            }
+
+            final List<Effect> effects = mediaItem.getAllEffects();
+            if (effects.size() > 0) {
+                serializer.startTag("", TAG_EFFECTS);
+                for (Effect effect : effects) {
+                    serializer.startTag("", TAG_EFFECT);
+                    serializer.attribute("", ATTR_ID, effect.getId());
+                    serializer.attribute("",
+                                  ATTR_TYPE, effect.getClass().getSimpleName());
+                    serializer.attribute("", ATTR_BEGIN_TIME,
+                            Long.toString(effect.getStartTime()));
+                    serializer.attribute("", ATTR_DURATION,
+                                           Long.toString(effect.getDuration()));
+                    if (effect instanceof EffectColor) {
+                        final EffectColor colorEffect = (EffectColor)effect;
+                        serializer.attribute("", ATTR_COLOR_EFFECT_TYPE,
+                                Integer.toString(colorEffect.getType()));
+                        if (colorEffect.getType() == EffectColor.TYPE_COLOR ||
+                                colorEffect.getType() == EffectColor.TYPE_GRADIENT) {
+                            serializer.attribute("", ATTR_COLOR_EFFECT_VALUE,
+                                    Integer.toString(colorEffect.getColor()));
+                        }
+                    } else if (effect instanceof EffectKenBurns) {
+                        final Rect startRect = ((EffectKenBurns)effect).getStartRect();
+                        serializer.attribute("", ATTR_START_RECT_LEFT,
+                                Integer.toString(startRect.left));
+                        serializer.attribute("", ATTR_START_RECT_TOP,
+                                Integer.toString(startRect.top));
+                        serializer.attribute("", ATTR_START_RECT_RIGHT,
+                                Integer.toString(startRect.right));
+                        serializer.attribute("", ATTR_START_RECT_BOTTOM,
+                                Integer.toString(startRect.bottom));
+
+                        final Rect endRect = ((EffectKenBurns)effect).getEndRect();
+                        serializer.attribute("", ATTR_END_RECT_LEFT,
+                                                Integer.toString(endRect.left));
+                        serializer.attribute("", ATTR_END_RECT_TOP,
+                                                 Integer.toString(endRect.top));
+                        serializer.attribute("", ATTR_END_RECT_RIGHT,
+                                               Integer.toString(endRect.right));
+                        serializer.attribute("", ATTR_END_RECT_BOTTOM,
+                                Integer.toString(endRect.bottom));
+                        final MediaItem mItem = effect.getMediaItem();
+                        serializer.attribute("", ATTR_GENERATED_IMAGE_CLIP,
+                               ((MediaImageItem)mItem).getGeneratedImageClip());
+                    }
+
+                    serializer.endTag("", TAG_EFFECT);
+                }
+                serializer.endTag("", TAG_EFFECTS);
+            }
+
+            serializer.endTag("", TAG_MEDIA_ITEM);
         }
+        serializer.endTag("", TAG_MEDIA_ITEMS);
 
-        // This is necessary because the user may had called setDuration on
-        // MediaImageItems
-        computeTimelineDuration();
-    }
+        serializer.startTag("", TAG_TRANSITIONS);
 
-    /*
-     * {@inheritDoc}
-     */
-    public void release() {
-        stopPreview();
-    }
+        for (Transition transition : mTransitions) {
+            serializer.startTag("", TAG_TRANSITION);
+            serializer.attribute("", ATTR_ID, transition.getId());
+            serializer.attribute("", ATTR_TYPE,
+                                         transition.getClass().getSimpleName());
+            serializer.attribute("", ATTR_DURATION,
+                                       Long.toString(transition.getDuration()));
+            serializer.attribute("", ATTR_BEHAVIOR,
+                                    Integer.toString(transition.getBehavior()));
+            serializer.attribute("", ATTR_IS_TRANSITION_GENERATED,
+                                    Boolean.toString(transition.isGenerated()));
+            if (transition.isGenerated() == true) {
+                serializer.attribute("", ATTR_GENERATED_TRANSITION_CLIP,
+                                                          transition.mFilename);
+            }
+            final MediaItem afterMediaItem = transition.getAfterMediaItem();
+            if (afterMediaItem != null) {
+                serializer.attribute("", ATTR_AFTER_MEDIA_ITEM_ID,
+                                                        afterMediaItem.getId());
+            }
 
-    /*
-     * {@inheritDoc}
-     */
-    public long getDuration() {
-        // Since MediaImageItem can change duration we need to compute the
-        // duration here
-        computeTimelineDuration();
-        return mDurationMs;
-    }
+            final MediaItem beforeMediaItem = transition.getBeforeMediaItem();
+            if (beforeMediaItem != null) {
+                serializer.attribute("", ATTR_BEFORE_MEDIA_ITEM_ID,
+                                                       beforeMediaItem.getId());
+            }
 
-    /*
-     * {@inheritDoc}
-     */
-    public int getAspectRatio() {
-        return mAspectRatio;
+            if (transition instanceof TransitionSliding) {
+                serializer.attribute("", ATTR_DIRECTION,
+                        Integer.toString(((TransitionSliding)transition).getDirection()));
+            } else if (transition instanceof TransitionAlpha) {
+                TransitionAlpha ta = (TransitionAlpha)transition;
+                serializer.attribute("", ATTR_BLENDING,
+                                     Integer.toString(ta.getBlendingPercent()));
+                serializer.attribute("", ATTR_INVERT,
+                                               Boolean.toString(ta.isInvert()));
+                if (ta.getMaskFilename() != null) {
+                    serializer.attribute("", ATTR_MASK, ta.getMaskFilename());
+                }
+            }
+            serializer.endTag("", TAG_TRANSITION);
+        }
+        serializer.endTag("", TAG_TRANSITIONS);
+        serializer.startTag("", TAG_AUDIO_TRACKS);
+        for (AudioTrack at : mAudioTracks) {
+            serializer.startTag("", TAG_AUDIO_TRACK);
+            serializer.attribute("", ATTR_ID, at.getId());
+            serializer.attribute("", ATTR_FILENAME, at.getFilename());
+            serializer.attribute("", ATTR_START_TIME,
+                                              Long.toString(at.getStartTime()));
+            serializer.attribute("", ATTR_BEGIN_TIME,
+                                      Long.toString(at.getBoundaryBeginTime()));
+            serializer.attribute("", ATTR_END_TIME,
+                                        Long.toString(at.getBoundaryEndTime()));
+            serializer.attribute("", ATTR_VOLUME,
+                                              Integer.toString(at.getVolume()));
+            serializer.attribute("", ATTR_DUCK_ENABLED,
+                                       Boolean.toString(at.isDuckingEnabled()));
+            serializer.attribute("", ATTR_DUCKED_TRACK_VOLUME,
+                                   Integer.toString(at.getDuckedTrackVolume()));
+            serializer.attribute("", ATTR_DUCK_THRESHOLD,
+                                   Integer.toString(at.getDuckingThreshhold()));
+            serializer.attribute("", ATTR_MUTED, Boolean.toString(at.isMuted()));
+            serializer.attribute("", ATTR_LOOP, Boolean.toString(at.isLooping()));
+            if (at.getAudioWaveformFilename() != null) {
+                serializer.attribute("", ATTR_AUDIO_WAVEFORM_FILENAME,
+                        at.getAudioWaveformFilename());
+            }
+
+            serializer.endTag("", TAG_AUDIO_TRACK);
+        }
+        serializer.endTag("", TAG_AUDIO_TRACKS);
+
+        serializer.endTag("", TAG_PROJECT);
+        serializer.endDocument();
+
+        /**
+         *  Save the metadata XML file
+         */
+        final FileOutputStream out = new FileOutputStream(new File(getPath(),
+                                                          PROJECT_FILENAME));
+        out.write(writer.toString().getBytes());
+        out.flush();
+        out.close();
     }
 
     /*
@@ -1097,7 +1573,9 @@
      */
     public void setAspectRatio(int aspectRatio) {
         mAspectRatio = aspectRatio;
-
+        /**
+         *  Invalidate all transitions
+         */
         for (Transition transition : mTransitions) {
             transition.invalidate();
         }
@@ -1106,53 +1584,83 @@
     /*
      * {@inheritDoc}
      */
-    public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs) {
-        if (mPreviewThread != null) {
-            throw new IllegalStateException("Previewing is in progress");
-        }
-        return timeMs;
-    }
+    public void startPreview(SurfaceHolder surfaceHolder, long fromMs, long toMs,
+                             boolean loop, int callbackAfterFrameCount,
+                             PreviewProgressListener listener) {
 
-    /*
-     * {@inheritDoc}
-     */
-    public synchronized void startPreview(SurfaceHolder surfaceHolder, long fromMs, long toMs,
-            boolean loop, int callbackAfterFrameCount, PreviewProgressListener listener) {
+        if (surfaceHolder == null) {
+            throw new IllegalArgumentException();
+        }
+        if (listener == null) {
+            throw new IllegalArgumentException();
+        }
         if (fromMs >= mDurationMs) {
-            return;
+            throw new IllegalArgumentException("requested time not correct");
         }
-        mPreviewThread = new PreviewThread(fromMs, toMs, loop, callbackAfterFrameCount, listener);
-        mPreviewThread.start();
-    }
 
-    /*
-     * {@inheritDoc}
-     */
-    public synchronized long stopPreview() {
-        final long stopTimeMs;
-        if (mPreviewThread != null) {
-            stopTimeMs = mPreviewThread.stopPreview();
-            mPreviewThread = null;
-        } else {
-            stopTimeMs = 0;
+        if (fromMs < 0) {
+            throw new IllegalArgumentException("requested time not correct");
         }
-        return stopTimeMs;
-    }
 
-    /**
-     * Compute the duration
-     */
-    private void computeTimelineDuration() {
-        mDurationMs = 0;
-        final int mediaItemsCount = mMediaItems.size();
-        for (int i = 0; i < mediaItemsCount; i++) {
-            final MediaItem mediaItem = mMediaItems.get(i);
-            mDurationMs += mediaItem.getTimelineDuration();
-            if (mediaItem.getEndTransition() != null) {
-                if (i < mediaItemsCount - 1) {
-                    mDurationMs -= mediaItem.getEndTransition().getDuration();
+        boolean semAcquireDone = false;
+        try{
+            mPreviewSemaphore.acquire();
+            semAcquireDone = true;
+        } catch (InterruptedException  ex) {
+            Log.e("VideoEditorImpl", "Sem acquire NOT successful in startPreview");
+        }
+
+        if (semAcquireDone) {
+            Surface mSurface = surfaceHolder.getSurface();
+
+            if (mSurface == null) {
+                Log.e("VideoEditoeImpl",
+                "Surface could not be retrieved from surface holder"); throw new
+                RuntimeException();
+            }
+
+            if (mMediaItems.size() > 0) {
+                try {
+                    mMANativeHelper.previewStoryBoard(mMediaItems, mTransitions,
+                                                      mAudioTracks, null);
+                    mMANativeHelper.doPreview(mSurface, fromMs, toMs, loop,
+                                             callbackAfterFrameCount, listener);
+                    mPreviewInProgress = true;
+                } catch (IllegalArgumentException ex) {
+                    mPreviewSemaphore.release();
+                    Log.e("VideoEditorImpl", "Illegal Argument exception in do preview");
+                    throw ex;
+                } catch (IllegalStateException ex) {
+                    mPreviewSemaphore.release();
+                    Log.e("VideoEditorImpl", "Illegal State exception in do preview");
+                    throw ex;
+                } catch (RuntimeException ex) {
+                    mPreviewSemaphore.release();
+                    Log.e("VideoEditorImpl", "Runtime exception in do preview");
+                    throw ex;
                 }
             }
+            /**
+             *  release on complete by calling stopPreview
+             */
+        }
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    public long stopPreview() {
+        if (mPreviewInProgress) {
+            long result = mMANativeHelper.stopPreview();
+            mPreviewInProgress = false;
+            /**
+             *  release the sem acquired in startPreview
+             */
+            mPreviewSemaphore.release();
+            return result;
+        }
+        else {
+            return 0;
         }
     }
 
@@ -1209,7 +1717,7 @@
     /**
      * Remove the transition after this media item
      *
-     * @param index The media item index
+     * @param mediaItem The media item
      */
     private void removeTransitionAfter(int index) {
         final MediaItem mediaItem = mMediaItems.get(index);
@@ -1220,7 +1728,9 @@
                 it.remove();
                 t.invalidate();
                 mediaItem.setEndTransition(null);
-                // Invalidate the reference in the next media item
+                /**
+                 *  Invalidate the reference in the next media item
+                 */
                 if (index < mMediaItems.size() - 1) {
                     mMediaItems.get(index + 1).setBeginTransition(null);
                 }
@@ -1228,4 +1738,82 @@
             }
         }
     }
+
+    /**
+     * Compute the duration
+     */
+    private void computeTimelineDuration() {
+        mDurationMs = 0;
+        final int mediaItemsCount = mMediaItems.size();
+        for (int i = 0; i < mediaItemsCount; i++) {
+            final MediaItem mediaItem = mMediaItems.get(i);
+            mDurationMs += mediaItem.getTimelineDuration();
+            if (mediaItem.getEndTransition() != null) {
+                if (i < mediaItemsCount - 1) {
+                    mDurationMs -= mediaItem.getEndTransition().getDuration();
+                }
+            }
+        }
+    }
+
+    /*
+     * Generate the project thumbnail
+     */
+    private void generateProjectThumbnail() {
+        /*
+         * If a thumbnail already exists, then delete it first
+         */
+        if ((new File(mProjectPath + "/" + THUMBNAIL_FILENAME)).exists()) {
+            (new File(mProjectPath + "/" + THUMBNAIL_FILENAME)).delete();
+        }
+        /*
+         * Generate a new thumbnail for the project from first media Item
+         */
+        if (mMediaItems.size() > 0) {
+            MediaItem mI = mMediaItems.get(0);
+            /*
+             * Lets initialise the width for default aspect ratio i.e 16:9
+             */
+            int height = 480;
+            int width = 854;
+            switch (getAspectRatio()) {
+                case MediaProperties.ASPECT_RATIO_3_2:
+                    width =  720;
+                    break;
+                case MediaProperties.ASPECT_RATIO_4_3:
+                    width =  640;
+                    break;
+                case MediaProperties.ASPECT_RATIO_5_3:
+                    width =  800;
+                    break;
+                case MediaProperties.ASPECT_RATIO_11_9:
+                    width =  586;
+                    break;
+                case MediaProperties.ASPECT_RATIO_16_9:
+                case MediaProperties.ASPECT_RATIO_UNDEFINED:
+                    break;
+            }
+
+            Bitmap projectBitmap = null;
+            try {
+                projectBitmap = mI.getThumbnail(width, height, 500);
+            } catch (IllegalArgumentException e) {
+                throw new IllegalArgumentException ("Illegal Argument Error creating project thumbnail");
+            } catch (IOException e) {
+                throw new IllegalArgumentException ("IO Error creating project thumbnail");
+            }
+            try {
+                FileOutputStream stream = new FileOutputStream(mProjectPath + "/"
+                                                          + THUMBNAIL_FILENAME);
+                projectBitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
+                stream.flush();
+                stream.close();
+            } catch (IOException e) {
+
+                throw new IllegalArgumentException ("Error creating project thumbnail");
+            } finally {
+                projectBitmap.recycle();
+            }
+        }
+    }
 }
diff --git a/media/java/android/media/videoeditor/WaveformData.java b/media/java/android/media/videoeditor/WaveformData.java
old mode 100644
new mode 100755
index 1b865ca..6c10e3c
--- a/media/java/android/media/videoeditor/WaveformData.java
+++ b/media/java/android/media/videoeditor/WaveformData.java
@@ -14,24 +14,29 @@
  * limitations under the License.
  */
 
+
 package android.media.videoeditor;
 
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 
 /**
  * Class which describes the waveform data of an audio track. The gain values
- * represent the average gain for an audio frame. For audio codecs which do
- * not operate on a per frame bases (eg. ALAW, ULAW) a reasonable audio frame
+ * represent the average gain for an audio frame. For audio codecs which do not
+ * operate on a per frame bases (eg. ALAW, ULAW) a reasonable audio frame
  * duration will be assumed (eg. 50ms).
  * {@hide}
  */
 public class WaveformData {
-    // Instance variables
+    /*
+     *  Instance variables
+     */
     private final int mFrameDurationMs;
     private final int mFramesCount;
     private final short[] mGains;
 
-    /**
+    /*
      * This constructor shall not be used
      */
     @SuppressWarnings("unused")
@@ -41,18 +46,74 @@
         mGains = null;
     }
 
-    /**
+    /*
      * Constructor
      *
      * @param audioWaveformFilename The name of the audio waveform file
+     *
+     * The file format is as following:
+     * <ul>
+     *  <li>first 4 bytes provide the number of samples for each value, as
+     *  big-endian signed</li>
+     *  <li>4 following bytes is the total number of values in the file, as
+     *  big-endian signed</li>
+     *  <li>then, all values follow as bytes</li>
+     * </ul>
+     *
+     * @throws IOException on failure of file input stream operations
+     * @throws IllegalArgumentException if audioWaveformFilename is null
      */
     WaveformData(String audioWaveformFilename) throws IOException {
-        // TODO: Read these values from the file
-        mFrameDurationMs = 20;
-        mFramesCount = 300000 / mFrameDurationMs;
-        mGains = new short[mFramesCount];
-        for (int i = 0; i < mFramesCount; i++) {
-            mGains[i] = (short)((i * 5) % 256);
+
+        if (audioWaveformFilename == null) {
+            throw new IllegalArgumentException("WaveformData : filename is null");
+        }
+
+        FileInputStream audioGraphFileReadHandle = null;
+
+        try {
+            final File audioGraphFileContext = new File(audioWaveformFilename);
+
+            audioGraphFileReadHandle = new FileInputStream(audioGraphFileContext);
+            /*
+             * Read frame duration
+             */
+            final byte tempFrameDuration[] = new byte[4];
+
+            audioGraphFileReadHandle.read(tempFrameDuration, 0, 4);
+
+            int tempFrameDurationMs = 0;
+            int tempFramesCounter = 0;
+            for (int i = 0; i < 4; i++) {
+                tempFrameDurationMs = (tempFrameDurationMs << 8);
+                tempFrameDurationMs = (tempFrameDurationMs | (tempFrameDuration[i] & 0xff));
+            }
+            mFrameDurationMs = tempFrameDurationMs;
+
+            /*
+             * Read count
+             */
+            final byte tempFramesCount[] = new byte[4];
+
+            audioGraphFileReadHandle.read(tempFramesCount, 0, 4);
+            for (int i = 0; i < 4; i++) {
+                tempFramesCounter = (tempFramesCounter << 8);
+                tempFramesCounter = (tempFramesCounter | (tempFramesCount[i] & 0xff));
+            }
+            mFramesCount = tempFramesCounter;
+
+            /*
+             *  Capture the graph values
+             */
+            mGains = new short[mFramesCount];
+
+            for (int i = 0; i < mFramesCount; i++) {
+                mGains[i] = (short)audioGraphFileReadHandle.read();
+            }
+        } finally {
+            if (audioGraphFileReadHandle != null) {
+                audioGraphFileReadHandle.close();
+            }
         }
     }
 
@@ -72,7 +133,7 @@
 
     /**
      * @return The array of frame gains. The size of the array is the frames
-     *  count. The values of the frame gains range from 0 to 256.
+     *         count. The values of the frame gains range from 0 to 255.
      */
     public short[] getFrameGains() {
         return mGains;
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index ac476ff..abc457e 100644
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -185,7 +185,7 @@
         }
     }
 
-    private void endSendObject(String path, int handle, int format, long actualSize, boolean succeeded) {
+    private void endSendObject(String path, int handle, int format, boolean succeeded) {
         if (succeeded) {
             // handle abstract playlists separately
             // they do not exist in the file system so don't use the media scanner here
@@ -196,11 +196,16 @@
                 if (lastSlash >= 0) {
                     name = name.substring(lastSlash + 1);
                 }
+                // strip trailing ".pla" from the name
+                if (name.endsWith(".pla")) {
+                    name = name.substring(0, name.length() - 4);
+                }
 
                 ContentValues values = new ContentValues(1);
                 values.put(Audio.Playlists.DATA, path);
                 values.put(Audio.Playlists.NAME, name);
                 values.put(Files.FileColumns.FORMAT, format);
+                values.put(Files.FileColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
                 values.put(MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, handle);
                 try {
                     Uri uri = mMediaProvider.insert(Audio.Playlists.EXTERNAL_CONTENT_URI, values);
@@ -208,18 +213,6 @@
                     Log.e(TAG, "RemoteException in endSendObject", e);
                 }
             } else {
-                if (actualSize >= 0) {
-                    // update size if necessary
-                    ContentValues values = new ContentValues();
-                    values.put(Files.FileColumns.SIZE, actualSize);
-                    try {
-                        String[] whereArgs = new String[] {  Integer.toString(handle) };
-                        mMediaProvider.update(mObjectsUri, values, ID_WHERE, whereArgs);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "RemoteException in mMediaProvider.update", e);
-                    }
-                }
-
                 mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
             }
         } else {
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 8f9b8a2..9abf6a2 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -99,7 +99,6 @@
     virtual void                    endSendObject(const char* path,
                                             MtpObjectHandle handle,
                                             MtpObjectFormat format,
-                                            int64_t actualSize,
                                             bool succeeded);
 
     virtual MtpObjectHandleList*    getObjectList(MtpStorageID storageID,
@@ -236,11 +235,11 @@
 }
 
 void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
-                                MtpObjectFormat format, int64_t actualSize, bool succeeded) {
+                                MtpObjectFormat format, bool succeeded) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jstring pathStr = env->NewStringUTF(path);
     env->CallVoidMethod(mDatabase, method_endSendObject, pathStr,
-                        (jint)handle, (jint)format, (jlong)actualSize, (jboolean)succeeded);
+                        (jint)handle, (jint)format, (jboolean)succeeded);
 
     if (pathStr)
         env->DeleteLocalRef(pathStr);
@@ -1094,7 +1093,7 @@
         LOGE("Can't find beginSendObject");
         return -1;
     }
-    method_endSendObject = env->GetMethodID(clazz, "endSendObject", "(Ljava/lang/String;IIJZ)V");
+    method_endSendObject = env->GetMethodID(clazz, "endSendObject", "(Ljava/lang/String;IIZ)V");
     if (method_endSendObject == NULL) {
         LOGE("Can't find endSendObject");
         return -1;
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index 241f18a..8908e67 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -62,6 +62,7 @@
     String8         mStoragePath;
     uint64_t        mReserveSpace;
     jobject         mJavaServer;
+    bool            mDone;
     int             mFd;
 
 public:
@@ -72,6 +73,7 @@
             mStoragePath(storagePath),
             mReserveSpace(reserveSpace),
             mJavaServer(javaServer),
+            mDone(false),
             mFd(-1)
     {
     }
@@ -94,27 +96,33 @@
 
     virtual bool threadLoop() {
         sMutex.lock();
-        mFd = open("/dev/mtp_usb", O_RDWR);
-        printf("open returned %d\n", mFd);
-        if (mFd < 0) {
-            LOGE("could not open MTP driver\n");
+
+        while (!mDone) {
+            mFd = open("/dev/mtp_usb", O_RDWR);
+            printf("open returned %d\n", mFd);
+            if (mFd < 0) {
+                LOGE("could not open MTP driver\n");
+                sMutex.unlock();
+                return false;
+            }
+
+            mServer = new MtpServer(mFd, mDatabase, AID_MEDIA_RW, 0664, 0775);
+            mServer->addStorage(mStoragePath, mReserveSpace);
+
             sMutex.unlock();
-            return false;
+
+            LOGD("MtpThread mServer->run");
+            mServer->run();
+            sleep(1);
+
+            sMutex.lock();
+
+            close(mFd);
+            mFd = -1;
+            delete mServer;
+            mServer = NULL;
         }
 
-        mServer = new MtpServer(mFd, mDatabase, AID_MEDIA_RW, 0664, 0775);
-        mServer->addStorage(mStoragePath, mReserveSpace);
-        sMutex.unlock();
-
-        LOGD("MtpThread mServer->run");
-        mServer->run();
-
-        sMutex.lock();
-        close(mFd);
-        mFd = -1;
-        delete mServer;
-        mServer = NULL;
-
         JNIEnv* env = AndroidRuntime::getJNIEnv();
         env->SetIntField(mJavaServer, field_context, 0);
         env->DeleteGlobalRef(mJavaServer);
@@ -124,6 +132,12 @@
         return false;
     }
 
+    void stop() {
+        sMutex.lock();
+        mDone = true;
+        sMutex.unlock();
+    }
+
     void sendObjectAdded(MtpObjectHandle handle) {
         sMutex.lock();
         if (mServer)
@@ -181,6 +195,9 @@
 {
 #ifdef HAVE_ANDROID_OS
     LOGD("stop\n");
+    MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
+    if (thread)
+        thread->stop();
 #endif
 }
 
@@ -212,7 +229,7 @@
     MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
     if (thread)
         thread->setPtpMode(usePtp);
- #endif
+#endif
 }
 
 // ----------------------------------------------------------------------------
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
new file mode 100755
index 0000000..27c41be
--- /dev/null
+++ b/media/jni/mediaeditor/Android.mk
@@ -0,0 +1,90 @@
+#
+# Copyright (C) 2011 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    VideoEditorMain.cpp \
+    VideoEditorClasses.cpp \
+    VideoEditorOsal.cpp \
+    VideoEditorJava.cpp \
+    VideoEditorPropertiesMain.cpp \
+    VideoEditorThumbnailMain.cpp  \
+    VideoBrowserMain.c
+
+LOCAL_C_INCLUDES += \
+    $(TOP)/frameworks/base/core/jni \
+    $(TOP)/frameworks/base/include \
+    $(TOP)/frameworks/base/include/media \
+    $(TOP)/frameworks/base/media/libmediaplayerservice \
+    $(TOP)/frameworks/base/media/libstagefright \
+    $(TOP)/frameworks/base/media/libstagefright/include \
+    $(TOP)/frameworks/base/media/libstagefright/rtsp \
+    $(JNI_H_INCLUDE) \
+    $(call include-path-for, corecg graphics) \
+    $(TOP)/frameworks/base/include/media/stagefright/openmax \
+    $(TOP)/frameworks/base/core/jni/mediaeditor \
+    $(TOP)/frameworks/media/libvideoeditor/vss/inc \
+    $(TOP)/frameworks/media/libvideoeditor/vss/common/inc \
+    $(TOP)/frameworks/media/libvideoeditor/vss/mcs/inc \
+    $(TOP)/frameworks/media/libvideoeditor/vss/stagefrightshells/inc \
+    $(TOP)/frameworks/media/libvideoeditor/lvpp \
+    $(TOP)/frameworks/media/libvideoeditor/osal/inc
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libutils \
+    libandroid_runtime \
+    libnativehelper \
+    libmedia \
+    libbinder \
+    libstagefright \
+    libstagefright_omx \
+    libsurfaceflinger_client \
+    libvideoeditorplayer
+
+
+LOCAL_CFLAGS += \
+    -DUSE_STAGEFRIGHT_CODECS \
+    -DUSE_STAGEFRIGHT_AUDIODEC \
+    -DUSE_STAGEFRIGHT_VIDEODEC \
+    -DUSE_STAGEFRIGHT_AUDIOENC \
+    -DUSE_STAGEFRIGHT_VIDEOENC \
+    -DUSE_STAGEFRIGHT_READERS \
+    -DUSE_STAGEFRIGHT_3GPP_READER
+
+
+LOCAL_LDFLAGS += -fuse-ld=bfd
+
+LOCAL_STATIC_LIBRARIES := \
+    libvideoeditor_core \
+    libstagefright_color_conversion \
+    libvideoeditor_3gpwriter \
+    libvideoeditor_mcs \
+    libvideoeditor_videofilters \
+    libvideoeditor_stagefrightshells \
+    libvideoeditor_osal
+
+LOCAL_MODULE:= libvideoeditor_jni
+
+# Don't prelink this library.  For more efficient code, you may want
+# to add this library to the prelink map and set this to true.
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_MODULE_TAGS := eng development
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/mediaeditor/VideoBrowserInternal.h b/media/jni/mediaeditor/VideoBrowserInternal.h
new file mode 100755
index 0000000..ed63129
--- /dev/null
+++ b/media/jni/mediaeditor/VideoBrowserInternal.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2011 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 VIDEO_BROWSER_INTERNAL_H
+#define VIDEO_BROWSER_INTERNAL_H
+
+#include "VideoBrowserMain.h"
+
+#include "M4READER_Common.h"
+#include "M4DECODER_Common.h"
+
+
+#define VIDEO_BROWSER_BGR565
+
+
+#define VIDEO_BROWSER_PREDECODE_TIME 2000    /* In miliseconds */
+
+/*---------------------------- MACROS ----------------------------*/
+#define CHECK_PTR(fct, p, err, errValue) \
+{ \
+    if (M4OSA_NULL == p) \
+    { \
+        err = errValue ; \
+        M4OSA_TRACE1_1("" #fct "(L%d): " #p " is NULL, returning " #errValue "", __LINE__) ; \
+        goto fct##_cleanUp; \
+    } \
+}
+
+#define CHECK_ERR(fct, err) \
+{ \
+    if (M4OSA_ERR_IS_ERROR(err)) \
+    { \
+        M4OSA_TRACE1_2("" #fct "(L%d): ERROR 0x%.8x returned", __LINE__,err) ; \
+        goto fct##_cleanUp; \
+    } \
+    else if (M4OSA_ERR_IS_WARNING(err)) \
+    { \
+        M4OSA_TRACE2_2("" #fct "(L%d): WARNING 0x%.8x returned", __LINE__,err) ; \
+    } \
+}
+
+#define CHECK_STATE(fct, state, pC) \
+{ \
+    if (state != pC->m_state) \
+    { \
+        M4OSA_TRACE1_1("" #fct " called in bad state %d", pC->m_state) ; \
+        err = M4ERR_STATE ; \
+        goto fct##_cleanUp; \
+    } \
+}
+
+#define SAFE_FREE(p) \
+{ \
+    if (M4OSA_NULL != p) \
+    { \
+        M4OSA_free((M4OSA_MemAddr32)p) ; \
+        p = M4OSA_NULL ; \
+    } \
+}
+
+/*--- Video Browser state ---*/
+typedef enum
+{
+    VideoBrowser_kVBCreating,
+    VideoBrowser_kVBOpened,
+    VideoBrowser_kVBBrowsing
+} VideoBrowser_videoBrowerState;
+
+
+/*--- Video Browser execution context. ---*/
+typedef struct
+{
+    VideoBrowser_videoBrowerState       m_state ;
+    VideoBrowser_videoBrowerDrawMode    m_drawmode;
+
+    M4OSA_Context                       g_hbmp2;
+    M4OSA_Context                       dc;
+    M4OSA_Int16*                        g_bmPixels2;
+
+    /*--- Reader parameters ---*/
+    M4OSA_FileReadPointer               m_fileReadPtr;
+    M4READER_GlobalInterface*           m_3gpReader ;
+    M4READER_DataInterface*             m_3gpData ;
+    M4READER_MediaType                  m_mediaType ;
+    M4OSA_Context                       m_pReaderCtx ;
+
+    M4_StreamHandler*                   m_pStreamHandler ;
+    M4_AccessUnit                       m_accessUnit ;
+
+    /*--- Decoder parameters ---*/
+    M4DECODER_VideoInterface*           m_pDecoder ;
+    M4OSA_Context                       m_pDecoderCtx ;
+
+    /*--- Common display parameters ---*/
+    M4OSA_UInt32                        m_x ;
+    M4OSA_UInt32                        m_y ;
+    M4VIFI_ImagePlane                   m_outputPlane[3] ;
+
+    /*--- Current browsing time ---*/
+    M4OSA_UInt32                        m_currentCTS ;
+
+    /*--- Platform dependent display parameters ---*/
+    M4OSA_Context                       m_pCoreContext ;
+
+    /*--- Callback function settings ---*/
+    videoBrowser_Callback               m_pfCallback;
+    M4OSA_Void*                         m_pCallbackUserData;
+
+    /*--- Codec Loader core context ---*/
+    M4OSA_Context                       m_pCodecLoaderContext;
+
+    /*--- Required color type ---*/
+    VideoBrowser_VideoColorType         m_frameColorType;
+
+} VideoBrowserContext;
+
+#endif /* VIDEO_BROWSER_INTERNAL_H */
diff --git a/media/jni/mediaeditor/VideoBrowserMain.c b/media/jni/mediaeditor/VideoBrowserMain.c
new file mode 100755
index 0000000..0d40f56
--- /dev/null
+++ b/media/jni/mediaeditor/VideoBrowserMain.c
@@ -0,0 +1,593 @@
+/*
+ * Copyright (C) 2011 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 "VideoEditorVideoDecoder.h"
+#include "VideoEditor3gpReader.h"
+
+#include <utils/Log.h>
+#include "VideoBrowserInternal.h"
+#include "LVOSA_FileReader_optim.h"
+
+//#define M4OSA_TRACE_LEVEL 1
+#if (M4OSA_TRACE_LEVEL >= 1)
+#undef M4OSA_TRACE1_0
+#undef M4OSA_TRACE1_1
+#undef M4OSA_TRACE1_2
+#undef M4OSA_TRACE1_3
+
+#define M4OSA_TRACE1_0(a)       __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a);
+#define M4OSA_TRACE1_1(a,b)     __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a,b);
+#define M4OSA_TRACE1_2(a,b,c)   __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a,b,c);
+#define M4OSA_TRACE1_3(a,b,c,d) __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a,b,c,d);
+#endif
+
+/******************************************************************************
+ * M4OSA_ERR     videoBrowserSetWindow(
+ *          M4OSA_Context pContext, M4OSA_UInt32 x,
+ *          M4OSA_UInt32 y, M4OSA_UInt32 dx, M4OSA_UInt32 dy);
+ * @brief        This function sets the size and the position of the display.
+ * @param        pContext       (IN) : Video Browser context
+ * @param        pPixelArray    (IN) : Array to hold the video frame.
+ * @param        x              (IN) : Horizontal position of the top left
+ *                                     corner
+ * @param        y              (IN) : Vertical position of the top left corner
+ * @param        dx             (IN) : Width of the display window
+ * @param        dy             (IN) : Height of the video window
+ * @return       M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
+ ******************************************************************************/
+M4OSA_ERR videoBrowserSetWindow(
+        M4OSA_Context pContext,
+        M4OSA_Int32 *pPixelArray,
+        M4OSA_UInt32 x, M4OSA_UInt32 y,
+        M4OSA_UInt32 dx, M4OSA_UInt32 dy)
+{
+    VideoBrowserContext* pC = (VideoBrowserContext*)pContext;
+    M4OSA_ERR err = M4NO_ERROR;
+
+    M4OSA_TRACE2_5("videoBrowserSetWindow: entering with 0x%x %d %d %d %d ",
+            pContext, x, y, dx, dy);
+
+    /*--- Sanity checks ---*/
+    CHECK_PTR(videoBrowserSetWindow, pContext, err, M4ERR_PARAMETER);
+    CHECK_PTR(videoBrowserSetWindow, pPixelArray, err, M4ERR_PARAMETER);
+    CHECK_STATE(videoBrowserSetWindow, VideoBrowser_kVBOpened, pC);
+
+    pC->m_outputPlane[0].u_topleft = 0;
+
+    pC->m_outputPlane[0].u_height = dy;
+    pC->m_outputPlane[0].u_width = dx;
+    pC->m_x = x;
+    pC->m_y = y;
+
+    if (pC->m_frameColorType == VideoBrowser_kGB565) {
+        pC->m_outputPlane[0].u_stride = pC->m_outputPlane[0].u_width << 1;
+        pC->m_outputPlane[0].pac_data = (M4OSA_UInt8*)M4OSA_malloc(
+            pC->m_outputPlane[0].u_stride * pC->m_outputPlane[0].u_height,
+            VIDEOBROWSER, (M4OSA_Char *)"output plane");
+
+        CHECK_PTR(videoBrowserSetWindow,
+            pC->m_outputPlane[0].pac_data, err, M4ERR_ALLOC);
+    }
+    else if (pC->m_frameColorType == VideoBrowser_kYUV420) {
+        pC->m_outputPlane[0].u_stride = pC->m_outputPlane[0].u_width;
+        pC->m_outputPlane[1].u_height = pC->m_outputPlane[0].u_height >> 1;
+        pC->m_outputPlane[1].u_width = pC->m_outputPlane[0].u_width >> 1;
+        pC->m_outputPlane[1].u_topleft = 0;
+        pC->m_outputPlane[1].u_stride = pC->m_outputPlane[1].u_width;
+
+        pC->m_outputPlane[2].u_height = pC->m_outputPlane[0].u_height >> 1;
+        pC->m_outputPlane[2].u_width = pC->m_outputPlane[0].u_width >> 1;
+        pC->m_outputPlane[2].u_topleft = 0;
+        pC->m_outputPlane[2].u_stride = pC->m_outputPlane[2].u_width;
+
+        pC->m_outputPlane[0].pac_data = (M4OSA_UInt8*)pPixelArray;
+
+        CHECK_PTR(videoBrowserSetWindow,
+            pC->m_outputPlane[0].pac_data, err, M4ERR_ALLOC);
+
+        pC->m_outputPlane[1].pac_data =
+            pC->m_outputPlane[0].pac_data +
+            (pC->m_outputPlane[0].u_stride * pC->m_outputPlane[0].u_height);
+
+        pC->m_outputPlane[2].pac_data =
+            pC->m_outputPlane[1].pac_data +
+            (pC->m_outputPlane[1].u_stride * pC->m_outputPlane[1].u_height);
+    }
+
+
+    M4OSA_TRACE2_0("videoBrowserSetWindow returned NO ERROR");
+    return M4NO_ERROR;
+
+videoBrowserSetWindow_cleanUp:
+
+    M4OSA_TRACE2_1("videoBrowserSetWindow returned 0x%x", err);
+    return err;
+}
+
+/******************************************************************************
+* @brief  This function allocates the resources needed for browsing a video file
+* @param   ppContext     (OUT): Pointer on a context filled by this function.
+* @param   pURL          (IN) : Path of File to browse
+* @param   DrawMode      (IN) : Indicate which method is used to draw (Direct draw etc...)
+* @param   pfCallback    (IN) : Callback function to be called when a frame must be displayed
+* @param   pCallbackData (IN) : User defined data that will be passed as parameter of the callback
+* @param   clrType       (IN) : Required color type.
+* @return  M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
+******************************************************************************/
+M4OSA_ERR videoBrowserCreate(
+        M4OSA_Context* ppContext,
+        M4OSA_Char* pURL,
+        M4OSA_UInt32 DrawMode,
+        M4OSA_FileReadPointer* ptrF,
+        videoBrowser_Callback pfCallback,
+        M4OSA_Void* pCallbackData,
+        VideoBrowser_VideoColorType clrType)
+{
+    VideoBrowserContext* pContext = M4OSA_NULL;
+    M4READER_MediaFamily mediaFamily = M4READER_kMediaFamilyUnknown;
+    M4_StreamHandler* pStreamHandler = M4OSA_NULL;
+    M4_VideoStreamHandler* pVideoStreamHandler = M4OSA_NULL;
+    M4DECODER_VideoType decoderType;
+    M4DECODER_OutputFilter FilterOption;
+
+    M4OSA_Bool deb = M4OSA_TRUE;
+    M4OSA_ERR err = M4NO_ERROR;
+
+    M4OSA_TRACE1_2(
+        "videoBrowserCreate: entering with 0x%x 0x%x", ppContext, pURL);
+
+    /*--- Sanity checks ---*/
+    CHECK_PTR(videoBrowserCreate, ppContext, err, M4ERR_PARAMETER);
+    *ppContext = M4OSA_NULL ;
+    CHECK_PTR(videoBrowserCreate, pURL,  err, M4ERR_PARAMETER);
+
+    /*--- Create context ---*/
+    pContext = (VideoBrowserContext*)M4OSA_malloc(
+            sizeof(VideoBrowserContext),
+            VIDEOBROWSER, (M4OSA_Char*)"Video browser context");
+
+    CHECK_PTR(videoBrowserCreate, pContext,err, M4ERR_ALLOC);
+    M4OSA_memset((M4OSA_MemAddr8)pContext, sizeof(VideoBrowserContext), 0);
+
+    /*--- Initialize the context parameters ---*/
+    pContext->m_state = VideoBrowser_kVBCreating ;
+    pContext->m_frameColorType = clrType;
+
+    /*--- Copy the file reader functions ---*/
+    M4OSA_memcpy((M4OSA_MemAddr8)&pContext->m_fileReadPtr,
+                 (M4OSA_MemAddr8)ptrF,
+                 sizeof(M4OSA_FileReadPointer)) ;
+
+    /* PR#SP00013 DGR bug 13 : first frame is not visible */
+    pContext->m_drawmode = DrawMode;
+
+
+    /* Retrieve the 3gp reader interface */
+    VideoEditor3gpReader_getInterface(&pContext->m_mediaType,
+        &pContext->m_3gpReader, &pContext->m_3gpData);
+
+    CHECK_PTR(videoBrowserCreate, pContext->m_3gpReader,  err, M4ERR_ALLOC);
+    CHECK_PTR(videoBrowserCreate, pContext->m_3gpData,    err, M4ERR_ALLOC);
+
+    /*--- Create the file reader ---*/
+    err = pContext->m_3gpReader->m_pFctCreate(&pContext->m_pReaderCtx);
+    CHECK_ERR(videoBrowserCreate, err);
+    CHECK_PTR(videoBrowserCreate, pContext->m_pReaderCtx, err, M4ERR_ALLOC);
+    pContext->m_3gpData->m_readerContext = pContext->m_pReaderCtx;
+
+    /*--- Set the OSAL file reader functions ---*/
+    err = pContext->m_3gpReader->m_pFctSetOption(
+            pContext->m_pReaderCtx,
+            M4READER_kOptionID_SetOsaFileReaderFctsPtr,
+            (M4OSA_DataOption)(&pContext->m_fileReadPtr));
+
+    CHECK_ERR(videoBrowserCreate, err) ;
+
+    /*--- Open the file ---*/
+    err = pContext->m_3gpReader->m_pFctOpen(pContext->m_pReaderCtx, pURL);
+    CHECK_ERR(videoBrowserCreate, err) ;
+
+    /*--- Try to find a video stream ---*/
+    while (err == M4NO_ERROR)
+    {
+        err = pContext->m_3gpReader->m_pFctGetNextStream(
+                pContext->m_pReaderCtx, &mediaFamily, &pStreamHandler);
+
+        /*in case we found a bifs stream or something else...*/
+        if ((err == M4ERR_READER_UNKNOWN_STREAM_TYPE) ||
+            (err == M4WAR_TOO_MUCH_STREAMS))
+        {
+            err = M4NO_ERROR;
+            continue;
+        }
+
+        if (err != M4WAR_NO_MORE_STREAM)
+        {
+            if (M4READER_kMediaFamilyVideo != mediaFamily)
+            {
+                err = M4NO_ERROR;
+                continue;
+            }
+
+            pContext->m_pStreamHandler = pStreamHandler;
+
+            err = pContext->m_3gpReader->m_pFctReset(
+                    pContext->m_pReaderCtx, pContext->m_pStreamHandler);
+
+            CHECK_ERR(videoBrowserCreate, err);
+
+            err = pContext->m_3gpReader->m_pFctFillAuStruct(
+                    pContext->m_pReaderCtx,
+                    pContext->m_pStreamHandler,
+                    &pContext->m_accessUnit);
+
+            CHECK_ERR(videoBrowserCreate, err);
+
+            pVideoStreamHandler =
+                (M4_VideoStreamHandler*)pContext->m_pStreamHandler;
+
+            switch (pContext->m_pStreamHandler->m_streamType)
+            {
+                case M4DA_StreamTypeVideoMpeg4:
+                case M4DA_StreamTypeVideoH263:
+                {
+                    pContext->m_pCodecLoaderContext = M4OSA_NULL;
+                    decoderType = M4DECODER_kVideoTypeMPEG4;
+
+                    err = VideoEditorVideoDecoder_getInterface_MPEG4(
+                        &decoderType, &pContext->m_pDecoder);
+
+                    CHECK_ERR(videoBrowserCreate, err) ;
+
+                    err = pContext->m_pDecoder->m_pFctCreate(
+                            &pContext->m_pDecoderCtx,
+                            pContext->m_pStreamHandler,
+                            pContext->m_3gpData,
+                            &pContext->m_accessUnit,
+                            pContext->m_pCodecLoaderContext) ;
+
+                    CHECK_ERR(videoBrowserCreate, err) ;
+                }
+                break;
+
+                case M4DA_StreamTypeVideoMpeg4Avc:
+                {
+                    pContext->m_pCodecLoaderContext = M4OSA_NULL;
+
+                    decoderType = M4DECODER_kVideoTypeAVC;
+                    err = VideoEditorVideoDecoder_getInterface_H264(
+                        &decoderType, &pContext->m_pDecoder);
+                   CHECK_ERR(videoBrowserCreate, err) ;
+
+                    err = pContext->m_pDecoder->m_pFctCreate(
+                            &pContext->m_pDecoderCtx,
+                            pContext->m_pStreamHandler,
+                            pContext->m_3gpData,
+                            &pContext->m_accessUnit,
+                            pContext->m_pCodecLoaderContext) ;
+
+                    CHECK_ERR(videoBrowserCreate, err) ;
+                }
+                break;
+
+                default:
+                    err = M4ERR_VB_MEDIATYPE_NOT_SUPPORTED;
+                    goto videoBrowserCreate_cleanUp;
+            }
+        }
+    }
+
+    if (err == M4WAR_NO_MORE_STREAM)
+    {
+        err = M4NO_ERROR ;
+    }
+
+    if (M4OSA_NULL == pContext->m_pStreamHandler)
+    {
+        err = M4ERR_VB_NO_VIDEO ;
+        goto videoBrowserCreate_cleanUp ;
+    }
+
+    err = pContext->m_pDecoder->m_pFctSetOption(
+            pContext->m_pDecoderCtx,
+            M4DECODER_kOptionID_DeblockingFilter,
+            (M4OSA_DataOption)&deb);
+
+    if (err == M4WAR_DEBLOCKING_FILTER_NOT_IMPLEMENTED)
+    {
+        err = M4NO_ERROR;
+    }
+    CHECK_ERR(videoBrowserCreate, err);
+
+    FilterOption.m_pFilterUserData = M4OSA_NULL;
+
+
+    if (pContext->m_frameColorType == VideoBrowser_kGB565) {
+        FilterOption.m_pFilterFunction =
+            (M4OSA_Void*)M4VIFI_ResizeBilinearYUV420toBGR565;
+    }
+    else if (pContext->m_frameColorType == VideoBrowser_kYUV420) {
+        FilterOption.m_pFilterFunction =
+            (M4OSA_Void*)M4VIFI_ResizeBilinearYUV420toYUV420;
+    }
+    else {
+        err = M4ERR_PARAMETER;
+        goto videoBrowserCreate_cleanUp;
+    }
+
+    err = pContext->m_pDecoder->m_pFctSetOption(
+            pContext->m_pDecoderCtx,
+            M4DECODER_kOptionID_OutputFilter,
+            (M4OSA_DataOption)&FilterOption);
+
+    CHECK_ERR(videoBrowserCreate, err);
+
+    /* store the callback details */
+    pContext->m_pfCallback = pfCallback;
+    pContext->m_pCallbackUserData = pCallbackData;
+    /* store the callback details */
+
+    pContext->m_state = VideoBrowser_kVBOpened;
+    *ppContext = pContext;
+
+    M4OSA_TRACE1_0("videoBrowserCreate returned NO ERROR");
+    return M4NO_ERROR;
+
+videoBrowserCreate_cleanUp:
+
+    if (M4OSA_NULL != pContext)
+    {
+        if (M4OSA_NULL != pContext->m_pDecoderCtx)
+        {
+            pContext->m_pDecoder->m_pFctDestroy(pContext->m_pDecoderCtx);
+            pContext->m_pDecoderCtx = M4OSA_NULL;
+        }
+
+        if (M4OSA_NULL != pContext->m_pReaderCtx)
+        {
+            pContext->m_3gpReader->m_pFctClose(pContext->m_pReaderCtx);
+            pContext->m_3gpReader->m_pFctDestroy(pContext->m_pReaderCtx);
+            pContext->m_pReaderCtx = M4OSA_NULL;
+        }
+        SAFE_FREE(pContext->m_pDecoder);
+        SAFE_FREE(pContext->m_3gpReader);
+        SAFE_FREE(pContext->m_3gpData);
+        SAFE_FREE(pContext);
+    }
+
+    M4OSA_TRACE2_1("videoBrowserCreate returned 0x%x", err);
+    return err;
+}
+
+/******************************************************************************
+* M4OSA_ERR     videoBrowserCleanUp(M4OSA_Context pContext);
+* @brief        This function frees the resources needed for browsing a
+*               video file.
+* @param        pContext     (IN) : Video browser context
+* @return       M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE
+******************************************************************************/
+M4OSA_ERR videoBrowserCleanUp(M4OSA_Context pContext)
+{
+    VideoBrowserContext* pC = (VideoBrowserContext*)pContext;
+    M4OSA_ERR err = M4NO_ERROR;
+
+    M4OSA_TRACE2_1("videoBrowserCleanUp: entering with 0x%x", pContext);
+
+    /*--- Sanity checks ---*/
+    CHECK_PTR(videoBrowserCleanUp, pContext, err, M4ERR_PARAMETER);
+
+    if (M4OSA_NULL != pC->m_pDecoderCtx)
+    {
+        pC->m_pDecoder->m_pFctDestroy(pC->m_pDecoderCtx);
+        pC->m_pDecoderCtx = M4OSA_NULL ;
+    }
+
+    if (M4OSA_NULL != pC->m_pReaderCtx)
+    {
+        pC->m_3gpReader->m_pFctClose(pC->m_pReaderCtx) ;
+        pC->m_3gpReader->m_pFctDestroy(pC->m_pReaderCtx);
+        pC->m_pReaderCtx = M4OSA_NULL;
+    }
+
+    SAFE_FREE(pC->m_pDecoder);
+    SAFE_FREE(pC->m_3gpReader);
+    SAFE_FREE(pC->m_3gpData);
+
+    if (pC->m_frameColorType != VideoBrowser_kYUV420) {
+        SAFE_FREE(pC->m_outputPlane[0].pac_data);
+    }
+    SAFE_FREE(pC);
+
+    M4OSA_TRACE2_0("videoBrowserCleanUp returned NO ERROR");
+    return M4NO_ERROR;
+
+videoBrowserCleanUp_cleanUp:
+
+    M4OSA_TRACE2_1("videoBrowserCleanUp returned 0x%x", err);
+    return err;
+}
+/******************************************************************************
+* M4OSA_ERR     videoBrowserPrepareFrame(
+*       M4OSA_Context pContext, M4OSA_UInt32* pTime);
+* @brief        This function prepares the frame.
+* @param        pContext     (IN) : Video browser context
+* @param        pTime        (IN/OUT) : Pointer on the time to reach. Updated
+*                                       by this function with the reached time
+* @return       M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
+******************************************************************************/
+M4OSA_ERR videoBrowserPrepareFrame(M4OSA_Context pContext, M4OSA_UInt32* pTime)
+{
+    VideoBrowserContext* pC = (VideoBrowserContext*)pContext;
+    M4OSA_ERR err = M4NO_ERROR;
+    M4OSA_UInt32 targetTime = 0;
+    M4OSA_UInt32 jumpTime = 0;
+    M4_MediaTime timeMS = 0;
+    M4OSA_Int32 rapTime = 0;
+    M4OSA_Bool isBackward = M4OSA_FALSE;
+    M4OSA_Bool bJumpNeeded = M4OSA_FALSE;
+
+
+    /*--- Sanity checks ---*/
+    CHECK_PTR(videoBrowserPrepareFrame, pContext, err, M4ERR_PARAMETER);
+    CHECK_PTR(videoBrowserPrepareFrame, pTime,  err, M4ERR_PARAMETER);
+
+    targetTime = *pTime ;
+
+    /*--- Check the state, if this is the first call to this function
+          we move to the state "browsing" ---*/
+    if (VideoBrowser_kVBOpened == pC->m_state)
+    {
+        pC->m_state = VideoBrowser_kVBBrowsing;
+    }
+    else if (VideoBrowser_kVBBrowsing != pC->m_state)
+    {
+        err = M4ERR_STATE ;
+        goto videoBrowserPrepareFrame_cleanUp;
+    }
+
+    /*--- Check the duration ---*/
+    /*--- If we jump backward, we need to jump ---*/
+    if (targetTime < pC->m_currentCTS)
+    {
+        isBackward = M4OSA_TRUE;
+        bJumpNeeded = M4OSA_TRUE;
+    }
+    /*--- If we jumpt to a time greater than "currentTime" + "predecodeTime"
+          we need to jump ---*/
+    else if (targetTime > (pC->m_currentCTS + VIDEO_BROWSER_PREDECODE_TIME))
+    {
+        bJumpNeeded = M4OSA_TRUE;
+    }
+
+    if (M4OSA_TRUE == bJumpNeeded)
+    {
+        rapTime = targetTime;
+        /*--- Retrieve the previous RAP time ---*/
+        err = pC->m_3gpReader->m_pFctGetPrevRapTime(
+                pC->m_pReaderCtx, pC->m_pStreamHandler, &rapTime);
+
+        CHECK_ERR(videoBrowserPrepareFrame, err);
+
+        jumpTime = rapTime;
+
+        err = pC->m_3gpReader->m_pFctJump(pC->m_pReaderCtx,
+                                          pC->m_pStreamHandler,
+                                          (M4OSA_Int32*)&jumpTime);
+        CHECK_ERR(videoBrowserPrepareFrame, err);
+    }
+
+    timeMS = (M4_MediaTime)targetTime;
+    err = pC->m_pDecoder->m_pFctDecode(
+        pC->m_pDecoderCtx, &timeMS, bJumpNeeded);
+
+    if ((err != M4NO_ERROR) && (err != M4WAR_NO_MORE_AU))
+    {
+        return err;
+    }
+
+    // FIXME:
+    // Not sure that I understand why we need a second jump logic here
+    if ((timeMS >= pC->m_currentCTS) && (M4OSA_TRUE == isBackward))
+    {
+        jumpTime = rapTime;
+        err = pC->m_3gpReader->m_pFctJump(
+            pC->m_pReaderCtx, pC->m_pStreamHandler, (M4OSA_Int32*)&jumpTime);
+
+        CHECK_ERR(videoBrowserPrepareFrame, err);
+
+        timeMS = (M4_MediaTime)rapTime;
+        err = pC->m_pDecoder->m_pFctDecode(
+            pC->m_pDecoderCtx, &timeMS, M4OSA_TRUE);
+
+        if ((err != M4NO_ERROR) && (err != M4WAR_NO_MORE_AU))
+        {
+            return err;
+        }
+    }
+
+    err = pC->m_pDecoder->m_pFctRender(
+        pC->m_pDecoderCtx, &timeMS, pC->m_outputPlane, M4OSA_TRUE);
+
+    if (M4WAR_VIDEORENDERER_NO_NEW_FRAME == err)
+    {
+        err = M4NO_ERROR;
+    }
+    CHECK_ERR(videoBrowserPrepareFrame, err) ;
+
+    pC->m_currentCTS = (M4OSA_UInt32)timeMS;
+
+    *pTime = pC->m_currentCTS;
+
+    return M4NO_ERROR;
+
+videoBrowserPrepareFrame_cleanUp:
+
+    if ((M4WAR_INVALID_TIME == err) || (M4WAR_NO_MORE_AU == err))
+    {
+        err = M4NO_ERROR;
+    }
+    else if (M4OSA_NULL != pC)
+    {
+        pC->m_currentCTS = 0;
+    }
+
+    M4OSA_TRACE2_1("videoBrowserPrepareFrame returned 0x%x", err);
+    return err;
+}
+
+/******************************************************************************
+* M4OSA_ERR     videoBrowserDisplayCurrentFrame(M4OSA_Context pContext);
+* @brief        This function displays the current frame.
+* @param        pContext     (IN) : Video browser context
+* @return       M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
+******************************************************************************/
+M4OSA_ERR videoBrowserDisplayCurrentFrame(M4OSA_Context pContext)
+{
+    VideoBrowserContext* pC = (VideoBrowserContext*)pContext ;
+    M4OSA_ERR err = M4NO_ERROR ;
+
+    /*--- Sanity checks ---*/
+    CHECK_PTR(videoBrowserDisplayCurrentFrame, pContext, err, M4ERR_PARAMETER);
+
+    // Request display of the frame
+    pC->m_pfCallback((M4OSA_Context) pC,             // VB context
+        VIDEOBROWSER_DISPLAY_FRAME,                  // action requested
+        M4NO_ERROR,                                  // error code
+        (M4OSA_Void*) &(pC->m_outputPlane[0]),       // image to be displayed
+        (M4OSA_Void*) pC->m_pCallbackUserData);      // user-provided data
+
+#ifdef DUMPTOFILE
+    {
+        M4OSA_Context fileContext;
+        M4OSA_Char* fileName = "/sdcard/textBuffer_RGB565.rgb";
+        M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,
+            M4OSA_kFileWrite | M4OSA_kFileCreate);
+
+        M4OSA_fileWriteData(fileContext,
+            (M4OSA_MemAddr8) pC->m_outputPlane[0].pac_data,
+            pC->m_outputPlane[0].u_height*pC->m_outputPlane[0].u_width*2);
+
+        M4OSA_fileWriteClose(fileContext);
+    }
+#endif
+
+    M4OSA_TRACE2_0("videoBrowserDisplayCurrentFrame returned NO ERROR") ;
+    return M4NO_ERROR;
+
+videoBrowserDisplayCurrentFrame_cleanUp:
+
+    M4OSA_TRACE2_1("videoBrowserDisplayCurrentFrame returned 0x%x", err) ;
+    return err;
+}
diff --git a/media/jni/mediaeditor/VideoBrowserMain.h b/media/jni/mediaeditor/VideoBrowserMain.h
new file mode 100755
index 0000000..5156ebb
--- /dev/null
+++ b/media/jni/mediaeditor/VideoBrowserMain.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2011 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 VIDEO_BROWSER_MAIN_H
+#define VIDEO_BROWSER_MAIN_H
+
+/**
+ ************************************************************************
+ * @file    VideoBrowserMain.h
+ * @brief   Video browser Interface functions
+ ************************************************************************
+*/
+
+#define VIDEOBROWSER    0x423
+
+#include "M4OSA_Memory.h"
+#include "M4OSA_CharStar.h"
+#include "M4OSA_OptionID.h"
+#include "M4OSA_Debug.h"
+#include "M4VIFI_FiltersAPI.h"
+#include "M4OSA_FileReader.h"
+
+
+/**
+ ************************************************************************
+ * @brief    Error codes definition.
+ * @note    These value are the Browser engine specific error codes.
+ ************************************************************************
+*/
+#define M4ERR_VB_MEDIATYPE_NOT_SUPPORTED    M4OSA_ERR_CREATE(M4_ERR, VIDEOBROWSER, 0x01)
+#define M4ERR_VB_NO_VIDEO                   M4OSA_ERR_CREATE(M4_ERR, VIDEOBROWSER, 0x02)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ *  Video Browser draw mode, extension for angle based bliting can be done
+ */
+typedef enum
+{
+    VideoBrowser_kVBNormalBliting
+} VideoBrowser_videoBrowerDrawMode;
+
+
+/*--- Video Browser output frame color type ---*/
+typedef enum
+{
+    VideoBrowser_kYUV420,
+    VideoBrowser_kGB565
+} VideoBrowser_VideoColorType;
+
+/**
+ ************************************************************************
+ * enumeration  VideoBrowser_Notification
+ * @brief       Video Browser notification type.
+ * @note        This callback mechanism must be used to wait the completion of an asynchronous
+ * operation, before calling another API function.
+ ************************************************************************
+*/
+typedef enum
+{
+    /**
+     * A frame is ready to be displayed, it should be displayed in the callback function
+     * pCbData type = M4VIFI_ImagePlane*
+     */
+    VIDEOBROWSER_DISPLAY_FRAME            = 0x00000001,
+    VIDEOBROWSER_NOTIFICATION_NONE        = 0xffffffff
+}VideoBrowser_Notification;
+
+
+/**
+ ************************************************************************
+ * @brief    videoBrowser_Callback type definition
+ * @param    pInstance          (IN) Video Browser context.
+ * @param    notificationID     (IN) Id of the callback which generated the error
+ * @param    errCode            (IN) Error code from the core
+ * @param    pCbData            (IN) pointer to data associated wit the callback.
+ * @param    pCbUserData        (IN) pointer to application user data passed in init.
+ * @note    This callback mechanism is used to request display of an image
+ ************************************************************************
+*/
+typedef M4OSA_Void (*videoBrowser_Callback) (M4OSA_Context pInstance,
+                                        VideoBrowser_Notification notificationID,
+                                        M4OSA_ERR errCode,
+                                        M4OSA_Void* pCbData,
+                                        M4OSA_Void* pCallbackUserData);
+
+
+/******************************************************************************
+* @brief   This function allocates the resources needed for browsing a video file.
+* @param   ppContext     (OUT): Pointer on a context filled by this function.
+* @param   pURL          (IN) : Path of File to browse
+* @param   DrawMode      (IN) : Indicate which method is used to draw (Direct draw etc...)
+* @param   pfCallback    (IN) : Callback function to be called when a frame must be displayed
+* @param   pCallbackData (IN)  : User defined data that will be passed as parameter of the callback
+* @param   clrType       (IN) : Required color type.
+* @return  M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
+******************************************************************************/
+M4OSA_ERR videoBrowserCreate(M4OSA_Context* ppContext, M4OSA_Char* pURL,
+                                        M4OSA_UInt32 DrawMode,
+                                        M4OSA_FileReadPointer* ptrF,
+                                        videoBrowser_Callback pfCallback,
+                                        M4OSA_Void* pCallbackData,
+                                        VideoBrowser_VideoColorType clrType);
+
+/******************************************************************************
+* @brief        This function frees the resources needed for browsing a video file.
+* @param        pContext     (IN) : Video browser context
+* @return       M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE
+******************************************************************************/
+M4OSA_ERR videoBrowserCleanUp(M4OSA_Context pContext) ;
+
+
+/******************************************************************************
+* @brief        This function allocates the resources needed for browsing a video file.
+* @param        pContext  (IN)      : Video browser context
+* @param        pTime     (IN/OUT)  : Pointer on the time to reach. Updated by
+*                                     this function with the reached time
+* @return       M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
+******************************************************************************/
+M4OSA_ERR videoBrowserPrepareFrame(M4OSA_Context pContext, M4OSA_UInt32* pTime);
+
+/******************************************************************************
+* @brief        This function sets the size and the position of the display.
+* @param        pContext     (IN) : Video Browser context
+* @param        pixelArray   (IN) : Array to hold the video frame.
+* @param        x            (IN) : Horizontal position of the top left corner
+* @param        y            (IN) : Vertical position of the top left corner
+* @param        dx           (IN) : Width of the display window
+* @param        dy           (IN) : Height of the video window
+* @return       M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
+******************************************************************************/
+M4OSA_ERR videoBrowserSetWindow(M4OSA_Context pContext, M4OSA_Int32* pixelArray,
+                                M4OSA_UInt32 x, M4OSA_UInt32 y,
+                                M4OSA_UInt32 dx, M4OSA_UInt32 dy);
+
+/******************************************************************************
+* @brief        This function displays the current frame.
+* @param        pContext     (IN) : Video browser context
+* @return       M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
+******************************************************************************/
+M4OSA_ERR videoBrowserDisplayCurrentFrame(M4OSA_Context pContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VIDEO_BROWSER_MAIN_H */
diff --git a/media/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp
new file mode 100755
index 0000000..52e032a
--- /dev/null
+++ b/media/jni/mediaeditor/VideoEditorClasses.cpp
@@ -0,0 +1,3174 @@
+/*
+ * Copyright (C) 2011 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 <VideoEditorClasses.h>
+#include <VideoEditorJava.h>
+#include <VideoEditorLogging.h>
+#include <VideoEditorOsal.h>
+
+extern "C" {
+#include <M4OSA_Clock.h>
+#include <M4OSA_CharStar.h>
+#include <M4OSA_FileCommon.h>
+#include <M4OSA_FileReader.h>
+#include <M4OSA_FileWriter.h>
+#include <M4OSA_Memory.h>
+#include <M4OSA_Debug.h>
+#include <M4OSA_String.h>
+#include <M4OSA_Thread.h>
+#include <M4VSS3GPP_API.h>
+#include <M4xVSS_API.h>
+#include <M4VSS3GPP_ErrorCodes.h>
+#include <M4MCS_ErrorCodes.h>
+#include <M4READER_Common.h>
+#include <M4WRITER_common.h>
+#include <M4DECODER_Common.h>
+};
+
+#define VIDEOEDIT_PROP_JAVA_RESULT_STRING_MAX                     (128)
+
+#define VIDEOEDIT_JAVA__RESULT_STRING_MAX                     (128)
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(AudioEffect)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("NONE",     M4VSS3GPP_kAudioEffectType_None),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FADE_IN",  M4VSS3GPP_kAudioEffectType_FadeIn),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FADE_OUT", M4VSS3GPP_kAudioEffectType_FadeOut)
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(AudioEffect, AUDIO_EFFECT_CLASS_NAME, M4OSA_NULL, M4OSA_NULL)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(AudioFormat)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("NO_AUDIO",          M4VIDEOEDITING_kNoneAudio),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("AMR_NB",            M4VIDEOEDITING_kAMR_NB),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("AAC",               M4VIDEOEDITING_kAAC),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("AAC_PLUS",          M4VIDEOEDITING_kAACplus),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ENHANCED_AAC_PLUS", M4VIDEOEDITING_keAACplus),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("MP3",               M4VIDEOEDITING_kMP3),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("EVRC",              M4VIDEOEDITING_kEVRC),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("PCM",               M4VIDEOEDITING_kPCM),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("NULL_AUDIO",        M4VIDEOEDITING_kNullAudio),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("UNSUPPORTED_AUDIO", M4VIDEOEDITING_kUnsupportedAudio)
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(AudioFormat, AUDIO_FORMAT_CLASS_NAME, M4OSA_NULL, M4OSA_NULL)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(AudioSamplingFrequency)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_DEFAULT", M4VIDEOEDITING_kDefault_ASF),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_8000",    M4VIDEOEDITING_k8000_ASF),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_16000",   M4VIDEOEDITING_k16000_ASF),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_22050",   M4VIDEOEDITING_k22050_ASF),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_24000",   M4VIDEOEDITING_k24000_ASF),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_32000",   M4VIDEOEDITING_k32000_ASF),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_44100",   M4VIDEOEDITING_k44100_ASF),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_48000",   M4VIDEOEDITING_k48000_ASF)
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(AudioSamplingFrequency,AUDIO_SAMPLING_FREQUENCY_CLASS_NAME,
+                                     M4OSA_NULL, M4OSA_NULL)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(AudioTransition)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("NONE",       M4VSS3GPP_kAudioTransitionType_None),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("CROSS_FADE", M4VSS3GPP_kAudioTransitionType_CrossFade)
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(AudioTransition, AUDIO_TRANSITION_CLASS_NAME, M4OSA_NULL,
+                                     M4OSA_NULL)
+
+
+static const char*
+videoEditClasses_getUnknownBitrateString(int bitrate)
+{
+    static char string[VIDEOEDIT_JAVA__RESULT_STRING_MAX] = "";
+
+    M4OSA_chrSPrintf((M4OSA_Char *)string, sizeof(string) - 1, (M4OSA_Char*)"%d", bitrate);
+
+    // Return the bitrate string.
+    return(string);
+}
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(Bitrate)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("VARIABLE",     M4VIDEOEDITING_kVARIABLE_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("UNDEFINED",    M4VIDEOEDITING_kUndefinedBitrate),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_9_2_KBPS",  M4VIDEOEDITING_k9_2_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_12_2_KBPS", M4VIDEOEDITING_k12_2_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_16_KBPS",   M4VIDEOEDITING_k16_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_24_KBPS",   M4VIDEOEDITING_k24_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_32_KBPS",   M4VIDEOEDITING_k32_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_48_KBPS",   M4VIDEOEDITING_k48_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_64_KBPS",   M4VIDEOEDITING_k64_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_96_KBPS",   M4VIDEOEDITING_k96_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_128_KBPS",  M4VIDEOEDITING_k128_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_192_KBPS",  M4VIDEOEDITING_k192_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_256_KBPS",  M4VIDEOEDITING_k256_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_288_KBPS",  M4VIDEOEDITING_k288_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_384_KBPS",  M4VIDEOEDITING_k384_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_512_KBPS",  M4VIDEOEDITING_k512_KBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_800_KBPS",  M4VIDEOEDITING_k800_KBPS),
+/*+ New Encoder bitrates */
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_2_MBPS",  M4VIDEOEDITING_k2_MBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_5_MBPS",  M4VIDEOEDITING_k5_MBPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BR_8_MBPS",  M4VIDEOEDITING_k8_MBPS)
+/*- New Encoder bitrates */
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(Bitrate, BITRATE_CLASS_NAME,
+ videoEditClasses_getUnknownBitrateString, videoEditClasses_getUnknownBitrateString)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(ClipType)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("THREE_GPP",   M4VIDEOEDITING_kFileType_3GPP),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("MP4",         M4VIDEOEDITING_kFileType_MP4),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("AMR",         M4VIDEOEDITING_kFileType_AMR),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("MP3",         M4VIDEOEDITING_kFileType_MP3),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("PCM",         M4VIDEOEDITING_kFileType_PCM),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("JPG",         M4VIDEOEDITING_kFileType_JPG),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("UNSUPPORTED", M4VIDEOEDITING_kFileType_Unsupported)
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(ClipType, FILE_TYPE_CLASS_NAME, M4OSA_NULL, M4OSA_NULL)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(Engine)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("TASK_LOADING_SETTINGS",    TASK_LOADING_SETTINGS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("TASK_ENCODING",            TASK_ENCODING)
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(Engine, MANUAL_EDIT_ENGINE_CLASS_NAME, M4OSA_NULL,
+                                     M4OSA_NULL)
+
+
+static const char*
+videoEditClasses_getUnknownErrorName(int error)
+{
+    static char string[VIDEOEDIT_JAVA__RESULT_STRING_MAX] = "ERR_INTERNAL";
+
+    // Format the unknown error string.
+    M4OSA_chrSPrintf((M4OSA_Char *)string, sizeof(string) - 1, (M4OSA_Char*)"ERR_INTERNAL(%s)",
+                    videoEditOsal_getResultString(error));
+
+    // Return the error string.
+    return(string);
+}
+
+static const char*
+videoEditClasses_getUnknownErrorString(int error)
+{
+    // Return the result string.
+    return(videoEditOsal_getResultString(error));
+}
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(Error)
+{
+    // M4OSA_Clock.h
+    VIDEOEDIT_JAVA_CONSTANT_INIT("WAR_TIMESCALE_TOO_BIG",                   \
+          M4WAR_TIMESCALE_TOO_BIG                               ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_CLOCK_BAD_REF_YEAR",                  \
+          M4ERR_CLOCK_BAD_REF_YEAR                              ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_FILE_NOT_FOUND",                      \
+          M4ERR_FILE_NOT_FOUND                                  ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("WAR_TRANSCODING_NECESSARY",               \
+          M4VSS3GPP_WAR_TRANSCODING_NECESSARY                   ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("WAR_MAX_OUTPUT_SIZE_EXCEEDED",            \
+          M4VSS3GPP_WAR_OUTPUTFILESIZE_EXCEED                   ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_BUFFER_OUT_TOO_SMALL",                \
+          M4xVSSWAR_BUFFER_OUT_TOO_SMALL                        ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_NOMORE_SPACE_FOR_FILE",               \
+          M4xVSSERR_NO_MORE_SPACE                               ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_FILE_TYPE",                   \
+          M4VSS3GPP_ERR_INVALID_FILE_TYPE                       ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_EFFECT_KIND",                 \
+          M4VSS3GPP_ERR_INVALID_EFFECT_KIND                     ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_VIDEO_EFFECT_TYPE",           \
+          M4VSS3GPP_ERR_INVALID_VIDEO_EFFECT_TYPE               ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_AUDIO_EFFECT_TYPE",           \
+          M4VSS3GPP_ERR_INVALID_AUDIO_EFFECT_TYPE               ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_VIDEO_TRANSITION_TYPE",       \
+          M4VSS3GPP_ERR_INVALID_VIDEO_TRANSITION_TYPE           ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_AUDIO_TRANSITION_TYPE",       \
+          M4VSS3GPP_ERR_INVALID_AUDIO_TRANSITION_TYPE           ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_VIDEO_ENCODING_FRAME_RATE",   \
+          M4VSS3GPP_ERR_INVALID_VIDEO_ENCODING_FRAME_RATE       ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EXTERNAL_EFFECT_NULL",                \
+          M4VSS3GPP_ERR_EXTERNAL_EFFECT_NULL                    ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EXTERNAL_TRANSITION_NULL",            \
+          M4VSS3GPP_ERR_EXTERNAL_TRANSITION_NULL                ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_BEGIN_CUT_LARGER_THAN_DURATION",      \
+          M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_DURATION          ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_BEGIN_CUT_LARGER_THAN_END_CUT",       \
+          M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_END_CUT           ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_OVERLAPPING_TRANSITIONS",             \
+         M4VSS3GPP_ERR_OVERLAPPING_TRANSITIONS                  ),
+#ifdef M4VSS3GPP_ERR_ANALYSIS_DATA_SIZE_TOO_SMALL
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_ANALYSIS_DATA_SIZE_TOO_SMALL",        \
+          M4VSS3GPP_ERR_ANALYSIS_DATA_SIZE_TOO_SMALL            ),
+#endif
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_3GPP_FILE",                     \
+        M4VSS3GPP_ERR_INVALID_3GPP_FILE                         ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_UNSUPPORTED_INPUT_VIDEO_FORMAT",        \
+        M4VSS3GPP_ERR_UNSUPPORTED_INPUT_VIDEO_FORMAT            ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_UNSUPPORTED_INPUT_AUDIO_FORMAT",        \
+        M4VSS3GPP_ERR_UNSUPPORTED_INPUT_AUDIO_FORMAT            ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_AMR_EDITING_UNSUPPORTED",               \
+        M4VSS3GPP_ERR_AMR_EDITING_UNSUPPORTED                   ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INPUT_VIDEO_AU_TOO_LARGE",              \
+        M4VSS3GPP_ERR_INPUT_VIDEO_AU_TOO_LARGE                  ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INPUT_AUDIO_AU_TOO_LARGE",              \
+        M4VSS3GPP_ERR_INPUT_AUDIO_AU_TOO_LARGE                  ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INPUT_AUDIO_CORRUPTED_AU",              \
+        M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AU                  ),
+#ifdef M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AMR_AU
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INPUT_AUDIO_CORRUPTED_AU",              \
+        M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AMR_AU              ),
+#endif
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_ENCODER_ACCES_UNIT_ERROR",              \
+        M4VSS3GPP_ERR_ENCODER_ACCES_UNIT_ERROR                  ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EDITING_UNSUPPORTED_VIDEO_FORMAT",      \
+        M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_FORMAT          ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EDITING_UNSUPPORTED_H263_PROFILE",      \
+        M4VSS3GPP_ERR_EDITING_UNSUPPORTED_H263_PROFILE          ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EDITING_UNSUPPORTED_MPEG4_PROFILE",     \
+        M4VSS3GPP_ERR_EDITING_UNSUPPORTED_MPEG4_PROFILE         ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EDITING_UNSUPPORTED_MPEG4_RVLC",        \
+        M4VSS3GPP_ERR_EDITING_UNSUPPORTED_MPEG4_RVLC            ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EDITING_UNSUPPORTED_AUDIO_FORMAT",      \
+        M4VSS3GPP_ERR_EDITING_UNSUPPORTED_AUDIO_FORMAT          ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EDITING_NO_SUPPORTED_STREAM_IN_FILE",   \
+        M4VSS3GPP_ERR_EDITING_NO_SUPPORTED_STREAM_IN_FILE       ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EDITING_NO_SUPPORTED_VIDEO_STREAM_IN_FILE",\
+     M4VSS3GPP_ERR_EDITING_NO_SUPPORTED_VIDEO_STREAM_IN_FILE),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_CLIP_ANALYSIS_VERSION",        \
+         M4VSS3GPP_ERR_INVALID_CLIP_ANALYSIS_VERSION            ),
+#ifdef M4VSS3GPP_ERR_INVALID_CLIP_ANALYSIS_PLATFORM
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_CLIP_ANALYSIS_PLATFORM",       \
+        M4VSS3GPP_ERR_INVALID_CLIP_ANALYSIS_PLATFORM            ),
+#endif
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INCOMPATIBLE_VIDEO_FORMAT",            \
+         M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_FORMAT                ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INCOMPATIBLE_VIDEO_FRAME_SIZE",        \
+         M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_FRAME_SIZE            ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INCOMPATIBLE_VIDEO_TIME_SCALE",        \
+         M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_TIME_SCALE            ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INCOMPATIBLE_VIDEO_DATA_PARTITIONING", \
+         M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_DATA_PARTITIONING     ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_UNSUPPORTED_MP3_ASSEMBLY",             \
+         M4VSS3GPP_ERR_UNSUPPORTED_MP3_ASSEMBLY                 ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_NO_SUPPORTED_STREAM_IN_FILE",          \
+         M4VSS3GPP_ERR_NO_SUPPORTED_STREAM_IN_FILE              ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_ADDVOLUME_EQUALS_ZERO",                \
+         M4VSS3GPP_ERR_ADDVOLUME_EQUALS_ZERO                    ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_ADDCTS_HIGHER_THAN_VIDEO_DURATION",    \
+         M4VSS3GPP_ERR_ADDCTS_HIGHER_THAN_VIDEO_DURATION        ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_UNDEFINED_AUDIO_TRACK_FILE_FORMAT",    \
+         M4VSS3GPP_ERR_UNDEFINED_AUDIO_TRACK_FILE_FORMAT        ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_UNSUPPORTED_ADDED_AUDIO_STREAM",       \
+         M4VSS3GPP_ERR_UNSUPPORTED_ADDED_AUDIO_STREAM           ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_AUDIO_MIXING_UNSUPPORTED",             \
+         M4VSS3GPP_ERR_AUDIO_MIXING_UNSUPPORTED                 ),
+#ifdef M4VSS3GPP_ERR_AUDIO_MIXING_MP3_UNSUPPORTED
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_AUDIO_MIXING_MP3_UNSUPPORTED",         \
+          M4VSS3GPP_ERR_AUDIO_MIXING_MP3_UNSUPPORTED            ),
+#endif
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_FEATURE_UNSUPPORTED_WITH_AUDIO_TRACK", \
+      M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AUDIO_TRACK        ),
+#ifdef M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AAC
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_FEATURE_UNSUPPORTED_WITH_AAC",         \
+       M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AAC               ),
+#endif
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_AUDIO_CANNOT_BE_MIXED",                \
+        M4VSS3GPP_ERR_AUDIO_CANNOT_BE_MIXED                     ),
+#ifdef M4VSS3GPP_ERR_ONLY_AMRNB_INPUT_CAN_BE_MIXED
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_ONLY_AMRNB_INPUT_CAN_BE_MIXED",        \
+         M4VSS3GPP_ERR_ONLY_AMRNB_INPUT_CAN_BE_MIXED            ),
+#endif
+#ifdef M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_EVRC
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_FEATURE_UNSUPPORTED_WITH_EVRC",        \
+          M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_EVRC           ),
+#endif
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_H263_PROFILE_NOT_SUPPORTED",           \
+          M4VSS3GPP_ERR_H263_PROFILE_NOT_SUPPORTED              ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_NO_SUPPORTED_VIDEO_STREAM_IN_FILE",    \
+          M4VSS3GPP_ERR_NO_SUPPORTED_VIDEO_STREAM_IN_FILE       ),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INTERNAL",                             \
+          M4NO_ERROR                                            ),
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(Error, ERROR_CLASS_NAME,
+ videoEditClasses_getUnknownErrorName, videoEditClasses_getUnknownErrorString)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(FileType)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("THREE_GPP",   VideoEditClasses_kFileType_3GPP),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("MP4",         VideoEditClasses_kFileType_MP4),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("AMR",         VideoEditClasses_kFileType_AMR),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("MP3",         VideoEditClasses_kFileType_MP3),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("PCM",         VideoEditClasses_kFileType_PCM),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("JPG",         VideoEditClasses_kFileType_JPG),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("GIF",         VideoEditClasses_kFileType_GIF),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("PNG",         VideoEditClasses_kFileType_PNG),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("UNSUPPORTED", VideoEditClasses_kFileType_Unsupported)
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(FileType, FILE_TYPE_CLASS_NAME, M4OSA_NULL, M4OSA_NULL)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(MediaRendering)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("RESIZING",      M4xVSS_kResizing),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("CROPPING",      M4xVSS_kCropping),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BLACK_BORDERS", M4xVSS_kBlackBorders)
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(MediaRendering, MEDIA_RENDERING_CLASS_NAME,
+ M4OSA_NULL, M4OSA_NULL)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(SlideDirection)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("RIGHT_OUT_LEFT_IN", M4xVSS_SlideTransition_RightOutLeftIn),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("LEFT_OUT_RIGTH_IN", M4xVSS_SlideTransition_LeftOutRightIn),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("TOP_OUT_BOTTOM_IN", M4xVSS_SlideTransition_TopOutBottomIn),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BOTTOM_OUT_TOP_IN", M4xVSS_SlideTransition_BottomOutTopIn)
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(SlideDirection, SLIDE_DIRECTION_CLASS_NAME,
+ M4OSA_NULL, M4OSA_NULL)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(TransitionBehaviour)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("SPEED_UP",    M4VSS3GPP_TransitionBehaviour_SpeedUp),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("LINEAR",      M4VSS3GPP_TransitionBehaviour_Linear),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("SPEED_DOWN",  M4VSS3GPP_TransitionBehaviour_SpeedDown),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("SLOW_MIDDLE", M4VSS3GPP_TransitionBehaviour_SlowMiddle),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FAST_MIDDLE", M4VSS3GPP_TransitionBehaviour_FastMiddle)
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(TransitionBehaviour, TRANSITION_BEHAVIOUR_CLASS_NAME,
+ M4OSA_NULL, M4OSA_NULL)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(VideoEffect)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("NONE",            M4VSS3GPP_kVideoEffectType_None),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FADE_FROM_BLACK", M4VSS3GPP_kVideoEffectType_FadeFromBlack),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("CURTAIN_OPENING", M4VSS3GPP_kVideoEffectType_CurtainOpening),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FADE_TO_BLACK",   M4VSS3GPP_kVideoEffectType_FadeToBlack),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("CURTAIN_CLOSING", M4VSS3GPP_kVideoEffectType_CurtainClosing),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("EXTERNAL",        M4VSS3GPP_kVideoEffectType_External),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("BLACK_AND_WHITE", M4xVSS_kVideoEffectType_BlackAndWhite),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("PINK",            M4xVSS_kVideoEffectType_Pink),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("GREEN",           M4xVSS_kVideoEffectType_Green),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("SEPIA",           M4xVSS_kVideoEffectType_Sepia),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("NEGATIVE",        M4xVSS_kVideoEffectType_Negative),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FRAMING",         M4xVSS_kVideoEffectType_Framing),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("TEXT",            M4xVSS_kVideoEffectType_Text),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ZOOM_IN",         M4xVSS_kVideoEffectType_ZoomIn),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ZOOM_OUT",        M4xVSS_kVideoEffectType_ZoomOut),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FIFTIES",         M4xVSS_kVideoEffectType_Fifties),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("COLORRGB16",      M4xVSS_kVideoEffectType_ColorRGB16),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("GRADIENT",        M4xVSS_kVideoEffectType_Gradient),
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(VideoEffect, VIDEO_EFFECT_CLASS_NAME, M4OSA_NULL, M4OSA_NULL)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(VideoFormat)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("NO_VIDEO",    M4VIDEOEDITING_kNoneVideo),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H263",        M4VIDEOEDITING_kH263),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("MPEG4",       M4VIDEOEDITING_kMPEG4),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("MPEG4_EMP",   M4VIDEOEDITING_kMPEG4_EMP),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264",        M4VIDEOEDITING_kH264),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("NULL_VIDEO",  M4VIDEOEDITING_kNullVideo),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("UNSUPPORTED", M4VIDEOEDITING_kUnsupportedVideo),
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(VideoFormat, VIDEO_FORMAT_CLASS_NAME, M4OSA_NULL, M4OSA_NULL)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(VideoFrameRate)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FR_5_FPS",    M4VIDEOEDITING_k5_FPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FR_7_5_FPS",  M4VIDEOEDITING_k7_5_FPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FR_10_FPS",   M4VIDEOEDITING_k10_FPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FR_12_5_FPS", M4VIDEOEDITING_k12_5_FPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FR_15_FPS",   M4VIDEOEDITING_k15_FPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FR_20_FPS",   M4VIDEOEDITING_k20_FPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FR_25_FPS",   M4VIDEOEDITING_k25_FPS),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FR_30_FPS",   M4VIDEOEDITING_k30_FPS)
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(VideoFrameRate, VIDEO_FRAME_RATE_CLASS_NAME,
+ M4OSA_NULL, M4OSA_NULL)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(VideoFrameSize)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("SQCIF", M4VIDEOEDITING_kSQCIF),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("QQVGA", M4VIDEOEDITING_kQQVGA),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("QCIF",  M4VIDEOEDITING_kQCIF),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("QVGA",  M4VIDEOEDITING_kQVGA),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("CIF",   M4VIDEOEDITING_kCIF),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("VGA",   M4VIDEOEDITING_kVGA),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("WVGA", M4VIDEOEDITING_kWVGA),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("NTSC", M4VIDEOEDITING_kNTSC),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("nHD", M4VIDEOEDITING_k640_360),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("WVGA16x9", M4VIDEOEDITING_k854_480),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("V720p", M4VIDEOEDITING_kHD1280),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("W720p", M4VIDEOEDITING_kHD1080),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("S720p", M4VIDEOEDITING_kHD960)
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(VideoFrameSize, VIDEO_FRAME_SIZE_CLASS_NAME,
+ M4OSA_NULL, M4OSA_NULL)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(VideoProfile)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("MPEG4_SP_LEVEL_0",       \
+        M4VIDEOEDITING_kMPEG4_SP_Level_0),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("MPEG4_SP_LEVEL_0B",      \
+        M4VIDEOEDITING_kMPEG4_SP_Level_0b),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("MPEG4_SP_LEVEL_1",       \
+        M4VIDEOEDITING_kMPEG4_SP_Level_1),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("MPEG4_SP_LEVEL_2",       \
+        M4VIDEOEDITING_kMPEG4_SP_Level_2),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("MPEG4_SP_LEVEL_3",       \
+        M4VIDEOEDITING_kMPEG4_SP_Level_3),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("MPEG4_SP_LEVEL_4A",      \
+        M4VIDEOEDITING_kMPEG4_SP_Level_4a),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("MPEG4_SP_LEVEL_5",       \
+        M4VIDEOEDITING_kMPEG4_SP_Level_5),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H263_PROFILE_0_LEVEL_10",\
+        M4VIDEOEDITING_kH263_Profile_0_Level_10),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H263_PROFILE_0_LEVEL_20",\
+        M4VIDEOEDITING_kH263_Profile_0_Level_20),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H263_PROFILE_0_LEVEL_30",\
+        M4VIDEOEDITING_kH263_Profile_0_Level_30),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H263_PROFILE_0_LEVEL_40",\
+        M4VIDEOEDITING_kH263_Profile_0_Level_40),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H263_PROFILE_0_LEVEL_45",\
+        M4VIDEOEDITING_kH263_Profile_0_Level_45),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_1", \
+        M4VIDEOEDITING_kH264_Profile_0_Level_1),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_1b",\
+        M4VIDEOEDITING_kH264_Profile_0_Level_1b),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_1_1",\
+        M4VIDEOEDITING_kH264_Profile_0_Level_1_1),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_1_2",\
+        M4VIDEOEDITING_kH264_Profile_0_Level_1_2),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_1_3",\
+        M4VIDEOEDITING_kH264_Profile_0_Level_1_3),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_2",  \
+        M4VIDEOEDITING_kH264_Profile_0_Level_2),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_2_1",\
+        M4VIDEOEDITING_kH264_Profile_0_Level_2_1),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_2_2",\
+        M4VIDEOEDITING_kH264_Profile_0_Level_2_2),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_3",  \
+        M4VIDEOEDITING_kH264_Profile_0_Level_3),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_3_1",\
+        M4VIDEOEDITING_kH264_Profile_0_Level_3_1),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_3_2",\
+        M4VIDEOEDITING_kH264_Profile_0_Level_3_2),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_4",  \
+        M4VIDEOEDITING_kH264_Profile_0_Level_4),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_4_1",\
+        M4VIDEOEDITING_kH264_Profile_0_Level_4_1),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_4_2",\
+        M4VIDEOEDITING_kH264_Profile_0_Level_4_2),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_5",  \
+        M4VIDEOEDITING_kH264_Profile_0_Level_5),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("H264_PROFILE_0_LEVEL_5_1",\
+        M4VIDEOEDITING_kH264_Profile_0_Level_5_1),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("OUT_OF_RANGE",            \
+        M4VIDEOEDITING_kProfile_and_Level_Out_Of_Range)
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(VideoProfile, VIDEO_PROFILE_CLASS_NAME, M4OSA_NULL,
+                                     M4OSA_NULL)
+
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANTS(VideoTransition)
+{
+    VIDEOEDIT_JAVA_CONSTANT_INIT("NONE",             M4VSS3GPP_kVideoTransitionType_None),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("CROSS_FADE",       M4VSS3GPP_kVideoTransitionType_CrossFade),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("EXTERNAL",         M4VSS3GPP_kVideoTransitionType_External),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("ALPHA_MAGIC",      M4xVSS_kVideoTransitionType_AlphaMagic),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("SLIDE_TRANSITION", M4xVSS_kVideoTransitionType_SlideTransition),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("FADE_BLACK",       M4xVSS_kVideoTransitionType_FadeBlack)
+};
+
+VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(VideoTransition, VIDEO_TRANSITION_CLASS_NAME,
+                                     M4OSA_NULL, M4OSA_NULL)
+
+
+VIDEOEDIT_JAVA_DEFINE_FIELDS(AlphaMagic)
+{
+    VIDEOEDIT_JAVA_FIELD_INIT("file",            "Ljava/lang/String;"),
+    VIDEOEDIT_JAVA_FIELD_INIT("blendingPercent", "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("invertRotation",  "Z"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("rgbWidth",  "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("rgbHeight",  "I"                 )
+};
+
+VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(AlphaMagic, ALPHA_MAGIC_SETTINGS_CLASS_NAME)
+
+VIDEOEDIT_JAVA_DEFINE_FIELDS(Properties)
+{
+    VIDEOEDIT_JAVA_FIELD_INIT("duration",               "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("fileType",               "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("videoFormat",            "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("videoDuration",          "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("videoBitrate",           "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("width",                  "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("height",                 "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("averageFrameRate",       "F"),
+    VIDEOEDIT_JAVA_FIELD_INIT("profileAndLevel",        "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("audioFormat",            "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("audioDuration",          "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("audioBitrate",           "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("audioChannels",          "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("audioSamplingFrequency", "I")
+};
+
+VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(Properties, PROPERTIES_CLASS_NAME)
+
+VIDEOEDIT_JAVA_DEFINE_FIELDS(BackgroundMusic)
+{
+    VIDEOEDIT_JAVA_FIELD_INIT("file",          "Ljava/lang/String;"),
+    VIDEOEDIT_JAVA_FIELD_INIT("fileType",      "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("insertionTime", "J"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("volumePercent", "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("beginLoop",     "J"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("endLoop",       "J"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("enableDucking",   "Z"               ),
+    VIDEOEDIT_JAVA_FIELD_INIT("duckingThreshold","I"               ),
+    VIDEOEDIT_JAVA_FIELD_INIT("lowVolume",         "I"             ),
+    VIDEOEDIT_JAVA_FIELD_INIT("isLooping",         "Z"             )
+};
+
+VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(BackgroundMusic, BACKGROUND_MUSIC_SETTINGS_CLASS_NAME)
+
+/*
+VIDEOEDIT_JAVA_DEFINE_FIELDS(BestEditSettings)
+{
+    VIDEOEDIT_JAVA_FIELD_INIT("videoFormat",    "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("videoFrameSize", "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("audioFormat",    "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("audioChannels",  "I")
+};
+
+VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(BestEditSettings, BEST_EDIT_SETTINGS_CLASS_NAME)
+*/
+
+VIDEOEDIT_JAVA_DEFINE_FIELDS(ClipSettings)
+{
+    VIDEOEDIT_JAVA_FIELD_INIT("clipPath",             "Ljava/lang/String;"),
+    VIDEOEDIT_JAVA_FIELD_INIT("fileType",             "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("beginCutTime",         "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("endCutTime",           "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("beginCutPercent",      "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("endCutPercent",        "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("panZoomEnabled",       "Z"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("panZoomPercentStart",  "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("panZoomTopLeftXStart", "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("panZoomTopLeftYStart", "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("panZoomPercentEnd",    "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("panZoomTopLeftXEnd",   "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("panZoomTopLeftYEnd",   "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("mediaRendering",       "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("rgbWidth",           "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("rgbHeight",          "I"                 )
+};
+
+VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(ClipSettings, CLIP_SETTINGS_CLASS_NAME)
+
+
+VIDEOEDIT_JAVA_DEFINE_FIELDS(EditSettings)
+{
+    VIDEOEDIT_JAVA_FIELD_INIT("clipSettingsArray",       "[L"CLIP_SETTINGS_CLASS_NAME";"         ),
+    VIDEOEDIT_JAVA_FIELD_INIT("transitionSettingsArray", "[L"TRANSITION_SETTINGS_CLASS_NAME";"   ),
+    VIDEOEDIT_JAVA_FIELD_INIT("effectSettingsArray",     "[L"EFFECT_SETTINGS_CLASS_NAME";"       ),
+    VIDEOEDIT_JAVA_FIELD_INIT("videoFrameRate",          "I"                                     ),
+    VIDEOEDIT_JAVA_FIELD_INIT("outputFile",              "Ljava/lang/String;"                    ),
+    VIDEOEDIT_JAVA_FIELD_INIT("videoFrameSize",          "I"                                     ),
+    VIDEOEDIT_JAVA_FIELD_INIT("videoFormat",             "I"                                     ),
+    VIDEOEDIT_JAVA_FIELD_INIT("audioFormat",             "I"                                     ),
+    VIDEOEDIT_JAVA_FIELD_INIT("audioSamplingFreq",       "I"                                     ),
+    VIDEOEDIT_JAVA_FIELD_INIT("maxFileSize",             "I"                                     ),
+    VIDEOEDIT_JAVA_FIELD_INIT("audioChannels",           "I"                                     ),
+    VIDEOEDIT_JAVA_FIELD_INIT("videoBitrate",            "I"                                     ),
+    VIDEOEDIT_JAVA_FIELD_INIT("audioBitrate",            "I"                                     ),
+    VIDEOEDIT_JAVA_FIELD_INIT("backgroundMusicSettings",\
+    "L"BACKGROUND_MUSIC_SETTINGS_CLASS_NAME";"),
+    VIDEOEDIT_JAVA_FIELD_INIT("primaryTrackVolume",            "I"                               )
+};
+
+VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(EditSettings, EDIT_SETTINGS_CLASS_NAME)
+
+
+VIDEOEDIT_JAVA_DEFINE_FIELDS(EffectSettings)
+{
+    VIDEOEDIT_JAVA_FIELD_INIT("startTime",                       "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("duration",                        "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("videoEffectType",                 "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("audioEffectType",                 "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("startPercent",                    "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("durationPercent",                 "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("framingFile",                     "Ljava/lang/String;"),
+    VIDEOEDIT_JAVA_FIELD_INIT("framingBuffer",                   "[I"                ),
+    VIDEOEDIT_JAVA_FIELD_INIT("bitmapType",                      "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("width",                           "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("height",                          "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("topLeftX",                        "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("topLeftY",                        "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("framingResize",                   "Z"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("framingScaledSize",               "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("text",                            "Ljava/lang/String;"),
+    VIDEOEDIT_JAVA_FIELD_INIT("textRenderingData",               "Ljava/lang/String;"),
+    VIDEOEDIT_JAVA_FIELD_INIT("textBufferWidth",                 "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("textBufferHeight",                "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("fiftiesFrameRate",                "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("rgb16InputColor",                 "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("alphaBlendingStartPercent",       "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("alphaBlendingMiddlePercent",      "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("alphaBlendingEndPercent",         "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("alphaBlendingFadeInTimePercent",  "I"                 ),
+    VIDEOEDIT_JAVA_FIELD_INIT("alphaBlendingFadeOutTimePercent", "I"                 )
+};
+
+VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(EffectSettings, EFFECT_SETTINGS_CLASS_NAME)
+
+
+VIDEOEDIT_JAVA_DEFINE_FIELDS(Engine)
+{
+    VIDEOEDIT_JAVA_FIELD_INIT("mManualEditContext", "I")
+};
+
+VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(Engine, MANUAL_EDIT_ENGINE_CLASS_NAME)
+
+
+VIDEOEDIT_JAVA_DEFINE_FIELDS(SlideTransitionSettings)
+{
+    VIDEOEDIT_JAVA_FIELD_INIT("direction", "I")
+};
+
+VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(SlideTransitionSettings, SLIDE_TRANSITION_SETTINGS_CLASS_NAME)
+
+
+VIDEOEDIT_JAVA_DEFINE_FIELDS(TransitionSettings)
+{
+    VIDEOEDIT_JAVA_FIELD_INIT("duration",            "I"                                       ),
+    VIDEOEDIT_JAVA_FIELD_INIT("videoTransitionType", "I"                                       ),
+    VIDEOEDIT_JAVA_FIELD_INIT("audioTransitionType", "I"                                       ),
+    VIDEOEDIT_JAVA_FIELD_INIT("transitionBehaviour", "I"                                       ),
+    VIDEOEDIT_JAVA_FIELD_INIT("alphaSettings",       "L"ALPHA_MAGIC_SETTINGS_CLASS_NAME";"     ),
+    VIDEOEDIT_JAVA_FIELD_INIT("slideSettings",       "L"SLIDE_TRANSITION_SETTINGS_CLASS_NAME";")
+};
+
+VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(TransitionSettings, TRANSITION_SETTINGS_CLASS_NAME)
+
+
+VIDEOEDIT_JAVA_DEFINE_FIELDS(Version)
+{
+    VIDEOEDIT_JAVA_FIELD_INIT("major",    "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("minor",    "I"),
+    VIDEOEDIT_JAVA_FIELD_INIT("revision", "I")
+};
+
+VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(Version, VERSION_CLASS_NAME)
+
+
+VIDEOEDIT_JAVA_DEFINE_METHODS(Engine)
+{
+    VIDEOEDIT_JAVA_METHOD_INIT("onProgressUpdate", "(II)V")
+};
+
+VIDEOEDIT_JAVA_DEFINE_METHOD_CLASS(Engine, MANUAL_EDIT_ENGINE_CLASS_NAME)
+
+
+static const char*
+videoEditClasses_getBrandString(M4OSA_UInt32 brand)
+{
+    static char         brandString[11] = "0x00000000";
+           const char*  pBrandString    = M4OSA_NULL;
+           M4OSA_UInt8* pBrand          = (M4OSA_UInt8*)&brand;
+           M4OSA_UInt32 brandHost       = 0;
+
+    // Convert the brand from big endian to host.
+    brandHost =  pBrand[0];
+    brandHost =  brandHost << 8;
+    brandHost += pBrand[1];
+    brandHost =  brandHost << 8;
+    brandHost += pBrand[2];
+    brandHost =  brandHost << 8;
+    brandHost += pBrand[3];
+
+    switch (brandHost)
+    {
+    case M4VIDEOEDITING_BRAND_0000:
+        pBrandString = "0000";
+        break;
+    case M4VIDEOEDITING_BRAND_3G2A:
+        pBrandString = "3G2A";
+        break;
+    case M4VIDEOEDITING_BRAND_3GP4:
+        pBrandString = "3GP4";
+        break;
+    case M4VIDEOEDITING_BRAND_3GP5:
+        pBrandString = "3GP5";
+        break;
+    case M4VIDEOEDITING_BRAND_3GP6:
+        pBrandString = "3GP6";
+        break;
+    case M4VIDEOEDITING_BRAND_AVC1:
+        pBrandString = "AVC1";
+        break;
+    case M4VIDEOEDITING_BRAND_EMP:
+        pBrandString = "EMP";
+        break;
+    case M4VIDEOEDITING_BRAND_ISOM:
+        pBrandString = "ISOM";
+        break;
+    case M4VIDEOEDITING_BRAND_MP41:
+        pBrandString = "MP41";
+        break;
+    case M4VIDEOEDITING_BRAND_MP42:
+        pBrandString = "MP42";
+        break;
+    case M4VIDEOEDITING_BRAND_VFJ1:
+        pBrandString = "VFJ1";
+        break;
+    default:
+        M4OSA_chrSPrintf((M4OSA_Char *)brandString,
+                         sizeof(brandString) - 1,
+                         (M4OSA_Char*)"0x%08X", brandHost);
+        pBrandString = brandString;
+        break;
+    }
+
+    // Return the brand string.
+    return(pBrandString);
+}
+
+#ifdef VIDEOEDIT_LOGGING_ENABLED
+static void
+videoEditClasses_logFtypBox(
+                M4VIDEOEDITING_FtypBox*             pBox,
+                int                                 indentation)
+{
+    // Check if memory was allocated for the FtypBox.
+    if (M4OSA_NULL != pBox)
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                "%*c major_brand:        %s",    indentation, ' ',
+                 videoEditClasses_getBrandString(pBox->major_brand));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                "%*c minor_version:      %08X",  indentation, ' ',
+                (unsigned int)pBox->minor_version);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                "%*c nbCompatibleBrands: %u",    indentation, ' ',
+                (unsigned int)pBox->nbCompatibleBrands);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                "%*c compatible_brands:", indentation, ' ');
+                indentation += VIDEOEDIT_LOG_INDENTATION;
+        for (int i = 0; (i < (int)pBox->nbCompatibleBrands) &&\
+         (i < M4VIDEOEDITING_MAX_COMPATIBLE_BRANDS); i++)
+        {
+            VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                    "%*c compatible_brand[%d]: %s",    indentation, ' ',
+                    i, videoEditClasses_getBrandString(pBox->compatible_brands[i]));
+        }
+        indentation -= VIDEOEDIT_LOG_INDENTATION;
+    }
+    else
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c <null>",
+                 indentation, ' ');
+    }
+}
+#endif
+
+
+void
+videoEditClasses_init(
+                bool*                               pResult,
+                JNIEnv*                             pEnv)
+{
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",\
+        "videoEditClasses_init()");
+
+        // Initialize the constants.
+        videoEditJava_initAudioEffectConstants(pResult, pEnv);
+        videoEditJava_initAudioFormatConstants(pResult, pEnv);
+        videoEditJava_initAudioSamplingFrequencyConstants(pResult, pEnv);
+        videoEditJava_initAudioTransitionConstants(pResult, pEnv);
+        videoEditJava_initBitrateConstants(pResult, pEnv);
+        videoEditJava_initClipTypeConstants(pResult, pEnv);
+        videoEditJava_initEngineConstants(pResult, pEnv);
+        videoEditJava_initErrorConstants(pResult, pEnv);
+        videoEditJava_initFileTypeConstants(pResult, pEnv);
+        videoEditJava_initMediaRenderingConstants(pResult, pEnv);
+        videoEditJava_initSlideDirectionConstants(pResult, pEnv);
+        videoEditJava_initTransitionBehaviourConstants(pResult, pEnv);
+        videoEditJava_initVideoEffectConstants(pResult, pEnv);
+        videoEditJava_initVideoFormatConstants(pResult, pEnv);
+        videoEditJava_initVideoFrameRateConstants(pResult, pEnv);
+        videoEditJava_initVideoFrameSizeConstants(pResult, pEnv);
+        videoEditJava_initVideoProfileConstants(pResult, pEnv);
+        videoEditJava_initVideoTransitionConstants(pResult, pEnv);
+
+        // Initialize the fields.
+        videoEditJava_initAlphaMagicFields(pResult, pEnv);
+        videoEditJava_initBackgroundMusicFields(pResult, pEnv);
+        videoEditJava_initClipSettingsFields(pResult, pEnv);
+        videoEditJava_initEditSettingsFields(pResult, pEnv);
+        videoEditJava_initEffectSettingsFields(pResult, pEnv);
+        videoEditJava_initEngineFields(pResult, pEnv);
+        videoEditJava_initSlideTransitionSettingsFields(pResult, pEnv);
+        videoEditJava_initTransitionSettingsFields(pResult, pEnv);
+        videoEditJava_initVersionFields(pResult, pEnv);
+        // Initialize the methods.
+        videoEditJava_initEngineMethods(pResult, pEnv);
+    }
+}
+
+void
+videoEditPropClass_init(
+                bool*                               pResult,
+                JNIEnv*                             pEnv)
+{
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",\
+            "videoEditPropClass_init()");
+
+        // Initialize the constants.
+        videoEditJava_initAudioFormatConstants(pResult, pEnv);
+        videoEditJava_initErrorConstants(pResult, pEnv);
+        videoEditJava_initFileTypeConstants(pResult, pEnv);
+        videoEditJava_initVideoFormatConstants(pResult, pEnv);
+        videoEditJava_initVideoProfileConstants(pResult, pEnv);
+
+        // Initialize the fields.
+        videoEditJava_initPropertiesFields(pResult, pEnv);
+    }
+}
+
+void
+videoEditClasses_getAlphaMagicSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                M4xVSS_AlphaMagicSettings**         ppSettings)
+{
+    VideoEditJava_AlphaMagicFieldIds   fieldIds  = {NULL, NULL, NULL, NULL, NULL};
+    M4xVSS_AlphaMagicSettings* pSettings = M4OSA_NULL;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                   "videoEditClasses_getAlphaMagicSettings()");
+
+        // Retrieve the field ids.
+        videoEditJava_getAlphaMagicFieldIds(pResult, pEnv, &fieldIds);
+    }
+
+    // Only validate the AlphaMagicSettings if the fields could be located.
+    if (*pResult)
+    {
+        // Check if the clip is set.
+        videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                                                    (NULL == object),
+                                                    "alphaSettings is null");
+    }
+
+    // Only retrieve the AlphaMagicSettings if the fields could be located and validated.
+    if (*pResult)
+    {
+        // Allocate memory for the AlphaMagicSettings.
+        pSettings = (M4xVSS_AlphaMagicSettings*)videoEditOsal_alloc(pResult, pEnv,
+                sizeof(M4xVSS_AlphaMagicSettings), "AlphaMagicSettings");
+
+        // Check if memory could be allocated for the AlphaMagicSettings.
+        if (*pResult)
+        {
+            // Set the alpha magic file path (JPG file).
+            pSettings->pAlphaFilePath = (M4OSA_Char*)videoEditJava_getString(pResult, pEnv, object,
+                    fieldIds.file, M4OSA_NULL);
+
+            // Check if the alpha magic file path is valid.
+            videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                    (M4OSA_NULL == pSettings->pAlphaFilePath), "alphaSettings.file is null");
+        }
+
+        // Check if the alpha file path could be retrieved.
+        if (*pResult)
+        {
+            // Set the blending percentage between 0 and 100.
+            pSettings->blendingPercent = (M4OSA_UInt8)pEnv->GetIntField(object,
+                    fieldIds.blendingPercent);
+
+            // Set the direct effect or reverse.
+            pSettings->isreverse = (M4OSA_Bool)pEnv->GetBooleanField(object,
+                    fieldIds.invertRotation);
+
+            // Get the rgb width
+            pSettings->width = (M4OSA_UInt32) pEnv->GetIntField(object, fieldIds.rgbWidth );
+
+            pSettings->height = (M4OSA_UInt32) pEnv->GetIntField(object, fieldIds.rgbHeight );
+
+             VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                    "((((((((((path %s", pSettings->pAlphaFilePath);
+
+            VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                    "------- getAlphaMagicSettings width %d", pEnv->GetIntField(object,
+                    fieldIds.rgbWidth ));
+            VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                   "-------- getAlphaMagicSettings Height %d",
+                   pEnv->GetIntField(object, fieldIds.rgbHeight ));
+        }
+
+        // Check if settings could be set.
+        if (*pResult)
+        {
+            // Return the settings.
+            (*ppSettings) = pSettings;
+        }
+        else
+        {
+            // Free the settings.
+            videoEditClasses_freeAlphaMagicSettings(&pSettings);
+        }
+    }
+}
+
+void
+videoEditClasses_freeAlphaMagicSettings(
+                M4xVSS_AlphaMagicSettings**         ppSettings)
+{
+    // Check if memory was allocated for the AlphaMagicSettings.
+    if (M4OSA_NULL != (*ppSettings))
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                  "videoEditClasses_freeAlphaMagicSettings()");
+
+        // Free the alpha file path.
+        videoEditOsal_free((*ppSettings)->pAlphaFilePath);
+        (*ppSettings)->pAlphaFilePath = M4OSA_NULL;
+
+        // Free the settings structure.
+        videoEditOsal_free((*ppSettings));
+        (*ppSettings) = M4OSA_NULL;
+    }
+}
+
+#ifdef VIDEOEDIT_LOGGING_ENABLED
+void
+videoEditClasses_logAlphaMagicSettings(
+                M4xVSS_AlphaMagicSettings*          pSettings,
+                int                                 indentation)
+{
+    // Check if memory was allocated for the AlphaMagicSettings.
+    if (M4OSA_NULL != pSettings)
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+             "%*c pAlphaFilePath:  %s",    indentation, ' ',
+            (M4OSA_NULL != pSettings->pAlphaFilePath) ? \
+            (char *)pSettings->pAlphaFilePath : "<null>");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+             "%*c blendingPercent: %u %%", indentation, ' ',
+            (unsigned int)pSettings->blendingPercent);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c isreverse:       %s",    indentation, ' ',
+            pSettings->isreverse ? "true" : "false");
+    }
+    else
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c <null>", indentation, ' ');
+    }
+}
+#endif
+
+
+void
+videoEditClasses_getBackgroundMusicSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                M4xVSS_BGMSettings**                ppSettings)
+{
+    VideoEditJava_BackgroundMusicFieldIds fieldIds  = {NULL, NULL, NULL, NULL,
+                                                       NULL, NULL,NULL,NULL,NULL,NULL};
+    M4xVSS_BGMSettings*           pSettings = M4OSA_NULL;
+    bool                          converted = true;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+               "videoEditClasses_getBackgroundMusicSettings()");
+
+        // Retrieve the field ids.
+        videoEditJava_getBackgroundMusicFieldIds(pResult, pEnv, &fieldIds);
+    }
+
+    // Only retrieve the BackgroundMusicSettings if the fields could be located.
+    if (*pResult)
+    {
+        // Check if the object is valid.
+        if (NULL != object)
+        {
+            // Allocate memory for the BackgroundMusicSettings.
+            pSettings = (M4xVSS_BGMSettings*)videoEditOsal_alloc(pResult, pEnv,
+                sizeof(M4xVSS_BGMSettings), "BackgroundMusicSettings");
+
+            // Check if memory could be allocated for the BackgroundMusicSettings.
+            if (*pResult)
+            {
+                // Set the input file path.
+                pSettings->pFile = (M4OSA_Char*)videoEditJava_getString(pResult, pEnv, object,
+                        fieldIds.file, M4OSA_NULL);
+
+                // Check if the input file path is valid.
+                videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                        (M4OSA_NULL == pSettings->pFile), "backgroundMusicSettings.file is null");
+            }
+
+            // Check if the input file path could be retrieved.
+            if (*pResult)
+            {
+                // Set the file type .3gp, .amr, .mp3.
+                pSettings->FileType = M4VIDEOEDITING_kFileType_PCM;
+                /*(M4VIDEOEDITING_FileType)videoEditJava_getClipTypeJavaToC(
+                 &converted, pEnv->GetIntField(object, fieldIds.fileType));*/
+
+                // Check if the file type is valid.
+                videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                        !converted, "backgroundMusicSettings.fileType is invalid");
+            }
+
+            // Check if the file type could be retrieved.
+            if (*pResult)
+            {
+                // Set the time, in milliseconds, at which the added audio track is inserted.
+                pSettings->uiAddCts = (M4OSA_UInt32)pEnv->GetLongField(object,
+                        fieldIds.insertionTime);
+
+                // Set the volume, in percentage (0..100), of the added audio track.
+                pSettings->uiAddVolume = (M4OSA_UInt32)pEnv->GetIntField(object,
+                        fieldIds.volumePercent);
+
+                // Set the start time of the loop in milli seconds.
+                pSettings->uiBeginLoop = (M4OSA_UInt32)pEnv->GetLongField(object,
+                        fieldIds.beginLoop);
+
+                // Set the end time of the loop in milli seconds.
+                pSettings->uiEndLoop = (M4OSA_UInt32)pEnv->GetLongField(object,
+                        fieldIds.endLoop);
+                // Set the end time of the loop in milli seconds.
+                pSettings->b_DuckingNeedeed =
+                        (M4OSA_Bool)pEnv->GetBooleanField(object, fieldIds.enableDucking);
+
+                // Set the end time of the loop in milli seconds.
+                pSettings->InDucking_threshold =
+                        (M4OSA_Int32)pEnv->GetIntField(object, fieldIds.duckingThreshold);
+
+                // Set the end time of the loop in milli seconds.
+                pSettings->lowVolume =
+                        (M4OSA_Float)(((M4OSA_Float)pEnv->GetIntField(object, fieldIds.lowVolume)));
+
+                // Set the end time of the loop in milli seconds.
+                pSettings->bLoop = (M4OSA_Bool)pEnv->GetBooleanField(object, fieldIds.isLooping);
+
+                // Set sampling freq and channels
+                pSettings->uiSamplingFrequency = M4VIDEOEDITING_k32000_ASF;
+                pSettings->uiNumChannels = 2;
+            }
+
+            // Check if settings could be set.
+            if (*pResult)
+            {
+                // Return the settings.
+                (*ppSettings) = pSettings;
+            }
+            else
+            {
+                // Free the settings.
+                videoEditClasses_freeBackgroundMusicSettings(&pSettings);
+            }
+        }
+    }
+}
+
+void
+videoEditClasses_freeBackgroundMusicSettings(
+                M4xVSS_BGMSettings**                ppSettings)
+{
+    // Check if memory was allocated for the BackgroundMusicSettings.
+    if (M4OSA_NULL != (*ppSettings))
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+         "videoEditClasses_freeBackgroundMusicSettings()");
+
+        // Free the input file path.
+        videoEditOsal_free((*ppSettings)->pFile);
+        (*ppSettings)->pFile = M4OSA_NULL;
+
+        // Free the settings structure.
+        videoEditOsal_free((*ppSettings));
+        (*ppSettings) = M4OSA_NULL;
+    }
+}
+
+#ifdef VIDEOEDIT_LOGGING_ENABLED
+void
+videoEditClasses_logBackgroundMusicSettings(
+                M4xVSS_BGMSettings*                 pSettings,
+                int                                 indentation)
+{
+    // Check if memory was allocated for the BackgroundMusicSettings.
+    if (M4OSA_NULL != pSettings)
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c pFile:       %s",
+            indentation, ' ',
+            (M4OSA_NULL != pSettings->pFile) ? (char *)pSettings->pFile : "<null>");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c FileType:    %s",    indentation, ' ',
+            videoEditJava_getClipTypeString(pSettings->FileType));
+
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c uiAddCts:    %u ms",
+            indentation, ' ', (unsigned int)pSettings->uiAddCts);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c uiAddVolume: %u %%",
+            indentation, ' ', (unsigned int)pSettings->uiAddVolume);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c uiBeginLoop: %u ms",
+            indentation, ' ', (unsigned int)pSettings->uiBeginLoop);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c uiEndLoop:   %u ms",
+            indentation, ' ', (unsigned int)pSettings->uiEndLoop);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c b_DuckingNeedeed:\
+            %u ", indentation, ' ', (bool)pSettings->b_DuckingNeedeed);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c InDucking_threshold: \
+            %u ms", indentation, ' ', (unsigned int)pSettings->InDucking_threshold);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c lowVolume:   %2.2f ",\
+            indentation, ' ', (float)pSettings->lowVolume);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c bLoop:   %u ms",\
+            indentation, ' ', (bool)pSettings->bLoop);
+    }
+    else
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c <null>",
+            indentation, ' ');
+    }
+}
+#endif
+
+#ifdef VIDEOEDIT_LOGGING_ENABLED
+void
+videoEditClasses_logClipProperties(
+                M4VIDEOEDITING_ClipProperties*      pProperties,
+                int                                 indentation)
+{
+    // Check if memory was allocated for the ClipProperties.
+    if (M4OSA_NULL != pProperties)
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c bAnalysed:                        %s",       indentation, ' ',
+            pProperties->bAnalysed ? "true" : "false");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c Version:                          %d.%d.%d", indentation, ' ',
+            pProperties->Version[0], pProperties->Version[1], pProperties->Version[2]);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiClipDuration:                   %u",       indentation, ' ',
+            (unsigned int)pProperties->uiClipDuration);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c FileType:                         %s",       indentation, ' ',
+            videoEditJava_getClipTypeString(pProperties->FileType));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c ftyp:",
+                                              indentation, ' ');
+        videoEditClasses_logFtypBox(&pProperties->ftyp, indentation + VIDEOEDIT_LOG_INDENTATION);
+
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c VideoStreamType:                  %s",       indentation, ' ',
+            videoEditJava_getVideoFormatString(pProperties->VideoStreamType));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiClipVideoDuration:              %u",       indentation, ' ',
+            (unsigned int)pProperties->uiClipVideoDuration);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiVideoBitrate:                   %s",       indentation, ' ',
+            videoEditJava_getBitrateString(pProperties->uiVideoBitrate));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiVideoMaxAuSize:                 %u",       indentation, ' ',
+            (unsigned int)pProperties->uiVideoMaxAuSize);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiVideoWidth:                     %u",       indentation, ' ',
+            (unsigned int)pProperties->uiVideoWidth);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiVideoHeight:                    %u",       indentation, ' ',
+            (unsigned int)(unsigned int)pProperties->uiVideoHeight);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiVideoTimeScale:                 %u",       indentation, ' ',
+            (unsigned int)pProperties->uiVideoTimeScale);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c fAverageFrameRate:                %.3f",     indentation, ' ',
+            pProperties->fAverageFrameRate);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c ProfileAndLevel:                  %s",       indentation, ' ',
+            videoEditJava_getVideoProfileString(pProperties->ProfileAndLevel));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiH263level:                      %d",       indentation, ' ',
+            pProperties->uiH263level);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiVideoProfile:                   %d",       indentation, ' ',
+            pProperties->uiVideoProfile);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c bMPEG4dataPartition:              %s",       indentation, ' ',
+            pProperties->bMPEG4dataPartition ? "true" : "false");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c bMPEG4rvlc:                       %s",       indentation, ' ',
+            pProperties->bMPEG4rvlc ? "true" : "false");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c bMPEG4resynchMarker:              %s",       indentation, ' ',
+            pProperties->bMPEG4resynchMarker ? "true" : "false");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c AudioStreamType:                  %s",       indentation, ' ',
+            videoEditJava_getAudioFormatString(pProperties->AudioStreamType));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiClipAudioDuration:              %u",       indentation, ' ',
+            (unsigned int)pProperties->uiClipAudioDuration);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiAudioBitrate:                   %s",       indentation, ' ',
+            videoEditJava_getBitrateString(pProperties->uiAudioBitrate));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiAudioMaxAuSize:                 %u",       indentation, ' ',
+            (unsigned int)pProperties->uiAudioMaxAuSize);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiNbChannels:                     %u",       indentation, ' ',
+            (unsigned int)pProperties->uiNbChannels);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiSamplingFrequency:              %u",       indentation, ' ',
+            (unsigned int)pProperties->uiSamplingFrequency);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiExtendedSamplingFrequency:      %u",       indentation, ' ',
+            (unsigned int)pProperties->uiExtendedSamplingFrequency);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiDecodedPcmSize:                 %u",       indentation, ' ',
+            (unsigned int)pProperties->uiDecodedPcmSize);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c bVideoIsEditable:                 %s",       indentation, ' ',
+            pProperties->bVideoIsEditable ? "true" : "false");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c bAudioIsEditable:                 %s",       indentation, ' ',
+            pProperties->bAudioIsEditable ? "true" : "false");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c bVideoIsCompatibleWithMasterClip: %s",       indentation, ' ',
+            pProperties->bVideoIsCompatibleWithMasterClip ? "true" : "false");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c bAudioIsCompatibleWithMasterClip: %s",       indentation, ' ',
+            pProperties->bAudioIsCompatibleWithMasterClip ? "true" : "false");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiClipAudioVolumePercentage:      %d",       indentation, ' ',
+                        pProperties->uiClipAudioVolumePercentage);
+    }
+    else
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c <null>",
+            indentation, ' ');
+    }
+}
+#endif
+
+void
+videoEditClasses_getClipSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                M4VSS3GPP_ClipSettings**            ppSettings)
+{
+    VideoEditJava_ClipSettingsFieldIds fieldIds  = {NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                             NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+    M4VSS3GPP_ClipSettings*    pSettings = M4OSA_NULL;
+    M4OSA_ERR                  result    = M4NO_ERROR;
+    bool                       converted = true;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "videoEditClasses_getClipSettings()");
+
+        // Retrieve the field ids.
+        videoEditJava_getClipSettingsFieldIds(pResult, pEnv, &fieldIds);
+    }
+
+    // Only validate the ClipSettings if the fields could be located.
+    if (*pResult)
+    {
+        // Check if the clip is set.
+        videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                                                    (NULL == object),
+                                                    "clip is null");
+    }
+
+    // Only retrieve the ClipSettings if the fields could be located and validated.
+    if (*pResult)
+    {
+        // Allocate memory for the ClipSettings.
+        pSettings = (M4VSS3GPP_ClipSettings *)videoEditOsal_alloc(pResult, pEnv,
+            sizeof(M4VSS3GPP_ClipSettings), "ClipSettings");
+
+        // Check if memory could be allocated for the ClipSettings.
+        if (*pResult)
+        {
+            // Log the API call.
+            VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4xVSS_CreateClipSettings()");
+
+            // Initialize the ClipSettings.
+            result = M4xVSS_CreateClipSettings(pSettings, NULL, 0, 0);
+
+            // Log the result.
+            VIDEOEDIT_LOG_RESULT(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+                videoEditOsal_getResultString(result));
+
+            // Check if the initialization succeeded.
+            videoEditJava_checkAndThrowRuntimeException(pResult, pEnv,
+                (M4NO_ERROR != result), result);
+        }
+
+        // Check if the allocation and initialization succeeded
+        //(required because pSettings is dereferenced).
+        if (*pResult)
+        {
+            // Set the input file path.
+            pSettings->pFile = (M4OSA_Char*)videoEditJava_getString(pResult, pEnv, object,
+                fieldIds.clipPath, &pSettings->filePathSize);
+
+            // Check if the file path is valid.
+            videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                    (M4OSA_NULL == pSettings->pFile), "clip.clipPath is null");
+        }
+
+        // Check if the input file could be retrieved.
+        if (*pResult)
+        {
+            // Set the file type .3gp, .amr, .mp3.
+            pSettings->FileType = (M4VIDEOEDITING_FileType)videoEditJava_getClipTypeJavaToC(
+                                        &converted, pEnv->GetIntField(object, fieldIds.fileType));
+
+            if ( pSettings->FileType == M4VIDEOEDITING_kFileType_JPG)
+            {
+                 pSettings->FileType = M4VIDEOEDITING_kFileType_ARGB8888;
+            }
+
+            // Check if the file type is valid.
+            videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                    !converted, "clip.fileType is invalid");
+        }
+
+        // Check if the file type could be retrieved.
+        if (*pResult)
+        {
+            // Set the begin cut time, in milliseconds.
+            pSettings->uiBeginCutTime =
+                (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.beginCutTime);
+
+            // Set the end cut time, in milliseconds.
+            pSettings->uiEndCutTime = (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.endCutTime);
+
+            // Set the begin cut time, in percent of clip duration (only for 3GPP clip !).
+            pSettings->xVSS.uiBeginCutPercent =
+                (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.beginCutPercent);
+
+            // Set the end cut time, in percent of clip duration (only for 3GPP clip !).
+            pSettings->xVSS.uiEndCutPercent =
+                (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.endCutPercent);
+
+            // Set the duration of the clip, if different from 0,
+            // has priority on uiEndCutTime or uiEndCutPercent.
+            pSettings->xVSS.uiDuration = 0;
+
+            // Set whether or not the pan and zoom mode is enabled.
+            pSettings->xVSS.isPanZoom =
+                (M4OSA_Bool)pEnv->GetBooleanField(object, fieldIds.panZoomEnabled);
+
+            // Set the pan and zoom start zoom percentage.
+            pSettings->xVSS.PanZoomXa        =
+                (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.panZoomPercentStart);
+
+            // Set the pan and zoom start x.
+            pSettings->xVSS.PanZoomTopleftXa =
+                (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.panZoomTopLeftXStart);
+
+            // Set the pan and zoom start y.
+            pSettings->xVSS.PanZoomTopleftYa =
+                (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.panZoomTopLeftYStart);
+
+            // Set the pan and zoom end zoom percentage.
+            pSettings->xVSS.PanZoomXb        =
+                (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.panZoomPercentEnd);
+
+            // Set the pan and zoom end x.
+            pSettings->xVSS.PanZoomTopleftXb =
+                (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.panZoomTopLeftXEnd);
+
+            // Set the pan and zoom end y.
+            pSettings->xVSS.PanZoomTopleftYb =
+                (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.panZoomTopLeftYEnd);
+
+            // Set the media rendering mode, only used with JPEG to crop, resize,
+            // or render black borders.
+            pSettings->xVSS.MediaRendering =
+                (M4xVSS_MediaRendering)videoEditJava_getMediaRenderingJavaToC(
+                    &converted, pEnv->GetIntField(object,fieldIds.mediaRendering));
+
+            // Check if the media rendering is valid.
+            videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv, !converted,
+                "clip.mediaRendering is invalid");
+
+             // Capture the rgb file width and height
+            pSettings->ClipProperties.uiStillPicWidth =
+                (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.rgbFileWidth);
+            pSettings->ClipProperties.uiStillPicHeight  =
+                (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.rgbFileHeight);
+
+            VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", \
+                "getClipSettings-- rgbFileWidth %d ",
+                pSettings->ClipProperties.uiStillPicWidth);
+            VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", \
+                "getClipSettings-- rgbFileHeight %d ",
+                pSettings->ClipProperties.uiStillPicHeight);
+        }
+
+        // Check if settings could be set.
+        if (*pResult)
+        {
+            // Return the settings.
+            (*ppSettings) = pSettings;
+        }
+        else
+        {
+            // Free the settings.
+            videoEditClasses_freeClipSettings(&pSettings);
+        }
+    }
+}
+
+void
+videoEditClasses_createClipSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                M4VSS3GPP_ClipSettings*             pSettings,
+                jobject*                            pObject)
+{
+    VideoEditJava_ClipSettingsFieldIds fieldIds = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                           NULL, NULL, NULL, NULL, NULL, NULL};
+    jclass                     clazz    = NULL;
+    jobject                    object   = NULL;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "videoEditClasses_createClipSettings()");
+
+        // Retrieve the class.
+        videoEditJava_getClipSettingsClass(pResult, pEnv, &clazz);
+
+        // Retrieve the field ids.
+        videoEditJava_getClipSettingsFieldIds(pResult, pEnv, &fieldIds);
+    }
+
+    // Only create an object if the class and fields could be located.
+    if (*pResult)
+    {
+        // Allocate a new object.
+        object = pEnv->AllocObject(clazz);
+        if (NULL != object)
+        {
+            // Set the clipPath field.
+            pEnv->SetObjectField(object, fieldIds.clipPath, NULL);
+
+            // Set the fileType field.
+            pEnv->SetIntField(object, fieldIds.fileType, videoEditJava_getClipTypeCToJava(
+                                                                    pSettings->FileType));
+
+            // Set the beginCutTime field.
+            pEnv->SetIntField(object, fieldIds.beginCutTime, pSettings->uiBeginCutTime);
+
+            // Set the endCutTime field.
+            pEnv->SetIntField(object, fieldIds.endCutTime, pSettings->uiEndCutTime);
+
+            // Set the beginCutPercent field.
+            pEnv->SetIntField(object, fieldIds.beginCutPercent, pSettings->xVSS.uiBeginCutPercent);
+
+            // Set the endCutPercent field.
+            pEnv->SetIntField(object, fieldIds.endCutPercent, pSettings->xVSS.uiEndCutPercent);
+
+            // Set the panZoomEnabled field.
+            pEnv->SetBooleanField(object, fieldIds.panZoomEnabled, pSettings->xVSS.isPanZoom);
+
+            // Set the panZoomPercentStart field.
+            pEnv->SetIntField(object, fieldIds.panZoomPercentStart,
+                (100 - pSettings->xVSS.PanZoomXa));
+
+            // Set the panZoomTopLeftXStart field.
+            pEnv->SetIntField(object, fieldIds.panZoomTopLeftXStart,
+                pSettings->xVSS.PanZoomTopleftXa);
+
+            // Set the panZoomTopLeftYStart field.
+            pEnv->SetIntField(object, fieldIds.panZoomTopLeftYStart,
+                pSettings->xVSS.PanZoomTopleftYa);
+
+            // Set the panZoomPercentEnd field.
+            pEnv->SetIntField(object, fieldIds.panZoomPercentEnd,
+                (100 - pSettings->xVSS.PanZoomXb));
+
+            // Set the panZoomTopLeftXEnd field.
+            pEnv->SetIntField(object, fieldIds.panZoomTopLeftXEnd,
+                pSettings->xVSS.PanZoomTopleftXb);
+
+            // Set the panZoomTopLeftYEnd field.
+            pEnv->SetIntField(object, fieldIds.panZoomTopLeftYEnd,
+                pSettings->xVSS.PanZoomTopleftYb);
+
+            // Set the mediaRendering field.
+            pEnv->SetIntField(object, fieldIds.mediaRendering,
+                videoEditJava_getMediaRenderingCToJava(pSettings->xVSS.MediaRendering));
+
+            // Set the rgb file width and height
+            pEnv->SetIntField(object, fieldIds.rgbFileWidth,
+                pSettings->ClipProperties.uiStillPicWidth );
+
+            pEnv->SetIntField(object, fieldIds.rgbFileHeight,
+                pSettings->ClipProperties.uiStillPicHeight );
+
+            VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                "rgbFileWeight %d rgbFileHeight %d ",
+                pSettings->ClipProperties.uiStillPicWidth ,
+                pSettings->ClipProperties.uiStillPicHeight);
+
+            // Return the object.
+            (*pObject) = object;
+        }
+    }
+}
+void
+videoEditPropClass_createProperties(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                VideoEditPropClass_Properties*      pProperties,
+                jobject*                            pObject)
+{
+    VideoEditJava_PropertiesFieldIds fieldIds = {NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                                     NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+    jclass                   clazz    = NULL;
+    jobject                  object   = NULL;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+                "videoEditPropClass_createProperties()");
+
+        // Retrieve the class.
+        videoEditJava_getPropertiesClass(pResult, pEnv, &clazz);
+
+        // Retrieve the field ids.
+        videoEditJava_getPropertiesFieldIds(pResult, pEnv, &fieldIds);
+    }
+
+    // Only create an object if the class and fields could be located.
+    if (*pResult)
+    {
+        // Allocate a new object.
+        object = pEnv->AllocObject(clazz);
+        if (NULL != object)
+        {
+            // Set the duration field.
+            pEnv->SetIntField(object, fieldIds.duration, pProperties->uiClipDuration);
+
+            // Set the fileType field.
+            pEnv->SetIntField(object, fieldIds.fileType,
+                videoEditJava_getFileTypeCToJava(pProperties->FileType));
+
+            // Set the videoFormat field.
+            pEnv->SetIntField(object, fieldIds.videoFormat,
+                videoEditJava_getVideoFormatCToJava(pProperties->VideoStreamType));
+
+            // Set the videoDuration field.
+            pEnv->SetIntField(object, fieldIds.videoDuration, pProperties->uiClipVideoDuration);
+
+            // Set the videoBitrate field.
+            pEnv->SetIntField(object, fieldIds.videoBitrate, pProperties->uiVideoBitrate);
+
+            // Set the width field.
+            pEnv->SetIntField(object, fieldIds.width, pProperties->uiVideoWidth);
+
+            // Set the height field.
+            pEnv->SetIntField(object, fieldIds.height, pProperties->uiVideoHeight);
+
+            // Set the averageFrameRate field.
+            pEnv->SetFloatField(object, fieldIds.averageFrameRate, pProperties->fAverageFrameRate);
+
+            // Set the profileAndLevel field.
+            pEnv->SetIntField(object, fieldIds.profileAndLevel,
+                videoEditJava_getVideoProfileCToJava(pProperties->ProfileAndLevel));
+
+            // Set the audioFormat field.
+            pEnv->SetIntField(object, fieldIds.audioFormat,
+                videoEditJava_getAudioFormatCToJava(pProperties->AudioStreamType));
+
+            // Set the audioDuration field.
+            pEnv->SetIntField(object, fieldIds.audioDuration, pProperties->uiClipAudioDuration);
+
+            // Set the audioBitrate field.
+            pEnv->SetIntField(object, fieldIds.audioBitrate, pProperties->uiAudioBitrate);
+
+            // Set the audioChannels field.
+            pEnv->SetIntField(object, fieldIds.audioChannels, pProperties->uiNbChannels);
+
+            // Set the audioSamplingFrequency field.
+            pEnv->SetIntField(object, fieldIds.audioSamplingFrequency,
+                pProperties->uiSamplingFrequency);
+
+            // Return the object.
+            (*pObject) = object;
+        }
+    }
+}
+
+void
+videoEditClasses_freeClipSettings(
+                M4VSS3GPP_ClipSettings**            ppSettings)
+{
+    // Check if memory was allocated for the ClipSettings.
+    if (M4OSA_NULL != (*ppSettings))
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "videoEditClasses_freeClipSettings()");
+
+        // Free the input file path.
+        videoEditOsal_free((*ppSettings)->pFile);
+        (*ppSettings)->pFile = M4OSA_NULL;
+        (*ppSettings)->filePathSize = 0;
+
+        // Free the clip settings.
+        M4xVSS_FreeClipSettings((*ppSettings));
+
+        // Free the settings structure.
+        videoEditOsal_free((*ppSettings));
+        (*ppSettings) = M4OSA_NULL;
+    }
+}
+
+#ifdef VIDEOEDIT_LOGGING_ENABLED
+void
+videoEditClasses_logClipSettings(
+                M4VSS3GPP_ClipSettings*             pSettings,
+                int                                 indentation)
+{
+    // Check if memory was allocated for the ClipSettings.
+    if (M4OSA_NULL != pSettings)
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c pFile:           %s", indentation, ' ',
+            (M4OSA_NULL != pSettings->pFile) ? (char*)pSettings->pFile : "<null>");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c FileType:        %s", indentation, ' ',
+            videoEditJava_getClipTypeString(pSettings->FileType));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c filePathSize:    %u", indentation, ' ',
+            (unsigned int)pSettings->filePathSize);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c ClipProperties:",  indentation, ' ');
+        videoEditClasses_logClipProperties(&pSettings->ClipProperties,
+            indentation + VIDEOEDIT_LOG_INDENTATION);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiBeginCutTime:    %u ms", indentation, ' ',
+            (unsigned int)pSettings->uiBeginCutTime);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiEndCutTime:      %u ms", indentation, ' ',
+            (unsigned int)pSettings->uiEndCutTime);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiBeginCutPercent: %u %%", indentation, ' ',
+            (unsigned int)pSettings->xVSS.uiBeginCutPercent);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiEndCutPercent:   %u %%", indentation, ' ',
+            (unsigned int)pSettings->xVSS.uiEndCutPercent);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiDuration:        %u ms", indentation, ' ',
+            (unsigned int)pSettings->xVSS.uiDuration);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c isPanZoom:         %s",    indentation, ' ',
+            pSettings->xVSS.isPanZoom ? "true" : "false");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c PanZoomXa:         %d ms", indentation, ' ',
+            pSettings->xVSS.PanZoomXa);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c PanZoomTopleftXa:  %d ms", indentation, ' ',
+            pSettings->xVSS.PanZoomTopleftXa);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c PanZoomTopleftYa:  %d ms", indentation, ' ',
+            pSettings->xVSS.PanZoomTopleftYa);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c PanZoomXb:         %d ms", indentation, ' ',
+            pSettings->xVSS.PanZoomXb);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c PanZoomTopleftXb:  %d ms", indentation, ' ',
+            pSettings->xVSS.PanZoomTopleftXb);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c PanZoomTopleftYb:  %d ms", indentation, ' ',
+            pSettings->xVSS.PanZoomTopleftYb);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c MediaRendering:    %s",    indentation, ' ',
+            videoEditJava_getMediaRenderingString(pSettings->xVSS.MediaRendering));
+    }
+    else
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c <null>", indentation, ' ');
+    }
+}
+#endif
+
+
+void
+videoEditClasses_getEditSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                M4VSS3GPP_EditSettings**            ppSettings,
+                bool                                flag)
+{
+    VideoEditJava_EditSettingsFieldIds fieldIds            ={NULL, NULL, NULL, NULL, NULL, NULL,
+                                                            NULL, NULL, NULL, NULL, NULL, NULL,
+                                                            NULL, NULL,NULL};
+    jobjectArray               clipSettingsArray           = NULL;
+    jsize                      clipSettingsArraySize       = 0;
+    jobject                    clipSettings                = NULL;
+    jobjectArray               transitionSettingsArray     = NULL;
+    jsize                      transitionSettingsArraySize = 0;
+    jobject                    transitionSettings          = NULL;
+    jobjectArray               effectSettingsArray         = NULL;
+    jsize                      effectSettingsArraySize     = 0;
+    jobject                    effectSettings              = NULL;
+    jobject                    backgroundMusicSettings     = NULL;
+    int                        audioChannels               = 0;
+    M4VSS3GPP_EditSettings*    pSettings                   = M4OSA_NULL;
+    bool                       converted                   = true;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                "videoEditClasses_getEditSettings()");
+
+        // Retrieve the field ids.
+        videoEditJava_getEditSettingsFieldIds(pResult, pEnv, &fieldIds);
+    }
+
+    // Only retrieve the EditSettings if the previous action succeeded.
+    if (*pResult)
+    {
+        // Check if the object is valid.
+        if (NULL != object)
+        {
+            // Retrieve the clipSettingsArray.
+            videoEditJava_getArray(pResult, pEnv, object,
+                           fieldIds.clipSettingsArray,
+                           &clipSettingsArray,
+                           &clipSettingsArraySize);
+
+            // Retrieve the transitionSettingsArray.
+            videoEditJava_getArray(pResult, pEnv, object,
+                           fieldIds.transitionSettingsArray,
+                           &transitionSettingsArray,
+                           &transitionSettingsArraySize);
+
+            // Retrieve the effectSettingsArray.
+            videoEditJava_getArray(pResult, pEnv, object,
+                           fieldIds.effectSettingsArray,
+                           &effectSettingsArray,
+                           &effectSettingsArraySize);
+
+            // Retrieve the backgroundMusicSettings.
+            videoEditJava_getObject(pResult, pEnv, object, fieldIds.backgroundMusicSettings,
+                    &backgroundMusicSettings);
+
+            // Check if the arrays and background music settings object could be retrieved.
+            if (*pResult)
+            {
+                // Retrieve the number of channels.
+                audioChannels = pEnv->GetIntField(object, fieldIds.audioChannels);
+            }
+        }
+    }
+
+    // Only validate the EditSettings if the fields could be located.
+    if (*pResult)
+    {
+        // Check if there is at least one clip.
+        //videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+         //                                          (clipSettingsArraySize < 1),
+         //                                          "there should be at least one clip");
+        if(clipSettingsArraySize < 1) {
+            return;
+        }
+        if(flag)
+        {
+            // Check if there are clips.
+            if ((clipSettingsArraySize != 0) || (transitionSettingsArraySize != 0))
+            {
+                // The number of transitions must be equal to the number of clips - 1.
+                videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                         (clipSettingsArraySize != (transitionSettingsArraySize + 1)),
+                         "the number of transitions should be equal to the number of clips - 1");
+            }
+        }
+    }
+
+    // Only retrieve the EditSettings if the fields could be located.
+    if (*pResult)
+    {
+        // Check if the object is valid.
+        if (NULL != object)
+        {
+            // Allocate memory for the EditSettings.
+            pSettings = (M4VSS3GPP_EditSettings*)videoEditOsal_alloc(pResult, pEnv,
+                    sizeof(M4VSS3GPP_EditSettings), "EditSettings");
+
+            // Check if memory could be allocated for the EditSettings.
+            if (*pResult)
+            {
+                // Set the number of clips that will be edited.
+                pSettings->uiClipNumber = clipSettingsArraySize;
+
+                // Check if the clip settings array contains items.
+                if (clipSettingsArraySize > 0)
+                {
+                    // Allocate memory for the clip settings array.
+                    pSettings->pClipList = (M4VSS3GPP_ClipSettings **)videoEditOsal_alloc(pResult,
+                                pEnv,
+                                clipSettingsArraySize * sizeof(M4VSS3GPP_ClipSettings *),
+                                "ClipSettingsArray");
+                    if (*pResult)
+                    {
+                        // Loop over all clip settings objects.
+                        for (int i = 0; ((*pResult) && (i < clipSettingsArraySize)); i++)
+                        {
+                            // Get the clip settings object.
+                            clipSettings = pEnv->GetObjectArrayElement(clipSettingsArray, i);
+
+                            // Get the clip settings.
+                            videoEditClasses_getClipSettings(pResult, pEnv, clipSettings,
+                                &pSettings->pClipList[i]);
+                        }
+                    }
+                }
+
+                // Check if the transition settings array contains items.
+                if (transitionSettingsArraySize > 0)
+                {
+                    // Allocate memory for the transition settings array.
+                    pSettings->pTransitionList =
+                            (M4VSS3GPP_TransitionSettings **)videoEditOsal_alloc(pResult,
+                                pEnv, transitionSettingsArraySize * sizeof(M4VSS3GPP_TransitionSettings *),
+                                "TransitionSettingsArray");
+                    if (*pResult)
+                    {
+                        // Loop over all transition settings objects.
+                        for (int i = 0; ((*pResult) && (i < transitionSettingsArraySize)); i++)
+                        {
+                            // Get the transition settings object.
+                            transitionSettings =
+                                    pEnv->GetObjectArrayElement(transitionSettingsArray, i);
+
+                            // Get the transition settings.
+                            videoEditClasses_getTransitionSettings(pResult, pEnv,
+                                    transitionSettings, &pSettings->pTransitionList[i]);
+                        }
+                    }
+                }
+
+                // Check if the effect settings array contains items.
+                if (effectSettingsArraySize > 0)
+                {
+                    // Allocate memory for the effect settings array.
+                    pSettings->Effects = (M4VSS3GPP_EffectSettings*)videoEditOsal_alloc(pResult,
+                                pEnv,
+                                effectSettingsArraySize * sizeof(M4VSS3GPP_EffectSettings),
+                                "EffectSettingsArray");
+                    if (*pResult)
+                    {
+                        // Loop over all effect settings objects.
+                        for (int i = 0; ((*pResult) && (i < effectSettingsArraySize)); i++)
+                        {
+                            // Get the effect settings object.
+                            effectSettings = pEnv->GetObjectArrayElement(effectSettingsArray, i);
+
+                            // Get the effect settings.
+                            videoEditClasses_getEffectSettings(pResult, pEnv, effectSettings,
+                                    &pSettings->Effects[i]);
+                        }
+                    }
+                }
+
+                // Check if the clips, transitions and effects could be set.
+                if (*pResult)
+                {
+                    // Set the number of effects in the clip.
+                    pSettings->nbEffects = (M4OSA_UInt8)effectSettingsArraySize;
+
+                    // Set the frame rate of the output video.
+                    pSettings->videoFrameRate =
+                        (M4VIDEOEDITING_VideoFramerate)videoEditJava_getVideoFrameRateJavaToC(
+                             &converted, pEnv->GetIntField(object, fieldIds.videoFrameRate));
+
+                    // Check if the frame rate is valid.
+                    videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                        !converted, "editSettings.videoFrameRate is invalid");
+                }
+
+                // Check if the frame rate could be set.
+                if (*pResult)
+                {
+                    // Set the path of the output file.
+                    pSettings->pOutputFile = (M4OSA_Char*)videoEditJava_getString(pResult, pEnv,
+                        object, fieldIds.outputFile, &pSettings->uiOutputPathSize);
+                }
+
+                // Check if path of the output file could be set.
+                if (*pResult)
+                {
+                    // Set the path of the temporary file produced when using
+                    // the constant memory 3gp writer.
+                    pSettings->pTemporaryFile = M4OSA_NULL;
+
+                    // Set the output video size.
+                    pSettings->xVSS.outputVideoSize =
+                        (M4VIDEOEDITING_VideoFrameSize)videoEditJava_getVideoFrameSizeJavaToC(
+                                &converted, pEnv->GetIntField(object, fieldIds.videoFrameSize));
+
+                    // Check if the output video size is valid.
+                    videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                        !converted, "editSettings.videoFrameSize is invalid");
+                }
+
+                // Check if the output video size could be set.
+                if (*pResult)
+                {
+                    // Set the output video format.
+                    pSettings->xVSS.outputVideoFormat =
+                        (M4VIDEOEDITING_VideoFormat)videoEditJava_getVideoFormatJavaToC(
+                               &converted, pEnv->GetIntField(object, fieldIds.videoFormat));
+
+                    // Check if the output video format is valid.
+                    videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                        !converted, "editSettings.videoFormat is invalid");
+                }
+
+                // Check if the output video format could be set.
+                if (*pResult)
+                {
+                    // Set the output audio format.
+                    pSettings->xVSS.outputAudioFormat =
+                            (M4VIDEOEDITING_AudioFormat)videoEditJava_getAudioFormatJavaToC(
+                                  &converted, pEnv->GetIntField(object, fieldIds.audioFormat));
+
+                    // Check if the output audio format is valid.
+                    videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                            !converted, "editSettings.audioFormat is invalid");
+                }
+
+                // Check if the output audio format could be set.
+                if (*pResult)
+                {
+                    // Set the output audio sampling frequency when not replacing the audio,
+                    // or replacing it with MP3 audio.
+                    pSettings->xVSS.outputAudioSamplFreq =
+                        (M4VIDEOEDITING_AudioSamplingFrequency)\
+                            videoEditJava_getAudioSamplingFrequencyJavaToC(
+                                &converted, pEnv->GetIntField(object, fieldIds.audioSamplingFreq));
+
+                    // Check if the output audio sampling frequency is valid.
+                    videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                            !converted, "editSettings.audioSamplingFreq is invalid");
+                }
+
+                // Check if the output audio sampling frequency could be set.
+                if (*pResult)
+                {
+                    // Check if the number of audio channels is valid.
+                    videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                        ((0 != audioChannels ) ||
+                        ((M4VIDEOEDITING_kNoneAudio != pSettings->xVSS.outputAudioFormat) &&
+                        (M4VIDEOEDITING_kNullAudio != pSettings->xVSS.outputAudioFormat) ) ) &&
+                        (1 != audioChannels ) &&
+                        (2 != audioChannels ),
+                        "editSettings.audioChannels must be set to 0, 1 or 2");
+                }
+
+                // Check if the number of audio channels is valid.
+                if (*pResult)
+                {
+                    // Set the maximum output file size (MMS usecase).
+                    pSettings->xVSS.outputFileSize = (M4OSA_UInt32)pEnv->GetIntField(object,
+                            fieldIds.maxFileSize);
+
+                    // Whether or not the audio is mono, only valid for AAC.
+                    pSettings->xVSS.bAudioMono = (M4OSA_Bool)(1 == audioChannels);
+
+                    // Set the output video bitrate.
+                    pSettings->xVSS.outputVideoBitrate = (M4OSA_UInt32)pEnv->GetIntField(object,
+                            fieldIds.videoBitrate);
+
+                    // Set the output audio bitrate.
+                    pSettings->xVSS.outputAudioBitrate = (M4OSA_UInt32)pEnv->GetIntField(object,
+                            fieldIds.audioBitrate);
+
+                    // Set the background music settings.
+                    videoEditClasses_getBackgroundMusicSettings(pResult, pEnv,
+                            backgroundMusicSettings, &pSettings->xVSS.pBGMtrack);
+
+                    // Set the text rendering function (will be set elsewhere).
+                    pSettings->xVSS.pTextRenderingFct = M4OSA_NULL;
+                    pSettings->PTVolLevel =
+                            (M4OSA_Float)pEnv->GetIntField(object, fieldIds.primaryTrackVolume);
+                }
+            }
+
+            // Check if settings could be set.
+            if (*pResult)
+            {
+                // Return the settings.
+                (*ppSettings) = pSettings;
+            }
+            else
+            {
+                // Free the settings.
+                videoEditClasses_freeEditSettings(&pSettings);
+            }
+        }
+    }
+}
+
+void
+videoEditClasses_freeEditSettings(
+                M4VSS3GPP_EditSettings**            ppSettings)
+{
+    // Check if memory was allocated for the EditSettings.
+    if (M4OSA_NULL != (*ppSettings))
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                "videoEditClasses_freeEditSettings()");
+
+        // Free the background music settings.
+        videoEditClasses_freeBackgroundMusicSettings(&(*ppSettings)->xVSS.pBGMtrack);
+
+        // Free the path of the output file.
+        videoEditOsal_free((*ppSettings)->pOutputFile);
+        (*ppSettings)->pOutputFile = M4OSA_NULL;
+        (*ppSettings)->uiOutputPathSize = 0;
+
+        // Check if the EffectSettings should be freed.
+        if (M4OSA_NULL != (*ppSettings)->Effects)
+        {
+            // Loop over all effect settings.
+            for (int i = 0; i < (*ppSettings)->nbEffects; i++)
+            {
+                // Free the effect settings.
+                videoEditClasses_freeEffectSettings(&(*ppSettings)->Effects[i]);
+            }
+
+            // Free the memory for the effect settings array.
+            videoEditOsal_free((*ppSettings)->Effects);
+            (*ppSettings)->Effects = M4OSA_NULL;
+        }
+
+        // Reset the number of effects in the clip.
+        (*ppSettings)->nbEffects = 0;
+
+        // Check if there are clips.
+        if (0 < (*ppSettings)->uiClipNumber)
+        {
+            // Check if the TransitionSettings should be freed.
+            if (M4OSA_NULL != (*ppSettings)->pTransitionList)
+            {
+                // Loop over all transition settings.
+                for (int i = 0; i < ((*ppSettings)->uiClipNumber - 1); i++)
+                {
+                    // Free the transition settings.
+                    videoEditClasses_freeTransitionSettings(&(*ppSettings)->pTransitionList[i]);
+                }
+
+                // Free the memory for the transition settings array.
+                videoEditOsal_free((*ppSettings)->pTransitionList);
+                (*ppSettings)->pTransitionList = M4OSA_NULL;
+            }
+
+            // Check if the ClipSettings should be freed.
+            if (M4OSA_NULL != (*ppSettings)->pClipList)
+            {
+                // Loop over all clip settings.
+                for (int i = 0; i < (*ppSettings)->uiClipNumber; i++)
+                {
+                    // Free the clip settings.
+                    videoEditClasses_freeClipSettings(&(*ppSettings)->pClipList[i]);
+                }
+
+                // Free the memory for the clip settings array.
+                videoEditOsal_free((*ppSettings)->pClipList);
+                (*ppSettings)->pClipList = M4OSA_NULL;
+            }
+        }
+
+        // Reset the number of clips.
+        (*ppSettings)->uiClipNumber = 0;
+
+        // Free the settings structure.
+        videoEditOsal_free((*ppSettings));
+        (*ppSettings) = M4OSA_NULL;
+    }
+}
+
+#ifdef VIDEOEDIT_LOGGING_ENABLED
+void
+videoEditClasses_logEditSettings(
+                M4VSS3GPP_EditSettings*             pSettings,
+                int                                 indentation)
+{
+    // Check if memory was allocated for the EditSettings.
+    if (M4OSA_NULL != pSettings)
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiClipNumber:         %d", indentation, ' ',
+            pSettings->uiClipNumber);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiMasterClip:         %d", indentation, ' ',
+            pSettings->uiMasterClip);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c pClipList:            %s", indentation, ' ',
+            (M4OSA_NULL != pSettings->pClipList) ? " " : "<null>");
+        if (M4OSA_NULL != pSettings->pClipList)
+        {
+            indentation += VIDEOEDIT_LOG_INDENTATION;
+            for (int i = 0; i < pSettings->uiClipNumber; i++)
+            {
+                VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                    "%*c pClipList[%d]:", indentation, ' ',
+                    i);
+                videoEditClasses_logClipSettings(pSettings->pClipList[i],
+                    indentation + VIDEOEDIT_LOG_INDENTATION);
+            }
+            indentation -= VIDEOEDIT_LOG_INDENTATION;
+        }
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c pTransitionList:      %s", indentation, ' ',
+            (M4OSA_NULL != pSettings->pTransitionList) ? " " : "<null>");
+        if (M4OSA_NULL != pSettings->pTransitionList)
+        {
+            indentation += VIDEOEDIT_LOG_INDENTATION;
+            for (int i = 0; i < (pSettings->uiClipNumber - 1); i++)
+            {
+                VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                    "%*c pTransitionList[%d]:", indentation, ' ', i);
+                videoEditClasses_logTransitionSettings(pSettings->pTransitionList[i],
+                    indentation + VIDEOEDIT_LOG_INDENTATION);
+            }
+            indentation -= VIDEOEDIT_LOG_INDENTATION;
+        }
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c Effects:              %s", indentation, ' ',
+            (M4OSA_NULL != pSettings->Effects)   ? " " : "<null>");
+        if (M4OSA_NULL != pSettings->Effects)
+        {
+            indentation += VIDEOEDIT_LOG_INDENTATION;
+            for (int i = 0; i < pSettings->nbEffects; i++)
+            {
+                VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                    "%*c Effects[%d]:", indentation, ' ',  i);
+                videoEditClasses_logEffectSettings(&pSettings->Effects[i],
+                    indentation + VIDEOEDIT_LOG_INDENTATION);
+            }
+            indentation -= VIDEOEDIT_LOG_INDENTATION;
+        }
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c nbEffects:            %d", indentation, ' ',
+            pSettings->nbEffects);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c videoFrameRate:       %s", indentation, ' ',
+            videoEditJava_getVideoFrameRateString(pSettings->videoFrameRate));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c pOutputFile:          %s", indentation, ' ',
+            (M4OSA_NULL != pSettings->pOutputFile) ? (char*)pSettings->pOutputFile : "<null>");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiOutputPathSize:     %u", indentation, ' ',
+            (unsigned int)pSettings->uiOutputPathSize);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c pTemporaryFile:       %s", indentation, ' ',
+            (M4OSA_NULL != pSettings->pTemporaryFile) ?\
+             (char*)pSettings->pTemporaryFile : "<null>");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c outputVideoSize:      %s", indentation, ' ',
+            videoEditJava_getVideoFrameSizeString(pSettings->xVSS.outputVideoSize));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c outputVideoFormat:    %s", indentation, ' ',
+            videoEditJava_getVideoFormatString(pSettings->xVSS.outputVideoFormat));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c outputAudioFormat:    %s", indentation, ' ',
+            videoEditJava_getAudioFormatString(pSettings->xVSS.outputAudioFormat));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c outputAudioSamplFreq: %s", indentation, ' ',
+            videoEditJava_getAudioSamplingFrequencyString(pSettings->xVSS.outputAudioSamplFreq));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c outputFileSize:       %u", indentation, ' ',
+            (unsigned int)pSettings->xVSS.outputFileSize);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c bAudioMono:           %s", indentation, ' ',
+            pSettings->xVSS.bAudioMono ? "true" : "false");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c outputVideoBitrate:   %s", indentation, ' ',
+            videoEditJava_getBitrateString(pSettings->xVSS.outputVideoBitrate));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c outputAudioBitrate:   %s", indentation, ' ',
+            videoEditJava_getBitrateString(pSettings->xVSS.outputAudioBitrate));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c pBGMtrack:",               indentation, ' ');
+        videoEditClasses_logBackgroundMusicSettings(pSettings->xVSS.pBGMtrack,
+            indentation + VIDEOEDIT_LOG_INDENTATION);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c pTextRenderingFct:    %s", indentation, ' ',
+            (M4OSA_NULL != pSettings->xVSS.pTextRenderingFct) ? "set" : "<null>");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c PTVolLevel:       %u", indentation, ' ',
+            (unsigned int)pSettings->PTVolLevel);
+    }
+    else
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c <null>", indentation, ' ');
+    }
+}
+#endif
+
+
+void
+videoEditClasses_getEffectSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                M4VSS3GPP_EffectSettings*           pSettings)
+{
+    VideoEditJava_EffectSettingsFieldIds fieldIds  = {NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                  NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+    bool                         converted = true;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+         "videoEditClasses_getEffectSettings()");
+
+        // Retrieve the field ids.
+        videoEditJava_getEffectSettingsFieldIds(pResult, pEnv, &fieldIds);
+    }
+
+    // Only validate the EffectSettings if the fields could be located.
+    if (*pResult)
+    {
+        // Check if the effect is set.
+        videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                                                    (NULL == object),
+                                                    "effect is null");
+    }
+
+    // Only retrieve the EffectSettings if the fields could be located and validated.
+    if (*pResult)
+    {
+        // Set the start time in milliseconds.
+        pSettings->uiStartTime = (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.startTime);
+
+        // Set the duration in milliseconds.
+        pSettings->uiDuration = (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.duration);
+
+        // Set the video effect type, None, FadeIn, FadeOut, etc.
+        pSettings->VideoEffectType =
+                (M4VSS3GPP_VideoEffectType)videoEditJava_getVideoEffectJavaToC(
+                              &converted, pEnv->GetIntField(object, fieldIds.videoEffectType));
+
+        // Check if the video effect type is valid.
+        videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                !converted, "effect.videoEffectType is invalid");
+    }
+
+    // Check if the video effect type could be set.
+    if (*pResult)
+    {
+        // Set the external effect function.
+        pSettings->ExtVideoEffectFct = M4OSA_NULL;
+
+        // Set the context given to the external effect function.
+        pSettings->pExtVideoEffectFctCtxt = M4OSA_NULL;
+
+        // Set the audio effect type, None, FadeIn, FadeOut.
+        pSettings->AudioEffectType =
+                (M4VSS3GPP_AudioEffectType)videoEditJava_getAudioEffectJavaToC(
+                        &converted, pEnv->GetIntField(object, fieldIds.audioEffectType));
+
+        // Check if the audio effect type is valid.
+        videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                !converted, "effect.audioEffectType is invalid");
+    }
+
+    // Check if the audio effect type could be set.
+    if (*pResult)
+    {
+        // Set the start in percentage of the cut clip duration.
+        pSettings->xVSS.uiStartPercent = (M4OSA_UInt32)pEnv->GetIntField(object,
+                fieldIds.startPercent);
+
+        // Set the duration in percentage of the ((clip duration) - (effect starttime)).
+        pSettings->xVSS.uiDurationPercent = (M4OSA_UInt32)pEnv->GetIntField(object,
+                fieldIds.durationPercent);
+
+        // Set the framing file path (GIF/PNG file).
+        pSettings->xVSS.pFramingFilePath = (M4OSA_Char*)videoEditJava_getString(pResult, pEnv,
+                object, fieldIds.framingFile, M4OSA_NULL);
+
+        // Check if this is a framing effect.
+        if (M4xVSS_kVideoEffectType_Framing == (M4xVSS_VideoEffectType)pSettings->VideoEffectType)
+        {
+            // Check if the framing file path is valid.
+            videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                    (M4OSA_NULL == pSettings->xVSS.pFramingFilePath), "effect.framingFile is null");
+        }
+    }
+
+    // Check if the framing file path could be retrieved.
+    if (*pResult)
+    {
+        // Set the Framing RGB565 buffer.
+        pSettings->xVSS.pFramingBuffer = M4OSA_NULL;
+
+        // Set the top-left X coordinate in the output picture
+        // where the added frame will be displayed.
+        pSettings->xVSS.topleft_x = (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.topLeftX);
+
+        // Set the top-left Y coordinate in the output picture
+        // where the added frame will be displayed.
+        pSettings->xVSS.topleft_y = (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.topLeftY);
+
+        // Set whether or not the framing image is resized to output video size.
+        pSettings->xVSS.bResize =
+                (M4OSA_Bool)pEnv->GetBooleanField(object, fieldIds.framingResize);
+
+        // Set the new size to which framing buffer needs to be resized to
+        pSettings->xVSS.framingScaledSize =
+                (M4VIDEOEDITING_VideoFrameSize)pEnv->GetIntField(object, fieldIds.framingScaledSize);
+
+        // Set the text buffer.
+        pSettings->xVSS.pTextBuffer = (M4OSA_Char*)videoEditJava_getString(pResult, pEnv, object,
+                fieldIds.text, &pSettings->xVSS.textBufferSize);
+    }
+
+    // Check if the text buffer could be retrieved.
+    if (*pResult)
+    {
+        // Set the data used by the font engine (size, color...).
+        pSettings->xVSS.pRenderingData = (M4OSA_Char*)videoEditJava_getString(pResult, pEnv,
+                object, fieldIds.textRenderingData, M4OSA_NULL);
+    }
+
+    // Check if the text rendering data could be retrieved.
+    if (*pResult)
+    {
+        // Set the text plane width.
+        pSettings->xVSS.uiTextBufferWidth = (M4OSA_UInt32)pEnv->GetIntField(object,
+                fieldIds.textBufferWidth);
+
+        // Set the text plane height.
+        pSettings->xVSS.uiTextBufferHeight = (M4OSA_UInt32)pEnv->GetIntField(object,
+                fieldIds.textBufferHeight);
+
+        // Set the processing rate of the effect added when using the Fifties effect.
+        pSettings->xVSS.uiFiftiesOutFrameRate = (M4OSA_UInt32)pEnv->GetIntField(object,
+                fieldIds.fiftiesFrameRate);
+
+        // Set the RGB16 input color of the effect added when using the rgb16 color effect.
+        pSettings->xVSS.uiRgb16InputColor = (M4OSA_UInt16)pEnv->GetIntField(object,
+                fieldIds.rgb16InputColor);
+
+        // Set the start percentage of Alpha blending.
+        pSettings->xVSS.uialphaBlendingStart = (M4OSA_UInt8)pEnv->GetIntField(object,
+                fieldIds.alphaBlendingStartPercent);
+
+        // Set the middle percentage of Alpha blending.
+        pSettings->xVSS.uialphaBlendingMiddle = (M4OSA_UInt8)pEnv->GetIntField(object,
+                fieldIds.alphaBlendingMiddlePercent);
+
+        // Set the end percentage of Alpha blending.
+        pSettings->xVSS.uialphaBlendingEnd = (M4OSA_UInt8)pEnv->GetIntField(object,
+                fieldIds.alphaBlendingEndPercent);
+
+        // Set the duration, in percentage of effect duration, of the FadeIn phase.
+        pSettings->xVSS.uialphaBlendingFadeInTime = (M4OSA_UInt8)pEnv->GetIntField(object,
+                fieldIds.alphaBlendingFadeInTimePercent);
+
+        // Set the duration, in percentage of effect duration, of the FadeOut phase.
+        pSettings->xVSS.uialphaBlendingFadeOutTime = (M4OSA_UInt8)pEnv->GetIntField(object,
+                fieldIds.alphaBlendingFadeOutTimePercent);
+
+        if (pSettings->xVSS.pFramingFilePath != M4OSA_NULL)
+        {
+            pSettings->xVSS.pFramingBuffer =
+                (M4VIFI_ImagePlane *)M4OSA_malloc(sizeof(M4VIFI_ImagePlane),
+                0x00,(M4OSA_Char *)"framing buffer");
+        }
+
+        if (pSettings->xVSS.pFramingBuffer != M4OSA_NULL)
+        {
+             // OverFrame height and width
+            pSettings->xVSS.pFramingBuffer->u_width = pEnv->GetIntField(object,
+             fieldIds.width);
+
+            pSettings->xVSS.pFramingBuffer->u_height = pEnv->GetIntField(object,
+             fieldIds.height);
+
+            pSettings->xVSS.width = pSettings->xVSS.pFramingBuffer->u_width;
+            pSettings->xVSS.height = pSettings->xVSS.pFramingBuffer->u_height;
+            pSettings->xVSS.rgbType = M4VSS3GPP_kRGB888;
+
+            VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                    "pFramingBuffer u_width %d ", pSettings->xVSS.pFramingBuffer->u_width);
+            VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                    "pFramingBuffer u_height %d", pSettings->xVSS.pFramingBuffer->u_height);
+
+        }
+
+        // Check if settings could be set.
+        if (!(*pResult))
+        {
+            // Free the settings.
+            videoEditClasses_freeEffectSettings(pSettings);
+        }
+    }
+}
+
+void
+videoEditClasses_freeEffectSettings(
+                M4VSS3GPP_EffectSettings*           pSettings)
+{
+    // Check if memory was allocated for the EffectSettings.
+    if (M4OSA_NULL != pSettings)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                "videoEditClasses_freeEffectSettings()");
+
+        // Free the data used by the font engine (size, color...).
+        videoEditOsal_free(pSettings->xVSS.pRenderingData);
+        pSettings->xVSS.pRenderingData = M4OSA_NULL;
+
+        // Free the text buffer.
+        videoEditOsal_free(pSettings->xVSS.pTextBuffer);
+        pSettings->xVSS.pTextBuffer = M4OSA_NULL;
+        pSettings->xVSS.textBufferSize = 0;
+
+        // Free the framing file path.
+        videoEditOsal_free(pSettings->xVSS.pFramingFilePath);
+        pSettings->xVSS.pFramingFilePath = M4OSA_NULL;
+    }
+}
+
+#ifdef VIDEOEDIT_LOGGING_ENABLED
+void
+videoEditClasses_logEffectSettings(
+                M4VSS3GPP_EffectSettings*           pSettings,
+                int                                 indentation)
+{
+    // Check if memory was allocated for the EffectSettings.
+    if (M4OSA_NULL != pSettings)
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiStartTime:                %u ms", indentation, ' ',
+            (unsigned int)pSettings->uiStartTime);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiDuration:                 %u ms", indentation, ' ',
+            (unsigned int)pSettings->uiDuration);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c VideoEffectType:            %s",    indentation, ' ',
+            videoEditJava_getVideoEffectString(pSettings->VideoEffectType));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+             "%*c ExtVideoEffectFct:          %s",    indentation, ' ',
+            (M4OSA_NULL != pSettings->ExtVideoEffectFct) ? "set" : "<null>");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c pExtVideoEffectFctCtxt:     %s",    indentation, ' ',
+            (M4OSA_NULL != pSettings->pExtVideoEffectFctCtxt) ? "set" : "<null>");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c AudioEffectType:            %s",    indentation, ' ',
+            videoEditJava_getAudioEffectString(pSettings->AudioEffectType));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiStartPercent:             %u %%", indentation, ' ',
+            (unsigned int)pSettings->xVSS.uiStartPercent);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiDurationPercent:          %u %%", indentation, ' ',
+            (unsigned int)pSettings->xVSS.uiDurationPercent);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c pFramingFilePath:           %s",    indentation, ' ',
+            (M4OSA_NULL != pSettings->xVSS.pFramingFilePath) ?\
+             (char*)pSettings->xVSS.pFramingFilePath : "<null>");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c pFramingBuffer:             %s",    indentation, ' ',
+            (M4OSA_NULL != pSettings->xVSS.pFramingBuffer) ? "set" : "<null>");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c topleft_x:                  %u",    indentation, ' ',
+            (unsigned int)pSettings->xVSS.topleft_x);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c topleft_y:                  %u",    indentation, ' ',
+            (unsigned int)pSettings->xVSS.topleft_y);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c bResize:                    %s",    indentation, ' ',
+            pSettings->xVSS.bResize ? "true" : "false");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c pTextBuffer:                %s",    indentation, ' ',
+            (M4OSA_NULL != pSettings->xVSS.pTextBuffer) ?\
+             (char*)pSettings->xVSS.pTextBuffer : "<null>");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c textBufferSize:             %u",    indentation, ' ',
+            (unsigned int)pSettings->xVSS.textBufferSize);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c pRenderingData:             %s",    indentation, ' ',
+            (M4OSA_NULL != pSettings->xVSS.pRenderingData) ?\
+             (char*)pSettings->xVSS.pRenderingData : "<null>");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiTextBufferWidth:          %u",    indentation, ' ',
+            (unsigned int)pSettings->xVSS.uiTextBufferWidth);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+             "%*c uiTextBufferHeight:         %u",    indentation, ' ',
+            (unsigned int)pSettings->xVSS.uiTextBufferHeight);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiFiftiesOutFrameRate:      %u",    indentation, ' ',
+            (unsigned int)pSettings->xVSS.uiFiftiesOutFrameRate);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uiRgb16InputColor:          %d",    indentation, ' ',
+            pSettings->xVSS.uiRgb16InputColor);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uialphaBlendingStart:       %d %%", indentation, ' ',
+            pSettings->xVSS.uialphaBlendingStart);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uialphaBlendingMiddle:      %d %%", indentation, ' ',
+            pSettings->xVSS.uialphaBlendingMiddle);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uialphaBlendingEnd:         %d %%", indentation, ' ',
+            pSettings->xVSS.uialphaBlendingEnd);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uialphaBlendingFadeInTime:  %d %%", indentation, ' ',
+            pSettings->xVSS.uialphaBlendingFadeInTime);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c uialphaBlendingFadeOutTime: %d %%", indentation, ' ',
+            pSettings->xVSS.uialphaBlendingFadeOutTime);
+    }
+    else
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c <null>", indentation, ' ');
+    }
+}
+#endif
+
+
+void
+videoEditClasses_getSlideTransitionSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                M4xVSS_SlideTransitionSettings**    ppSettings)
+{
+    VideoEditJava_SlideTransitionSettingsFieldIds fieldIds  = {NULL};
+    M4xVSS_SlideTransitionSettings*       pSettings = M4OSA_NULL;
+    bool                                  converted = true;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                "videoEditClasses_getSlideTransitionSettings()");
+
+        // Retrieve the field ids.
+        videoEditJava_getSlideTransitionSettingsFieldIds(pResult, pEnv, &fieldIds);
+    }
+
+
+    // Only validate the SlideTransitionSettings if the fields could be located.
+    if (*pResult)
+    {
+        // Check if the clip is set.
+        videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                                                    (NULL == object),
+                                                    "slideSettings is null");
+    }
+
+    // Only retrieve the SlideTransitionSettings if the fields could be located and validated.
+    if (*pResult)
+    {
+        // Allocate memory for the SlideTransitionSettings.
+        pSettings = (M4xVSS_SlideTransitionSettings*)videoEditOsal_alloc(pResult, pEnv,
+                sizeof(M4xVSS_SlideTransitionSettings), "SlideTransitionSettings");
+
+        // Check if memory could be allocated for the SlideTransitionSettings.
+        if (*pResult)
+        {
+            // Set the direction of the slide.
+            pSettings->direction =
+                    (M4xVSS_SlideTransition_Direction)videoEditJava_getSlideDirectionJavaToC(
+                            &converted, pEnv->GetIntField(object, fieldIds.direction));
+
+            // Check if the direction is valid.
+            videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                    !converted, "slideSettings.direction is invalid");
+        }
+
+        // Check if settings could be set.
+        if (*pResult)
+        {
+            // Return the settings.
+            (*ppSettings) = pSettings;
+        }
+        else
+        {
+            // Free the settings.
+            videoEditClasses_freeSlideTransitionSettings(&pSettings);
+        }
+    }
+}
+
+void
+videoEditClasses_freeSlideTransitionSettings(
+                M4xVSS_SlideTransitionSettings**    ppSettings)
+{
+    // Check if memory was allocated for the SlideTransitionSettings.
+    if (M4OSA_NULL != (*ppSettings))
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                "videoEditClasses_freeSlideTransitionSettings()");
+
+        // Free the settings structure.
+        videoEditOsal_free((*ppSettings));
+        (*ppSettings) = M4OSA_NULL;
+    }
+}
+
+#ifdef VIDEOEDIT_LOGGING_ENABLED
+void
+videoEditClasses_logSlideTransitionSettings(
+                M4xVSS_SlideTransitionSettings*     pSettings,
+                int                                 indentation)
+{
+    // Check if memory was allocated for the SlideTransitionSettings.
+    if (M4OSA_NULL != pSettings)
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c direction: %s", indentation, ' ',
+            videoEditJava_getSlideDirectionString(pSettings->direction));
+    }
+    else
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+            "%*c <null>", indentation, ' ');
+    }
+}
+#endif
+
+
+void
+videoEditClasses_getTransitionSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                M4VSS3GPP_TransitionSettings**      ppSettings)
+{
+    VideoEditJava_TransitionSettingsFieldIds fieldIds      = {NULL, NULL, NULL, NULL, NULL, NULL};
+    jobject                          alphaSettings = NULL;
+    jobject                          slideSettings = NULL;
+    M4VSS3GPP_TransitionSettings*    pSettings     = M4OSA_NULL;
+    bool                             converted     = true;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+               "videoEditClasses_getTransitionSettings()");
+
+        // Retrieve the field ids.
+        videoEditJava_getTransitionSettingsFieldIds(pResult, pEnv, &fieldIds);
+    }
+
+    // Only validate the TransitionSettings if the fields could be located.
+    if (*pResult)
+    {
+        // Check if the transition is set.
+        videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                                                    (NULL == object),
+                                                    "transition is null");
+    }
+
+    // Check if the field ids could be located and validated.
+    if (*pResult)
+    {
+        // Retrieve the alphaSettings.
+        videoEditJava_getObject(pResult, pEnv, object, fieldIds.alphaSettings, &alphaSettings);
+
+        // Retrieve the slideSettings.
+        videoEditJava_getObject(pResult, pEnv, object, fieldIds.slideSettings, &slideSettings);
+    }
+
+    // Only retrieve the TransitionSettings if the fields could be located.
+    if (*pResult)
+    {
+        // Allocate memory for the TransitionSettings.
+        pSettings = (M4VSS3GPP_TransitionSettings*)videoEditOsal_alloc(pResult,
+                pEnv, sizeof(M4VSS3GPP_TransitionSettings), "TransitionSettings");
+
+        // Check if memory could be allocated for the TransitionSettings.
+        if (*pResult)
+        {
+            // Set the duration of the transition, in milliseconds (set to 0 to get no transition).
+            pSettings->uiTransitionDuration = (M4OSA_UInt32)pEnv->GetIntField(object,
+                    fieldIds.duration);
+
+            // Set the type of the video transition.
+            pSettings->VideoTransitionType =
+                    (M4VSS3GPP_VideoTransitionType)videoEditJava_getVideoTransitionJavaToC(
+                             &converted, pEnv->GetIntField(object, fieldIds.videoTransitionType));
+
+            // Check if the video transition type is valid.
+            videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv, !converted,
+                            "transition.videoTransitionType is invalid");
+        }
+
+        // Check if the video transition type could be set.
+        if (*pResult)
+        {
+            // Set the external transition video effect function.
+            pSettings->ExtVideoTransitionFct = M4OSA_NULL;
+
+            // Set the context of the external transition video effect function.
+            pSettings->pExtVideoTransitionFctCtxt = M4OSA_NULL;
+
+            // Set the type of the audio transition.
+            pSettings->AudioTransitionType =
+                    (M4VSS3GPP_AudioTransitionType)videoEditJava_getAudioTransitionJavaToC(
+                            &converted, pEnv->GetIntField(object, fieldIds.audioTransitionType));
+
+            // Check if the audio transition type is valid.
+            videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv, !converted,
+                             "transition.audioTransitionType is invalid");
+        }
+
+        // Check if the audio transition type could be set.
+        if (*pResult)
+        {
+            // Set the transition behaviour.
+            pSettings->TransitionBehaviour =
+                    (M4VSS3GPP_TransitionBehaviour)videoEditJava_getTransitionBehaviourJavaToC(
+                            &converted, pEnv->GetIntField(object, fieldIds.transitionBehaviour));
+
+            // Check if the transition behaviour is valid.
+            videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv, !converted,
+                                                    "transition.transitionBehaviour is invalid");
+        }
+
+        // Check if the audio transition behaviour could be set.
+        if (*pResult)
+        {
+            // Check if a slide transition or alpha magic setting object is expected.
+            if ((int)pSettings->VideoTransitionType == M4xVSS_kVideoTransitionType_SlideTransition)
+            {
+                // Set the slide transition settings.
+                videoEditClasses_getSlideTransitionSettings(pResult, pEnv, slideSettings,
+                                     &pSettings->xVSS.transitionSpecific.pSlideTransitionSettings);
+            }
+            else if ((int)pSettings->VideoTransitionType == M4xVSS_kVideoTransitionType_AlphaMagic)
+            {
+                // Set the alpha magic settings.
+                videoEditClasses_getAlphaMagicSettings(pResult, pEnv, alphaSettings,
+                                  &pSettings->xVSS.transitionSpecific.pAlphaMagicSettings);
+            }
+        }
+
+        // Check if settings could be set.
+        if (*pResult)
+        {
+            // Return the settings.
+            (*ppSettings) = pSettings;
+        }
+        else
+        {
+            // Free the settings.
+            videoEditClasses_freeTransitionSettings(&pSettings);
+        }
+    }
+}
+
+void
+videoEditClasses_freeTransitionSettings(
+                M4VSS3GPP_TransitionSettings**      ppSettings)
+{
+    // Check if memory was allocated for the TransitionSettings.
+    if (M4OSA_NULL != (*ppSettings))
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                               "videoEditClasses_freeTransitionSettings()");
+
+        // Check if a slide transition or alpha magic setting structure is expected.
+        if ((int)(*ppSettings)->VideoTransitionType == M4xVSS_kVideoTransitionType_SlideTransition)
+        {
+            // Free the slide transition settings.
+            videoEditClasses_freeSlideTransitionSettings(
+                               &(*ppSettings)->xVSS.transitionSpecific.pSlideTransitionSettings);
+        }
+        else
+        {
+            // Free the alpha magic settings.
+            videoEditClasses_freeAlphaMagicSettings(
+                              &(*ppSettings)->xVSS.transitionSpecific.pAlphaMagicSettings);
+        }
+
+        // Free the settings structure.
+        videoEditOsal_free((*ppSettings));
+        (*ppSettings) = M4OSA_NULL;
+    }
+}
+
+#ifdef VIDEOEDIT_LOGGING_ENABLED
+void
+videoEditClasses_logTransitionSettings(
+                M4VSS3GPP_TransitionSettings*       pSettings,
+                int                                 indentation)
+{
+    // Check if memory was allocated for the TransitionSettings.
+    if (M4OSA_NULL != pSettings)
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                               "%*c uiTransitionDuration:       %u ms", indentation, ' ',
+                                  (unsigned int)pSettings->uiTransitionDuration);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                           "%*c VideoTransitionType:        %s",    indentation, ' ',
+                           videoEditJava_getVideoTransitionString(pSettings->VideoTransitionType));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                              "%*c ExtVideoTransitionFct:      %s",    indentation, ' ',
+                              (M4OSA_NULL != pSettings->ExtVideoTransitionFct) ? "set" : "<null>");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                         "%*c pExtVideoTransitionFctCtxt: %s",    indentation, ' ',
+                         (M4OSA_NULL != pSettings->pExtVideoTransitionFctCtxt) ? "set" : "<null>");
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                         "%*c AudioTransitionType:        %s",    indentation, ' ',
+                          videoEditJava_getAudioTransitionString(pSettings->AudioTransitionType));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                      "%*c TransitionBehaviour:        %s",    indentation, ' ',
+                      videoEditJava_getTransitionBehaviourString(pSettings->TransitionBehaviour));
+
+        // Check if a slide transition or alpha magic setting structure is expected.
+        if ((int)pSettings->VideoTransitionType == M4xVSS_kVideoTransitionType_SlideTransition)
+        {
+            // Log the slide transition settings.
+            VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                                   "%*c pSlideTransitionSettings:", indentation, ' ');
+            videoEditClasses_logSlideTransitionSettings\
+            (pSettings->xVSS.transitionSpecific.pSlideTransitionSettings,
+            indentation + VIDEOEDIT_LOG_INDENTATION);
+        }
+        else
+        {
+            // Log the alpha magic settings.
+            VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                                   "%*c pAlphaMagicSettings:", indentation, ' ');
+            videoEditClasses_logAlphaMagicSettings\
+            (pSettings->xVSS.transitionSpecific.pAlphaMagicSettings,
+            indentation + VIDEOEDIT_LOG_INDENTATION);
+        }
+    }
+    else
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                               "%*c <null>", indentation, ' ');
+    }
+}
+#endif
+#ifdef VIDEOEDIT_LOGGING_ENABLED
+void
+videoEditPropClass_logProperties(
+                VideoEditPropClass_Properties*                   pProperties,
+                int                                 indentation)
+{
+    // Check if memory was allocated for the Properties.
+    if (M4OSA_NULL != pProperties)
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+            "%*c uiClipDuration:                   %u",       indentation, ' ',
+            (unsigned int)pProperties->uiClipDuration);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+            "%*c FileType:                         %s",       indentation, ' ',
+            videoEditJava_getFileTypeString(pProperties->FileType));
+
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+            "%*c VideoStreamType:                  %s",       indentation, ' ',
+            videoEditJava_getVideoFormatString(pProperties->VideoStreamType));
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+            "%*c uiClipVideoDuration:              %u",       indentation, ' ',
+            (unsigned int)pProperties->uiClipVideoDuration);
+
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+            "%*c uiVideoBitrate:                   %s",       indentation, ' ',
+            videoEditJava_getBitrateString(pProperties->uiVideoBitrate));
+
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+            "%*c uiVideoWidth:                     %u",       indentation, ' ',
+            (unsigned int)pProperties->uiVideoWidth);
+
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+            "%*c uiVideoHeight:                    %u",       indentation, ' ',
+            (unsigned int)(unsigned int)pProperties->uiVideoHeight);
+
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+            "%*c fAverageFrameRate:                %.3f",     indentation, ' ',
+            pProperties->fAverageFrameRate);
+
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+            "%*c ProfileAndLevel:                  %s",       indentation, ' ',
+            videoEditJava_getVideoProfileString(pProperties->ProfileAndLevel));
+
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+            "%*c AudioStreamType:                  %s",       indentation, ' ',
+            videoEditJava_getAudioFormatString(pProperties->AudioStreamType));
+
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+            "%*c uiClipAudioDuration:              %u",       indentation, ' ',
+            (unsigned int)pProperties->uiClipAudioDuration);
+
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+            "%*c uiAudioBitrate:                   %s",       indentation, ' ',
+            videoEditJava_getBitrateString(pProperties->uiAudioBitrate));
+
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+            "%*c uiNbChannels:                     %u",       indentation, ' ',
+            (unsigned int)pProperties->uiNbChannels);
+
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+             "%*c uiSamplingFrequency:              %u",       indentation, ' ',
+            (unsigned int)pProperties->uiSamplingFrequency);
+    }
+    else
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
+            "%*c <null>", indentation, ' ');
+    }
+}
+#endif
+
+
+void
+videoEditClasses_createVersion(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                M4_VersionInfo*                     pVersionInfo,
+                jobject*                            pObject)
+{
+    VideoEditJava_VersionFieldIds fieldIds = {NULL, NULL, NULL};
+    jclass                clazz    = NULL;
+    jobject               object   = NULL;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                               "videoEditClasses_createVersion()");
+
+        // Retrieve the class.
+        videoEditJava_getVersionClass(pResult, pEnv, &clazz);
+
+        // Retrieve the field ids.
+        videoEditJava_getVersionFieldIds(pResult, pEnv, &fieldIds);
+    }
+
+    // Only create an object if the class and fields could be located.
+    if (*pResult)
+    {
+        // Allocate a new object.
+        object = pEnv->AllocObject(clazz);
+
+        // check if alloc is done
+        videoEditJava_checkAndThrowRuntimeException(pResult, pEnv,
+                                                    (NULL == object),
+                                                    M4ERR_ALLOC);
+        if (NULL != object)
+        {
+            // Set the major field.
+            pEnv->SetIntField(object, fieldIds.major, pVersionInfo->m_major);
+
+            // Set the minor field.
+            pEnv->SetIntField(object, fieldIds.minor, pVersionInfo->m_minor);
+
+            // Set the revision field.
+            pEnv->SetIntField(object, fieldIds.revision, pVersionInfo->m_revision);
+
+            // Return the object.
+            (*pObject) = object;
+        }
+    }
+}
+
+#ifdef VIDEOEDIT_LOGGING_ENABLED
+void
+videoEditClasses_logVersion(
+                M4_VersionInfo*                     pVersionInfo,
+                int                                 indentation)
+{
+    // Check if memory was allocated for the Version.
+    if (M4OSA_NULL != pVersionInfo)
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                             "%*c major:    %u ms", indentation, ' ',
+                             (unsigned int)pVersionInfo->m_major);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                              "%*c minor:    %u",    indentation, ' ',
+                              (unsigned int)pVersionInfo->m_minor);
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                             "%*c revision: %u",    indentation, ' ',
+                             (unsigned int)pVersionInfo->m_revision);
+    }
+    else
+    {
+        VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                              "%*c <null>", indentation, ' ');
+    }
+}
+#endif
+
+
+void*
+videoEditClasses_getContext(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object)
+{
+    void*                pContext = M4OSA_NULL;
+    jclass               clazz    = NULL;
+    VideoEditJava_EngineFieldIds fieldIds = {NULL};
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                               "videoEditClasses_getContext()");
+
+        // Retrieve the class.
+        videoEditJava_getEngineClass(pResult, pEnv, &clazz);
+
+        // Retrieve the field ids.
+        videoEditJava_getEngineFieldIds(pResult, pEnv, &fieldIds);
+    }
+
+    // Check if the class and field ids could be located.
+    if (*pResult)
+    {
+        // Retrieve the context pointer.
+        pContext = (void *)pEnv->GetIntField(object, fieldIds.context);
+    }
+
+    // Return the context pointer.
+    return(pContext);
+}
+
+void
+videoEditClasses_setContext(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                void*                               pContext)
+{
+    jclass               clazz    = NULL;
+    VideoEditJava_EngineFieldIds fieldIds = {NULL};
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                               "videoEditClasses_setContext()");
+
+        // Retrieve the class.
+        videoEditJava_getEngineClass(pResult, pEnv, &clazz);
+
+        // Retrieve the field ids.
+        videoEditJava_getEngineFieldIds(pResult, pEnv, &fieldIds);
+    }
+
+    // Check if the class and field ids could be located.
+    if (*pResult)
+    {
+        // Set the context field.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                        "The context value from JAVA before setting is = 0x%x",
+                        pEnv->GetIntField(object, fieldIds.context));
+
+        pEnv->SetIntField(object, fieldIds.context, (int)pContext);
+        M4OSA_TRACE1_1("The context value in JNI is = 0x%x",pContext);
+
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
+                         "The context value from JAVA after setting is = 0x%x",
+                         pEnv->GetIntField(object, fieldIds.context));
+    }
+}
+
diff --git a/media/jni/mediaeditor/VideoEditorClasses.h b/media/jni/mediaeditor/VideoEditorClasses.h
new file mode 100755
index 0000000..3c8f055
--- /dev/null
+++ b/media/jni/mediaeditor/VideoEditorClasses.h
@@ -0,0 +1,589 @@
+/*
+ * Copyright (C) 2011 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 VIDEO_EDITOR_CLASSES_H
+#define VIDEO_EDITOR_CLASSES_H
+
+#include <VideoEditorJava.h>
+#include <VideoEditorClasses.h>
+/**
+ ************************************************************************
+ * @file        VideoEditorClasses.h
+ * @brief       Interface for JNI methods/defines that have specific
+ *              access to class, objects and method Ids defined in Java layer
+ ************************************************************************
+*/
+
+
+extern "C" {
+#include <M4xVSS_API.h>
+#include <M4VSS3GPP_API.h>
+#include <M4VSS3GPP_ErrorCodes.h>
+#include <M4MCS_ErrorCodes.h>
+#include <M4READER_Common.h>
+#include <M4WRITER_common.h>
+};
+
+/*
+ * Java layer class/object name strings
+ */
+#define PACKAGE_NAME                           "android/media/videoeditor"
+
+#define MANUAL_EDIT_ENGINE_CLASS_NAME          PACKAGE_NAME"/MediaArtistNativeHelper"
+#define MEDIA_PROPERTIES_ENGINE_CLASS_NAME     PACKAGE_NAME"/MediaArtistNativeHelper"
+
+#define AUDIO_FORMAT_CLASS_NAME                MANUAL_EDIT_ENGINE_CLASS_NAME"$AudioFormat"
+#define RESULTS_CLASS_NAME                     MANUAL_EDIT_ENGINE_CLASS_NAME"$Results"
+#define VERSION_CLASS_NAME                     MANUAL_EDIT_ENGINE_CLASS_NAME"$Version"
+#define AUDIO_SAMPLING_FREQUENCY_CLASS_NAME    MANUAL_EDIT_ENGINE_CLASS_NAME"$AudioSamplingFrequency"
+#define BITRATE_CLASS_NAME                     MANUAL_EDIT_ENGINE_CLASS_NAME"$Bitrate"
+#define ERROR_CLASS_NAME                       MANUAL_EDIT_ENGINE_CLASS_NAME"$Result"
+#define FILE_TYPE_CLASS_NAME                   MANUAL_EDIT_ENGINE_CLASS_NAME"$FileType"
+#define MEDIA_RENDERING_CLASS_NAME             MANUAL_EDIT_ENGINE_CLASS_NAME"$MediaRendering"
+#define VIDEO_FORMAT_CLASS_NAME                MANUAL_EDIT_ENGINE_CLASS_NAME"$VideoFormat"
+#define VIDEO_FRAME_RATE_CLASS_NAME            MANUAL_EDIT_ENGINE_CLASS_NAME"$VideoFrameRate"
+#define VIDEO_FRAME_SIZE_CLASS_NAME            MANUAL_EDIT_ENGINE_CLASS_NAME"$VideoFrameSize"
+#define VIDEO_PROFILE_CLASS_NAME               MANUAL_EDIT_ENGINE_CLASS_NAME"$VideoProfile"
+#define ALPHA_MAGIC_SETTINGS_CLASS_NAME        MANUAL_EDIT_ENGINE_CLASS_NAME"$AlphaMagicSettings"
+#define AUDIO_EFFECT_CLASS_NAME                MANUAL_EDIT_ENGINE_CLASS_NAME"$AudioEffect"
+#define AUDIO_TRANSITION_CLASS_NAME            MANUAL_EDIT_ENGINE_CLASS_NAME"$AudioTransition"
+#define BACKGROUND_MUSIC_SETTINGS_CLASS_NAME   MANUAL_EDIT_ENGINE_CLASS_NAME"$BackgroundMusicSettings"
+#define CLIP_SETTINGS_CLASS_NAME               MANUAL_EDIT_ENGINE_CLASS_NAME"$ClipSettings"
+#define EDIT_SETTINGS_CLASS_NAME               MANUAL_EDIT_ENGINE_CLASS_NAME"$EditSettings"
+#define EFFECT_SETTINGS_CLASS_NAME             MANUAL_EDIT_ENGINE_CLASS_NAME"$EffectSettings"
+#define SLIDE_DIRECTION_CLASS_NAME             MANUAL_EDIT_ENGINE_CLASS_NAME"$SlideDirection"
+#define SLIDE_TRANSITION_SETTINGS_CLASS_NAME   MANUAL_EDIT_ENGINE_CLASS_NAME"$SlideTransitionSettings"
+#define TRANSITION_BEHAVIOUR_CLASS_NAME        MANUAL_EDIT_ENGINE_CLASS_NAME"$TransitionBehaviour"
+#define TRANSITION_SETTINGS_CLASS_NAME         MANUAL_EDIT_ENGINE_CLASS_NAME"$TransitionSettings"
+#define VIDEO_EFFECT_CLASS_NAME                MANUAL_EDIT_ENGINE_CLASS_NAME"$VideoEffect"
+#define VIDEO_TRANSITION_CLASS_NAME            MANUAL_EDIT_ENGINE_CLASS_NAME"$VideoTransition"
+#define PREVIEW_CLIPS_CLASS_NAME               MANUAL_EDIT_ENGINE_CLASS_NAME"$PreviewClips"
+#define PREVIEW_SETTING_CLASS_NAME             MANUAL_EDIT_ENGINE_CLASS_NAME"$PreviewSettings"
+#define PREVIEW_PROPERTIES_CLASS_NAME          MANUAL_EDIT_ENGINE_CLASS_NAME"$PreviewClipProperties"
+#define AUDIO_SETTINGS_CLASS_NAME              MANUAL_EDIT_ENGINE_CLASS_NAME"$AudioSettings"
+#define PROPERTIES_CLASS_NAME                  MANUAL_EDIT_ENGINE_CLASS_NAME"$Properties"
+
+#define TASK_IDLE                                   0
+#define TASK_LOADING_SETTINGS                       1
+#define TASK_ENCODING                               2
+
+/*
+ * File type enum
+ */
+typedef enum
+{
+    VideoEditClasses_kFileType_3GPP,
+    VideoEditClasses_kFileType_MP4,
+    VideoEditClasses_kFileType_AMR,
+    VideoEditClasses_kFileType_MP3,
+    VideoEditClasses_kFileType_PCM,
+    VideoEditClasses_kFileType_JPG,
+    VideoEditClasses_kFileType_GIF,
+    VideoEditClasses_kFileType_PNG,
+    VideoEditClasses_kFileType_Unsupported
+} VideoEditClasses_FileType;
+
+/*
+ * Alpha magic transition structure
+ */
+typedef struct
+{
+    jfieldID file;
+    jfieldID blendingPercent;
+    jfieldID invertRotation;
+    jfieldID rgbWidth;
+    jfieldID rgbHeight;
+} VideoEditJava_AlphaMagicFieldIds;
+
+typedef struct
+{
+    jfieldID file;
+    jfieldID fileType;
+    jfieldID insertionTime;
+    jfieldID volumePercent;
+    jfieldID beginLoop;
+    jfieldID endLoop;
+    jfieldID enableDucking;
+    jfieldID duckingThreshold;
+    jfieldID lowVolume;
+    jfieldID isLooping;
+} VideoEditJava_BackgroundMusicFieldIds;
+/*
+ * Structure to hold media properties from native layer
+ */
+typedef struct {
+    M4OSA_UInt32                        uiClipDuration;
+    VideoEditClasses_FileType         FileType;
+    M4VIDEOEDITING_VideoFormat          VideoStreamType;
+    M4OSA_UInt32                        uiClipVideoDuration;
+    M4OSA_UInt32                        uiVideoBitrate;
+    M4OSA_UInt32                        uiVideoWidth;
+    M4OSA_UInt32                        uiVideoHeight;
+    M4OSA_Float                         fAverageFrameRate;
+    M4VIDEOEDITING_VideoProfileAndLevel ProfileAndLevel;
+    M4VIDEOEDITING_AudioFormat          AudioStreamType;
+    M4OSA_UInt32                        uiClipAudioDuration;
+    M4OSA_UInt32                        uiAudioBitrate;
+    M4OSA_UInt32                        uiNbChannels;
+    M4OSA_UInt32                        uiSamplingFrequency;
+} VideoEditPropClass_Properties;
+
+typedef struct
+{
+    jfieldID duration;
+    jfieldID fileType;
+    jfieldID videoFormat;
+    jfieldID videoDuration;
+    jfieldID videoBitrate;
+    jfieldID width;
+    jfieldID height;
+    jfieldID averageFrameRate;
+    jfieldID profileAndLevel;
+    jfieldID audioFormat;
+    jfieldID audioDuration;
+    jfieldID audioBitrate;
+    jfieldID audioChannels;
+    jfieldID audioSamplingFrequency;
+} VideoEditJava_PropertiesFieldIds;
+
+
+typedef struct
+{
+    jfieldID clipPath;
+    jfieldID fileType;
+    jfieldID beginCutTime;
+    jfieldID endCutTime;
+    jfieldID beginCutPercent;
+    jfieldID endCutPercent;
+    jfieldID panZoomEnabled;
+    jfieldID panZoomPercentStart;
+    jfieldID panZoomTopLeftXStart;
+    jfieldID panZoomTopLeftYStart;
+    jfieldID panZoomPercentEnd;
+    jfieldID panZoomTopLeftXEnd;
+    jfieldID panZoomTopLeftYEnd;
+    jfieldID mediaRendering;
+    jfieldID rgbFileWidth;
+    jfieldID rgbFileHeight;
+} VideoEditJava_ClipSettingsFieldIds;
+
+typedef struct
+{
+    jfieldID clipSettingsArray;
+    jfieldID transitionSettingsArray;
+    jfieldID effectSettingsArray;
+    jfieldID videoFrameRate;
+    jfieldID outputFile;
+    jfieldID videoFrameSize;
+    jfieldID videoFormat;
+    jfieldID audioFormat;
+    jfieldID audioSamplingFreq;
+    jfieldID maxFileSize;
+    jfieldID audioChannels;
+    jfieldID videoBitrate;
+    jfieldID audioBitrate;
+    jfieldID backgroundMusicSettings;
+    jfieldID primaryTrackVolume;
+} VideoEditJava_EditSettingsFieldIds;
+
+
+typedef struct
+{
+    jfieldID startTime;
+    jfieldID duration;
+    jfieldID videoEffectType;
+    jfieldID audioEffectType;
+    jfieldID startPercent;
+    jfieldID durationPercent;
+    jfieldID framingFile;
+    jfieldID framingBuffer;
+    jfieldID bitmapType;
+    jfieldID width;
+    jfieldID height;
+    jfieldID topLeftX;
+    jfieldID topLeftY;
+    jfieldID framingResize;
+    jfieldID framingScaledSize;
+    jfieldID text;
+    jfieldID textRenderingData;
+    jfieldID textBufferWidth;
+    jfieldID textBufferHeight;
+    jfieldID fiftiesFrameRate;
+    jfieldID rgb16InputColor;
+    jfieldID alphaBlendingStartPercent;
+    jfieldID alphaBlendingMiddlePercent;
+    jfieldID alphaBlendingEndPercent;
+    jfieldID alphaBlendingFadeInTimePercent;
+    jfieldID alphaBlendingFadeOutTimePercent;
+} VideoEditJava_EffectSettingsFieldIds;
+
+typedef struct
+{
+    jfieldID context;
+} VideoEditJava_EngineFieldIds;
+
+typedef struct
+{
+    jfieldID direction;
+} VideoEditJava_SlideTransitionSettingsFieldIds;
+
+typedef struct
+{
+    jfieldID duration;
+    jfieldID videoTransitionType;
+    jfieldID audioTransitionType;
+    jfieldID transitionBehaviour;
+    jfieldID alphaSettings;
+    jfieldID slideSettings;
+} VideoEditJava_TransitionSettingsFieldIds;
+
+typedef struct
+{
+    jfieldID major;
+    jfieldID minor;
+    jfieldID revision;
+} VideoEditJava_VersionFieldIds;
+
+
+typedef struct
+{
+    jmethodID onProgressUpdate;
+} VideoEditJava_EngineMethodIds;
+
+
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(AudioEffect           )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(AudioFormat           )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(AudioSamplingFrequency)
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(AudioTransition       )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(Bitrate               )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(Engine                )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(Error                 )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(FileType              )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(MediaRendering        )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(SlideDirection        )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(TransitionBehaviour   )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(VideoEffect           )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(VideoFormat           )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(VideoFrameRate        )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(VideoFrameSize        )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(VideoProfile          )
+VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(VideoTransition       )
+
+
+VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(AlphaMagic               )
+VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(BackgroundMusic          )
+VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(ClipSettings             )
+VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(ClipSettings             )
+VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(EditSettings             )
+VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(EffectSettings           )
+VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(Engine                   )
+VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(SlideTransitionSettings  )
+VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(TransitionSettings       )
+VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(Version                  )
+
+VIDEOEDIT_JAVA_DECLARE_METHOD_CLASS(Engine                  )
+
+/*
+ * Init all Edit settings related structures
+ */
+void
+videoEditClasses_init(
+                bool*                               pResult,
+                JNIEnv*                             pEnv);
+/**
+ ************************************************************************
+ * @brief    Media Properties init function.
+ * @param    pResult    (OUT) Pointer to hold result
+ * @param    pEnv       (IN)  JVM Interface pointer
+ ************************************************************************
+*/
+void
+videoEditPropClass_init(
+                bool*                               pResult,
+                JNIEnv*                             pEnv);
+/**
+ ************************************************************************
+ * @brief    Interface to populate Media Properties.
+ * @param    pResult        (IN/OUT)    Pointer to hold result
+ * @param    pEnv           (IN)        JVM Interface pointer
+ * @param    pProperties    (IN)        Media propeties structure pointer
+ * @param    pObject        (OUT)       Java object to hold media
+ *                                      properties for java layer.
+ ************************************************************************
+*/
+void
+videoEditPropClass_createProperties(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                VideoEditPropClass_Properties*      pProperties,
+                jobject*                            pObject);
+
+/**
+ ************************************************************************
+ * @brief    Interface to log/display media properties.
+ * @param    pProperties    (IN) Pointer holding media properties
+ * @param    indentation    (IN) Indentation to follow in display
+ ************************************************************************
+*/
+void
+videoEditPropClass_logProperties(
+                VideoEditPropClass_Properties*      pProperties,
+                int                                 indentation);
+
+/*
+ * Get alpha magic transition settings
+ */
+void
+videoEditClasses_getAlphaMagicSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                M4xVSS_AlphaMagicSettings**         ppSettings);
+
+/*
+ * Free alpha magic transition settings structure
+ */
+void
+videoEditClasses_freeAlphaMagicSettings(
+                M4xVSS_AlphaMagicSettings**         ppSettings);
+
+/*
+ * Log alpha magic transition settings
+ */
+void
+videoEditClasses_logAlphaMagicSettings(
+                M4xVSS_AlphaMagicSettings*          pSettings,
+                int                                 indentation);
+
+/*
+ * Get Background Track settings
+ */
+void
+videoEditClasses_getBackgroundMusicSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                M4xVSS_BGMSettings**                ppSettings);
+
+/*
+ * Free Background Track settings structure
+ */
+void
+videoEditClasses_freeBackgroundMusicSettings(
+                M4xVSS_BGMSettings**                ppSettings);
+
+/*
+ * Log Background Track settings
+ */
+void
+videoEditClasses_logBackgroundMusicSettings(
+                M4xVSS_BGMSettings*                 pSettings,
+                int                                 indentation);
+
+/*
+ * Log clip properties
+ */
+void
+videoEditClasses_logClipProperties(
+                M4VIDEOEDITING_ClipProperties*      pProperties,
+                int                                 indentation);
+
+/*
+ * Get clip settings from Java
+ */
+void
+videoEditClasses_getClipSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                M4VSS3GPP_ClipSettings**            ppSettings);
+/**
+ ************************************************************************
+ * @brief   Interface function to retrieve media properties for a given
+ *          file.
+ * @param   pEnv    (IN)    Pointer holding media properties
+ * @param   thiz    (IN)    Indentation to follow in display
+ * @param   file    (IN)    File path for which media properties has
+ *                          to be retrieved.
+ ************************************************************************
+*/
+jobject
+videoEditProp_getProperties(
+                JNIEnv*                             pEnv,
+                jobject                             thiz,
+                jstring                             file);
+
+/*
+ * Create/Set the clip settings to java Object
+ */
+void
+videoEditClasses_createClipSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                M4VSS3GPP_ClipSettings*             pSettings,
+                jobject*                            pObject);
+
+/*
+ * Free clip settings structure
+ */
+void
+videoEditClasses_freeClipSettings(
+                M4VSS3GPP_ClipSettings**            ppSettings);
+
+/*
+ * Log clip settings structure
+ */
+void
+videoEditClasses_logClipSettings(
+                M4VSS3GPP_ClipSettings*             pSettings,
+                int                                 indentation);
+
+/*
+ * Get Edit settings from Java
+ */
+void
+videoEditClasses_getEditSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                M4VSS3GPP_EditSettings**            ppSettings,
+                bool                                flag);
+
+/*
+ * Free Edit Settings structure
+ */
+void
+videoEditClasses_freeEditSettings(
+                M4VSS3GPP_EditSettings**            ppSettings);
+
+/*
+ * Log Edit settings structure
+ */
+void
+videoEditClasses_logEditSettings(
+                M4VSS3GPP_EditSettings*             pSettings,
+                int                                 indentation);
+
+/*
+ * Get Effect settings from Java
+ */
+void
+videoEditClasses_getEffectSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                M4VSS3GPP_EffectSettings*           pSettings);
+
+/*
+ * Free Effect settings structure
+ */
+void
+videoEditClasses_freeEffectSettings(
+                M4VSS3GPP_EffectSettings*           pSettings);
+
+/*
+ * Log Effect settings
+ */
+void
+videoEditClasses_logEffectSettings(
+                M4VSS3GPP_EffectSettings*           pSettings,
+                int                                 indentation);
+
+/*
+ * Get Transition-Sliding settings from Java
+ */
+void
+videoEditClasses_getSlideTransitionSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                M4xVSS_SlideTransitionSettings**    ppSettings);
+
+/*
+ * Free Transition-Sliding structure
+ */
+void
+videoEditClasses_freeSlideTransitionSettings(
+                M4xVSS_SlideTransitionSettings**    ppSettings);
+
+/*
+ * Free Transition-Sliding structure
+ */
+void
+videoEditClasses_logSlideTransitionSettings(
+                M4xVSS_SlideTransitionSettings*     pSettings,
+                int                                 indentation);
+
+/*
+ * Get Transition settings from Java
+ */
+void
+videoEditClasses_getTransitionSettings(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                M4VSS3GPP_TransitionSettings**      ppSettings);
+
+/*
+ * Free Transition settings structure
+ */
+void
+videoEditClasses_freeTransitionSettings(
+                M4VSS3GPP_TransitionSettings**      ppSettings);
+
+/*
+ * Log Transition settings
+ */
+void
+videoEditClasses_logTransitionSettings(
+                M4VSS3GPP_TransitionSettings*       pSettings,
+                int                                 indentation);
+
+/*
+ * Set version information to Java object
+ */
+void
+videoEditClasses_createVersion(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                M4_VersionInfo*                     pVersionInfo,
+                jobject*                            pObject);
+
+/*
+ * Log Version information
+ */
+void
+videoEditClasses_logVersion(
+                M4_VersionInfo*                     pVersionInfo,
+                int                                 indentation);
+
+
+void*
+videoEditClasses_getContext(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object);
+
+void
+videoEditClasses_setContext(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                void*                               pContext);
+
+
+#endif // VIDEO_EDITOR_CLASSES_H
+
diff --git a/media/jni/mediaeditor/VideoEditorJava.cpp b/media/jni/mediaeditor/VideoEditorJava.cpp
new file mode 100755
index 0000000..1d610f6
--- /dev/null
+++ b/media/jni/mediaeditor/VideoEditorJava.cpp
@@ -0,0 +1,885 @@
+/*
+ * Copyright (C) 2011 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 <VideoEditorClasses.h>
+#include <VideoEditorJava.h>
+#include <VideoEditorLogging.h>
+#include <VideoEditorOsal.h>
+
+extern "C" {
+#include <M4OSA_CharStar.h>
+};
+
+
+void
+videoEditJava_checkAndThrowIllegalArgumentException(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                bool                                condition,
+                const char*                         pMessage)
+{
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Check if the condition is true.
+        if (condition)
+        {
+            // Log the exception.
+            VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_JAVA",\
+                    "videoEditJava_checkAndThrowIllegalArgumentException, %s", pMessage);
+
+            // Reset the result flag.
+            (*pResult) = false;
+
+            // Throw an exception.
+            jniThrowException(pEnv, "java/lang/IllegalArgumentException", pMessage);
+        }
+    }
+}
+
+void
+videoEditJava_checkAndThrowRuntimeException(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                bool                                condition,
+                M4OSA_ERR                           result)
+{
+    const char* pMessage = NULL;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Check if the condition is true.
+        if (condition)
+        {
+            // Get the error string.
+            pMessage = videoEditJava_getErrorName(result);
+
+            // Log the exception.
+            VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_JAVA",
+                    "videoEditJava_checkAndThrowRuntimeException, %s", pMessage);
+
+            // Reset the result flag.
+            (*pResult) = false;
+
+            // Throw an exception.
+            jniThrowException(pEnv, "java/lang/RuntimeException", pMessage);
+        }
+    }
+}
+
+void
+videoEditJava_checkAndThrowIllegalStateException(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                bool                                condition,
+                const char*                         pMessage)
+{
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Check if the condition is true.
+        if (condition)
+        {
+            // Log the exception.
+            VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_JAVA",
+                    "videoEditJava_checkAndThrowIllegalStateException, %s", pMessage);
+
+            // Reset the result flag.
+            (*pResult) = false;
+
+            // Throw an exception.
+            jniThrowException(pEnv, "java/lang/IllegalStateException", pMessage);
+        }
+    }
+}
+
+void
+videoEditJava_getClass(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                const char*                         pName,
+                jclass*                             pClazz)
+{
+    // Only look for the class if locating the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
+                "videoEditJava_getClass(%s)", pName);
+
+        // Look up the class.
+        jclass clazz = pEnv->FindClass(pName);
+
+        // Clear any resulting exceptions.
+        pEnv->ExceptionClear();
+
+        // Check if the class could be located.
+        if (NULL != clazz)
+        {
+            // Return the class.
+            (*pClazz) = clazz;
+        }
+        else
+        {
+            // Reset the result flag.
+            (*pResult) = false;
+
+            // Log the error.
+            VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_JAVA",
+                    "videoEditJava_getClass, error: unable to locate class %s", pName);
+
+            // Throw an exception.
+            jniThrowException(pEnv, "java/lang/ClassNotFoundException",
+                    "unable to locate class");
+        }
+    }
+}
+
+void
+videoEditJava_getMethodId(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jclass                              clazz,
+                const char*                         pName,
+                const char*                         pType,
+                jmethodID*                          pMethodId)
+{
+    // Only look for the class if locating the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
+                "videoEditJava_getMethodId(%s,%s)", pName, pType);
+
+        // Look up the method id.
+        jmethodID methodId = pEnv->GetMethodID(clazz, pName, pType);
+
+        // Clear any resulting exceptions.
+        pEnv->ExceptionClear();
+
+        // Check if the method could be located.
+        if (NULL != methodId)
+        {
+            // Return the method id.
+            (*pMethodId) = methodId;
+        }
+        else
+        {
+            // Reset the result flag.
+            (*pResult) = false;
+
+            // Log the error.
+            VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_JAVA",
+                    "videoEditJava_getMethodId, error: unable to locate method %s with type %s",
+                    pName, pType);
+
+            // Throw an exception.
+            jniThrowException(pEnv, "java/lang/NoSuchMethodException", "unable to locate method");
+        }
+    }
+}
+
+void
+videoEditJava_getFieldId(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jclass                              clazz,
+                const char*                         pName,
+                const char*                         pType,
+                jfieldID*                           pFieldId)
+{
+    // Only look for the class if locating the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
+                "videoEditJava_getFieldId(%s,%s)", pName, pType);
+
+        // Look up the field id.
+        jfieldID fieldId = pEnv->GetFieldID(clazz, pName, pType);
+
+        // Clear any resulting exceptions.
+        pEnv->ExceptionClear();
+
+        // Check if the field could be located.
+        if (NULL != fieldId)
+        {
+            // Return the field id.
+            (*pFieldId) = fieldId;
+        }
+        else
+        {
+            // Reset the result flag.
+            (*pResult) = false;
+
+            // Log the error.
+            VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_JAVA",
+                    "videoEditJava_getFieldId, error: unable to locate field %s with type %s",
+                    pName, pType);
+
+            // Throw an exception.
+            jniThrowException(pEnv, "java/lang/NoSuchFieldException", "unable to locate field");
+        }
+    }
+}
+
+void
+videoEditJava_getObject(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                jfieldID                            objectFieldId,
+                jobject*                            pObject)
+{
+    // Only retrieve the array object and size if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
+            "videoEditJava_getObject()");
+
+        // Retrieve the object.
+        (*pObject) = pEnv->GetObjectField(object, objectFieldId);
+
+        // Clear any resulting exceptions.
+        pEnv->ExceptionClear();
+    }
+}
+
+void
+videoEditJava_getArray(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                jfieldID                            arrayFieldId,
+                jobjectArray*                       pArray,
+                jsize*                              pArraySize)
+{
+    // Only retrieve the array object and size if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA", "videoEditJava_getArray()");
+
+        // Retrieve the array object.
+        jobjectArray array     = (jobjectArray)pEnv->GetObjectField(object, arrayFieldId);
+        jsize        arraySize = 0;
+
+        // Clear any resulting exceptions.
+        pEnv->ExceptionClear();
+
+        // Check if the array could be retrieved.
+        if (NULL != array)
+        {
+            // Retrieve the array size.
+            arraySize = pEnv->GetArrayLength(array);
+        }
+
+        // Return the array and its size.
+        (*pArray)     = array;
+        (*pArraySize) = arraySize;
+    }
+}
+
+void*
+videoEditJava_getString(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                jfieldID                            stringFieldId,
+                M4OSA_UInt32*                       pLength)
+{
+    void*        pString = M4OSA_NULL;
+    jstring      string  = NULL;
+    M4OSA_UInt32 length  = 0;
+    M4OSA_Char*  pLocal  = M4OSA_NULL;
+    M4OSA_ERR    result  = M4NO_ERROR;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA", "videoEditJava_getString()");
+
+        // Check if an object containing a string was specified.
+        if (NULL != stringFieldId)
+        {
+            // Retrieve the string object.
+            string = (jstring)pEnv->GetObjectField(object, stringFieldId);
+
+            // Clear any resulting exceptions.
+            pEnv->ExceptionClear();
+        }
+        else
+        {
+            // The string itself was specified.
+            string = (jstring)object;
+        }
+
+        // Check if the string could be retrieved.
+        if (NULL != string)
+        {
+            // Get a local copy of the string.
+            pLocal = (M4OSA_Char*)pEnv->GetStringUTFChars(string, M4OSA_NULL);
+            if (M4OSA_NULL != pLocal)
+            {
+                // Determine the length of the path
+                // (add one extra character for the zero terminator).
+                length = M4OSA_chrLength(pLocal) + 1;
+
+                // Allocate memory for the string.
+                pString = videoEditOsal_alloc(pResult, pEnv, length, "String");
+                if (*pResult)
+                {
+                    // Copy the string.
+                    result = M4OSA_chrNCopy((M4OSA_Char*)pString, pLocal, length);
+
+                    // Check if the copy succeeded.
+                    videoEditJava_checkAndThrowRuntimeException(pResult, pEnv,
+                     (M4NO_ERROR != result), result);
+
+                    // Check if the string could not be copied.
+                    if (!(*pResult))
+                    {
+                        // Free the allocated memory.
+                        videoEditOsal_free(pString);
+                        pString = M4OSA_NULL;
+                    }
+                }
+
+                // Release the local copy of the string.
+                pEnv->ReleaseStringUTFChars(string, (const char *)pLocal);
+            }
+        }
+
+        // Check if the string was empty or could be copied.
+        if (*pResult)
+        {
+            // Check if the length was requested.
+            if (M4OSA_NULL != pLength)
+            {
+                // Return the length.
+                (*pLength) = length;
+            }
+        }
+    }
+
+    // Return the string.
+    return(pString);
+}
+
+void
+videoEditJava_getStaticIntField(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jclass                              clazz,
+                const char*                         pName,
+                int*                                pValue)
+{
+    // Only look for the class if locating the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
+                "videoEditJava_getStaticIntField(%s)", pName);
+
+        // Look up the field id.
+        jfieldID fieldId = pEnv->GetStaticFieldID(clazz, pName, "I");
+
+        // Clear any resulting exceptions.
+        pEnv->ExceptionClear();
+
+        // Check if the field could be located.
+        if (NULL != fieldId)
+        {
+            // Retrieve the field value.
+            (*pValue) = pEnv->GetStaticIntField(clazz, fieldId);
+
+            // Log the value.
+            VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
+                    "videoEditJava_getStaticIntField, %s = %d", pName, (*pValue));
+        }
+        else
+        {
+            // Reset the result flag.
+            (*pResult) = false;
+
+            // Log the error.
+            VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_JAVA",
+                    "videoEditJava_getStaticIntField, error: unable to locate field %s", pName);
+
+            // Throw an exception.
+            jniThrowException(pEnv, "java/lang/NoSuchFieldException",
+                    "unable to locate static field");
+        }
+    }
+}
+
+void
+videoEditJava_initConstantClass(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                VideoEditJava_ConstantsClass*               pClass)
+{
+    bool   gotten = true;
+    jclass clazz  = NULL;
+    int    index  = 0;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
+                "videoEditJava_initConstantClass(%s)", pClass->pName);
+
+        // Only initialize the class once.
+        if (!pClass->initialized)
+        {
+            // Look up the class.
+            videoEditJava_getClass(pResult, pEnv, pClass->pName, &clazz);
+
+            // Loop over the constants.
+            for (index = 0; index < pClass->count; index++)
+            {
+                // Look up the constant.
+                videoEditJava_getStaticIntField(pResult, pEnv, clazz,
+                                        pClass->pConstants[index].pName,
+                                        &pClass->pConstants[index].java);
+            }
+
+            // Check if all constants could be located.
+            if (*pResult)
+            {
+                // Set the initialized flag.
+                pClass->initialized = true;
+            }
+        }
+    }
+}
+
+const char*
+videoEditJava_getConstantClassName(
+                const VideoEditJava_ConstantsClass*         pClass,
+                int                                 value,
+                VideoEditJava_UnknownConstant               unknown)
+{
+    const char* pName = M4OSA_NULL;
+    int         index = 0;
+
+    // Loop over the list with constants.
+    for (index = 0;
+         ((M4OSA_NULL == pName) && (index < pClass->count));
+         index++)
+    {
+        // Check if the specified value matches the c value of the constant.
+        if (value == pClass->pConstants[index].c)
+        {
+            // Set the name.
+            pName = pClass->pConstants[index].pName;
+        }
+    }
+
+    // Check if no constant was found.
+    if (M4OSA_NULL == pName)
+    {
+        // Check if a function was specified to handle this case.
+        if (M4OSA_NULL != unknown)
+        {
+            // Pass the constant to the specified unknown function.
+            pName = unknown(value);
+        }
+        else
+        {
+            // Set the description to a default value.
+            pName = "<unknown>";
+        }
+    }
+
+    // Return the result.
+    return(pName);
+}
+
+const char*
+videoEditJava_getConstantClassString(
+                const VideoEditJava_ConstantsClass*         pClass,
+                int                                 value,
+                VideoEditJava_UnknownConstant               unknown)
+{
+    const char* pString = M4OSA_NULL;
+    int         index   = 0;
+
+    // Loop over the list with constants.
+    for (index = 0;
+         ((M4OSA_NULL == pString) && (index < pClass->count));
+         index++)
+    {
+        // Check if the specified value matches the c value of the constant.
+        if (value == pClass->pConstants[index].c)
+        {
+            // Set the description.
+            pString = pClass->pConstants[index].pDescription;
+        }
+    }
+
+    // Check if no constant was found.
+    if (M4OSA_NULL == pString)
+    {
+        // Check if a function was specified to handle this case.
+        if (M4OSA_NULL != unknown)
+        {
+            // Pass the constant to the specified unknown function.
+            pString = unknown(value);
+        }
+        else
+        {
+            // Set the description to a default value.
+            pString = "<unknown>";
+        }
+    }
+
+    // Return the result.
+    return(pString);
+}
+
+int
+videoEditJava_getConstantClassJavaToC(
+                bool*                               pResult,
+                const VideoEditJava_ConstantsClass*         pClass,
+                int                                 value)
+{
+    bool gotten = false;
+    int  index  = 0;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Loop over the list with constants.
+        for (index = 0; ((!gotten) && (index < pClass->count)); index++)
+        {
+            // Check if the specified value matches the java value of the constant.
+            if (value == pClass->pConstants[index].java)
+            {
+                // Set the value to the c value.
+                value = pClass->pConstants[index].c;
+
+                // Set the gotten flag.
+                gotten = true;
+            }
+        }
+
+        // Check if the value was not found.
+        if (!gotten)
+        {
+            (*pResult) = false;
+        }
+    }
+
+    // Return the translated value.
+    return(value);
+}
+
+int
+videoEditJava_getConstantClassJavaToC(
+                bool*                               pResult,
+                const VideoEditJava_ConstantsClass*         pClass,
+                int                                 value,
+                int                                 unknown)
+{
+    bool gotten = false;
+    int  index  = 0;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Loop over the list with constants.
+        for (index = 0; ((!gotten) && (index < pClass->count)); index++)
+        {
+            // Check if the specified value matches the java value of the constant.
+            if (value == pClass->pConstants[index].java)
+            {
+                // Set the value to the c value.
+                value = pClass->pConstants[index].c;
+
+                // Set the gotten flag.
+                gotten = true;
+            }
+        }
+
+        // If the constant was not found, look for the specified unknown.
+        if (!gotten)
+        {
+            // Set the value to the c value.
+            value = unknown;
+        }
+    }
+
+    // Return the translated value.
+    return(value);
+}
+
+int
+videoEditJava_getConstantClassCToJava(
+                const VideoEditJava_ConstantsClass*         pClass,
+                int                                 value)
+{
+    bool gotten = false;
+    int  index  = 0;
+
+    // Loop over the list with constants.
+    for (index = 0; ((!gotten) && (index < pClass->count)); index++)
+    {
+        // Check if the specified value matches the c value of the constant.
+        if (value == pClass->pConstants[index].c)
+        {
+            // Set the value to the java value.
+            value = pClass->pConstants[index].java;
+
+            // Set the gotten flag.
+            gotten = true;
+        }
+    }
+
+    // Return the translated value.
+    return(value);
+}
+
+int
+videoEditJava_getConstantClassCToJava(
+                const VideoEditJava_ConstantsClass*         pClass,
+                int                                 value,
+                int                                 unknown)
+{
+    bool gotten = false;
+    int  index  = 0;
+
+    // Loop over the list with constants.
+    for (index = 0; ((!gotten) && (index < pClass->count)); index++)
+    {
+        // Check if the specified value matches the c value of the constant.
+        if (value == pClass->pConstants[index].c)
+        {
+            // Set the value to the java value.
+            value = pClass->pConstants[index].java;
+
+            // Set the gotten flag.
+            gotten = true;
+        }
+    }
+
+    // If the constant was not found, look for the specified unknown.
+    if (!gotten)
+    {
+        // Loop over the list with constants.
+        for (index = 0; ((!gotten) && (index < pClass->count)); index++)
+        {
+            // Check if the specified value matches the java value of the constant.
+            if (unknown == pClass->pConstants[index].c)
+            {
+                // Set the value to the c value.
+                value = pClass->pConstants[index].java;
+
+                // Set the gotten flag.
+                gotten = true;
+            }
+        }
+    }
+
+    // Return the translated value.
+    return(value);
+}
+
+void
+videoEditJava_initFieldClass(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                VideoEditJava_FieldsClass*                  pClass)
+{
+    bool   gotten = true;
+    jclass clazz  = NULL;
+    int    index  = 0;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
+                "videoEditJava_initFieldClass(%s)", pClass->pName);
+
+        // Only initialize the class once.
+        if (!pClass->initialized)
+        {
+            // Look up the class.
+            videoEditJava_getClass(pResult, pEnv, pClass->pName, &clazz);
+
+            // Loop over the fields.
+            for (index = 0; index < pClass->count; index++)
+            {
+                // Look up the field id.
+                videoEditJava_getFieldId(
+                        pResult,
+                        pEnv,
+                        clazz,
+                        pClass->pFields[index].pName,
+                        pClass->pFields[index].pType,
+                        &pClass->pFields[index].fieldId);
+            }
+
+            // Check if all fields could be located.
+            if (*pResult)
+            {
+                // Set the initialized flag.
+                pClass->initialized = true;
+            }
+        }
+    }
+}
+
+void
+videoEditJava_fieldClassClass(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                const VideoEditJava_FieldsClass*            pClass,
+                jclass*                             pClazz)
+{
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Check if the class is initialized.
+        videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv, (!pClass->initialized),
+                "field class not initialized");
+
+        // Get the class.
+        videoEditJava_getClass(pResult, pEnv, pClass->pName, pClazz);
+    }
+}
+
+void
+videoEditJava_fieldClassFieldIds(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                const VideoEditJava_FieldsClass*            pClass,
+                int                                 count,
+                VideoEditJava_FieldIds*                     pIds)
+{
+    int index = 0;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Check if the class is initialized.
+        videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv, (!pClass->initialized),
+                "field class not initialized");
+
+        // Check if the number of fields matches.
+        videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
+                (pClass->count != count),
+                "field class type mismatch");
+
+        // Check if the class and object are valid.
+        if (*pResult)
+        {
+            // Loop over the class fields.
+            for (index = 0; index < count; index++)
+            {
+                // Copy the field ids.
+                pIds->fieldIds[index] = pClass->pFields[index].fieldId;
+            }
+        }
+    }
+}
+
+void
+videoEditJava_initMethodClass(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                VideoEditJava_MethodsClass*                 pClass)
+{
+    bool   gotten = true;
+    jclass clazz  = NULL;
+    int    index  = 0;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Log the function call.
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
+                "videoEditJava_initMethodClass(%s)", pClass->pName);
+
+        // Only initialize the class once.
+        if (!pClass->initialized)
+        {
+            // Look up the class.
+            videoEditJava_getClass(pResult, pEnv, pClass->pName, &clazz);
+
+            // Loop over the methods.
+            for (index = 0; index < pClass->count; index++)
+            {
+                // Look up the method id.
+                videoEditJava_getMethodId(
+                        pResult,
+                        pEnv,
+                        clazz,
+                        pClass->pMethods[index].pName,
+                        pClass->pMethods[index].pType,
+                        &pClass->pMethods[index].methodId);
+            }
+
+            // Check if all methods could be located.
+            if (*pResult)
+            {
+                // Set the initialized flag.
+                pClass->initialized = true;
+            }
+        }
+    }
+}
+
+void
+videoEditJava_methodClassMethodIds(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                const VideoEditJava_MethodsClass*   pClass,
+                int                                 count,
+                VideoEditJava_MethodIds*            pIds)
+{
+    int index = 0;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Check if the class is initialized.
+        videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv, (!pClass->initialized),
+                    "method class not initialized");
+
+        // Check if the number of methods matches.
+        videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,\
+                    (pClass->count != count),
+                    "method class type mismatch");
+
+        // Check if the class and object are valid.
+        if (*pResult)
+        {
+            // Loop over the class methods.
+            for (index = 0; index < count; index++)
+            {
+                // Copy the method ids.
+                pIds->methodIds[index] = pClass->pMethods[index].methodId;
+            }
+        }
+    }
+}
+
diff --git a/media/jni/mediaeditor/VideoEditorJava.h b/media/jni/mediaeditor/VideoEditorJava.h
new file mode 100755
index 0000000..9d7f096
--- /dev/null
+++ b/media/jni/mediaeditor/VideoEditorJava.h
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2011 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 VIDEO_EDiTOR_JAVA_H
+#define VIDEO_EDiTOR_JAVA_H
+
+#include <jni.h>
+#include <JNIHelp.h>
+
+/**
+ ************************************************************************
+ * @file        VideoEditorJava.h
+ * @brief       Interface for JNI methods that have specific access to
+ *              class, objects and method Ids defined in Java layer
+ ************************************************************************
+*/
+
+extern "C" {
+#include <M4OSA_Types.h>
+#include <M4OSA_Error.h>
+}
+
+#define VIDEOEDIT_JAVA_CONSTANT_INIT(m_name, m_c)                           \
+            { m_name,                                                       \
+              0,                                                            \
+              m_c,                                                          \
+              #m_c }
+
+#define VIDEOEDIT_JAVA_DEFINE_CONSTANTS(m_class)                            \
+static                                                                      \
+VideoEditJava_Constant g##m_class##Constants [] =
+
+#define VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(                               \
+                m_class,                                                    \
+                m_name,                                                     \
+                m_unknownName,                                              \
+                m_unknownString)                                            \
+                                                                            \
+static VideoEditJava_ConstantsClass g##m_class##ConstantsClass =            \
+{       m_name,                                                             \
+        &g##m_class##Constants[0],                                          \
+        (sizeof(g##m_class##Constants) / sizeof(VideoEditJava_Constant)),   \
+        false                                                               \
+};                                                                          \
+                                                                            \
+                                                                            \
+void videoEditJava_init##m_class##Constants(                                \
+                bool*                               pResult,                \
+                JNIEnv*                             pEnv)                   \
+{                                                                           \
+    videoEditJava_initConstantClass(                                        \
+                pResult,                                                    \
+                pEnv,                                                       \
+                &g##m_class##ConstantsClass);                               \
+}                                                                           \
+                                                                            \
+const char* videoEditJava_get##m_class##Name(                               \
+                int                                 value)                  \
+{                                                                           \
+    return(videoEditJava_getConstantClassName(                              \
+                &g##m_class##ConstantsClass,                                \
+                value,                                                      \
+                m_unknownName));                                            \
+}                                                                           \
+                                                                            \
+const char* videoEditJava_get##m_class##String(                             \
+                int                                 value)                  \
+{                                                                           \
+    return(videoEditJava_getConstantClassString(                            \
+                &g##m_class##ConstantsClass,                                \
+                value,                                                      \
+                m_unknownString));                                          \
+}                                                                           \
+                                                                            \
+int                                                                         \
+videoEditJava_get##m_class##JavaToC(                                        \
+                bool*                               pResult,                \
+                int                                 value)                  \
+{                                                                           \
+    return(videoEditJava_getConstantClassJavaToC(                           \
+                pResult,                                                    \
+                &g##m_class##ConstantsClass,                                \
+                value));                                                    \
+}                                                                           \
+                                                                            \
+int                                                                         \
+videoEditJava_get##m_class##JavaToC(                                        \
+                bool*                               pResult,                \
+                int                                 value,                  \
+                int                                 unknown)                \
+{                                                                           \
+    return(videoEditJava_getConstantClassJavaToC(                           \
+                pResult,                                                    \
+                &g##m_class##ConstantsClass,                                \
+                value,                                                      \
+                unknown));                                                  \
+}                                                                           \
+                                                                            \
+int                                                                         \
+videoEditJava_get##m_class##CToJava(                                        \
+                        int                                 value)          \
+{                                                                           \
+    return(videoEditJava_getConstantClassCToJava(                           \
+                &g##m_class##ConstantsClass,                                \
+                value));                                                    \
+}                                                                           \
+                                                                            \
+int                                                                         \
+videoEditJava_get##m_class##CToJava(                                        \
+                int                                 value,                  \
+                int                                 unknown)                \
+{                                                                           \
+    return(videoEditJava_getConstantClassCToJava(                           \
+                &g##m_class##ConstantsClass,                                \
+                value,                                                      \
+                unknown));                                                  \
+}
+
+
+#define VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(m_class)                       \
+void                                                                        \
+videoEditJava_init##m_class##Constants(                                     \
+                bool*                               pResult,                \
+                JNIEnv*                             pEnv);                  \
+                                                                            \
+const char*                                                                 \
+videoEditJava_get##m_class##Name(                                           \
+                int                                 value);                 \
+                                                                            \
+const char*                                                                 \
+videoEditJava_get##m_class##String(                                         \
+                int                                 value);                 \
+                                                                            \
+int                                                                         \
+videoEditJava_get##m_class##JavaToC(                                        \
+                bool*                               pResult,                \
+                int                                 value,                  \
+                int                                 unknown);               \
+                                                                            \
+int                                                                         \
+videoEditJava_get##m_class##JavaToC(                                        \
+                bool*                               pResult,                \
+                int                                 value);                 \
+                                                                            \
+int                                                                         \
+videoEditJava_get##m_class##CToJava(                                        \
+                int                                 value);                 \
+                                                                            \
+int                                                                         \
+videoEditJava_get##m_class##CToJava(                                        \
+                int                                 value,                  \
+                int                                 unknown);
+
+#define VIDEOEDIT_JAVA_FIELD_INIT(m_name, m_type)                           \
+    { m_name,                                                               \
+      m_type,                                                               \
+      NULL }
+
+#define VIDEOEDIT_JAVA_DEFINE_FIELDS(m_class)                               \
+static                                                                      \
+VideoEditJava_Field g##m_class##Fields [] =
+
+#define VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(m_class, m_name)                  \
+static VideoEditJava_FieldsClass g##m_class##FieldsClass =                  \
+    { m_name,                                                               \
+      &g##m_class##Fields[0],                                               \
+      (sizeof(g##m_class##Fields) / sizeof(VideoEditJava_Field)),           \
+      false };                                                              \
+                                                                            \
+void                                                                        \
+videoEditJava_init##m_class##Fields(                                        \
+                bool*                               pResult,                \
+                JNIEnv*                             pEnv)                   \
+{                                                                           \
+    videoEditJava_initFieldClass(                                           \
+                pResult,                                                    \
+                pEnv,                                                       \
+                &g##m_class##FieldsClass);                                  \
+}                                                                           \
+                                                                            \
+void                                                                        \
+videoEditJava_get##m_class##Class(                                          \
+                bool*                               pResult,                \
+                JNIEnv*                             pEnv,                   \
+                jclass*                             pClazz)                 \
+{                                                                           \
+    videoEditJava_fieldClassClass(                                          \
+                pResult,                                                    \
+                pEnv,                                                       \
+                &g##m_class##FieldsClass,                                   \
+                pClazz);                                                    \
+}                                                                           \
+                                                                            \
+void                                                                        \
+videoEditJava_get##m_class##FieldIds(                                       \
+                bool*                               pResult,                \
+                JNIEnv*                             pEnv,                   \
+                VideoEditJava_##m_class##FieldIds*          pIds)           \
+{                                                                           \
+    videoEditJava_fieldClassFieldIds(                                       \
+                pResult,                                                    \
+                pEnv,                                                       \
+                &g##m_class##FieldsClass,                                   \
+                (sizeof(VideoEditJava_##m_class##FieldIds) /                \
+                 sizeof(jfieldID)),                                         \
+                (VideoEditJava_FieldIds*)pIds);                             \
+}
+
+#define VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(m_class)                         \
+void                                                                        \
+videoEditJava_init##m_class##Fields(                                        \
+                bool*                               pResult,                \
+                JNIEnv*                             pEnv);                  \
+                                                                            \
+void                                                                        \
+videoEditJava_get##m_class##Class(                                          \
+                bool*                               pResult,                \
+                JNIEnv*                             pEnv,                   \
+                jclass*                             pClazz);                \
+                                                                            \
+void                                                                        \
+videoEditJava_get##m_class##FieldIds(                                       \
+                bool*                               pResult,                \
+                JNIEnv*                             pEnv,                   \
+                VideoEditJava_##m_class##FieldIds*          pIds);
+
+
+#define VIDEOEDIT_JAVA_METHOD_INIT(m_name, m_type)                          \
+    { m_name,                                                               \
+      m_type,                                                               \
+      NULL }
+
+#define VIDEOEDIT_JAVA_DEFINE_METHODS(m_class)                              \
+static                                                                      \
+VideoEditJava_Method g##m_class##Methods [] =
+
+#define VIDEOEDIT_JAVA_DEFINE_METHOD_CLASS(m_class, m_name)                 \
+static VideoEditJava_MethodsClass g##m_class##MethodsClass =                \
+    { m_name,                                                               \
+      &g##m_class##Methods[0],                                              \
+      (sizeof(g##m_class##Methods) / sizeof(VideoEditJava_Method)),         \
+      false };                                                              \
+                                                                            \
+void                                                                        \
+videoEditJava_init##m_class##Methods(                                       \
+                bool*                               pResult,                \
+                JNIEnv*                             pEnv)                   \
+{                                                                           \
+    videoEditJava_initMethodClass(                                          \
+                pResult,                                                    \
+                pEnv,                                                       \
+                &g##m_class##MethodsClass);                                 \
+}                                                                           \
+                                                                            \
+void                                                                        \
+videoEditJava_get##m_class##MethodIds(                                      \
+                bool*                               pResult,                \
+                JNIEnv*                             pEnv,                   \
+                VideoEditJava_##m_class##MethodIds*         pIds)           \
+{                                                                           \
+    videoEditJava_methodClassMethodIds(                                     \
+                pResult,                                                    \
+                pEnv,                                                       \
+                &g##m_class##MethodsClass,                                  \
+                (sizeof(VideoEditJava_##m_class##MethodIds) /               \
+                 sizeof(jmethodID)),                                        \
+                (VideoEditJava_MethodIds*)pIds);                            \
+}
+
+#define VIDEOEDIT_JAVA_DECLARE_METHOD_CLASS(m_class)                        \
+void                                                                        \
+videoEditJava_init##m_class##Methods(                                       \
+                bool*                               pResult,                \
+                JNIEnv*                             pEnv);                  \
+                                                                            \
+void                                                                        \
+videoEditJava_get##m_class##MethodIds(                                      \
+                bool*                               pResult,                \
+                JNIEnv*                             pEnv,                   \
+                VideoEditJava_##m_class##MethodIds*         pIds);
+
+
+typedef struct
+{
+    const char*     pName;
+    int             java;
+    int             c;
+    const char*     pDescription;
+} VideoEditJava_Constant;
+
+typedef struct
+{
+    const char*             pName;
+    VideoEditJava_Constant* pConstants;
+    int                     count;
+    bool                    initialized;
+} VideoEditJava_ConstantsClass;
+
+typedef const char* (*VideoEditJava_UnknownConstant)(int constant);
+
+typedef struct
+{
+    const char*             pName;
+    const char*             pType;
+    jfieldID                fieldId;
+} VideoEditJava_Field;
+
+typedef struct
+{
+    const char*             pName;
+    VideoEditJava_Field*    pFields;
+    int                     count;
+    bool                    initialized;
+} VideoEditJava_FieldsClass;
+
+typedef struct
+{
+    jfieldID fieldIds[];
+} VideoEditJava_FieldIds;
+
+typedef struct
+{
+    const char*             pName;
+    const char*             pType;
+    jmethodID               methodId;
+} VideoEditJava_Method;
+
+typedef struct
+{
+    const char*             pName;
+    VideoEditJava_Method*   pMethods;
+    int                     count;
+    bool                    initialized;
+} VideoEditJava_MethodsClass;
+
+typedef struct
+{
+    jmethodID methodIds[];
+} VideoEditJava_MethodIds;
+
+void
+videoEditJava_checkAndThrowIllegalArgumentException(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                bool                                condition,
+                const char*                         pMessage);
+
+void
+videoEditJava_checkAndThrowRuntimeException(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                bool                                condition,
+                M4OSA_ERR                           result);
+
+void
+videoEditJava_checkAndThrowIllegalStateException(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                bool                                condition,
+                const char*                         pMessage);
+
+void
+videoEditJava_getClass(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                const char*                         pName,
+                jclass*                             pClazz);
+
+void
+videoEditJava_getMethodId(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jclass                              clazz,
+                const char*                         pName,
+                const char*                         pType,
+                jmethodID*                          pMethodId);
+
+void videoEditJava_getFieldId(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jclass                              clazz,
+                const char*                         pName,
+                const char*                         pType,
+                jfieldID*                           pFieldId);
+
+void videoEditJava_getObject(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                jfieldID                            objectFieldId,
+                jobject*                            pObject);
+
+void videoEditJava_getArray(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                jfieldID                            arrayFieldId,
+                jobjectArray*                       pArray,
+                jsize*                              pArraySize);
+
+void* videoEditJava_getString(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                jobject                             object,
+                jfieldID                            stringFieldId,
+                M4OSA_UInt32*                       pLength);
+
+void videoEditJava_getStaticIntField(
+                bool*                               pResult,
+                JNIEnv*                             env,
+                jclass                              clazz,
+                const char*                         pName,
+                int*                                pValue);
+
+void
+videoEditJava_initConstantClass(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                VideoEditJava_ConstantsClass*               pClass);
+
+const char*
+videoEditJava_getConstantClassName(
+                const VideoEditJava_ConstantsClass*         pClass,
+                int                                 value,
+                VideoEditJava_UnknownConstant               unknown);
+
+const char*
+videoEditJava_getConstantClassString(
+                const VideoEditJava_ConstantsClass*         pClass,
+                int                                 value,
+                VideoEditJava_UnknownConstant               unknown);
+
+int
+videoEditJava_getConstantClassJavaToC(
+                bool*                               pResult,
+                const VideoEditJava_ConstantsClass*         pClass,
+                int                                 value);
+
+int
+videoEditJava_getConstantClassJavaToC(
+                bool*                               pResult,
+                const VideoEditJava_ConstantsClass*         pClass,
+                int                                 value,
+                int                                 unknown);
+
+int
+videoEditJava_getConstantClassCToJava(
+                const VideoEditJava_ConstantsClass*         pClass,
+                int                                 value);
+
+int
+videoEditJava_getConstantClassCToJava(
+                const VideoEditJava_ConstantsClass*         pClass,
+                int                                 value,
+                int                                 unknown);
+
+void
+videoEditJava_initFieldClass(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                VideoEditJava_FieldsClass*                  pClass);
+
+void
+videoEditJava_fieldClassClass(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                const VideoEditJava_FieldsClass*            pClass,
+                jclass*                             pClazz);
+
+void
+videoEditJava_fieldClassFieldIds(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                const VideoEditJava_FieldsClass*            pClass,
+                int                                 count,
+                VideoEditJava_FieldIds*                     pIds);
+
+void
+videoEditJava_initMethodClass(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                VideoEditJava_MethodsClass*                 pClass);
+
+void
+videoEditJava_methodClassMethodIds(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                const VideoEditJava_MethodsClass*           pClass,
+                int                                 count,
+                VideoEditJava_MethodIds*                    pIds);
+
+#endif // VIDEO_EDiTOR_JAVA_H
+
diff --git a/media/jni/mediaeditor/VideoEditorLogging.h b/media/jni/mediaeditor/VideoEditorLogging.h
new file mode 100755
index 0000000..ca8c047
--- /dev/null
+++ b/media/jni/mediaeditor/VideoEditorLogging.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 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 VIDEO_EDITOR_LOGGING_H
+#define VIDEO_EDITOR_LOGGING_H
+
+//#define VIDEOEDIT_LOGGING_ENABLED
+
+#define VIDEOEDIT_LOG_INDENTATION                       (3)
+
+#ifdef VIDEOEDIT_LOGGING_ENABLED
+
+#define VIDEOEDIT_LOG_ALLOCATION                        __android_log_print
+#define VIDEOEDIT_LOG_API                               __android_log_print
+#define VIDEOEDIT_LOG_ERROR                             __android_log_print
+#define VIDEOEDIT_LOG_EXCEPTION                         __android_log_print
+#define VIDEOEDIT_LOG_FUNCTION                          __android_log_print
+#define VIDEOEDIT_LOG_RESULT(x,y, ...)                     LOGI(y, __VA_ARGS__ )
+#define VIDEOEDIT_LOG_SETTING                           __android_log_print
+#define VIDEOEDIT_LOG_EDIT_SETTINGS(m_settings)         videoEditClasses_logEditSettings\
+                                               (m_settings, VIDEOEDIT_LOG_INDENTATION)
+#define VIDEOEDIT_PROP_LOG_PROPERTIES(m_properties)          videoEditPropClass_logProperties\
+                                                  (m_properties, VIDEOEDIT_LOG_INDENTATION)
+#define VIDEOEDIT_PROP_LOG_RESULT                            __android_log_print
+
+#else
+
+#define VIDEOEDIT_LOG_ALLOCATION                        (void)
+#define VIDEOEDIT_LOG_API                               (void)
+#define VIDEOEDIT_LOG_ERROR                             (void)
+#define VIDEOEDIT_LOG_EXCEPTION                         (void)
+#define VIDEOEDIT_LOG_FUNCTION                          (void)
+#define VIDEOEDIT_LOG_RESULT                            (void)
+#define VIDEOEDIT_LOG_SETTING                           (void)
+#define VIDEOEDIT_LOG_EDIT_SETTINGS(m_settings)         (void)m_settings
+#define VIDEOEDIT_PROP_LOG_PROPERTIES(m_properties)          (void)m_properties
+#define VIDEOEDIT_PROP_LOG_RESULT                            (void)
+
+#endif
+
+#endif // VIDEO_EDITOR_LOGGING_H
+
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
new file mode 100755
index 0000000..e66e4b9
--- /dev/null
+++ b/media/jni/mediaeditor/VideoEditorMain.cpp
@@ -0,0 +1,3056 @@
+/*
+ * Copyright (C) 2011 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 <dlfcn.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <VideoEditorClasses.h>
+#include <VideoEditorJava.h>
+#include <VideoEditorOsal.h>
+#include <VideoEditorLogging.h>
+#include <marker.h>
+#include <VideoEditorClasses.h>
+#include <VideoEditorThumbnailMain.h>
+#include <M4OSA_Debug.h>
+#include <M4xVSS_Internal.h>
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/ISurface.h>
+#include "VideoEditorPreviewController.h"
+
+#include "VideoEditorMain.h"
+
+extern "C" {
+#include <M4OSA_Clock.h>
+#include <M4OSA_CharStar.h>
+#include <M4OSA_Error.h>
+#include <M4OSA_FileCommon.h>
+#include <M4OSA_FileReader.h>
+#include <M4OSA_FileWriter.h>
+#include <M4OSA_FileExtra.h>
+#include <M4OSA_Memory.h>
+#include <M4OSA_String.h>
+#include <M4OSA_Thread.h>
+#include <M4xVSS_API.h>
+#include <M4VSS3GPP_ErrorCodes.h>
+#include <M4MCS_API.h>
+#include <M4MCS_ErrorCodes.h>
+#include <M4MDP_API.h>
+#include <M4READER_Common.h>
+#include <M4WRITER_common.h>
+};
+
+
+using namespace android;
+
+#define THREAD_STACK_SIZE       (65536)
+
+#define VIDEOEDITOR_VERSION_MAJOR     0
+#define VIDEOEDITOR_VERSION_MINOR     0
+#define VIDEOEDITOR_VERSION_REVISION  1
+
+
+typedef enum
+{
+    ManualEditState_NOT_INITIALIZED,
+    ManualEditState_INITIALIZED,
+    ManualEditState_ANALYZING,
+    ManualEditState_ANALYZING_ERROR,
+    ManualEditState_OPENED,
+    ManualEditState_SAVING,
+    ManualEditState_SAVING_ERROR,
+    ManualEditState_SAVED,
+    ManualEditState_STOPPING
+} ManualEditState;
+
+typedef struct
+{
+    JavaVM*                        pVM;
+    jobject                        engine;
+    jmethodID                      onCompletionMethodId;
+    jmethodID                      onErrorMethodId;
+    jmethodID                      onWarningMethodId;
+    jmethodID                      onProgressUpdateMethodId;
+    jmethodID                      onPreviewProgressUpdateMethodId;
+    M4xVSS_InitParams              initParams;
+    void*                          pTextRendererHandle;
+    M4xVSS_getTextRgbBufferFct     pTextRendererFunction;
+    M4OSA_Context                  engineContext;
+    ManualEditState                state;
+    M4VSS3GPP_EditSettings*        pEditSettings;
+    M4OSA_Context                  threadContext;
+    M4OSA_ERR                      threadResult;
+    M4OSA_UInt8                    threadProgress;
+    VideoEditorPreviewController   *mPreviewController;
+    M4xVSS_AudioMixingSettings     *mAudioSettings;
+    /* Audio Graph changes */
+    M4OSA_Context                   pAudioGraphMCSCtx;
+    M4OSA_Bool                      bSkipState;
+    jmethodID                       onAudioGraphProgressUpdateMethodId;
+    Mutex                           mLock;
+} ManualEditContext;
+
+extern "C" M4OSA_ERR M4MCS_open_normalMode(
+                M4MCS_Context                       pContext,
+                M4OSA_Void*                         pFileIn,
+                M4VIDEOEDITING_FileType             InputFileType,
+                M4OSA_Void*                         pFileOut,
+                M4OSA_Void*                         pTempFile);
+
+static M4OSA_ERR videoEditor_toUTF8Fct(
+                M4OSA_Void*                         pBufferIn,
+                M4OSA_UInt8*                        pBufferOut,
+                M4OSA_UInt32*                       bufferOutSize);
+
+static M4OSA_ERR videoEditor_fromUTF8Fct(
+                M4OSA_UInt8*                        pBufferIn,
+                M4OSA_Void*                         pBufferOut,
+                M4OSA_UInt32*                       bufferOutSize);
+
+static M4OSA_ERR videoEditor_getTextRgbBufferFct(
+                M4OSA_Void*                         pRenderingData,
+                M4OSA_Void*                         pTextBuffer,
+                M4OSA_UInt32                        textBufferSize,
+                M4VIFI_ImagePlane**                 pOutputPlane);
+
+static void videoEditor_callOnProgressUpdate(
+                ManualEditContext*                  pContext,
+                int                                 task,
+                int                                 progress);
+
+static void videoEditor_freeContext(
+                JNIEnv*                             pEnv,
+                ManualEditContext**                 ppContext);
+
+static M4OSA_ERR videoEditor_threadProc(
+                M4OSA_Void*                         param);
+
+static jobject videoEditor_getVersion(
+                JNIEnv*                             pEnv,
+                jobject                             thiz);
+
+static void videoEditor_init(
+                JNIEnv*                             pEnv,
+                jobject                             thiz,
+                jstring                             tempPath,
+                jstring                             textRendererPath);
+
+static void videoEditor_loadSettings(
+                JNIEnv*                             pEnv,
+                jobject                             thiz,
+                jobject                             settings);
+
+static void videoEditor_unloadSettings(
+                JNIEnv*                             pEnv,
+                jobject                             thiz);
+
+
+static void videoEditor_stopEncoding(
+                JNIEnv*                             pEnv,
+                jobject                             thiz);
+
+static void videoEditor_release(
+                JNIEnv*                             pEnv,
+                jobject                             thiz);
+static int videoEditor_getPixels(
+                                 JNIEnv*                  env,
+                                 jobject                  thiz,
+                                 jstring                  path,
+                                 jintArray                pixelArray,
+                                 M4OSA_UInt32             width,
+                                 M4OSA_UInt32             height,
+                                 M4OSA_UInt32             timeMS);
+static int videoEditor_getPixelsList(
+                                     JNIEnv*                  env,
+                                     jobject                  thiz,
+                                     jstring                  path,
+                                     jintArray                pixelArray,
+                                     M4OSA_UInt32             width,
+                                     M4OSA_UInt32             height,
+                                     M4OSA_UInt32             deltatimeMS,
+                                     M4OSA_UInt32             noOfThumbnails,
+                                     M4OSA_UInt32             startTime,
+                                     M4OSA_UInt32             endTime);
+
+static void
+videoEditor_startPreview(
+                JNIEnv*                 pEnv,
+                jobject                 thiz,
+                jobject                 mSurface,
+                jlong                   fromMs,
+                jlong                   toMs,
+                jint                    callbackInterval,
+                jboolean                loop);
+
+static void
+videoEditor_populateSettings(
+                JNIEnv*                 pEnv,
+                jobject                 thiz,
+                jobject                 settings,
+                jobject                 object,
+                jobject                 audioSettingObject);
+
+static void videoEditor_stopPreview(JNIEnv*  pEnv,
+                              jobject  thiz);
+
+static jobject
+videoEditor_getProperties(
+                JNIEnv*                             pEnv,
+                jobject                             thiz,
+                jstring                             file);
+
+static int videoEditor_renderPreviewFrame(JNIEnv* pEnv,
+                                    jobject thiz,
+                                    jobject    mSurface,
+                                    jlong fromMs,
+                                    jint  surfaceWidth,
+                                    jint  surfaceHeight);
+
+static int videoEditor_registerManualEditMethods(
+                JNIEnv*                             pEnv);
+
+static void jniPreviewProgressCallback(void* cookie, M4OSA_UInt32 msgType,
+                                        M4OSA_UInt32 argc);
+
+static int videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv, 
+                                                    jobject thiz,
+                                                    jobject mSurface,
+                                                    jstring filePath,
+                                                    jint frameWidth,
+                                                    jint frameHeight,
+                                                    jint surfaceWidth,
+                                                    jint surfaceHeight,
+                                                    jlong fromMs);
+
+static int videoEditor_generateAudioWaveFormSync ( JNIEnv*     pEnv,
+                                                  jobject     thiz,
+                                                  jstring     pcmfilePath,
+                                                  jstring     outGraphfilePath,
+                                                  jint        frameDuration,
+                                                  jint        channels,
+                                                  jint        samplesCount);
+
+static int videoEditor_generateAudioRawFile(JNIEnv* pEnv,
+                                    jobject thiz,
+                                    jstring infilePath,
+                                    jstring pcmfilePath );
+
+M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
+                                    M4OSA_Char* infilePath,
+                                    M4OSA_Char* pcmfilePath );
+
+static int
+videoEditor_generateClip(
+                JNIEnv*                             pEnv,
+                jobject                             thiz,
+                jobject                             settings);
+
+
+static JNINativeMethod gManualEditMethods[] = {
+    {"getVersion",               "()L"VERSION_CLASS_NAME";",
+                                (void *)videoEditor_getVersion      },
+    {"_init",                    "(Ljava/lang/String;Ljava/lang/String;)V",
+                                (void *)videoEditor_init    },
+    {"nativeStartPreview",       "(Landroid/view/Surface;JJIZ)V",
+                                (void *)videoEditor_startPreview    },
+    {"nativePopulateSettings",
+            "(L"EDIT_SETTINGS_CLASS_NAME";L"PREVIEW_PROPERTIES_CLASS_NAME";L"
+            AUDIO_SETTINGS_CLASS_NAME";)V",
+                                (void *)videoEditor_populateSettings    },
+    {"nativeRenderPreviewFrame", "(Landroid/view/Surface;JII)I",
+                                (int *)videoEditor_renderPreviewFrame     },
+    {"nativeRenderMediaItemPreviewFrame",
+    "(Landroid/view/Surface;Ljava/lang/String;IIIIJ)I",
+                        (int *)videoEditor_renderMediaItemPreviewFrame     },
+    {"nativeStopPreview",       "()V",
+                                (void *)videoEditor_stopPreview            },
+    {"stopEncoding",            "()V",
+                                (void *)videoEditor_stopEncoding         },
+    {"release",                 "()V",
+                                (void *)videoEditor_release            },
+    {"nativeGetPixels",         "(Ljava/lang/String;[IIIJ)I",
+                                (void*)videoEditor_getPixels               },
+    {"nativeGetPixelsList",     "(Ljava/lang/String;[IIIIIJJ)I",
+                                (void*)videoEditor_getPixelsList           },
+    {"getMediaProperties",
+    "(Ljava/lang/String;)Landroid/media/videoeditor/MediaArtistNativeHelper$Properties;",
+                                (void *)videoEditor_getProperties          },
+    {"nativeGenerateAudioGraph","(Ljava/lang/String;Ljava/lang/String;III)I",
+                                (int *)videoEditor_generateAudioWaveFormSync },
+    {"nativeGenerateRawAudio",  "(Ljava/lang/String;Ljava/lang/String;)I",
+                                (int *)videoEditor_generateAudioRawFile      },
+    {"nativeGenerateClip",      "(L"EDIT_SETTINGS_CLASS_NAME";)I",
+                                (void *)videoEditor_generateClip  },
+};
+
+// temp file name of VSS out file
+#define TEMP_MCS_OUT_FILE_PATH "/tmpOut.3gp"
+
+void
+getClipSetting(
+                JNIEnv*                                       pEnv,
+                jobject                                       object,
+                M4VSS3GPP_ClipSettings*                       pSettings)
+{
+
+    jfieldID fid;
+    int field = 0;
+    bool needToBeLoaded = true;
+    jclass clazz = pEnv->FindClass(PROPERTIES_CLASS_NAME);
+
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                             (M4OSA_NULL == clazz),
+                                             "not initialized");
+
+    fid = pEnv->GetFieldID(clazz,"duration","I");
+    pSettings->ClipProperties.uiClipDuration = pEnv->GetIntField(object,fid);
+    M4OSA_TRACE1_1("duration = %d",pSettings->ClipProperties.uiClipDuration);
+
+    fid = pEnv->GetFieldID(clazz,"videoFormat","I");
+    pSettings->ClipProperties.VideoStreamType =
+        (M4VIDEOEDITING_VideoFormat)pEnv->GetIntField(object,fid);
+    M4OSA_TRACE1_1("videoFormat = %d",pSettings->ClipProperties.VideoStreamType);
+
+    fid = pEnv->GetFieldID(clazz,"videoDuration","I");
+    pSettings->ClipProperties.uiClipVideoDuration = pEnv->GetIntField(object,fid);
+    M4OSA_TRACE1_1("videoDuration = %d",
+                    pSettings->ClipProperties.uiClipVideoDuration);
+
+    fid = pEnv->GetFieldID(clazz,"width","I");
+    pSettings->ClipProperties.uiVideoWidth = pEnv->GetIntField(object,fid);
+    M4OSA_TRACE1_1("width = %d",pSettings->ClipProperties.uiVideoWidth);
+
+    fid = pEnv->GetFieldID(clazz,"height","I");
+    pSettings->ClipProperties.uiVideoHeight = pEnv->GetIntField(object,fid);
+    M4OSA_TRACE1_1("height = %d",pSettings->ClipProperties.uiVideoHeight);
+
+    fid = pEnv->GetFieldID(clazz,"audioFormat","I");
+    pSettings->ClipProperties.AudioStreamType =
+        (M4VIDEOEDITING_AudioFormat)pEnv->GetIntField(object,fid);
+    M4OSA_TRACE1_1("audioFormat = %d",pSettings->ClipProperties.AudioStreamType);
+
+    fid = pEnv->GetFieldID(clazz,"audioDuration","I");
+    pSettings->ClipProperties.uiClipAudioDuration = pEnv->GetIntField(object,fid);
+    M4OSA_TRACE1_1("audioDuration = %d",
+                    pSettings->ClipProperties.uiClipAudioDuration);
+
+    fid = pEnv->GetFieldID(clazz,"audioBitrate","I");
+    pSettings->ClipProperties.uiAudioBitrate = pEnv->GetIntField(object,fid);
+    M4OSA_TRACE1_1("audioBitrate = %d",pSettings->ClipProperties.uiAudioBitrate);
+
+    fid = pEnv->GetFieldID(clazz,"audioChannels","I");
+    pSettings->ClipProperties.uiNbChannels = pEnv->GetIntField(object,fid);
+    M4OSA_TRACE1_1("audioChannels = %d",pSettings->ClipProperties.uiNbChannels);
+
+    fid = pEnv->GetFieldID(clazz,"audioSamplingFrequency","I");
+    pSettings->ClipProperties.uiSamplingFrequency = pEnv->GetIntField(object,fid);
+    M4OSA_TRACE1_1("audioSamplingFrequency = %d",
+                    pSettings->ClipProperties.uiSamplingFrequency);
+
+   fid = pEnv->GetFieldID(clazz,"audioVolumeValue","I");
+   pSettings->ClipProperties.uiClipAudioVolumePercentage =
+                    pEnv->GetIntField(object,fid);
+   M4OSA_TRACE1_1("audioVolumeValue = %d",
+                    pSettings->ClipProperties.uiClipAudioVolumePercentage);
+}
+
+static void jniPreviewProgressCallback (void* cookie, M4OSA_UInt32 msgType,
+                                        M4OSA_UInt32 argc)
+{
+    ManualEditContext *pContext = (ManualEditContext *)cookie;
+    JNIEnv*     pEnv = NULL;
+    bool        isFinished = false;
+    int         currentMs = 0;
+    int         error = M4NO_ERROR;
+
+    // Attach the current thread.
+    pContext->pVM->AttachCurrentThread(&pEnv, NULL);
+    switch(msgType)
+    {
+        case MSG_TYPE_PROGRESS_INDICATION:
+            currentMs = argc;
+            break;
+        case MSG_TYPE_PLAYER_ERROR:
+            currentMs = -1;
+            error = argc;
+            break;
+        case MSG_TYPE_PREVIEW_END:
+            isFinished = true;
+            break;
+        default:
+            break;
+    }
+
+    pEnv->CallVoidMethod(pContext->engine,
+                        pContext->onPreviewProgressUpdateMethodId,
+                        currentMs,isFinished);
+
+    // Detach the current thread.
+    pContext->pVM->DetachCurrentThread();
+
+}
+static void videoEditor_stopPreview(JNIEnv*  pEnv,
+                              jobject  thiz)
+{
+    ManualEditContext* pContext = M4OSA_NULL;
+    bool needToBeLoaded = true;
+    // Get the context.
+    pContext =
+            (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
+
+    // Make sure that the context was set.
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                             (M4OSA_NULL == pContext),
+                                             "not initialized");
+    pContext->mPreviewController->stopPreview();
+}
+
+static int videoEditor_renderPreviewFrame(JNIEnv* pEnv,
+                                    jobject thiz,
+                                    jobject    mSurface,
+                                    jlong fromMs,
+                                    jint surfaceWidth,
+                                    jint surfaceHeight )
+{
+    bool needToBeLoaded = true;
+    M4OSA_ERR result = M4NO_ERROR;
+    M4OSA_UInt32 timeMs = (M4OSA_UInt32)fromMs;
+    M4OSA_UInt32 i=0,tnTimeMs = 0, framesizeYuv =0;
+    M4VIFI_UInt8 *pixelArray = M4OSA_NULL;
+    M4OSA_UInt32    iCurrentClipIndex = 0, uiNumberOfClipsInStoryBoard =0,
+                    uiClipDuration = 0, uiTotalClipDuration = 0,
+                    iIncrementedDuration = 0;
+    VideoEditor_renderPreviewFrameStr frameStr;
+    M4OSA_Context tnContext = M4OSA_NULL;
+    const char* pMessage = NULL;
+    M4VIFI_ImagePlane *yuvPlane;
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
+        "VIDEO_EDITOR", "surfaceWidth = %d",surfaceWidth);
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
+        "VIDEO_EDITOR", "surfaceHeight = %d",surfaceHeight);
+    ManualEditContext* pContext = M4OSA_NULL;
+    // Get the context.
+    pContext =
+            (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
+                                "VIDEO_EDITOR","pContext = 0x%x",pContext);
+
+    // Make sure that the context was set.
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                             (M4OSA_NULL == pContext),
+                                             "not initialized");
+
+    // Make sure that the context was set.
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                 (M4OSA_NULL == pContext->mPreviewController),
+                                 "not initialized");
+
+    // Validate the mSurface parameter.
+    videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
+                                                (NULL == mSurface),
+                                                "mSurface is null");
+    jclass surfaceClass = pEnv->FindClass("android/view/Surface");
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                             (M4OSA_NULL == surfaceClass),
+                                             "not initialized");
+
+    jfieldID surface_native =
+            pEnv->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I");
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                             (M4OSA_NULL == surface_native),
+                                             "not initialized");
+
+    Surface* const p = (Surface*)pEnv->GetIntField(mSurface, surface_native);
+    sp<Surface> previewSurface = sp<Surface>(p);
+
+    /* Determine the total number of clips, total duration*/
+    uiNumberOfClipsInStoryBoard = pContext->pEditSettings->uiClipNumber;
+
+    for (i = 0; i < uiNumberOfClipsInStoryBoard; i++) {
+        uiClipDuration = pContext->pEditSettings->pClipList[i]->uiEndCutTime -
+            pContext->pEditSettings->pClipList[i]->uiBeginCutTime;
+        uiTotalClipDuration += uiClipDuration;
+    }
+
+    /* determine the clip whose thumbnail needs to be rendered*/
+    if (timeMs == 0) {
+        iCurrentClipIndex = 0;
+        i=0;
+    } else {
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+            "videoEditor_renderPreviewFrame() timeMs=%d", timeMs);
+
+        if (timeMs > uiTotalClipDuration) {
+            VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+                "videoEditor_renderPreviewFrame() timeMs > uiTotalClipDuration");
+            pMessage = videoEditJava_getErrorName(M4ERR_PARAMETER);
+            jniThrowException(pEnv, "java/lang/IllegalArgumentException", pMessage);
+            return -1;
+        }
+
+        for (i = 0; i < uiNumberOfClipsInStoryBoard; i++) {
+            if (timeMs < (iIncrementedDuration +
+                          (pContext->pEditSettings->pClipList[i]->uiEndCutTime -
+                           pContext->pEditSettings->pClipList[i]->uiBeginCutTime)))
+            {
+                iCurrentClipIndex = i;
+                VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+                    "videoEditor_renderPreviewFrame() iCurrentClipIndex=%d for timeMs=%d",
+                    iCurrentClipIndex, timeMs);
+                break;
+            }
+            else {
+                iIncrementedDuration = iIncrementedDuration +
+                    (pContext->pEditSettings->pClipList[i]->uiEndCutTime -
+                    pContext->pEditSettings->pClipList[i]->uiBeginCutTime);
+            }
+        }
+    }
+    /* If timestamp is beyond story board duration, return*/
+    if (i >= uiNumberOfClipsInStoryBoard) {
+        if (timeMs == iIncrementedDuration) {
+            iCurrentClipIndex = i-1;
+        } else {
+           return -1;
+        }
+    }
+
+    /*+ Handle the image files here */
+      if (pContext->pEditSettings->pClipList[iCurrentClipIndex]->FileType ==
+          /*M4VIDEOEDITING_kFileType_JPG*/ M4VIDEOEDITING_kFileType_ARGB8888 ) {
+          VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", " iCurrentClipIndex %d ", iCurrentClipIndex);
+          VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+                "  Height = %d",
+                pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoHeight);
+
+          VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+                "  Width = %d",
+                pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoWidth);
+
+          LvGetImageThumbNail((const char *)pContext->pEditSettings->\
+          pClipList[iCurrentClipIndex]->pFile,
+            pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoHeight,
+            pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoWidth,
+            (M4OSA_Void **)&frameStr.pBuffer);
+    } else {
+        /* Handle 3gp/mp4 Clips here */
+        /* get thumbnail*/
+        result = ThumbnailOpen(&tnContext,
+            (const M4OSA_Char*)pContext->pEditSettings->\
+            pClipList[iCurrentClipIndex]->pFile, M4OSA_TRUE);
+        if (result != M4NO_ERROR || tnContext  == M4OSA_NULL) {
+            return -1;
+        }
+
+        /* timeMs is relative to storyboard; in this api it shud be relative to this clip */
+        if ((i >= uiNumberOfClipsInStoryBoard) &&
+            (timeMs == iIncrementedDuration)) {
+            tnTimeMs = pContext->pEditSettings->\
+            pClipList[iCurrentClipIndex]->uiEndCutTime;
+        } else {
+            tnTimeMs = pContext->pEditSettings->\
+            pClipList[iCurrentClipIndex]->uiBeginCutTime
+            + (timeMs - iIncrementedDuration);
+        }
+
+        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+            "video width = %d",pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
+            ClipProperties.uiVideoWidth);
+        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+            "video height = %d",pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
+            ClipProperties.uiVideoHeight);
+        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+            "current clip index = %d",iCurrentClipIndex);
+
+        M4OSA_UInt32 width = pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
+            ClipProperties.uiVideoWidth;
+        M4OSA_UInt32 height = pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
+            ClipProperties.uiVideoHeight;
+
+        framesizeYuv = width * height * 1.5;
+
+        pixelArray = (M4VIFI_UInt8 *)M4OSA_malloc(framesizeYuv, M4VS,
+            (M4OSA_Char*)"videoEditor pixelArray");
+        if (pixelArray == M4OSA_NULL) {
+            VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+                "videoEditor_renderPreviewFrame() malloc error");
+            ThumbnailClose(tnContext);
+            pMessage = videoEditJava_getErrorName(M4ERR_ALLOC);
+            jniThrowException(pEnv, "java/lang/RuntimeException", pMessage);
+            return -1;
+        }
+
+        result = ThumbnailGetPixels16(tnContext, (M4OSA_Int16 *)pixelArray,
+            pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
+            ClipProperties.uiVideoWidth,
+            pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
+            ClipProperties.uiVideoHeight,
+            &tnTimeMs);
+        if (result != M4NO_ERROR) {
+            M4OSA_free((M4OSA_MemAddr32)pixelArray);
+            ThumbnailClose(tnContext);
+            return -1;
+        }
+
+        ThumbnailClose(tnContext);
+        tnContext = M4OSA_NULL;
+
+#ifdef DUMPTOFILE
+        {
+            M4OSA_Context fileContext;
+            M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/FirstRGB565.raw";
+            M4OSA_fileExtraDelete((const M4OSA_Char *)fileName);
+            M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\
+                M4OSA_kFileWrite|M4OSA_kFileCreate);
+            M4OSA_fileWriteData(fileContext, (M4OSA_MemAddr8) pixelArray,
+                framesizeYuv);
+            M4OSA_fileWriteClose(fileContext);
+        }
+#endif
+
+        /**
+        * Allocate output YUV planes
+        */
+        yuvPlane = (M4VIFI_ImagePlane*)M4OSA_malloc(3*sizeof(M4VIFI_ImagePlane), M4VS,
+            (M4OSA_Char*)"videoEditor_renderPreviewFrame Output plane YUV");
+        if (yuvPlane == M4OSA_NULL) {
+            VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+                "videoEditor_renderPreviewFrame() malloc error for yuv plane");
+            M4OSA_free((M4OSA_MemAddr32)pixelArray);
+            pMessage = videoEditJava_getErrorName(M4ERR_ALLOC);
+            jniThrowException(pEnv, "java/lang/RuntimeException", pMessage);
+            return -1;
+        }
+
+        yuvPlane[0].u_width = width;
+        yuvPlane[0].u_height = height;
+        yuvPlane[0].u_topleft = 0;
+        yuvPlane[0].u_stride = width;
+        yuvPlane[0].pac_data = (M4VIFI_UInt8*)pixelArray;
+
+        yuvPlane[1].u_width = width>>1;
+        yuvPlane[1].u_height = height>>1;
+        yuvPlane[1].u_topleft = 0;
+        yuvPlane[1].u_stride = width>>1;
+        yuvPlane[1].pac_data = yuvPlane[0].pac_data
+                    + yuvPlane[0].u_width * yuvPlane[0].u_height;
+        yuvPlane[2].u_width = (width)>>1;
+        yuvPlane[2].u_height = (height)>>1;
+        yuvPlane[2].u_topleft = 0;
+        yuvPlane[2].u_stride = (width)>>1;
+        yuvPlane[2].pac_data = yuvPlane[1].pac_data
+                    + yuvPlane[1].u_width * yuvPlane[1].u_height;
+
+#ifdef DUMPTOFILE
+        {
+            M4OSA_Context fileContext;
+            M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/ConvertedYuv.yuv";
+            M4OSA_fileExtraDelete((const M4OSA_Char *)fileName);
+            M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\
+                M4OSA_kFileWrite|M4OSA_kFileCreate);
+            M4OSA_fileWriteData(fileContext,
+                (M4OSA_MemAddr8) yuvPlane[0].pac_data, framesizeYuv);
+            M4OSA_fileWriteClose(fileContext);
+        }
+#endif
+
+        /* Fill up the render structure*/
+        frameStr.pBuffer = (M4OSA_Void*)yuvPlane[0].pac_data;
+    }
+
+    frameStr.timeMs = timeMs;    /* timestamp on storyboard*/
+    frameStr.uiSurfaceWidth =
+        pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
+        ClipProperties.uiVideoWidth;
+    frameStr.uiSurfaceHeight =
+        pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
+        ClipProperties.uiVideoHeight;
+    frameStr.uiFrameWidth =
+        pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
+        ClipProperties.uiVideoWidth;
+    frameStr.uiFrameHeight =
+        pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
+        ClipProperties.uiVideoHeight;
+    if (pContext->pEditSettings->nbEffects > 0) {
+        frameStr.bApplyEffect = M4OSA_TRUE;
+    } else {
+        frameStr.bApplyEffect = M4OSA_FALSE;
+    }
+    frameStr.clipBeginCutTime = iIncrementedDuration;
+    frameStr.clipEndCutTime =
+        iIncrementedDuration +
+        (pContext->pEditSettings->pClipList[iCurrentClipIndex]->uiEndCutTime -\
+        pContext->pEditSettings->pClipList[iCurrentClipIndex]->uiBeginCutTime);
+
+    pContext->mPreviewController->setPreviewFrameRenderingMode(
+        pContext->pEditSettings->\
+        pClipList[iCurrentClipIndex]->xVSS.MediaRendering,
+        pContext->pEditSettings->xVSS.outputVideoSize);
+
+    result = pContext->mPreviewController->renderPreviewFrame(previewSurface,
+                                                              &frameStr);
+    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
+            (M4NO_ERROR != result), result);
+
+    if (pContext->pEditSettings->pClipList[iCurrentClipIndex]->FileType ==\
+         /*M4VIDEOEDITING_kFileType_JPG */ M4VIDEOEDITING_kFileType_ARGB8888) {
+            M4OSA_free((M4OSA_MemAddr32)frameStr.pBuffer);
+    } else {
+        M4OSA_free((M4OSA_MemAddr32)yuvPlane[0].pac_data);
+        M4OSA_free((M4OSA_MemAddr32)yuvPlane);
+    }
+    return tnTimeMs;
+}
+
+static int videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv,
+                                                    jobject thiz,
+                                                    jobject mSurface,
+                                                    jstring filePath,
+                                                    jint    frameWidth,
+                                                    jint    frameHeight,
+                                                    jint    surfaceWidth,
+                                                    jint    surfaceHeight,
+                                                    jlong   fromMs)
+{
+    bool needToBeLoaded = true;
+    M4OSA_ERR result = M4NO_ERROR;
+    M4OSA_UInt32 timeMs = (M4OSA_UInt32)fromMs;
+    M4OSA_UInt32 framesizeYuv =0;
+    M4VIFI_UInt8 *pixelArray = M4OSA_NULL;
+    VideoEditor_renderPreviewFrameStr frameStr;
+    M4OSA_Context tnContext = M4OSA_NULL;
+    const char* pMessage = NULL;
+    M4VIFI_ImagePlane yuvPlane[3], rgbPlane;
+
+    ManualEditContext* pContext = M4OSA_NULL;
+    // Get the context.
+    pContext =
+            (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded,
+                                                      pEnv, thiz);
+
+    // Make sure that the context was set.
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                             (M4OSA_NULL == pContext),
+                                             "not initialized");
+
+    // Make sure that the context was set.
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                 (M4OSA_NULL == pContext->mPreviewController),
+                                 "not initialized");
+
+    // Validate the mSurface parameter.
+    videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
+                                                (NULL == mSurface),
+                                                "mSurface is null");
+    jclass surfaceClass = pEnv->FindClass("android/view/Surface");
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                             (M4OSA_NULL == surfaceClass),
+                                             "not initialized");
+
+    jfieldID surface_native =
+            pEnv->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I");
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                             (M4OSA_NULL == surface_native),
+                                             "not initialized");
+
+    Surface* const p = (Surface*)pEnv->GetIntField(mSurface, surface_native);
+    sp<Surface> previewSurface = sp<Surface>(p);
+
+
+    const char *pString = pEnv->GetStringUTFChars(filePath, NULL);
+    if (pString == M4OSA_NULL) {
+        if (pEnv != NULL) {
+            jniThrowException(pEnv, "java/lang/RuntimeException", "Input string null");
+        }
+    }
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+        "videoEditor_renderMediaItemPreviewFrame() timeMs=%d", timeMs);
+    /* get thumbnail*/
+    result = ThumbnailOpen(&tnContext,(const M4OSA_Char*)pString, M4OSA_TRUE);
+    if (result != M4NO_ERROR || tnContext  == M4OSA_NULL) {
+        return timeMs;
+    }
+
+    framesizeYuv = ((frameWidth)*(frameHeight)*1.5);
+
+    pixelArray = (M4VIFI_UInt8 *)M4OSA_malloc(framesizeYuv, M4VS,\
+        (M4OSA_Char*)"videoEditor pixelArray");
+    if (pixelArray == M4OSA_NULL) {
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+            "videoEditor_renderPreviewFrame() malloc error");
+        ThumbnailClose(tnContext);
+        pMessage = videoEditJava_getErrorName(M4ERR_ALLOC);
+        jniThrowException(pEnv, "java/lang/RuntimeException", pMessage);
+        return timeMs;
+    }
+
+    result = ThumbnailGetPixels16(tnContext, (M4OSA_Int16 *)pixelArray,
+                                                frameWidth,
+                                                frameHeight, &timeMs);
+    if (result != M4NO_ERROR) {
+        M4OSA_free((M4OSA_MemAddr32)pixelArray);
+        ThumbnailClose(tnContext);
+        return fromMs;
+    }
+
+#ifdef DUMPTOFILESYSTEM
+    {
+        M4OSA_Context fileContext;
+        M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/FirstRGB565.rgb";
+        M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\
+            M4OSA_kFileWrite|M4OSA_kFileCreate);
+        M4OSA_fileWriteData(fileContext, (M4OSA_MemAddr8) pixelArray,
+                            framesizeRgb);
+        M4OSA_fileWriteClose(fileContext);
+    }
+#endif
+
+    yuvPlane[0].pac_data = (M4VIFI_UInt8*)pixelArray;
+    yuvPlane[0].u_height = frameHeight;
+    yuvPlane[0].u_width = frameWidth;
+    yuvPlane[0].u_stride = yuvPlane[0].u_width;
+    yuvPlane[0].u_topleft = 0;
+
+    yuvPlane[1].u_height = frameHeight/2;
+    yuvPlane[1].u_width = frameWidth/2;
+    yuvPlane[1].u_stride = yuvPlane[1].u_width;
+    yuvPlane[1].u_topleft = 0;
+    yuvPlane[1].pac_data = yuvPlane[0].pac_data
+                + yuvPlane[0].u_width*yuvPlane[0].u_height;
+
+    yuvPlane[2].u_height = frameHeight/2;
+    yuvPlane[2].u_width = frameWidth/2;
+    yuvPlane[2].u_stride = yuvPlane[2].u_width;
+    yuvPlane[2].u_topleft = 0;
+    yuvPlane[2].pac_data = yuvPlane[0].pac_data
+        + yuvPlane[0].u_width*yuvPlane[0].u_height + \
+        (yuvPlane[0].u_width/2)*(yuvPlane[0].u_height/2);
+#ifdef DUMPTOFILESYSTEM
+    {
+        M4OSA_Context fileContext;
+        M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/ConvertedYuv.yuv";
+        M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\
+            M4OSA_kFileWrite|M4OSA_kFileCreate);
+        M4OSA_fileWriteData(fileContext, (M4OSA_MemAddr8) yuvPlane[0].pac_data,
+                            framesizeYuv);
+        M4OSA_fileWriteClose(fileContext);
+    }
+#endif
+
+    /* Fill up the render structure*/
+    frameStr.pBuffer = (M4OSA_Void*)yuvPlane[0].pac_data;
+    frameStr.timeMs = timeMs;    /* timestamp on storyboard*/
+    frameStr.uiSurfaceWidth = frameWidth;
+    frameStr.uiSurfaceHeight = frameHeight;
+    frameStr.uiFrameWidth = frameWidth;
+    frameStr.uiFrameHeight = frameHeight;
+    frameStr.bApplyEffect = M4OSA_FALSE;
+    // clip begin cuttime and end cuttime set to 0
+    // as its only required when effect needs to be applied while rendering
+    frameStr.clipBeginCutTime = 0;
+    frameStr.clipEndCutTime = 0;
+
+    /*  pContext->mPreviewController->setPreviewFrameRenderingMode(M4xVSS_kBlackBorders,
+    (M4VIDEOEDITING_VideoFrameSize)(M4VIDEOEDITING_kHD960+1));*/
+    result
+    = pContext->mPreviewController->renderPreviewFrame(previewSurface,&frameStr);
+    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
+                                                (M4NO_ERROR != result), result);
+
+    /* free the pixelArray and yuvPlane[0].pac_data */
+    M4OSA_free((M4OSA_MemAddr32)yuvPlane[0].pac_data);
+
+    ThumbnailClose(tnContext);
+
+    return timeMs;
+}
+
+int videoEditor_generateAudioRawFile(   JNIEnv*     pEnv,
+                                        jobject     thiz,
+                                        jstring     infilePath,
+                                        jstring     pcmfilePath)
+{
+    M4OSA_ERR result = M4NO_ERROR;
+    bool               loaded   = true;
+    ManualEditContext* pContext = M4OSA_NULL;
+
+
+
+    const char *pInputFile = pEnv->GetStringUTFChars(infilePath, NULL);
+    if (pInputFile == M4OSA_NULL) {
+        if (pEnv != NULL) {
+            jniThrowException(pEnv, "java/lang/RuntimeException", "Input string null");
+        }
+    }
+
+    const char *pStringOutPCMFilePath = pEnv->GetStringUTFChars(pcmfilePath, NULL);
+    if (pStringOutPCMFilePath == M4OSA_NULL) {
+        if (pEnv != NULL) {
+            jniThrowException(pEnv, "java/lang/RuntimeException", "Input string null");
+        }
+    }
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
+        "VIDEO_EDITOR", "videoEditor_generateAudioRawFile infilePath %s",
+        pInputFile);
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
+        "VIDEO_EDITOR", "videoEditor_generateAudioRawFile pcmfilePath %s",
+        pStringOutPCMFilePath);
+    // Get the context.
+    pContext = (ManualEditContext*)videoEditClasses_getContext(&loaded, pEnv, thiz);
+
+    result = videoEditor_generateAudio( pEnv, pContext, (M4OSA_Char*)pInputFile,
+        (M4OSA_Char*)pStringOutPCMFilePath);
+
+    return result;
+}
+
+M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
+                                    M4OSA_Char* infilePath,
+                                    M4OSA_Char* pcmfilePath )
+{
+    bool                            needToBeLoaded = true;
+    M4OSA_ERR                       result = M4NO_ERROR;
+    M4MCS_Context                   mcsContext;
+    M4OSA_Char*                     pInputFile = M4OSA_NULL;
+    M4OSA_Char*                     pOutputFile = M4OSA_NULL;
+    M4OSA_Char*                     pTempPath = M4OSA_NULL;
+    M4MCS_OutputParams*             pOutputParams = M4OSA_NULL;
+    M4MCS_EncodingParams*           pEncodingParams = M4OSA_NULL;
+    M4OSA_Int32                     pInputFileType = 0;
+    M4OSA_UInt8                     threadProgress = 0;
+    M4OSA_Char*                     pTemp3gpFilePath = M4OSA_NULL;
+
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudio()");
+
+    videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
+        (NULL == pContext),
+        "ManualEditContext is null");
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_init()");
+
+    pOutputParams = (M4MCS_OutputParams *)M4OSA_malloc(
+        sizeof(M4MCS_OutputParams),0x00,
+        (M4OSA_Char *)"M4MCS_OutputParams");
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+        (M4OSA_NULL == pOutputParams),
+        "not initialized");
+
+    pEncodingParams = (M4MCS_EncodingParams *)M4OSA_malloc(
+        sizeof(M4MCS_EncodingParams),0x00,
+        (M4OSA_Char *)"M4MCS_EncodingParams");
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+        (M4OSA_NULL == pEncodingParams),
+        "not initialized");
+    // Initialize the MCS library.
+    result = M4MCS_init(&mcsContext, pContext->initParams.pFileReadPtr,
+        pContext->initParams.pFileWritePtr);
+    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,\
+        (M4NO_ERROR != result), result);
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+        (M4OSA_NULL == mcsContext),
+        "not initialized");
+    // generate the path for temp 3gp output file
+    pTemp3gpFilePath = (M4OSA_Char*) M4OSA_malloc (
+        (M4OSA_chrLength((M4OSA_Char*)pContext->initParams.pTempPath)
+        + M4OSA_chrLength ((M4OSA_Char*)TEMP_MCS_OUT_FILE_PATH)) , 0x0,
+        (M4OSA_Char*) "Malloc for temp 3gp file");
+    if ( pTemp3gpFilePath != M4OSA_NULL )
+    {
+        M4OSA_memset(pTemp3gpFilePath  ,
+            M4OSA_chrLength((M4OSA_Char*)pContext->initParams.pTempPath)
+            + M4OSA_chrLength((M4OSA_Char*)TEMP_MCS_OUT_FILE_PATH), 0);
+        M4OSA_chrNCat ( (M4OSA_Char*)pTemp3gpFilePath,
+            (M4OSA_Char*)pContext->initParams.pTempPath  ,
+            M4OSA_chrLength ((M4OSA_Char*)pContext->initParams.pTempPath));
+        M4OSA_chrNCat ( pTemp3gpFilePath , (M4OSA_Char*)TEMP_MCS_OUT_FILE_PATH,
+            M4OSA_chrLength ((M4OSA_Char*)TEMP_MCS_OUT_FILE_PATH));
+    }
+
+    pInputFile = (M4OSA_Char *) infilePath; //pContext->mAudioSettings->pFile;
+    //Delete this file later
+    pOutputFile = (M4OSA_Char *) pTemp3gpFilePath;
+    // Temp folder path for VSS use = ProjectPath
+    pTempPath = (M4OSA_Char *) pContext->initParams.pTempPath;
+    pInputFileType = (M4VIDEOEDITING_FileType)pContext->mAudioSettings->fileType;
+
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "TEMP_MCS_OUT_FILE_PATH len %d",
+        M4OSA_chrLength ((M4OSA_Char*)TEMP_MCS_OUT_FILE_PATH));
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "pTemp3gpFilePath %s",
+        pOutputFile);
+
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_open()");
+
+    result = M4MCS_open(mcsContext, pInputFile,
+        (M4VIDEOEDITING_FileType)pInputFileType,
+        pOutputFile, pTempPath);
+    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
+        (M4NO_ERROR != result), result);
+
+    pOutputParams->OutputFileType
+        = (M4VIDEOEDITING_FileType)M4VIDEOEDITING_kFileType_3GPP;
+    // Set the video format.
+    pOutputParams->OutputVideoFormat =
+        (M4VIDEOEDITING_VideoFormat)M4VIDEOEDITING_kNoneVideo;//M4VIDEOEDITING_kNoneVideo;
+    // Set the frame size.
+    pOutputParams->OutputVideoFrameSize
+        = (M4VIDEOEDITING_VideoFrameSize)M4VIDEOEDITING_kQCIF;
+    // Set the frame rate.
+    pOutputParams->OutputVideoFrameRate
+        = (M4VIDEOEDITING_VideoFramerate)M4VIDEOEDITING_k5_FPS;
+
+    // Set the audio format.
+    pOutputParams->OutputAudioFormat
+        = (M4VIDEOEDITING_AudioFormat)M4VIDEOEDITING_kAAC;
+    // Set the audio sampling frequency.
+    pOutputParams->OutputAudioSamplingFrequency =
+        (M4VIDEOEDITING_AudioSamplingFrequency)M4VIDEOEDITING_k32000_ASF;
+    // Set the audio mono.
+    pOutputParams->bAudioMono = false;
+    // Set the pcm file; null for now.
+    pOutputParams->pOutputPCMfile = (M4OSA_Char *)pcmfilePath;
+    //(M4OSA_Char *)"/sdcard/Output/AudioPcm.pcm";
+    // Set the audio sampling frequency.
+    pOutputParams->MediaRendering = (M4MCS_MediaRendering)M4MCS_kCropping;
+    // new params after integrating MCS 2.0
+    // Set the number of audio effects; 0 for now.
+    pOutputParams->nbEffects = 0;
+    // Set the audio effect; null for now.
+    pOutputParams->pEffects = NULL;
+    // Set the audio effect; null for now.
+    pOutputParams->bDiscardExif = M4OSA_FALSE;
+    // Set the audio effect; null for now.
+    pOutputParams->bAdjustOrientation = M4OSA_FALSE;
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_setOutputParams()");
+    result = M4MCS_setOutputParams(mcsContext, pOutputParams);
+    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
+                                        (M4NO_ERROR != result), result);
+
+    // Set the video bitrate.
+    pEncodingParams->OutputVideoBitrate =
+    (M4VIDEOEDITING_Bitrate)M4VIDEOEDITING_kUndefinedBitrate;
+    // Set the audio bitrate.
+    pEncodingParams->OutputAudioBitrate
+        = (M4VIDEOEDITING_Bitrate)M4VIDEOEDITING_k128_KBPS;
+    // Set the end cut time in milliseconds.
+    pEncodingParams->BeginCutTime = 0;
+    // Set the end cut time in milliseconds.
+    pEncodingParams->EndCutTime = 0;
+    // Set the output file size in bytes.
+    pEncodingParams->OutputFileSize = 0;
+    // Set video time scale.
+    pEncodingParams->OutputVideoTimescale = 0;
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+                            "M4MCS_setEncodingParams()");
+    result = M4MCS_setEncodingParams(mcsContext, pEncodingParams);
+    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
+        (M4NO_ERROR != result), result);
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+                            "M4MCS_checkParamsAndStart()");
+    result = M4MCS_checkParamsAndStart(mcsContext);
+    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
+        (M4NO_ERROR != result), result);
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_step()");
+
+    /*+ PROGRESS CB */
+    M4OSA_UInt8 curProgress = 0;
+    int         lastProgress = 0;
+
+    LOGV("LVME_generateAudio Current progress is =%d", curProgress);
+    pEnv->CallVoidMethod(pContext->engine,
+            pContext->onProgressUpdateMethodId, 1/*task status*/,
+            curProgress/*progress*/);
+    do {
+        result = M4MCS_step(mcsContext, &curProgress);
+
+        if (result != M4NO_ERROR) {
+            LOGV("LVME_generateAudio M4MCS_step returned 0x%x",result);
+
+            if (result == M4MCS_WAR_TRANSCODING_DONE) {
+                LOGV("LVME_generateAudio MCS process ended");
+
+                // Send a progress notification.
+                curProgress = 100;
+                pEnv->CallVoidMethod(pContext->engine,
+                    pContext->onProgressUpdateMethodId, 1/*task status*/,
+                    curProgress);
+                LOGV("LVME_generateAudio Current progress is =%d", curProgress);
+            }
+        } else {
+            // Send a progress notification if needed
+            if (curProgress != lastProgress) {
+                lastProgress = curProgress;
+                pEnv->CallVoidMethod(pContext->engine,
+                    pContext->onProgressUpdateMethodId, 0/*task status*/,
+                    curProgress/*progress*/);
+                LOGV("LVME_generateAudio Current progress is =%d",curProgress);
+            }
+        }
+    } while (result == M4NO_ERROR);
+    /*- PROGRESS CB */
+
+    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
+        (M4MCS_WAR_TRANSCODING_DONE != result), result);
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_abort()");
+    result = M4MCS_abort(mcsContext);
+    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
+        (M4NO_ERROR != result), result);
+
+    //pContext->mAudioSettings->pFile = pOutputParams->pOutputPCMfile;
+    M4OSA_fileExtraDelete((const M4OSA_Char *) pTemp3gpFilePath);
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudio() EXIT ");
+
+    M4OSA_free((M4OSA_MemAddr32)pTemp3gpFilePath);
+    M4OSA_free((M4OSA_MemAddr32)pOutputParams);
+    M4OSA_free((M4OSA_MemAddr32)pEncodingParams);
+    return result;
+}
+
+static int removeAlphafromRGB8888 (
+                        M4OSA_Char* pFramingFilePath,
+                        M4xVSS_FramingStruct *pFramingCtx)
+{
+    M4OSA_UInt32 frameSize_argb = (pFramingCtx->width * pFramingCtx->height * 4); // aRGB data
+    M4OSA_Context lImageFileFp  = M4OSA_NULL;
+    M4OSA_ERR err = M4NO_ERROR;
+
+    LOGV("removeAlphafromRGB8888: width %d", pFramingCtx->width);
+
+    M4OSA_UInt8 *pTmpData = (M4OSA_UInt8*) M4OSA_malloc(frameSize_argb, M4VS, (M4OSA_Char*)"Image argb data");
+    if (pTmpData == M4OSA_NULL) {
+        LOGE("Failed to allocate memory for Image clip");
+        return M4ERR_ALLOC;
+    }
+
+       /** Read the argb data from the passed file. */
+    M4OSA_ERR lerr = M4OSA_fileReadOpen(&lImageFileFp, (M4OSA_Void *) pFramingFilePath, M4OSA_kFileRead);
+
+
+    if ((lerr != M4NO_ERROR) || (lImageFileFp == M4OSA_NULL))
+    {
+        LOGE("removeAlphafromRGB8888: Can not open the file ");
+        M4OSA_free((M4OSA_MemAddr32)pTmpData);
+        return M4ERR_FILE_NOT_FOUND;
+    }
+
+
+    lerr = M4OSA_fileReadData(lImageFileFp, (M4OSA_MemAddr8)pTmpData, &frameSize_argb);
+    if (lerr != M4NO_ERROR)
+    {
+        LOGE("removeAlphafromRGB8888: can not read the data ");
+        M4OSA_fileReadClose(lImageFileFp);
+        M4OSA_free((M4OSA_MemAddr32)pTmpData);
+        return lerr;
+    }
+    M4OSA_fileReadClose(lImageFileFp);
+
+    M4OSA_UInt32 frameSize = (pFramingCtx->width * pFramingCtx->height * 3); //Size of RGB 888 data.
+
+    pFramingCtx->FramingRgb = (M4VIFI_ImagePlane*)M4OSA_malloc(
+             sizeof(M4VIFI_ImagePlane), M4VS, (M4OSA_Char*)"Image clip RGB888 data");
+    pFramingCtx->FramingRgb->pac_data = (M4VIFI_UInt8*)M4OSA_malloc(
+             frameSize, M4VS, (M4OSA_Char*)"Image clip RGB888 data");
+
+    if (pFramingCtx->FramingRgb == M4OSA_NULL)
+    {
+        LOGE("Failed to allocate memory for Image clip");
+        M4OSA_free((M4OSA_MemAddr32)pTmpData);
+        return M4ERR_ALLOC;
+    }
+
+    /** Remove the alpha channel */
+    for (int i = 0, j = 0; i < frameSize_argb; i++) {
+        if ((i % 4) == 0) continue;
+        pFramingCtx->FramingRgb->pac_data[j] = pTmpData[i];
+        j++;
+    }
+    M4OSA_free((M4OSA_MemAddr32)pTmpData);
+    return M4NO_ERROR;
+}
+
+static void
+videoEditor_populateSettings(
+                JNIEnv*                 pEnv,
+                jobject                 thiz,
+                jobject                 settings,
+                jobject                 object,
+                jobject                 audioSettingObject)
+{
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+            "videoEditor_populateSettings()");
+
+    bool                needToBeLoaded  = true;
+    ManualEditContext*  pContext        = M4OSA_NULL;
+    M4OSA_ERR           result          = M4NO_ERROR;
+    jstring             str             = M4OSA_NULL;
+    jobjectArray        propertiesClipsArray           = M4OSA_NULL;
+    jobject             properties      = M4OSA_NULL;
+    jint*               bitmapArray     =  M4OSA_NULL;
+    jobjectArray        effectSettingsArray = M4OSA_NULL;
+    jobject             effectSettings  = M4OSA_NULL;
+    jintArray           pixelArray      = M4OSA_NULL;
+    int width = 0;
+    int height = 0;
+    int nbOverlays = 0;
+    int i,j = 0;
+    int *pOverlayIndex = M4OSA_NULL;
+
+    // Add a code marker (the condition must always be true).
+    ADD_CODE_MARKER_FUN(NULL != pEnv)
+
+    // Validate the settings parameter.
+    videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
+                                                (NULL == settings),
+                                                "settings is null");
+    // Get the context.
+    pContext =
+            (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
+
+    // Make sure that the context was set.
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                             (M4OSA_NULL == pContext),
+                                             "not initialized");
+    // Make sure that the context was set.
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                 (M4OSA_NULL == pContext->mPreviewController),
+                                 "not initialized");
+    jclass mPreviewClipPropClazz = pEnv->FindClass(PREVIEW_PROPERTIES_CLASS_NAME);
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                     (M4OSA_NULL == mPreviewClipPropClazz),
+                                     "not initialized");
+
+    jfieldID fid = pEnv->GetFieldID(mPreviewClipPropClazz,"clipProperties",
+            "[L"PROPERTIES_CLASS_NAME";"  );
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                     (M4OSA_NULL == fid),
+                                     "not initialized");
+
+    propertiesClipsArray = (jobjectArray)pEnv->GetObjectField(object, fid);
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                     (M4OSA_NULL == propertiesClipsArray),
+                                     "not initialized");
+
+    jclass engineClass = pEnv->FindClass(MANUAL_EDIT_ENGINE_CLASS_NAME);
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                     (M4OSA_NULL == engineClass),
+                                     "not initialized");
+
+    pContext->onPreviewProgressUpdateMethodId = pEnv->GetMethodID(engineClass,
+            "onPreviewProgressUpdate",     "(IZ)V");
+    // Check if the context is valid (required because the context is dereferenced).
+    if (needToBeLoaded) {
+        // Make sure that we are in a correct state.
+        videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                             (pContext->state != ManualEditState_INITIALIZED),
+                             "settings already loaded");
+        // Retrieve the edit settings.
+        if (pContext->pEditSettings != M4OSA_NULL) {
+            videoEditClasses_freeEditSettings(&pContext->pEditSettings);
+            pContext->pEditSettings = M4OSA_NULL;
+        }
+        videoEditClasses_getEditSettings(&needToBeLoaded, pEnv,
+            settings, &pContext->pEditSettings,false);
+    }
+    M4OSA_TRACE1_0("videoEditorC_getEditSettings done");
+
+    if ( pContext->pEditSettings != NULL )
+    {
+        // Check if the edit settings could be retrieved.
+        jclass mEditClazz = pEnv->FindClass(EDIT_SETTINGS_CLASS_NAME);
+        if(mEditClazz == M4OSA_NULL)
+        {
+            M4OSA_TRACE1_0("cannot find object field for mEditClazz");
+            return;
+        }
+        jclass mEffectsClazz = pEnv->FindClass(EFFECT_SETTINGS_CLASS_NAME);
+        if(mEffectsClazz == M4OSA_NULL)
+        {
+            M4OSA_TRACE1_0("cannot find object field for mEffectsClazz");
+            return;
+        }
+        fid = pEnv->GetFieldID(mEditClazz,"effectSettingsArray", "[L"EFFECT_SETTINGS_CLASS_NAME";"  );
+        if(fid == M4OSA_NULL)
+        {
+            M4OSA_TRACE1_0("cannot find field for effectSettingsArray Array");
+            return;
+        }
+        effectSettingsArray = (jobjectArray)pEnv->GetObjectField(settings, fid);
+        if(effectSettingsArray == M4OSA_NULL)
+        {
+            M4OSA_TRACE1_0("cannot find object field for effectSettingsArray");
+            return;
+        }
+        i = 0;
+        j = 0;
+        //int overlayIndex[pContext->pEditSettings->nbEffects];
+        if ( pContext->pEditSettings->nbEffects )
+        {
+            pOverlayIndex
+            = (int*) M4OSA_malloc(pContext->pEditSettings->nbEffects, 0,
+                (M4OSA_Char*)"pOverlayIndex");
+        }
+
+        M4OSA_TRACE1_1("no of effects = %d",pContext->pEditSettings->nbEffects);
+        while (j < pContext->pEditSettings->nbEffects)
+        {
+            if (pContext->pEditSettings->Effects[j].xVSS.pFramingFilePath != M4OSA_NULL)
+            {
+                pOverlayIndex[nbOverlays] = j;
+                nbOverlays++;
+                M4xVSS_FramingStruct *aFramingCtx = M4OSA_NULL;
+                aFramingCtx
+                = (M4xVSS_FramingStruct*)M4OSA_malloc(sizeof(M4xVSS_FramingStruct), M4VS,
+                  (M4OSA_Char*)"M4xVSS_internalDecodeGIF: Context of the framing effect");
+                if (aFramingCtx == M4OSA_NULL)
+                {
+                    M4OSA_TRACE1_0("Allocation error in videoEditor_populateSettings");
+                }
+                aFramingCtx->pCurrent = M4OSA_NULL; /* Only used by the first element of the chain */
+                aFramingCtx->previousClipTime = -1;
+                aFramingCtx->FramingYuv = M4OSA_NULL;
+                aFramingCtx->FramingRgb = M4OSA_NULL;
+                aFramingCtx->topleft_x
+                    = pContext->pEditSettings->Effects[j].xVSS.topleft_x;
+                aFramingCtx->topleft_y
+                    = pContext->pEditSettings->Effects[j].xVSS.topleft_y;
+
+
+                 VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "OF u_width %d",
+                                        pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width);
+                 VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "OF u_height() %d",
+                                        pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height);
+                 VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "OF rgbType() %d",
+                                        pContext->pEditSettings->Effects[j].xVSS.rgbType);
+
+                 aFramingCtx->width = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width;
+                 aFramingCtx->height = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height;
+
+
+                result = M4xVSS_internalConvertARGB888toYUV420_FrammingEffect(pContext->engineContext,
+                    &(pContext->pEditSettings->Effects[j]),aFramingCtx,
+                pContext->pEditSettings->Effects[j].xVSS.framingScaledSize);
+                if (result != M4NO_ERROR)
+                {
+                    M4OSA_TRACE1_1("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect returned 0x%x", result);
+                }
+
+                //framing buffers are resized to fit the output video resolution.
+                pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width =
+                    aFramingCtx->FramingRgb->u_width;
+                pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height =
+                    aFramingCtx->FramingRgb->u_height;
+
+
+                VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "A framing Context aFramingCtx->width = %d",
+                    aFramingCtx->FramingRgb->u_width);
+
+                VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "A framing Context aFramingCtx->height = %d",
+                    aFramingCtx->FramingRgb->u_height);
+
+
+                width = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width;
+                height = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height;
+
+                pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_stride = width*3;
+
+                //for RGB888
+                pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_topleft = 0;
+
+                pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->pac_data =
+                                                    (M4VIFI_UInt8 *)M4OSA_malloc(width*height*3,
+                    0x00,(M4OSA_Char *)"pac_data buffer");
+
+                M4OSA_memcpy((M4OSA_Int8 *)&pContext->pEditSettings->\
+                    Effects[j].xVSS.pFramingBuffer->\
+                    pac_data[0],(M4OSA_Int8 *)&aFramingCtx->FramingRgb->pac_data[0],(width*height*3));
+
+                //As of now rgb type is always rgb888, can be changed in future for rgb 565
+                pContext->pEditSettings->Effects[j].xVSS.rgbType =
+                (M4VSS3GPP_RGBType)M4VSS3GPP_kRGB888; //M4VSS3GPP_kRGB565;
+
+                if (aFramingCtx->FramingYuv != M4OSA_NULL )
+                {
+                    if (aFramingCtx->FramingYuv->pac_data != M4OSA_NULL) {
+                        M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingYuv->pac_data);
+                        aFramingCtx->FramingYuv->pac_data = M4OSA_NULL;
+                    }
+                }
+                if (aFramingCtx->FramingYuv != M4OSA_NULL) {
+                    M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingYuv);
+                    aFramingCtx->FramingYuv = M4OSA_NULL;
+                }
+                if (aFramingCtx->FramingRgb->pac_data != M4OSA_NULL) {
+                    M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingRgb->pac_data);
+                    aFramingCtx->FramingRgb->pac_data = M4OSA_NULL;
+                }
+                if (aFramingCtx->FramingRgb != M4OSA_NULL) {
+                    M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingRgb);
+                    aFramingCtx->FramingRgb = M4OSA_NULL;
+                }
+                if (aFramingCtx != M4OSA_NULL) {
+                    M4OSA_free((M4OSA_MemAddr32)aFramingCtx);
+                    aFramingCtx = M4OSA_NULL;
+                }
+            }
+            j++;
+        }
+
+        // Check if the edit settings could be retrieved.
+        M4OSA_TRACE1_1("total clips are = %d",pContext->pEditSettings->uiClipNumber);
+        for (i = 0; i < pContext->pEditSettings->uiClipNumber; i++) {
+            M4OSA_TRACE1_1("clip no = %d",i);
+            properties = pEnv->GetObjectArrayElement(propertiesClipsArray, i);
+            videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                (M4OSA_NULL == properties),
+                "not initialized");
+            getClipSetting(pEnv,properties, pContext->pEditSettings->pClipList[i]);
+        }
+
+        if (needToBeLoaded) {
+            // Log the edit settings.
+            VIDEOEDIT_LOG_EDIT_SETTINGS(pContext->pEditSettings);
+        }
+    }
+
+    if (audioSettingObject != M4OSA_NULL) {
+        jclass audioSettingClazz = pEnv->FindClass(AUDIO_SETTINGS_CLASS_NAME);
+        videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                         (M4OSA_NULL == audioSettingClazz),
+                                         "not initialized");
+
+        videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                     (M4OSA_NULL == pContext->mAudioSettings),
+                                     "not initialized");
+
+        fid = pEnv->GetFieldID(audioSettingClazz,"bRemoveOriginal","Z");
+        pContext->mAudioSettings->bRemoveOriginal = pEnv->GetIntField(audioSettingObject,fid);
+        M4OSA_TRACE1_1("bRemoveOriginal = %d",pContext->mAudioSettings->bRemoveOriginal);
+
+        fid = pEnv->GetFieldID(audioSettingClazz,"channels","I");
+        pContext->mAudioSettings->uiNbChannels = pEnv->GetIntField(audioSettingObject,fid);
+        M4OSA_TRACE1_1("uiNbChannels = %d",pContext->mAudioSettings->uiNbChannels);
+
+        fid = pEnv->GetFieldID(audioSettingClazz,"Fs","I");
+        pContext->mAudioSettings->uiSamplingFrequency = pEnv->GetIntField(audioSettingObject,fid);
+        M4OSA_TRACE1_1("uiSamplingFrequency = %d",pContext->mAudioSettings->uiSamplingFrequency);
+
+        fid = pEnv->GetFieldID(audioSettingClazz,"ExtendedFs","I");
+        pContext->mAudioSettings->uiExtendedSamplingFrequency =
+         pEnv->GetIntField(audioSettingObject,fid);
+        M4OSA_TRACE1_1("uiExtendedSamplingFrequency = %d",
+        pContext->mAudioSettings->uiExtendedSamplingFrequency);
+
+        fid = pEnv->GetFieldID(audioSettingClazz,"startMs","J");
+        pContext->mAudioSettings->uiAddCts
+            = pEnv->GetIntField(audioSettingObject,fid);
+        M4OSA_TRACE1_1("uiAddCts = %d",pContext->mAudioSettings->uiAddCts);
+
+        fid = pEnv->GetFieldID(audioSettingClazz,"volume","I");
+        pContext->mAudioSettings->uiAddVolume
+            = pEnv->GetIntField(audioSettingObject,fid);
+        M4OSA_TRACE1_1("uiAddVolume = %d",pContext->mAudioSettings->uiAddVolume);
+
+        fid = pEnv->GetFieldID(audioSettingClazz,"loop","Z");
+        pContext->mAudioSettings->bLoop
+            = pEnv->GetIntField(audioSettingObject,fid);
+        M4OSA_TRACE1_1("bLoop = %d",pContext->mAudioSettings->bLoop);
+
+        fid = pEnv->GetFieldID(audioSettingClazz,"beginCutTime","J");
+        pContext->mAudioSettings->beginCutMs
+            = pEnv->GetIntField(audioSettingObject,fid);
+        M4OSA_TRACE1_1("begin cut time = %d",pContext->mAudioSettings->beginCutMs);
+
+        fid = pEnv->GetFieldID(audioSettingClazz,"endCutTime","J");
+        pContext->mAudioSettings->endCutMs
+            = pEnv->GetIntField(audioSettingObject,fid);
+        M4OSA_TRACE1_1("end cut time = %d",pContext->mAudioSettings->endCutMs);
+
+        fid = pEnv->GetFieldID(audioSettingClazz,"fileType","I");
+        pContext->mAudioSettings->fileType
+            = pEnv->GetIntField(audioSettingObject,fid);
+        M4OSA_TRACE1_1("fileType = %d",pContext->mAudioSettings->fileType);
+        fid = pEnv->GetFieldID(audioSettingClazz,"pFile","Ljava/lang/String;");
+        str = (jstring)pEnv->GetObjectField(audioSettingObject,fid);
+        pContext->mAudioSettings->pFile
+                = (M4OSA_Char*)pEnv->GetStringUTFChars(str, M4OSA_NULL);
+        M4OSA_TRACE1_1("file name = %s",pContext->mAudioSettings->pFile);
+        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEOEDITOR", "regenerateAudio() file name = %s",\
+        pContext->mAudioSettings->pFile);
+        fid = pEnv->GetFieldID(audioSettingClazz,"pcmFilePath","Ljava/lang/String;");
+        str = (jstring)pEnv->GetObjectField(audioSettingObject,fid);
+        pContext->mAudioSettings->pPCMFilePath =
+        (M4OSA_Char*)pEnv->GetStringUTFChars(str, M4OSA_NULL);
+        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEOEDITOR", "pPCMFilePath -- %s ",\
+        pContext->mAudioSettings->pPCMFilePath);
+        fid = pEnv->GetFieldID(engineClass,"mRegenerateAudio","Z");
+        bool regenerateAudio = pEnv->GetBooleanField(thiz,fid);
+        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEOEDITOR", "regenerateAudio -- %d ",\
+        regenerateAudio);
+        if (regenerateAudio) {
+            M4OSA_TRACE1_0("Calling Generate Audio now");
+            result = videoEditor_generateAudio(pEnv,
+                        pContext,
+                        (M4OSA_Char*)pContext->mAudioSettings->pFile,
+                        (M4OSA_Char*)pContext->mAudioSettings->pPCMFilePath);
+            regenerateAudio = false;
+            pEnv->SetBooleanField(thiz,fid,regenerateAudio);
+        }
+        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEOEDITOR", "regenerateAudio()");
+
+        /* Audio mix and duck */
+        fid = pEnv->GetFieldID(audioSettingClazz,"ducking_threshold","I");
+        pContext->mAudioSettings->uiInDucking_threshold
+            = pEnv->GetIntField(audioSettingObject,fid);
+        M4OSA_TRACE1_1("ducking threshold = %d",
+            pContext->mAudioSettings->uiInDucking_threshold);
+
+        fid = pEnv->GetFieldID(audioSettingClazz,"ducking_lowVolume","I");
+        pContext->mAudioSettings->uiInDucking_lowVolume
+            = pEnv->GetIntField(audioSettingObject,fid);
+        M4OSA_TRACE1_1("ducking lowVolume = %d",
+            pContext->mAudioSettings->uiInDucking_lowVolume);
+
+        fid = pEnv->GetFieldID(audioSettingClazz,"bInDucking_enable","Z");
+        pContext->mAudioSettings->bInDucking_enable
+            = pEnv->GetBooleanField(audioSettingObject,fid);
+        M4OSA_TRACE1_1("ducking lowVolume = %d",
+            pContext->mAudioSettings->bInDucking_enable);
+    } else {
+        if (pContext->mAudioSettings != M4OSA_NULL) {
+            pContext->mAudioSettings->pFile = M4OSA_NULL;
+            pContext->mAudioSettings->bRemoveOriginal = 0;
+            pContext->mAudioSettings->uiNbChannels = 0;
+            pContext->mAudioSettings->uiSamplingFrequency = 0;
+            pContext->mAudioSettings->uiExtendedSamplingFrequency = 0;
+            pContext->mAudioSettings->uiAddCts = 0;
+            pContext->mAudioSettings->uiAddVolume = 0;
+            pContext->mAudioSettings->beginCutMs = 0;
+            pContext->mAudioSettings->endCutMs = 0;
+               pContext->mAudioSettings->fileType = 0;
+            pContext->mAudioSettings->bLoop = 0;
+            pContext->mAudioSettings->uiInDucking_lowVolume  = 0;
+            pContext->mAudioSettings->bInDucking_enable  = 0;
+            pContext->mAudioSettings->uiBTChannelCount  = 0;
+            pContext->mAudioSettings->uiInDucking_threshold = 0;
+
+            fid = pEnv->GetFieldID(engineClass,"mRegenerateAudio","Z");
+            bool regenerateAudio = pEnv->GetBooleanField(thiz,fid);
+            if(!regenerateAudio) {
+                regenerateAudio = true;
+                pEnv->SetBooleanField(thiz,fid,regenerateAudio);
+            }
+        }
+    }
+    if (pContext->pEditSettings != NULL )
+    {
+        result = pContext->mPreviewController->loadEditSettings(pContext->pEditSettings,
+        pContext->mAudioSettings);
+        videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
+                                            (M4NO_ERROR != result), result);
+
+        pContext->mPreviewController->setJniCallback((void*)pContext,
+         (jni_progress_callback_fct)jniPreviewProgressCallback);
+
+        j = 0;
+        while (j < nbOverlays)
+        {
+            if (pContext->pEditSettings->Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data != \
+                M4OSA_NULL) {
+                M4OSA_free((M4OSA_MemAddr32)pContext->pEditSettings->\
+                Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data);
+                pContext->pEditSettings->\
+                Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data = M4OSA_NULL;
+            }
+            if (pContext->pEditSettings->Effects[pOverlayIndex[j]].xVSS.pFramingBuffer != M4OSA_NULL) {
+                M4OSA_free((M4OSA_MemAddr32)pContext->pEditSettings->\
+                Effects[pOverlayIndex[j]].xVSS.pFramingBuffer);
+                pContext->pEditSettings->Effects[pOverlayIndex[j]].xVSS.pFramingBuffer = M4OSA_NULL;
+            }
+            j++;
+        }
+    }
+    if (pOverlayIndex != M4OSA_NULL)
+    {
+        M4OSA_free((M4OSA_MemAddr32)pOverlayIndex);
+        pOverlayIndex = M4OSA_NULL;
+    }
+    return;
+}
+
+static void
+videoEditor_startPreview(
+                JNIEnv*                 pEnv,
+                jobject                 thiz,
+                jobject                 mSurface,
+                jlong                   fromMs,
+                jlong                   toMs,
+                jint                    callbackInterval,
+                jboolean                loop)
+{
+    bool needToBeLoaded = true;
+    M4OSA_ERR result = M4NO_ERROR;
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_startPreview()");
+
+    ManualEditContext* pContext = M4OSA_NULL;
+    // Get the context.
+    pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
+
+    // Make sure that the context was set.
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                             (M4OSA_NULL == pContext),
+                                             "not initialized");
+
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                     (M4OSA_NULL == pContext->mAudioSettings),
+                                     "not initialized");
+    // Make sure that the context was set.
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                 (M4OSA_NULL == pContext->mPreviewController),
+                                 "not initialized");
+
+    // Validate the mSurface parameter.
+    videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
+                                                (NULL == mSurface),
+                                                "mSurface is null");
+
+    jclass surfaceClass = pEnv->FindClass("android/view/Surface");
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                             (M4OSA_NULL == surfaceClass),
+                                             "not initialized");
+    //jfieldID surface_native = pEnv->GetFieldID(surfaceClass, "mSurface", "I");
+    jfieldID surface_native
+        = pEnv->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I");
+
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                             (M4OSA_NULL == surface_native),
+                                             "not initialized");
+
+    Surface* const p = (Surface*)pEnv->GetIntField(mSurface, surface_native);
+
+    sp<Surface> previewSurface = sp<Surface>(p);
+
+    result =  pContext->mPreviewController->setSurface(previewSurface);
+    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
+        (M4NO_ERROR != result), result);
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "fromMs=%ld, toMs=%ld",
+        (M4OSA_UInt32)fromMs, (M4OSA_Int32)toMs);
+
+    result = pContext->mPreviewController->startPreview((M4OSA_UInt32)fromMs,
+                                                (M4OSA_Int32)toMs,
+                                                (M4OSA_UInt16)callbackInterval,
+                                                (M4OSA_Bool)loop);
+    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result);
+}
+
+
+static jobject
+videoEditor_getProperties(
+                JNIEnv*                             pEnv,
+                jobject                             thiz,
+                jstring                             file)
+{
+    jobject object = M4OSA_NULL;
+    object = videoEditProp_getProperties(pEnv,thiz,file);
+
+    return object;
+
+}
+static int videoEditor_getPixels(
+                    JNIEnv*                     env,
+                    jobject                     thiz,
+                    jstring                     path,
+                    jintArray                   pixelArray,
+                    M4OSA_UInt32                width,
+                    M4OSA_UInt32                height,
+                    M4OSA_UInt32                timeMS)
+{
+
+    M4OSA_ERR       err = M4NO_ERROR;
+    M4OSA_Context   mContext = M4OSA_NULL;
+    jint*           m_dst32 = M4OSA_NULL;
+
+
+    // Add a text marker (the condition must always be true).
+    ADD_TEXT_MARKER_FUN(NULL != env)
+
+    const char *pString = env->GetStringUTFChars(path, NULL);
+    if (pString == M4OSA_NULL) {
+        if (env != NULL) {
+            jniThrowException(env, "java/lang/RuntimeException", "Input string null");
+        }
+        return M4ERR_ALLOC;
+    }
+
+    err = ThumbnailOpen(&mContext,(const M4OSA_Char*)pString, M4OSA_FALSE);
+    if (err != M4NO_ERROR || mContext == M4OSA_NULL) {
+        if (pString != NULL) {
+            env->ReleaseStringUTFChars(path, pString);
+        }
+        if (env != NULL) {
+            jniThrowException(env, "java/lang/RuntimeException", "ThumbnailOpen failed");
+        }
+    }
+
+    m_dst32 = env->GetIntArrayElements(pixelArray, NULL);
+
+    err = ThumbnailGetPixels32(mContext, (M4OSA_Int32 *)m_dst32, width,height,&timeMS);
+    if (err != M4NO_ERROR ) {
+        if (env != NULL) {
+            jniThrowException(env, "java/lang/RuntimeException",\
+                "ThumbnailGetPixels32 failed");
+        }
+    }
+    env->ReleaseIntArrayElements(pixelArray, m_dst32, 0);
+
+    ThumbnailClose(mContext);
+    if (pString != NULL) {
+        env->ReleaseStringUTFChars(path, pString);
+    }
+
+    return timeMS;
+}
+
+static int videoEditor_getPixelsList(
+                JNIEnv*                     env,
+                jobject                     thiz,
+                jstring                     path,
+                jintArray                 pixelArray,
+                M4OSA_UInt32             width,
+                M4OSA_UInt32             height,
+                M4OSA_UInt32             deltatimeMS,
+                M4OSA_UInt32            noOfThumbnails,
+                M4OSA_UInt32                startTime,
+                M4OSA_UInt32                endTime)
+{
+
+    M4OSA_ERR           err;
+    M4OSA_Context       mContext = M4OSA_NULL;
+    jint*               m_dst32;
+    M4OSA_UInt32        timeMS = startTime;
+    int                 arrayOffset = 0;
+
+
+
+    // Add a text marker (the condition must always be true).
+    ADD_TEXT_MARKER_FUN(NULL != env)
+
+    const char *pString = env->GetStringUTFChars(path, NULL);
+    if (pString == M4OSA_NULL) {
+        if (env != NULL) {
+            jniThrowException(env, "java/lang/RuntimeException", "Input string null");
+        }
+        return M4ERR_ALLOC;
+    }
+
+    err = ThumbnailOpen(&mContext,(const M4OSA_Char*)pString, M4OSA_FALSE);
+    if (err != M4NO_ERROR || mContext == M4OSA_NULL) {
+        if (env != NULL) {
+            jniThrowException(env, "java/lang/RuntimeException", "ThumbnailOpen failed");
+        }
+        if (pString != NULL) {
+            env->ReleaseStringUTFChars(path, pString);
+        }
+        return err;
+    }
+
+    m_dst32 = env->GetIntArrayElements(pixelArray, NULL);
+
+    do {
+        err = ThumbnailGetPixels32(mContext, ((M4OSA_Int32 *)m_dst32 + arrayOffset),
+            width,height,&timeMS);
+        if (err != M4NO_ERROR ) {
+            if (env != NULL) {
+                jniThrowException(env, "java/lang/RuntimeException",\
+                    "ThumbnailGetPixels32 failed");
+            }
+            return err;
+        }
+        timeMS += deltatimeMS;
+        arrayOffset += (width * height * 4);
+        noOfThumbnails--;
+    } while(noOfThumbnails > 0);
+
+    env->ReleaseIntArrayElements(pixelArray, m_dst32, 0);
+
+    ThumbnailClose(mContext);
+    if (pString != NULL) {
+        env->ReleaseStringUTFChars(path, pString);
+    }
+
+    return err;
+
+}
+
+static M4OSA_ERR
+videoEditor_toUTF8Fct(
+                M4OSA_Void*                         pBufferIn,
+                M4OSA_UInt8*                        pBufferOut,
+                M4OSA_UInt32*                       bufferOutSize)
+{
+    M4OSA_ERR    result = M4NO_ERROR;
+    M4OSA_UInt32 length = 0;
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_toUTF8Fct()");
+
+    // Determine the length of the input buffer.
+    if (M4OSA_NULL != pBufferIn)
+    {
+        length = M4OSA_chrLength((M4OSA_Char *)pBufferIn);
+    }
+
+    // Check if the output buffer is large enough to hold the input buffer.
+    if ((*bufferOutSize) > length)
+    {
+        // Check if the input buffer is not M4OSA_NULL.
+        if (M4OSA_NULL != pBufferIn)
+        {
+            // Copy the temp path, ignore the result.
+            M4OSA_chrNCopy((M4OSA_Char *)pBufferOut, (M4OSA_Char *)pBufferIn, length);
+        }
+        else
+        {
+            // Set the output buffer to an empty string.
+            (*(M4OSA_Char *)pBufferOut) = 0;
+        }
+    }
+    else
+    {
+        // The buffer is too small.
+        result = M4xVSSWAR_BUFFER_OUT_TOO_SMALL;
+    }
+
+    // Return the buffer output size.
+    (*bufferOutSize) = length + 1;
+
+    // Return the result.
+    return(result);
+}
+
+static M4OSA_ERR
+videoEditor_fromUTF8Fct(
+                M4OSA_UInt8*                        pBufferIn,
+                M4OSA_Void*                         pBufferOut,
+                M4OSA_UInt32*                       bufferOutSize)
+{
+    M4OSA_ERR    result = M4NO_ERROR;
+    M4OSA_UInt32 length = 0;
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_fromUTF8Fct()");
+
+    // Determine the length of the input buffer.
+    if (M4OSA_NULL != pBufferIn)
+    {
+        length = M4OSA_chrLength((M4OSA_Char *)pBufferIn);
+    }
+
+    // Check if the output buffer is large enough to hold the input buffer.
+    if ((*bufferOutSize) > length)
+    {
+        // Check if the input buffer is not M4OSA_NULL.
+        if (M4OSA_NULL != pBufferIn)
+        {
+            // Copy the temp path, ignore the result.
+            M4OSA_chrNCopy((M4OSA_Char *)pBufferOut, (M4OSA_Char *)pBufferIn, length);
+        }
+        else
+        {
+            // Set the output buffer to an empty string.
+            (*(M4OSA_Char *)pBufferOut) = 0;
+        }
+    }
+    else
+    {
+        // The buffer is too small.
+        result = M4xVSSWAR_BUFFER_OUT_TOO_SMALL;
+    }
+
+    // Return the buffer output size.
+    (*bufferOutSize) = length + 1;
+
+    // Return the result.
+    return(result);
+}
+
+static M4OSA_ERR
+videoEditor_getTextRgbBufferFct(
+                M4OSA_Void*                         pRenderingData,
+                M4OSA_Void*                         pTextBuffer,
+                M4OSA_UInt32                        textBufferSize,
+                M4VIFI_ImagePlane**                 pOutputPlane)
+{
+    M4OSA_ERR result = M4NO_ERROR;
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_getTextRgbBufferFct()");
+
+    // Return the result.
+    return(result);
+}
+
+static void
+videoEditor_callOnProgressUpdate(
+                ManualEditContext*                  pContext,
+                int                                 task,
+                int                                 progress)
+{
+    JNIEnv* pEnv = NULL;
+
+
+    // Attach the current thread.
+    pContext->pVM->AttachCurrentThread(&pEnv, NULL);
+
+
+    // Call the on completion callback.
+    pEnv->CallVoidMethod(pContext->engine, pContext->onProgressUpdateMethodId,
+     videoEditJava_getEngineCToJava(task), progress);
+
+
+    // Detach the current thread.
+    pContext->pVM->DetachCurrentThread();
+}
+
+static void
+videoEditor_freeContext(
+                JNIEnv*                             pEnv,
+                ManualEditContext**                 ppContext)
+{
+    ManualEditContext* pContext = M4OSA_NULL;
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_freeContext");
+
+    // Set the context pointer.
+    pContext = (*ppContext);
+
+    // Check if the context was set.
+    if (M4OSA_NULL != pContext)
+    {
+        // Check if a global reference to the engine object was set.
+        if (NULL != pContext->engine)
+        {
+            // Free the global reference.
+            pEnv->DeleteGlobalRef(pContext->engine);
+            pContext->engine = NULL;
+        }
+
+        // Check if the temp path was set.
+        if (M4OSA_NULL != pContext->initParams.pTempPath)
+        {
+            // Free the memory allocated for the temp path.
+            videoEditOsal_free(pContext->initParams.pTempPath);
+            pContext->initParams.pTempPath = M4OSA_NULL;
+        }
+
+        // Check if the file writer was set.
+        if (M4OSA_NULL != pContext->initParams.pFileWritePtr)
+        {
+            // Free the memory allocated for the file writer.
+            videoEditOsal_free(pContext->initParams.pFileWritePtr);
+            pContext->initParams.pFileWritePtr = M4OSA_NULL;
+        }
+
+        // Check if the file reader was set.
+        if (M4OSA_NULL != pContext->initParams.pFileReadPtr)
+        {
+            // Free the memory allocated for the file reader.
+            videoEditOsal_free(pContext->initParams.pFileReadPtr);
+            pContext->initParams.pFileReadPtr = M4OSA_NULL;
+        }
+
+        // Free the memory allocated for the context.
+        videoEditOsal_free(pContext);
+        pContext = M4OSA_NULL;
+
+        // Reset the context pointer.
+        (*ppContext) = M4OSA_NULL;
+    }
+}
+
+static jobject
+videoEditor_getVersion(
+                JNIEnv*                             pEnv,
+                jobject                             thiz)
+{
+    bool           isSuccessful          = true;
+    jobject        version         = NULL;
+    M4_VersionInfo versionInfo     = {0, 0, 0, 0};
+    M4OSA_ERR      result          = M4NO_ERROR;
+
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_getVersion()");
+
+    versionInfo.m_structSize = sizeof(versionInfo);
+    versionInfo.m_major = VIDEOEDITOR_VERSION_MAJOR;
+    versionInfo.m_minor = VIDEOEDITOR_VERSION_MINOR;
+    versionInfo.m_revision = VIDEOEDITOR_VERSION_REVISION;
+
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_getVersion() major %d,\
+     minor %d, revision %d", versionInfo.m_major, versionInfo.m_minor, versionInfo.m_revision);
+
+    // Create a version object.
+    videoEditClasses_createVersion(&isSuccessful, pEnv, &versionInfo, &version);
+
+    // Return the version object.
+    return(version);
+}
+
+static void
+videoEditor_init(
+                JNIEnv*                             pEnv,
+                jobject                             thiz,
+                jstring                             tempPath,
+                jstring                             libraryPath)
+{
+    bool                  initialized            = true;
+    ManualEditContext*    pContext               = M4OSA_NULL;
+    VideoEditJava_EngineMethodIds methodIds              = {NULL};
+    M4OSA_Char*           pLibraryPath           = M4OSA_NULL;
+    M4OSA_Char*           pTextRendererPath      = M4OSA_NULL;
+    M4OSA_UInt32          textRendererPathLength = 0;
+    M4OSA_ERR             result                 = M4NO_ERROR;
+
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_init()");
+
+    // Add a text marker (the condition must always be true).
+    ADD_TEXT_MARKER_FUN(NULL != pEnv)
+
+    // Get the context.
+    pContext = (ManualEditContext*)videoEditClasses_getContext(&initialized, pEnv, thiz);
+
+    // Get the engine method ids.
+    videoEditJava_getEngineMethodIds(&initialized, pEnv, &methodIds);
+
+    // Validate the tempPath parameter.
+    videoEditJava_checkAndThrowIllegalArgumentException(&initialized, pEnv,
+                                                (NULL == tempPath),
+                                                "tempPath is null");
+
+    // Make sure that the context was not set already.
+    videoEditJava_checkAndThrowIllegalStateException(&initialized, pEnv,
+                                             (M4OSA_NULL != pContext),
+                                             "already initialized");
+
+    // Check if the initialization succeeded (required because of dereferencing of psContext,
+    // and freeing when initialization fails).
+    if (initialized)
+    {
+        // Allocate a new context.
+        pContext = new ManualEditContext;
+
+        // Check if the initialization succeeded (required because of dereferencing of psContext).
+        //if (initialized)
+        if (pContext != NULL)
+        {
+            // Set the state to not initialized.
+            pContext->state = ManualEditState_NOT_INITIALIZED;
+
+            // Allocate a file read pointer structure.
+            pContext->initParams.pFileReadPtr =
+             (M4OSA_FileReadPointer*)videoEditOsal_alloc(&initialized, pEnv,
+              sizeof(M4OSA_FileReadPointer), "FileReadPointer");
+
+            // Allocate a file write pointer structure.
+            pContext->initParams.pFileWritePtr =
+             (M4OSA_FileWriterPointer*)videoEditOsal_alloc(&initialized, pEnv,
+              sizeof(M4OSA_FileWriterPointer), "FileWriterPointer");
+
+            // Get the temp path.
+            M4OSA_Char* tmpString =
+                (M4OSA_Char *)videoEditJava_getString(&initialized, pEnv, tempPath,
+                NULL, M4OSA_NULL);
+            pContext->initParams.pTempPath = (M4OSA_Char *)
+                 M4OSA_malloc(M4OSA_chrLength(tmpString) + 1, 0x0,
+                                                 (M4OSA_Char *)"tempPath");
+            //initialize the first char. so that strcat works.
+            M4OSA_Char *ptmpChar = (M4OSA_Char*)pContext->initParams.pTempPath;
+            ptmpChar[0] = 0x00;
+            M4OSA_chrNCat((M4OSA_Char*)pContext->initParams.pTempPath, tmpString, M4OSA_chrLength(tmpString));
+            M4OSA_chrNCat((M4OSA_Char*)pContext->initParams.pTempPath, (M4OSA_Char*)"/", 1);
+            M4OSA_free((M4OSA_MemAddr32)tmpString);
+        }
+
+        // Check if the initialization succeeded
+        // (required because of dereferencing of pContext, pFileReadPtr and pFileWritePtr).
+        if (initialized)
+        {
+
+            // Initialize the OSAL file system function pointers.
+            videoEditOsal_getFilePointers(pContext->initParams.pFileReadPtr ,
+                                          pContext->initParams.pFileWritePtr);
+
+            // Set the UTF8 conversion functions.
+            pContext->initParams.pConvToUTF8Fct   = videoEditor_toUTF8Fct;
+            pContext->initParams.pConvFromUTF8Fct = videoEditor_fromUTF8Fct;
+
+            // Set the callback method ids.
+            pContext->onProgressUpdateMethodId = methodIds.onProgressUpdate;
+
+            // Set the virtual machine.
+            pEnv->GetJavaVM(&(pContext->pVM));
+
+            // Create a global reference to the engine object.
+            pContext->engine = pEnv->NewGlobalRef(thiz);
+
+            // Check if the global reference could be created.
+            videoEditJava_checkAndThrowRuntimeException(&initialized, pEnv,
+             (NULL == pContext->engine), M4NO_ERROR);
+        }
+
+        // Check if the initialization succeeded (required because of dereferencing of pContext).
+        if (initialized)
+        {
+            // Log the API call.
+            VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4xVSS_Init()");
+
+            // Initialize the visual studio library.
+            result = M4xVSS_Init(&pContext->engineContext, &pContext->initParams);
+
+            // Log the result.
+            VIDEOEDIT_LOG_RESULT(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+             videoEditOsal_getResultString(result));
+
+            // Check if the library could be initialized.
+            videoEditJava_checkAndThrowRuntimeException(&initialized, pEnv,
+             (M4NO_ERROR != result), result);
+        }
+
+        if(initialized)
+        {
+            pContext->mPreviewController = new VideoEditorPreviewController();
+            videoEditJava_checkAndThrowIllegalStateException(&initialized, pEnv,
+                                 (M4OSA_NULL == pContext->mPreviewController),
+                                 "not initialized");
+            pContext->mAudioSettings =
+             (M4xVSS_AudioMixingSettings *)
+             M4OSA_malloc(sizeof(M4xVSS_AudioMixingSettings),0x0,
+             (M4OSA_Char *)"mAudioSettings");
+            videoEditJava_checkAndThrowIllegalStateException(&initialized, pEnv,
+                                     (M4OSA_NULL == pContext->mAudioSettings),
+                                     "not initialized");
+            pContext->mAudioSettings->pFile = M4OSA_NULL;
+            pContext->mAudioSettings->bRemoveOriginal = 0;
+            pContext->mAudioSettings->uiNbChannels = 0;
+            pContext->mAudioSettings->uiSamplingFrequency = 0;
+            pContext->mAudioSettings->uiExtendedSamplingFrequency = 0;
+            pContext->mAudioSettings->uiAddCts = 0;
+            pContext->mAudioSettings->uiAddVolume = 0;
+            pContext->mAudioSettings->beginCutMs = 0;
+            pContext->mAudioSettings->endCutMs = 0;
+            pContext->mAudioSettings->fileType = 0;
+            pContext->mAudioSettings->bLoop = 0;
+            pContext->mAudioSettings->uiInDucking_lowVolume  = 0;
+            pContext->mAudioSettings->bInDucking_enable  = 0;
+            pContext->mAudioSettings->uiBTChannelCount  = 0;
+            pContext->mAudioSettings->uiInDucking_threshold = 0;
+        }
+        // Check if the library could be initialized.
+        if (initialized)
+        {
+            // Set the state to initialized.
+            pContext->state = ManualEditState_INITIALIZED;
+        }
+
+        // Set the context.
+        videoEditClasses_setContext(&initialized, pEnv, thiz, (void* )pContext);
+        pLibraryPath = M4OSA_NULL;
+
+        pContext->pEditSettings = M4OSA_NULL;
+        // Cleanup if anything went wrong during initialization.
+        if (!initialized)
+        {
+            // Free the context.
+            videoEditor_freeContext(pEnv, &pContext);
+        }
+    }
+}
+
+/*+ PROGRESS CB */
+static
+M4OSA_ERR videoEditor_processClip(
+                            JNIEnv*  pEnv,
+                            jobject  thiz,
+                            int      unuseditemID) {
+
+    bool               loaded           = true;
+    ManualEditContext* pContext         = NULL;
+    M4OSA_UInt8        progress         = 0;
+    M4OSA_UInt8        progressBase     = 0;
+    M4OSA_UInt8        lastProgress     = 0;
+    M4OSA_ERR          result           = M4NO_ERROR;
+
+    // Get the context.
+    pContext = (ManualEditContext*)videoEditClasses_getContext(&loaded, pEnv, thiz);
+
+    // Make sure that the context was set.
+    videoEditJava_checkAndThrowIllegalStateException(&loaded, pEnv,
+                                             (M4OSA_NULL == pContext),
+                                             "not initialized");
+
+    // We start in Analyzing state
+    pContext->state = ManualEditState_ANALYZING;
+    M4OSA_ERR          completionResult = M4VSS3GPP_WAR_ANALYZING_DONE;
+    ManualEditState    completionState  = ManualEditState_OPENED;
+    ManualEditState    errorState       = ManualEditState_ANALYZING_ERROR;
+
+    // While analyzing progress goes from 0 to 50
+    progressBase     = 0;
+
+    // Set the text rendering function.
+    if (M4OSA_NULL != pContext->pTextRendererFunction)
+    {
+        // Use the text renderer function in the library.
+        pContext->pEditSettings->xVSS.pTextRenderingFct = pContext->pTextRendererFunction;
+    }
+    else
+    {
+        // Use the internal text renderer function.
+        pContext->pEditSettings->xVSS.pTextRenderingFct = videoEditor_getTextRgbBufferFct;
+    }
+
+    // Send the command.
+    LOGV("videoEditor_processClip ITEM %d Calling M4xVSS_SendCommand()", unuseditemID);
+    result = M4xVSS_SendCommand(pContext->engineContext, pContext->pEditSettings);
+    LOGV("videoEditor_processClip ITEM %d M4xVSS_SendCommand() returned 0x%x",
+        unuseditemID, (unsigned int) result);
+
+    // Remove warnings indications (we only care about errors here)
+    if ((result == M4VSS3GPP_WAR_TRANSCODING_NECESSARY)
+        || (result == M4VSS3GPP_WAR_OUTPUTFILESIZE_EXCEED)) {
+        result = M4NO_ERROR;
+    }
+
+    // Send the first progress indication (=0)
+    LOGV("VERY FIRST PROGRESS videoEditor_processClip ITEM %d Progress indication %d",
+        unuseditemID, progress);
+    pEnv->CallVoidMethod(pContext->engine, pContext->onProgressUpdateMethodId,
+        unuseditemID, progress);
+
+    // Check if a task is being performed.
+    // ??? ADD STOPPING MECHANISM
+    LOGV("videoEditor_processClip Entering processing loop");
+    while((result == M4NO_ERROR)
+        &&(pContext->state!=ManualEditState_SAVED)
+        &&(pContext->state!=ManualEditState_STOPPING)) {
+
+            // Perform the next processing step.
+            //LOGV("LVME_processClip Entering M4xVSS_Step()");
+            result = M4xVSS_Step(pContext->engineContext, &progress);
+            //LOGV("LVME_processClip M4xVSS_Step() returned 0x%x", (unsigned int)result);
+
+            // Log the the 1 % .. 100 % progress after processing.
+            progress = progressBase + progress/2;
+            if (progress != lastProgress)
+            {
+                // Send a progress notification.
+                LOGV("videoEditor_processClip ITEM %d Progress indication %d",
+                    unuseditemID, progress);
+                pEnv->CallVoidMethod(pContext->engine,
+                    pContext->onProgressUpdateMethodId,
+                    unuseditemID, progress);
+                lastProgress = progress;
+            }
+
+            // Check if processing has been completed.
+            if (result == completionResult)
+            {
+                // Set the state to the completions state.
+                pContext->state = completionState;
+                LOGV("videoEditor_processClip ITEM %d STATE changed to %d",
+                    unuseditemID, pContext->state);
+
+                // Reset progress indication, as we switch to next state
+                lastProgress = 0;
+
+                // Reset error code, as we start a new round of processing
+                result = M4NO_ERROR;
+
+                // Check if we are analyzing input
+                if (pContext->state == ManualEditState_OPENED) {
+                    // File is opened, we must start saving it
+                    LOGV("videoEditor_processClip Calling M4xVSS_SaveStart()");
+                    result = M4xVSS_SaveStart(pContext->engineContext,
+                        (M4OSA_Char*)pContext->pEditSettings->pOutputFile,
+                        (M4OSA_UInt32)pContext->pEditSettings->uiOutputPathSize);
+                    LOGV("videoEditor_processClip ITEM %d SaveStart() returned 0x%x",
+                        unuseditemID, (unsigned int) result);
+
+                    // Set the state to saving.
+                    pContext->state  = ManualEditState_SAVING;
+                    completionState  = ManualEditState_SAVED;
+                    completionResult = M4VSS3GPP_WAR_SAVING_DONE;
+                    errorState       = ManualEditState_SAVING_ERROR;
+
+                    // While saving progress goes from 50 to 100
+                    progressBase     = 50;
+                }
+                // Check if we encoding is ongoing
+                else if (pContext->state == ManualEditState_SAVED) {
+                    if (progress != 100) {
+                        // Send a progress notification.
+                        progress = 100;
+                        LOGI("videoEditor_processClip ITEM %d Last progress indication %d",
+                            unuseditemID, progress);
+                        pEnv->CallVoidMethod(pContext->engine,
+                            pContext->onProgressUpdateMethodId,
+                            unuseditemID, progress);
+                    }
+
+                    // Stop the encoding.
+                    LOGV("videoEditor_processClip Calling M4xVSS_SaveStop()");
+                    result = M4xVSS_SaveStop(pContext->engineContext);
+                    LOGV("videoEditor_processClip M4xVSS_SaveStop() returned 0x%x", result);
+                }
+                // Other states are unexpected
+                else {
+                    result = M4ERR_STATE;
+                    LOGE("videoEditor_processClip ITEM %d State ERROR 0x%x",
+                        unuseditemID, (unsigned int) result);
+                }
+            }
+
+            // Check if an error occurred.
+            if (result != M4NO_ERROR)
+            {
+                // Set the state to the error state.
+                pContext->state = errorState;
+
+                // Log the result.
+                LOGE("videoEditor_processClip ITEM %d Processing ERROR 0x%x",
+                    unuseditemID, (unsigned int) result);
+            }
+    }
+
+    // Return the error result
+    LOGE("videoEditor_processClip ITEM %d END 0x%x", unuseditemID, (unsigned int) result);
+    return result;
+}
+/*+ PROGRESS CB */
+
+static int
+videoEditor_generateClip(
+                JNIEnv*                             pEnv,
+                jobject                             thiz,
+                jobject                             settings) {
+    bool               loaded   = true;
+    ManualEditContext* pContext = M4OSA_NULL;
+    M4OSA_ERR          result   = M4NO_ERROR;
+
+    LOGV("videoEditor_generateClip START");
+
+    // Get the context.
+    pContext = (ManualEditContext*)videoEditClasses_getContext(&loaded, pEnv, thiz);
+
+    Mutex::Autolock autoLock(pContext->mLock);
+
+    // Validate the settings parameter.
+    videoEditJava_checkAndThrowIllegalArgumentException(&loaded, pEnv,
+                                                (NULL == settings),
+                                                "settings is null");
+
+    // Make sure that the context was set.
+    videoEditJava_checkAndThrowIllegalStateException(&loaded, pEnv,
+                                             (M4OSA_NULL == pContext),
+                                             "not initialized");
+
+    // Load the clip settings
+    LOGV("videoEditor_generateClip Calling videoEditor_loadSettings");
+    videoEditor_loadSettings(pEnv, thiz, settings);
+    LOGV("videoEditor_generateClip videoEditor_loadSettings returned");
+
+    // Generate the clip
+    LOGV("videoEditor_generateClip Calling LVME_processClip");
+    result = videoEditor_processClip(pEnv, thiz, 0 /*item id is unused*/);
+    LOGV("videoEditor_generateClip videoEditor_processClip returned 0x%x", result);
+
+    // Free up memory (whatever the result)
+    videoEditor_unloadSettings(pEnv, thiz);
+    //LVME_release(pEnv, thiz);
+
+    LOGV("videoEditor_generateClip END 0x%x", (unsigned int) result);
+    return result;
+}
+
+static void
+videoEditor_loadSettings(
+                JNIEnv*                             pEnv,
+                jobject                             thiz,
+                jobject                             settings)
+{
+    bool               needToBeLoaded   = true;
+    ManualEditContext* pContext = M4OSA_NULL;
+
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_loadSettings()");
+
+    // Add a code marker (the condition must always be true).
+    ADD_CODE_MARKER_FUN(NULL != pEnv)
+
+    // Get the context.
+    pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded,
+                                                                pEnv, thiz);
+
+    // Validate the settings parameter.
+    videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
+                                                (NULL == settings),
+                                                "settings is null");
+
+    // Make sure that the context was set.
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                             (M4OSA_NULL == pContext),
+                                             "not initialized");
+
+    // Check if the context is valid (required because the context is dereferenced).
+    if (needToBeLoaded)
+    {
+        // Make sure that we are in a correct state.
+        videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                             (pContext->state != ManualEditState_INITIALIZED),
+                             "settings already loaded");
+
+        // Retrieve the edit settings.
+        if(pContext->pEditSettings != M4OSA_NULL) {
+            videoEditClasses_freeEditSettings(&pContext->pEditSettings);
+            pContext->pEditSettings = M4OSA_NULL;
+        }
+        videoEditClasses_getEditSettings(&needToBeLoaded, pEnv, settings,
+            &pContext->pEditSettings,true);
+    }
+
+    // Check if the edit settings could be retrieved.
+    if (needToBeLoaded)
+    {
+        // Log the edit settings.
+        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "inside load settings");
+        VIDEOEDIT_LOG_EDIT_SETTINGS(pContext->pEditSettings);
+    }
+    LOGV("videoEditor_loadSettings END");
+}
+
+
+
+static void
+videoEditor_unloadSettings(
+                JNIEnv*                             pEnv,
+                jobject                             thiz)
+{
+    bool               needToBeUnLoaded = true;
+    ManualEditContext* pContext = M4OSA_NULL;
+    M4OSA_ERR          result   = M4NO_ERROR;
+
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_unloadSettings()");
+
+    // Get the context.
+    pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeUnLoaded, pEnv, thiz);
+
+    // Make sure that the context was set.
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeUnLoaded, pEnv,
+                                             (M4OSA_NULL == pContext),
+                                             "not initialized");
+
+    // Check if the context is valid (required because the context is dereferenced).
+    if (needToBeUnLoaded)
+    {
+        LOGV("videoEditor_unloadSettings state %d", pContext->state);
+        // Make sure that we are in a correct state.
+        videoEditJava_checkAndThrowIllegalStateException(&needToBeUnLoaded, pEnv,
+                     ((pContext->state != ManualEditState_ANALYZING      ) &&
+                      (pContext->state != ManualEditState_ANALYZING_ERROR) &&
+                      (pContext->state != ManualEditState_OPENED         ) &&
+                      (pContext->state != ManualEditState_SAVING_ERROR   ) &&
+                      (pContext->state != ManualEditState_SAVED          ) &&
+                      (pContext->state != ManualEditState_STOPPING       ) ),
+                     "videoEditor_unloadSettings no load settings in progress");
+    }
+
+    // Check if we are in a correct state.
+    if (needToBeUnLoaded)
+    {
+        // Check if the thread could be stopped.
+        if (needToBeUnLoaded)
+        {
+            // Close the command.
+            LOGV("videoEditor_unloadSettings Calling M4xVSS_CloseCommand()");
+            result = M4xVSS_CloseCommand(pContext->engineContext);
+            LOGV("videoEditor_unloadSettings M4xVSS_CloseCommand() returned 0x%x",
+                (unsigned int)result);
+
+            // Check if the command could be closed.
+            videoEditJava_checkAndThrowRuntimeException(&needToBeUnLoaded, pEnv,
+             (M4NO_ERROR != result), result);
+        }
+
+        // Check if the command could be closed.
+        if (needToBeUnLoaded)
+        {
+            // Free the edit settings.
+            //videoEditClasses_freeEditSettings(&pContext->pEditSettings);
+
+            // Reset the thread result.
+            pContext->threadResult = M4NO_ERROR;
+
+            // Reset the thread progress.
+            pContext->threadProgress = 0;
+
+            // Set the state to initialized.
+            pContext->state = ManualEditState_INITIALIZED;
+        }
+    }
+}
+
+static void
+videoEditor_stopEncoding(
+                JNIEnv*                             pEnv,
+                jobject                             thiz)
+{
+    bool               stopped  = true;
+    ManualEditContext* pContext = M4OSA_NULL;
+    M4OSA_ERR          result   = M4NO_ERROR;
+
+    LOGV("videoEditor_stopEncoding START");
+
+    // Get the context.
+    pContext = (ManualEditContext*)videoEditClasses_getContext(&stopped, pEnv, thiz);
+
+    // Change state and get Lock
+    // This will ensure the generateClip function exits
+    pContext->state = ManualEditState_STOPPING;
+    Mutex::Autolock autoLock(pContext->mLock);
+
+    // Make sure that the context was set.
+    videoEditJava_checkAndThrowIllegalStateException(&stopped, pEnv,
+                                             (M4OSA_NULL == pContext),
+                                             "not initialized");
+
+    if (stopped) {
+
+        // Check if the command should be closed.
+        if (pContext->state != ManualEditState_INITIALIZED)
+        {
+            // Close the command.
+            LOGV("videoEditor_stopEncoding Calling M4xVSS_CloseCommand()");
+            result = M4xVSS_CloseCommand(pContext->engineContext);
+            LOGV("videoEditor_stopEncoding M4xVSS_CloseCommand() returned 0x%x",
+                (unsigned int)result);
+        }
+
+        // Check if the command could be closed.
+        videoEditJava_checkAndThrowRuntimeException(&stopped, pEnv,
+            (M4NO_ERROR != result), result);
+
+        // Free the edit settings.
+        videoEditClasses_freeEditSettings(&pContext->pEditSettings);
+
+        // Set the state to initialized.
+        pContext->state = ManualEditState_INITIALIZED;
+    }
+
+}
+
+static void
+videoEditor_release(
+                JNIEnv*                             pEnv,
+                jobject                             thiz)
+{
+    bool               released = true;
+    ManualEditContext* pContext = M4OSA_NULL;
+    M4OSA_ERR          result   = M4NO_ERROR;
+
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_release()");
+
+    // Add a text marker (the condition must always be true).
+    ADD_TEXT_MARKER_FUN(NULL != pEnv)
+
+    // Get the context.
+    pContext = (ManualEditContext*)videoEditClasses_getContext(&released, pEnv, thiz);
+
+    // If context is not set, return (we consider release already happened)
+    if (pContext == NULL) {
+        LOGV("videoEditor_release Nothing to do, context is aleady NULL");
+        return;
+    }
+
+
+    // Check if the context is valid (required because the context is dereferenced).
+    if (released)
+    {
+        if (pContext->state != ManualEditState_INITIALIZED)
+        {
+            // Change state and get Lock
+            // This will ensure the generateClip function exits if it is running
+            pContext->state = ManualEditState_STOPPING;
+            Mutex::Autolock autoLock(pContext->mLock);
+        }
+
+        // Reset the context.
+        videoEditClasses_setContext(&released, pEnv, thiz, (void *)M4OSA_NULL);
+
+        // Check if the command should be closed.
+        if (pContext->state != ManualEditState_INITIALIZED)
+        {
+            // Close the command.
+            LOGV("videoEditor_release Calling M4xVSS_CloseCommand() state =%d",
+                pContext->state);
+            result = M4xVSS_CloseCommand(pContext->engineContext);
+            LOGV("videoEditor_release M4xVSS_CloseCommand() returned 0x%x",
+                (unsigned int)result);
+
+            // Check if the command could be closed.
+            videoEditJava_checkAndThrowRuntimeException(&released, pEnv,
+                (M4NO_ERROR != result), result);
+        }
+
+        // Cleanup the engine.
+        LOGV("videoEditor_release Calling M4xVSS_CleanUp()");
+        result = M4xVSS_CleanUp(pContext->engineContext);
+        LOGV("videoEditor_release M4xVSS_CleanUp() returned 0x%x", (unsigned int)result);
+
+        // Check if the cleanup succeeded.
+        videoEditJava_checkAndThrowRuntimeException(&released, pEnv,
+            (M4NO_ERROR != result), result);
+
+        // Free the edit settings.
+        videoEditClasses_freeEditSettings(&pContext->pEditSettings);
+        pContext->pEditSettings = M4OSA_NULL;
+
+
+        if(pContext->mPreviewController != M4OSA_NULL)
+        {
+            delete pContext->mPreviewController;
+            pContext->mPreviewController = M4OSA_NULL;
+        }
+
+        // Free the context.
+        if(pContext->mAudioSettings != M4OSA_NULL)
+        {
+            M4OSA_free((M4OSA_MemAddr32)pContext->mAudioSettings);
+            pContext->mAudioSettings = M4OSA_NULL;
+        }
+        videoEditor_freeContext(pEnv, &pContext);
+    }
+}
+
+static int
+videoEditor_registerManualEditMethods(
+                JNIEnv*                             pEnv)
+{
+    int result = -1;
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+     "videoEditor_registerManualEditMethods()");
+
+    // Look up the engine class
+    jclass engineClazz = pEnv->FindClass(MANUAL_EDIT_ENGINE_CLASS_NAME);
+
+    // Clear any resulting exceptions.
+    pEnv->ExceptionClear();
+
+    // Check if the engine class was found.
+    if (NULL != engineClazz)
+    {
+        // Register all the methods.
+        if (pEnv->RegisterNatives(engineClazz, gManualEditMethods,
+                sizeof(gManualEditMethods) / sizeof(gManualEditMethods[0])) == JNI_OK)
+        {
+            // Success.
+            result = 0;
+        }
+    }
+
+    // Return the result.
+    return(result);
+}
+
+/*******Audio Graph*******/
+
+static M4OSA_UInt32 getDecibelSound(M4OSA_UInt32 value)
+{
+    int dbSound = 1;
+
+    if (value == 0) return 0;
+
+    if (value > 0x4000 && value <= 0x8000) // 32768
+        dbSound = 90;
+    else if (value > 0x2000 && value <= 0x4000) // 16384
+        dbSound = 84;
+    else if (value > 0x1000 && value <= 0x2000) // 8192
+        dbSound = 78;
+    else if (value > 0x0800 && value <= 0x1000) // 4028
+        dbSound = 72;
+    else if (value > 0x0400 && value <= 0x0800) // 2048
+        dbSound = 66;
+    else if (value > 0x0200 && value <= 0x0400) // 1024
+        dbSound = 60;
+    else if (value > 0x0100 && value <= 0x0200) // 512
+        dbSound = 54;
+    else if (value > 0x0080 && value <= 0x0100) // 256
+        dbSound = 48;
+    else if (value > 0x0040 && value <= 0x0080) // 128
+        dbSound = 42;
+    else if (value > 0x0020 && value <= 0x0040) // 64
+        dbSound = 36;
+    else if (value > 0x0010 && value <= 0x0020) // 32
+        dbSound = 30;
+    else if (value > 0x0008 && value <= 0x0010) //16
+        dbSound = 24;
+    else if (value > 0x0007 && value <= 0x0008) //8
+        dbSound = 24;
+    else if (value > 0x0003 && value <= 0x0007) // 4
+        dbSound = 18;
+    else if (value > 0x0001 && value <= 0x0003) //2
+        dbSound = 12;
+    else if (value > 0x000 && value == 0x0001) // 1
+        dbSound = 6;
+    else
+        dbSound = 0;
+
+    return dbSound;
+}
+
+typedef struct
+{
+    M4OSA_UInt8      *m_dataAddress;
+    M4OSA_UInt32    m_bufferSize;
+} M4AM_Buffer;
+
+
+M4OSA_UInt8 logLookUp[256]{
+0,120,137,146,154,159,163,167,171,173,176,178,181,182,184,186,188,189,190,192,193,
+194,195,196,198,199,199,200,201,202,203,204,205,205,206,207,207,208,209,209,210,
+211,211,212,212,213,213,214,215,215,216,216,216,217,217,218,218,219,219,220,220,
+220,221,221,222,222,222,223,223,223,224,224,224,225,225,225,226,226,226,227,227,
+227,228,228,228,229,229,229,229,230,230,230,230,231,231,231,232,232,232,232,233,
+233,233,233,233,234,234,234,234,235,235,235,235,236,236,236,236,236,237,237,237,
+237,237,238,238,238,238,238,239,239,239,239,239,240,240,240,240,240,240,241,241,
+241,241,241,241,242,242,242,242,242,242,243,243,243,243,243,243,244,244,244,244,
+244,244,245,245,245,245,245,245,245,246,246,246,246,246,246,246,247,247,247,247,
+247,247,247,247,248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,250,
+250,250,250,250,250,250,250,250,251,251,251,251,251,251,251,251,252,252,252,252,
+252,252,252,252,252,253,253,253,253,253,253,253,253,253,253,254,254,254,254,254,
+254,254,254,254,255,255,255,255,255,255,255,255,255,255,255};
+
+M4OSA_ERR M4MA_generateAudioGraphFile(JNIEnv* pEnv, M4OSA_Char* pInputFileURL,
+                     M4OSA_Char* pOutFileURL,
+                     M4OSA_UInt32 samplesPerValue,
+                     M4OSA_UInt32 channels,
+                     M4OSA_UInt32 frameDuration,
+                     ManualEditContext* pContext)
+{
+    M4OSA_ERR           err;
+    M4OSA_Context       outFileHandle = M4OSA_NULL;
+    M4OSA_Context       inputFileHandle = M4OSA_NULL;
+    M4AM_Buffer         bufferIn = {0, 0};
+    M4OSA_UInt32        peakVolumeDbValue = 0;
+    M4OSA_UInt32        samplesCountInBytes= 0 , numBytesToRead = 0, index = 0;
+    M4OSA_UInt32        writeCount = 0, samplesCountBigEndian = 0, volumeValuesCount = 0;
+    M4OSA_Int32         seekPos = 0;
+    M4OSA_UInt32        fileSize = 0;
+    M4OSA_UInt32        totalBytesRead = 0;
+    M4OSA_UInt32        prevProgress = 0;
+    bool                threadStarted = true;
+
+    int dbValue = 0;
+    M4OSA_Int16 *ptr16 ;
+
+    jclass engineClass = pEnv->FindClass(MANUAL_EDIT_ENGINE_CLASS_NAME);
+    videoEditJava_checkAndThrowIllegalStateException(&threadStarted, pEnv,
+                                             (M4OSA_NULL == engineClass),
+                                             "not initialized");
+
+    /* register the call back function pointer */
+    pContext->onAudioGraphProgressUpdateMethodId =
+            pEnv->GetMethodID(engineClass, "onAudioGraphExtractProgressUpdate", "(IZ)V");
+
+
+    /* ENTER */
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "ENTER - M4MA_generateAudioGraphFile");
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+            "Audio Graph samplesPerValue %d channels %d", samplesPerValue, channels);
+
+    /******************************************************************************
+        OPEN INPUT AND OUTPUT FILES
+    *******************************************************************************/
+    err = M4OSA_fileReadOpen (&inputFileHandle, pInputFileURL, M4OSA_kFileRead);
+    if (inputFileHandle == M4OSA_NULL) {
+        VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+            "M4MA_generateAudioGraphFile: Cannot open input file 0x%x", err);
+        return err;
+    }
+
+    /* get the file size for progress */
+    err = M4OSA_fileReadGetOption(inputFileHandle, M4OSA_kFileReadGetFileSize,
+                                (M4OSA_Void**)&fileSize);
+    if ( err != M4NO_ERROR) {
+        //LVMEL_LOG_ERROR("M4MA_generateAudioGraphFile : File write failed \n");
+        jniThrowException(pEnv, "java/lang/IOException", "file size get option failed");
+        //return -1;
+    }
+
+    err = M4OSA_fileWriteOpen (&outFileHandle,(M4OSA_Char*) pOutFileURL,
+        M4OSA_kFileCreate | M4OSA_kFileWrite);
+    if (outFileHandle == M4OSA_NULL) {
+        if (inputFileHandle != NULL)
+        {
+            M4OSA_fileReadClose(inputFileHandle);
+        }
+        return err;
+    }
+
+    /******************************************************************************
+        PROCESS THE SAMPLES
+    *******************************************************************************/
+    samplesCountInBytes = (samplesPerValue * sizeof(M4OSA_UInt16) * channels);
+
+    bufferIn.m_dataAddress = (M4OSA_UInt8*)M4OSA_malloc(samplesCountInBytes*sizeof(M4OSA_UInt16), 0,
+    (M4OSA_Char*)"AudioGraph" );
+    if ( bufferIn.m_dataAddress != M4OSA_NULL) {
+        bufferIn.m_bufferSize = samplesCountInBytes*sizeof(M4OSA_UInt16);
+    } else {
+        VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+            "M4MA_generateAudioGraphFile: Malloc failed for bufferIn.m_dataAddress 0x%x",\
+            M4ERR_ALLOC);
+        return M4ERR_ALLOC;
+    }
+    /* sample to be converted to BIG endian ; store the frame duration */
+    samplesCountBigEndian = ((frameDuration>>24)&0xff) | // move byte 3 to byte 0
+                    ((frameDuration<<8)&0xff0000) | // move byte 1 to byte 2
+                    ((frameDuration>>8)&0xff00) | // move byte 2 to byte 1
+                    ((frameDuration<<24)&0xff000000); // byte 0 to byte 3
+
+    /* write the samples per value supplied to out file */
+    err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&samplesCountBigEndian,
+        sizeof(M4OSA_UInt32) );
+    if (err != M4NO_ERROR) {
+        jniThrowException(pEnv, "java/lang/IOException", "file write failed");
+    }
+
+
+    /* write UIn32 value 0 for no of values as place holder */
+    samplesCountBigEndian = 0; /* reusing local var */
+    err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&samplesCountBigEndian,
+        sizeof(M4OSA_UInt32) );
+    if (err != M4NO_ERROR) {
+        jniThrowException(pEnv, "java/lang/IOException", "file write failed");
+    }
+
+    /* loop until EOF */
+    do
+    {
+        M4OSA_memset((M4OSA_MemAddr8)bufferIn.m_dataAddress,bufferIn.m_bufferSize, 0);
+
+        numBytesToRead = samplesCountInBytes;
+
+        err =  M4OSA_fileReadData(  inputFileHandle,
+                                    (M4OSA_MemAddr8)bufferIn.m_dataAddress,
+                                    &numBytesToRead );
+
+        if (err != M4NO_ERROR) {
+            // if out value of bytes-read is 0, break
+            if ( numBytesToRead == 0) {
+                VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "numBytesToRead 0x%x",\
+                numBytesToRead);
+                break; /* stop if file is empty or EOF */
+            }
+        }
+
+        ptr16 = (M4OSA_Int16*)bufferIn.m_dataAddress;
+
+        peakVolumeDbValue = 0;
+        index = 0;
+
+        // loop through half the lenght frame bytes read 'cause its 16 bits samples
+        while (index < (numBytesToRead / 2)) {
+            /* absolute values of 16 bit sample */
+            if (ptr16[index] < 0) {
+                ptr16[index] = -(ptr16[index]);
+            }
+            peakVolumeDbValue = (peakVolumeDbValue > (M4OSA_UInt32)ptr16[index] ?\
+             peakVolumeDbValue : (M4OSA_UInt32)ptr16[index]);
+            index++;
+        }
+
+        // move 7 bits , ignore sign bit
+        dbValue = (peakVolumeDbValue >> 7);
+        dbValue = logLookUp[(M4OSA_UInt8)dbValue];
+
+        err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&dbValue, sizeof(M4OSA_UInt8) );
+        if (err != M4NO_ERROR) {
+            VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+             "M4MA_generateAudioGraphFile : File write failed");
+            break;
+        }
+
+        volumeValuesCount ++;
+        totalBytesRead += numBytesToRead;
+
+        if ((((totalBytesRead*100)/fileSize)) != prevProgress) {
+            if ( (pContext->threadProgress != prevProgress) && (prevProgress != 0 )) {
+                //pContext->threadProgress = prevProgress;
+                //onWveformProgressUpdateMethodId(prevProgress, 0);
+                //LVME_callAudioGraphOnProgressUpdate(pContext, 0, prevProgress);
+            pEnv->CallVoidMethod(pContext->engine,
+                                 pContext->onAudioGraphProgressUpdateMethodId,
+                                 prevProgress, 0);
+            VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "pContext->threadProgress %d",
+                             prevProgress);
+            }
+        }
+        prevProgress = (((totalBytesRead*100)/fileSize));
+
+    } while (numBytesToRead != 0);
+
+    VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "loop 0x%x", volumeValuesCount);
+
+    /* if some error occured in fwrite */
+    if (numBytesToRead != 0) {
+        //err = -1;
+        jniThrowException(pEnv, "java/lang/IOException", "numBytesToRead != 0 ; file write failed");
+    }
+
+    /* write the count in place holder after seek */
+    seekPos = sizeof(M4OSA_UInt32);
+    err = M4OSA_fileWriteSeek(outFileHandle, M4OSA_kFileSeekBeginning,
+            &seekPos /* after samples per value */);
+    if ( err != M4NO_ERROR) {
+        jniThrowException(pEnv, "java/lang/IOException", "file seek failed");
+    } else {
+        volumeValuesCount = ((volumeValuesCount>>24)&0xff) | // move byte 3 to byte 0
+                    ((volumeValuesCount<<8)&0xff0000) | // move byte 1 to byte 2
+                    ((volumeValuesCount>>8)&0xff00) |  // move byte 2 to byte 1
+                    ((volumeValuesCount<<24)&0xff000000); // byte 0 to byte 3
+
+        err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&volumeValuesCount,
+                                    sizeof(M4OSA_UInt32) );
+        if ( err != M4NO_ERROR) {
+            jniThrowException(pEnv, "java/lang/IOException", "file write failed");
+        }
+    }
+
+    /******************************************************************************
+    CLOSE AND FREE ALLOCATIONS
+    *******************************************************************************/
+    M4OSA_free((M4OSA_MemAddr32)bufferIn.m_dataAddress);
+    M4OSA_fileReadClose(inputFileHandle);
+    M4OSA_fileWriteClose(outFileHandle);
+    /* final finish callback */
+    pEnv->CallVoidMethod(pContext->engine, pContext->onAudioGraphProgressUpdateMethodId, 100, 0);
+
+    /* EXIT */
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "EXIT - M4MA_generateAudioGraphFile");
+
+    return err;
+}
+
+static int videoEditor_generateAudioWaveFormSync (JNIEnv*  pEnv, jobject thiz,
+                                                  jstring pcmfilePath,
+                                                  jstring outGraphfilePath,
+                                                  jint frameDuration, jint channels,
+                                                  jint samplesCount)
+{
+    M4OSA_ERR result = M4NO_ERROR;
+    ManualEditContext* pContext = M4OSA_NULL;
+    bool needToBeLoaded = true;
+
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+        "videoEditor_generateAudioWaveFormSync() ");
+
+    /* Get the context. */
+    pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
+    if (pContext == M4OSA_NULL) {
+        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+            "videoEditor_generateAudioWaveFormSync() - pContext is NULL ");
+    }
+
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+        "videoEditor_generateAudioWaveFormSync Retrieving pStringOutAudioGraphFile");
+
+    const char *pPCMFilePath = pEnv->GetStringUTFChars(pcmfilePath, NULL);
+    if (pPCMFilePath == M4OSA_NULL) {
+        if (pEnv != NULL) {
+            jniThrowException(pEnv, "java/lang/RuntimeException",
+                "Input string PCMFilePath is null");
+        }
+    }
+
+    const char *pStringOutAudioGraphFile = pEnv->GetStringUTFChars(outGraphfilePath, NULL);
+    if (pStringOutAudioGraphFile == M4OSA_NULL) {
+        if (pEnv != NULL) {
+            jniThrowException(pEnv, "java/lang/RuntimeException",
+                "Input string outGraphfilePath is null");
+        }
+    }
+
+    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+        "videoEditor_generateAudioWaveFormSync Generate the waveform data %s %d %d %d",
+        pStringOutAudioGraphFile, frameDuration, channels, samplesCount);
+
+    /* Generate the waveform */
+    result = M4MA_generateAudioGraphFile(pEnv, (M4OSA_Char*) pPCMFilePath,
+        (M4OSA_Char*) pStringOutAudioGraphFile,
+        (M4OSA_UInt32) samplesCount,
+        (M4OSA_UInt32) channels,
+        (M4OSA_UInt32)frameDuration,
+        pContext);
+
+    if (pStringOutAudioGraphFile != NULL) {
+        pEnv->ReleaseStringUTFChars(outGraphfilePath, pStringOutAudioGraphFile);
+    }
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
+        "videoEditor_generateAudioWaveFormSync pContext->bSkipState ");
+
+    return result;
+}
+
+/******** End Audio Graph *******/
+jint JNI_OnLoad(
+                JavaVM*                             pVm,
+                void*                               pReserved)
+{
+    void* pEnv         = NULL;
+    bool  needToBeInitialized = true;
+    jint  result      = -1;
+
+    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "JNI_OnLoad()");
+
+    // Add a text marker (the condition must always be true).
+    ADD_TEXT_MARKER_FUN(NULL != pVm)
+
+    // Check the JNI version.
+    if (pVm->GetEnv(&pEnv, JNI_VERSION_1_4) == JNI_OK)
+    {
+        // Add a code marker (the condition must always be true).
+        ADD_CODE_MARKER_FUN(NULL != pEnv)
+
+        // Register the manual edit JNI methods.
+        if (videoEditor_registerManualEditMethods((JNIEnv*)pEnv) == 0)
+        {
+            // Initialize the classes.
+            videoEditClasses_init(&needToBeInitialized, (JNIEnv*)pEnv);
+            if (needToBeInitialized)
+            {
+                // Success, return valid version number.
+                result = JNI_VERSION_1_4;
+            }
+        }
+    }
+
+    // Return the result.
+    return(result);
+}
+
diff --git a/media/jni/mediaeditor/VideoEditorMain.h b/media/jni/mediaeditor/VideoEditorMain.h
new file mode 100755
index 0000000..b73913a
--- /dev/null
+++ b/media/jni/mediaeditor/VideoEditorMain.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2011 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 __VIDEO_EDITOR_API_H__
+#define __VIDEO_EDITOR_API_H__
+
+#include "M4OSA_Types.h"
+
+typedef enum
+{
+    MSG_TYPE_PROGRESS_INDICATION,             /* Playback progress indication event*/
+    MSG_TYPE_PLAYER_ERROR,                    /* Playback error*/
+    MSG_TYPE_PREVIEW_END,                     /* Preview of clips is complete */
+} progress_callback_msg_type;
+
+typedef struct
+{
+    M4OSA_Void     *pFile;                   /** PCM file path */
+    M4OSA_Bool     bRemoveOriginal;          /** If true, the original audio track
+                                                 is not taken into account */
+    M4OSA_UInt32   uiNbChannels;            /** Number of channels (1=mono, 2=stereo) of BGM clip*/
+    M4OSA_UInt32   uiSamplingFrequency;     /** Sampling audio frequency (8000 for amr, 16000 or
+                                                more for aac) of BGM clip*/
+    M4OSA_UInt32   uiExtendedSamplingFrequency; /** Extended frequency for AAC+,
+                                                eAAC+ streams of BGM clip*/
+    M4OSA_UInt32   uiAddCts;                /** Time, in milliseconds, at which the added
+                                                audio track is inserted */
+    M4OSA_UInt32   uiAddVolume;             /** Volume, in percentage, of the added audio track */
+    M4OSA_UInt32   beginCutMs;
+    M4OSA_UInt32   endCutMs;
+    M4OSA_Int32    fileType;
+    M4OSA_Bool     bLoop;                   /** Looping on/off **/
+    /* Audio ducking */
+    M4OSA_UInt32   uiInDucking_threshold;   /** Threshold value at which
+                                                background music shall duck */
+    M4OSA_UInt32   uiInDucking_lowVolume;   /** lower the background track to
+                                                this factor of current level */
+    M4OSA_Bool     bInDucking_enable;       /** enable ducking */
+    M4OSA_UInt32   uiBTChannelCount;        /** channel count for BT */
+    M4OSA_Void     *pPCMFilePath;
+} M4xVSS_AudioMixingSettings;
+
+typedef struct
+{
+    M4OSA_Void      *pBuffer;            /* YUV420 buffer of frame to be rendered*/
+    M4OSA_UInt32    timeMs;            /* time stamp of the frame to be rendered*/
+    M4OSA_UInt32    uiSurfaceWidth;    /* Surface display width*/
+    M4OSA_UInt32    uiSurfaceHeight;    /* Surface display height*/
+    M4OSA_UInt32    uiFrameWidth;        /* Frame width*/
+    M4OSA_UInt32    uiFrameHeight;        /* Frame height*/
+    M4OSA_Bool      bApplyEffect;        /* Apply video effects before render*/
+    M4OSA_UInt32    clipBeginCutTime;  /* Clip begin cut time relative to storyboard */
+    M4OSA_UInt32    clipEndCutTime;    /* Clip end cut time relative to storyboard */
+
+} VideoEditor_renderPreviewFrameStr;
+#endif /*__VIDEO_EDITOR_API_H__*/
diff --git a/media/jni/mediaeditor/VideoEditorOsal.cpp b/media/jni/mediaeditor/VideoEditorOsal.cpp
new file mode 100755
index 0000000..423e93f
--- /dev/null
+++ b/media/jni/mediaeditor/VideoEditorOsal.cpp
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2011 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 <VideoEditorJava.h>
+#include <VideoEditorLogging.h>
+#include <VideoEditorOsal.h>
+
+extern "C" {
+#include <M4OSA_Clock.h>
+#include <M4OSA_CharStar.h>
+#include <M4OSA_FileCommon.h>
+#include <M4OSA_FileReader.h>
+#include <M4OSA_FileWriter.h>
+#include <M4OSA_Memory.h>
+#include <M4OSA_String.h>
+#include <M4OSA_Thread.h>
+#include <M4xVSS_API.h>
+#include <M4VSS3GPP_ErrorCodes.h>
+#include <M4MCS_ErrorCodes.h>
+#include <M4READER_Common.h>
+#include <M4WRITER_common.h>
+#include <M4VSS3GPP_API.h>
+#include <M4DECODER_Common.h>
+};
+
+
+#define VIDEOEDIT_OSAL_RESULT_STRING_MAX     (32)
+
+#define VIDEOEDIT_OSAL_RESULT_INIT(m_result) { m_result, #m_result }
+
+
+typedef struct
+{
+    M4OSA_ERR   result;
+    const char* pName;
+} VideoEdit_Osal_Result;
+
+static const VideoEdit_Osal_Result gkRESULTS[] =
+{
+    // M4OSA_Clock.h
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_TIMESCALE_TOO_BIG                                ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_CLOCK_BAD_REF_YEAR                               ),
+
+    // M4OSA_Error.h
+    VIDEOEDIT_OSAL_RESULT_INIT(M4NO_ERROR                                             ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_PARAMETER                                        ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_STATE                                            ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_ALLOC                                            ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_BAD_CONTEXT                                      ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_CONTEXT_FAILED                                   ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_BAD_STREAM_ID                                    ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_BAD_OPTION_ID                                    ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_WRITE_ONLY                                       ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_READ_ONLY                                        ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_NOT_IMPLEMENTED                                  ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_UNSUPPORTED_MEDIA_TYPE                           ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_NO_DATA_YET                                      ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_NO_MORE_STREAM                                   ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_INVALID_TIME                                     ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_NO_MORE_AU                                       ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_TIME_OUT                                         ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_BUFFER_FULL                                      ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_REDIRECT                                         ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_TOO_MUCH_STREAMS                                 ),
+
+    // M4OSA_FileCommon.h
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_FILE_NOT_FOUND                                   ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_FILE_LOCKED                                      ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_FILE_BAD_MODE_ACCESS                             ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_FILE_INVALID_POSITION                            ),
+
+    // M4OSA_String.h
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_STR_BAD_STRING                                   ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_STR_CONV_FAILED                                  ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_STR_OVERFLOW                                     ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_STR_BAD_ARGS                                     ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_STR_OVERFLOW                                     ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_STR_NOT_FOUND                                    ),
+
+    // M4OSA_Thread.h
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_THREAD_NOT_STARTED                               ),
+
+    // M4xVSS_API.h
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_ANALYZING_DONE                           ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_PREVIEW_READY                            ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_SAVING_DONE                              ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_TRANSCODING_NECESSARY                    ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_OUTPUTFILESIZE_EXCEED                    ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_JPG_TOO_BIG                              ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4xVSSWAR_BUFFER_OUT_TOO_SMALL                         ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4xVSSERR_NO_MORE_SPACE                                ),
+
+    // M4VSS3GPP_ErrorCodes.h
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_FILE_TYPE                        ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_EFFECT_KIND                      ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_VIDEO_EFFECT_TYPE                ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_AUDIO_EFFECT_TYPE                ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_VIDEO_TRANSITION_TYPE            ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_AUDIO_TRANSITION_TYPE            ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_VIDEO_ENCODING_FRAME_RATE        ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EXTERNAL_EFFECT_NULL                     ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EXTERNAL_TRANSITION_NULL                 ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_DURATION           ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_END_CUT            ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_OVERLAPPING_TRANSITIONS                  ),
+#ifdef M4VSS3GPP_ERR_ANALYSIS_DATA_SIZE_TOO_SMALL
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_ANALYSIS_DATA_SIZE_TOO_SMALL             ),
+#endif
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_3GPP_FILE                        ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_UNSUPPORTED_INPUT_VIDEO_FORMAT           ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_UNSUPPORTED_INPUT_AUDIO_FORMAT           ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AMR_EDITING_UNSUPPORTED                  ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INPUT_VIDEO_AU_TOO_LARGE                 ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INPUT_AUDIO_AU_TOO_LARGE                 ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AU                 ),
+#ifdef M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AMR_AU
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AMR_AU             ),
+#endif
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_ENCODER_ACCES_UNIT_ERROR                 ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_FORMAT         ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EDITING_UNSUPPORTED_H263_PROFILE         ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EDITING_UNSUPPORTED_MPEG4_PROFILE        ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EDITING_UNSUPPORTED_MPEG4_RVLC           ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EDITING_UNSUPPORTED_AUDIO_FORMAT         ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EDITING_NO_SUPPORTED_STREAM_IN_FILE      ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EDITING_NO_SUPPORTED_VIDEO_STREAM_IN_FILE),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_CLIP_ANALYSIS_VERSION            ),
+#ifdef M4VSS3GPP_ERR_INVALID_CLIP_ANALYSIS_PLATFORM
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_CLIP_ANALYSIS_PLATFORM           ),
+#endif
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_FORMAT                ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_FRAME_SIZE            ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_TIME_SCALE            ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_DATA_PARTITIONING     ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_UNSUPPORTED_MP3_ASSEMBLY                 ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_STREAM_TYPE           ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_NB_OF_CHANNELS        ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_SAMPLING_FREQUENCY    ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_NO_SUPPORTED_STREAM_IN_FILE              ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_ADDVOLUME_EQUALS_ZERO                    ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_ADDCTS_HIGHER_THAN_VIDEO_DURATION        ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_UNDEFINED_AUDIO_TRACK_FILE_FORMAT        ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_UNSUPPORTED_ADDED_AUDIO_STREAM           ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AUDIO_MIXING_UNSUPPORTED                 ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AUDIO_TRACK     ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AUDIO_CANNOT_BE_MIXED                    ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INPUT_CLIP_IS_NOT_A_3GPP                 ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_BEGINLOOP_HIGHER_ENDLOOP                 ),
+#ifdef M4VSS3GPP_ERR_AUDIO_MIXING_MP3_UNSUPPORTED
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AUDIO_MIXING_MP3_UNSUPPORTED             ),
+#endif
+#ifdef M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AAC
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AAC             ),
+#endif
+#ifdef M4VSS3GPP_ERR_ONLY_AMRNB_INPUT_CAN_BE_MIXED
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_ONLY_AMRNB_INPUT_CAN_BE_MIXED            ),
+#endif
+#ifdef M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_EVRC
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_EVRC            ),
+#endif
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_H263_PROFILE_NOT_SUPPORTED               ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_NO_SUPPORTED_VIDEO_STREAM_IN_FILE        ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INTERNAL_STATE                           ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_LUMA_FILTER_ERROR                        ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_CURTAIN_FILTER_ERROR                     ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_TRANSITION_FILTER_ERROR                  ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AUDIO_DECODER_INIT_FAILED                ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AUDIO_DECODED_PCM_SIZE_ISSUE             ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_OUTPUT_FILE_TYPE_ERROR                   ),
+
+    // M4MCS_ErrorCodes.h
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_WAR_TRANSCODING_DONE                             ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_WAR_MEDIATYPE_NOT_SUPPORTED                      ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM      ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_INVALID_INPUT_FILE                           ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FORMAT                ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_SIZE            ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_RATE            ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_UNDEFINED_OUTPUT_AUDIO_FORMAT                ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_INVALID_VIDEO_FRAME_SIZE_FOR_H263            ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_INVALID_VIDEO_FRAME_RATE_FOR_H263            ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_DURATION_IS_NULL                             ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_H263_FORBIDDEN_IN_MP4_FILE                   ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_H263_PROFILE_NOT_SUPPORTED                   ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_INVALID_AAC_SAMPLING_FREQUENCY               ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_AUDIO_CONVERSION_FAILED                      ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_BEGIN_CUT_LARGER_THAN_DURATION               ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_BEGIN_CUT_EQUALS_END_CUT                     ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_END_CUT_SMALLER_THAN_BEGIN_CUT               ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_MAXFILESIZE_TOO_SMALL                        ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_VIDEOBITRATE_TOO_LOW                         ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_AUDIOBITRATE_TOO_LOW                         ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_VIDEOBITRATE_TOO_HIGH                        ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_AUDIOBITRATE_TOO_HIGH                        ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_OUTPUT_FILE_SIZE_TOO_SMALL                   ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_NOMORE_SPACE                                 ),
+
+    // M4READER_Common.h
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_READER_UNKNOWN_STREAM_TYPE                       ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_READER_NO_METADATA                               ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_READER_INFORMATION_NOT_PRESENT                   ),
+
+    // M4WRITER_Common.h
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_WRITER_STOP_REQ                                  ),
+    // M4DECODER_Common.h
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_VIDEORENDERER_NO_NEW_FRAME                       ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_DEBLOCKING_FILTER_NOT_IMPLEMENTED                ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_DECODER_H263_PROFILE_NOT_SUPPORTED               ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_DECODER_H263_NOT_BASELINE                        )
+};
+
+static const int gkRESULTS_COUNT = (sizeof(gkRESULTS) / sizeof(VideoEdit_Osal_Result));
+
+#ifdef OSAL_MEM_LEAK_DEBUG
+static int gAllocatedBlockCount = 0;
+#endif
+
+const char*
+videoEditOsal_getResultString(
+                M4OSA_ERR                           result)
+{
+    static char string[VIDEOEDIT_OSAL_RESULT_STRING_MAX] = "";
+    const char* pString                         = M4OSA_NULL;
+    int         index                           = 0;
+
+    // Loop over the list with constants.
+    for (index = 0;
+         ((M4OSA_NULL == pString) && (index < gkRESULTS_COUNT));
+         index++)
+    {
+        // Check if the specified result matches.
+        if (result == gkRESULTS[index].result)
+        {
+            // Set the description.
+            pString = gkRESULTS[index].pName;
+        }
+    }
+
+    // Check if no result was found.
+    if (M4OSA_NULL == pString)
+    {
+        // Set the description to a default value.
+        M4OSA_chrSPrintf((M4OSA_Char *)string, sizeof(string) - 1,
+         (M4OSA_Char*)"<unknown(0x%08X)>", result);
+        pString = string;
+    }
+
+    // Return the result.
+    return(pString);
+}
+
+void *
+videoEditOsal_alloc(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                size_t                              size,
+                const char*                         pDescription)
+{
+    void *pData = M4OSA_NULL;
+
+    // Check if the previous action succeeded.
+    if (*pResult)
+    {
+        // Allocate memory for the settings.
+        pData = (M4VSS3GPP_EditSettings*)M4OSA_malloc(size, 0, (M4OSA_Char*)pDescription);
+        if (M4OSA_NULL != pData)
+        {
+            // Reset the allocated memory.
+            M4OSA_memset((M4OSA_MemAddr8)pData, size, 0);
+#ifdef OSAL_MEM_LEAK_DEBUG
+            // Update the allocated block count.
+            gAllocatedBlockCount++;
+#endif
+        }
+        else
+        {
+            // Reset the result flag.
+            (*pResult) = false;
+
+            // Log the error.
+            VIDEOEDIT_LOG_ERROR(ANDROID_LOG_ERROR, "VIDEO_EDITOR_OSAL", "videoEditOsal_alloc,\
+             error: unable to allocate memory for %s", pDescription);
+
+            // Throw an exception.
+            jniThrowException(pEnv, "java/lang/OutOfMemoryError", "unable to allocate memory");
+        }
+    }
+
+    // Return the allocated memory.
+    return(pData);
+}
+
+void
+videoEditOsal_free(
+                void*                               pData)
+{
+    // Check if memory was allocated.
+    if (M4OSA_NULL != pData)
+    {
+        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_OSAL", "videoEditOsal_free()");
+
+        // Log the API call.
+        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR_OSAL", "M4OSA_free()");
+
+        // Free the memory.
+        M4OSA_free((M4OSA_MemAddr32)pData);
+#ifdef OSAL_MEM_LEAK_DEBUG
+        // Update the allocated block count.
+        gAllocatedBlockCount--;
+
+        // Log the number of allocated blocks.
+        VIDEOEDIT_LOG_ALLOCATION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_OSAL", "allocated, %d blocks",\
+         gAllocatedBlockCount);
+#endif
+    }
+}
+
+
+void
+videoEditOsal_getFilePointers ( M4OSA_FileReadPointer *pOsaFileReadPtr,
+                                M4OSA_FileWriterPointer *pOsaFileWritePtr)
+{
+    if (pOsaFileReadPtr != M4OSA_NULL)
+    {
+        // Initialize the filereader function pointers.
+        pOsaFileReadPtr->openRead  = M4OSA_fileReadOpen;
+        pOsaFileReadPtr->readData  = M4OSA_fileReadData;
+        pOsaFileReadPtr->seek      = M4OSA_fileReadSeek;
+        pOsaFileReadPtr->closeRead = M4OSA_fileReadClose;
+        pOsaFileReadPtr->setOption = M4OSA_fileReadSetOption;
+        pOsaFileReadPtr->getOption = M4OSA_fileReadGetOption;
+    }
+
+    if (pOsaFileWritePtr != M4OSA_NULL)
+    {
+        // Initialize the filewriter function pointers.
+        pOsaFileWritePtr->openWrite  = M4OSA_fileWriteOpen;
+        pOsaFileWritePtr->writeData  = M4OSA_fileWriteData;
+        pOsaFileWritePtr->seek       = M4OSA_fileWriteSeek;
+        pOsaFileWritePtr->Flush      = M4OSA_fileWriteFlush;
+        pOsaFileWritePtr->closeWrite = M4OSA_fileWriteClose;
+        pOsaFileWritePtr->setOption  = M4OSA_fileWriteSetOption;
+        pOsaFileWritePtr->getOption  = M4OSA_fileWriteGetOption;
+    }
+}
+
diff --git a/media/jni/mediaeditor/VideoEditorOsal.h b/media/jni/mediaeditor/VideoEditorOsal.h
new file mode 100755
index 0000000..7a6f5ea
--- /dev/null
+++ b/media/jni/mediaeditor/VideoEditorOsal.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011 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 VIDEO_EDITOR_OSAL_H
+#define VIDEO_EDITOR_OSAL_H
+
+#include <jni.h>
+#include <JNIHelp.h>
+
+extern "C" {
+#include <M4OSA_Error.h>
+#include <M4OSA_Thread.h>
+#include <M4OSA_FileReader.h>
+#include <M4OSA_FileWriter.h>
+};
+
+const char*
+videoEditOsal_getResultString(
+                M4OSA_ERR                           result);
+
+void*
+videoEditOsal_alloc(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                size_t                              size,
+                const char*                         pDescription);
+
+void
+videoEditOsal_free(
+                void*                               pData);
+
+void
+videoEditOsal_startThread(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                int                                 stackSize,
+                M4OSA_ThreadDoIt                    callback,
+                M4OSA_Context*                      pContext,
+                void*                               pParam);
+
+void
+videoEditOsal_stopThread(
+                bool*                               pResult,
+                JNIEnv*                             pEnv,
+                M4OSA_Context*                      pContext);
+
+void
+videoEditOsal_getFilePointers ( M4OSA_FileReadPointer *pOsaFileReadPtr,
+                                M4OSA_FileWriterPointer *pOsaFileWritePtr);
+
+#endif // VIDEO_EDITOR_OSAL_H
+
diff --git a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
new file mode 100755
index 0000000..7bf76da
--- /dev/null
+++ b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) 2011 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 <dlfcn.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <VideoEditorClasses.h>
+#include <VideoEditorJava.h>
+#include <VideoEditorOsal.h>
+#include <VideoEditorLogging.h>
+#include <VideoEditorOsal.h>
+#include <marker.h>
+
+extern "C" {
+#include <M4OSA_Clock.h>
+#include <M4OSA_CharStar.h>
+#include <M4OSA_Error.h>
+#include <M4OSA_FileCommon.h>
+#include <M4OSA_FileReader.h>
+#include <M4OSA_FileWriter.h>
+#include <M4OSA_Memory.h>
+#include <M4OSA_String.h>
+#include <M4OSA_Thread.h>
+#include <M4VSS3GPP_API.h>
+#include <M4VSS3GPP_ErrorCodes.h>
+#include <M4MCS_API.h>
+#include <M4MCS_ErrorCodes.h>
+#include <M4MDP_API.h>
+#include <M4READER_Common.h>
+#include <M4WRITER_common.h>
+#include <M4DECODER_Common.h>
+#include <M4AD_Common.h>
+};
+
+extern "C" M4OSA_ERR M4MCS_open_normalMode(
+                M4MCS_Context                       pContext,
+                M4OSA_Void*                         pFileIn,
+                M4VIDEOEDITING_FileType             InputFileType,
+                M4OSA_Void*                         pFileOut,
+                M4OSA_Void*                         pTempFile);
+
+jobject videoEditProp_getProperties(
+                JNIEnv*                             pEnv,
+                jobject                             thiz,
+                jstring                             file);
+
+static void
+getFileAndMediaTypeFromExtension (
+                M4OSA_Char* pExtension,
+                VideoEditClasses_FileType   *pFileType,
+                M4VIDEOEDITING_FileType       *pClipType);
+
+static M4OSA_ERR
+getClipProperties(  JNIEnv*                         pEnv,
+                    jobject                         thiz,
+                    M4OSA_Char*                     pFile,
+                    M4VIDEOEDITING_FileType         clipType,
+                    M4VIDEOEDITING_ClipProperties*  pClipProperties);
+
+M4OSA_UInt32
+VideoEdit_chrCompare(M4OSA_Char* pStrIn1,
+                     M4OSA_Char* pStrIn2,
+                     M4OSA_Int32* pCmpResult);
+
+jobject videoEditProp_getProperties(
+        JNIEnv* pEnv,
+        jobject thiz,
+        jstring file)
+{
+    bool                           gotten          = true;
+    M4OSA_Char*                    pFile           = M4OSA_NULL;
+    M4OSA_Char*                    pExtension      = M4OSA_NULL;
+    M4OSA_UInt32                   index           = 0;
+    M4OSA_Int32                    cmpResult       = 0;
+    VideoEditPropClass_Properties* pProperties     = M4OSA_NULL;
+    M4VIDEOEDITING_ClipProperties* pClipProperties = M4OSA_NULL;
+    M4OSA_ERR                      result          = M4NO_ERROR;
+    M4MCS_Context                  context         = M4OSA_NULL;
+    M4OSA_FilePosition             size            = 0;
+    M4OSA_UInt32                   width           = 0;
+    M4OSA_UInt32                   height          = 0;
+    jobject                        properties      = NULL;
+    M4OSA_Context                  pOMXContext     = M4OSA_NULL;
+    M4DECODER_VideoInterface*      pOMXVidDecoderInterface = M4OSA_NULL;
+    M4AD_Interface*                pOMXAudDecoderInterface = M4OSA_NULL;
+
+    bool  initialized = true;
+    VideoEditClasses_FileType fileType = VideoEditClasses_kFileType_Unsupported;
+    M4VIDEOEDITING_FileType clipType = M4VIDEOEDITING_kFileType_Unsupported;
+
+    VIDEOEDIT_LOG_API(
+            ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
+            "videoEditProp_getProperties()");
+
+    // Add a text marker (the condition must always be true).
+    ADD_TEXT_MARKER_FUN(NULL != pEnv)
+
+    // Initialize the classes.
+    videoEditPropClass_init(&initialized, (JNIEnv*)pEnv);
+
+    // Validate the tempPath parameter.
+    videoEditJava_checkAndThrowIllegalArgumentException(
+            &gotten, pEnv, (NULL == file), "file is null");
+
+    // Get the file path.
+    pFile = (M4OSA_Char *)videoEditJava_getString(
+            &gotten, pEnv, file, NULL, M4OSA_NULL);
+
+    result = M4OSA_fileReadOpen(&context, (M4OSA_Void*)pFile, M4OSA_kFileRead);
+    videoEditJava_checkAndThrowIllegalArgumentException(&gotten, pEnv,
+        (M4NO_ERROR != result), "file not found");
+    if(M4NO_ERROR != result)
+        return(properties);
+    result = M4OSA_fileReadClose(context);
+    context = M4OSA_NULL;
+
+    // Check if the file path is valid.
+    if (gotten)
+    {
+        // Retrieve the extension.
+        result = M4OSA_chrReverseFindChar(pFile, '.', &pExtension);
+        if ((M4NO_ERROR == result) && (M4OSA_NULL != pExtension))
+        {
+            // Skip the dot.
+            pExtension++;
+
+            // Get the file type and Media type from extension
+            getFileAndMediaTypeFromExtension(
+                    pExtension ,&fileType, &clipType);
+        }
+    }
+
+    // Check if the file type could be determined.
+    videoEditJava_checkAndThrowIllegalArgumentException(
+            &gotten, pEnv,
+            (VideoEditClasses_kFileType_Unsupported == fileType),
+            "file type is not supported");
+
+    // Allocate a new properties structure.
+    pProperties = (VideoEditPropClass_Properties*)videoEditOsal_alloc(
+            &gotten, pEnv,
+            sizeof(VideoEditPropClass_Properties), "Properties");
+
+    // Check if the context is valid and allocation succeeded
+    // (required because of dereferencing of pProperties).
+    if (gotten)
+    {
+        // Check if this type of file needs to be analyzed using MCS.
+        if ((VideoEditClasses_kFileType_MP3  == fileType) ||
+            (VideoEditClasses_kFileType_MP4  == fileType) ||
+            (VideoEditClasses_kFileType_3GPP == fileType) ||
+            (VideoEditClasses_kFileType_AMR  == fileType) ||
+            (VideoEditClasses_kFileType_PCM  == fileType))
+        {
+            // Allocate a new clip properties structure.
+            pClipProperties =
+                (M4VIDEOEDITING_ClipProperties*)videoEditOsal_alloc(
+                    &gotten, pEnv,
+                    sizeof(M4VIDEOEDITING_ClipProperties), "ClipProperties");
+
+            // Check if allocation succeeded (required because of
+            // dereferencing of pClipProperties).
+            if (gotten)
+            {
+                // Add a code marker (the condition must always be true).
+                ADD_CODE_MARKER_FUN(NULL != pClipProperties)
+
+                // Log the API call.
+                VIDEOEDIT_LOG_API(
+                        ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
+                        "getClipProperties");
+
+                // Get Video clip properties
+                result = getClipProperties(
+                        pEnv, thiz, pFile, clipType, pClipProperties);
+
+                // Check if the creation succeeded.
+                videoEditJava_checkAndThrowIllegalArgumentException(
+                        &gotten, pEnv,(M4NO_ERROR != result),
+                        "Invalid File or File not found");
+
+                if (pClipProperties->uiVideoWidth >= 1920)
+                {
+                    result = M4MCS_ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM;
+                    videoEditJava_checkAndThrowIllegalArgumentException(
+                            &gotten, pEnv, (M4NO_ERROR != result),
+                            "HD Content (1080p) is not supported");
+                }
+            }
+
+            // Check if the properties could be retrieved.
+            if (gotten)
+            {
+                // Set the properties.
+                pProperties->uiClipDuration = pClipProperties->uiClipDuration;
+                if (M4VIDEOEDITING_kFileType_Unsupported == pClipProperties->FileType)
+                {
+                    pProperties->FileType        = VideoEditClasses_kFileType_Unsupported;
+                }
+                else
+                {
+                    pProperties->FileType        = fileType;
+                }
+                pProperties->VideoStreamType     = pClipProperties->VideoStreamType;
+                pProperties->uiClipVideoDuration = pClipProperties->uiClipVideoDuration;
+                pProperties->uiVideoBitrate      = pClipProperties->uiVideoBitrate;
+                pProperties->uiVideoWidth        = pClipProperties->uiVideoWidth;
+                pProperties->uiVideoHeight       = pClipProperties->uiVideoHeight;
+                pProperties->fAverageFrameRate   = pClipProperties->fAverageFrameRate;
+                pProperties->ProfileAndLevel     = pClipProperties->ProfileAndLevel;
+                pProperties->AudioStreamType     = pClipProperties->AudioStreamType;
+                pProperties->uiClipAudioDuration = pClipProperties->uiClipAudioDuration;
+                pProperties->uiAudioBitrate      = pClipProperties->uiAudioBitrate;
+                pProperties->uiNbChannels        = pClipProperties->uiNbChannels;
+                pProperties->uiSamplingFrequency = pClipProperties->uiSamplingFrequency;
+            }
+
+            // Free the clip properties.
+            videoEditOsal_free(pClipProperties);
+            pClipProperties = M4OSA_NULL;
+        }
+        else if ((VideoEditClasses_kFileType_JPG == fileType) ||
+            (VideoEditClasses_kFileType_GIF == fileType) ||
+            (VideoEditClasses_kFileType_PNG == fileType))
+        {
+            pProperties->uiClipDuration      = 0;
+            pProperties->FileType            = fileType;
+            pProperties->VideoStreamType     = M4VIDEOEDITING_kNoneVideo;
+            pProperties->uiClipVideoDuration = 0;
+            pProperties->uiVideoBitrate      = 0;
+            pProperties->uiVideoWidth        = width;
+            pProperties->uiVideoHeight       = height;
+            pProperties->fAverageFrameRate   = 0.0f;
+            pProperties->ProfileAndLevel     = M4VIDEOEDITING_kProfile_and_Level_Out_Of_Range;
+            pProperties->AudioStreamType     = M4VIDEOEDITING_kNoneAudio;
+            pProperties->uiClipAudioDuration = 0;
+            pProperties->uiAudioBitrate      = 0;
+            pProperties->uiNbChannels        = 0;
+            pProperties->uiSamplingFrequency = 0;
+
+            // Added for Handling invalid paths and non existent image files
+            // Open the file for reading.
+            result = M4OSA_fileReadOpen(&context, (M4OSA_Void*)pFile, M4OSA_kFileRead);
+            if (M4NO_ERROR != result)
+            {
+                pProperties->FileType = VideoEditClasses_kFileType_Unsupported;
+            }
+            result = M4OSA_fileReadClose(context);
+            context = M4OSA_NULL;
+        }
+    }
+
+    // Create a properties object.
+    videoEditPropClass_createProperties(&gotten, pEnv, pProperties, &properties);
+
+    // Log the properties.
+    VIDEOEDIT_PROP_LOG_PROPERTIES(pProperties);
+
+    // Free the properties.
+    videoEditOsal_free(pProperties);
+    pProperties = M4OSA_NULL;
+
+    // Free the file path.
+    videoEditOsal_free(pFile);
+    pFile = M4OSA_NULL;
+
+    // Add a text marker (the condition must always be true).
+    ADD_TEXT_MARKER_FUN(NULL != pEnv)
+
+    // Return the Properties object.
+    return(properties);
+}
+
+static void getFileAndMediaTypeFromExtension (
+        M4OSA_Char *pExtension,
+        VideoEditClasses_FileType *pFileType,
+        M4VIDEOEDITING_FileType *pClipType)
+{
+    M4OSA_Char extension[5] = {0, 0, 0, 0, 0};
+    VideoEditClasses_FileType fileType =
+            VideoEditClasses_kFileType_Unsupported;
+
+    M4VIDEOEDITING_FileType clipType =
+            M4VIDEOEDITING_kFileType_Unsupported;
+
+    M4OSA_UInt32 index = 0;
+    M4OSA_ERR result = M4NO_ERROR;
+    M4OSA_Int32 cmpResult = 0;
+    M4OSA_UInt32  extLength = M4OSA_chrLength(pExtension);
+
+    // Assign default
+    *pFileType = VideoEditClasses_kFileType_Unsupported;
+    *pClipType = M4VIDEOEDITING_kFileType_Unsupported;
+
+    // Check if the length of the extension is valid.
+    if ((3 == extLength) || (4 == extLength))
+    {
+        // Convert the extension to lowercase.
+        for (index = 0; index < extLength ; index++)
+        {
+            extension[index] = M4OSA_chrToLower(pExtension[index]);
+        }
+
+                // Check if the extension is ".mp3".
+        if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"mp3", &cmpResult)))
+        {
+            *pFileType = VideoEditClasses_kFileType_MP3;
+            *pClipType = M4VIDEOEDITING_kFileType_MP3;
+        }       // Check if the extension is ".mp4".
+        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"mp4", &cmpResult)))
+        {
+            *pFileType = VideoEditClasses_kFileType_MP4;
+            *pClipType = M4VIDEOEDITING_kFileType_MP4;
+        }
+        // Check if the extension is ".3gp".
+        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"3gp", &cmpResult)))
+        {
+            *pFileType = VideoEditClasses_kFileType_3GPP;
+            *pClipType = M4VIDEOEDITING_kFileType_3GPP;
+        }
+        // Check if the extension is ".3gp".
+        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"m4a", &cmpResult)))
+        {
+            *pFileType = VideoEditClasses_kFileType_3GPP;
+            *pClipType = M4VIDEOEDITING_kFileType_3GPP;
+        }
+        // Check if the extension is ".3gpp".
+        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"3gpp", &cmpResult)))
+        {
+            *pFileType = VideoEditClasses_kFileType_3GPP;
+            *pClipType = M4VIDEOEDITING_kFileType_3GPP;
+        }
+        // Check if the extension is ".amr".
+        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"amr", &cmpResult)))
+        {
+
+            *pFileType = VideoEditClasses_kFileType_AMR;
+            *pClipType = M4VIDEOEDITING_kFileType_AMR;
+        }
+        // Check if the extension is ".pcm".
+        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"pcm", &cmpResult)))
+        {
+            *pFileType = VideoEditClasses_kFileType_PCM;
+            *pClipType = M4VIDEOEDITING_kFileType_PCM;
+        }
+        // Check if the extension is ".jpg".
+        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"jpg", &cmpResult)))
+        {
+            *pFileType = VideoEditClasses_kFileType_JPG;
+        }
+        // Check if the extension is ".jpeg".
+        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"jpeg", &cmpResult)))
+        {
+            *pFileType = VideoEditClasses_kFileType_JPG;
+        }
+        // Check if the extension is ".gif".
+        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"gif", &cmpResult)))
+        {
+            *pFileType = VideoEditClasses_kFileType_GIF;
+        }
+        // Check if the extension is ".png".
+        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"png", &cmpResult)))
+        {
+            *pFileType = VideoEditClasses_kFileType_PNG;
+        }
+
+    }
+
+}
+
+static M4OSA_ERR getClipProperties(
+        JNIEnv* pEnv,
+        jobject thiz,
+        M4OSA_Char* pFile,
+        M4VIDEOEDITING_FileType clipType,
+        M4VIDEOEDITING_ClipProperties* pClipProperties)
+{
+    bool                      gotten          = true;
+    M4OSA_ERR                 result          = M4NO_ERROR;
+    M4OSA_ERR                 resultAbort     = M4NO_ERROR;
+    M4MCS_Context             context         = M4OSA_NULL;
+
+    M4OSA_FileReadPointer fileReadPtr =
+            { M4OSA_NULL, M4OSA_NULL, M4OSA_NULL,
+              M4OSA_NULL, M4OSA_NULL, M4OSA_NULL };
+
+    M4OSA_FileWriterPointer fileWritePtr =
+            { M4OSA_NULL, M4OSA_NULL, M4OSA_NULL,
+              M4OSA_NULL, M4OSA_NULL, M4OSA_NULL, M4OSA_NULL };
+
+    // Initialize the OSAL file system function pointers.
+    videoEditOsal_getFilePointers(&fileReadPtr , &fileWritePtr);
+
+    // Log the API call.
+    VIDEOEDIT_LOG_API(
+            ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",\
+            "getClipProperties - M4MCS_init()");
+
+    // Initialize the MCS context.
+    result = M4MCS_init(&context, &fileReadPtr, &fileWritePtr);
+
+    // Log the result.
+    VIDEOEDIT_PROP_LOG_RESULT(
+            ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
+            videoEditOsal_getResultString(result));
+
+    // Check if the creation succeeded.
+    videoEditJava_checkAndThrowRuntimeException(
+            &gotten, pEnv, (M4NO_ERROR != result), result);
+
+    // Check if opening the MCS context succeeded.
+    if (gotten)
+    {
+        // Log the API call.
+        VIDEOEDIT_LOG_API(
+                ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
+                "getClipProperties - M4MCS_open_normalMode()");
+
+        // Open the MCS in the normal opening mode to
+        // retrieve the exact duration
+        result = M4MCS_open_normalMode(
+                context, pFile, clipType, M4OSA_NULL, M4OSA_NULL);
+
+        // Log the result.
+        VIDEOEDIT_PROP_LOG_RESULT(
+                ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
+                videoEditOsal_getResultString(result));
+
+        // Check if the creation succeeded.
+        videoEditJava_checkAndThrowRuntimeException(
+                &gotten, pEnv, (M4NO_ERROR != result), result);
+
+        // Check if the MCS could be opened.
+        if (gotten)
+        {
+            // Log the API call.
+            VIDEOEDIT_LOG_API(
+                    ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
+                    "getClipProperties - M4MCS_getInputFileProperties()");
+
+            // Get the properties.
+            result = M4MCS_getInputFileProperties(context, pClipProperties);
+
+            // Log the result.
+            VIDEOEDIT_PROP_LOG_RESULT(
+                    ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
+                    videoEditOsal_getResultString(result));
+
+            // Check if the creation succeeded.
+            videoEditJava_checkAndThrowRuntimeException(
+                    &gotten, pEnv, (M4NO_ERROR != result), result);
+        }
+
+        // Log the API call.
+        VIDEOEDIT_LOG_API(
+                ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
+                "getClipProperties - M4MCS_abort()");
+
+        // Close the MCS session.
+        resultAbort = M4MCS_abort(context);
+
+       if (result == M4NO_ERROR) {
+            // Log the result.
+            VIDEOEDIT_PROP_LOG_RESULT(
+                    ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
+                    videoEditOsal_getResultString(resultAbort));
+
+            // Check if the abort succeeded.
+            videoEditJava_checkAndThrowRuntimeException(
+                    &gotten, pEnv, (M4NO_ERROR != resultAbort), resultAbort);
+            result = resultAbort;
+        }
+    }
+
+    return result;
+}
+
+M4OSA_UInt32
+VideoEdit_chrCompare(M4OSA_Char* pStrIn1,
+                     M4OSA_Char* pStrIn2,
+                      M4OSA_Int32* pCmpResult)
+{
+    M4OSA_chrCompare(pStrIn1, pStrIn2, pCmpResult);
+    return *pCmpResult;
+}
+
+
diff --git a/media/jni/mediaeditor/VideoEditorThumbnailMain.cpp b/media/jni/mediaeditor/VideoEditorThumbnailMain.cpp
new file mode 100755
index 0000000..b1f9fe4
--- /dev/null
+++ b/media/jni/mediaeditor/VideoEditorThumbnailMain.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2011 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 <jni.h>
+#include <JNIHelp.h>
+#include <utils/Log.h>
+#include "VideoBrowserMain.h"
+#include "VideoBrowserInternal.h"
+
+#if (M4OSA_TRACE_LEVEL >= 1)
+#undef M4OSA_TRACE1_0
+#undef M4OSA_TRACE1_1
+#undef M4OSA_TRACE1_2
+#undef M4OSA_TRACE1_3
+
+#define M4OSA_TRACE1_0(a)       __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a);
+#define M4OSA_TRACE1_1(a,b)     __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a,b);
+#define M4OSA_TRACE1_2(a,b,c)   __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a,b,c);
+#define M4OSA_TRACE1_3(a,b,c,d) __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a,b,c,d);
+#endif
+
+/*
+ * Memory format of 'ARGB8888' in skia is RGBA, so ABGR in 32bit little-endian packed format
+ * bitmap format is rgb565
+ */
+//                                RED                 GREEN               BLUE            ALPHA
+#define RGB565toSKCOLOR(c) ( (((c)&0xF800)>>8) | (((c)&0x7E0)<<5) | (((c)&0x1F)<<19) | 0xFF000000)
+
+#define GetIntField(env, obj, name) env->GetIntField(obj,\
+env->GetFieldID(env->GetObjectClass(obj), name, "I"))
+
+extern "C" M4OSA_ERR NXPSW_FileReaderOptim_init(M4OSA_Void *lowLevel_functionPointers,
+        M4OSA_Void *optimized_functionPointers);
+
+/*
+ * Video Browser execution context.
+ * Based on request for RGB565 or RGB888, m_dst16 or m_dst32
+ * will be initialized and used
+ */
+typedef struct
+{
+    M4OSA_Context       m_pVideoBrowser;
+    M4OSA_UInt32        m_previousTime;
+    M4OSA_Int32*        m_dst32;
+    M4OSA_Int16*        m_dst16;
+    unsigned int        m_width;
+    unsigned int        m_height;
+    M4OSA_Bool          m_bRender;
+} ThumbnailContext;
+
+/**
+ ************************************************************************
+ * @brief    Interface to retrieve the thumbnail pixels
+ * @param    pContext   (IN)    Thumbnail Context.
+ * @param    width      (IN)    Width of thumbnail
+ * @param    height     (IN)    Height of thumbnail
+ * @param    pTimeMS    (IN/OUT)Time stamp at which thumbnail is retrieved.
+ ************************************************************************
+*/
+M4OSA_ERR ThumbnailGetPixels(const M4OSA_Context pContext,
+                             M4OSA_Int32* pixelArray,
+                             M4OSA_UInt32 width, M4OSA_UInt32 height,
+                             M4OSA_UInt32* pTimeMS);
+
+
+/**
+ ************************************************************************
+ * @brief    Video browser callback, called when a frame must be displayed
+ * @param    pInstance          (IN) Thumbnail context.
+ * @param    notificationID     (IN) Id of the callback which generated the error
+ * @param    errCode            (IN) Error code from the Core
+ * @param    pCbData            (IN) pointer to data associated wit the callback.
+ * @param    pCbUserData        (IN) pointer to application user data passed in init.
+ * @note     This callback mechanism is used to request display of an image
+ ************************************************************************
+*/
+M4OSA_Void VBcallback(  M4OSA_Context  pInstance,
+                        VideoBrowser_Notification notificationID,
+                        M4OSA_ERR errCode, M4OSA_Void* pCbData,
+                        M4OSA_Void* pCallbackUserData)
+{
+    M4OSA_UInt32 i, j;
+    M4OSA_ERR err;
+
+    M4OSA_TRACE3_0("inside VBcallback");
+    M4VIFI_ImagePlane* pPlane=NULL;
+    M4OSA_UInt16* src=NULL;
+    ThumbnailContext* pC = NULL;
+
+    CHECK_PTR(VBcallback, pCbData, err, M4ERR_PARAMETER);
+    CHECK_PTR(VBcallback, pInstance,err, M4ERR_PARAMETER);
+
+    pC = (ThumbnailContext*)pCallbackUserData ;
+    CHECK_PTR(VBcallback, pC->m_pVideoBrowser, err, M4ERR_PARAMETER);
+
+    pPlane = (M4VIFI_ImagePlane*)pCbData;
+    src = (M4OSA_UInt16*)pPlane->pac_data;
+
+    if (pC->m_dst32 != NULL)
+    {
+        M4OSA_Int32* dst = pC->m_dst32;
+
+        for (j = 0; j < pPlane->u_height; j++)
+        {
+            for (i = 0; i < pPlane->u_width; i++)
+            {
+                dst[i] = RGB565toSKCOLOR(src[i]);
+            }
+            for (i = pPlane->u_width; i < pC->m_width; i++)
+            {
+                dst[i] = 0;
+            }
+            src = (M4OSA_UInt16*)((M4OSA_UInt8*)src + pPlane->u_stride);
+            dst += pC->m_width;
+        }
+    }
+    else if (pC->m_dst16 != NULL)
+    {
+        M4OSA_Int16* dst = pC->m_dst16;
+
+        for (j = 0; j < pPlane->u_height; j++)
+        {
+            M4OSA_memcpy((M4OSA_MemAddr8 )dst, (M4OSA_MemAddr8 )src, pPlane->u_stride);
+            for (i = pPlane->u_width; i < pC->m_width; i++)
+            {
+                dst[i] = 0;
+            }
+            src = (M4OSA_UInt16*)((M4OSA_UInt8*)src + pPlane->u_stride);
+            dst += pC->m_width;
+        }
+    }
+    else
+    {
+        CHECK_PTR(VBcallback, NULL, err, M4ERR_PARAMETER);
+    }
+
+VBcallback_cleanUp:
+
+    return;
+}
+
+M4OSA_ERR ThumbnailOpen(M4OSA_Context *pPContext,
+                  const M4OSA_Char *pString,
+                  M4OSA_Bool bRender)
+{
+
+    M4OSA_ERR err;
+    ThumbnailContext *pContext = M4OSA_NULL;
+    VideoBrowser_VideoColorType vbColorType;
+
+    CHECK_PTR(ThumbnailOpen, pString, err, M4ERR_BAD_CONTEXT);
+
+    /*--- Create context ---*/
+    pContext = (ThumbnailContext*)M4OSA_malloc(sizeof(ThumbnailContext), VIDEOBROWSER,
+        (M4OSA_Char*)"Thumbnail context") ;
+    M4OSA_TRACE3_1("context value is = %d",pContext);
+    CHECK_PTR(ThumbnailOpen, pContext, err, M4ERR_ALLOC);
+
+    M4OSA_memset((M4OSA_MemAddr8)pContext, sizeof(ThumbnailContext), 0);
+
+    M4OSA_FileReadPointer optFP;
+    M4OSA_FileReadPointer llFP;
+
+    NXPSW_FileReaderOptim_init(&llFP, &optFP);
+    M4OSA_TRACE1_2("ThumbnailOpen: entering videoBrowserCreate with 0x%x %s",
+        &pContext->m_pVideoBrowser, pString) ;
+
+    pContext->m_bRender = bRender;
+    if (bRender == M4OSA_TRUE) {
+        //Open is called for rendering the frame.
+        //So set YUV420 as the output color format.
+        vbColorType = VideoBrowser_kYUV420;
+    } else {
+        //Open is called for thumbnail Extraction
+        //So set BGR565 as the output.
+        vbColorType = VideoBrowser_kGB565;
+    }
+
+    err = videoBrowserCreate(&pContext->m_pVideoBrowser, (M4OSA_Char*)pString,
+        VideoBrowser_kVBNormalBliting, &optFP, VBcallback, pContext, vbColorType);
+
+    M4OSA_TRACE1_1("err value is = 0x%x",err);
+    CHECK_ERR(ThumbnailOpen, err);
+    CHECK_PTR(ThumbnailOpen, pContext->m_pVideoBrowser, err, M4ERR_ALLOC);
+
+    *pPContext = pContext;
+    M4OSA_TRACE1_1("context value is = %d",*pPContext);
+
+    return M4NO_ERROR;
+
+ThumbnailOpen_cleanUp:
+
+    M4OSA_TRACE1_0("i am inside cleanUP");
+    if (M4OSA_NULL != pContext)
+    {
+        if (M4OSA_NULL != pContext->m_pVideoBrowser)
+        {
+            videoBrowserCleanUp(pContext->m_pVideoBrowser) ;
+        }
+        M4OSA_free((M4OSA_MemAddr32)pContext) ;
+    }
+    return err;
+}
+
+M4OSA_ERR ThumbnailGetPixels(const M4OSA_Context pContext,
+                             M4OSA_Int32* pixelArray,
+                             M4OSA_UInt32 width, M4OSA_UInt32 height,
+                             M4OSA_UInt32* pTimeMS)
+{
+    M4OSA_ERR err;
+
+    ThumbnailContext* pC = (ThumbnailContext*)pContext;
+
+    if ((pC->m_width != width) || (pC->m_height != height))
+    {
+        err = videoBrowserSetWindow(pC->m_pVideoBrowser, pixelArray,
+                                      0, 0, width, height);
+        CHECK_ERR(ThumbnailGetPixels, err);
+        pC->m_width  = width;
+        pC->m_height = height;
+    }
+
+    // Alter the pTimeMS to a valid value at which a frame is found
+    // m_currentCTS has the actual frame time stamp just ahead of the
+    // pTimeMS supplied.
+    if ((((VideoBrowserContext*)pC->m_pVideoBrowser)->m_currentCTS != 0) &&
+        (*pTimeMS >= pC->m_previousTime) &&
+        (*pTimeMS < ((VideoBrowserContext*)pC->m_pVideoBrowser)->m_currentCTS))
+    {
+        pC->m_previousTime = *pTimeMS;
+        *pTimeMS = ((VideoBrowserContext*)pC->m_pVideoBrowser)->m_currentCTS;
+    }
+    else
+    {
+        pC->m_previousTime = *pTimeMS;
+    }
+
+    err = videoBrowserPrepareFrame(pC->m_pVideoBrowser, pTimeMS);
+    CHECK_ERR(ThumbnailGetPixels, err);
+
+    if (pC->m_bRender != M4OSA_TRUE) {
+        err = videoBrowserDisplayCurrentFrame(pC->m_pVideoBrowser);
+        CHECK_ERR(ThumbnailGetPixels, err);
+    }
+
+ThumbnailGetPixels_cleanUp:
+
+    return err;
+}
+
+M4OSA_ERR ThumbnailGetPixels32(const M4OSA_Context pContext,
+                         M4OSA_Int32* pixelArray, M4OSA_UInt32 width,
+                         M4OSA_UInt32 height, M4OSA_UInt32* timeMS)
+{
+
+    M4OSA_ERR err = M4NO_ERROR;
+
+    ThumbnailContext* pC = (ThumbnailContext*)pContext;
+
+    CHECK_PTR(ThumbnailGetPixels32, pC->m_pVideoBrowser, err, M4ERR_ALLOC) ;
+    CHECK_PTR(ThumbnailGetPixels32, pixelArray, err, M4ERR_ALLOC) ;
+
+    pC->m_dst16 = NULL;
+    pC->m_dst32 = pixelArray;
+
+    err = ThumbnailGetPixels(pContext, pixelArray, width, height, timeMS);
+
+ThumbnailGetPixels32_cleanUp:
+
+    return err;
+}
+
+M4OSA_ERR ThumbnailGetPixels16(const M4OSA_Context pContext,
+                         M4OSA_Int16* pixelArray, M4OSA_UInt32 width,
+                         M4OSA_UInt32 height, M4OSA_UInt32* timeMS)
+{
+    M4OSA_ERR err = M4NO_ERROR;
+
+    ThumbnailContext* pC = (ThumbnailContext*)pContext;
+
+    CHECK_PTR(ThumbnailGetPixels16, pC->m_pVideoBrowser, err, M4ERR_ALLOC);
+    CHECK_PTR(ThumbnailGetPixels16, pixelArray, err, M4ERR_ALLOC);
+
+    pC->m_dst16 = pixelArray;
+    pC->m_dst32 = NULL;
+
+    err = ThumbnailGetPixels(pContext, (M4OSA_Int32*)pixelArray, width, height, timeMS);
+
+ThumbnailGetPixels16_cleanUp:
+
+    return err;
+}
+
+
+void ThumbnailClose(const M4OSA_Context pContext)
+{
+    M4OSA_ERR err;
+
+    ThumbnailContext* pC = (ThumbnailContext*)pContext;
+
+    CHECK_PTR(ThumbnailClose, pC, err, M4ERR_ALLOC);
+
+    if (M4OSA_NULL != pC)
+    {
+        if (M4OSA_NULL != pC->m_pVideoBrowser)
+        {
+            videoBrowserCleanUp(pC->m_pVideoBrowser);
+        }
+        M4OSA_free((M4OSA_MemAddr32)pC);
+    }
+
+ThumbnailClose_cleanUp:
+
+    return;
+}
+
diff --git a/media/jni/mediaeditor/VideoEditorThumbnailMain.h b/media/jni/mediaeditor/VideoEditorThumbnailMain.h
new file mode 100755
index 0000000..14c60dd
--- /dev/null
+++ b/media/jni/mediaeditor/VideoEditorThumbnailMain.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 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 VIDEOEDITOR_THUMBNAIL_MAIN_H
+#define VIDEOEDITOR_THUMBNAIL_MAIN_H
+
+/**
+ ************************************************************************
+ * @file        VideoEditorThumbnailMain.h
+ * @brief       Thumbnail extract interface.
+ ************************************************************************
+*/
+
+/**
+ ************************************************************************
+ * @brief    Interface to open a Thumbnail session.
+ * @param    pContext   (OUT)   Thumbnail Context.
+ * @param    pString    (IN)    File path from which thumbnail will be
+ *                              retrieved
+ * @param    M4OSA_Bool (IN)    true if this is for rendering at native layer.
+ ************************************************************************
+*/
+M4OSA_ERR ThumbnailOpen(M4OSA_Context *pPContext,
+                  const M4OSA_Char *pString,
+                  M4OSA_Bool bRender);
+
+/**
+ ************************************************************************
+ * @brief    Interface to retrieve a RGB888 format thumbnail pixels
+ * @param    pContext   (IN)    Thumbnail Context.
+ * @param    pixelArray (OUT)   Pointer to array in which pixels data to return
+ * @param    width      (IN)    Width of thumbnail
+ * @param    height     (IN)    Height of thumbnail
+ * @param    pTimeMS    (IN/OUT)Time stamp at which thumbnail is retrieved.
+ ************************************************************************
+*/
+M4OSA_ERR ThumbnailGetPixels32(const M4OSA_Context pContext,
+                             M4OSA_Int32* pixelArray, M4OSA_UInt32 width,
+                             M4OSA_UInt32 height, M4OSA_UInt32 *timeMS);
+
+/**
+ ************************************************************************
+ * @brief    Interface to retrieve a RGB565 format thumbnail pixels
+ * @param    pContext   (IN)    Thumbnail Context.
+ * @param    pixelArray (OUT)   Pointer to array in which pixcel data to return
+ * @param    width      (IN)    Width of thumbnail
+ * @param    height     (IN)    Height of thumbnail
+ * @param    pTimeMS    (IN/OUT)Time stamp at which thumbnail is retrieved.
+ ************************************************************************
+*/
+M4OSA_ERR ThumbnailGetPixels16(const M4OSA_Context pContext,
+                             M4OSA_Int16* pixelArray, M4OSA_UInt32 width,
+                             M4OSA_UInt32 height, M4OSA_UInt32 *timeMS);
+
+/**
+ ************************************************************************
+ * @brief    Interface to close the Thumbnail session.
+ * @param    pContext   (IN)    Thumbnail Context.
+ ************************************************************************
+*/
+void ThumbnailClose(const M4OSA_Context pContext);
+
+#endif // VIDEOEDITOR_THUMBNAIL_MAIN_H
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 9ce6738..af67175 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -5,6 +5,7 @@
 #include <binder/IMemory.h>
 #include <binder/Parcel.h>
 #include <media/IOMX.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <surfaceflinger/ISurface.h>
 #include <surfaceflinger/Surface.h>
 
@@ -449,74 +450,8 @@
         }
 
         case GET_PARAMETER:
-        {
-            CHECK_INTERFACE(IOMX, data, reply);
-
-            node_id node = (void*)data.readIntPtr();
-            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
-
-            size_t size = data.readInt32();
-
-            // XXX I am not happy with this but Parcel::readInplace didn't work.
-            void *params = malloc(size);
-            data.read(params, size);
-
-            status_t err = getParameter(node, index, params, size);
-
-            reply->writeInt32(err);
-
-            if (err == OK) {
-                reply->write(params, size);
-            }
-
-            free(params);
-            params = NULL;
-
-            return NO_ERROR;
-        }
-
         case SET_PARAMETER:
-        {
-            CHECK_INTERFACE(IOMX, data, reply);
-
-            node_id node = (void*)data.readIntPtr();
-            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
-
-            size_t size = data.readInt32();
-            void *params = const_cast<void *>(data.readInplace(size));
-
-            reply->writeInt32(setParameter(node, index, params, size));
-
-            return NO_ERROR;
-        }
-
         case GET_CONFIG:
-        {
-            CHECK_INTERFACE(IOMX, data, reply);
-
-            node_id node = (void*)data.readIntPtr();
-            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
-
-            size_t size = data.readInt32();
-
-            // XXX I am not happy with this but Parcel::readInplace didn't work.
-            void *params = malloc(size);
-            data.read(params, size);
-
-            status_t err = getConfig(node, index, params, size);
-
-            reply->writeInt32(err);
-
-            if (err == OK) {
-                reply->write(params, size);
-            }
-
-            free(params);
-            params = NULL;
-
-            return NO_ERROR;
-        }
-
         case SET_CONFIG:
         {
             CHECK_INTERFACE(IOMX, data, reply);
@@ -525,9 +460,36 @@
             OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
 
             size_t size = data.readInt32();
-            void *params = const_cast<void *>(data.readInplace(size));
 
-            reply->writeInt32(setConfig(node, index, params, size));
+            void *params = malloc(size);
+            data.read(params, size);
+
+            status_t err;
+            switch (code) {
+                case GET_PARAMETER:
+                    err = getParameter(node, index, params, size);
+                    break;
+                case SET_PARAMETER:
+                    err = setParameter(node, index, params, size);
+                    break;
+                case GET_CONFIG:
+                    err = getConfig(node, index, params, size);
+                    break;
+                case SET_CONFIG:
+                    err = setConfig(node, index, params, size);
+                    break;
+                default:
+                    TRESPASS();
+            }
+
+            reply->writeInt32(err);
+
+            if ((code == GET_PARAMETER || code == GET_CONFIG) && err == OK) {
+                reply->write(params, size);
+            }
+
+            free(params);
+            params = NULL;
 
             return NO_ERROR;
         }
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 992abd7..153b2a6 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1229,23 +1229,13 @@
     }
     if (mVideoEncoderLevel != -1) {
         enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
-    } else if (mCaptureTimeLapse) {
-        // Check if we are using high resolution and/or high bitrate and
-        // set appropriate level for the software AVCEncoder.
-        if ((width * height >= 921600) // 720p
-                || (videoBitRate >= 20000000)) {
-            enc_meta->setInt32(kKeyVideoLevel, OMX_VIDEO_AVCLevel5);
-        }
     }
 
     OMXClient client;
     CHECK_EQ(client.connect(), OK);
 
-    // Use software codec for time lapse
     uint32_t encoder_flags = 0;
-    if (mCaptureTimeLapse) {
-        encoder_flags |= OMXCodec::kPreferSoftwareCodecs;
-    } else if (mIsMetaDataStoredInVideoBuffers) {
+    if (mIsMetaDataStoredInVideoBuffers) {
         encoder_flags |= OMXCodec::kHardwareCodecsOnly;
         encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
     }
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 4cfe28e..58c4a2e 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -165,6 +165,8 @@
       mTimeSource(NULL),
       mVideoRendererIsPreview(false),
       mAudioPlayer(NULL),
+      mDisplayWidth(0),
+      mDisplayHeight(0),
       mFlags(0),
       mExtractorFlags(0),
       mVideoBuffer(NULL),
@@ -329,6 +331,18 @@
         if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
             setVideoSource(extractor->getTrack(i));
             haveVideo = true;
+
+            // Set the presentation/display size
+            int32_t displayWidth, displayHeight;
+            bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth);
+            if (success) {
+                success = meta->findInt32(kKeyDisplayHeight, &displayHeight);
+            }
+            if (success) {
+                mDisplayWidth = displayWidth;
+                mDisplayHeight = displayHeight;
+            }
+
         } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
             setAudioSource(extractor->getTrack(i));
             haveAudio = true;
@@ -370,6 +384,8 @@
 
 void AwesomePlayer::reset_l() {
     LOGI("reset_l");
+    mDisplayWidth = 0;
+    mDisplayHeight = 0;
 
     if (mDecryptHandle != NULL) {
             mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
@@ -520,8 +536,10 @@
         *durationUs = mRTSPController->getQueueDurationUs(eos);
         return true;
     } else if (mCachedSource != NULL && getBitrate(&bitrate)) {
-        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
+        status_t finalStatus;
+        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
         *durationUs = cachedDataRemaining * 8000000ll / bitrate;
+        *eos = (finalStatus != OK);
         return true;
     }
 
@@ -564,11 +582,14 @@
     mBufferingEventPending = false;
 
     if (mCachedSource != NULL) {
-        bool eos;
-        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
+        status_t finalStatus;
+        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
+        bool eos = (finalStatus != OK);
 
         if (eos) {
-            notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
+            if (finalStatus == ERROR_END_OF_STREAM) {
+                notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
+            }
             if (mFlags & PREPARING) {
                 LOGV("cache has reached EOS, prepare is done.");
                 finishAsyncPrepare_l();
@@ -857,6 +878,12 @@
 
     int32_t usableWidth = cropRight - cropLeft + 1;
     int32_t usableHeight = cropBottom - cropTop + 1;
+    if (mDisplayWidth != 0) {
+        usableWidth = mDisplayWidth;
+    }
+    if (mDisplayHeight != 0) {
+        usableHeight = mDisplayHeight;
+    }
 
     int32_t rotationDegrees;
     if (!mVideoTrack->getFormat()->findInt32(
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 31b6ec9..b58b9d8 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -66,7 +66,7 @@
         int32_t videoFrameRate,
         const sp<Surface>& surface,
         int64_t timeBetweenTimeLapseFrameCaptureUs)
-    : CameraSource(camera, cameraId, videoSize, videoFrameRate, surface, false),
+    : CameraSource(camera, cameraId, videoSize, videoFrameRate, surface, true),
       mTimeBetweenTimeLapseFrameCaptureUs(timeBetweenTimeLapseFrameCaptureUs),
       mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate),
       mLastTimeLapseFrameRealTimestampUs(0),
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index e7f00aa..057868c 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -25,13 +25,14 @@
 #include <arpa/inet.h>
 #include <ctype.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 
 namespace android {
 
@@ -47,6 +48,82 @@
     disconnect();
 }
 
+static bool MakeSocketBlocking(int s, bool blocking) {
+    // Make socket non-blocking.
+    int flags = fcntl(s, F_GETFL, 0);
+    if (flags == -1) {
+        return false;
+    }
+
+    if (blocking) {
+        flags &= ~O_NONBLOCK;
+    } else {
+        flags |= O_NONBLOCK;
+    }
+
+    return fcntl(s, F_SETFL, flags) != -1;
+}
+
+static status_t MyConnect(
+        int s, const struct sockaddr *addr, socklen_t addrlen) {
+    status_t result = UNKNOWN_ERROR;
+
+    MakeSocketBlocking(s, false);
+
+    if (connect(s, addr, addrlen) == 0) {
+        result = OK;
+    } else if (errno != EINPROGRESS) {
+        result = -errno;
+    } else {
+        for (;;) {
+            fd_set rs, ws;
+            FD_ZERO(&rs);
+            FD_ZERO(&ws);
+            FD_SET(s, &rs);
+            FD_SET(s, &ws);
+
+            struct timeval tv;
+            tv.tv_sec = 0;
+            tv.tv_usec = 100000ll;
+
+            int nfds = ::select(s + 1, &rs, &ws, NULL, &tv);
+
+            if (nfds < 0) {
+                if (errno == EINTR) {
+                    continue;
+                }
+
+                result = -errno;
+                break;
+            }
+
+            if (FD_ISSET(s, &ws) && !FD_ISSET(s, &rs)) {
+                result = OK;
+                break;
+            }
+
+            if (FD_ISSET(s, &rs) || FD_ISSET(s, &ws)) {
+                // Get the pending error.
+                int error = 0;
+                socklen_t errorLen = sizeof(error);
+                if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &errorLen) == -1) {
+                    // Couldn't get the real error, so report why not.
+                    result = -errno;
+                } else {
+                    result = -error;
+                }
+                break;
+            }
+
+            // Timeout expired. Try again.
+        }
+    }
+
+    MakeSocketBlocking(s, true);
+
+    return result;
+}
+
 status_t HTTPStream::connect(const char *server, int port) {
     Mutex::Autolock autoLock(mLock);
 
@@ -82,7 +159,7 @@
     addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
     memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
 
-    int res = ::connect(s, (const struct sockaddr *)&addr, sizeof(addr));
+    status_t res = MyConnect(s, (const struct sockaddr *)&addr, sizeof(addr));
 
     mLock.lock();
 
@@ -90,12 +167,12 @@
         return UNKNOWN_ERROR;
     }
 
-    if (res < 0) {
+    if (res != OK) {
         close(mSocket);
         mSocket = -1;
 
         mState = READY;
-        return UNKNOWN_ERROR;
+        return res;
     }
 
     mState = CONNECTED;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index bafa243..e6e98aa 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1040,8 +1040,23 @@
             // have a 4 byte header (0x00 0x00 0x00 0x01) after conversion,
             // and thus will grow by 2 bytes per fragment.
             mLastTrack->meta->setInt32(kKeyMaxInputSize, max_size + 10 * 2);
-
             *offset += chunk_size;
+
+            // Calculate average frame rate.
+            const char *mime;
+            CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
+            if (!strncasecmp("video/", mime, 6)) {
+                size_t nSamples = mLastTrack->sampleTable->countSamples();
+                int64_t durationUs;
+                if (mLastTrack->meta->findInt64(kKeyDuration, &durationUs)) {
+                    if (durationUs > 0) {
+                        int32_t frameRate = (nSamples * 1000000LL +
+                                    (durationUs >> 1)) / durationUs;
+                        mLastTrack->meta->setInt32(kKeyFrameRate, frameRate);
+                    }
+                }
+            }
+
             break;
         }
 
@@ -1321,10 +1336,12 @@
         mLastTrack->meta->setInt32(kKeyRotation, rotationDegrees);
     }
 
-#if 0
+    // Handle presentation display size, which could be different
+    // from the image size indicated by kKeyWidth and kKeyHeight.
     uint32_t width = U32_AT(&buffer[dynSize + 52]);
     uint32_t height = U32_AT(&buffer[dynSize + 56]);
-#endif
+    mLastTrack->meta->setInt32(kKeyDisplayWidth, width >> 16);
+    mLastTrack->meta->setInt32(kKeyDisplayHeight, height >> 16);
 
     return OK;
 }
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 9017921..20f1655 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -393,13 +393,13 @@
     return mCacheOffset + mCache->totalSize();
 }
 
-size_t NuCachedSource2::approxDataRemaining(bool *eos) {
+size_t NuCachedSource2::approxDataRemaining(status_t *finalStatus) {
     Mutex::Autolock autoLock(mLock);
-    return approxDataRemaining_l(eos);
+    return approxDataRemaining_l(finalStatus);
 }
 
-size_t NuCachedSource2::approxDataRemaining_l(bool *eos) {
-    *eos = (mFinalStatus != OK);
+size_t NuCachedSource2::approxDataRemaining_l(status_t *finalStatus) {
+    *finalStatus = mFinalStatus;
     off64_t lastBytePosCached = mCacheOffset + mCache->totalSize();
     if (mLastAccessPos < lastBytePosCached) {
         return lastBytePosCached - mLastAccessPos;
@@ -488,4 +488,3 @@
     return mSource->getUri();
 }
 }  // namespace android
-
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index e516cb4..d842f65 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -2233,7 +2233,11 @@
                 enablePortAsync(portIndex);
 
                 status_t err = allocateBuffersOnPort(portIndex);
-                CHECK_EQ(err, (status_t)OK);
+
+                if (err != OK) {
+                    CODEC_LOGE("allocateBuffersOnPort failed (err = %d)", err);
+                    setState(ERROR);
+                }
             }
             break;
         }
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 5979be6..e731080 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -493,8 +493,14 @@
 
     CHECK(buffer != NULL);
 
-    CHECK_EQ((status_t)OK,
-             decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer));
+    err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer);
+
+    if (err != OK) {
+        LOGE("decryptBuffer failed w/ error %d", err);
+
+        mDataSource->queueEOS(err);
+        return;
+    }
 
     if (buffer->size() == 0 || buffer->data()[0] != 0x47) {
         // Not a transport stream???
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 130ad82..41ef181 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -100,6 +100,7 @@
 
 private:
     friend struct AwesomeEvent;
+    friend struct PreviewPlayer;
 
     enum {
         PLAYING             = 1,
@@ -149,6 +150,9 @@
     AudioPlayer *mAudioPlayer;
     int64_t mDurationUs;
 
+    int32_t mDisplayWidth;
+    int32_t mDisplayHeight;
+
     uint32_t mFlags;
     uint32_t mExtractorFlags;
     uint32_t mSinceLastDropped;
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index aa320fc..28840be 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -43,7 +43,7 @@
     ////////////////////////////////////////////////////////////////////////////
 
     size_t cachedSize();
-    size_t approxDataRemaining(bool *eos);
+    size_t approxDataRemaining(status_t *finalStatus);
 
     void resumeFetchingIfNecessary();
 
@@ -92,7 +92,7 @@
     ssize_t readInternal(off64_t offset, void *data, size_t size);
     status_t seekInternal_l(off64_t offset);
 
-    size_t approxDataRemaining_l(bool *eos);
+    size_t approxDataRemaining_l(status_t *finalStatus);
     void restartPrefetcherIfNecessary_l(bool ignoreLowWaterThreshold = false);
 
     DISALLOW_EVIL_CONSTRUCTORS(NuCachedSource2);
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 10cc88b..f0b858d 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -373,7 +373,17 @@
         br.skipBits(2);  // chroma_format
         br.skipBits(1);  // low_delay
         if (br.getBits(1)) {  // vbv_parameters
-            TRESPASS();
+            br.skipBits(15);  // first_half_bit_rate
+            CHECK(br.getBits(1));  // marker_bit
+            br.skipBits(15);  // latter_half_bit_rate
+            CHECK(br.getBits(1));  // marker_bit
+            br.skipBits(15);  // first_half_vbv_buffer_size
+            CHECK(br.getBits(1));  // marker_bit
+            br.skipBits(3);  // latter_half_vbv_buffer_size
+            br.skipBits(11);  // first_half_vbv_occupancy
+            CHECK(br.getBits(1));  // marker_bit
+            br.skipBits(15);  // latter_half_vbv_occupancy
+            CHECK(br.getBits(1));  // marker_bit
         }
     }
     unsigned video_object_layer_shape = br.getBits(2);
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
index 6dcb931..4d9a1ae 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -42,7 +42,6 @@
     virtual void                    endSendObject(const char* path,
                                             MtpObjectHandle handle,
                                             MtpObjectFormat format,
-                                            int64_t size,
                                             bool succeeded) = 0;
 
     virtual MtpObjectHandleList*    getObjectList(MtpStorageID storageID,
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 236cd0a..b1bd145 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -700,6 +700,9 @@
         if (ret && ret != -EEXIST)
             return MTP_RESPONSE_GENERAL_ERROR;
         chown((const char *)path, getuid(), mFileGroup);
+
+        // SendObject does not get sent for directories, so call endSendObject here instead
+        mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
     } else {
         mSendObjectFilePath = path;
         // save the handle for the SendObject call, which should follow
@@ -718,7 +721,6 @@
     MtpResponseCode result = MTP_RESPONSE_OK;
     mode_t mask;
     int ret;
-    uint64_t actualSize = -1;
 
     if (mSendObjectHandle == kInvalidObjectHandle) {
         LOGE("Expected SendObjectInfo before SendObject");
@@ -761,18 +763,11 @@
             result = MTP_RESPONSE_TRANSACTION_CANCELLED;
         else
             result = MTP_RESPONSE_GENERAL_ERROR;
-    } else if (mSendObjectFileSize == 0xFFFFFFFF) {
-        // actual size is likely > 4 gig so stat the file to compute actual length
-        struct stat s;
-        if (lstat(mSendObjectFilePath, &s) == 0) {
-            actualSize = s.st_size;
-            LOGD("actualSize: %lld\n", actualSize);
-        }
     }
 
 done:
     mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
-            actualSize, result == MTP_RESPONSE_OK);
+            result == MTP_RESPONSE_OK);
     mSendObjectHandle = kInvalidObjectHandle;
     mSendObjectFormat = 0;
     return result;
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 8f2f974..32d1a23 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -272,6 +272,35 @@
     }
 
     /**
+     * Control whether the EGL context is preserved when the GLSurfaceView is paused and
+     * resumed.
+     * <p>
+     * If set to true, then the EGL context may be preserved when the GLSurfaceView is paused.
+     * Whether the EGL context is actually preserved or not depends upon whether the
+     * Android device that the program is running on can support an arbitrary number of EGL
+     * contexts or not. Devices that can only support a limited number of EGL contexts must
+     * release the  EGL context in order to allow multiple applications to share the GPU.
+     * <p>
+     * If set to false, the EGL context will be released when the GLSurfaceView is paused,
+     * and recreated when the GLSurfaceView is resumed.
+     * <p>
+     *
+     * The default is false.
+     *
+     * @param preserveOnPause preserve the EGL context when paused
+     */
+    public void setPreserveEGLContextOnPause(boolean preserveOnPause) {
+        mPreserveEGLContextOnPause = preserveOnPause;
+    }
+
+    /**
+     * @return true if the EGL context will be preserved when paused
+     */
+    public boolean getPreserveEGLContextOnPause() {
+        return mPreserveEGLContextOnPause;
+    }
+
+    /**
      * Set the renderer associated with this view. Also starts the thread that
      * will call the renderer, which in turn causes the rendering to start.
      * <p>This method should be called once and only once in the life-cycle of
@@ -1240,7 +1269,7 @@
                                     Log.i("GLThread", "releasing EGL surface because paused tid=" + getId());
                                 }
                                 stopEglSurfaceLocked();
-                                if (sGLThreadManager.shouldReleaseEGLContextWhenPausing()) {
+                                if (!mPreserveEGLContextOnPause || sGLThreadManager.shouldReleaseEGLContextWhenPausing()) {
                                     stopEglContextLocked();
                                     if (LOG_SURFACE) {
                                         Log.i("GLThread", "releasing EGL context because paused tid=" + getId());
@@ -1705,7 +1734,7 @@
             // Release the EGL context when pausing even if
             // the hardware supports multiple EGL contexts.
             // Otherwise the device could run out of EGL contexts.
-            return true;
+            return mLimitedGLESContexts;
         }
 
         public synchronized boolean shouldTerminateEGLWhenPausing() {
@@ -1716,16 +1745,18 @@
         public synchronized void checkGLDriver(GL10 gl) {
             if (! mGLESDriverCheckComplete) {
                 checkGLESVersion();
+                String renderer = gl.glGetString(GL10.GL_RENDERER);
                 if (mGLESVersion < kGLES_20) {
-                    String renderer = gl.glGetString(GL10.GL_RENDERER);
                     mMultipleGLESContextsAllowed =
                         ! renderer.startsWith(kMSM7K_RENDERER_PREFIX);
-                    if (LOG_SURFACE) {
-                        Log.w(TAG, "checkGLDriver renderer = \"" + renderer + "\" multipleContextsAllowed = "
-                            + mMultipleGLESContextsAllowed);
-                    }
                     notifyAll();
                 }
+                mLimitedGLESContexts = !mMultipleGLESContextsAllowed || renderer.startsWith(kADRENO);
+                if (LOG_SURFACE) {
+                    Log.w(TAG, "checkGLDriver renderer = \"" + renderer + "\" multipleContextsAllowed = "
+                        + mMultipleGLESContextsAllowed
+                        + " mLimitedGLESContexts = " + mLimitedGLESContexts);
+                }
                 mGLESDriverCheckComplete = true;
             }
         }
@@ -1750,9 +1781,11 @@
         private int mGLESVersion;
         private boolean mGLESDriverCheckComplete;
         private boolean mMultipleGLESContextsAllowed;
+        private boolean mLimitedGLESContexts;
         private static final int kGLES_20 = 0x20000;
         private static final String kMSM7K_RENDERER_PREFIX =
             "Q3Dimension MSM7500 ";
+        private static final String kADRENO = "Adreno";
         private GLThread mEglOwner;
     }
 
@@ -1768,4 +1801,5 @@
     private GLWrapper mGLWrapper;
     private int mDebugFlags;
     private int mEGLContextClientVersion;
+    private boolean mPreserveEGLContextOnPause;
 }
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 2ec2226..21f77e3 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -190,6 +190,7 @@
                 while ((pkg=pm.nextPackageToClean(pkg)) != null) {
                     eraseFiles(Environment.getExternalStorageAppDataDirectory(pkg));
                     eraseFiles(Environment.getExternalStorageAppMediaDirectory(pkg));
+                    eraseFiles(Environment.getExternalStorageAppObbDirectory(pkg));
                 }
             } catch (RemoteException e) {
             }
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_pressed.png
index 993ea55..3359602 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_pressed.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 5f01f4d..b0eac55 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index aa98f7d..53c44c6 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 583044d..168d8af 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index ea5694d..1ff4a80 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index b95c6cb..969a7d8 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 4043c2e..cc741ee 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 39a462c..83f29ff 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 72373bb..068451e 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml b/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml
index f29259a..5c9c6fc 100644
--- a/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml
@@ -9,6 +9,8 @@
     <string name="status_bar_settings_rotation_lock" msgid="9125161825884157545">"Bloquear orient. de pant."</string>
     <!-- XL -->
     <string name="recent_tasks_app_label" msgid="5550538721034982973">"Google Apps"</string>
+    <!-- XL -->
+    <string name="bluetooth_tethered" msgid="8017158699581472359">"Bluetooth anclado"</string>
     <!-- XL xlarge -->
     <string name="status_bar_settings_signal_meter_disconnected" msgid="4866302415753953027">"Sin conexión a Internet"</string>
     <!-- XL xlarge -->
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 8013a19..da742e6 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 3acfb45..58046ab 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 0528d68..3c65051 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 1ce102a..cbb2eec 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 12308fb..d199d9a 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 411336a..3e60b8d 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index b82aa77..dbcd29d 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index db170ab..db87cd3 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index ca99d86..9d751795 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index f2d5621..34eb41f 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 25d8873..3b59844 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 6c5970a..35d7503 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 90a5e44..a5848a9 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index fb33329..cf81e85 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 82405a8..4d6140f 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 4efdcbb..339d146 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 07ef5ef..b50c422 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index aa14cce..01544b5 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 17be76a..35ffabb 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index e3fec88..7b94e9b 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -57,4 +57,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 2bb3c14..4e32019 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 89b9cc8..7a6a71e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 9716327..6b497b9 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index b05b93c..54145f2 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -32,8 +32,7 @@
     <string name="invalid_charger" msgid="4549105996740522523">"Polnjenje po povezavi USB ni podprto."\n"Uporabite priloženi polnilnik."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"Uporaba baterije"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavitve"</string>
-    <!-- no translation found for status_bar_settings_wifi_button (1733928151698311923) -->
-    <skip />
+    <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Način za letalo"</string>
     <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Zakleni usmerjenost zaslona"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"TIHO"</string>
@@ -45,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index ff1d3fb..6ee4009 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 06b6880..99623c3 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 2d337a90..7d154a6 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index e94d3cc..bb56bc2 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4c3f818..361d7ee 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 85ead1c..ae40e56 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 71df0c3..2ec07f1 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 0cdc38d..cb15613 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index c85020f..960130f 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -44,4 +44,6 @@
     <skip />
     <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
     <skip />
+    <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
index 69bc161..7012ddc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
@@ -188,6 +188,12 @@
                 Settings.Secure.INPUT_METHOD_SELECTOR_VISIBILITY, ID_IME_BUTTON_VISIBILITY_AUTO);
     }
 
+    public void setIconImage(int resId) {
+        if (mIcon != null) {
+            mIcon.setImageResource(resId);
+        }
+    }
+
     public void setIMEButtonVisible(IBinder token, boolean keyboardVisible) {
         mToken = token;
         mKeyboardVisible = keyboardVisible;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
index add67b1..cc200e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.os.IBinder;
 import android.provider.Settings;
@@ -53,11 +52,12 @@
                     new HashMap<InputMethodInfo, List<InputMethodSubtype>>();
     private final HashMap<View, Pair<InputMethodInfo, InputMethodSubtype>> mRadioViewAndImiMap =
             new HashMap<View, Pair<InputMethodInfo, InputMethodSubtype>>();
-    private final PackageManager mPackageManager;
 
     private Context mContext;
     private IBinder mToken;
+    private InputMethodButton mInputMethodSwitchButton;
     private LinearLayout mInputMethodMenuList;
+    private PackageManager mPackageManager;
     private String mEnabledInputMethodAndSubtypesCacheStr;
     private View mConfigureImeShortcut;
 
@@ -69,7 +69,6 @@
         super(context, attrs, defStyle);
         mContext = context;
         mImm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
-        mPackageManager = context.getPackageManager();
     }
 
     @Override
@@ -90,8 +89,17 @@
     @Override
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
-        if (visibility == View.VISIBLE && changedView == this) {
-            updateUiElements();
+        if (changedView == this) {
+            if (visibility == View.VISIBLE) {
+                updateUiElements();
+                if (mInputMethodSwitchButton != null) {
+                    mInputMethodSwitchButton.setIconImage(R.drawable.ic_sysbar_ime_pressed);
+                }
+            } else {
+                if (mInputMethodSwitchButton != null) {
+                    mInputMethodSwitchButton.setIconImage(R.drawable.ic_sysbar_ime);
+                }
+            }
         }
     }
 
@@ -180,6 +188,8 @@
         // TODO: Reuse subtype views.
         mInputMethodMenuList.removeAllViews();
         mRadioViewAndImiMap.clear();
+        mPackageManager = mContext.getPackageManager();
+
         HashMap<InputMethodInfo, List<InputMethodSubtype>> enabledIMIs
                 = getEnabledInputMethodAndSubtypeList();
         // TODO: Sort by alphabet and mode.
@@ -198,10 +208,14 @@
         updateRadioButtons();
     }
 
-    public void setIMEToken(IBinder token) {
+    public void setImeToken(IBinder token) {
         mToken = token;
     }
 
+    public void setImeSwitchButton(InputMethodButton imb) {
+        mInputMethodSwitchButton = imb;
+    }
+
     private void setInputMethodAndSubtype(InputMethodInfo imi, InputMethodSubtype subtype) {
         if (mToken != null) {
             mImm.setInputMethodAndSubtype(mToken, imi.getId(), subtype);
@@ -308,6 +322,10 @@
 
     private CharSequence getSubtypeName(InputMethodInfo imi, InputMethodSubtype subtype) {
         if (imi == null || subtype == null) return null;
+        if (DEBUG) {
+            Log.d(TAG, "Get text from: " + imi.getPackageName() + subtype.getNameResId()
+                    + imi.getServiceInfo().applicationInfo);
+        }
         // TODO: Change the language of subtype name according to subtype's locale.
         return mPackageManager.getText(
                 imi.getPackageName(), subtype.getNameResId(), imi.getServiceInfo().applicationInfo);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
index bab8ed3..7544f46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
@@ -297,7 +297,7 @@
 
     private Drawable getFullResDefaultActivityIcon() {
         return getFullResIcon(Resources.getSystem(),
-                com.android.internal.R.drawable.sym_def_app_icon);
+                com.android.internal.R.mipmap.sym_def_app_icon);
     }
 
     private Drawable getFullResIcon(Resources resources, int iconId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
index e864577..a67f915 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
@@ -120,7 +120,7 @@
                 mAltText.setVisibility(View.VISIBLE);
                 if (mClipping.getItemCount() > 0) {
                     // TODO: figure out how to visualize every kind of ClipData!
-                    mAltText.setText(mClipping.getItem(0).coerceToText(getContext()));
+                    mAltText.setText(mClipping.getItemAt(0).coerceToText(getContext()));
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 825877a..6db74d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -272,6 +272,7 @@
         mInputMethodsPanel.setVisibility(View.GONE);
         mInputMethodsPanel.setOnTouchListener(new TouchOutsideListener(
                 MSG_CLOSE_INPUT_METHODS_PANEL, mInputMethodsPanel));
+        mInputMethodsPanel.setImeSwitchButton(mInputMethodSwitchButton);
         mStatusBarView.setIgnoreChildren(3, mInputMethodSwitchButton, mInputMethodsPanel);
         lp = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.WRAP_CONTENT,
@@ -853,7 +854,7 @@
         if (oldVisibility != mInputMethodSwitchButton.getVisibility()) {
             updateNotificationIcons();
         }
-        mInputMethodsPanel.setIMEToken(token);
+        mInputMethodsPanel.setImeToken(token);
         mBackButton.setImageResource(
                 visible ? R.drawable.ic_sysbar_back_ime : R.drawable.ic_sysbar_back);
         if (FAKE_SPACE_BAR) {
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
index 63b87b1..a618423 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
@@ -328,6 +328,7 @@
             public void run() {
                 Log.i(TAG, "VPN connectivity monitor running");
                 try {
+                    mNotification.update(mStartTime); // to pop up notification
                     for (int i = 10; ; i--) {
                         long now = System.currentTimeMillis();
 
@@ -417,13 +418,27 @@
 
     // Helper class for showing, updating notification.
     private class NotificationHelper {
+        private NotificationManager mNotificationManager = (NotificationManager)
+                mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        private Notification mNotification =
+                new Notification(R.drawable.vpn_connected, null, 0L);
+        private PendingIntent mPendingIntent = PendingIntent.getActivity(
+                mContext, 0,
+                new VpnManager(mContext).createSettingsActivityIntent(), 0);
+        private String mConnectedTitle;
+
         void update(long now) {
-            String title = getNotificationTitle(true);
-            Notification n = new Notification(R.drawable.vpn_connected, title,
-                    mStartTime);
-            n.setLatestEventInfo(mContext, title,
+            Notification n = mNotification;
+            if (now == mStartTime) {
+                // to pop up the notification for the first time
+                n.when = mStartTime;
+                n.tickerText = mConnectedTitle = getNotificationTitle(true);
+            } else {
+                n.tickerText = null;
+            }
+            n.setLatestEventInfo(mContext, mConnectedTitle,
                     getConnectedNotificationMessage(now),
-                    prepareNotificationIntent());
+                    mPendingIntent);
             n.flags |= Notification.FLAG_NO_CLEAR;
             n.flags |= Notification.FLAG_ONGOING_EVENT;
             enableNotification(n);
@@ -435,25 +450,18 @@
                     title, System.currentTimeMillis());
             n.setLatestEventInfo(mContext, title,
                     getDisconnectedNotificationMessage(),
-                    prepareNotificationIntent());
+                    mPendingIntent);
             n.flags |= Notification.FLAG_AUTO_CANCEL;
             disableNotification();
             enableNotification(n);
         }
 
         void disableNotification() {
-            ((NotificationManager) mContext.getSystemService(
-                    Context.NOTIFICATION_SERVICE)).cancel(NOTIFICATION_ID);
+            mNotificationManager.cancel(NOTIFICATION_ID);
         }
 
         private void enableNotification(Notification n) {
-            ((NotificationManager) mContext.getSystemService(
-                    Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, n);
-        }
-
-        private PendingIntent prepareNotificationIntent() {
-            return PendingIntent.getActivity(mContext, 0,
-                    new VpnManager(mContext).createSettingsActivityIntent(), 0);
+            mNotificationManager.notify(NOTIFICATION_ID, n);
         }
 
         private String getNotificationTitle(boolean connected) {
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
index 70a4b20..32c016d 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -114,14 +114,12 @@
             lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
             lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen;
 
-            if (mContext.getResources().getBoolean(R.bool.config_enableLockScreenRotation)) {
-                Log.d(TAG, "Rotation sensor for lock screen On!");
-                lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR;
-            } else {
-                Log.d(TAG, "Rotation sensor for lock screen Off!");
-                lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
-            }
-
+            // TODO: Sometimes we get the wrong value for the sensor resource we use to configure
+            // this.  However, the current UI design has LockScreen always respond to orientation so
+            // we don't need this for the time-being.
+            //
+            // For reference, the configuration variable is R.bool.config_enableLockScreenRotation
+            lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR;
             lp.setTitle("Keyguard");
             mWindowLayoutParams = lp;
 
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index c0c3afd..7809961 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -123,7 +123,7 @@
     /**
      * The default amount of time we stay awake (used for all key input)
      */
-    protected static final int AWAKE_INTERVAL_DEFAULT_MS = 5000;
+    protected static final int AWAKE_INTERVAL_DEFAULT_MS = 10000;
 
 
     /**
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 68c1453..c313713b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -166,6 +166,8 @@
 
     private int mTitleColor = 0;
 
+    private boolean mAlwaysReadCloseOnTouchAttr = false;
+    
     private ContextMenuBuilder mContextMenu;
     private MenuDialogHelper mContextMenuHelper;
     private ActionButtonSubmenu mActionButtonPopup;
@@ -1983,6 +1985,7 @@
                 }
 
                 if (mActionModeView != null) {
+                    mActionModeView.killMode();
                     mode = new StandaloneActionMode(getContext(), mActionModeView, wrappedCallback);
                     if (callback.onCreateActionMode(mode, mode.getMenu())) {
                         mode.invalidate();
@@ -2326,6 +2329,15 @@
             addFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);
         }
         
+        if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
+                >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+            if (a.getBoolean(
+                    com.android.internal.R.styleable.Window_windowCloseOnTouchOutside,
+                    false)) {
+                setCloseOnTouchOutsideIfNotSet(true);
+            }
+        }
+        
         WindowManager.LayoutParams params = getAttributes();
 
         if (!hasSoftInputMode()) {
@@ -2479,6 +2491,11 @@
         return contentParent;
     }
 
+    /** @hide */
+    public void alwaysReadCloseOnTouchAttr() {
+        mAlwaysReadCloseOnTouchAttr = true;
+    }
+
     private void installDecor() {
         if (mDecor == null) {
             mDecor = generateDecor();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 6b559cf..747242f 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1965,23 +1965,29 @@
             // behind it.
             return false;
         }
-        if (mStatusBar != null && mStatusBar.isVisibleLw()) {
-            Rect rect = new Rect(mStatusBar.getShownFrameLw());
-            for (int i=mStatusBarPanels.size()-1; i>=0; i--) {
-                WindowState w = mStatusBarPanels.get(i);
-                if (w.isVisibleLw()) {
-                    rect.union(w.getShownFrameLw());
+        if (false) {
+            // Don't do this on the tablet, since the system bar never completely
+            // covers the screen, and with all its transparency this will
+            // incorrectly think it does cover it when it doesn't.  We'll revisit
+            // this later when we re-do the phone status bar.
+            if (mStatusBar != null && mStatusBar.isVisibleLw()) {
+                Rect rect = new Rect(mStatusBar.getShownFrameLw());
+                for (int i=mStatusBarPanels.size()-1; i>=0; i--) {
+                    WindowState w = mStatusBarPanels.get(i);
+                    if (w.isVisibleLw()) {
+                        rect.union(w.getShownFrameLw());
+                    }
                 }
-            }
-            final int insetw = mRestrictedScreenWidth/10;
-            final int inseth = mRestrictedScreenHeight/10;
-            if (rect.contains(insetw, inseth, mRestrictedScreenWidth-insetw,
-                        mRestrictedScreenHeight-inseth)) {
-                // All of the status bar windows put together cover the
-                // screen, so the app can't be seen.  (Note this test doesn't
-                // work if the rects of these windows are at off offsets or
-                // sizes, causing gaps in the rect union we have computed.)
-                return false;
+                final int insetw = mRestrictedScreenWidth/10;
+                final int inseth = mRestrictedScreenHeight/10;
+                if (rect.contains(insetw, inseth, mRestrictedScreenWidth-insetw,
+                            mRestrictedScreenHeight-inseth)) {
+                    // All of the status bar windows put together cover the
+                    // screen, so the app can't be seen.  (Note this test doesn't
+                    // work if the rects of these windows are at off offsets or
+                    // sizes, causing gaps in the rect union we have computed.)
+                    return false;
+                }
             }
         }
         return true;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 51b5947..16c042d 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -131,18 +131,21 @@
     : BnAudioFlinger(),
         mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)
 {
+    Mutex::Autolock _l(mLock);
+
     mHardwareStatus = AUDIO_HW_IDLE;
 
     mAudioHardware = AudioHardwareInterface::create();
 
     mHardwareStatus = AUDIO_HW_INIT;
     if (mAudioHardware->initCheck() == NO_ERROR) {
-        // open 16-bit output stream for s/w mixer
+        AutoMutex lock(mHardwareLock);
         mMode = AudioSystem::MODE_NORMAL;
-        setMode(mMode);
-
-        setMasterVolume(1.0f);
-        setMasterMute(false);
+        mHardwareStatus = AUDIO_HW_SET_MODE;
+        mAudioHardware->setMode(mMode);
+        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+        mAudioHardware->setMasterVolume(1.0f);
+        mHardwareStatus = AUDIO_HW_IDLE;
     } else {
         LOGE("Couldn't even initialize the stubbed audio hardware!");
     }
@@ -440,13 +443,16 @@
     }
 
     // when hw supports master volume, don't scale in sw mixer
-    AutoMutex lock(mHardwareLock);
-    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-    if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
-        value = 1.0f;
+    { // scope for the lock
+        AutoMutex lock(mHardwareLock);
+        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+        if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
+            value = 1.0f;
+        }
+        mHardwareStatus = AUDIO_HW_IDLE;
     }
-    mHardwareStatus = AUDIO_HW_IDLE;
 
+    Mutex::Autolock _l(mLock);
     mMasterVolume = value;
     for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
        mPlaybackThreads.valueAt(i)->setMasterVolume(value);
@@ -517,6 +523,7 @@
         return PERMISSION_DENIED;
     }
 
+    Mutex::Autolock _l(mLock);
     mMasterMute = muted;
     for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
        mPlaybackThreads.valueAt(i)->setMasterMute(muted);
@@ -579,6 +586,7 @@
         return BAD_VALUE;
     }
 
+    AutoMutex lock(mLock);
     mStreamTypes[stream].mute = muted;
     for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
        mPlaybackThreads.valueAt(i)->setStreamMute(stream, muted);
diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
index eeca7ab..e4086c4 100644
--- a/services/audioflinger/AudioPolicyManagerBase.cpp
+++ b/services/audioflinger/AudioPolicyManagerBase.cpp
@@ -1052,25 +1052,27 @@
 
     updateDeviceForStrategy();
 #ifdef AUDIO_POLICY_TEST
-    AudioParameter outputCmd = AudioParameter();
-    outputCmd.addInt(String8("set_id"), 0);
-    mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
+    if (mHardwareOutput != 0) {
+        AudioParameter outputCmd = AudioParameter();
+        outputCmd.addInt(String8("set_id"), 0);
+        mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
 
-    mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
-    mTestSamplingRate = 44100;
-    mTestFormat = AudioSystem::PCM_16_BIT;
-    mTestChannels =  AudioSystem::CHANNEL_OUT_STEREO;
-    mTestLatencyMs = 0;
-    mCurOutput = 0;
-    mDirectOutput = false;
-    for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
-        mTestOutputs[i] = 0;
+        mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
+        mTestSamplingRate = 44100;
+        mTestFormat = AudioSystem::PCM_16_BIT;
+        mTestChannels =  AudioSystem::CHANNEL_OUT_STEREO;
+        mTestLatencyMs = 0;
+        mCurOutput = 0;
+        mDirectOutput = false;
+        for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+            mTestOutputs[i] = 0;
+        }
+
+        const size_t SIZE = 256;
+        char buffer[SIZE];
+        snprintf(buffer, SIZE, "AudioPolicyManagerTest");
+        run(buffer, ANDROID_PRIORITY_AUDIO);
     }
-
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    snprintf(buffer, SIZE, "AudioPolicyManagerTest");
-    run(buffer, ANDROID_PRIORITY_AUDIO);
 #endif //AUDIO_POLICY_TEST
 }
 
@@ -1091,6 +1093,11 @@
    mInputs.clear();
 }
 
+status_t AudioPolicyManagerBase::initCheck()
+{
+    return (mHardwareOutput == 0) ? NO_INIT : NO_ERROR;
+}
+
 #ifdef AUDIO_POLICY_TEST
 bool AudioPolicyManagerBase::threadLoop()
 {
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index f24e08e..46a01ad 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -68,6 +68,8 @@
 {
     char value[PROPERTY_VALUE_MAX];
 
+    Mutex::Autolock _l(mLock);
+
     // start tone playback thread
     mTonePlaybackThread = new AudioCommandThread(String8(""));
     // start audio commands thread
@@ -88,9 +90,18 @@
     }
 #endif
 
-    // load properties
-    property_get("ro.camera.sound.forced", value, "0");
-    mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
+    if ((mpPolicyManager != NULL) && (mpPolicyManager->initCheck() != NO_ERROR)) {
+        delete mpPolicyManager;
+        mpPolicyManager = NULL;
+    }
+
+    if (mpPolicyManager == NULL) {
+        LOGE("Could not create AudioPolicyManager");
+    } else {
+        // load properties
+        property_get("ro.camera.sound.forced", value, "0");
+        mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
+    }
 }
 
 AudioPolicyService::~AudioPolicyService()
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 6b66791..8e9a5a4 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -121,7 +121,7 @@
         const sp<InputReaderPolicyInterface>& policy,
         const sp<InputDispatcherInterface>& dispatcher) :
         mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher),
-        mGlobalMetaState(0) {
+        mGlobalMetaState(0), mDisableVirtualKeysTimeout(-1) {
     configureExcludedDevices();
     updateGlobalMetaState();
     updateInputConfiguration();
@@ -373,6 +373,24 @@
     } // release state lock
 }
 
+void InputReader::disableVirtualKeysUntil(nsecs_t time) {
+    mDisableVirtualKeysTimeout = time;
+}
+
+bool InputReader::shouldDropVirtualKey(nsecs_t now,
+        InputDevice* device, int32_t keyCode, int32_t scanCode) {
+    if (now < mDisableVirtualKeysTimeout) {
+        LOGI("Dropping virtual key from device %s because virtual keys are "
+                "temporarily disabled for the next %0.3fms.  keyCode=%d, scanCode=%d",
+                device->getName().string(),
+                (mDisableVirtualKeysTimeout - now) * 0.000001,
+                keyCode, scanCode);
+        return true;
+    } else {
+        return false;
+    }
+}
+
 void InputReader::getInputConfiguration(InputConfiguration* outConfiguration) {
     { // acquire state lock
         AutoMutex _l(mStateLock);
@@ -889,6 +907,12 @@
                 keyCode = mLocked.keyDowns.itemAt(keyDownIndex).keyCode;
             } else {
                 // key down
+                if ((policyFlags & POLICY_FLAG_VIRTUAL)
+                        && mContext->shouldDropVirtualKey(when,
+                                getDevice(), keyCode, scanCode)) {
+                    return;
+                }
+
                 mLocked.keyDowns.push();
                 KeyDown& keyDown = mLocked.keyDowns.editTop();
                 keyDown.keyCode = keyCode;
@@ -1428,6 +1452,7 @@
     mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents();
     mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents();
     mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents();
+    mParameters.virtualKeyQuietTime = getPolicy()->getVirtualKeyQuietTime();
 
     String8 deviceTypeString;
     mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
@@ -2219,6 +2244,7 @@
 
     TouchResult touchResult = consumeOffScreenTouches(when, policyFlags);
     if (touchResult == DISPATCH_TOUCH) {
+        detectGestures(when);
         dispatchTouches(when, policyFlags);
     }
 
@@ -2304,6 +2330,11 @@
                     if (mCurrentTouch.pointerCount == 1) {
                         const VirtualKey* virtualKey = findVirtualKeyHitLocked(x, y);
                         if (virtualKey) {
+                            if (mContext->shouldDropVirtualKey(when, getDevice(),
+                                    virtualKey->keyCode, virtualKey->scanCode)) {
+                                return DROP_STROKE;
+                            }
+
                             mLocked.currentVirtualKey.down = true;
                             mLocked.currentVirtualKey.downTime = when;
                             mLocked.currentVirtualKey.keyCode = virtualKey->keyCode;
@@ -2341,6 +2372,26 @@
     return touchResult;
 }
 
+void TouchInputMapper::detectGestures(nsecs_t when) {
+    // Disable all virtual key touches that happen within a short time interval of the
+    // most recent touch.  The idea is to filter out stray virtual key presses when
+    // interacting with the touch screen.
+    //
+    // Problems we're trying to solve:
+    //
+    // 1. While scrolling a list or dragging the window shade, the user swipes down into a
+    //    virtual key area that is implemented by a separate touch panel and accidentally
+    //    triggers a virtual key.
+    //
+    // 2. While typing in the on screen keyboard, the user taps slightly outside the screen
+    //    area and accidentally triggers a virtual key.  This often happens when virtual keys
+    //    are layed out below the screen near to where the on screen keyboard's space bar
+    //    is displayed.
+    if (mParameters.virtualKeyQuietTime > 0 && mCurrentTouch.pointerCount != 0) {
+        mContext->disableVirtualKeysUntil(when + mParameters.virtualKeyQuietTime);
+    }
+}
+
 void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
     uint32_t currentPointerCount = mCurrentTouch.pointerCount;
     uint32_t lastPointerCount = mLastTouch.pointerCount;
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 8b2d40a..7619682 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -78,6 +78,12 @@
      */
     virtual bool filterJumpyTouchEvents() = 0;
 
+    /* Gets the amount of time to disable virtual keys after the screen is touched
+     * in order to filter out accidental virtual key presses due to swiping gestures
+     * or taps near the edge of the display.  May be 0 to disable the feature.
+     */
+    virtual nsecs_t getVirtualKeyQuietTime() = 0;
+
     /* Gets the excluded device names for the platform. */
     virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0;
 
@@ -147,6 +153,10 @@
     virtual void updateGlobalMetaState() = 0;
     virtual int32_t getGlobalMetaState() = 0;
 
+    virtual void disableVirtualKeysUntil(nsecs_t time) = 0;
+    virtual bool shouldDropVirtualKey(nsecs_t now,
+            InputDevice* device, int32_t keyCode, int32_t scanCode) = 0;
+
     virtual InputReaderPolicyInterface* getPolicy() = 0;
     virtual InputDispatcherInterface* getDispatcher() = 0;
     virtual EventHubInterface* getEventHub() = 0;
@@ -234,6 +244,11 @@
     InputConfiguration mInputConfiguration;
     void updateInputConfiguration();
 
+    nsecs_t mDisableVirtualKeysTimeout;
+    virtual void disableVirtualKeysUntil(nsecs_t time);
+    virtual bool shouldDropVirtualKey(nsecs_t now,
+            InputDevice* device, int32_t keyCode, int32_t scanCode);
+
     // state queries
     typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code);
     int32_t getState(int32_t deviceId, uint32_t sourceMask, int32_t code,
@@ -603,6 +618,7 @@
         bool useBadTouchFilter;
         bool useJumpyTouchFilter;
         bool useAveragingTouchFilter;
+        nsecs_t virtualKeyQuietTime;
     } mParameters;
 
     // Immutable calibration parameters in parsed form.
@@ -839,6 +855,7 @@
     void dispatchTouch(nsecs_t when, uint32_t policyFlags, TouchData* touch,
             BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,
             int32_t motionEventAction);
+    void detectGestures(nsecs_t when);
 
     bool isPointInsideSurfaceLocked(int32_t x, int32_t y);
     const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y);
diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp
index ebc58ee..92af51e 100644
--- a/services/input/PointerController.cpp
+++ b/services/input/PointerController.cpp
@@ -310,8 +310,16 @@
 void PointerController::setPointerIcon(const SkBitmap* bitmap, float hotSpotX, float hotSpotY) {
     AutoMutex _l(mLock);
 
-    delete mLocked.iconBitmap;
-    mLocked.iconBitmap = bitmap ? new SkBitmap(*bitmap) : NULL;
+    if (mLocked.iconBitmap) {
+        delete mLocked.iconBitmap;
+        mLocked.iconBitmap = NULL;
+    }
+
+    if (bitmap) {
+        mLocked.iconBitmap = new SkBitmap();
+        bitmap->copyTo(mLocked.iconBitmap, SkBitmap::kARGB_8888_Config);
+    }
+
     mLocked.iconHotSpotX = hotSpotX;
     mLocked.iconHotSpotY = hotSpotY;
     mLocked.drawn = false;
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 8ec6f53..775747c 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -127,6 +127,10 @@
         mFilterJumpyTouchEvents = enabled;
     }
 
+    virtual nsecs_t getVirtualKeyQuietTime() {
+        return 0;
+    }
+
     void addExcludedDeviceName(const String8& deviceName) {
         mExcludedDeviceNames.push(deviceName);
     }
@@ -722,6 +726,14 @@
     virtual InputDispatcherInterface* getDispatcher() {
         return mDispatcher.get();
     }
+
+    virtual void disableVirtualKeysUntil(nsecs_t time) {
+    }
+
+    virtual bool shouldDropVirtualKey(nsecs_t now,
+            InputDevice* device, int32_t keyCode, int32_t scanCode) {
+        return false;
+    }
 };
 
 
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 22dd804..59a540b 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -16,6 +16,23 @@
 
 package com.android.server;
 
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.appwidget.AppWidgetManager;
@@ -24,46 +41,37 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.Intent.FilterComparison;
 import android.content.IntentFilter;
+import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.AttributeSet;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.widget.RemoteViews;
 
-import java.io.IOException;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.HashMap;
-import java.util.HashSet;
-
-import com.android.internal.appwidget.IAppWidgetService;
 import com.android.internal.appwidget.IAppWidgetHost;
+import com.android.internal.appwidget.IAppWidgetService;
 import com.android.internal.util.FastXmlSerializer;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
+import com.android.internal.widget.IRemoteViewsAdapterConnection;
 
 class AppWidgetService extends IAppWidgetService.Stub
 {
@@ -107,6 +115,56 @@
         Host host;
     }
 
+    /**
+     * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection.
+     * This needs to be a static inner class since a reference to the ServiceConnection is held
+     * globally and may lead us to leak AppWidgetService instances (if there were more than one).
+     */
+    static class ServiceConnectionProxy implements ServiceConnection {
+        private final AppWidgetService mAppWidgetService;
+        private final Pair<Integer, Intent.FilterComparison> mKey;
+        private final IBinder mConnectionCb;
+
+        ServiceConnectionProxy(AppWidgetService appWidgetService,
+                Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
+            mAppWidgetService = appWidgetService;
+            mKey = key;
+            mConnectionCb = connectionCb;
+        }
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            IRemoteViewsAdapterConnection cb =
+                IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
+            try {
+                cb.onServiceConnected(service);
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+        }
+        public void onServiceDisconnected(ComponentName name) {
+            IRemoteViewsAdapterConnection cb =
+                IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
+            try {
+                cb.onServiceDisconnected();
+                mAppWidgetService.mServiceConnectionUpdateHandler.post(new Runnable() {
+                    public void run() {
+                        // We don't want to touch mBoundRemoteViewsServices from any other thread
+                        // so queue this to run on the main thread.
+                        if (mAppWidgetService.mBoundRemoteViewsServices.containsKey(mKey)) {
+                            mAppWidgetService.mBoundRemoteViewsServices.remove(mKey);
+                        }
+                    }
+                });
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    // Manages connections to RemoteViewsServices
+    private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection>
+        mBoundRemoteViewsServices = new HashMap<Pair<Integer,FilterComparison>,ServiceConnection>();
+    private final Handler mServiceConnectionUpdateHandler = new Handler();
+
     Context mContext;
     Locale mLocale;
     PackageManager mPackageManager;
@@ -294,6 +352,9 @@
     }
 
     void deleteAppWidgetLocked(AppWidgetId id) {
+        // We first unbind all services that are bound to this id
+        unbindAppWidgetRemoteViewsServicesLocked(id);
+
         Host host = id.host;
         host.instances.remove(id);
         pruneHostLocked(host);
@@ -376,6 +437,77 @@
         }
     }
 
+    public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) {
+        synchronized (mAppWidgetIds) {
+            AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+            if (id == null) {
+                throw new IllegalArgumentException("bad appWidgetId");
+            }
+            final ComponentName componentName = intent.getComponent();
+            try {
+                final ServiceInfo si = mContext.getPackageManager().getServiceInfo(componentName,
+                        PackageManager.GET_PERMISSIONS);
+                if (!android.Manifest.permission.BIND_REMOTEVIEWS.equals(si.permission)) {
+                    throw new SecurityException("Selected service does not require "
+                            + android.Manifest.permission.BIND_REMOTEVIEWS
+                            + ": " + componentName);
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                throw new IllegalArgumentException("Unknown component " + componentName);
+            }
+
+            // Bind to the RemoteViewsService (which will trigger a callback to the
+            // RemoteViewsAdapter)
+            Pair<Integer, FilterComparison> key = Pair.create(appWidgetId,
+                    new FilterComparison(intent));
+            final ServiceConnection conn = new ServiceConnectionProxy(this, key, connection);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+                mBoundRemoteViewsServices.put(key, conn);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    }
+
+    public void unbindRemoteViewsService(int appWidgetId, Intent intent) {
+        synchronized (mAppWidgetIds) {
+            AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+            if (id == null) {
+                throw new IllegalArgumentException("bad appWidgetId");
+            }
+
+            // Unbind from the RemoteViewsService (which will trigger a callback to the bound
+            // RemoteViewsAdapter)
+            Pair<Integer, FilterComparison> key = Pair.create(appWidgetId,
+                    new FilterComparison(intent));
+            if (mBoundRemoteViewsServices.containsKey(key)) {
+                final ServiceConnection conn = mBoundRemoteViewsServices.get(key);
+                mBoundRemoteViewsServices.remove(key);
+                conn.onServiceDisconnected(null);
+                mContext.unbindService(conn);
+            }
+        }
+    }
+
+    private void unbindAppWidgetRemoteViewsServicesLocked(AppWidgetId id) {
+        Iterator<Pair<Integer, Intent.FilterComparison>> it =
+            mBoundRemoteViewsServices.keySet().iterator();
+        int appWidgetId = id.appWidgetId;
+
+        // Unbind all connections to AppWidgets bound to this id
+        while (it.hasNext()) {
+            final Pair<Integer, Intent.FilterComparison> key = it.next();
+            if (key.first.intValue() == appWidgetId) {
+                final ServiceConnection conn = mBoundRemoteViewsServices.get(key);
+                it.remove();
+                conn.onServiceDisconnected(null);
+                mContext.unbindService(conn);
+            }
+        }
+    }
+
     public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
         synchronized (mAppWidgetIds) {
             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java
index bec35d1..062ab74 100644
--- a/services/java/com/android/server/ClipboardService.java
+++ b/services/java/com/android/server/ClipboardService.java
@@ -140,7 +140,7 @@
     public boolean hasClipboardText() {
         synchronized (this) {
             if (mPrimaryClip != null) {
-                CharSequence text = mPrimaryClip.getItem(0).getText();
+                CharSequence text = mPrimaryClip.getItemAt(0).getText();
                 return text != null && text.length() > 0;
             }
             return false;
@@ -175,7 +175,7 @@
     private final void checkDataOwnerLocked(ClipData data, int uid) {
         final int N = data.getItemCount();
         for (int i=0; i<N; i++) {
-            checkItemOwnerLocked(data.getItem(i), uid);
+            checkItemOwnerLocked(data.getItemAt(i), uid);
         }
     }
 
@@ -214,7 +214,7 @@
         if (mPrimaryClip != null && !mActivePermissionOwners.contains(pkg)) {
             final int N = mPrimaryClip.getItemCount();
             for (int i=0; i<N; i++) {
-                grantItemLocked(mPrimaryClip.getItem(i), pkg);
+                grantItemLocked(mPrimaryClip.getItemAt(i), pkg);
             }
             mActivePermissionOwners.add(pkg);
         }
@@ -249,7 +249,7 @@
         }
         final int N = mPrimaryClip.getItemCount();
         for (int i=0; i<N; i++) {
-            revokeItemLocked(mPrimaryClip.getItem(i));
+            revokeItemLocked(mPrimaryClip.getItemAt(i));
         }
     }
 }
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index c0ce256..8a9e351 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -145,6 +145,7 @@
         int maximumFailedPasswordsForWipe = 0;
         long passwordExpirationTimeout = 0L;
         long passwordExpirationDate = 0L;
+        boolean encryptionRequested = false;
 
         // TODO: review implementation decisions with frameworks team
         boolean specifiesGlobalProxy = false;
@@ -242,6 +243,11 @@
                 out.attribute(null, "value", Long.toString(passwordExpirationDate));
                 out.endTag(null, "password-expiration-date");
             }
+            if (encryptionRequested) {
+                out.startTag(null, "encryption-requested");
+                out.attribute(null, "value", Boolean.toString(encryptionRequested));
+                out.endTag(null, "encryption-requested");
+            }
         }
 
         void readFromXml(XmlPullParser parser)
@@ -290,7 +296,7 @@
                     maximumFailedPasswordsForWipe = Integer.parseInt(
                             parser.getAttributeValue(null, "value"));
                 } else if ("specifies-global-proxy".equals(tag)) {
-                    specifiesGlobalProxy = Boolean.getBoolean(
+                    specifiesGlobalProxy = Boolean.parseBoolean(
                             parser.getAttributeValue(null, "value"));
                 } else if ("global-proxy-spec".equals(tag)) {
                     globalProxySpec =
@@ -304,6 +310,9 @@
                 } else if ("password-expiration-date".equals(tag)) {
                     passwordExpirationDate = Long.parseLong(
                             parser.getAttributeValue(null, "value"));
+                } else if ("encryption-requested".equals(tag)) {
+                    encryptionRequested = Boolean.parseBoolean(
+                            parser.getAttributeValue(null, "value"));
                 } else {
                     Slog.w(TAG, "Unknown admin tag: " + tag);
                 }
@@ -356,6 +365,8 @@
                 pw.print(prefix); pw.print("globalProxyEclusionList=");
                         pw.println(globalProxyExclusionList);
             }
+            pw.print(prefix); pw.print("encryptionRequested=");
+                    pw.println(encryptionRequested);
         }
     }
 
@@ -1823,7 +1834,8 @@
     }
 
     /**
-     * Set the storage encryption request.
+     * Set the storage encryption request for a single admin.  Returns the new total request
+     * status (for all admins).
      */
     public int setStorageEncryption(ComponentName who, boolean encrypt) {
         synchronized (this) {
@@ -1834,29 +1846,94 @@
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
 
-            // TODO: (1) Record the value for the admin so it's sticky
-            // TODO: (2) Compute "max" for all admins (if any admin requests encryption, then
-            //           we enable it.
-            // TODO: (3) Work with filesystem / mount service to start/stop encryption
-            return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
+            // Quick exit:  If the filesystem does not support encryption, we can exit early.
+            if (!isEncryptionSupported()) {
+                return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
+            }
+
+            // (1) Record the value for the admin so it's sticky
+            if (ap.encryptionRequested != encrypt) {
+                ap.encryptionRequested = encrypt;
+                saveSettingsLocked();
+            }
+
+            // (2) Compute "max" for all admins
+            boolean newRequested = false;
+            final int N = mAdminList.size();
+            for (int i = 0; i < N; i++) {
+                newRequested |= mAdminList.get(i).encryptionRequested;
+            }
+
+            // Notify OS of new request
+            setEncryptionRequested(newRequested);
+
+            // Return the new global request status
+            return newRequested
+                    ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
+                    : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
         }
     }
 
     /**
-     * Get the current storage encryption status for a given storage domain.
+     * Get the current storage encryption request status for a given admin, or aggregate of all
+     * active admins.
      */
-    public int getStorageEncryption(ComponentName who) {
+    public boolean getStorageEncryption(ComponentName who) {
         synchronized (this) {
             // Check for permissions if a particular caller is specified
             if (who != null) {
-                getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
+                // When checking for a single caller, status is based on caller's request
+                ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+                        DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
+                return ap.encryptionRequested;
             }
 
-            // TODO: Work with filesystem / mount service to query encryption status
-            return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
+            // If no particular caller is specified, return the aggregate set of requests.
+            // This is short circuited by returning true on the first hit.
+            final int N = mAdminList.size();
+            for (int i = 0; i < N; i++) {
+                if (mAdminList.get(i).encryptionRequested) {
+                    return true;
+                }
+            }
+            return false;
         }
     }
 
+    /**
+     * Get the current encryption status of the device.
+     */
+    public int getStorageEncryptionStatus() {
+        return getEncryptionStatus();
+    }
+
+    /**
+     * Hook to low-levels:  This should report if the filesystem supports encrypted storage.
+     */
+    private boolean isEncryptionSupported() {
+        // Note, this can be implemented as
+        //   return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
+        // But is provided as a separate internal method if there's a faster way to do a
+        // simple check for supported-or-not.
+        return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
+    }
+
+    /**
+     * Hook to low-levels:  Reporting the current status of encryption.
+     * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
+     * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
+     * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
+     */
+    private int getEncryptionStatus() {
+        return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
+    }
+
+    /**
+     * Hook to low-levels:  If needed, record the new admin setting for encryption.
+     */
+    private void setEncryptionRequested(boolean encrypt) {
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
diff --git a/services/java/com/android/server/DropBoxManagerService.java b/services/java/com/android/server/DropBoxManagerService.java
index 4305c358..5c878c9 100644
--- a/services/java/com/android/server/DropBoxManagerService.java
+++ b/services/java/com/android/server/DropBoxManagerService.java
@@ -97,10 +97,18 @@
     // Ensure that all log entries have a unique timestamp
     private long mLastTimestamp = 0;
 
+    private volatile boolean mBooted = false;
+
     /** Receives events that might indicate a need to clean up files. */
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
+            if (intent != null && Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
+                mBooted = true;
+                return;
+            }
+
+            // Else, for ACTION_DEVICE_STORAGE_LOW:
             mCachedQuotaUptimeMillis = 0;  // Force a re-check of quota size
 
             // Run the initialization in the background (not this main thread).
@@ -132,7 +140,11 @@
         // Set up intent receivers
         mContext = context;
         mContentResolver = context.getContentResolver();
-        context.registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW));
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
+        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
+        context.registerReceiver(mReceiver, filter);
 
         mContentResolver.registerContentObserver(
             Settings.Secure.CONTENT_URI, true,
@@ -224,6 +236,9 @@
             Intent dropboxIntent = new Intent(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED);
             dropboxIntent.putExtra(DropBoxManager.EXTRA_TAG, tag);
             dropboxIntent.putExtra(DropBoxManager.EXTRA_TIME, time);
+            if (!mBooted) {
+                dropboxIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            }
             mContext.sendBroadcast(dropboxIntent, android.Manifest.permission.READ_LOGS);
 
         } catch (IOException e) {
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index 06595ae..8d249ff 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -481,7 +481,13 @@
             return mContext.getResources().getBoolean(
                     com.android.internal.R.bool.config_filterJumpyTouchEvents);
         }
-        
+
+        @SuppressWarnings("unused")
+        public int getVirtualKeyQuietTimeMillis() {
+            return mContext.getResources().getInteger(
+                    com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
+        }
+
         @SuppressWarnings("unused")
         public String[] getExcludedDeviceNames() {
             ArrayList<String> names = new ArrayList<String>();
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 7b4f246..4d40620 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -2049,8 +2049,9 @@
         for (int i = 0; i < N; ++i) {
             InputMethodSubtype subtype = subtypes.get(i);
             final String subtypeLocale = subtype.getLocale();
-            // An applicable subtype should match "mode".
-            if (subtypes.get(i).getMode().equalsIgnoreCase(mode)) {
+            // An applicable subtype should match "mode". If mode is null, mode will be ignored,
+            // and all subtypes with all modes can be candidates.
+            if (mode == null || subtypes.get(i).getMode().equalsIgnoreCase(mode)) {
                 if (firstMatchedModeSubtype == null) {
                     firstMatchedModeSubtype = subtype;
                 }
@@ -2175,11 +2176,24 @@
                     InputMethodInfo imi = mMethodMap.get(lastInputMethodId);
                     if (imi != null) {
                         // If there are no selected subtypes, the framework will try to find
-                        // the most applicable subtype from all subtypes whose mode is
-                        // SUBTYPE_MODE_KEYBOARD. This is an exceptional case, so we will hardcode
-                        // the mode.
-                        mCurrentSubtype = findLastResortApplicableSubtypeLocked(
-                                mRes, imi.getSubtypes(), SUBTYPE_MODE_KEYBOARD, null, true);
+                        // the most applicable subtype from explicitly or implicitly enabled
+                        // subtypes.
+                        List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
+                                getEnabledInputMethodSubtypeList(imi, true);
+                        // If there is only one explicitly or implicitly enabled subtype,
+                        // just returns it.
+                        if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
+                            mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
+                        } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
+                            mCurrentSubtype = findLastResortApplicableSubtypeLocked(
+                                    mRes, explicitlyOrImplicitlyEnabledSubtypes,
+                                    SUBTYPE_MODE_KEYBOARD, null, true);
+                            if (mCurrentSubtype == null) {
+                                mCurrentSubtype = findLastResortApplicableSubtypeLocked(
+                                        mRes, explicitlyOrImplicitlyEnabledSubtypes, null, null,
+                                        true);
+                            }
+                        }
                     }
                 } else {
                     mCurrentSubtype =
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 19667d4..059c0b8 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -4390,8 +4390,6 @@
         }
     };
 
-    private static final boolean DEBUG_OBB = false;
-
     private static final void sendPackageBroadcast(String action, String pkg,
             Bundle extras, IIntentReceiver finishedReceiver) {
         IActivityManager am = ActivityManagerNative.getDefault();
@@ -4409,10 +4407,19 @@
             }
         }
     }
-    
+
+    /**
+     * Check if the external storage media is available. This is true if there
+     * is a mounted external storage medium or if the external storage is
+     * emulated.
+     */
+    private boolean isExternalMediaAvailable() {
+        return mMediaMounted || Environment.isExternalStorageEmulated();
+    }
+
     public String nextPackageToClean(String lastPackage) {
         synchronized (mPackages) {
-            if (!mMediaMounted) {
+            if (!isExternalMediaAvailable()) {
                 // If the external storage is no longer mounted at this point,
                 // the caller may not have been able to delete all of this
                 // packages files and can not delete any more.  Bail.
@@ -4432,7 +4439,7 @@
     
     void startCleaningPackages() {
         synchronized (mPackages) {
-            if (!mMediaMounted) {
+            if (!isExternalMediaAvailable()) {
                 return;
             }
             if (mSettings.mPackagesToBeCleaned.size() <= 0) {
@@ -4641,64 +4648,6 @@
         }
     }
 
-    public void setPackageObbPaths(String packageName, String[] paths) {
-        if (DEBUG_OBB)
-            Log.v(TAG, "Setting .obb paths for " + packageName + " to: " + Arrays.toString(paths));
-        final int uid = Binder.getCallingUid();
-        final int permission = mContext.checkCallingPermission(
-                android.Manifest.permission.INSTALL_PACKAGES);
-        final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
-        if (!allowedByPermission) {
-            throw new SecurityException("Permission denial: attempt to set .obb file from pid="
-                    + Binder.getCallingPid());
-        }
-        synchronized (mPackages) {
-            final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
-            if (pkgSetting == null) {
-                throw new IllegalArgumentException("Unknown package: " + packageName);
-            }
-
-            if (paths != null) {
-                if (paths.length == 0) {
-                    // Don't bother storing an empty array.
-                    paths = null;
-                } else {
-                    // Don't allow the caller to manipulate our copy of the
-                    // list.
-                    paths = paths.clone();
-                }
-            }
-
-            // Only write settings file if the new and old settings are not the
-            // same.
-            if (!Arrays.equals(paths, pkgSetting.obbPathStrings)) {
-                pkgSetting.obbPathStrings = paths;
-                mSettings.writeLP();
-            }
-        }
-    }
-
-    public String[] getPackageObbPaths(String packageName) {
-        if (DEBUG_OBB)
-            Log.v(TAG, "Getting .obb paths for " + packageName);
-        final int uid = Binder.getCallingUid();
-        final int permission = mContext.checkCallingPermission(
-                android.Manifest.permission.INSTALL_PACKAGES);
-        final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
-        synchronized (mPackages) {
-            final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
-            if (pkgSetting == null) {
-                throw new IllegalArgumentException("Unknown package: " + packageName);
-            }
-            if (!allowedByPermission && (uid != pkgSetting.userId)) {
-                throw new SecurityException("Permission denial: attempt to set .obb file from pid="
-                        + Binder.getCallingPid() + ", uid=" + uid + ", package uid="
-                        + pkgSetting.userId);
-            }
-            return pkgSetting.obbPathStrings;
-        }
-    }
-
     private void processPendingInstall(final InstallArgs args, final int currentStatus) {
         // Queue up an async operation since the package installation may take a little while.
         mHandler.post(new Runnable() {
@@ -4853,6 +4802,11 @@
                         .getExternalStorageAppMediaDirectory(mStats.packageName);
                 mStats.externalMediaSize = mContainerService
                         .calculateDirectorySize(externalCacheDir.getPath());
+
+                final File externalObbDir = Environment
+                        .getExternalStorageAppObbDirectory(mStats.packageName);
+                mStats.externalObbSize = mContainerService.calculateDirectorySize(externalObbDir
+                        .getPath());
             }
         }
 
@@ -7333,7 +7287,6 @@
                     pw.print("    codePath="); pw.println(ps.codePathString);
                     pw.print("    resourcePath="); pw.println(ps.resourcePathString);
                     pw.print("    nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
-                    pw.print("    obbPaths="); pw.println(Arrays.toString(ps.obbPathStrings));
                     pw.print("    versionCode="); pw.println(ps.versionCode);
                     if (ps.pkg != null) {
                         pw.print("    versionName="); pw.println(ps.pkg.mVersionName);
@@ -7917,7 +7870,6 @@
         File resourcePath;
         String resourcePathString;
         String nativeLibraryPathString;
-        String[] obbPathStrings;
         long timeStamp;
         long firstInstallTime;
         long lastUpdateTime;
@@ -7963,11 +7915,6 @@
             resourcePath = base.resourcePath;
             resourcePathString = base.resourcePathString;
             nativeLibraryPathString = base.nativeLibraryPathString;
-
-            if (base.obbPathStrings != null) {
-                obbPathStrings = base.obbPathStrings.clone();
-            }
-
             timeStamp = base.timeStamp;
             firstInstallTime = base.firstInstallTime;
             lastUpdateTime = base.lastUpdateTime;
@@ -9026,16 +8973,6 @@
             if (pkg.installerPackageName != null) {
                 serializer.attribute(null, "installer", pkg.installerPackageName);
             }
-            if (pkg.obbPathStrings != null && pkg.obbPathStrings.length > 0) {
-                int N = pkg.obbPathStrings.length;
-                serializer.startTag(null, "obbs");
-                for (int i = 0; i < N; i++) {
-                    serializer.startTag(null, "obb");
-                    serializer.attribute(null, "path", pkg.obbPathStrings[i]);
-                    serializer.endTag(null, "obb");
-                }
-                serializer.endTag(null, "obbs");
-            }
             pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
             if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
                 serializer.startTag(null, "perms");
@@ -9628,8 +9565,6 @@
                         readGrantedPermissionsLP(parser,
                                 packageSetting.grantedPermissions);
                         packageSetting.permissionsFixed = true;
-                    } else if (tagName.equals("obbs")) {
-                        readObbPathsLP(packageSetting, parser);
                     } else {
                         reportSettingsProblem(Log.WARN,
                                 "Unknown element under <package>: "
@@ -9834,34 +9769,6 @@
             }
         }
 
-        private void readObbPathsLP(PackageSettingBase packageSetting, XmlPullParser parser)
-                throws XmlPullParserException, IOException {
-            final List<String> obbPaths = new ArrayList<String>();
-            final int outerDepth = parser.getDepth();
-            int type;
-            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                    continue;
-                }
-
-                final String tagName = parser.getName();
-                if (tagName.equals("obb")) {
-                    final String path = parser.getAttributeValue(null, "path");
-                    obbPaths.add(path);
-                } else {
-                    reportSettingsProblem(Log.WARN, "Unknown element under <obbs>: "
-                            + parser.getName());
-                }
-                XmlUtils.skipCurrentTag(parser);
-            }
-            if (obbPaths.size() == 0) {
-                return;
-            } else {
-                packageSetting.obbPathStrings = obbPaths.toArray(new String[obbPaths.size()]);
-            }
-        }
-
         // Returns -1 if we could not find an available UserId to assign
         private int newUserIdLP(Object obj) {
             // Let's be stupidly inefficient for now...
diff --git a/services/java/com/android/server/UsbService.java b/services/java/com/android/server/UsbService.java
index 77ddf3b..8ef03d4 100644
--- a/services/java/com/android/server/UsbService.java
+++ b/services/java/com/android/server/UsbService.java
@@ -134,14 +134,17 @@
         mContext = context;
         init();  // set initial status
 
-        mUEventObserver.startObserving(USB_CONNECTED_MATCH);
-        mUEventObserver.startObserving(USB_CONFIGURATION_MATCH);
-        mUEventObserver.startObserving(USB_FUNCTIONS_MATCH);
+        if (mConfiguration >= 0) {
+            mUEventObserver.startObserving(USB_CONNECTED_MATCH);
+            mUEventObserver.startObserving(USB_CONFIGURATION_MATCH);
+            mUEventObserver.startObserving(USB_FUNCTIONS_MATCH);
+        }
     }
 
     private final void init() {
         char[] buffer = new char[1024];
 
+        mConfiguration = -1;
         try {
             FileReader file = new FileReader(USB_CONNECTED_PATH);
             int len = file.read(buffer, 0, 1024);
@@ -154,10 +157,12 @@
             mConfiguration = Integer.valueOf((new String(buffer, 0, len)).trim());
 
         } catch (FileNotFoundException e) {
-            Slog.w(TAG, "This kernel does not have USB configuration switch support");
+            Slog.i(TAG, "This kernel does not have USB configuration switch support");
         } catch (Exception e) {
             Slog.e(TAG, "" , e);
         }
+        if (mConfiguration < 0)
+            return;
 
         try {
             File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles();
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 1b3725c..3e930ae 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -3031,7 +3031,7 @@
     }
 
     private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
-        if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: params package="
+        if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
                 + (lp != null ? lp.packageName : null)
                 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
         if (lp != null && lp.windowAnimations != 0) {
@@ -3052,7 +3052,7 @@
     }
 
     private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
-        if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: params package="
+        if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
                 + packageName + " resId=0x" + Integer.toHexString(resId));
         if (packageName != null) {
             if ((resId&0xFF000000) == 0x01000000) {
@@ -9957,8 +9957,8 @@
                         // The top-most window will supply the layout params,
                         // and we will determine it below.
                         LayoutParams animLp = null;
-                        AppWindowToken animToken = null;
                         int bestAnimLayer = -1;
+                        boolean fullscreenAnim = false;
 
                         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                                 "New wallpaper target=" + mWallpaperTarget
@@ -10000,11 +10000,18 @@
                                     // window, we will always use its anim.
                                     if ((ws.mAttrs.flags&FLAG_COMPATIBLE_WINDOW) != 0) {
                                         animLp = ws.mAttrs;
-                                        animToken = ws.mAppToken;
                                         bestAnimLayer = Integer.MAX_VALUE;
-                                    } else if (ws.mLayer > bestAnimLayer) {
+                                    } else if (!fullscreenAnim || ws.mLayer > bestAnimLayer) {
                                         animLp = ws.mAttrs;
-                                        animToken = ws.mAppToken;
+                                        bestAnimLayer = ws.mLayer;
+                                    }
+                                    fullscreenAnim = true;
+                                }
+                            } else if (!fullscreenAnim) {
+                                WindowState ws = wtoken.findMainWindow();
+                                if (ws != null) {
+                                    if (ws.mLayer > bestAnimLayer) {
+                                        animLp = ws.mAttrs;
                                         bestAnimLayer = ws.mLayer;
                                     }
                                 }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index dbf9a96..2ef85d5 100755
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3060,7 +3060,7 @@
                 }
                 if (uid == pkgUid || checkComponentPermission(
                         android.Manifest.permission.CLEAR_APP_USER_DATA,
-                        pid, uid, -1)
+                        pid, uid, -1, true)
                         == PackageManager.PERMISSION_GRANTED) {
                     forceStopPackageLocked(packageName, pkgUid);
                 } else {
@@ -4151,7 +4151,7 @@
      * This can be called with or without the global lock held.
      */
     int checkComponentPermission(String permission, int pid, int uid,
-            int reqUid) {
+            int owningUid, boolean exported) {
         // We might be performing an operation on behalf of an indirect binder
         // invocation, e.g. via {@link #openContentUri}.  Check and adjust the
         // client identity accordingly before proceeding.
@@ -4168,9 +4168,14 @@
             !Process.supportsProcesses()) {
             return PackageManager.PERMISSION_GRANTED;
         }
-        // If the target requires a specific UID, always fail for others.
-        if (reqUid >= 0 && uid != reqUid) {
-            Slog.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
+        // If there is a uid that owns whatever is being accessed, it has
+        // blanket access to it regardless of the permissions it requires.
+        if (owningUid >= 0 && uid == owningUid) {
+            return PackageManager.PERMISSION_GRANTED;
+        }
+        // If the target is not exported, then nobody else can get to it.
+        if (!exported) {
+            Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid);
             return PackageManager.PERMISSION_DENIED;
         }
         if (permission == null) {
@@ -4199,7 +4204,7 @@
         if (permission == null) {
             return PackageManager.PERMISSION_DENIED;
         }
-        return checkComponentPermission(permission, pid, uid, -1);
+        return checkComponentPermission(permission, pid, uid, -1, true);
     }
 
     /**
@@ -5322,12 +5327,12 @@
         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)
+                cpi.applicationInfo.uid, cpi.exported)
                 == PackageManager.PERMISSION_GRANTED) {
             return null;
         }
         if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
-                cpi.exported ? -1 : cpi.applicationInfo.uid)
+                cpi.applicationInfo.uid, cpi.exported)
                 == PackageManager.PERMISSION_GRANTED) {
             return null;
         }
@@ -5339,12 +5344,12 @@
                 i--;
                 PathPermission pp = pps[i];
                 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
-                        cpi.exported ? -1 : cpi.applicationInfo.uid)
+                        cpi.applicationInfo.uid, cpi.exported)
                         == PackageManager.PERMISSION_GRANTED) {
                     return null;
                 }
                 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
-                        cpi.exported ? -1 : cpi.applicationInfo.uid)
+                        cpi.applicationInfo.uid, cpi.exported)
                         == PackageManager.PERMISSION_GRANTED) {
                     return null;
                 }
@@ -5360,10 +5365,18 @@
             }
         }
 
-        String msg = "Permission Denial: opening provider " + cpi.name
-                + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
-                + ", uid=" + callingUid + ") requires "
-                + cpi.readPermission + " or " + cpi.writePermission;
+        String msg;
+        if (!cpi.exported) {
+            msg = "Permission Denial: opening provider " + cpi.name
+                    + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
+                    + ", uid=" + callingUid + ") that is not exported from uid "
+                    + cpi.applicationInfo.uid;
+        } else {
+            msg = "Permission Denial: opening provider " + cpi.name
+                    + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
+                    + ", uid=" + callingUid + ") requires "
+                    + cpi.readPermission + " or " + cpi.writePermission;
+        }
         Slog.w(TAG, msg);
         return msg;
     }
@@ -5953,7 +5966,7 @@
             
         final int perm = checkComponentPermission(
                 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
-                callingUid, -1);
+                callingUid, -1, true);
         if (perm == PackageManager.PERMISSION_GRANTED) {
             return true;
         }
@@ -8892,8 +8905,16 @@
             int callingPid = Binder.getCallingPid();
             int callingUid = Binder.getCallingUid();
             if (checkComponentPermission(r.permission,
-                    callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
+                    callingPid, callingUid, r.appInfo.uid, r.exported)
                     != PackageManager.PERMISSION_GRANTED) {
+                if (!r.exported) {
+                    Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+                            + " from pid=" + callingPid
+                            + ", uid=" + callingUid
+                            + " that is not exported from uid " + r.appInfo.uid);
+                    return new ServiceLookupResult(null, "not exported from uid "
+                            + r.appInfo.uid);
+                }
                 Slog.w(TAG, "Permission Denial: Accessing service " + r.name
                         + " from pid=" + callingPid
                         + ", uid=" + callingUid
@@ -8975,11 +8996,19 @@
         }
         if (r != null) {
             if (checkComponentPermission(r.permission,
-                    callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
+                    callingPid, callingUid, r.appInfo.uid, r.exported)
                     != PackageManager.PERMISSION_GRANTED) {
+                if (!r.exported) {
+                    Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+                            + " from pid=" + callingPid
+                            + ", uid=" + callingUid
+                            + " that is not exported from uid " + r.appInfo.uid);
+                    return new ServiceLookupResult(null, "not exported from uid "
+                            + r.appInfo.uid);
+                }
                 Slog.w(TAG, "Permission Denial: Accessing service " + r.name
-                        + " from pid=" + Binder.getCallingPid()
-                        + ", uid=" + Binder.getCallingUid()
+                        + " from pid=" + callingPid
+                        + ", uid=" + callingUid
                         + " requires " + r.permission);
                 return new ServiceLookupResult(null, r.permission);
             }
@@ -10479,7 +10508,7 @@
                 || uidRemoved) {
             if (checkComponentPermission(
                     android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
-                    callingPid, callingUid, -1)
+                    callingPid, callingUid, -1, true)
                     == PackageManager.PERMISSION_GRANTED) {
                 if (uidRemoved) {
                     final Bundle intentExtras = intent.getExtras();
@@ -11147,7 +11176,7 @@
         boolean skip = false;
         if (filter.requiredPermission != null) {
             int perm = checkComponentPermission(filter.requiredPermission,
-                    r.callingPid, r.callingUid, -1);
+                    r.callingPid, r.callingUid, -1, true);
             if (perm != PackageManager.PERMISSION_GRANTED) {
                 Slog.w(TAG, "Permission Denial: broadcasting "
                         + r.intent.toString()
@@ -11160,7 +11189,7 @@
         }
         if (r.requiredPermission != null) {
             int perm = checkComponentPermission(r.requiredPermission,
-                    filter.receiverList.pid, filter.receiverList.uid, -1);
+                    filter.receiverList.pid, filter.receiverList.uid, -1, true);
             if (perm != PackageManager.PERMISSION_GRANTED) {
                 Slog.w(TAG, "Permission Denial: receiving "
                         + r.intent.toString()
@@ -11426,17 +11455,26 @@
 
             boolean skip = false;
             int perm = checkComponentPermission(info.activityInfo.permission,
-                    r.callingPid, r.callingUid,
-                    info.activityInfo.exported
-                            ? -1 : info.activityInfo.applicationInfo.uid);
+                    r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
+                    info.activityInfo.exported);
             if (perm != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission Denial: broadcasting "
-                        + r.intent.toString()
-                        + " from " + r.callerPackage + " (pid=" + r.callingPid
-                        + ", uid=" + r.callingUid + ")"
-                        + " requires " + info.activityInfo.permission
-                        + " due to receiver " + info.activityInfo.packageName
-                        + "/" + info.activityInfo.name);
+                if (!info.activityInfo.exported) {
+                    Slog.w(TAG, "Permission Denial: broadcasting "
+                            + r.intent.toString()
+                            + " from " + r.callerPackage + " (pid=" + r.callingPid
+                            + ", uid=" + r.callingUid + ")"
+                            + " is not exported from uid " + info.activityInfo.applicationInfo.uid
+                            + " due to receiver " + info.activityInfo.packageName
+                            + "/" + info.activityInfo.name);
+                } else {
+                    Slog.w(TAG, "Permission Denial: broadcasting "
+                            + r.intent.toString()
+                            + " from " + r.callerPackage + " (pid=" + r.callingPid
+                            + ", uid=" + r.callingUid + ")"
+                            + " requires " + info.activityInfo.permission
+                            + " due to receiver " + info.activityInfo.packageName
+                            + "/" + info.activityInfo.name);
+                }
                 skip = true;
             }
             if (r.callingUid != Process.SYSTEM_UID &&
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index bc00478..dd6ddd6 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -2035,17 +2035,25 @@
         }
 
         final int perm = mService.checkComponentPermission(aInfo.permission, callingPid,
-                callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
+                callingUid, aInfo.applicationInfo.uid, aInfo.exported);
         if (perm != PackageManager.PERMISSION_GRANTED) {
             if (resultRecord != null) {
                 sendActivityResultLocked(-1,
                     resultRecord, resultWho, requestCode,
                     Activity.RESULT_CANCELED, null);
             }
-            String msg = "Permission Denial: starting " + intent.toString()
-                    + " from " + callerApp + " (pid=" + callingPid
-                    + ", uid=" + callingUid + ")"
-                    + " requires " + aInfo.permission;
+            String msg;
+            if (!aInfo.exported) {
+                msg = "Permission Denial: starting " + intent.toString()
+                        + " from " + callerApp + " (pid=" + callingPid
+                        + ", uid=" + callingUid + ")"
+                        + " not exported from uid " + aInfo.applicationInfo.uid;
+            } else {
+                msg = "Permission Denial: starting " + intent.toString()
+                        + " from " + callerApp + " (pid=" + callingPid
+                        + ", uid=" + callingUid + ")"
+                        + " requires " + aInfo.permission;
+            }
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 134b91e..dd9db9a 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -1233,18 +1233,18 @@
                 for (String iface : ifaces) {
                     for (String regex : mUpstreamIfaceRegexs) {
                         if (iface.matches(regex)) {
-                            // verify it is up!
+                            // verify it is active
                             InterfaceConfiguration ifcg = null;
                             try {
                                 ifcg = service.getInterfaceConfig(iface);
+                                if (ifcg.isActive()) {
+                                    return iface;
+                                }
                             } catch (Exception e) {
                                 Log.e(TAG, "Error getting iface config :" + e);
                                 // ignore - try next
                                 continue;
                             }
-                            if (ifcg.interfaceFlags.contains("up")) {
-                                return iface;
-                            }
                         }
                     }
                 }
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index e04e4c3..5b329bb 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -62,6 +62,7 @@
     jmethodID checkInjectEventsPermission;
     jmethodID filterTouchEvents;
     jmethodID filterJumpyTouchEvents;
+    jmethodID getVirtualKeyQuietTimeMillis;
     jmethodID getExcludedDeviceNames;
     jmethodID getMaxEventsPerSecond;
     jmethodID getPointerLayer;
@@ -159,6 +160,7 @@
             int32_t* width, int32_t* height, int32_t* orientation);
     virtual bool filterTouchEvents();
     virtual bool filterJumpyTouchEvents();
+    virtual nsecs_t getVirtualKeyQuietTime();
     virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames);
     virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId);
 
@@ -191,6 +193,7 @@
     // Cached filtering policies.
     int32_t mFilterTouchEvents;
     int32_t mFilterJumpyTouchEvents;
+    nsecs_t mVirtualKeyQuietTime;
 
     // Cached throttling policy.
     int32_t mMaxEventsPerSecond;
@@ -219,7 +222,7 @@
 
 
 NativeInputManager::NativeInputManager(jobject callbacksObj) :
-    mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1),
+    mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), mVirtualKeyQuietTime(-1),
     mMaxEventsPerSecond(-1) {
     JNIEnv* env = jniEnv();
 
@@ -355,6 +358,24 @@
     return mFilterJumpyTouchEvents;
 }
 
+nsecs_t NativeInputManager::getVirtualKeyQuietTime() {
+    if (mVirtualKeyQuietTime < 0) {
+        JNIEnv* env = jniEnv();
+
+        jint result = env->CallIntMethod(mCallbacksObj,
+                gCallbacksClassInfo.getVirtualKeyQuietTimeMillis);
+        if (checkAndClearExceptionFromCallback(env, "getVirtualKeyQuietTimeMillis")) {
+            result = 0;
+        }
+        if (result < 0) {
+            result = 0;
+        }
+
+        mVirtualKeyQuietTime = milliseconds_to_nanoseconds(result);
+    }
+    return mVirtualKeyQuietTime;
+}
+
 void NativeInputManager::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) {
     outExcludedDeviceNames.clear();
 
@@ -1155,6 +1176,9 @@
     GET_METHOD_ID(gCallbacksClassInfo.filterJumpyTouchEvents, gCallbacksClassInfo.clazz,
             "filterJumpyTouchEvents", "()Z");
 
+    GET_METHOD_ID(gCallbacksClassInfo.getVirtualKeyQuietTimeMillis, gCallbacksClassInfo.clazz,
+            "getVirtualKeyQuietTimeMillis", "()I");
+
     GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz,
             "getExcludedDeviceNames", "()[Ljava/lang/String;");
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 2c5aa3c..19e7fae 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -152,9 +152,16 @@
     private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {
         @Override
         public void onChange(boolean selfChange) {
-            Log.i("CdmaServiceStateTracker", "Auto time state called ...");
-            revertToNitz();
+            Log.i("CdmaServiceStateTracker", "Auto time state changed");
+            revertToNitzTime();
+        }
+    };
 
+    private ContentObserver mAutoTimeZoneObserver = new ContentObserver(new Handler()) {
+        @Override
+        public void onChange(boolean selfChange) {
+            Log.i("CdmaServiceStateTracker", "Auto time zone state changed");
+            revertToNitzTimeZone();
         }
     };
 
@@ -194,6 +201,9 @@
         cr.registerContentObserver(
                 Settings.System.getUriFor(Settings.System.AUTO_TIME), true,
                 mAutoTimeObserver);
+        cr.registerContentObserver(
+            Settings.System.getUriFor(Settings.System.AUTO_TIME_ZONE), true,
+            mAutoTimeZoneObserver);
         setSignalStrengthDefaultValues();
 
         mNeedToRegForRuimLoaded = true;
@@ -212,6 +222,7 @@
         cm.unSetOnSignalStrengthUpdate(this);
         cm.unSetOnNITZTime(this);
         cr.unregisterContentObserver(this.mAutoTimeObserver);
+        cr.unregisterContentObserver(this.mAutoTimeZoneObserver);
     }
 
     @Override
@@ -1582,20 +1593,29 @@
         phone.getContext().sendStickyBroadcast(intent);
     }
 
-     private void revertToNitz() {
+    private void revertToNitzTime() {
         if (Settings.System.getInt(cr, Settings.System.AUTO_TIME, 0) == 0) {
             return;
         }
-        Log.d(LOG_TAG, "Reverting to NITZ: tz='" + mSavedTimeZone
-                + "' mSavedTime=" + mSavedTime
+        Log.d(LOG_TAG, "Reverting to NITZ Time: mSavedTime=" + mSavedTime
                 + " mSavedAtTime=" + mSavedAtTime);
-        if (mSavedTimeZone != null && mSavedTime != 0 && mSavedAtTime != 0) {
-            setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
+        if (mSavedTime != 0 && mSavedAtTime != 0) {
             setAndBroadcastNetworkSetTime(mSavedTime
                     + (SystemClock.elapsedRealtime() - mSavedAtTime));
         }
     }
 
+    private void revertToNitzTimeZone() {
+        if (Settings.System.getInt(phone.getContext().getContentResolver(),
+                Settings.System.AUTO_TIME_ZONE, 0) == 0) {
+            return;
+        }
+        Log.d(LOG_TAG, "Reverting to NITZ TimeZone: tz='" + mSavedTimeZone);
+        if (mSavedTimeZone != null) {
+            setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
+        }
+    }
+
     private boolean isSidsAllZeros() {
         if (mHomeSystemId != null) {
             for (int i=0; i < mHomeSystemId.length; i++) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index b04d4b9..c107d17 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -181,7 +181,15 @@
         @Override
         public void onChange(boolean selfChange) {
             Log.i("GsmServiceStateTracker", "Auto time state changed");
-            revertToNitz();
+            revertToNitzTime();
+        }
+    };
+
+    private ContentObserver mAutoTimeZoneObserver = new ContentObserver(new Handler()) {
+        @Override
+        public void onChange(boolean selfChange) {
+            Log.i("GsmServiceStateTracker", "Auto time zone state changed");
+            revertToNitzTimeZone();
         }
     };
 
@@ -220,6 +228,10 @@
         cr.registerContentObserver(
                 Settings.System.getUriFor(Settings.System.AUTO_TIME), true,
                 mAutoTimeObserver);
+        cr.registerContentObserver(
+                Settings.System.getUriFor(Settings.System.AUTO_TIME_ZONE), true,
+                mAutoTimeZoneObserver);
+
         setSignalStrengthDefaultValues();
         mNeedToRegForSimLoaded = true;
 
@@ -244,6 +256,7 @@
         cm.unSetOnRestrictedStateChanged(this);
         cm.unSetOnNITZTime(this);
         cr.unregisterContentObserver(this.mAutoTimeObserver);
+        cr.unregisterContentObserver(this.mAutoTimeZoneObserver);
     }
 
     protected void finalize() {
@@ -1613,21 +1626,30 @@
         phone.getContext().sendStickyBroadcast(intent);
     }
 
-    private void revertToNitz() {
+    private void revertToNitzTime() {
         if (Settings.System.getInt(phone.getContext().getContentResolver(),
                 Settings.System.AUTO_TIME, 0) == 0) {
             return;
         }
-        Log.d(LOG_TAG, "Reverting to NITZ: tz='" + mSavedTimeZone
-                + "' mSavedTime=" + mSavedTime
+        Log.d(LOG_TAG, "Reverting to NITZ Time: mSavedTime=" + mSavedTime
                 + " mSavedAtTime=" + mSavedAtTime);
-        if (mSavedTimeZone != null && mSavedTime != 0 && mSavedAtTime != 0) {
-            setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
+        if (mSavedTime != 0 && mSavedAtTime != 0) {
             setAndBroadcastNetworkSetTime(mSavedTime
                     + (SystemClock.elapsedRealtime() - mSavedAtTime));
         }
     }
 
+    private void revertToNitzTimeZone() {
+        if (Settings.System.getInt(phone.getContext().getContentResolver(),
+                Settings.System.AUTO_TIME_ZONE, 0) == 0) {
+            return;
+        }
+        Log.d(LOG_TAG, "Reverting to NITZ TimeZone: tz='" + mSavedTimeZone);
+        if (mSavedTimeZone != null) {
+            setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
+        }
+    }
+
     /**
      * Post a notification to NotificationManager for restricted state
      *
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 2e4199e..0d20496 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -495,18 +495,4 @@
     public boolean isSafeMode() {
         throw new UnsupportedOperationException();
     }
-
-    public void setPackageObbPath(String packageName, String path) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void setPackageObbPaths(String packageName, String[] paths) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String[] getPackageObbPaths(String packageName) {
-        throw new UnsupportedOperationException();
-    }
 }
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
index e5a46b9..5bcf727 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
@@ -89,13 +89,12 @@
     }
 
     private void freeMem() {
-        Log.v(LOGTAG, "freeMem: calling gc/finalization...");
+        Log.v(LOGTAG, "freeMem: calling gc...");
         final VMRuntime runtime = VMRuntime.getRuntime();
 
         runtime.gcSoftReferences();
         runtime.gcSoftReferences();
         runtime.gcSoftReferences();
-        Runtime.getRuntime().runFinalization();
         Runtime.getRuntime().gc();
         Runtime.getRuntime().gc();
 
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 7099ab5..691aff28 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -166,6 +166,15 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        
+        <activity
+                android:name="BitmapsSkewActivity"
+                android:label="_BitmapsSkew">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
 
         <activity
                 android:name="BitmapsAlphaActivity"
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsActivity.java
index 4054353..607a173 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsActivity.java
@@ -25,6 +25,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
 import android.view.animation.Animation;
@@ -61,7 +62,15 @@
 
             mBitmap1 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
             mBitmap2 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset2);
+            
+            Log.d("Bitmap", "mBitmap1.isMutable() = " + mBitmap1.isMutable());
+            Log.d("Bitmap", "mBitmap2.isMutable() = " + mBitmap2.isMutable());
 
+            BitmapFactory.Options opts = new BitmapFactory.Options();
+            opts.inMutable = true;
+            Bitmap bitmap = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1, opts);
+            Log.d("Bitmap", "bitmap.isMutable() = " + bitmap.isMutable());
+            
             mBitmapPaint = new Paint();
             mDstIn = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
         }
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsSkewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsSkewActivity.java
new file mode 100644
index 0000000..099c0dd
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsSkewActivity.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class BitmapsSkewActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final BitmapsView view = new BitmapsView(this);
+        setContentView(view);
+    }
+
+    static class BitmapsView extends View {
+        private Paint mBitmapPaint;
+        private final Bitmap mBitmap1;
+
+        BitmapsView(Context c) {
+            super(c);
+
+            mBitmap1 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            canvas.translate(120.0f, 50.0f);
+            canvas.skew(0.2f, 0.3f);
+            canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBitmapPaint);
+        }
+    }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
index 1b79cb6..e7f431c 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
@@ -37,6 +37,7 @@
         private final Paint mLargePaint;
         private final Paint mStrikePaint;
         private final Paint mScaledPaint;
+        private final Paint mSkewPaint;
 
         CustomTextView(Context c) {
             super(c);
@@ -57,6 +58,10 @@
             mScaledPaint = new Paint();
             mScaledPaint.setAntiAlias(true);
             mScaledPaint.setTextSize(16.0f);
+
+            mSkewPaint = new Paint();
+            mSkewPaint.setAntiAlias(true);
+            mSkewPaint.setTextSize(16.0f);            
         }
 
         @Override
@@ -100,11 +105,18 @@
             mStrikePaint.setStrikeThruText(false);
             mStrikePaint.setUnderlineText(true);
             
+            mSkewPaint.setTextSkewX(-0.25f);
+            canvas.drawText("Hello OpenGL renderer!", 680, 200, mSkewPaint);
+            mSkewPaint.setTextSkewX(0.5f);
+            canvas.drawText("Hello OpenGL renderer!", 680, 230, mSkewPaint);
+            mSkewPaint.setTextSkewX(0.0f);
+            canvas.drawText("Hello OpenGL renderer!", 680, 260, mSkewPaint);
+
             mScaledPaint.setTextScaleX(0.5f);
             canvas.drawText("Hello OpenGL renderer!", 500, 200, mScaledPaint);
-            mScaledPaint.setTextScaleX(2.0f);
-            canvas.drawText("Hello OpenGL renderer!", 500, 230, mScaledPaint);
             mScaledPaint.setTextScaleX(1.0f);
+            canvas.drawText("Hello OpenGL renderer!", 500, 230, mScaledPaint);
+            mScaledPaint.setTextScaleX(2.0f);
             canvas.drawText("Hello OpenGL renderer!", 500, 260, mScaledPaint);
             
             canvas.save();
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity2.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity2.java
index a0b1d78..e795f02 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity2.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity2.java
@@ -38,6 +38,8 @@
         setupList(R.id.list1);
         setupList(R.id.list2);
         setupList(R.id.list3);
+        
+        findViewById(R.id.list1).setAlpha(0.7f);
     }
 
     private void setupList(int listId) {
diff --git a/tools/layoutlib/bridge/src/com/android/ide/common/resources/ResourceResolver.java b/tools/layoutlib/bridge/src/com/android/ide/common/resources/ResourceResolver.java
deleted file mode 100644
index 4c500e7..0000000
--- a/tools/layoutlib/bridge/src/com/android/ide/common/resources/ResourceResolver.java
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ide.common.resources;
-
-import com.android.ide.common.rendering.api.LayoutLog;
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.rendering.api.StyleResourceValue;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-public class ResourceResolver {
-
-    public final static String RES_ANIMATOR = "animator";
-    public final static String RES_STYLE = "style";
-    public final static String RES_ATTR = "attr";
-    public final static String RES_DIMEN = "dimen";
-    public final static String RES_DRAWABLE = "drawable";
-    public final static String RES_COLOR = "color";
-    public final static String RES_LAYOUT = "layout";
-    public final static String RES_STRING = "string";
-    public final static String RES_ID = "id";
-
-    public final static String REFERENCE_NULL = "@null";
-
-    private final static String REFERENCE_STYLE = RES_STYLE + "/";
-    private final static String PREFIX_ANDROID_RESOURCE_REF = "@android:";
-    private final static String PREFIX_RESOURCE_REF = "@";
-    private final static String PREFIX_ANDROID_THEME_REF = "?android:";
-    private final static String PREFIX_THEME_REF = "?";
-    private final static String PREFIX_ANDROID = "android:";
-
-
-    private final IFrameworkResourceIdProvider mFrameworkProvider;
-    private final Map<String, Map<String, ResourceValue>>  mProjectResources;
-    private final Map<String, Map<String, ResourceValue>>  mFrameworkResources;
-    private final LayoutLog mLogger;
-
-    private final Map<StyleResourceValue, StyleResourceValue> mStyleInheritanceMap =
-        new HashMap<StyleResourceValue, StyleResourceValue>();
-    private StyleResourceValue mTheme;
-
-    public interface IFrameworkResourceIdProvider {
-        Integer getId(String resType, String resName);
-    }
-
-    private ResourceResolver(
-            IFrameworkResourceIdProvider provider,
-            Map<String, Map<String, ResourceValue>> projectResources,
-            Map<String, Map<String, ResourceValue>> frameworkResources,
-            LayoutLog logger) {
-        mFrameworkProvider = provider;
-        mProjectResources = projectResources;
-        mFrameworkResources = frameworkResources;
-        mLogger = logger;
-    }
-
-    /**
-     * Creates a new ResourceResolver object.
-     *
-     * @param IFrameworkResourceIdProvider an optional framework resource ID provider
-     * @param projectResources the project resources.
-     * @param frameworkResources the framework resources.
-     * @param themeName the name of the current theme.
-     * @param isProjectTheme Is this a project theme?
-     * @return
-     */
-    public static ResourceResolver create(
-            IFrameworkResourceIdProvider provider,
-            Map<String, Map<String, ResourceValue>> projectResources,
-            Map<String, Map<String, ResourceValue>> frameworkResources,
-            String themeName, boolean isProjectTheme, LayoutLog logger) {
-
-        ResourceResolver resolver = new ResourceResolver(provider,
-                projectResources, frameworkResources,
-                logger);
-
-        resolver.computeStyleMaps(themeName, isProjectTheme);
-
-        return resolver;
-    }
-
-    public StyleResourceValue getTheme() {
-        return mTheme;
-    }
-
-    /**
-     * Returns a framework resource by type and name. The returned resource is resolved.
-     * @param resourceType the type of the resource
-     * @param resourceName the name of the resource
-     */
-    public ResourceValue getFrameworkResource(String resourceType, String resourceName) {
-        return getResource(resourceType, resourceName, mFrameworkResources);
-    }
-
-    /**
-     * Returns a project resource by type and name. The returned resource is resolved.
-     * @param resourceType the type of the resource
-     * @param resourceName the name of the resource
-     */
-    public ResourceValue getProjectResource(String resourceType, String resourceName) {
-        return getResource(resourceType, resourceName, mProjectResources);
-    }
-
-    /**
-     * Returns the {@link ResourceValue} matching a given name in the current theme. If the
-     * item is not directly available in the theme, the method looks in its parent theme.
-     *
-     * @param itemName the name of the item to search for.
-     * @return the {@link ResourceValue} object or <code>null</code>
-     */
-    public ResourceValue findItemInTheme(String itemName) {
-        if (mTheme != null) {
-            return findItemInStyle(mTheme, itemName);
-        }
-
-        return null;
-    }
-
-    /**
-     * Returns the {@link ResourceValue} matching a given name in a given style. If the
-     * item is not directly available in the style, the method looks in its parent style.
-     *
-     * @param style the style to search in
-     * @param itemName the name of the item to search for.
-     * @return the {@link ResourceValue} object or <code>null</code>
-     */
-    public ResourceValue findItemInStyle(StyleResourceValue style, String itemName) {
-        ResourceValue item = style.findValue(itemName);
-
-        // if we didn't find it, we look in the parent style (if applicable)
-        if (item == null && mStyleInheritanceMap != null) {
-            StyleResourceValue parentStyle = mStyleInheritanceMap.get(style);
-            if (parentStyle != null) {
-                return findItemInStyle(parentStyle, itemName);
-            }
-        }
-
-        return item;
-    }
-
-    /**
-     * Searches for, and returns a {@link ResourceValue} by its reference.
-     * <p/>
-     * The reference format can be:
-     * <pre>@resType/resName</pre>
-     * <pre>@android:resType/resName</pre>
-     * <pre>@resType/android:resName</pre>
-     * <pre>?resType/resName</pre>
-     * <pre>?android:resType/resName</pre>
-     * <pre>?resType/android:resName</pre>
-     * Any other string format will return <code>null</code>.
-     * <p/>
-     * The actual format of a reference is <pre>@[namespace:]resType/resName</pre> but this method
-     * only support the android namespace.
-     *
-     * @param reference the resource reference to search for.
-     * @param forceFrameworkOnly if true all references are considered to be toward framework
-     *      resource even if the reference does not include the android: prefix.
-     * @return a {@link ResourceValue} or <code>null</code>.
-     */
-    public ResourceValue findResValue(String reference, boolean forceFrameworkOnly) {
-        if (reference == null) {
-            return null;
-        }
-        if (reference.startsWith(PREFIX_THEME_REF)) {
-            // no theme? no need to go further!
-            if (mTheme == null) {
-                return null;
-            }
-
-            boolean frameworkOnly = false;
-
-            // eliminate the prefix from the string
-            if (reference.startsWith(PREFIX_ANDROID_THEME_REF)) {
-                frameworkOnly = true;
-                reference = reference.substring(PREFIX_ANDROID_THEME_REF.length());
-            } else {
-                reference = reference.substring(PREFIX_THEME_REF.length());
-            }
-
-            // at this point, value can contain type/name (drawable/foo for instance).
-            // split it to make sure.
-            String[] segments = reference.split("\\/");
-
-            // we look for the referenced item name.
-            String referenceName = null;
-
-            if (segments.length == 2) {
-                // there was a resType in the reference. If it's attr, we ignore it
-                // else, we assert for now.
-                if (RES_ATTR.equals(segments[0])) {
-                    referenceName = segments[1];
-                } else {
-                    // At this time, no support for ?type/name where type is not "attr"
-                    return null;
-                }
-            } else {
-                // it's just an item name.
-                referenceName = segments[0];
-            }
-
-            // now we look for android: in the referenceName in order to support format
-            // such as: ?attr/android:name
-            if (referenceName.startsWith(PREFIX_ANDROID)) {
-                frameworkOnly = true;
-                referenceName = referenceName.substring(PREFIX_ANDROID.length());
-            }
-
-            // Now look for the item in the theme, starting with the current one.
-            if (frameworkOnly) {
-                // FIXME for now we do the same as if it didn't specify android:
-                return findItemInStyle(mTheme, referenceName);
-            }
-
-            return findItemInStyle(mTheme, referenceName);
-        } else if (reference.startsWith(PREFIX_RESOURCE_REF)) {
-            boolean frameworkOnly = false;
-
-            // check for the specific null reference value.
-            if (REFERENCE_NULL.equals(reference)) {
-                return null;
-            }
-
-            // Eliminate the prefix from the string.
-            if (reference.startsWith(PREFIX_ANDROID_RESOURCE_REF)) {
-                frameworkOnly = true;
-                reference = reference.substring(
-                        PREFIX_ANDROID_RESOURCE_REF.length());
-            } else {
-                reference = reference.substring(PREFIX_RESOURCE_REF.length());
-            }
-
-            // at this point, value contains type/[android:]name (drawable/foo for instance)
-            String[] segments = reference.split("\\/");
-
-            // now we look for android: in the resource name in order to support format
-            // such as: @drawable/android:name
-            if (segments[1].startsWith(PREFIX_ANDROID)) {
-                frameworkOnly = true;
-                segments[1] = segments[1].substring(PREFIX_ANDROID.length());
-            }
-
-            return findResValue(segments[0], segments[1],
-                    forceFrameworkOnly ? true :frameworkOnly);
-        }
-
-        // Looks like the value didn't reference anything. Return null.
-        return null;
-    }
-
-    /**
-     * Resolves the value of a resource, if the value references a theme or resource value.
-     * <p/>
-     * This method ensures that it returns a {@link ResourceValue} object that does not
-     * reference another resource.
-     * If the resource cannot be resolved, it returns <code>null</code>.
-     * <p/>
-     * If a value that does not need to be resolved is given, the method will return a new
-     * instance of {@link ResourceValue} that contains the input value.
-     *
-     * @param type the type of the resource
-     * @param name the name of the attribute containing this value.
-     * @param value the resource value, or reference to resolve
-     * @param isFrameworkValue whether the value is a framework value.
-     *
-     * @return the resolved resource value or <code>null</code> if it failed to resolve it.
-     */
-    public ResourceValue resolveValue(String type, String name, String value,
-            boolean isFrameworkValue) {
-        if (value == null) {
-            return null;
-        }
-
-        // get the ResourceValue referenced by this value
-        ResourceValue resValue = findResValue(value, isFrameworkValue);
-
-        // if resValue is null, but value is not null, this means it was not a reference.
-        // we return the name/value wrapper in a ResourceValue. the isFramework flag doesn't
-        // matter.
-        if (resValue == null) {
-            return new ResourceValue(type, name, value, isFrameworkValue);
-        }
-
-        // we resolved a first reference, but we need to make sure this isn't a reference also.
-        return resolveResValue(resValue);
-    }
-
-    /**
-     * Returns the {@link ResourceValue} referenced by the value of <var>value</var>.
-     * <p/>
-     * This method ensures that it returns a {@link ResourceValue} object that does not
-     * reference another resource.
-     * If the resource cannot be resolved, it returns <code>null</code>.
-     * <p/>
-     * If a value that does not need to be resolved is given, the method will return the input
-     * value.
-     *
-     * @param value the value containing the reference to resolve.
-     * @return a {@link ResourceValue} object or <code>null</code>
-     */
-    public ResourceValue resolveResValue(ResourceValue value) {
-        if (value == null) {
-            return null;
-        }
-
-        // if the resource value is a style, we simply return it.
-        if (value instanceof StyleResourceValue) {
-            return value;
-        }
-
-        // else attempt to find another ResourceValue referenced by this one.
-        ResourceValue resolvedValue = findResValue(value.getValue(), value.isFramework());
-
-        // if the value did not reference anything, then we simply return the input value
-        if (resolvedValue == null) {
-            return value;
-        }
-
-        // otherwise, we attempt to resolve this new value as well
-        return resolveResValue(resolvedValue);
-    }
-
-
-    /**
-     * Searches for, and returns a {@link ResourceValue} by its name, and type.
-     * @param resType the type of the resource
-     * @param resName  the name of the resource
-     * @param frameworkOnly if <code>true</code>, the method does not search in the
-     * project resources
-     */
-    private ResourceValue findResValue(String resType, String resName, boolean frameworkOnly) {
-        // map of ResouceValue for the given type
-        Map<String, ResourceValue> typeMap;
-
-        // if allowed, search in the project resources first.
-        if (frameworkOnly == false) {
-            typeMap = mProjectResources.get(resType);
-            if (typeMap != null) {
-                ResourceValue item = typeMap.get(resName);
-                if (item != null) {
-                    return item;
-                }
-            }
-        }
-
-        // now search in the framework resources.
-        typeMap = mFrameworkResources.get(resType);
-        if (typeMap != null) {
-            ResourceValue item = typeMap.get(resName);
-            if (item != null) {
-                return item;
-            }
-
-            // if it was not found and the type is an id, it is possible that the ID was
-            // generated dynamically when compiling the framework resources.
-            // Look for it in the R map.
-            if (mFrameworkProvider != null && RES_ID.equals(resType)) {
-                if (mFrameworkProvider.getId(resType, resName) != null) {
-                    return new ResourceValue(resType, resName, true);
-                }
-            }
-        }
-
-        // didn't find the resource anywhere.
-        // This is normal if the resource is an ID that is generated automatically.
-        // For other resources, we output a warning
-        if ("+id".equals(resType) == false && "+android:id".equals(resType) == false) { //$NON-NLS-1$ //$NON-NLS-2$
-            mLogger.warning(LayoutLog.TAG_RESOURCES_RESOLVE,
-                    "Couldn't resolve resource @" +
-                    (frameworkOnly ? "android:" : "") + resType + "/" + resName,
-                    new ResourceValue(resType, resName, frameworkOnly));
-        }
-        return null;
-    }
-
-    ResourceValue getResource(String resourceType, String resourceName,
-            Map<String, Map<String, ResourceValue>> resourceRepository) {
-        Map<String, ResourceValue> typeMap = resourceRepository.get(resourceType);
-        if (typeMap != null) {
-            ResourceValue item = typeMap.get(resourceName);
-            if (item != null) {
-                item = resolveResValue(item);
-                return item;
-            }
-        }
-
-        // didn't find the resource anywhere.
-        return null;
-
-    }
-
-    /**
-     * Compute style information from the given list of style for the project and framework.
-     * @param themeName the name of the current theme.
-     * @param isProjectTheme Is this a project theme?
-     */
-    private void computeStyleMaps(String themeName, boolean isProjectTheme) {
-        Map<String, ResourceValue> projectStyleMap = mProjectResources.get(RES_STYLE);
-        Map<String, ResourceValue> frameworkStyleMap = mFrameworkResources.get(RES_STYLE);
-
-        if (projectStyleMap != null && frameworkStyleMap != null) {
-            // first, get the theme
-            ResourceValue theme = null;
-
-            // project theme names have been prepended with a *
-            if (isProjectTheme) {
-                theme = projectStyleMap.get(themeName);
-            } else {
-                theme = frameworkStyleMap.get(themeName);
-            }
-
-            if (theme instanceof StyleResourceValue) {
-                // compute the inheritance map for both the project and framework styles
-                computeStyleInheritance(projectStyleMap.values(), projectStyleMap,
-                        frameworkStyleMap);
-
-                // Compute the style inheritance for the framework styles/themes.
-                // Since, for those, the style parent values do not contain 'android:'
-                // we want to force looking in the framework style only to avoid using
-                // similarly named styles from the project.
-                // To do this, we pass null in lieu of the project style map.
-                computeStyleInheritance(frameworkStyleMap.values(), null /*inProjectStyleMap */,
-                        frameworkStyleMap);
-
-                mTheme = (StyleResourceValue) theme;
-            }
-        }
-    }
-
-
-
-    /**
-     * Compute the parent style for all the styles in a given list.
-     * @param styles the styles for which we compute the parent.
-     * @param inProjectStyleMap the map of project styles.
-     * @param inFrameworkStyleMap the map of framework styles.
-     * @param outInheritanceMap the map of style inheritance. This is filled by the method.
-     */
-    private void computeStyleInheritance(Collection<ResourceValue> styles,
-            Map<String, ResourceValue> inProjectStyleMap,
-            Map<String, ResourceValue> inFrameworkStyleMap) {
-        for (ResourceValue value : styles) {
-            if (value instanceof StyleResourceValue) {
-                StyleResourceValue style = (StyleResourceValue)value;
-                StyleResourceValue parentStyle = null;
-
-                // first look for a specified parent.
-                String parentName = style.getParentStyle();
-
-                // no specified parent? try to infer it from the name of the style.
-                if (parentName == null) {
-                    parentName = getParentName(value.getName());
-                }
-
-                if (parentName != null) {
-                    parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap);
-
-                    if (parentStyle != null) {
-                        mStyleInheritanceMap.put(style, parentStyle);
-                    }
-                }
-            }
-        }
-    }
-
-
-    /**
-     * Computes the name of the parent style, or <code>null</code> if the style is a root style.
-     */
-    private String getParentName(String styleName) {
-        int index = styleName.lastIndexOf('.');
-        if (index != -1) {
-            return styleName.substring(0, index);
-        }
-
-        return null;
-    }
-
-    /**
-     * Searches for and returns the {@link StyleResourceValue} from a given name.
-     * <p/>The format of the name can be:
-     * <ul>
-     * <li>[android:]&lt;name&gt;</li>
-     * <li>[android:]style/&lt;name&gt;</li>
-     * <li>@[android:]style/&lt;name&gt;</li>
-     * </ul>
-     * @param parentName the name of the style.
-     * @param inProjectStyleMap the project style map. Can be <code>null</code>
-     * @param inFrameworkStyleMap the framework style map.
-     * @return The matching {@link StyleResourceValue} object or <code>null</code> if not found.
-     */
-    private StyleResourceValue getStyle(String parentName,
-            Map<String, ResourceValue> inProjectStyleMap,
-            Map<String, ResourceValue> inFrameworkStyleMap) {
-        boolean frameworkOnly = false;
-
-        String name = parentName;
-
-        // remove the useless @ if it's there
-        if (name.startsWith(PREFIX_RESOURCE_REF)) {
-            name = name.substring(PREFIX_RESOURCE_REF.length());
-        }
-
-        // check for framework identifier.
-        if (name.startsWith(PREFIX_ANDROID)) {
-            frameworkOnly = true;
-            name = name.substring(PREFIX_ANDROID.length());
-        }
-
-        // at this point we could have the format <type>/<name>. we want only the name as long as
-        // the type is style.
-        if (name.startsWith(REFERENCE_STYLE)) {
-            name = name.substring(REFERENCE_STYLE.length());
-        } else if (name.indexOf('/') != -1) {
-            return null;
-        }
-
-        ResourceValue parent = null;
-
-        // if allowed, search in the project resources.
-        if (frameworkOnly == false && inProjectStyleMap != null) {
-            parent = inProjectStyleMap.get(name);
-        }
-
-        // if not found, then look in the framework resources.
-        if (parent == null) {
-            parent = inFrameworkStyleMap.get(name);
-        }
-
-        // make sure the result is the proper class type and return it.
-        if (parent instanceof StyleResourceValue) {
-            return (StyleResourceValue)parent;
-        }
-
-        assert false;
-        mLogger.error(LayoutLog.TAG_RESOURCES_RESOLVE,
-                String.format("Unable to resolve parent style name: %s", parentName),
-                null /*data*/);
-
-        return null;
-    }
-
-
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index f633201..8d194925 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -18,9 +18,9 @@
 
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.StyleResourceValue;
-import com.android.ide.common.resources.ResourceResolver;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
 import com.android.layoutlib.bridge.impl.Stack;
@@ -74,12 +74,13 @@
  */
 public final class BridgeContext extends Activity {
 
-    private Resources mResources;
+    private Resources mSystemResources;
     private Theme mTheme;
     private final HashMap<View, Object> mViewKeyMap = new HashMap<View, Object>();
     private final Object mProjectKey;
     private final DisplayMetrics mMetrics;
-    private final ResourceResolver mResourceResolver;
+    private final RenderResources mRenderResources;
+    private final ApplicationInfo mApplicationInfo;
 
     private final Map<Object, Map<String, String>> mDefaultPropMaps =
         new IdentityHashMap<Object, Map<String,String>>();
@@ -112,18 +113,23 @@
      * value is the resource value.
      * @param styleInheritanceMap
      * @param projectCallback
+     * @param targetSdkVersion the targetSdkVersion of the application.
      */
     public BridgeContext(Object projectKey, DisplayMetrics metrics,
-            ResourceResolver resourceResolver,
-            IProjectCallback projectCallback) {
+            RenderResources renderResources,
+            IProjectCallback projectCallback,
+            int targetSdkVersion) {
         mProjectKey = projectKey;
         mMetrics = metrics;
         mProjectCallback = projectCallback;
 
-        mResourceResolver = resourceResolver;
+        mRenderResources = renderResources;
 
         mFragments.mCurState = Fragment.CREATED;
         mFragments.mActivity = this;
+
+        mApplicationInfo = new ApplicationInfo();
+        mApplicationInfo.targetSdkVersion = targetSdkVersion;
     }
 
     /**
@@ -136,13 +142,13 @@
         AssetManager assetManager = AssetManager.getSystem();
         Configuration config = new Configuration();
 
-        mResources = BridgeResources.initSystem(
+        mSystemResources = BridgeResources.initSystem(
                 this,
                 assetManager,
                 mMetrics,
                 config,
                 mProjectCallback);
-        mTheme = mResources.newTheme();
+        mTheme = mSystemResources.newTheme();
     }
 
     /**
@@ -172,8 +178,8 @@
         return mProjectCallback;
     }
 
-    public ResourceResolver getResolver() {
-        return mResourceResolver;
+    public RenderResources getRenderResources() {
+        return mRenderResources;
     }
 
     public Map<String, String> getDefaultPropMap(Object key) {
@@ -225,7 +231,7 @@
 
     @Override
     public Resources getResources() {
-        return mResources;
+        return mSystemResources;
     }
 
     @Override
@@ -261,7 +267,7 @@
 
     @Override
     public final TypedArray obtainStyledAttributes(int[] attrs) {
-        return createStyleBasedTypedArray(mResourceResolver.getTheme(), attrs);
+        return createStyleBasedTypedArray(mRenderResources.getTheme(), attrs);
     }
 
     @Override
@@ -346,7 +352,7 @@
         boolean[] frameworkAttributes = new boolean[1];
         TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, frameworkAttributes);
 
-        BridgeTypedArray ta = ((BridgeResources) mResources).newTypeArray(attrs.length,
+        BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
                 isPlatformFile);
 
         // resolve the defStyleAttr value into a IStyleResourceValue
@@ -358,7 +364,7 @@
             customStyle = set.getAttributeValue(null /* namespace*/, "style");
         }
         if (customStyle != null) {
-            ResourceValue item = mResourceResolver.findResValue(customStyle,
+            ResourceValue item = mRenderResources.findResValue(customStyle,
                     false /*forceFrameworkOnly*/);
 
             if (item instanceof StyleResourceValue) {
@@ -375,11 +381,11 @@
             }
 
             // look for the style in the current theme, and its parent:
-            ResourceValue item = mResourceResolver.findItemInTheme(defStyleName);
+            ResourceValue item = mRenderResources.findItemInTheme(defStyleName);
 
             if (item != null) {
                 // item is a reference to a style entry. Search for it.
-                item = mResourceResolver.findResValue(item.getValue(),
+                item = mRenderResources.findResValue(item.getValue(),
                         false /*forceFrameworkOnly*/);
 
                 if (item instanceof StyleResourceValue) {
@@ -421,13 +427,13 @@
 
                     // look for the value in the defStyle first (and its parent if needed)
                     if (defStyleValues != null) {
-                        resValue = mResourceResolver.findItemInStyle(defStyleValues, name);
+                        resValue = mRenderResources.findItemInStyle(defStyleValues, name);
                     }
 
                     // if the item is not present in the defStyle, we look in the main theme (and
                     // its parent themes)
                     if (resValue == null) {
-                        resValue = mResourceResolver.findItemInTheme(name);
+                        resValue = mRenderResources.findItemInTheme(name);
                     }
 
                     // if we found a value, we make sure this doesn't reference another value.
@@ -438,7 +444,7 @@
                             defaultPropMap.put(name, resValue.getValue());
                         }
 
-                        resValue = mResourceResolver.resolveResValue(resValue);
+                        resValue = mRenderResources.resolveResValue(resValue);
                     }
 
                     ta.bridgeSetValue(index, name, resValue);
@@ -446,7 +452,7 @@
                     // there is a value in the XML, but we need to resolve it in case it's
                     // referencing another resource or a theme value.
                     ta.bridgeSetValue(index, name,
-                            mResourceResolver.resolveValue(null, name, value, isPlatformFile));
+                            mRenderResources.resolveValue(null, name, value, isPlatformFile));
                 }
             }
         }
@@ -473,7 +479,7 @@
             throws Resources.NotFoundException {
         TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, null);
 
-        BridgeTypedArray ta = ((BridgeResources) mResources).newTypeArray(attrs.length,
+        BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
                 false /* platformResourceFlag */);
 
         // loop through all the values in the style map, and init the TypedArray with
@@ -484,10 +490,10 @@
             String name = styleAttribute.getValue();
 
             // get the value from the style, or its parent styles.
-            ResourceValue resValue = mResourceResolver.findItemInStyle(style, name);
+            ResourceValue resValue = mRenderResources.findItemInStyle(style, name);
 
             // resolve it to make sure there are no references left.
-            ta.bridgeSetValue(index, name, mResourceResolver.resolveResValue(resValue));
+            ta.bridgeSetValue(index, name, mRenderResources.resolveResValue(resValue));
         }
 
         ta.sealArray();
@@ -836,7 +842,7 @@
 
     @Override
     public ApplicationInfo getApplicationInfo() {
-        return new ApplicationInfo();
+        return mApplicationInfo;
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
index 61f47ba..7fa6fdf 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
@@ -18,8 +18,8 @@
 
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.resources.ResourceResolver;
 import com.android.layoutlib.bridge.Bridge;
 
 import org.kxml2.io.KXmlParser;
@@ -155,14 +155,14 @@
 
             String[] layoutInfo = Bridge.resolveResourceValue(resource);
             if (layoutInfo != null) {
-                value = bridgeContext.getResolver().getFrameworkResource(
-                        ResourceResolver.RES_LAYOUT, layoutInfo[0]);
+                value = bridgeContext.getRenderResources().getFrameworkResource(
+                        RenderResources.RES_LAYOUT, layoutInfo[0]);
             } else {
                 layoutInfo = mProjectCallback.resolveResourceValue(resource);
 
                 if (layoutInfo != null) {
-                    value = bridgeContext.getResolver().getProjectResource(
-                            ResourceResolver.RES_LAYOUT, layoutInfo[0]);
+                    value = bridgeContext.getRenderResources().getProjectResource(
+                            RenderResources.RES_LAYOUT, layoutInfo[0]);
                 }
             }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
index 3af6a1b..7b66809 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
@@ -104,7 +104,8 @@
 
         if (resourceInfo != null) {
             platformResFlag_out[0] = true;
-            return mContext.getResolver().getFrameworkResource(resourceInfo[1], resourceInfo[0]);
+            return mContext.getRenderResources().getFrameworkResource(
+                    resourceInfo[1], resourceInfo[0]);
         }
 
         // didn't find a match in the framework? look in the project.
@@ -113,7 +114,8 @@
 
             if (resourceInfo != null) {
                 platformResFlag_out[0] = false;
-                return mContext.getResolver().getProjectResource(resourceInfo[1], resourceInfo[0]);
+                return mContext.getRenderResources().getProjectResource(
+                        resourceInfo[1], resourceInfo[0]);
             }
         }
 
@@ -180,8 +182,8 @@
                                 "Failed to configure parser for " + value, e, null /*data*/);
                         // we'll return null below.
                     } catch (Exception e) {
-                        // this is an error and not warning since the file existence is checked before
-                        // attempting to parse it.
+                        // this is an error and not warning since the file existence is
+                        // checked before attempting to parse it.
                         Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
                                 "Failed to parse file " + value, e, null /*data*/);
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index b166da5..8d3c929 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -17,9 +17,9 @@
 package com.android.layoutlib.bridge.android;
 
 import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.StyleResourceValue;
-import com.android.ide.common.resources.ResourceResolver;
 import com.android.internal.util.XmlUtils;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
@@ -634,11 +634,11 @@
             // if this is a framework id
             if (mPlatformFile || value.startsWith("@android") || value.startsWith("@+android")) {
                 // look for idName in the android R classes
-                return mContext.getFrameworkResourceValue(ResourceResolver.RES_ID, idName, defValue);
+                return mContext.getFrameworkResourceValue(RenderResources.RES_ID, idName, defValue);
             }
 
             // look for idName in the project R class.
-            return mContext.getProjectResourceValue(ResourceResolver.RES_ID, idName, defValue);
+            return mContext.getProjectResourceValue(RenderResources.RES_ID, idName, defValue);
         }
 
         // not a direct id valid reference? resolve it
@@ -683,7 +683,7 @@
 
         ResourceValue value = mResourceData[index];
         String stringValue = value.getValue();
-        if (stringValue == null || ResourceResolver.REFERENCE_NULL.equals(stringValue)) {
+        if (stringValue == null || RenderResources.REFERENCE_NULL.equals(stringValue)) {
             return null;
         }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java
index 45d8e26..4a6880b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java
@@ -16,8 +16,8 @@
 
 package com.android.layoutlib.bridge.android;
 
+import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.resources.ResourceResolver;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
 
@@ -58,7 +58,7 @@
         String ns = mParser.getAttributeNamespace(index);
 
         if (BridgeConstants.NS_RESOURCES.equals(ns)) {
-            Integer v = Bridge.getResourceValue(ResourceResolver.RES_ATTR, name);
+            Integer v = Bridge.getResourceValue(RenderResources.RES_ATTR, name);
             if (v != null) {
                 return v.intValue();
             }
@@ -69,7 +69,7 @@
         // this is not an attribute in the android namespace, we query the customviewloader, if
         // the namespaces match.
         if (mContext.getProjectCallback().getNamespace().equals(ns)) {
-            Integer v = mContext.getProjectCallback().getResourceValue(ResourceResolver.RES_ATTR,
+            Integer v = mContext.getProjectCallback().getResourceValue(RenderResources.RES_ATTR,
                     name);
             if (v != null) {
                 return v.intValue();
@@ -103,9 +103,9 @@
 
     private int resolveResourceValue(String value, int defaultValue) {
         // now look for this particular value
-        ResourceResolver resolver = mContext.getResolver();
-        ResourceValue resource = resolver.resolveResValue(
-                resolver.findResValue(value, mPlatformFile));
+        RenderResources resources = mContext.getRenderResources();
+        ResourceValue resource = resources.resolveResValue(
+                resources.findResValue(value, mPlatformFile));
 
         if (resource != null) {
             Integer id = null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index a227d0c..63d52e9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -30,6 +30,7 @@
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.ide.common.rendering.api.Params;
+import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.RenderSession;
 import com.android.ide.common.rendering.api.ResourceDensity;
 import com.android.ide.common.rendering.api.ResourceValue;
@@ -37,9 +38,8 @@
 import com.android.ide.common.rendering.api.StyleResourceValue;
 import com.android.ide.common.rendering.api.ViewInfo;
 import com.android.ide.common.rendering.api.Params.RenderingMode;
+import com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider;
 import com.android.ide.common.rendering.api.Result.Status;
-import com.android.ide.common.resources.ResourceResolver;
-import com.android.ide.common.resources.ResourceResolver.IFrameworkResourceIdProvider;
 import com.android.internal.util.XmlUtils;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
@@ -67,8 +67,10 @@
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup.LayoutParams;
 import android.widget.FrameLayout;
+import android.widget.LinearLayout;
 import android.widget.TabHost;
 import android.widget.TabWidget;
+import android.widget.TabHost.TabSpec;
 
 import java.awt.Color;
 import java.awt.Graphics2D;
@@ -87,7 +89,7 @@
  * be done on the layout.
  *
  */
-public class RenderSessionImpl {
+public class RenderSessionImpl extends FrameworkResourceIdProvider {
 
     private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
     private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
@@ -156,8 +158,6 @@
             return result;
         }
 
-        Bridge.setLog(mParams.getLog());
-
         // setup the display Metrics.
         DisplayMetrics metrics = new DisplayMetrics();
         metrics.densityDpi = mParams.getDensity();
@@ -168,40 +168,24 @@
         metrics.xdpi = mParams.getXdpi();
         metrics.ydpi = mParams.getYdpi();
 
-        // create the resource resolver
-        ResourceResolver resolver = ResourceResolver.create(
-                new IFrameworkResourceIdProvider() {
-                    public Integer getId(String resType, String resName) {
-                        return Bridge.getResourceValue(resType, resName);
-                    }
-                },
-                mParams.getProjectResources(),
-                mParams.getFrameworkResources(),
-                mParams.getThemeName(),
-                mParams.isProjectTheme(),
-                mParams.getLog());
-
+        RenderResources resources = mParams.getResources();
 
         // build the context
-        mContext = new BridgeContext(mParams.getProjectKey(), metrics, resolver,
-                mParams.getProjectCallback());
+        mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
+                mParams.getProjectCallback(), mParams.getTargetSdkVersion());
 
-        // set the current rendering context
-        sCurrentContext = mContext;
 
-        // make sure the Resources object references the context (and other objects) for this
-        // scene
-        mContext.initResources();
+        setUp();
 
         // get the screen offset and window-background resource
         mWindowBackground = null;
         mScreenOffset = 0;
-        StyleResourceValue theme = resolver.getTheme();
+        StyleResourceValue theme = resources.getTheme();
         if (theme != null && mParams.isBgColorOverridden() == false) {
-            mWindowBackground = resolver.findItemInTheme("windowBackground");
-            mWindowBackground = resolver.resolveResValue(mWindowBackground);
+            mWindowBackground = resources.findItemInTheme("windowBackground");
+            mWindowBackground = resources.resolveResValue(mWindowBackground);
 
-            mScreenOffset = getScreenOffset(resolver, metrics);
+            mScreenOffset = getScreenOffset(resources, metrics);
         }
 
         // build the inflater and parser.
@@ -249,11 +233,7 @@
             return result;
         }
 
-        // make sure the Resources object references the context (and other objects) for this
-        // scene
-        mContext.initResources();
-        sCurrentContext = mContext;
-        Bridge.setLog(mParams.getLog());
+        setUp();
 
         return SUCCESS.createResult();
     }
@@ -306,16 +286,45 @@
         // without a successful call to prepareScene. This test makes sure that unlock() will
         // not throw IllegalMonitorStateException.
         if (lock.isHeldByCurrentThread()) {
-            // Make sure to remove static references, otherwise we could not unload the lib
-            mContext.disposeResources();
-            Bridge.setLog(null);
-            sCurrentContext = null;
-
+            tearDown();
             lock.unlock();
         }
     }
 
     /**
+     * Sets up the session for rendering.
+     * <p/>
+     * The counterpart is {@link #tearDown()}.
+     */
+    private void setUp() {
+        // make sure the Resources object references the context (and other objects) for this
+        // scene
+        mContext.initResources();
+        sCurrentContext = mContext;
+
+        LayoutLog currentLog = mParams.getLog();
+        Bridge.setLog(currentLog);
+        mContext.getRenderResources().setFrameworkResourceIdProvider(this);
+        mContext.getRenderResources().setLogger(currentLog);
+    }
+
+    /**
+     * Tear down the session after rendering.
+     * <p/>
+     * The counterpart is {@link #setUp()}.
+     */
+    private void tearDown() {
+        // Make sure to remove static references, otherwise we could not unload the lib
+        mContext.disposeResources();
+        sCurrentContext = null;
+
+        Bridge.setLog(null);
+        mContext.getRenderResources().setFrameworkResourceIdProvider(null);
+        mContext.getRenderResources().setLogger(null);
+
+    }
+
+    /**
      * Inflates the layout.
      * <p>
      * {@link #acquire(long)} must have been called before this.
@@ -502,18 +511,18 @@
         ResourceValue animationResource = null;
         int animationId = 0;
         if (isFrameworkAnimation) {
-            animationResource = mContext.getResolver().getFrameworkResource(
-                    ResourceResolver.RES_ANIMATOR, animationName);
+            animationResource = mContext.getRenderResources().getFrameworkResource(
+                    RenderResources.RES_ANIMATOR, animationName);
             if (animationResource != null) {
-                animationId = Bridge.getResourceValue(ResourceResolver.RES_ANIMATOR,
+                animationId = Bridge.getResourceValue(RenderResources.RES_ANIMATOR,
                         animationName);
             }
         } else {
-            animationResource = mContext.getResolver().getProjectResource(
-                    ResourceResolver.RES_ANIMATOR, animationName);
+            animationResource = mContext.getRenderResources().getProjectResource(
+                    RenderResources.RES_ANIMATOR, animationName);
             if (animationResource != null) {
                 animationId = mContext.getProjectCallback().getResourceValue(
-                        ResourceResolver.RES_ANIMATOR, animationName);
+                        RenderResources.RES_ANIMATOR, animationName);
             }
         }
 
@@ -911,11 +920,11 @@
     /**
      * Returns the top screen offset. This depends on whether the current theme defines the user
      * of the title and status bars.
-     * @param resolver The {@link ResourceResolver}
+     * @param resolver The {@link RenderResources}
      * @param metrics The display metrics
      * @return the pixel height offset
      */
-    private int getScreenOffset(ResourceResolver resolver, DisplayMetrics metrics) {
+    private int getScreenOffset(RenderResources resolver, DisplayMetrics metrics) {
         int offset = 0;
 
         // get the title bar flag from the current theme.
@@ -961,7 +970,7 @@
             int defaultOffset = DEFAULT_STATUS_BAR_HEIGHT;
 
             // get the real value
-            value = resolver.getFrameworkResource(ResourceResolver.RES_DIMEN, "status_bar_height");
+            value = resolver.getFrameworkResource(RenderResources.RES_DIMEN, "status_bar_height");
             if (value != null) {
                 TypedValue typedValue = ResourceHelper.getValue(value.getValue());
                 if (typedValue != null) {
@@ -1040,28 +1049,36 @@
         // now process the content of the framelayout and dynamically create tabs for it.
         final int count = content.getChildCount();
 
-        if (count == 0) {
-            throw new PostInflateException(
-                    "The FrameLayout for the TabHost has no content. Rendering failed.\n");
-        }
-
         // this must be called before addTab() so that the TabHost searches its TabWidget
         // and FrameLayout.
         tabHost.setup();
 
-        // for each child of the framelayout, add a new TabSpec
-        for (int i = 0 ; i < count ; i++) {
-            View child = content.getChildAt(i);
-            String tabSpec = String.format("tab_spec%d", i+1);
-            int id = child.getId();
-            String[] resource = projectCallback.resolveResourceValue(id);
-            String name;
-            if (resource != null) {
-                name = resource[0]; // 0 is resource name, 1 is resource type.
-            } else {
-                name = String.format("Tab %d", i+1); // default name if id is unresolved.
+        if (count == 0) {
+            // Create a dummy child to get a single tab
+            TabSpec spec = tabHost.newTabSpec("tag").setIndicator("Tab Label",
+                    tabHost.getResources().getDrawable(android.R.drawable.ic_menu_info_details))
+                    .setContent(new TabHost.TabContentFactory() {
+                        public View createTabContent(String tag) {
+                            return new LinearLayout(mContext);
+                        }
+                    });
+            tabHost.addTab(spec);
+            return;
+        } else {
+            // for each child of the framelayout, add a new TabSpec
+            for (int i = 0 ; i < count ; i++) {
+                View child = content.getChildAt(i);
+                String tabSpec = String.format("tab_spec%d", i+1);
+                int id = child.getId();
+                String[] resource = projectCallback.resolveResourceValue(id);
+                String name;
+                if (resource != null) {
+                    name = resource[0]; // 0 is resource name, 1 is resource type.
+                } else {
+                    name = String.format("Tab %d", i+1); // default name if id is unresolved.
+                }
+                tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
             }
-            tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
         }
     }
 
@@ -1117,4 +1134,11 @@
     public RenderSession getSession() {
         return mScene;
     }
+
+    // --- FrameworkResourceIdProvider methods
+
+    @Override
+    public Integer getId(String resType, String resName) {
+        return Bridge.getResourceValue(resType, resName);
+    }
 }
diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java
index 3af6e78..dc66989 100644
--- a/voip/java/com/android/server/sip/SipService.java
+++ b/voip/java/com/android/server/sip/SipService.java
@@ -105,7 +105,7 @@
         if (SipManager.isApiSupported(context)) {
             ServiceManager.addService("sip", new SipService(context));
             context.sendBroadcast(new Intent(SipManager.ACTION_SIP_SERVICE_UP));
-            if (DEBUG) Log.i(TAG, "SIP service started");
+            if (DEBUG) Log.d(TAG, "SIP service started");
         }
     }
 
@@ -113,10 +113,6 @@
         if (DEBUG) Log.d(TAG, " service started!");
         mContext = context;
         mConnectivityReceiver = new ConnectivityReceiver();
-        context.registerReceiver(mConnectivityReceiver,
-                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
-        context.registerReceiver(mWifiStateReceiver,
-                new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));
         mMyWakeLock = new SipWakeLock((PowerManager)
                 context.getSystemService(Context.POWER_SERVICE));
 
@@ -124,7 +120,7 @@
         mWifiOnly = SipManager.isSipWifiOnly(context);
     }
 
-    BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
+    private BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
@@ -147,6 +143,20 @@
         }
     };
 
+    private void registerReceivers() {
+        mContext.registerReceiver(mConnectivityReceiver,
+                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
+        mContext.registerReceiver(mWifiStateReceiver,
+                new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));
+        if (DEBUG) Log.d(TAG, " +++ register receivers");
+    }
+
+    private void unregisterReceivers() {
+        mContext.unregisterReceiver(mConnectivityReceiver);
+        mContext.unregisterReceiver(mWifiStateReceiver);
+        if (DEBUG) Log.d(TAG, " --- unregister receivers");
+    }
+
     private MyExecutor getExecutor() {
         // create mExecutor lazily
         if (mExecutor == null) mExecutor = new MyExecutor();
@@ -166,12 +176,14 @@
         return profiles.toArray(new SipProfile[profiles.size()]);
     }
 
-    public void open(SipProfile localProfile) {
+    public synchronized void open(SipProfile localProfile) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.USE_SIP, null);
         localProfile.setCallingUid(Binder.getCallingUid());
         try {
+            boolean addingFirstProfile = mSipGroups.isEmpty();
             createGroup(localProfile);
+            if (addingFirstProfile && !mSipGroups.isEmpty()) registerReceivers();
         } catch (SipException e) {
             Log.e(TAG, "openToMakeCalls()", e);
             // TODO: how to send the exception back
@@ -192,8 +204,10 @@
         if (DEBUG) Log.d(TAG, "open3: " + localProfile.getUriString() + ": "
                 + incomingCallPendingIntent + ": " + listener);
         try {
+            boolean addingFirstProfile = mSipGroups.isEmpty();
             SipSessionGroupExt group = createGroup(localProfile,
                     incomingCallPendingIntent, listener);
+            if (addingFirstProfile && !mSipGroups.isEmpty()) registerReceivers();
             if (localProfile.getAutoRegistration()) {
                 group.openToReceiveCalls();
                 if (mWifiEnabled) grabWifiLock();
@@ -235,6 +249,7 @@
             releaseWifiLock();
             mMyWakeLock.reset(); // in case there's leak
         }
+        if (mSipGroups.isEmpty()) unregisterReceivers();
     }
 
     public synchronized boolean isOpened(String localProfileUri) {
@@ -1055,7 +1070,10 @@
                 // we want to skip the interim ones) but deliver bad news
                 // immediately
                 if (connected) {
-                    if (mTask != null) mTask.cancel();
+                    if (mTask != null) {
+                        mTask.cancel();
+                        mMyWakeLock.release(mTask);
+                    }
                     mTask = new MyTimerTask(type, connected);
                     mTimer.schedule(mTask, 2 * 1000L);
                     // hold wakup lock so that we can finish changes before the
@@ -1096,6 +1114,7 @@
                     if (mTask != this) {
                         Log.w(TAG, "  unexpected task: " + mNetworkType
                                 + (mConnected ? " CONNECTED" : "DISCONNECTED"));
+                        mMyWakeLock.release(this);
                         return;
                     }
                     mTask = null;