Merge "Don't break the build... update to 11.xml." into honeycomb
diff --git a/api/11.xml b/api/11.xml
index 254c1ba..d98fd04 100644
--- a/api/11.xml
+++ b/api/11.xml
@@ -4250,6 +4250,17 @@
visibility="public"
>
</field>
+<field name="fastScrollTextColor"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843611"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="fastScrollThumbDrawable"
type="int"
transient="false"
@@ -5812,6 +5823,17 @@
visibility="public"
>
</field>
+<field name="largeHeap"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843612"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="largeScreens"
type="int"
transient="false"
@@ -11462,6 +11484,28 @@
visibility="public"
>
</field>
+<field name="notification_large_icon_height"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17104902"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="notification_large_icon_width"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17104901"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="thumbnail_height"
type="int"
transient="false"
@@ -20082,42 +20126,6 @@
</parameter>
</method>
</class>
-<class name="DoubleEvaluator"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="android.animation.TypeEvaluator">
-</implements>
-<constructor name="DoubleEvaluator"
- type="android.animation.DoubleEvaluator"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="evaluate"
- return="java.lang.Object"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="fraction" type="float">
-</parameter>
-<parameter name="startValue" type="java.lang.Object">
-</parameter>
-<parameter name="endValue" type="java.lang.Object">
-</parameter>
-</method>
-</class>
<class name="FloatEvaluator"
extends="java.lang.Object"
abstract="false"
@@ -25150,17 +25158,6 @@
visibility="public"
>
</field>
-<field name="TASKS_GET_THUMBNAILS"
- type="int"
- transient="false"
- volatile="false"
- value="4096"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
</class>
<class name="ActivityManager.MemoryInfo"
extends="java.lang.Object"
@@ -25559,16 +25556,6 @@
visibility="public"
>
</field>
-<field name="thumbnail"
- type="android.graphics.Bitmap"
- transient="false"
- volatile="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
</class>
<class name="ActivityManager.RunningAppProcessInfo"
extends="java.lang.Object"
@@ -30685,6 +30672,17 @@
<parameter name="listener" type="android.app.FragmentManager.OnBackStackChangedListener">
</parameter>
</method>
+<method name="beginTransaction"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="countBackStackEntries"
return="int"
abstract="true"
@@ -30795,7 +30793,7 @@
</method>
<method name="openTransaction"
return="android.app.FragmentTransaction"
- abstract="true"
+ abstract="false"
native="false"
synchronized="false"
static="false"
@@ -37829,7 +37827,7 @@
</parameter>
</method>
<method name="getStorageEncryption"
- return="int"
+ return="boolean"
abstract="false"
native="false"
synchronized="false"
@@ -37841,6 +37839,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"
@@ -38181,7 +38190,7 @@
type="int"
transient="false"
volatile="false"
- value="3"
+ value="2"
static="true"
final="true"
deprecated="not deprecated"
@@ -38192,7 +38201,7 @@
type="int"
transient="false"
volatile="false"
- value="4"
+ value="3"
static="true"
final="true"
deprecated="not deprecated"
@@ -38210,17 +38219,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"
@@ -38983,6 +38981,17 @@
visibility="public"
>
</method>
+<method name="clearViews"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
<method name="createView"
return="android.appwidget.AppWidgetHostView"
abstract="false"
@@ -48155,6 +48164,17 @@
visibility="public"
>
</method>
+<method name="getObbDir"
+ return="java.io.File"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getPackageCodePath"
return="java.lang.String"
abstract="true"
@@ -49763,6 +49783,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"
@@ -58246,6 +58277,17 @@
visibility="public"
>
</field>
+<field name="FLAG_LARGE_HEAP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1048576"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_PERSISTENT"
type="int"
transient="false"
@@ -61503,6 +61545,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"
@@ -86270,7 +86352,7 @@
<method name="updateTexImage"
return="void"
abstract="false"
- native="true"
+ native="false"
synchronized="false"
static="false"
final="false"
@@ -95528,6 +95610,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"
@@ -95559,6 +95652,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"
@@ -137492,6 +137595,34 @@
<parameter name="params" type="Params...">
</parameter>
</method>
+<method name="execute"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="runnable" type="java.lang.Runnable">
+</parameter>
+</method>
+<method name="executeOnExecutor"
+ return="android.os.AsyncTask<Params, Progress, Result>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="exec" type="java.util.concurrent.Executor">
+</parameter>
+<parameter name="params" type="Params...">
+</parameter>
+</method>
<method name="get"
return="Result"
abstract="false"
@@ -137624,6 +137755,16 @@
<parameter name="values" type="Progress...">
</parameter>
</method>
+<field name="THREAD_POOL_EXECUTOR"
+ type="java.util.concurrent.ThreadPoolExecutor"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="AsyncTask.Status"
extends="java.lang.Enum"
@@ -147284,53 +147425,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"
@@ -147339,28 +147433,6 @@
deprecated="not deprecated"
visibility="public"
>
-<method name="disableUsbMassStorage"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="enableUsbMassStorage"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="getMountedObbPath"
return="java.lang.String"
abstract="false"
@@ -147387,28 +147459,6 @@
<parameter name="filename" type="java.lang.String">
</parameter>
</method>
-<method name="isUsbMassStorageConnected"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="isUsbMassStorageEnabled"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="mountObb"
return="boolean"
abstract="false"
@@ -147426,19 +147476,6 @@
<parameter name="listener" type="android.os.storage.OnObbStateChangeListener">
</parameter>
</method>
-<method name="registerListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="listener" type="android.os.storage.StorageEventListener">
-</parameter>
-</method>
<method name="unmountObb"
return="boolean"
abstract="false"
@@ -147456,124 +147493,6 @@
<parameter name="listener" type="android.os.storage.OnObbStateChangeListener">
</parameter>
</method>
-<method name="unregisterListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="listener" type="android.os.storage.StorageEventListener">
-</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"
@@ -167269,6 +167188,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"
@@ -173029,6 +172980,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"
@@ -173042,6 +173036,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"
@@ -173173,6 +173272,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"
@@ -183629,6 +183754,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"
@@ -238130,6 +238266,34 @@
>
</field>
</class>
+<class name="WebViewFragment"
+ extends="android.app.Fragment"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="WebViewFragment"
+ type="android.webkit.WebViewFragment"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getWebView"
+ return="android.webkit.WebView"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
</package>
<package name="android.widget"
>
diff --git a/api/current.xml b/api/current.xml
index d67a437..d98fd04 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -4250,6 +4250,17 @@
visibility="public"
>
</field>
+<field name="fastScrollTextColor"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843611"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="fastScrollThumbDrawable"
type="int"
transient="false"
@@ -5812,6 +5823,17 @@
visibility="public"
>
</field>
+<field name="largeHeap"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843612"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="largeScreens"
type="int"
transient="false"
@@ -11462,6 +11484,28 @@
visibility="public"
>
</field>
+<field name="notification_large_icon_height"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17104902"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="notification_large_icon_width"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17104901"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="thumbnail_height"
type="int"
transient="false"
@@ -20082,42 +20126,6 @@
</parameter>
</method>
</class>
-<class name="DoubleEvaluator"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="android.animation.TypeEvaluator">
-</implements>
-<constructor name="DoubleEvaluator"
- type="android.animation.DoubleEvaluator"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="evaluate"
- return="java.lang.Object"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="fraction" type="float">
-</parameter>
-<parameter name="startValue" type="java.lang.Object">
-</parameter>
-<parameter name="endValue" type="java.lang.Object">
-</parameter>
-</method>
-</class>
<class name="FloatEvaluator"
extends="java.lang.Object"
abstract="false"
@@ -25150,17 +25158,6 @@
visibility="public"
>
</field>
-<field name="TASKS_GET_THUMBNAILS"
- type="int"
- transient="false"
- volatile="false"
- value="4096"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
</class>
<class name="ActivityManager.MemoryInfo"
extends="java.lang.Object"
@@ -25559,16 +25556,6 @@
visibility="public"
>
</field>
-<field name="thumbnail"
- type="android.graphics.Bitmap"
- transient="false"
- volatile="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
</class>
<class name="ActivityManager.RunningAppProcessInfo"
extends="java.lang.Object"
@@ -30685,6 +30672,17 @@
<parameter name="listener" type="android.app.FragmentManager.OnBackStackChangedListener">
</parameter>
</method>
+<method name="beginTransaction"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="countBackStackEntries"
return="int"
abstract="true"
@@ -30795,7 +30793,7 @@
</method>
<method name="openTransaction"
return="android.app.FragmentTransaction"
- abstract="true"
+ abstract="false"
native="false"
synchronized="false"
static="false"
@@ -37829,7 +37827,7 @@
</parameter>
</method>
<method name="getStorageEncryption"
- return="int"
+ return="boolean"
abstract="false"
native="false"
synchronized="false"
@@ -37841,6 +37839,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"
@@ -38181,7 +38190,7 @@
type="int"
transient="false"
volatile="false"
- value="3"
+ value="2"
static="true"
final="true"
deprecated="not deprecated"
@@ -38192,7 +38201,7 @@
type="int"
transient="false"
volatile="false"
- value="4"
+ value="3"
static="true"
final="true"
deprecated="not deprecated"
@@ -38210,17 +38219,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"
@@ -48166,6 +48164,17 @@
visibility="public"
>
</method>
+<method name="getObbDir"
+ return="java.io.File"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getPackageCodePath"
return="java.lang.String"
abstract="true"
@@ -49774,6 +49783,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"
@@ -58257,6 +58277,17 @@
visibility="public"
>
</field>
+<field name="FLAG_LARGE_HEAP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1048576"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_PERSISTENT"
type="int"
transient="false"
@@ -60267,19 +60298,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"
@@ -60766,21 +60784,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"
@@ -61542,6 +61545,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"
@@ -86309,7 +86352,7 @@
<method name="updateTexImage"
return="void"
abstract="false"
- native="true"
+ native="false"
synchronized="false"
static="false"
final="false"
@@ -95567,6 +95610,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"
@@ -95598,6 +95652,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"
@@ -137531,6 +137595,34 @@
<parameter name="params" type="Params...">
</parameter>
</method>
+<method name="execute"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="runnable" type="java.lang.Runnable">
+</parameter>
+</method>
+<method name="executeOnExecutor"
+ return="android.os.AsyncTask<Params, Progress, Result>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="exec" type="java.util.concurrent.Executor">
+</parameter>
+<parameter name="params" type="Params...">
+</parameter>
+</method>
<method name="get"
return="Result"
abstract="false"
@@ -137663,6 +137755,16 @@
<parameter name="values" type="Progress...">
</parameter>
</method>
+<field name="THREAD_POOL_EXECUTOR"
+ type="java.util.concurrent.ThreadPoolExecutor"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="AsyncTask.Status"
extends="java.lang.Enum"
@@ -147323,53 +147425,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"
@@ -147378,28 +147433,6 @@
deprecated="not deprecated"
visibility="public"
>
-<method name="disableUsbMassStorage"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="enableUsbMassStorage"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="getMountedObbPath"
return="java.lang.String"
abstract="false"
@@ -147426,28 +147459,6 @@
<parameter name="filename" type="java.lang.String">
</parameter>
</method>
-<method name="isUsbMassStorageConnected"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="isUsbMassStorageEnabled"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="mountObb"
return="boolean"
abstract="false"
@@ -147465,19 +147476,6 @@
<parameter name="listener" type="android.os.storage.OnObbStateChangeListener">
</parameter>
</method>
-<method name="registerListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="listener" type="android.os.storage.StorageEventListener">
-</parameter>
-</method>
<method name="unmountObb"
return="boolean"
abstract="false"
@@ -147495,124 +147493,6 @@
<parameter name="listener" type="android.os.storage.OnObbStateChangeListener">
</parameter>
</method>
-<method name="unregisterListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="listener" type="android.os.storage.StorageEventListener">
-</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"
@@ -167308,6 +167188,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"
@@ -173068,6 +172980,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"
@@ -173081,6 +173036,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"
@@ -173212,6 +173272,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"
@@ -183668,6 +183754,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"
@@ -185256,19 +185353,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"
@@ -185768,21 +185852,6 @@
<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"
diff --git a/core/java/android/animation/DoubleEvaluator.java b/core/java/android/animation/DoubleEvaluator.java
deleted file mode 100644
index e46eb37..0000000
--- a/core/java/android/animation/DoubleEvaluator.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.animation;
-
-/**
- * This evaluator can be used to perform type interpolation between <code>double</code> values.
- */
-public class DoubleEvaluator implements TypeEvaluator {
- /**
- * This function returns the result of linearly interpolating the start and end values, with
- * <code>fraction</code> representing the proportion between the start and end values. The
- * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
- * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
- * and <code>t</code> is <code>fraction</code>.
- *
- * @param fraction The fraction from the starting to the ending values
- * @param startValue The start value; should be of type <code>double</code> or
- * <code>Double</code>
- * @param endValue The end value; should be of type <code>double</code> or
- * <code>Double</code>
- * @return A linear interpolation between the start and end values, given the
- * <code>fraction</code> parameter.
- */
- public Object evaluate(float fraction, Object startValue, Object endValue) {
- double startDouble = ((Number) startValue).doubleValue();
- return startDouble + fraction * (((Number) endValue).doubleValue() - startDouble);
- }
-}
\ No newline at end of file
diff --git a/core/java/android/animation/FloatKeyframeSet.java b/core/java/android/animation/FloatKeyframeSet.java
index 6fad4a68..4009f13 100644
--- a/core/java/android/animation/FloatKeyframeSet.java
+++ b/core/java/android/animation/FloatKeyframeSet.java
@@ -25,8 +25,8 @@
* values between those keyframes for a given animation. The class internal to the animation
* package because it is an implementation detail of how Keyframes are stored and used.
*
- * <p>This type-specific subclass of KeyframeSet, along with the other type-specific subclasses for
- * int, long, and double, exists to speed up the getValue() method when there is no custom
+ * <p>This type-specific subclass of KeyframeSet, along with the other type-specific subclass for
+ * int, exists to speed up the getValue() method when there is no custom
* TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the
* Object equivalents of these primitive types.</p>
*/
diff --git a/core/java/android/animation/IntKeyframeSet.java b/core/java/android/animation/IntKeyframeSet.java
index 14a4e3a..5629c5e 100644
--- a/core/java/android/animation/IntKeyframeSet.java
+++ b/core/java/android/animation/IntKeyframeSet.java
@@ -25,8 +25,8 @@
* values between those keyframes for a given animation. The class internal to the animation
* package because it is an implementation detail of how Keyframes are stored and used.
*
- * <p>This type-specific subclass of KeyframeSet, along with the other type-specific subclasses for
- * float, long, and double, exists to speed up the getValue() method when there is no custom
+ * <p>This type-specific subclass of KeyframeSet, along with the other type-specific subclass for
+ * float, exists to speed up the getValue() method when there is no custom
* TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the
* Object equivalents of these primitive types.</p>
*/
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 3212cba..d038cd6 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -18,7 +18,6 @@
import android.util.Log;
-import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.ArrayList;
@@ -29,8 +28,6 @@
* are then determined internally and the animation will call these functions as necessary to
* animate the property.
*
- * <p class="note"><b>Note:</b> Instances of this class hold only a {@link WeakReference}
- * to the target object.</p>
* @see #setPropertyName(String)
*
*/
@@ -38,7 +35,7 @@
private static final boolean DBG = false;
// The target object on which the property exists, set in the constructor
- private WeakReference<Object> mTargetRef;
+ private Object mTarget;
private String mPropertyName;
@@ -105,9 +102,6 @@
* @return Method the method associated with mPropertyName.
*/
private Method getPropertyFunction(String prefix, Class valueType) {
- final Object target = mTargetRef == null ? null : mTargetRef.get();
- if (target == null) return null;
-
// TODO: faster implementation...
Method returnVal = null;
String firstLetter = mPropertyName.substring(0, 1);
@@ -120,7 +114,7 @@
args[0] = valueType;
}
try {
- returnVal = target.getClass().getMethod(setterName, args);
+ returnVal = mTarget.getClass().getMethod(setterName, args);
} catch (NoSuchMethodException e) {
Log.e("ObjectAnimator",
"Couldn't find setter/getter for property " + mPropertyName + ": " + e);
@@ -140,14 +134,13 @@
* A constructor that takes a single property name and set of values. This constructor is
* used in the simple case of animating a single property.
*
- * @param target The object whose property is to be animated. It will be weakly referenced
- * from the newly-created ObjectAnimator. This object should have a public method on it called
- * <code>setName()</code>, where <code>name</code> is the value of the <code>propertyName</code>
- * parameter.
+ * @param target The object whose property is to be animated. This object should
+ * have a public method on it called <code>setName()</code>, where <code>name</code> is
+ * the value of the <code>propertyName</code> parameter.
* @param propertyName The name of the property being animated.
*/
private ObjectAnimator(Object target, String propertyName) {
- mTargetRef = new WeakReference<Object>(target);
+ mTarget = target;
setPropertyName(propertyName);
}
@@ -159,10 +152,9 @@
* from the target object and property being animated). Therefore, there should typically
* be two or more values.
*
- * @param target The object whose property is to be animated. It will be weakly referenced
- * from the newly-created ObjectAnimator. This object should have a public method on it called
- * <code>setName()</code>, where <code>name</code> is the value of the <code>propertyName</code>
- * parameter.
+ * @param target The object whose property is to be animated. This object should
+ * have a public method on it called <code>setName()</code>, where <code>name</code> is
+ * the value of the <code>propertyName</code> parameter.
* @param propertyName The name of the property being animated.
* @param values A set of values that the animation will animate between over time.
* @return A ValueAnimator object that is set up to animate between the given values.
@@ -181,10 +173,9 @@
* from the target object and property being animated). Therefore, there should typically
* be two or more values.
*
- * @param target The object whose property is to be animated. It will be weakly referenced
- * from the newly-created ObjectAnimator. This object should have a public method on it called
- * <code>setName()</code>, where <code>name</code> is the value of the <code>propertyName</code>
- * parameter.
+ * @param target The object whose property is to be animated. This object should
+ * have a public method on it called <code>setName()</code>, where <code>name</code> is
+ * the value of the <code>propertyName</code> parameter.
* @param propertyName The name of the property being animated.
* @param values A set of values that the animation will animate between over time.
* @return A ValueAnimator object that is set up to animate between the given values.
@@ -201,10 +192,10 @@
* PropertyValuesHolder allows you to associate a set of animation values with a property
* name.
*
- * @param target The object whose property is to be animated. It will be weakly referenced
- * from the newly-created ObjectAnimator. This object should have public methods on it called
- * <code>setName()</code>, where <code>name</code> is the name of the property passed in as the
- * <code>propertyName</code> parameter for each of the PropertyValuesHolder objects.
+ * @param target The object whose property is to be animated. This object should
+ * have public methods on it called <code>setName()</code>, where <code>name</code> is
+ * the name of the property passed in as the <code>propertyName</code> parameter for
+ * each of the PropertyValuesHolder objects.
* @param propertyName The name of the property being animated.
* @param evaluator A TypeEvaluator that will be called on each animation frame to
* provide the ncessry interpolation between the Object values to derive the animated
@@ -227,10 +218,10 @@
* PropertyValuesHolder allows you to associate a set of animation values with a property
* name.
*
- * @param target The object whose property is to be animated. It will be weakly referenced
- * from the newly-created ObjectAnimator. This object should have public methods on it called
- * <code>setName()</code>, where <code>name</code> is the name of the property passed in as the
- * <code>propertyName</code> parameter for each of the PropertyValuesHolder objects.
+ * @param target The object whose property is to be animated. This object should
+ * have public methods on it called <code>setName()</code>, where <code>name</code> is
+ * the name of the property passed in as the <code>propertyName</code> parameter for
+ * each of the PropertyValuesHolder objects.
* @param values A set of PropertyValuesHolder objects whose values will be animated
* between over time.
* @return A ValueAnimator object that is set up to animate between the given values.
@@ -238,7 +229,7 @@
public static ObjectAnimator ofPropertyValuesHolder(Object target,
PropertyValuesHolder... values) {
ObjectAnimator anim = new ObjectAnimator();
- anim.mTargetRef = new WeakReference<Object>(target);
+ anim.mTarget = target;
anim.setValues(values);
return anim;
}
@@ -279,8 +270,7 @@
@Override
public void start() {
if (DBG) {
- final Object target = mTargetRef == null ? null : mTargetRef.get();
- Log.d("ObjectAnimator", "Anim target, duration" + target + ", " + getDuration());
+ Log.d("ObjectAnimator", "Anim target, duration" + mTarget + ", " + getDuration());
for (int i = 0; i < mValues.length; ++i) {
PropertyValuesHolder pvh = mValues[i];
ArrayList<Keyframe> keyframes = pvh.mKeyframeSet.mKeyframes;
@@ -307,14 +297,11 @@
@Override
void initAnimation() {
if (!mInitialized) {
- final Object target = mTargetRef == null ? null : mTargetRef.get();
- if (target == null) return;
-
// mValueType may change due to setter/getter setup; do this before calling super.init(),
// which uses mValueType to set up the default type evaluator.
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
- mValues[i].setupSetterAndGetter(target);
+ mValues[i].setupSetterAndGetter(mTarget);
}
super.initAnimation();
}
@@ -339,26 +326,23 @@
/**
* The target object whose property will be animated by this animation
*
- * @return The object being animated, or null if the object has been garbage collected.
+ * @return The object being animated
*/
public Object getTarget() {
- return mTargetRef == null ? null : mTargetRef.get();
+ return mTarget;
}
/**
- * Sets the target object whose property will be animated by this animation. The target
- * will be weakly referenced from this object.
+ * Sets the target object whose property will be animated by this animation
*
* @param target The object being animated
*/
@Override
public void setTarget(Object target) {
- final Object currentTarget = mTargetRef == null ? null : mTargetRef.get();
-
- if (currentTarget != target) {
- mTargetRef = new WeakReference<Object>(target);
- if (currentTarget != null && target != null
- && currentTarget.getClass() == target.getClass()) {
+ if (mTarget != target) {
+ final Object oldTarget = mTarget;
+ mTarget = target;
+ if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) {
return;
}
// New target type should cause re-initialization prior to starting
@@ -368,25 +352,19 @@
@Override
public void setupStartValues() {
- final Object target = mTargetRef == null ? null : mTargetRef.get();
- if (target == null) return;
-
initAnimation();
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
- mValues[i].setupStartValue(target);
+ mValues[i].setupStartValue(mTarget);
}
}
@Override
public void setupEndValues() {
- final Object target = mTargetRef == null ? null : mTargetRef.get();
- if (target == null) return;
-
initAnimation();
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
- mValues[i].setupEndValue(target);
+ mValues[i].setupEndValue(mTarget);
}
}
@@ -405,13 +383,9 @@
@Override
void animateValue(float fraction) {
super.animateValue(fraction);
-
- final Object target = mTargetRef == null ? null : mTargetRef.get();
- if (target == null) return;
-
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
- mValues[i].setAnimatedValue(target);
+ mValues[i].setAnimatedValue(mTarget);
}
}
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 0254924..0c30aad 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -67,10 +67,9 @@
KeyframeSet mKeyframeSet = null;
- // type evaluators for the three primitive types handled by this implementation
+ // type evaluators for the primitive types handled by this implementation
private static final TypeEvaluator sIntEvaluator = new IntEvaluator();
private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();
- private static final TypeEvaluator sDoubleEvaluator = new DoubleEvaluator();
// We try several different types when searching for appropriate setter/getter functions.
// The caller may have supplied values in a type that does not match the setter/getter
@@ -104,7 +103,7 @@
/**
* The type evaluator used to calculate the animated values. This evaluator is determined
* automatically based on the type of the start/end objects passed into the constructor,
- * but the system only knows about the primitive types int, double, and float. Any other
+ * but the system only knows about the primitive types int and float. Any other
* type will need to set the evaluator to a custom evaluator for that type.
*/
private TypeEvaluator mEvaluator;
@@ -501,7 +500,7 @@
*/
void init() {
if (mEvaluator == null) {
- // We already handle int, float, long, double automatically, but not their Object
+ // We already handle int and float automatically, but not their Object
// equivalents
mEvaluator = (mValueType == Integer.class) ? sIntEvaluator :
(mValueType == Float.class) ? sFloatEvaluator :
@@ -509,7 +508,7 @@
}
if (mEvaluator != null) {
// KeyframeSet knows how to evaluate the common types - only give it a custom
- // evaulator if one has been set on this class
+ // evaluator if one has been set on this class
mKeyframeSet.setEvaluator(mEvaluator);
}
}
@@ -520,7 +519,7 @@
* desired. This may be important in cases where either the type of the values supplied
* do not match the way that they should be interpolated between, or if the values
* are of a custom type or one not currently understood by the animation system. Currently,
- * only values of type float, double, and int (and their Object equivalents, Float, Double,
+ * only values of type float and int (and their Object equivalents: Float
* and Integer) are correctly interpolated; all other types require setting a TypeEvaluator.
* @param evaluator
*/
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index f884473..5705057 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -143,10 +143,9 @@
private static final TimeInterpolator sDefaultInterpolator =
new AccelerateDecelerateInterpolator();
- // type evaluators for the three primitive types handled by this implementation
+ // type evaluators for the primitive types handled by this implementation
private static final TypeEvaluator sIntEvaluator = new IntEvaluator();
private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();
- private static final TypeEvaluator sDoubleEvaluator = new DoubleEvaluator();
/**
* Used to indicate whether the animation is currently playing in reverse. This causes the
@@ -858,7 +857,7 @@
/**
* The type evaluator to be used when calculating the animated values of this animation.
- * The system will automatically assign a float, int, or double evaluator based on the type
+ * The system will automatically assign a float or int evaluator based on the type
* of <code>startValue</code> and <code>endValue</code> in the constructor. But if these values
* are not one of these primitive types, or if different evaluation is desired (such as is
* necessary with int values that represent colors), a custom evaluator needs to be assigned.
@@ -1193,4 +1192,16 @@
public static int getCurrentAnimationsCount() {
return sAnimations.get().size();
}
+
+ /**
+ * Clear all animations on this thread, without canceling or ending them.
+ * This should be used with caution.
+ *
+ * @hide
+ */
+ public static void clearAllAnimations() {
+ sAnimations.get().clear();
+ sPendingAnimations.get().clear();
+ sDelayedAnims.get().clear();
+ }
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 44db50f..d5aa961 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -77,6 +77,9 @@
* This may be the same size as {@link #getMemoryClass()} on memory
* constrained devices, or it may be significantly larger on devices with
* a large amount of available RAM.
+ *
+ * <p>The is the size of the application's Dalvik heap if it has
+ * specified <code>android:largeHeap="true"</code> in its manifest.
*/
public int getLargeMemoryClass() {
return staticGetLargeMemoryClass();
@@ -119,6 +122,8 @@
/**
* Thumbnail representation of the task's last state. Must
* use {@link ActivityManager#TASKS_GET_THUMBNAILS} to have this set.
+ * @hide -- this is not scalable, need to have a separate API to get
+ * the bitmap.
*/
public Bitmap thumbnail;
@@ -200,6 +205,7 @@
/**
* Flag for use with {@link #getRecentTasks}: also return the thumbnail
* bitmap (if available) for each recent task.
+ * @hide
*/
public static final int TASKS_GET_THUMBNAILS = 0x0001000;
@@ -211,8 +217,7 @@
* actual number returned may be smaller, depending on how many tasks the
* user has started and the maximum number the system can remember.
* @param flags Information about what to return. May be any combination
- * of {@link #RECENT_WITH_EXCLUDED}, {@link #RECENT_IGNORE_UNAVAILABLE},
- * and {@link #TASKS_GET_THUMBNAILS}.
+ * of {@link #RECENT_WITH_EXCLUDED} and {@link #RECENT_IGNORE_UNAVAILABLE}.
*
* @return Returns a list of RecentTaskInfo records describing each of
* the recent tasks.
@@ -258,8 +263,8 @@
public ComponentName topActivity;
/**
- * Thumbnail representation of the task's current state. Must
- * use {@link ActivityManager#TASKS_GET_THUMBNAILS} to have this set.
+ * Thumbnail representation of the task's current state. Currently
+ * always null.
*/
public Bitmap thumbnail;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index cc94aa0..db046ef 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -45,7 +45,6 @@
import android.net.IConnectivityManager;
import android.net.Proxy;
import android.net.ProxyProperties;
-import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
@@ -3463,6 +3462,10 @@
mInstrumentation = new Instrumentation();
}
+ if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
+ // XXX bump up Dalvik's heap.
+ }
+
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
@@ -3471,7 +3474,7 @@
List<ProviderInfo> providers = data.providers;
if (providers != null) {
installContentProviders(app, providers);
- // For process that contain content providers, we want to
+ // For process that contains content providers, we want to
// ensure that the JIT is enabled "at some point".
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
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/ContextImpl.java b/core/java/android/app/ContextImpl.java
index e133ea0..6f63990 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -153,6 +153,7 @@
private File mPreferencesDir;
private File mFilesDir;
private File mCacheDir;
+ private File mObbDir;
private File mExternalFilesDir;
private File mExternalCacheDir;
@@ -647,6 +648,17 @@
}
@Override
+ public File getObbDir() {
+ synchronized (mSync) {
+ if (mObbDir == null) {
+ mObbDir = Environment.getExternalStorageAppObbDirectory(
+ getPackageName());
+ }
+ return mObbDir;
+ }
+ }
+
+ @Override
public File getCacheDir() {
synchronized (mSync) {
if (mCacheDir == null) {
diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java
index 6194240..6f25293 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();
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index eb9b8a3..e35ef87 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -100,8 +100,13 @@
* 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();
+ /** Old API */
+ public FragmentTransaction openTransaction() {
+ return beginTransaction();
+ }
+
/**
* After a {@link FragmentTransaction} is committed with
* {@link FragmentTransaction#commit FragmentTransaction.commit()}, it
@@ -347,7 +352,7 @@
};
@Override
- public FragmentTransaction openTransaction() {
+ public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index 5f8c098..cd5e3bb 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
@@ -353,7 +353,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/NativeActivity.java b/core/java/android/app/NativeActivity.java
index a5c49ec..35cc324 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -84,7 +84,7 @@
private boolean mDestroyed;
private native int loadNativeCode(String path, String funcname, MessageQueue queue,
- String internalDataPath, String externalDataPath, int sdkVersion,
+ String internalDataPath, String obbPath, String externalDataPath, int sdkVersion,
AssetManager assetMgr, byte[] savedState);
private native void unloadNativeCode(int handle);
@@ -191,7 +191,7 @@
? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null;
mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(),
- getFilesDir().toString(),
+ getFilesDir().toString(), getObbDir().toString(),
Environment.getExternalStorageAppFilesDirectory(ai.packageName).toString(),
Build.VERSION.SDK_INT, getAssets(), nativeSavedState);
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/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 4f8ee93..d8adc6c 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -94,8 +94,12 @@
public AppWidgetHostView(Context context, int animationIn, int animationOut) {
super(context);
mContext = context;
+
+ // We want to segregate the view ids within AppWidgets to prevent
+ // problems when those ids collide with view ids in the AppWidgetHost.
+ setIsRootNamespace(true);
}
-
+
/**
* Set the AppWidget that will be displayed by this view.
*/
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 227df21..d14cf4d 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -516,6 +516,13 @@
public abstract File getExternalFilesDir(String type);
/**
+ * Return the directory where this application's OBB files (if there
+ * are any) can be found. Note if the application does not have any OBB
+ * files, this directory may not exist.
+ */
+ public abstract File getObbDir();
+
+ /**
* Returns the absolute path to the application specific cache directory
* on the filesystem. These files will be ones that get deleted first when the
* device runs low on storage.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 545144e..3928aaf 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -191,6 +191,11 @@
}
@Override
+ public File getObbDir() {
+ return mBase.getObbDir();
+ }
+
+ @Override
public File getCacheDir() {
return mBase.getCacheDir();
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index bb0ed6a..2d95781 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -270,19 +270,19 @@
public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 1<<19;
/**
- * Value for {@link #flags}: this is true if the application has set
- * its android:neverEncrypt to true, false otherwise. It is used to specify
- * that this package specifically "opts-out" of a secured file system solution,
- * and will always store its data in-the-clear.
- *
- * {@hide}
+ * Value for {@link #flags}: true when the application has requested a
+ * large heap for its processes. Corresponds to
+ * {@link android.R.styleable#AndroidManifestApplication_largeHeap
+ * android:largeHeap}.
*/
- public static final int FLAG_NEVER_ENCRYPT = 1<<30;
+ public static final int FLAG_LARGE_HEAP = 1<<20;
/**
* Value for {@link #flags}: Set to true if the application has been
* installed using the forward lock option.
*
+ * NOTE: DO NOT CHANGE THIS VALUE! It is saved in packages.xml.
+ *
* {@hide}
*/
public static final int FLAG_FORWARD_LOCK = 1<<29;
@@ -298,7 +298,7 @@
*
* {@hide}
*/
- public static final int FLAG_CANT_SAVE_STATE = 1<<27;
+ public static final int FLAG_CANT_SAVE_STATE = 1<<28;
/**
* Flags associated with the application. Any combination of
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/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b2937ba..7676258 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -389,11 +389,15 @@
XmlResourceParser parser = null;
AssetManager assmgr = null;
+ Resources res = null;
boolean assetError = true;
try {
assmgr = new AssetManager();
int cookie = assmgr.addAssetPath(mArchiveSourcePath);
- if(cookie != 0) {
+ if (cookie != 0) {
+ res = new Resources(assmgr, metrics, null);
+ assmgr.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Build.VERSION.RESOURCES_SDK_INT);
parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
assetError = false;
} else {
@@ -403,7 +407,7 @@
Log.w(TAG, "Unable to read AndroidManifest.xml of "
+ mArchiveSourcePath, e);
}
- if(assetError) {
+ if (assetError) {
if (assmgr != null) assmgr.close();
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
return null;
@@ -413,7 +417,6 @@
Exception errorException = null;
try {
// XXXX todo: need to figure out correct configuration.
- Resources res = new Resources(assmgr, metrics, null);
pkg = parsePackage(res, parser, flags, errorText);
} catch (Exception e) {
errorException = e;
@@ -593,6 +596,8 @@
AssetManager assmgr = null;
try {
assmgr = new AssetManager();
+ assmgr.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Build.VERSION.RESOURCES_SDK_INT);
int cookie = assmgr.addAssetPath(packageFilePath);
parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
} catch (Exception e) {
@@ -1574,9 +1579,9 @@
}
if (sa.getBoolean(
- com.android.internal.R.styleable.AndroidManifestApplication_neverEncrypt,
+ com.android.internal.R.styleable.AndroidManifestApplication_largeHeap,
false)) {
- ai.flags |= ApplicationInfo.FLAG_NEVER_ENCRYPT;
+ ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP;
}
String str;
diff --git a/core/java/android/content/pm/PackageStats.java b/core/java/android/content/pm/PackageStats.java
index 9464321..11068e5 100755
--- a/core/java/android/content/pm/PackageStats.java
+++ b/core/java/android/content/pm/PackageStats.java
@@ -19,20 +19,47 @@
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
-
/**
* implementation of PackageStats associated with a
* application package.
*/
public class PackageStats implements Parcelable {
+ /** Name of the package to which this stats applies. */
public String packageName;
+
+ /** Size of the code (e.g., APK) */
public long codeSize;
+
+ /**
+ * Size of the internal data size for the application. (e.g.,
+ * /data/data/<app>)
+ */
public long dataSize;
+
+ /** Size of cache used by the application. (e.g., /data/data/<app>/cache) */
public long cacheSize;
-
+
+ /**
+ * Size of the external data used by the application (e.g.,
+ * <sdcard>/Android/data/<app>)
+ */
+ public long externalDataSize;
+
+ /**
+ * Size of the external cache used by the application (i.e., on the SD
+ * card). If this is a subdirectory of the data directory, this size will be
+ * subtracted out of the external data size.
+ */
+ public long externalCacheSize;
+
+ /** 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>() {
+ = new Parcelable.Creator<PackageStats>() {
public PackageStats createFromParcel(Parcel in) {
return new PackageStats(in);
}
@@ -41,29 +68,53 @@
return new PackageStats[size];
}
};
-
+
public String toString() {
- return "PackageStats{"
- + Integer.toHexString(System.identityHashCode(this))
- + " " + packageName + "}";
+ final StringBuilder sb = new StringBuilder("PackageStats{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" packageName=");
+ sb.append(packageName);
+ sb.append(",codeSize=");
+ sb.append(codeSize);
+ sb.append(",dataSize=");
+ sb.append(dataSize);
+ sb.append(",cacheSize=");
+ sb.append(cacheSize);
+ sb.append(",externalDataSize=");
+ sb.append(externalDataSize);
+ sb.append(",externalCacheSize=");
+ sb.append(externalCacheSize);
+ sb.append(",externalMediaSize=");
+ sb.append(externalMediaSize);
+ sb.append(",externalObbSize=");
+ sb.append(externalObbSize);
+ return sb.toString();
}
-
+
public PackageStats(String pkgName) {
packageName = pkgName;
}
-
+
public PackageStats(Parcel source) {
packageName = source.readString();
codeSize = source.readLong();
dataSize = source.readLong();
cacheSize = source.readLong();
+ externalDataSize = source.readLong();
+ externalCacheSize = source.readLong();
+ externalMediaSize = source.readLong();
+ externalObbSize = source.readLong();
}
-
+
public PackageStats(PackageStats pStats) {
packageName = pStats.packageName;
codeSize = pStats.codeSize;
dataSize = pStats.dataSize;
cacheSize = pStats.cacheSize;
+ externalDataSize = pStats.externalDataSize;
+ externalCacheSize = pStats.externalCacheSize;
+ externalMediaSize = pStats.externalMediaSize;
+ externalObbSize = pStats.externalObbSize;
}
public int describeContents() {
@@ -75,5 +126,9 @@
dest.writeLong(codeSize);
dest.writeLong(dataSize);
dest.writeLong(cacheSize);
+ dest.writeLong(externalDataSize);
+ dest.writeLong(externalCacheSize);
+ dest.writeLong(externalMediaSize);
+ dest.writeLong(externalObbSize);
}
}
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 406b091..6baf1c2 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -283,6 +283,7 @@
private Rect mContentInsetsBuffer = null;
private Rect mVisibleInsetsBuffer = null;
+ private Region mTouchableAreaBuffer = null;
Translator(float applicationScale, float applicationInvertedScale) {
this.applicationScale = applicationScale;
@@ -395,14 +396,25 @@
/**
* Translate the visible insets in application window to Screen. This uses
- * the internal buffer for content insets to avoid extra object allocation.
+ * the internal buffer for visible insets to avoid extra object allocation.
*/
- public Rect getTranslatedVisbileInsets(Rect visibleInsets) {
+ public Rect getTranslatedVisibleInsets(Rect visibleInsets) {
if (mVisibleInsetsBuffer == null) mVisibleInsetsBuffer = new Rect();
mVisibleInsetsBuffer.set(visibleInsets);
translateRectInAppWindowToScreen(mVisibleInsetsBuffer);
return mVisibleInsetsBuffer;
}
+
+ /**
+ * Translate the touchable area in application window to Screen. This uses
+ * the internal buffer for touchable area to avoid extra object allocation.
+ */
+ public Region getTranslatedTouchableArea(Region touchableArea) {
+ if (mTouchableAreaBuffer == null) mTouchableAreaBuffer = new Region();
+ mTouchableAreaBuffer.set(touchableArea);
+ mTouchableAreaBuffer.scale(applicationScale);
+ return mTouchableAreaBuffer;
+ }
}
/**
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index b40a226..29bb004c 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -56,10 +56,6 @@
private static final int ID_OTHER = 0x01000004;
- // Use the current SDK version code. If we are a development build,
- // also allow the previous SDK version + 1.
- private static final int sSdkVersion = Build.VERSION.SDK_INT
- + ("REL".equals(Build.VERSION.CODENAME) ? 0 : 1);
private static final Object mSync = new Object();
private static Resources mSystem = null;
@@ -1427,14 +1423,14 @@
mConfiguration.touchscreen,
(int)(mMetrics.density*160), mConfiguration.keyboard,
keyboardHidden, mConfiguration.navigation, width, height,
- mConfiguration.screenLayout, mConfiguration.uiMode, sSdkVersion);
+ mConfiguration.screenLayout, mConfiguration.uiMode,
+ Build.VERSION.RESOURCES_SDK_INT);
clearDrawableCache(mDrawableCache, configChanges);
clearDrawableCache(mColorDrawableCache, configChanges);
mColorStateListCache.clear();
-
flushLayoutCache();
}
synchronized (mSync) {
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 23b9ad5..4d25bac 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -25,6 +25,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ResultReceiver;
@@ -283,11 +284,13 @@
View decor = getWindow().getWindow().getDecorView();
info.contentInsets.top = info.visibleInsets.top
= decor.getHeight();
+ info.touchableRegion.setEmpty();
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
} else {
onComputeInsets(mTmpInsets);
info.contentInsets.top = mTmpInsets.contentTopInsets;
info.visibleInsets.top = mTmpInsets.visibleTopInsets;
+ info.touchableRegion.set(mTmpInsets.touchableRegion);
info.setTouchableInsets(mTmpInsets.touchableInsets);
}
}
@@ -510,7 +513,14 @@
* of the input method window.
*/
public int visibleTopInsets;
-
+
+ /**
+ * This is the region of the UI that is touchable. It is used when
+ * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
+ * The region should be specified relative to the origin of the window frame.
+ */
+ public final Region touchableRegion = new Region();
+
/**
* Option for {@link #touchableInsets}: the entire window frame
* can be touched.
@@ -531,11 +541,19 @@
*/
public static final int TOUCHABLE_INSETS_VISIBLE
= ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
-
+
+ /**
+ * Option for {@link #touchableInsets}: the region specified by
+ * {@link #touchableRegion} can be touched.
+ */
+ public static final int TOUCHABLE_INSETS_REGION
+ = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
+
/**
* Determine which area of the window is touchable by the user. May
* be one of: {@link #TOUCHABLE_INSETS_FRAME},
- * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_VISIBLE}.
+ * {@link #TOUCHABLE_INSETS_CONTENT}, {@link #TOUCHABLE_INSETS_VISIBLE},
+ * or {@link #TOUCHABLE_INSETS_REGION}.
*/
public int touchableInsets;
}
@@ -950,6 +968,7 @@
}
outInsets.visibleTopInsets = loc[1];
outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE;
+ outInsets.touchableRegion.setEmpty();
}
/**
@@ -2153,6 +2172,7 @@
p.println("Last computed insets:");
p.println(" contentTopInsets=" + mTmpInsets.contentTopInsets
+ " visibleTopInsets=" + mTmpInsets.visibleTopInsets
- + " touchableInsets=" + mTmpInsets.touchableInsets);
+ + " touchableInsets=" + mTmpInsets.touchableInsets
+ + " touchableRegion=" + mTmpInsets.touchableRegion);
}
}
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 9f7e31c..5a35eb0 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -16,9 +16,11 @@
package android.os;
+import java.util.ArrayDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
+import java.util.concurrent.Executor;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
@@ -151,8 +153,6 @@
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;
- private static final BlockingQueue<Runnable> sWorkQueue =
- new LinkedBlockingQueue<Runnable>(10);
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
@@ -162,8 +162,17 @@
}
};
- private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
- MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
+ private static final BlockingQueue<Runnable> sPoolWorkQueue =
+ new LinkedBlockingQueue<Runnable>(10);
+
+ /**
+ * A {@link ThreadPoolExecutor} that can be used to execute tasks in parallel.
+ */
+ public static final ThreadPoolExecutor THREAD_POOL_EXECUTOR
+ = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
+ TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
+
+ private static final SerialExecutor sSerialExecutor = new SerialExecutor();
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
@@ -177,6 +186,32 @@
private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
+ private static class SerialExecutor implements Executor {
+ final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
+ Runnable mActive;
+
+ public synchronized void execute(final Runnable r) {
+ mTasks.offer(new Runnable() {
+ public void run() {
+ try {
+ r.run();
+ } finally {
+ scheduleNext();
+ }
+ }
+ });
+ if (mActive == null) {
+ scheduleNext();
+ }
+ }
+
+ protected synchronized void scheduleNext() {
+ if ((mActive = mTasks.poll()) != null) {
+ THREAD_POOL_EXECUTOR.execute(mActive);
+ }
+ }
+ }
+
/**
* Indicates the current status of the task. Each status will be set only once
* during the lifetime of a task.
@@ -433,7 +468,11 @@
/**
* Executes the task with the specified parameters. The task returns
- * itself (this) so that the caller can keep a reference to it.
+ * itself (this) so that the caller can keep a reference to it. The tasks
+ * started by all invocations of this method in a given process are run
+ * sequentially. Call the executeOnExecutor(Executor,Params...)
+ * with a custom {@link Executor} to have finer grained control over how the
+ * tasks are run.
*
* This method must be invoked on the UI thread.
*
@@ -445,6 +484,26 @@
* {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
*/
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
+ return executeOnExecutor(sSerialExecutor, params);
+ }
+
+ /**
+ * Executes the task with the specified parameters. The task returns
+ * itself (this) so that the caller can keep a reference to it.
+ *
+ * This method must be invoked on the UI thread.
+ *
+ * @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a
+ * convenient process-wide thread pool for tasks that are loosely coupled.
+ * @param params The parameters of the task.
+ *
+ * @return This instance of AsyncTask.
+ *
+ * @throws IllegalStateException If {@link #getStatus()} returns either
+ * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
+ */
+ public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
+ Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
@@ -462,12 +521,20 @@
onPreExecute();
mWorker.mParams = params;
- sExecutor.execute(mFuture);
+ exec.execute(mFuture);
return this;
}
/**
+ * Schedules the {@link Runnable} in serial with the other AsyncTasks that were started
+ * with {@link #execute}.
+ */
+ public static void execute(Runnable runnable) {
+ sSerialExecutor.execute(runnable);
+ }
+
+ /**
* This method can be invoked from {@link #doInBackground} to
* publish updates on the UI thread while the background computation is
* still running. Each call to this method will trigger the execution of
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 6e50e97..af7b28b 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -100,6 +100,15 @@
* a release build.
*/
public static final String CODENAME = getString("ro.build.version.codename");
+
+ /**
+ * The SDK version to use when accessing resources.
+ * Use the current SDK version code. If we are a development build,
+ * also allow the previous SDK version + 1.
+ * @hide
+ */
+ public static final int RESOURCES_SDK_INT = SDK_INT
+ + ("REL".equals(CODENAME) ? 0 : 1);
}
/**
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 4f188f8..cc95642 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -107,6 +107,10 @@
= new File (new File(getDirectory("EXTERNAL_STORAGE", "/sdcard"),
"Android"), "media");
+ private static final File EXTERNAL_STORAGE_ANDROID_OBB_DIRECTORY
+ = new File (new File(getDirectory("EXTERNAL_STORAGE", "/sdcard"),
+ "Android"), "obb");
+
private static final File DOWNLOAD_CACHE_DIRECTORY
= getDirectory("DOWNLOAD_CACHE", "/cache");
@@ -304,6 +308,14 @@
}
/**
+ * Generates the raw path to an application's OBB files
+ * @hide
+ */
+ public static File getExternalStorageAppObbDirectory(String packageName) {
+ return new File(EXTERNAL_STORAGE_ANDROID_OBB_DIRECTORY, packageName);
+ }
+
+ /**
* Generates the path to an application's files.
* @hide
*/
diff --git a/core/java/android/os/storage/StorageEventListener.java b/core/java/android/os/storage/StorageEventListener.java
index d3d39d6..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/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index fb76937..73ac79f 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -312,6 +312,7 @@
*
* @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
*
+ * @hide
*/
public void registerListener(StorageEventListener listener) {
if (listener == null) {
@@ -328,6 +329,7 @@
*
* @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
*
+ * @hide
*/
public void unregisterListener(StorageEventListener listener) {
if (listener == null) {
@@ -348,6 +350,8 @@
/**
* Enables USB Mass Storage (UMS) on the device.
+ *
+ * @hide
*/
public void enableUsbMassStorage() {
try {
@@ -359,6 +363,8 @@
/**
* Disables USB Mass Storage (UMS) on the device.
+ *
+ * @hide
*/
public void disableUsbMassStorage() {
try {
@@ -371,6 +377,8 @@
/**
* Query if a USB Mass Storage (UMS) host is connected.
* @return true if UMS host is connected.
+ *
+ * @hide
*/
public boolean isUsbMassStorageConnected() {
try {
@@ -384,6 +392,8 @@
/**
* Query if a USB Mass Storage (UMS) is enabled on the device.
* @return true if UMS host is enabled.
+ *
+ * @hide
*/
public boolean isUsbMassStorageEnabled() {
try {
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..ee3bdab 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -1044,7 +1044,7 @@
getFragmentManager().popBackStack(BACK_STACK_PREFS,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
Fragment f = Fragment.instantiate(this, fragmentName, args);
- FragmentTransaction transaction = getFragmentManager().openTransaction();
+ FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setTransition(direction == 0 ? FragmentTransaction.TRANSIT_NONE
: direction > 0 ? FragmentTransaction.TRANSIT_FRAGMENT_NEXT
: FragmentTransaction.TRANSIT_FRAGMENT_PREV);
@@ -1136,7 +1136,7 @@
* 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);
@@ -1175,7 +1175,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/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index a5f405a..1218e81 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -101,7 +101,7 @@
* {@link android.view.ViewTreeObserver.InternalInsetsInfo}.
*/
void setInsets(IWindow window, int touchableInsets, in Rect contentInsets,
- in Rect visibleInsets);
+ in Rect visibleInsets, in Region touchableRegion);
/**
* Return the current display size in which the window is being laid out,
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index e228537..96f8cdc 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1229,24 +1229,34 @@
}
if (computesInternalInsets) {
- ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
- final Rect givenContent = attachInfo.mGivenInternalInsets.contentInsets;
- final Rect givenVisible = attachInfo.mGivenInternalInsets.visibleInsets;
- givenContent.left = givenContent.top = givenContent.right
- = givenContent.bottom = givenVisible.left = givenVisible.top
- = givenVisible.right = givenVisible.bottom = 0;
+ // Clear the original insets.
+ final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
+ insets.reset();
+
+ // Compute new insets in place.
attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
- Rect contentInsets = insets.contentInsets;
- Rect visibleInsets = insets.visibleInsets;
- if (mTranslator != null) {
- contentInsets = mTranslator.getTranslatedContentInsets(contentInsets);
- visibleInsets = mTranslator.getTranslatedVisbileInsets(visibleInsets);
- }
+
+ // Tell the window manager.
if (insetsPending || !mLastGivenInsets.equals(insets)) {
mLastGivenInsets.set(insets);
+
+ // Translate insets to screen coordinates if needed.
+ final Rect contentInsets;
+ final Rect visibleInsets;
+ final Region touchableRegion;
+ if (mTranslator != null) {
+ contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
+ visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
+ touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
+ } else {
+ contentInsets = insets.contentInsets;
+ visibleInsets = insets.visibleInsets;
+ touchableRegion = insets.touchableRegion;
+ }
+
try {
sWindowSession.setInsets(mWindow, insets.mTouchableInsets,
- contentInsets, visibleInsets);
+ contentInsets, visibleInsets, touchableRegion);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 06a0fa6..db87175 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -17,6 +17,7 @@
package android.view;
import android.graphics.Rect;
+import android.graphics.Region;
import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -126,11 +127,18 @@
public final Rect contentInsets = new Rect();
/**
- * Offsets from the fram of the window at which windows behind it
+ * Offsets from the frame of the window at which windows behind it
* are visible.
*/
public final Rect visibleInsets = new Rect();
-
+
+ /**
+ * Touchable region defined relative to the origin of the frame of the window.
+ * Only used when {@link #setTouchableInsets(int)} is called with
+ * the option {@link #TOUCHABLE_INSETS_REGION}.
+ */
+ public final Region touchableRegion = new Region();
+
/**
* Option for {@link #setTouchableInsets(int)}: the entire window frame
* can be touched.
@@ -148,11 +156,17 @@
* the visible insets can be touched.
*/
public static final int TOUCHABLE_INSETS_VISIBLE = 2;
-
+
+ /**
+ * Option for {@link #setTouchableInsets(int)}: the area inside of
+ * the provided touchable region in {@link #touchableRegion} can be touched.
+ */
+ public static final int TOUCHABLE_INSETS_REGION = 3;
+
/**
* Set which parts of the window can be touched: either
* {@link #TOUCHABLE_INSETS_FRAME}, {@link #TOUCHABLE_INSETS_CONTENT},
- * or {@link #TOUCHABLE_INSETS_VISIBLE}.
+ * {@link #TOUCHABLE_INSETS_VISIBLE}, or {@link #TOUCHABLE_INSETS_REGION}.
*/
public void setTouchableInsets(int val) {
mTouchableInsets = val;
@@ -165,11 +179,9 @@
int mTouchableInsets;
void reset() {
- final Rect givenContent = contentInsets;
- final Rect givenVisible = visibleInsets;
- givenContent.left = givenContent.top = givenContent.right
- = givenContent.bottom = givenVisible.left = givenVisible.top
- = givenVisible.right = givenVisible.bottom = 0;
+ contentInsets.setEmpty();
+ visibleInsets.setEmpty();
+ touchableRegion.setEmpty();
mTouchableInsets = TOUCHABLE_INSETS_FRAME;
}
@@ -179,13 +191,16 @@
return false;
}
InternalInsetsInfo other = (InternalInsetsInfo)o;
+ if (mTouchableInsets != other.mTouchableInsets) {
+ return false;
+ }
if (!contentInsets.equals(other.contentInsets)) {
return false;
}
if (!visibleInsets.equals(other.visibleInsets)) {
return false;
}
- return mTouchableInsets == other.mTouchableInsets;
+ return touchableRegion.equals(other.touchableRegion);
} catch (ClassCastException e) {
return false;
}
@@ -194,6 +209,7 @@
void set(InternalInsetsInfo other) {
contentInsets.set(other.contentInsets);
visibleInsets.set(other.visibleInsets);
+ touchableRegion.set(other.touchableRegion);
mTouchableInsets = other.mTouchableInsets;
}
}
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index dbcf1e9..4d63cf4 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -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/FastScroller.java b/core/java/android/widget/FastScroller.java
index d4ef044..dfa94c7 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -56,7 +56,7 @@
private static final int[] DEFAULT_STATES = new int[0];
private static final int[] ATTRS = new int[] {
- android.R.attr.textColorPrimary,
+ android.R.attr.fastScrollTextColor,
android.R.attr.fastScrollThumbDrawable,
android.R.attr.fastScrollTrackDrawable,
android.R.attr.fastScrollPreviewBackgroundLeft,
@@ -64,7 +64,7 @@
android.R.attr.fastScrollOverlayPosition
};
- private static final int PRIMARY_TEXT_COLOR = 0;
+ private static final int TEXT_COLOR = 0;
private static final int THUMB_DRAWABLE = 1;
private static final int TRACK_DRAWABLE = 2;
private static final int PREVIEW_BACKGROUND_LEFT = 3;
@@ -247,7 +247,7 @@
mPaint.setTextAlign(Paint.Align.CENTER);
mPaint.setTextSize(mOverlaySize / 2);
- ColorStateList textColor = ta.getColorStateList(PRIMARY_TEXT_COLOR);
+ ColorStateList textColor = ta.getColorStateList(TEXT_COLOR);
int textColorNormal = textColor.getDefaultColor();
mPaint.setColor(textColorNormal);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
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/SearchView.java b/core/java/android/widget/SearchView.java
index 2c96056..585dcf2 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -83,6 +83,7 @@
private CursorAdapter mSuggestionsAdapter;
private View mSearchButton;
private View mSubmitButton;
+ private View mSubmitArea;
private ImageView mCloseButton;
private View mSearchEditFrame;
private View mVoiceButton;
@@ -92,6 +93,7 @@
private boolean mQueryRefinement;
private boolean mClearingFocus;
private int mMaxWidth;
+ private boolean mVoiceButtonEnabled;
private SearchableInfo mSearchable;
@@ -187,6 +189,7 @@
mQueryTextView.setSearchView(this);
mSearchEditFrame = findViewById(R.id.search_edit_frame);
+ mSubmitArea = findViewById(R.id.submit_area);
mSubmitButton = findViewById(R.id.search_go_btn);
mCloseButton = (ImageView) findViewById(R.id.search_close_btn);
mVoiceButton = findViewById(R.id.search_voice_btn);
@@ -248,6 +251,8 @@
if (mSearchable != null) {
updateSearchAutoComplete();
}
+ // Cache the voice search capability
+ mVoiceButtonEnabled = hasVoiceSearch();
updateViewsVisibility(mIconifiedByDefault);
}
@@ -513,18 +518,55 @@
mIconified = collapsed;
// Visibility of views that are visible when collapsed
final int visCollapsed = collapsed ? VISIBLE : GONE;
- // Visibility of views that are visible when expanded
- final int visExpanded = collapsed ? GONE : VISIBLE;
// Is there text in the query
final boolean hasText = !TextUtils.isEmpty(mQueryTextView.getText());
mSearchButton.setVisibility(visCollapsed);
- mSubmitButton.setVisibility(mSubmitButtonEnabled && hasText ? visExpanded : GONE);
- mSearchEditFrame.setVisibility(visExpanded);
+ updateSubmitButton(hasText);
+ mSearchEditFrame.setVisibility(collapsed ? GONE : VISIBLE);
updateCloseButton();
updateVoiceButton(!hasText);
+ updateSubmitArea();
requestLayout();
- invalidate();
+ }
+
+ private boolean hasVoiceSearch() {
+ if (mSearchable != null && mSearchable.getVoiceSearchEnabled()) {
+ Intent testIntent = null;
+ if (mSearchable.getVoiceSearchLaunchWebSearch()) {
+ testIntent = mVoiceWebSearchIntent;
+ } else if (mSearchable.getVoiceSearchLaunchRecognizer()) {
+ testIntent = mVoiceAppSearchIntent;
+ }
+ if (testIntent != null) {
+ ResolveInfo ri = getContext().getPackageManager().resolveActivity(testIntent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ return ri != null;
+ }
+ }
+ return false;
+ }
+
+ private boolean isSubmitAreaEnabled() {
+ return (mSubmitButtonEnabled || mVoiceButtonEnabled) && !isIconified();
+ }
+
+ private void updateSubmitButton(boolean hasText) {
+ mSubmitButton.setVisibility(
+ isSubmitAreaEnabled() ? (hasText ? VISIBLE : INVISIBLE) : GONE);
+ }
+
+ private void updateSubmitArea() {
+ int visibility = GONE;
+ if (isSubmitAreaEnabled()) {
+ if (mSubmitButton.getVisibility() == VISIBLE
+ || mVoiceButton.getVisibility() == VISIBLE) {
+ visibility = VISIBLE;
+ } else {
+ visibility = INVISIBLE;
+ }
+ }
+ mSubmitArea.setVisibility(visibility);
}
private void updateCloseButton() {
@@ -790,22 +832,14 @@
* be visible - i.e., if the user has typed a query, remove the voice button.
*/
private void updateVoiceButton(boolean empty) {
- int visibility = View.GONE;
- if (mSearchable != null && mSearchable.getVoiceSearchEnabled() && empty
- && !isIconified()) {
- Intent testIntent = null;
- if (mSearchable.getVoiceSearchLaunchWebSearch()) {
- testIntent = mVoiceWebSearchIntent;
- } else if (mSearchable.getVoiceSearchLaunchRecognizer()) {
- testIntent = mVoiceAppSearchIntent;
- }
- if (testIntent != null) {
- ResolveInfo ri = getContext().getPackageManager().resolveActivity(testIntent,
- PackageManager.MATCH_DEFAULT_ONLY);
- if (ri != null) {
- visibility = View.VISIBLE;
- }
- }
+ // If the voice button is to be visible, show it
+ // Else, make it gone if the submit button is enabled, otherwise invisible to
+ // avoid losing the real-estate
+ int visibility = mSubmitButtonEnabled ? GONE : INVISIBLE;
+
+ if (mVoiceButtonEnabled && !isIconified() && empty) {
+ visibility = VISIBLE;
+ mSubmitButton.setVisibility(GONE);
}
mVoiceButton.setVisibility(visibility);
}
@@ -825,12 +859,11 @@
CharSequence text = mQueryTextView.getText();
boolean hasText = !TextUtils.isEmpty(text);
if (isSubmitButtonEnabled()) {
- mSubmitButton.setVisibility(hasText ? VISIBLE : GONE);
- requestLayout();
- invalidate();
+ updateSubmitButton(hasText);
}
updateVoiceButton(!hasText);
updateCloseButton();
+ updateSubmitArea();
if (mOnQueryChangeListener != null) {
mOnQueryChangeListener.onQueryTextChanged(newText.toString());
}
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 264af71..2c10077 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
+/* 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.
@@ -209,22 +208,19 @@
}
}
- if (fromIndex == -1 && toIndex == NUM_ACTIVE_VIEWS -1) {
+ if (fromIndex == -1 && toIndex == getNumActiveViews() -1) {
// Fade item in
if (view.getAlpha() == 1) {
view.setAlpha(0);
}
- view.setScaleX(1 - PERSPECTIVE_SCALE_FACTOR);
- view.setScaleY(1 - PERSPECTIVE_SCALE_FACTOR);
- view.setTranslationX(mPerspectiveShiftX);
- view.setTranslationY(0);
+ transformViewAtIndex(toIndex, view, false);
view.setVisibility(VISIBLE);
alphaOa = ObjectAnimator.ofFloat(view, "alpha", view.getAlpha(), 1.0f);
alphaOa.setDuration(FADE_IN_ANIMATION_DURATION);
if (oldAlphaOa != null) oldAlphaOa.cancel();
alphaOa.start();
- view.setTagInternal(com.android.internal.R.id.viewAlphaAnimation,
+ view.setTagInternal(com.android.internal.R.id.viewAlphaAnimation,
new WeakReference<ObjectAnimator>(alphaOa));
} else if (fromIndex == 0 && toIndex == 1) {
// Slide item in
@@ -270,7 +266,7 @@
alphaOa.setDuration(STACK_RELAYOUT_DURATION);
if (oldAlphaOa != null) oldAlphaOa.cancel();
alphaOa.start();
- view.setTagInternal(com.android.internal.R.id.viewAlphaAnimation,
+ view.setTagInternal(com.android.internal.R.id.viewAlphaAnimation,
new WeakReference<ObjectAnimator>(alphaOa));
}
@@ -284,16 +280,20 @@
final float maxPerspectiveShiftY = mPerspectiveShiftY;
final float maxPerspectiveShiftX = mPerspectiveShiftX;
- index = mMaxNumActiveViews - index - 1;
- if (index == mMaxNumActiveViews - 1) index--;
+ if (mStackMode == ITEMS_SLIDE_DOWN) {
+ index = mMaxNumActiveViews - index - 1;
+ if (index == mMaxNumActiveViews - 1) index--;
+ } else {
+ index--;
+ if (index < 0) index++;
+ }
float r = (index * 1.0f) / (mMaxNumActiveViews - 2);
final float scale = 1 - PERSPECTIVE_SCALE_FACTOR * (1 - r);
- int stackDirection = (mStackMode == ITEMS_SLIDE_UP) ? 1 : -1;
- float perspectiveTranslationY = -stackDirection * r * maxPerspectiveShiftY;
- float scaleShiftCorrectionY = stackDirection * (1 - scale) *
+ float perspectiveTranslationY = r * maxPerspectiveShiftY;
+ float scaleShiftCorrectionY = (scale - 1) *
(getMeasuredHeight() * (1 - PERSPECTIVE_SHIFT_FACTOR_Y) / 2.0f);
final float transY = perspectiveTranslationY + scaleShiftCorrectionY;
@@ -302,7 +302,7 @@
(getMeasuredWidth() * (1 - PERSPECTIVE_SHIFT_FACTOR_X) / 2.0f);
final float transX = perspectiveTranslationX + scaleShiftCorrectionX;
- // If this view is currently being animated for a certain position, we need to cancel
+ // If this view is currently being animated for a certain position, we need to cancel
// this animation so as not to interfere with the new transformation.
Object tag = view.getTag(com.android.internal.R.id.viewAnimation);
if (tag instanceof WeakReference<?>) {
@@ -515,11 +515,12 @@
private void beginGestureIfNeeded(float deltaY) {
if ((int) Math.abs(deltaY) > mTouchSlop && mSwipeGestureType == GESTURE_NONE) {
- int swipeGestureType = deltaY < 0 ? GESTURE_SLIDE_UP : GESTURE_SLIDE_DOWN;
+ final int swipeGestureType = deltaY < 0 ? GESTURE_SLIDE_UP : GESTURE_SLIDE_DOWN;
cancelLongPress();
requestDisallowInterceptTouchEvent(true);
if (mAdapter == null) return;
+ final int adapterCount = mAdapter.getCount();
int activeIndex;
if (mStackMode == ITEMS_SLIDE_UP) {
@@ -528,13 +529,20 @@
activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ? 1 : 0;
}
+ boolean endOfStack = mLoopViews && adapterCount == 1 &&
+ ((mStackMode == ITEMS_SLIDE_UP && swipeGestureType == GESTURE_SLIDE_UP) ||
+ (mStackMode == ITEMS_SLIDE_DOWN && swipeGestureType == GESTURE_SLIDE_DOWN));
+ boolean beginningOfStack = mLoopViews && adapterCount == 1 &&
+ ((mStackMode == ITEMS_SLIDE_DOWN && swipeGestureType == GESTURE_SLIDE_UP) ||
+ (mStackMode == ITEMS_SLIDE_UP && swipeGestureType == GESTURE_SLIDE_DOWN));
+
int stackMode;
- if (mLoopViews) {
+ if (mLoopViews && !beginningOfStack && !endOfStack) {
stackMode = StackSlider.NORMAL_MODE;
- } else if (mCurrentWindowStartUnbounded + activeIndex == -1) {
+ } else if (mCurrentWindowStartUnbounded + activeIndex == -1 || beginningOfStack) {
activeIndex++;
stackMode = StackSlider.BEGINNING_OF_STACK_MODE;
- } else if (mCurrentWindowStartUnbounded + activeIndex == mAdapter.getCount() - 1) {
+ } else if (mCurrentWindowStartUnbounded + activeIndex == adapterCount - 1 || endOfStack) {
stackMode = StackSlider.END_OF_STACK_MODE;
} else {
stackMode = StackSlider.NORMAL_MODE;
@@ -989,6 +997,11 @@
@Override
public void advance() {
long timeSinceLastInteraction = System.currentTimeMillis() - mLastInteractionTime;
+
+ if (mAdapter == null) return;
+ final int adapterCount = mAdapter.getCount();
+ if (adapterCount == 1 && mLoopViews) return;
+
if (mSwipeGestureType == GESTURE_NONE &&
timeSinceLastInteraction > MIN_TIME_BETWEEN_INTERACTION_AND_AUTOADVANCE) {
showNext();
@@ -1266,4 +1279,4 @@
mask.recycle();
}
}
-}
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 4ee3083..0e31fef 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -492,7 +492,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/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 8e491e9..8825c02 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -20,7 +20,6 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
@@ -44,6 +43,7 @@
private MenuBuilder mMenu;
private int mMaxItems;
+ private int mWidthLimit;
private boolean mReserveOverflow;
private OverflowMenuButton mOverflowButton;
private MenuPopupHelper mOverflowPopup;
@@ -91,6 +91,7 @@
final int screen = res.getConfiguration().screenLayout;
mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) ==
Configuration.SCREENLAYOUT_SIZE_XLARGE;
+ mWidthLimit = res.getDisplayMetrics().widthPixels / 2;
TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
mDivider = a.getDrawable(com.android.internal.R.styleable.Theme_dividerVertical);
@@ -108,6 +109,7 @@
mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) ==
Configuration.SCREENLAYOUT_SIZE_XLARGE;
mMaxItems = getMaxActionButtons();
+ mWidthLimit = getResources().getDisplayMetrics().widthPixels / 2;
if (mMenu != null) {
mMenu.setMaxActionItems(mMaxItems);
updateChildren(false);
@@ -172,6 +174,19 @@
}
public void initialize(MenuBuilder menu, int menuType) {
+ int width = mWidthLimit;
+ if (mReserveOverflow) {
+ if (mOverflowButton == null) {
+ OverflowMenuButton button = new OverflowMenuButton(mContext);
+ mOverflowButton = button;
+ }
+ final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ mOverflowButton.measure(spec, spec);
+ width -= mOverflowButton.getMeasuredWidth();
+ }
+
+ menu.setActionWidthLimit(width);
+
menu.setMaxActionItems(mMaxItems);
mMenu = menu;
updateChildren(true);
@@ -219,9 +234,11 @@
if (itemCount > 0) {
addView(makeDividerView(), makeDividerLayoutParams());
}
- OverflowMenuButton button = new OverflowMenuButton(mContext);
- addView(button);
- mOverflowButton = button;
+ if (mOverflowButton == null) {
+ OverflowMenuButton button = new OverflowMenuButton(mContext);
+ mOverflowButton = button;
+ }
+ addView(mOverflowButton);
} else {
mOverflowButton = null;
}
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 830c2c1..588b10c 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -27,9 +27,10 @@
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
-import android.util.Log;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.TypedValue;
+import android.view.ContextMenu.ContextMenuInfo;
import android.view.ContextThemeWrapper;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -38,8 +39,8 @@
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
+import android.view.View.MeasureSpec;
import android.view.ViewGroup;
-import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
@@ -164,6 +165,10 @@
*/
private int mMaxActionItems;
/**
+ * The total width limit in pixels for all action items within a menu
+ */
+ private int mActionWidthLimit;
+ /**
* Whether or not the items (or any one item's action state) has changed since it was
* last fetched.
*/
@@ -208,6 +213,11 @@
private boolean mOptionalIconsVisible = false;
+ private ViewGroup mMeasureActionButtonParent;
+
+ // Group IDs that have been added as actions - used temporarily, allocated here for reuse.
+ private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray();
+
private static int getAlertDialogTheme(Context context) {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
@@ -1035,6 +1045,44 @@
return mVisibleItems;
}
+ /**
+ * @return A fake action button parent view for obtaining child views.
+ */
+ private ViewGroup getMeasureActionButtonParent() {
+ if (mMeasureActionButtonParent == null) {
+ mMeasureActionButtonParent = (ViewGroup) mMenuTypes[TYPE_ACTION_BUTTON].getInflater()
+ .inflate(LAYOUT_RES_FOR_TYPE[TYPE_ACTION_BUTTON], null, false);
+ }
+ return mMeasureActionButtonParent;
+ }
+
+ /**
+ * This method determines which menu items get to be 'action items' that will appear
+ * in an action bar and which items should be 'overflow items' in a secondary menu.
+ * The rules are as follows:
+ *
+ * <p>Items are considered for inclusion in the order specified within the menu.
+ * There is a limit of mMaxActionItems as a total count, optionally including the overflow
+ * menu button itself. This is a soft limit; if an item shares a group ID with an item
+ * previously included as an action item, the new item will stay with its group and become
+ * an action item itself even if it breaks the max item count limit. This is done to
+ * limit the conceptual complexity of the items presented within an action bar. Only a few
+ * unrelated concepts should be presented to the user in this space, and groups are treated
+ * as a single concept.
+ *
+ * <p>There is also a hard limit of consumed measurable space: mActionWidthLimit. This
+ * limit may be broken by a single item that exceeds the remaining space, but no further
+ * items may be added. If an item that is part of a group cannot fit within the remaining
+ * measured width, the entire group will be demoted to overflow. This is done to ensure room
+ * for navigation and other affordances in the action bar as well as reduce general UI clutter.
+ *
+ * <p>The space freed by demoting a full group cannot be consumed by future menu items.
+ * Once items begin to overflow, all future items become overflow items as well. This is
+ * to avoid inadvertent reordering that may break the app's intended design.
+ *
+ * @param reserveActionOverflow true if an overflow button should consume one space
+ * in the available item count
+ */
private void flagActionItems(boolean reserveActionOverflow) {
if (reserveActionOverflow != mReserveActionOverflow) {
mReserveActionOverflow = reserveActionOverflow;
@@ -1048,9 +1096,13 @@
final ArrayList<MenuItemImpl> visibleItems = getVisibleItems();
final int itemsSize = visibleItems.size();
int maxActions = mMaxActionItems;
+ int widthLimit = mActionWidthLimit;
+ final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ final ViewGroup parent = getMeasureActionButtonParent();
int requiredItems = 0;
int requestedItems = 0;
+ int firstActionWidth = 0;
boolean hasOverflow = false;
for (int i = 0; i < itemsSize; i++) {
MenuItemImpl item = visibleItems.get(i);
@@ -1070,12 +1122,68 @@
}
maxActions -= requiredItems;
+ final SparseBooleanArray seenGroups = mActionButtonGroups;
+ seenGroups.clear();
+
// Flag as many more requested items as will fit.
for (int i = 0; i < itemsSize; i++) {
MenuItemImpl item = visibleItems.get(i);
- if (item.requestsActionButton()) {
- item.setIsActionButton(maxActions > 0);
+
+ if (item.requiresActionButton()) {
+ View v = item.getActionView();
+ if (v == null) {
+ v = item.getItemView(TYPE_ACTION_BUTTON, parent);
+ }
+ v.measure(querySpec, querySpec);
+ final int measuredWidth = v.getMeasuredWidth();
+ widthLimit -= measuredWidth;
+ if (firstActionWidth == 0) {
+ firstActionWidth = measuredWidth;
+ }
+ final int groupId = item.getGroupId();
+ if (groupId != 0) {
+ seenGroups.put(groupId, true);
+ }
+ } else if (item.requestsActionButton()) {
+ // Items in a group with other items that already have an action slot
+ // can break the max actions rule, but not the width limit.
+ final int groupId = item.getGroupId();
+ final boolean inGroup = seenGroups.get(groupId);
+ boolean isAction = (maxActions > 0 || inGroup) && widthLimit > 0;
maxActions--;
+
+ if (isAction) {
+ View v = item.getActionView();
+ if (v == null) {
+ v = item.getItemView(TYPE_ACTION_BUTTON, parent);
+ }
+ v.measure(querySpec, querySpec);
+ final int measuredWidth = v.getMeasuredWidth();
+ widthLimit -= measuredWidth;
+ if (firstActionWidth == 0) {
+ firstActionWidth = measuredWidth;
+ }
+
+ // Did this push the entire first item past halfway?
+ if (widthLimit + firstActionWidth <= 0) {
+ isAction = false;
+ }
+ }
+
+ if (isAction && groupId != 0) {
+ seenGroups.put(groupId, true);
+ } else if (inGroup) {
+ // We broke the width limit. Demote the whole group, they all overflow now.
+ seenGroups.put(groupId, false);
+ for (int j = 0; j < i; j++) {
+ MenuItemImpl areYouMyGroupie = visibleItems.get(j);
+ if (areYouMyGroupie.getGroupId() == groupId) {
+ areYouMyGroupie.setIsActionButton(false);
+ }
+ }
+ }
+
+ item.setIsActionButton(isAction);
}
}
@@ -1108,6 +1216,11 @@
mIsActionItemsStale = true;
}
+ void setActionWidthLimit(int widthLimit) {
+ mActionWidthLimit = widthLimit;
+ mIsActionItemsStale = true;
+ }
+
public void clearHeader() {
mHeaderIcon = null;
mHeaderTitle = null;
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 23f89f1..31e7bab 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;
@@ -447,7 +448,7 @@
@Override
public void onAnimationEnd(Animator animation) {
- if (mAnimationMode == ANIMATE_OUT) {
+ if (mAnimationMode != ANIMATE_IN) {
killMode();
}
mAnimationMode = ANIMATE_IDLE;
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index d28bdc9..f023e94 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -63,7 +63,6 @@
extern int register_android_graphics_Movie(JNIEnv* env);
extern int register_android_graphics_NinePatch(JNIEnv*);
extern int register_android_graphics_PathEffect(JNIEnv* env);
-extern int register_android_graphics_Region(JNIEnv* env);
extern int register_android_graphics_Shader(JNIEnv* env);
extern int register_android_graphics_Typeface(JNIEnv* env);
extern int register_android_graphics_YuvImage(JNIEnv* env);
@@ -111,6 +110,7 @@
extern int register_android_graphics_Picture(JNIEnv*);
extern int register_android_graphics_PorterDuff(JNIEnv* env);
extern int register_android_graphics_Rasterizer(JNIEnv* env);
+extern int register_android_graphics_Region(JNIEnv* env);
extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
extern int register_android_graphics_Xfermode(JNIEnv* env);
extern int register_android_graphics_PixelFormat(JNIEnv* env);
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index 723cd37..c43b5ce 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -1,8 +1,30 @@
+/*
+ * 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 "SkRegion.h"
#include "SkPath.h"
#include "GraphicsJNI.h"
+#include <binder/Parcel.h>
+#include "android_util_Binder.h"
+
#include <jni.h>
+#include <android_runtime/AndroidRuntime.h>
+
+namespace android {
static jfieldID gRegion_nativeInstanceFieldID;
@@ -134,9 +156,6 @@
////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#include <binder/Parcel.h>
-#include "android_util_Binder.h"
-
static SkRegion* Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
{
if (parcel == NULL) {
@@ -215,8 +234,6 @@
////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#include <android_runtime/AndroidRuntime.h>
-
static JNINativeMethod gRegionIterMethods[] = {
{ "nativeConstructor", "(I)I", (void*)RegionIter_constructor },
{ "nativeDestructor", "(I)V", (void*)RegionIter_destructor },
@@ -268,3 +285,9 @@
return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/RegionIterator",
gRegionIterMethods, SK_ARRAY_COUNT(gRegionIterMethods));
}
+
+SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj) {
+ return GetSkRegion(env, regionObj);
+}
+
+} // namespace android
diff --git a/core/jni/android/graphics/Region.h b/core/jni/android/graphics/Region.h
new file mode 100644
index 0000000..c15f06e
--- /dev/null
+++ b/core/jni/android/graphics/Region.h
@@ -0,0 +1,30 @@
+/*
+ * 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 _ANDROID_GRAPHICS_REGION_H
+#define _ANDROID_GRAPHICS_REGION_H
+
+#include "jni.h"
+#include "SkRegion.h"
+
+namespace android {
+
+/* Gets the underlying SkRegion from a Region object. */
+extern SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj);
+
+} // namespace android
+
+#endif // _ANDROID_GRAPHICS_REGION_H
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index c1229f3..88de94f 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -25,8 +25,8 @@
#include <utils/Log.h>
#include <utils/misc.h>
-#include "android/graphics/GraphicsJNI.h"
#include "jni.h"
+#include "JNIHelp.h"
// ----------------------------------------------------------------------------
@@ -35,57 +35,127 @@
static const char* const OutOfResourcesException =
"android/graphics/SurfaceTexture$OutOfResourcesException";
-struct st_t {
- jfieldID surfaceTexture;
+struct fields_t {
+ jfieldID surfaceTexture;
+ jmethodID postEvent;
};
-static st_t st;
+static fields_t fields;
// ----------------------------------------------------------------------------
-static void setSurfaceTexture(JNIEnv* env, jobject clazz,
+static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
const sp<SurfaceTexture>& surfaceTexture)
{
SurfaceTexture* const p =
- (SurfaceTexture*)env->GetIntField(clazz, st.surfaceTexture);
+ (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture);
if (surfaceTexture.get()) {
- surfaceTexture->incStrong(clazz);
+ surfaceTexture->incStrong(thiz);
}
if (p) {
- p->decStrong(clazz);
+ p->decStrong(thiz);
}
- env->SetIntField(clazz, st.surfaceTexture, (int)surfaceTexture.get());
+ env->SetIntField(thiz, fields.surfaceTexture, (int)surfaceTexture.get());
}
-sp<SurfaceTexture> getSurfaceTexture(JNIEnv* env, jobject clazz)
+sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz)
{
sp<SurfaceTexture> surfaceTexture(
- (SurfaceTexture*)env->GetIntField(clazz, st.surfaceTexture));
+ (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture));
return surfaceTexture;
}
// ----------------------------------------------------------------------------
-static void SurfaceTexture_init(JNIEnv* env, jobject clazz, jint texName)
+class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener
{
- sp<SurfaceTexture> surfaceTexture(new SurfaceTexture(texName));
+public:
+ JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz);
+ virtual ~JNISurfaceTextureContext();
+ virtual void onFrameAvailable();
- if (surfaceTexture == 0) {
- doThrow(env, OutOfResourcesException);
- return;
- }
- setSurfaceTexture(env, clazz, surfaceTexture);
+private:
+ jobject mWeakThiz;
+ jclass mClazz;
+};
+
+JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env,
+ jobject weakThiz, jclass clazz) :
+ mWeakThiz(env->NewGlobalRef(weakThiz)),
+ mClazz((jclass)env->NewGlobalRef(clazz))
+{}
+
+JNISurfaceTextureContext::~JNISurfaceTextureContext()
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->DeleteGlobalRef(mWeakThiz);
+ env->DeleteGlobalRef(mClazz);
}
-static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject clazz)
+void JNISurfaceTextureContext::onFrameAvailable()
{
- sp<SurfaceTexture> surfaceTexture(getSurfaceTexture(env, clazz));
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz);
+}
+
+// ----------------------------------------------------------------------------
+
+static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz)
+{
+ fields.surfaceTexture = env->GetFieldID(clazz,
+ ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
+ if (fields.surfaceTexture == NULL) {
+ LOGE("can't find android/graphics/SurfaceTexture.%s",
+ ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID);
+ }
+
+ fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
+ "(Ljava/lang/Object;)V");
+ if (fields.postEvent == NULL) {
+ LOGE("can't find android/graphics/SurfaceTexture.postEventFromNative");
+ }
+
+}
+
+static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName,
+ jobject weakThiz)
+{
+ sp<SurfaceTexture> surfaceTexture(new SurfaceTexture(texName));
+ if (surfaceTexture == 0) {
+ jniThrowException(env, OutOfResourcesException,
+ "Unable to create native SurfaceTexture");
+ return;
+ }
+ SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
+
+ jclass clazz = env->GetObjectClass(thiz);
+ if (clazz == NULL) {
+ jniThrowRuntimeException(env,
+ "Can't find android/graphics/SurfaceTexture");
+ return;
+ }
+
+ sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz,
+ clazz));
+ surfaceTexture->setFrameAvailableListener(ctx);
+}
+
+static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz)
+{
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ surfaceTexture->setFrameAvailableListener(0);
+ SurfaceTexture_setSurfaceTexture(env, thiz, 0);
+}
+
+static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
+{
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
surfaceTexture->updateTexImage();
}
-static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject clazz,
+static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz,
jfloatArray jmtx)
{
- sp<SurfaceTexture> surfaceTexture(getSurfaceTexture(env, clazz));
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
float* mtx = env->GetFloatArrayElements(jmtx, NULL);
surfaceTexture->getTransformMatrix(mtx);
env->ReleaseFloatArrayElements(jmtx, mtx, 0);
@@ -94,21 +164,15 @@
// ----------------------------------------------------------------------------
const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
-static void nativeClassInit(JNIEnv* env, jclass clazz);
static JNINativeMethod gSurfaceTextureMethods[] = {
- {"nativeClassInit", "()V", (void*)nativeClassInit },
- {"init", "(I)V", (void*)SurfaceTexture_init },
- {"updateTexImage", "()V", (void*)SurfaceTexture_updateTexImage },
- {"getTransformMatrixImpl", "([F)V", (void*)SurfaceTexture_getTransformMatrix },
+ {"nativeClassInit", "()V", (void*)SurfaceTexture_classInit },
+ {"nativeInit", "(ILjava/lang/Object;)V", (void*)SurfaceTexture_init },
+ {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize },
+ {"nativeUpdateTexImage", "()V", (void*)SurfaceTexture_updateTexImage },
+ {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix },
};
-static void nativeClassInit(JNIEnv* env, jclass clazz)
-{
- st.surfaceTexture = env->GetFieldID(clazz,
- ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
-}
-
int register_android_graphics_SurfaceTexture(JNIEnv* env)
{
int err = 0;
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index b033878..0430a81 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -500,8 +500,9 @@
void* dlhandle;
ANativeActivity_createFunc* createActivityFunc;
- String8 internalDataPath;
- String8 externalDataPath;
+ String8 internalDataPathObj;
+ String8 externalDataPathObj;
+ String8 obbPathObj;
sp<ANativeWindow> nativeWindow;
int32_t lastWindowWidth;
@@ -641,8 +642,8 @@
static jint
loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName,
- jobject messageQueue,
- jstring internalDataDir, jstring externalDataDir, int sdkVersion,
+ jobject messageQueue, jstring internalDataDir, jstring obbDir,
+ jstring externalDataDir, int sdkVersion,
jobject jAssetMgr, jbyteArray savedState)
{
LOG_TRACE("loadNativeCode_native");
@@ -699,19 +700,24 @@
code->clazz = env->NewGlobalRef(clazz);
const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL);
- code->internalDataPath = dirStr;
- code->internalDataPath = code->internalDataPath.string();
- env->ReleaseStringUTFChars(path, dirStr);
+ code->internalDataPathObj = dirStr;
+ code->internalDataPath = code->internalDataPathObj.string();
+ env->ReleaseStringUTFChars(internalDataDir, dirStr);
dirStr = env->GetStringUTFChars(externalDataDir, NULL);
- code->externalDataPath = dirStr;
- code->externalDataPath = code->externalDataPath.string();
- env->ReleaseStringUTFChars(path, dirStr);
+ code->externalDataPathObj = dirStr;
+ code->externalDataPath = code->externalDataPathObj.string();
+ env->ReleaseStringUTFChars(externalDataDir, dirStr);
code->sdkVersion = sdkVersion;
code->assetManager = assetManagerForJavaObject(env, jAssetMgr);
+ dirStr = env->GetStringUTFChars(obbDir, NULL);
+ code->obbPathObj = dirStr;
+ code->obbPath = code->obbPathObj.string();
+ env->ReleaseStringUTFChars(obbDir, dirStr);
+
jbyte* rawSavedState = NULL;
jsize rawSavedSize = 0;
if (savedState != NULL) {
@@ -1022,7 +1028,7 @@
}
static const JNINativeMethod g_methods[] = {
- { "loadNativeCode", "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)I",
+ { "loadNativeCode", "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)I",
(void*)loadNativeCode_native },
{ "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
{ "onStartNative", "(I)V", (void*)onStart_native },
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 8a46546..4f5beff 100644
--- a/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml
+++ b/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml
@@ -27,12 +27,11 @@
android:layout_height="0px"
android:layout_weight="1"
android:layout_above="@+id/emergencyCall">
- <RelativeLayout
+ <RelativeLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
-
- <TextView
+ android:layout_height="match_parent">
+
+ <TextView
android:id="@+id/topHeader"
android:layout_width="match_parent"
android:layout_height="64dip"
@@ -43,7 +42,7 @@
android:drawableLeft="@drawable/ic_lock_idle_lock"
android:drawablePadding="5dip"
/>
-
+
<!-- spacer below header -->
<View
android:id="@+id/spacerTop"
@@ -51,7 +50,7 @@
android:layout_height="1dip"
android:layout_below="@id/topHeader"
android:background="@drawable/divider_horizontal_dark"/>
-
+
<TextView
android:id="@+id/instructions"
android:layout_width="match_parent"
@@ -62,7 +61,7 @@
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@android:string/lockscreen_glogin_instructions"
/>
-
+
<EditText
android:id="@+id/login"
android:layout_width="match_parent"
@@ -74,7 +73,7 @@
android:hint="@android:string/lockscreen_glogin_username_hint"
android:inputType="textEmailAddress"
/>
-
+
<EditText
android:id="@+id/password"
android:layout_width="match_parent"
@@ -88,11 +87,11 @@
android:nextFocusRight="@+id/ok"
android:nextFocusDown="@+id/ok"
/>
-
+
<!-- ok below password, aligned to right of screen -->
<Button
android:id="@+id/ok"
- android:layout_width="85dip"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/password"
android:layout_marginTop="7dip"
@@ -100,10 +99,10 @@
android:layout_alignParentRight="true"
android:text="@android:string/lockscreen_glogin_submit_button"
/>
-
+
</RelativeLayout>
</ScrollView>
-
+
<!-- spacer above emergency call -->
<View
android:layout_width="match_parent"
@@ -121,6 +120,7 @@
android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="8dip"
android:text="@android:string/lockscreen_emergency_call"
+ android:visibility="gone"
/>
</LinearLayout>
diff --git a/core/res/res/layout/alert_dialog_holo.xml b/core/res/res/layout/alert_dialog_holo.xml
index 1002c4b..57eb9c7 100644
--- a/core/res/res/layout/alert_dialog_holo.xml
+++ b/core/res/res/layout/alert_dialog_holo.xml
@@ -27,7 +27,6 @@
<LinearLayout android:id="@+id/topPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="64dip"
android:orientation="vertical">
<ImageView android:id="@+id/titleDividerTop"
android:layout_width="match_parent"
@@ -42,9 +41,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:gravity="center_vertical"
- android:layout_marginTop="8dip"
- android:layout_marginBottom="8dip"
+ android:gravity="center_vertical|left"
+ android:minHeight="60dip"
android:layout_marginLeft="32dip"
android:layout_marginRight="32dip">
<ImageView android:id="@+id/icon"
diff --git a/core/res/res/layout/dialog_custom_title_holo.xml b/core/res/res/layout/dialog_custom_title_holo.xml
index 854873f..74b6070 100644
--- a/core/res/res/layout/dialog_custom_title_holo.xml
+++ b/core/res/res/layout/dialog_custom_title_holo.xml
@@ -23,10 +23,19 @@
android:fitsSystemWindows="true">
<FrameLayout android:id="@android:id/title_container"
android:layout_width="match_parent"
- android:layout_height="24dip"
+ android:layout_height="60dip"
android:layout_weight="0"
+ android:gravity="center_vertical|left"
style="?android:attr/windowTitleBackgroundStyle">
</FrameLayout>
+ <ImageView android:id="@+id/titleDivider"
+ android:layout_width="match_parent"
+ android:layout_height="4dip"
+ android:scaleType="fitXY"
+ android:gravity="fill_horizontal"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:src="@android:drawable/divider_strong_holo" />
<FrameLayout
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_weight="1"
@@ -34,10 +43,6 @@
android:foreground="?android:attr/windowContentOverlay">
<FrameLayout android:id="@android:id/content"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingTop="6dip"
- android:paddingBottom="10dip"
- android:paddingLeft="10dip"
- android:paddingRight="10dip" />
+ android:layout_height="match_parent" />
</FrameLayout>
</LinearLayout>
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/layout/search_view.xml b/core/res/res/layout/search_view.xml
index 46d0341..0a7cd3c 100644
--- a/core/res/res/layout/search_view.xml
+++ b/core/res/res/layout/search_view.xml
@@ -100,8 +100,8 @@
android:id="@+id/search_close_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:paddingLeft="4dip"
- android:paddingRight="4dip"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip"
android:layout_gravity="center_vertical"
android:background="?android:attr/selectableItemBackground"
android:src="?android:attr/searchViewCloseIcon"
@@ -111,26 +111,34 @@
</LinearLayout>
- <ImageView
- android:id="@+id/search_go_btn"
+ <LinearLayout
+ android:id="@+id/submit_area"
+ android:orientation="horizontal"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center_vertical"
- android:paddingLeft="4dip"
- android:paddingRight="4dip"
- android:background="?android:attr/selectableItemBackground"
- android:src="?android:attr/searchViewGoIcon"
- />
+ android:layout_height="match_parent">
- <ImageView
- android:id="@+id/search_voice_btn"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center_vertical"
- android:paddingLeft="4dip"
- android:paddingRight="4dip"
- android:src="?android:attr/searchViewVoiceIcon"
- android:background="?android:attr/selectableItemBackground"
- android:visibility="gone"
- />
+ <ImageView
+ android:id="@+id/search_go_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:background="?android:attr/selectableItemBackground"
+ android:src="?android:attr/searchViewGoIcon"
+ android:visibility="gone"
+ />
+
+ <ImageView
+ android:id="@+id/search_voice_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:src="?android:attr/searchViewVoiceIcon"
+ android:background="?android:attr/selectableItemBackground"
+ android:visibility="gone"
+ />
+ </LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/simple_dropdown_item_1line.xml b/core/res/res/layout/simple_dropdown_item_1line.xml
index 18e7b88..3ec930c 100644
--- a/core/res/res/layout/simple_dropdown_item_1line.xml
+++ b/core/res/res/layout/simple_dropdown_item_1line.xml
@@ -20,7 +20,7 @@
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
style="?android:attr/dropDownItemStyle"
- android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
diff --git a/core/res/res/layout/simple_dropdown_item_2line.xml b/core/res/res/layout/simple_dropdown_item_2line.xml
index 903adb0..d6f911a 100644
--- a/core/res/res/layout/simple_dropdown_item_2line.xml
+++ b/core/res/res/layout/simple_dropdown_item_2line.xml
@@ -37,7 +37,7 @@
<TextView
android:id="@android:id/text1"
style="?android:attr/dropDownItemStyle"
- android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
@@ -45,7 +45,7 @@
<TextView
android:id="@android:id/text2"
style="?android:attr/dropDownItemStyle"
- android:textAppearance="?android:attr/textAppearanceSmallInverse"
+ android:textAppearance="?android:attr/textAppearanceSmallPopupMenu"
android:textColor="#323232"
android:singleLine="true"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/textview_hint.xml b/core/res/res/layout/textview_hint.xml
index 4978be5..20b08bf 100644
--- a/core/res/res/layout/textview_hint.xml
+++ b/core/res/res/layout/textview_hint.xml
@@ -18,5 +18,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/popup_inline_error"
- android:textAppearance="?android:attr/textAppearanceSmallInverse"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/primary_text_light"
/>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 02855b5..19e2b8d 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -544,6 +544,9 @@
<enum name="floating" value="0" />
<enum name="atThumb" value="1" />
</attr>
+ <!-- Text color for the fast scroll index overlay. Make sure it
+ plays nicely with fastScrollPreviewBackground[Left|Right]. -->
+ <attr name="fastScrollTextColor" format="color" />
<!-- =================== -->
<!-- Action bar styles -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 5ff6212..a9a7e4a 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -778,6 +778,13 @@
<attr name="restoreNeedsApplication" />
<attr name="restoreAnyVersion" />
<attr name="neverEncrypt" />
+ <!-- Request that your application's processes be created with
+ a large Dalvik heap. This applies to <em>all</em> processes
+ created for the application. It only applies to the first
+ application loaded into a process; if using a sharedUserId
+ to allow multiple applications to use a process, they all must
+ use this option consistently or will get unpredictable results. -->
+ <attr name="largeHeap" format="boolean" />
<!-- Declare that this applicationn can't participate in the normal
state save/restore mechanism. Since it is not able to save and
restore its state on demand,
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index e5b6563..a51a26d 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -68,4 +68,10 @@
is along the minor axis (that is the screen is portrait). This may
be either a fraction or a dimension. -->
<item type="dimen" name="dialog_min_width_minor">95%</item>
+
+ <!-- The width of the big icons in notifications. -->
+ <dimen name="notification_large_icon_width">60dp</dimen>
+ <!-- The width of the big icons in notifications. -->
+ <dimen name="notification_large_icon_height">60dp</dimen>
+
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 9b88b01..3ad29c4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1425,6 +1425,8 @@
<public type="attr" name="windowMinWidthMajor" />
<public type="attr" name="windowMinWidthMinor" />
<public type="attr" name="queryHint" />
+ <public type="attr" name="fastScrollTextColor" />
+ <public type="attr" name="largeHeap" />
<!-- A simple fade-in animation. -->
<public type="animator" name="fade_in" id="0x010b0000" />
@@ -1469,6 +1471,8 @@
<public type="dimen" name="dialog_min_width_major" />
<public type="dimen" name="dialog_min_width_minor" />
+ <public type="dimen" name="notification_large_icon_width" />
+ <public type="dimen" name="notification_large_icon_height" />
<!-- Standard content view for a {@link android.app.ListFragment}.
If you are implementing a subclass of ListFragment with your
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 1183915..a366047 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -889,22 +889,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>
@@ -2057,7 +2101,7 @@
<!-- Window title -->
<style name="WindowTitleBackground.Holo">
- <item name="android:background">@android:drawable/title_bar</item>
+ <item name="android:background">@null</item>
</style>
<style name="WindowTitle.Holo">
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 291c1f8..506dd07 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -294,6 +294,7 @@
<item name="fastScrollPreviewBackgroundRight">@android:drawable/menu_submenu_background</item>
<item name="fastScrollPreviewBackgroundLeft">@android:drawable/menu_submenu_background</item>
<item name="fastScrollOverlayPosition">floating</item>
+ <item name="fastScrollTextColor">@android:color/primary_text_dark</item>
</style>
@@ -923,18 +924,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 -->
@@ -1106,6 +1107,7 @@
<item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_holo</item>
<item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_holo</item>
<item name="dialogTitleDecorLayout">@layout/dialog_title_holo</item>
+ <item name="alertDialogCenterButtons">false</item>
<item name="alertDialogTheme">@android:style/Theme.Holo.Light.Dialog.Alert</item>
<item name="alertDialogIcon">@android:drawable/ic_dialog_alert_holo_light</item>
@@ -1185,16 +1187,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 -->
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/topics/fragments/index.jd b/docs/html/guide/topics/fragments/index.jd
index d07daf4..045a1e8 100644
--- a/docs/html/guide/topics/fragments/index.jd
+++ b/docs/html/guide/topics/fragments/index.jd
@@ -6,7 +6,7 @@
<h2>Quickview</h2>
<ul>
- <li>Decompose application functionality and UI into reusable modules</li>
+ <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>
@@ -14,12 +14,27 @@
<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>
+ <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>
@@ -29,100 +44,108 @@
<li>{@link android.app.FragmentTransaction}</li>
</ol>
- <!--
<h2>Related samples</h2>
<ol>
<li><a
-href="{@docRoot}resources/samples/NotePad/index.html">NotePad</a></li>
+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>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>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—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>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—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>
+<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 <fragment>} 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>
-<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>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>
-<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>
+
+<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—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
+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.</p>
+activity, as illustrated in figure 1.</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>
--->
+<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>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 <fragment>} 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—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>
+<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—to continue with the news application example—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>
-<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>
+<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>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>
+<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 the essential components of the fragment that should be retained when the fragment is
-paused or stopped.</dd>
+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
@@ -135,101 +158,117 @@
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>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 different subclasses of {@link android.app.Fragment} that you might want
-to use:</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 the dialog can be
-incorporated into the fragment back stack managed by the activity.</dd>
+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}. Provides methods
-for managing a list, such as the {@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 on list items.</dd>
+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}. </dd>
+{@link android.preference.PreferenceActivity}. This is useful when creating a "settings"
+activity for your application.</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">Adding a user interface</h3>
-<h3 id="UI">Providing 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 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
+<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>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>
+<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 SimpleFragment extends Fragment {
+public static class ExampleFragment extends Fragment {
@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);
+ 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 (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—doing otherwise would create a redundant view group in the final layout)</li>
+ <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}—passing true 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>
+<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>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>
+<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 XML file.</b>
+ <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 itself and the fragment's layout
-fills that space. For example:</p>
+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>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
@@ -248,338 +287,286 @@
android:layout_height="match_parent" />
</LinearLayout>
</pre>
- <p>The {@code <fragment>} 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 <fragment>} element.</p>
+ <p>The {@code android:name} attribute in the {@code <fragment>} 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 <fragment>} 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>
+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, in the {@code
-<fragment>}</li>
- <li>Supply the {@code android:tag} attribute with a unique string ID, in the {@code
- <fragment>}</li>
- <li>If neither of the previous two are provided, the system uses the ID of the container
- view.</li>
+ <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 (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
+<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.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>
+of {@link android.app.FragmentTransaction} from your {@link android.app.Activity} like this:</p>
+
<pre>
-MyFragment fragment = new MyFragment();
-getFragmentManager().openTransaction().add(R.id.fragment_container, fragment).commit();
+FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()}
+FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#openTransaction()};
</pre>
- <p>The first argument passed to {@link android.app.FragmentTransaction#add add()}
+
+<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 object.</p>
- <p>Once you've made your changes using
+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} in order for the changes to take effect.</p>
+call {@link android.app.FragmentTransaction#commit} for the changes to take effect.</p>
</li>
</ul>
-<h3 id="Example1">Example: simple fragments</h3>
+<h4 id="AddingWithoutUI">Adding a fragment without a UI</h4>
-<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>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>First, here's a layout file for a fragment:</p>
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-<TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/hello" />
-<TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/hello" />
-</LinearLayout>
-</pre>
+<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>With that file saved at {@code res/layout/simple_fragment.xml}, the following {@link
-android.app.Fragment} uses it for its layout:</p>
+<p>Supplying a string tag for the fragment isn't strictly for non-UI fragments—you can also
+supply string tags to fragments that do have a UI—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>
-<pre>
-public static class SimpleFragment extends Fragment {
- @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>
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <fragment android:name="com.example.SimpleFragment"
- android:id="@+id/list"
- android:layout_weight="1"
- android:layout_width="0dp"
- android:layout_height="match_parent" />
- <fragment android:name="com.example.SimpleFragment"
- android:id="@+id/viewer"
- android:layout_weight="1"
- android:layout_width="0dp"
- android:layout_height="match_parent" />
-</LinearLayout>
-</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>
+<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>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>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>Common transactions you can perform with fragments include:</p>
+<p>Some things that you can do with {@link android.app.FragmentManager} 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>
+<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 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>
+<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>
-// 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();
+FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()};
+FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#openTransaction()};
</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
+<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().openTransaction();
+
+// 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 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>
+<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>
-
-
-<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—but only while the activity is
-resumed (while it is in the foreground)—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>
+<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</li>
+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.</p>
+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>
-<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>
+<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>
-<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>
+<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>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>
+<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>
-MyFragment fragment = (MyFragment) findFragmentById(R.id.myfragment);
-fragment.refreshList();
+ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
</pre>
-<h4 id="Callbacks">Creating event callbacks to the activity</h4>
+<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, it can share the information with other fragments in the layout as
-necessary.</p>
+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—one to show a list of
articles (fragment A) and another to display an article (fragment B)—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>
+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 SelectedCallback {
+ public interface OnArticleSelectedListener {
public void onArticleSelected(Uri articleUri);
}
...
}
</pre>
-<p>Then the activity that hosts the fragment implements the {@code SelectedCallback} interface and
+<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 (called when
-the fragment is added to the activity) instantiates an instance of {@code SelectedCallback} by
+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;
...
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
- mCallback = (SelectedCallback) activity;
+ mListener = (OnArticleSelectedListener) activity;
} catch (ClassCastException e) {
- activity.finish();
- throw new ClassCastException(activity.toString() + " must implement SelectedCallback");
+ throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
}
}
...
}
</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
+<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
@@ -587,13 +574,14 @@
<pre>
public static class FragmentA extends ListFragment {
+ OnArticleSelectedListener mListener;
...
@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);
+ mListener.onArticleSelected(noteUri);
}
...
}
@@ -611,38 +599,217 @@
+<h3 id="ActionBar">Adding items to the Action Bar</h3>
-
-
-<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
+<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 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>
+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>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
+<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>For more information, see <a href="{@docRoot}guide/topics/ui/menus.html">Creating
+<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/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/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 3eb0b03..64c209a 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -16,6 +16,11 @@
package android.graphics;
+import java.lang.ref.WeakReference;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
/**
* Captures frames from an image stream as an OpenGL ES texture.
*
@@ -32,6 +37,9 @@
*/
public class SurfaceTexture {
+ private EventHandler mEventHandler;
+ private OnFrameAvailableListener mOnFrameAvailableListener;
+
@SuppressWarnings("unused")
private int mSurfaceTexture;
@@ -59,7 +67,15 @@
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
*/
public SurfaceTexture(int texName) {
- init(texName);
+ Looper looper;
+ if ((looper = Looper.myLooper()) != null) {
+ mEventHandler = new EventHandler(looper);
+ } else if ((looper = Looper.getMainLooper()) != null) {
+ mEventHandler = new EventHandler(looper);
+ } else {
+ mEventHandler = null;
+ }
+ nativeInit(texName, new WeakReference<SurfaceTexture>(this));
}
/**
@@ -69,7 +85,7 @@
* thread invoking the callback.
*/
public void setOnFrameAvailableListener(OnFrameAvailableListener l) {
- // TODO: Implement this!
+ mOnFrameAvailableListener = l;
}
/**
@@ -77,8 +93,9 @@
* called while the OpenGL ES context that owns the texture is bound to the thread. It will
* implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
*/
- public native void updateTexImage();
-
+ public void updateTexImage() {
+ nativeUpdateTexImage();
+ }
/**
* Retrieve the 4x4 texture coordinate transform matrix associated with the texture image set by
@@ -99,12 +116,48 @@
if (mtx.length != 16) {
throw new IllegalArgumentException();
}
- getTransformMatrixImpl(mtx);
+ nativeGetTransformMatrix(mtx);
}
- private native void getTransformMatrixImpl(float[] mtx);
+ protected void finalize() throws Throwable {
+ try {
+ nativeFinalize();
+ } finally {
+ super.finalize();
+ }
+ }
- private native void init(int texName);
+ private class EventHandler extends Handler {
+ public EventHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (mOnFrameAvailableListener != null) {
+ mOnFrameAvailableListener.onFrameAvailable(SurfaceTexture.this);
+ }
+ return;
+ }
+ }
+
+ private static void postEventFromNative(Object selfRef) {
+ WeakReference weakSelf = (WeakReference)selfRef;
+ SurfaceTexture st = (SurfaceTexture)weakSelf.get();
+ if (st == null) {
+ return;
+ }
+
+ if (st.mEventHandler != null) {
+ Message m = st.mEventHandler.obtainMessage();
+ st.mEventHandler.sendMessage(m);
+ }
+ }
+
+ private native void nativeInit(int texName, Object weakSelf);
+ private native void nativeFinalize();
+ private native void nativeGetTransformMatrix(float[] mtx);
+ private native void nativeUpdateTexImage();
/*
* We use a class initializer to allow the native code to cache some
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 579f314..852aabf 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -239,15 +239,13 @@
}
/**
- * @hide
- *
* This is only intended to be used by auto-generate code reflected from the
* renderscript script files.
*
* @param xoff
* @param fp
*/
- public void setOneElement(int xoff, FieldPacker fp) {
+ public void setFromFieldPacker(int xoff, FieldPacker fp) {
int eSize = mType.mElement.getSizeBytes();
final byte[] data = fp.getData();
@@ -262,8 +260,6 @@
/**
- * @hide
- *
* This is only intended to be used by auto-generate code reflected from the
* renderscript script files.
*
@@ -271,7 +267,7 @@
* @param component_number
* @param fp
*/
- public void setOneComponent(int xoff, int component_number, FieldPacker fp) {
+ public void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) {
if (component_number >= mType.mElement.mElements.length) {
throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
}
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
index b3ad20a..56abba5 100644
--- a/graphics/java/android/renderscript/Script.java
+++ b/graphics/java/android/renderscript/Script.java
@@ -21,8 +21,6 @@
**/
public class Script extends BaseObj {
/**
- * @hide
- *
* Only intended for use by generated reflected code.
*
* @param slot
@@ -32,8 +30,6 @@
}
/**
- * @hide
- *
* Only intended for use by generated reflected code.
*
* @param slot
@@ -54,8 +50,6 @@
/**
- * @hide
- *
* Only intended for use by generated reflected code.
*
* @param va
@@ -71,8 +65,6 @@
}
/**
- * @hide
- *
* Only intended for use by generated reflected code.
*
* @param index
@@ -83,8 +75,6 @@
}
/**
- * @hide
- *
* Only intended for use by generated reflected code.
*
* @param index
@@ -95,8 +85,6 @@
}
/**
- * @hide
- *
* Only intended for use by generated reflected code.
*
* @param index
@@ -107,8 +95,6 @@
}
/**
- * @hide
- *
* Only intended for use by generated reflected code.
*
* @param index
@@ -119,8 +105,6 @@
}
/**
- * @hide
- *
* Only intended for use by generated reflected code.
*
* @param index
@@ -131,8 +115,6 @@
}
/**
- * @hide
- *
* Only intended for use by generated reflected code.
*
* @param index
@@ -143,8 +125,6 @@
}
/**
- * @hide
- *
* Only intended for use by generated reflected code.
*
* @param index
diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
index 14e4ab5..ff8f093 100644
--- a/graphics/java/android/renderscript/ScriptC.java
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -36,8 +36,6 @@
private static final String TAG = "ScriptC";
/**
- * @hide
- *
* Only intended for use by the generated derived classes.
*
* @param id
@@ -48,8 +46,6 @@
}
/**
- * @hide
- *
* Only intended for use by the generated derived classes.
*
*
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 002e48b..79c33f5 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -40,6 +40,10 @@
enum { MIN_BUFFER_SLOTS = 3 };
enum { NUM_BUFFER_SLOTS = 32 };
+ struct FrameAvailableListener : public virtual RefBase {
+ virtual void onFrameAvailable() = 0;
+ };
+
// tex indicates the name OpenGL texture to which images are to be streamed.
// This texture name cannot be changed once the SurfaceTexture is created.
SurfaceTexture(GLuint tex);
@@ -93,6 +97,10 @@
// functions.
void getTransformMatrix(float mtx[16]);
+ // setFrameAvailableListener sets the listener object that will be notified
+ // when a new frame becomes available.
+ void setFrameAvailableListener(const sp<FrameAvailableListener>& l);
+
private:
// freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
@@ -195,6 +203,11 @@
// to a buffer, but other processes do.
Vector<sp<GraphicBuffer> > mAllocdBuffers;
+ // mFrameAvailableListener is the listener object that will be called when a
+ // new frame becomes available. If it is not NULL it will be called from
+ // queueBuffer.
+ sp<FrameAvailableListener> mFrameAvailableListener;
+
// mMutex is the mutex used to prevent concurrent access to the member
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
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/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/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 447de76..1dadd53 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -166,6 +166,9 @@
mLastQueued = buf;
mLastQueuedCrop = mNextCrop;
mLastQueuedTransform = mNextTransform;
+ if (mFrameAvailableListener != 0) {
+ mFrameAvailableListener->onFrameAvailable();
+ }
return OK;
}
@@ -237,43 +240,68 @@
LOGV("SurfaceTexture::updateTexImage");
Mutex::Autolock lock(mMutex);
- float* xform = mtxIdentity;
- switch (mCurrentTransform) {
- case 0:
- xform = mtxIdentity;
- break;
- case NATIVE_WINDOW_TRANSFORM_FLIP_H:
- xform = mtxFlipH;
- break;
- case NATIVE_WINDOW_TRANSFORM_FLIP_V:
- xform = mtxFlipV;
- break;
- case NATIVE_WINDOW_TRANSFORM_ROT_90:
- xform = mtxRot90;
- break;
- case NATIVE_WINDOW_TRANSFORM_ROT_180:
- xform = mtxRot180;
- break;
- case NATIVE_WINDOW_TRANSFORM_ROT_270:
- xform = mtxRot270;
- break;
- default:
- LOGE("getTransformMatrix: unknown transform: %d", mCurrentTransform);
+ float xform[16];
+ for (int i = 0; i < 16; i++) {
+ xform[i] = mtxIdentity[i];
+ }
+ if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+ float result[16];
+ mtxMul(result, xform, mtxFlipH);
+ for (int i = 0; i < 16; i++) {
+ xform[i] = result[i];
+ }
+ }
+ if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+ float result[16];
+ mtxMul(result, xform, mtxFlipV);
+ for (int i = 0; i < 16; i++) {
+ xform[i] = result[i];
+ }
+ }
+ if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ float result[16];
+ mtxMul(result, xform, mtxRot90);
+ for (int i = 0; i < 16; i++) {
+ xform[i] = result[i];
+ }
}
sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer);
- float tx = float(mCurrentCrop.left) / float(buf->getWidth());
- float ty = float(mCurrentCrop.bottom) / float(buf->getHeight());
- float sx = float(mCurrentCrop.width()) / float(buf->getWidth());
- float sy = float(mCurrentCrop.height()) / float(buf->getHeight());
+ float tx, ty, sx, sy;
+ if (!mCurrentCrop.isEmpty()) {
+ tx = float(mCurrentCrop.left) / float(buf->getWidth());
+ ty = float(buf->getHeight() - mCurrentCrop.bottom) /
+ float(buf->getHeight());
+ sx = float(mCurrentCrop.width()) / float(buf->getWidth());
+ sy = float(mCurrentCrop.height()) / float(buf->getHeight());
+ } else {
+ tx = 0.0f;
+ ty = 0.0f;
+ sx = 1.0f;
+ sy = 1.0f;
+ }
float crop[16] = {
- sx, 0, 0, sx*tx,
- 0, sy, 0, sy*ty,
+ sx, 0, 0, 0,
+ 0, sy, 0, 0,
0, 0, 1, 0,
- 0, 0, 0, 1,
+ sx*tx, sy*ty, 0, 1,
};
- mtxMul(mtx, crop, xform);
+ float mtxBeforeFlipV[16];
+ mtxMul(mtxBeforeFlipV, crop, xform);
+
+ // SurfaceFlinger expects the top of its window textures to be at a Y
+ // coordinate of 0, so SurfaceTexture must behave the same way. We don't
+ // want to expose this to applications, however, so we must add an
+ // additional vertical flip to the transform after all the other transforms.
+ mtxMul(mtx, mtxFlipV, mtxBeforeFlipV);
+}
+
+void SurfaceTexture::setFrameAvailableListener(
+ const sp<FrameAvailableListener>& l) {
+ LOGV("SurfaceTexture::setFrameAvailableListener");
+ Mutex::Autolock lock(mMutex);
+ mFrameAvailableListener = l;
}
void SurfaceTexture::freeAllBuffers() {
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 24cee24..0ed8be5 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -111,7 +111,7 @@
LOGV("SurfaceTextureClient::cancelBuffer");
Mutex::Autolock lock(mMutex);
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
- if (mSlots[i].get() == buffer) {
+ if (mSlots[i]->handle == buffer->handle) {
mSurfaceTexture->cancelBuffer(i);
return OK;
}
@@ -129,7 +129,7 @@
LOGV("SurfaceTextureClient::queueBuffer");
Mutex::Autolock lock(mMutex);
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
- if (mSlots[i].get() == GraphicBuffer::getSelf(buffer)) {
+ if (mSlots[i]->handle == buffer->handle) {
return mSurfaceTexture->queueBuffer(i);
}
}
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
index aa4cf2d..bd4ae4e 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
@@ -56,7 +56,7 @@
}
//sliao
-uchar3 convert2uchar3(float3 xyz);
+extern uchar3 __attribute__((overloadable)) convert2uchar3(float3 xyz);
void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
uchar4 *output = (uchar4 *)v_out;
@@ -87,7 +87,7 @@
temp = pow(temp, (float3)gamma);
temp = clamp(temp * outWMinOutB + outBlack, 0.f, 255.f);
- output->xyz = convert2uchar3(temp);
+ output->xyz = convert_uchar3(temp);
//output->w = input->w;
}
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 2ed7774..41c9fe2 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -188,12 +188,7 @@
isFirstUpload = true;
}
- GLenum target = (GLenum)getGLTarget();
- if (target == GL_TEXTURE_2D) {
- upload2DTexture(isFirstUpload, mPtr);
- } else if (target == GL_TEXTURE_CUBE_MAP) {
- uploadCubeTexture(isFirstUpload);
- }
+ upload2DTexture(isFirstUpload);
if (!(mUsageFlags & RS_ALLOCATION_USAGE_SCRIPT)) {
freeScriptMemory();
@@ -202,18 +197,32 @@
rsc->checkError("Allocation::uploadToTexture");
}
+const static GLenum gFaceOrder[] = {
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
+};
+
void Allocation::update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff,
uint32_t lod, RsAllocationCubemapFace face,
uint32_t w, uint32_t h) {
GLenum type = mType->getElement()->getComponent().getGLType();
GLenum format = mType->getElement()->getComponent().getGLFormat();
GLenum target = (GLenum)getGLTarget();
+ rsAssert(mTextureID);
glBindTexture(target, mTextureID);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexSubImage2D(GL_TEXTURE_2D, lod, xoff, yoff, w, h, format, type, ptr);
+ GLenum t = GL_TEXTURE_2D;
+ if (mType->getDimFaces()) {
+ t = gFaceOrder[face];
+ }
+ glTexSubImage2D(t, lod, xoff, yoff, w, h, format, type, ptr);
}
-void Allocation::upload2DTexture(bool isFirstUpload, const void *ptr) {
+void Allocation::upload2DTexture(bool isFirstUpload) {
GLenum type = mType->getElement()->getComponent().getGLType();
GLenum format = mType->getElement()->getComponent().getGLFormat();
@@ -221,62 +230,29 @@
glBindTexture(target, mTextureID);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- for (uint32_t lod = 0; lod < mType->getLODCount(); lod++) {
- const uint8_t *p = (const uint8_t *)ptr;
- p += mType->getLODOffset(lod);
-
- if (isFirstUpload) {
- glTexImage2D(GL_TEXTURE_2D, lod, format,
- mType->getLODDimX(lod), mType->getLODDimY(lod),
- 0, format, type, p);
- } else {
- glTexSubImage2D(GL_TEXTURE_2D, lod, 0, 0,
- mType->getLODDimX(lod), mType->getLODDimY(lod),
- format, type, p);
- }
+ uint32_t faceCount = 1;
+ if (mType->getDimFaces()) {
+ faceCount = 6;
}
- if (mMipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) {
-#ifndef ANDROID_RS_BUILD_FOR_HOST
- glGenerateMipmap(target);
-#endif //ANDROID_RS_BUILD_FOR_HOST
- }
-}
-
-void Allocation::uploadCubeTexture(bool isFirstUpload) {
- GLenum type = mType->getElement()->getComponent().getGLType();
- GLenum format = mType->getElement()->getComponent().getGLFormat();
-
- GLenum target = (GLenum)getGLTarget();
- glBindTexture(target, mTextureID);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
- GLenum faceOrder[] = {
- GL_TEXTURE_CUBE_MAP_POSITIVE_X,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
- GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
- GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
- };
-
- Adapter2D adapt(getContext(), this);
- for (uint32_t face = 0; face < 6; face ++) {
- adapt.setFace(face);
-
+ for (uint32_t face = 0; face < faceCount; face ++) {
for (uint32_t lod = 0; lod < mType->getLODCount(); lod++) {
- adapt.setLOD(lod);
+ const uint8_t *p = (const uint8_t *)mPtr;
+ p += mType->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0);
- uint16_t * ptr = static_cast<uint16_t *>(adapt.getElement(0,0));
+ GLenum t = GL_TEXTURE_2D;
+ if (mType->getDimFaces()) {
+ t = gFaceOrder[face];
+ }
if (isFirstUpload) {
- glTexImage2D(faceOrder[face], lod, format,
- adapt.getDimX(), adapt.getDimY(),
- 0, format, type, ptr);
+ glTexImage2D(t, lod, format,
+ mType->getLODDimX(lod), mType->getLODDimY(lod),
+ 0, format, type, p);
} else {
- glTexSubImage2D(faceOrder[face], lod, 0, 0,
- adapt.getDimX(), adapt.getDimY(),
- format, type, ptr);
+ glTexSubImage2D(t, lod, 0, 0,
+ mType->getLODDimX(lod), mType->getLODDimY(lod),
+ format, type, p);
}
}
}
@@ -364,7 +340,7 @@
if (mPtr) {
const uint8_t *src = static_cast<const uint8_t *>(data);
uint8_t *dst = static_cast<uint8_t *>(mPtr);
- dst += mType->getLODOffset(lod, xoff, yoff);
+ dst += mType->getLODFaceOffset(lod, face, xoff, yoff);
//LOGE(" %p %p %i ", dst, src, eSize);
for (uint32_t line=yoff; line < (yoff+h); line++) {
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index a160765..4f5d5a8 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -105,9 +105,6 @@
return mMipmapControl != RS_ALLOCATION_MIPMAP_NONE;
}
- void upload2DTexture(bool isFirstUpload, const void *ptr);
- void update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff,
- uint32_t lod, RsAllocationCubemapFace face, uint32_t w, uint32_t h);
protected:
ObjectBaseRef<const Type> mType;
@@ -149,7 +146,9 @@
private:
void init(Context *rsc, const Type *);
- void uploadCubeTexture(bool isFirstUpload);
+ void upload2DTexture(bool isFirstUpload);
+ void update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff,
+ uint32_t lod, RsAllocationCubemapFace face, uint32_t w, uint32_t h);
void allocScriptMemory();
void freeScriptMemory();
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 872e7a6..1ab2109 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -462,8 +462,10 @@
return NULL;
}
+#if 0
extern const char rs_runtime_lib_bc[];
extern unsigned rs_runtime_lib_bc_size;
+#endif
void ScriptCState::runCompiler(Context *rsc,
ScriptC *s,
@@ -484,11 +486,13 @@
// Handle Fatal Error
}
-#if 0
+#if 1
if (bccLinkBC(s->mBccScript,
resName,
- rs_runtime_lib_bc,
- rs_runtime_lib_bc_size, 0) != 0) {
+ 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
}
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 1c6c5ac..001ac55 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -53,6 +53,10 @@
waitForCommand = false;
//LOGV("playCoreCommands 3 %i %i", cmdID, cmdSize);
+ if (cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) {
+ rsAssert(cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *)));
+ LOGE("playCoreCommands error con %p, cmd %i", con, cmdID);
+ }
gPlaybackFuncs[cmdID](con, data);
mToCore.next();
}
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 670ea33..d7b5f12 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -132,6 +132,17 @@
return offset;
}
+uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const {
+ uint32_t offset = mLODs[lod].mOffset;
+ offset += (x + y * mLODs[lod].mX) * mElement->getSizeBytes();
+
+ if (face != 0) {
+ uint32_t faceOffset = getSizeBytes() / 6;
+ offset += faceOffset * face;
+ }
+ return offset;
+}
+
void Type::dumpLOGV(const char *prefix) const {
char buf[1024];
ObjectBase::dumpLOGV(prefix);
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index 34498f0..90ae039 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -44,12 +44,14 @@
uint32_t getLODDimX(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mX;}
uint32_t getLODDimY(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mY;}
uint32_t getLODDimZ(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mZ;}
- uint32_t getLODOffset(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mOffset;}
+ uint32_t getLODOffset(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mOffset;}
uint32_t getLODOffset(uint32_t lod, uint32_t x) const;
uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const;
uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const;
+ uint32_t getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const;
+
uint32_t getLODCount() const {return mLODCount;}
bool getIsNp2() const;
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
index 1e468bb..4ac5b7f 100644
--- a/libs/rs/rsg_generator.c
+++ b/libs/rs/rsg_generator.c
@@ -219,7 +219,7 @@
fprintf(f, "};\n\n");
}
- fprintf(f, "RsPlaybackFunc gPlaybackFuncs[] = {\n");
+ fprintf(f, "RsPlaybackFunc gPlaybackFuncs[%i] = {\n", apiCount + 1);
fprintf(f, " NULL,\n");
for (ct=0; ct < apiCount; ct++) {
fprintf(f, " %s%s,\n", "rsp_", apis[ct].name);
@@ -265,7 +265,7 @@
printFuncDecls(f, "rsi_", 1);
printPlaybackFuncs(f, "rsp_");
fprintf(f, "\n\ntypedef void (*RsPlaybackFunc)(Context *, const void *);\n");
- fprintf(f, "extern RsPlaybackFunc gPlaybackFuncs[];\n");
+ fprintf(f, "extern RsPlaybackFunc gPlaybackFuncs[%i];\n", apiCount + 1);
fprintf(f, "}\n");
fprintf(f, "}\n");
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/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 cc9f4b2..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/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
new file mode 100755
index 0000000..9d6e7d4
--- /dev/null
+++ b/media/jni/mediaeditor/Android.mk
@@ -0,0 +1,92 @@
+#
+# 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)/external/opencore/extern_libs_v2/khronos/openmax/include \
+ $(TOP)/external/opencore/android \
+ $(TOP)/vendor/qcom/proprietary/qdsp6/mm-core/omxcore/inc \
+ $(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/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 130ad82..fe00856 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,
diff --git a/native/android/looper.cpp b/native/android/looper.cpp
index 9f5cda9..615493f 100644
--- a/native/android/looper.cpp
+++ b/native/android/looper.cpp
@@ -19,9 +19,11 @@
#include <android/looper.h>
#include <utils/Looper.h>
+#include <binder/IPCThreadState.h>
using android::Looper;
using android::sp;
+using android::IPCThreadState;
ALooper* ALooper_forThread() {
return Looper::getForThread().get();
@@ -46,6 +48,7 @@
return ALOOPER_POLL_ERROR;
}
+ IPCThreadState::self()->flushCommands();
return looper->pollOnce(timeoutMillis, outFd, outEvents, outData);
}
@@ -55,7 +58,8 @@
LOGE("ALooper_pollAll: No looper for this thread!");
return ALOOPER_POLL_ERROR;
}
-
+
+ IPCThreadState::self()->flushCommands();
return looper->pollAll(timeoutMillis, outFd, outEvents, outData);
}
diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h
index d89bc8b..a361846 100644
--- a/native/include/android/native_activity.h
+++ b/native/include/android/native_activity.h
@@ -91,6 +91,13 @@
* uses this to access binary assets bundled inside its own .apk file.
*/
AAssetManager* assetManager;
+
+ /**
+ * Available starting with Honeycomb: path to the directory containing
+ * the application's OBB files (if any). If the app doesn't have any
+ * OBB files, this directory may not exist.
+ */
+ const char* obbPath;
} ANativeActivity;
/**
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 386cc5d..ed36171 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -62,6 +62,8 @@
"EGL_KHR_image_base "
"EGL_KHR_image_pixmap "
"EGL_KHR_gl_texture_2D_image "
+ "EGL_KHR_gl_texture_cubemap_image "
+ "EGL_KHR_gl_renderbuffer_image "
"EGL_KHR_fence_sync "
"EGL_ANDROID_image_native_buffer "
"EGL_ANDROID_swap_rectangle "
@@ -1471,6 +1473,29 @@
return result;
}
+// Note: Similar implementations of these functions also exist in
+// gl2.cpp and gl.cpp, and are used by applications that call the
+// exported entry points directly.
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+
+static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL;
+static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL;
+
+static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image)
+{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ glEGLImageTargetTexture2DOES_impl(target, implImage);
+}
+
+static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image)
+{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ glEGLImageTargetRenderbufferStorageOES_impl(target, implImage);
+}
+
__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
{
// eglGetProcAddress() could be the very first function called
@@ -1531,6 +1556,16 @@
}
if (found) {
addr = gExtensionForwarders[slot];
+
+ if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) {
+ glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr;
+ addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper;
+ }
+ if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) {
+ glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr;
+ addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper;
+ }
+
gGLExtentionMap.add(name, addr);
gGLExtentionSlot++;
}
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 0c85af8..2ec2226 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -165,8 +165,13 @@
}
@Override
- public long calculateDirectorySize(String directory) throws RemoteException {
- return MeasurementUtils.measureDirectory(directory);
+ public long calculateDirectorySize(String path) throws RemoteException {
+ final File directory = new File(path);
+ if (directory.exists() && directory.isDirectory()) {
+ return MeasurementUtils.measureDirectory(path);
+ } else {
+ return 0L;
+ }
}
};
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_notification_row.xml b/packages/SystemUI/res/layout-xlarge/status_bar_notification_row.xml
index 4991a40..e97345b 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_notification_row.xml
@@ -18,8 +18,8 @@
<ImageView
android:id="@+id/large_icon"
- android:layout_width="@dimen/notification_large_icon_width"
- android:layout_height="@dimen/notification_large_icon_height"
+ android:layout_width="@android:dimen/notification_large_icon_width"
+ android:layout_height="@android:dimen/notification_large_icon_height"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:scaleType="center"
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_ticker_compat.xml b/packages/SystemUI/res/layout-xlarge/status_bar_ticker_compat.xml
index 5d9a680..6de7697 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_ticker_compat.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_ticker_compat.xml
@@ -25,8 +25,8 @@
<ImageView
android:id="@+id/large_icon"
- android:layout_width="@dimen/notification_large_icon_width"
- android:layout_height="@dimen/notification_large_icon_height"
+ android:layout_width="@android:dimen/notification_large_icon_width"
+ android:layout_height="@android:dimen/notification_large_icon_height"
android:scaleType="center"
android:visibility="gone"
/>
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_ticker_panel.xml b/packages/SystemUI/res/layout-xlarge/status_bar_ticker_panel.xml
index cae6a77..d570ace 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_ticker_panel.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_ticker_panel.xml
@@ -29,8 +29,8 @@
<ImageView
android:id="@+id/large_icon"
- android:layout_width="@dimen/notification_large_icon_height"
- android:layout_height="@dimen/notification_large_icon_width"
+ android:layout_width="@android:dimen/notification_large_icon_height"
+ android:layout_height="@android:dimen/notification_large_icon_width"
android:scaleType="center"
android:visibility="gone"
/>
diff --git a/packages/SystemUI/res/values-xlarge/dimens.xml b/packages/SystemUI/res/values-xlarge/dimens.xml
index b9f5837..9d89e21 100644
--- a/packages/SystemUI/res/values-xlarge/dimens.xml
+++ b/packages/SystemUI/res/values-xlarge/dimens.xml
@@ -16,10 +16,6 @@
*/
-->
<resources>
- <!-- The width of the big icons in notifications. -->
- <dimen name="notification_large_icon_width">60dp</dimen>
- <!-- The width of the big icons in notifications. -->
- <dimen name="notification_large_icon_height">60dp</dimen>
<!-- The width of the ticker, including the icon -->
<dimen name="notification_ticker_width">360dp</dimen>
<!-- Status bar panel bottom offset (height of status bar - overlap) -->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 7e8a5c1..004174e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -19,6 +19,7 @@
import android.app.Notification;
import android.os.IBinder;
import android.view.View;
+import android.widget.ImageView;
import com.android.internal.statusbar.StatusBarNotification;
@@ -36,6 +37,7 @@
public View row; // the outer expanded view
public View content; // takes the click events and sends the PendingIntent
public View expanded; // the inflated RemoteViews
+ public ImageView largeIcon;
public Entry() {}
public Entry(IBinder key, StatusBarNotification n, StatusBarIconView ic) {
this.key = key;
@@ -88,6 +90,7 @@
entry.content = content;
entry.expanded = expanded;
entry.icon = icon;
+ entry.largeIcon = null; // TODO add support for large icons
return add(entry);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 73b6723..dfe0262 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -668,7 +668,8 @@
if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
iconLevel = getEvdoLevel();
if (false) {
- Slog.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
+ Slog.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level="
+ + getCdmaLevel());
}
} else {
iconLevel = getCdmaLevel();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java
index da60f0d..0d2538d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.AsyncTask;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
@@ -54,7 +55,6 @@
}
public void onCheckedChanged(CompoundButton view, boolean checked) {
- Slog.d(TAG, "onCheckedChanged checked=" + checked + " mAirplaneMode=" + mAirplaneMode);
if (checked != mAirplaneMode) {
mAirplaneMode = checked;
unsafe(checked);
@@ -78,15 +78,19 @@
// TODO: Fix this racy API by adding something better to TelephonyManager or
// ConnectivityService.
- private void unsafe(boolean enabled) {
- Settings.System.putInt(
- mContext.getContentResolver(),
- Settings.System.AIRPLANE_MODE_ON,
- enabled ? 1 : 0);
- Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- intent.putExtra("state", enabled);
- mContext.sendBroadcast(intent);
+ private void unsafe(final boolean enabled) {
+ AsyncTask.execute(new Runnable() {
+ public void run() {
+ Settings.System.putInt(
+ mContext.getContentResolver(),
+ Settings.System.AIRPLANE_MODE_ON,
+ enabled ? 1 : 0);
+ Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.putExtra("state", enabled);
+ mContext.sendBroadcast(intent);
+ }
+ });
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
index 866e5fc..b0a6d7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
@@ -18,6 +18,7 @@
import android.content.ContentResolver;
import android.content.Context;
+import android.os.AsyncTask;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
@@ -45,7 +46,6 @@
}
public void onCheckedChanged(CompoundButton view, boolean checked) {
- Slog.d(TAG, "onCheckedChanged checked=" + checked + " mLockRotation=" + mLockRotation);
if (checked != mLockRotation) {
setLockRotation(checked);
}
@@ -56,18 +56,22 @@
return 0 == Settings.System.getInt(cr, Settings.System.ACCELEROMETER_ROTATION, 0);
}
- private void setLockRotation(boolean locked) {
+ private void setLockRotation(final boolean locked) {
mLockRotation = locked;
- try {
- IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService(
- Context.WINDOW_SERVICE));
- ContentResolver cr = mContext.getContentResolver();
- if (locked) {
- wm.freezeRotation();
- } else {
- wm.thawRotation();
- }
- } catch (RemoteException exc) {
- }
+ AsyncTask.execute(new Runnable() {
+ public void run() {
+ try {
+ IWindowManager wm = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+ ContentResolver cr = mContext.getContentResolver();
+ if (locked) {
+ wm.freezeRotation();
+ } else {
+ wm.thawRotation();
+ }
+ } catch (RemoteException exc) {
+ }
+ }
+ });
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
index c11d04e..521467a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
@@ -18,6 +18,7 @@
import android.content.ContentResolver;
import android.content.Context;
+import android.os.AsyncTask;
import android.os.IPowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -79,7 +80,16 @@
setMode(automatic ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
: Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
if (!automatic) {
- setBrightness(value + MINIMUM_BACKLIGHT);
+ final int val = value + value + MINIMUM_BACKLIGHT;
+ setBrightness(val);
+ if (!tracking) {
+ AsyncTask.execute(new Runnable() {
+ public void run() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS, val);
+ }
+ });
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 3a7bd90..e80e37d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -47,7 +47,6 @@
int mRepeat;
Runnable mCheckLongPress = new Runnable() {
public void run() {
- Slog.d("KeyButtonView", "longpress");
if (isPressed()) {
mLongPressed = true;
mRepeat++;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
index 5616159..90c9568 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
@@ -73,12 +73,10 @@
private void setPlugged(boolean plugged) {
final Resources res = mContext.getResources();
- Slog.d(TAG, "plugged=" + plugged);
int height = -1;
if (plugged) {
final DisplayMetrics metrics = new DisplayMetrics();
mWindowManager.getDefaultDisplay().getMetrics(metrics);
- Slog.d(TAG, "metrics=" + metrics);
height = metrics.heightPixels - 720;
}
@@ -87,7 +85,8 @@
if (height < minHeight) {
height = minHeight;
}
- Slog.d(TAG, "using height=" + height + " old=" + mHeight);
+ Slog.i(TAG, "Resizing status bar plugged=" + plugged + " height="
+ + height + " old=" + mHeight);
mHeight = height;
final int N = mListeners.size();
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 d4ba693..add67b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
@@ -242,6 +242,7 @@
// Turn on the selected radio button at startup
private void updateRadioButtonsByImiAndSubtype(
InputMethodInfo imi, InputMethodSubtype subtype) {
+ if (imi == null) return;
if (DEBUG) {
Log.d(TAG, "Update radio buttons by " + imi.getId() + ", " + subtype);
}
@@ -253,7 +254,7 @@
return;
}
Pair<InputMethodInfo, InputMethodSubtype> imiAndSubtype =
- mRadioViewAndImiMap.get(radioView);
+ mRadioViewAndImiMap.get(radioView);
if (imiAndSubtype.first.getId().equals(imi.getId())
&& (imiAndSubtype.second == null || imiAndSubtype.second.equals(subtype))) {
subtypeRadioButton.setChecked(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
index a2f6e3a..45a22b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
@@ -269,7 +269,8 @@
// fully closed, no animation necessary
} else if (mVisible) {
if (DEBUG) {
- Slog.d(TAG, "panelHeight not zero but trying to open; scheduling an anim to open fully");
+ Slog.d(TAG, "panelHeight not zero but trying to open; scheduling an anim"
+ + " to open fully");
}
startAnimation(true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
index 07af466..9ca83e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
@@ -95,7 +95,6 @@
// Network
// ----------------------------
private void onClickNetwork() {
- Slog.d(TAG, "onClickNetwork");
getContext().startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
getStatusBarManager().collapse();
@@ -104,7 +103,6 @@
// Settings
// ----------------------------
private void onClickSettings() {
- Slog.d(TAG, "onClickSettings");
getContext().startActivity(new Intent(Settings.ACTION_SETTINGS)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
getStatusBarManager().collapse();
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 2ebd067..e864577 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
@@ -143,7 +143,6 @@
hideWindow();
return true;
} else if (action == MotionEvent.ACTION_DOWN) {
- Slog.d(TAG, "ACTION_DOWN");
final ClipData clip = mClipping;
if (clip != null) {
final Bitmap icon = clip.getIcon();
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 af730fe..825877a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -596,7 +596,7 @@
// TODO: immersive mode popups for tablet
} else if (notification.notification.fullScreenIntent != null) {
// not immersive & a full-screen alert should be shown
- Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive;"
+ Slog.w(TAG, "Notification has fullScreenIntent and activity is not immersive;"
+ " sending fullScreenIntent");
try {
notification.notification.fullScreenIntent.send();
@@ -635,16 +635,15 @@
// Can we just reapply the RemoteViews in place? If when didn't change, the order
// didn't change.
- boolean contentsUnchanged = notification.isOngoing() == oldNotification.isOngoing()
- && oldEntry.expanded != null
- && contentView != null
- && oldContentView != null
+ boolean contentsUnchanged = oldEntry.expanded != null
+ && contentView != null && oldContentView != null
&& contentView.getPackage() != null
&& oldContentView.getPackage() != null
&& oldContentView.getPackage().equals(contentView.getPackage())
&& oldContentView.getLayoutId() == contentView.getLayoutId();
ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
- boolean orderUnchanged = notification.notification.when==oldNotification.notification.when;
+ boolean orderUnchanged = notification.notification.when==oldNotification.notification.when
+ && notification.isOngoing() == oldNotification.isOngoing();
boolean isLastAnyway = rowParent.indexOfChild(oldEntry.row) == rowParent.getChildCount()-1;
if (contentsUnchanged && (orderUnchanged || isLastAnyway)) {
if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key);
@@ -668,6 +667,13 @@
handleNotificationError(key, notification, "Couldn't update icon: " + ic);
return;
}
+ // Update the large icon
+ if (notification.notification.largeIcon != null) {
+ oldEntry.largeIcon.setImageBitmap(notification.notification.largeIcon);
+ } else {
+ oldEntry.largeIcon.getLayoutParams().width = 0;
+ oldEntry.largeIcon.setVisibility(View.INVISIBLE);
+ }
if (key == mNotificationPeekKey) {
// must update the peek window
@@ -726,28 +732,28 @@
// act accordingly
if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
- Slog.d(TAG, "DISABLE_CLOCK: " + (show ? "no" : "yes"));
+ Slog.i(TAG, "DISABLE_CLOCK: " + (show ? "no" : "yes"));
showClock(show);
}
if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
boolean show = (state & StatusBarManager.DISABLE_SYSTEM_INFO) == 0;
- Slog.d(TAG, "DISABLE_SYSTEM_INFO: " + (show ? "no" : "yes"));
+ Slog.i(TAG, "DISABLE_SYSTEM_INFO: " + (show ? "no" : "yes"));
mNotificationTrigger.setVisibility(show ? View.VISIBLE : View.GONE);
}
if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
- Slog.d(TAG, "DISABLE_EXPAND: yes");
+ Slog.i(TAG, "DISABLE_EXPAND: yes");
animateCollapse();
}
}
if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
- Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+ Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
// synchronize with current shadow state
mNotificationIconArea.setVisibility(View.GONE);
mTicker.halt();
} else {
- Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+ Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: no");
// synchronize with current shadow state
mNotificationIconArea.setVisibility(View.VISIBLE);
}
@@ -758,11 +764,11 @@
}
if ((diff & StatusBarManager.DISABLE_NAVIGATION) != 0) {
if ((state & StatusBarManager.DISABLE_NAVIGATION) != 0) {
- Slog.d(TAG, "DISABLE_NAVIGATION: yes");
+ Slog.i(TAG, "DISABLE_NAVIGATION: yes");
mNavigationArea.setVisibility(View.GONE);
mInputMethodSwitchButton.setScreenLocked(true);
} else {
- Slog.d(TAG, "DISABLE_NAVIGATION: no");
+ Slog.i(TAG, "DISABLE_NAVIGATION: no");
mNavigationArea.setVisibility(View.VISIBLE);
mInputMethodSwitchButton.setScreenLocked(false);
}
@@ -1286,6 +1292,7 @@
entry.row = row;
entry.content = content;
entry.expanded = expanded;
+ entry.largeIcon = largeIcon;
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
index 4ee985d..98f718b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
@@ -65,7 +65,9 @@
}
}
}
- Slog.d(TabletStatusBar.TAG, "TabletStatusBarView not intercepting event");
+ if (TabletStatusBar.DEBUG) {
+ Slog.d(TabletStatusBar.TAG, "TabletStatusBarView not intercepting event");
+ }
return super.onInterceptTouchEvent(ev);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
index 7705dfc..440d680 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
@@ -111,7 +111,6 @@
public void remove(IBinder key, boolean advance) {
if (mCurrentKey == key) {
- Slog.d(TAG, "removed current");
// Showing now
if (advance) {
removeMessages(MSG_ADVANCE);
@@ -121,7 +120,6 @@
// In the queue
for (int i=0; i<QUEUE_LENGTH; i++) {
if (mKeys[i] == key) {
- Slog.d(TAG, "removed from queue: " + i);
for (; i<QUEUE_LENGTH-1; i++) {
mKeys[i] = mKeys[i+1];
mQueue[i] = mQueue[i+1];
@@ -208,7 +206,8 @@
final Resources res = mContext.getResources();
final FrameLayout view = new FrameLayout(mContext);
final int width = res.getDimensionPixelSize(R.dimen.notification_ticker_width);
- final int height = res.getDimensionPixelSize(R.dimen.notification_large_icon_height);
+ final int height = res.getDimensionPixelSize(
+ android.R.dimen.notification_large_icon_height);
int windowFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 79fbe0e..1b810d5 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -311,8 +311,8 @@
setFocusableInTouchMode(true);
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
- updateMonitor.registerInfoCallback(this);
- updateMonitor.registerSimStateCallback(this);
+ mUpdateMonitor.registerInfoCallback(this);
+ mUpdateMonitor.registerSimStateCallback(this);
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mSilentMode = isSilentMode();
@@ -414,6 +414,9 @@
public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
int batteryLevel) {
if (DBG) Log.d(TAG, "onRefreshBatteryInfo(" + showBatteryInfo + ", " + pluggedIn + ")");
+
+ mStatusView.onRefreshBatteryInfo(showBatteryInfo, pluggedIn, batteryLevel);
+
mShowingBatteryInfo = showBatteryInfo;
mPluggedIn = pluggedIn;
mBatteryLevel = batteryLevel;
diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
index 9db86aa..eb4d930 100644
--- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
@@ -109,22 +109,21 @@
mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
mKeyboardHelper = new PasswordEntryKeyboardHelper(context, mKeyboardView, this, false);
+ // TODO: re-enable on phones with keyboards
+ boolean isPhysicalKbShowing = false;
+ //mCreationHardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
if (mKeyboardViewAlpha == null || !mIsAlpha) {
mKeyboardHelper.setKeyboardMode(mIsAlpha ?
PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
: PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
- mKeyboardView.setVisibility(
- mCreationHardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO
- ? View.INVISIBLE : View.VISIBLE);
+ mKeyboardView.setVisibility(isPhysicalKbShowing ? View.INVISIBLE : View.VISIBLE);
} else {
mKeyboardHelperAlpha = new PasswordEntryKeyboardHelper(context, mKeyboardViewAlpha,
this, false);
mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
mKeyboardHelperAlpha.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA);
mKeyboardView.setVisibility(View.GONE);
- mKeyboardViewAlpha.setVisibility(
- mCreationHardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO
- ? View.INVISIBLE : View.VISIBLE);
+ mKeyboardViewAlpha.setVisibility(isPhysicalKbShowing ? View.INVISIBLE : View.VISIBLE);
mPasswordEntry.setWidth(mKeyboardViewAlpha.getLayoutParams().width);
}
@@ -136,9 +135,12 @@
// numeric keys.
if (mIsAlpha) {
mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
+ mStatusView.setHelpMessage(R.string.keyguard_password_enter_password_code,
+ StatusView.LOCK_ICON);
} else {
mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
- mStatusView.setInstructionText(R.string.keyguard_password_enter_pin_password_code);
+ mStatusView.setHelpMessage(R.string.keyguard_password_enter_pin_code,
+ StatusView.LOCK_ICON);
}
mKeyboardHelper.setVibratePattern(mLockPatternUtils.isTactileFeedbackEnabled() ?
@@ -152,6 +154,11 @@
mStatusView.setCarrierText(LockScreen.getCarrierString(
mUpdateMonitor.getTelephonyPlmn(),
mUpdateMonitor.getTelephonySpn()));
+
+ mUpdateMonitor.registerInfoCallback(this);
+ //mUpdateMonitor.registerSimStateCallback(this);
+
+ resetStatusInfo();
}
@Override
@@ -205,6 +212,7 @@
if (mLockPatternUtils.checkPassword(entry)) {
mCallback.keyguardDone(true);
mCallback.reportSuccessfulUnlockAttempt();
+ mStatusView.setInstructionText(null);
} else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) {
// to avoid accidental lockout, only count attempts that are long enough to be a
// real password. This may require some tweaking.
@@ -317,11 +325,8 @@
}
private void resetStatusInfo() {
- if(mIsAlpha) {
- mStatusView.setInstructionText(R.string.keyguard_password_enter_password_code);
- } else {
- mStatusView.setInstructionText(R.string.keyguard_password_enter_pin_password_code);
- }
+ mStatusView.setInstructionText(null);
+ mStatusView.updateStatusLines(true);
}
}
diff --git a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
index 5d1455e..6815d50 100644
--- a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
@@ -169,6 +169,9 @@
}
mStatusView = new StatusView(this, mUpdateMonitor, mLockPatternUtils);
+ // This shows up when no other information is required on status1
+ mStatusView.setHelpMessage(R.string.lockscreen_pattern_instructions,
+ StatusView.LOCK_ICON);
mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);
@@ -216,8 +219,8 @@
// assume normal footer mode for now
updateFooter(FooterMode.Normal);
- updateMonitor.registerInfoCallback(this);
- updateMonitor.registerSimStateCallback(this);
+ mUpdateMonitor.registerInfoCallback(this);
+ mUpdateMonitor.registerSimStateCallback(this);
setFocusableInTouchMode(true);
// until we get an update...
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index d6b7366..68c1453 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -197,7 +197,8 @@
/* Another feature is enabled and the user is trying to enable the custom title feature */
throw new AndroidRuntimeException("You cannot combine custom titles with other title features");
}
- if (((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) && (featureId != FEATURE_CUSTOM_TITLE)) {
+ if (((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) &&
+ (featureId != FEATURE_CUSTOM_TITLE) && (featureId != FEATURE_ACTION_MODE_OVERLAY)) {
/* Custom title feature is enabled and the user is trying to enable another feature */
throw new AndroidRuntimeException("You cannot combine custom titles with other title features");
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 2a39322..6b559cf 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -191,9 +191,6 @@
static final int APPLICATION_PANEL_SUBLAYER = 1;
static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
- // Debugging: set this to have the system act like there is no hard keyboard.
- static final boolean KEYBOARD_ALWAYS_HIDDEN = false;
-
static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
@@ -914,38 +911,44 @@
}
private int determineHiddenState(int mode, int hiddenValue, int visibleValue) {
- if (KEYBOARD_ALWAYS_HIDDEN) {
- return hiddenValue;
- }
- if (mLidOpen == LID_ABSENT) {
- return visibleValue;
- }
-
- switch (mode) {
- case 1:
- return mLidOpen == LID_OPEN ? visibleValue : hiddenValue;
- case 2:
- return mLidOpen == LID_OPEN ? hiddenValue : visibleValue;
+ if (mLidOpen != LID_ABSENT) {
+ switch (mode) {
+ case 1:
+ return mLidOpen == LID_OPEN ? visibleValue : hiddenValue;
+ case 2:
+ return mLidOpen == LID_OPEN ? hiddenValue : visibleValue;
+ }
}
return visibleValue;
}
-
+
/** {@inheritDoc} */
public void adjustConfigurationLw(Configuration config) {
readLidState();
+
mPowerManager.setKeyboardVisibility(mLidOpen == LID_OPEN);
- config.hardKeyboardHidden = determineHiddenState(
- mLidKeyboardAccessibility, Configuration.HARDKEYBOARDHIDDEN_YES,
- Configuration.HARDKEYBOARDHIDDEN_NO);
- config.navigationHidden = determineHiddenState(
- mLidNavigationAccessibility, Configuration.NAVIGATIONHIDDEN_YES,
- Configuration.NAVIGATIONHIDDEN_NO);
- config.keyboardHidden = (config.hardKeyboardHidden
- == Configuration.HARDKEYBOARDHIDDEN_NO || mHasSoftInput)
- ? Configuration.KEYBOARDHIDDEN_NO
- : Configuration.KEYBOARDHIDDEN_YES;
+
+ if (config.keyboard == Configuration.KEYBOARD_NOKEYS) {
+ config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES;
+ } else {
+ config.hardKeyboardHidden = determineHiddenState(mLidKeyboardAccessibility,
+ Configuration.HARDKEYBOARDHIDDEN_YES, Configuration.HARDKEYBOARDHIDDEN_NO);
+ }
+
+ if (config.navigation == Configuration.NAVIGATION_NONAV) {
+ config.navigationHidden = Configuration.NAVIGATIONHIDDEN_YES;
+ } else {
+ config.navigationHidden = determineHiddenState(mLidNavigationAccessibility,
+ Configuration.NAVIGATIONHIDDEN_YES, Configuration.NAVIGATIONHIDDEN_NO);
+ }
+
+ if (mHasSoftInput || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
+ config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
+ } else {
+ config.keyboardHidden = Configuration.KEYBOARDHIDDEN_YES;
+ }
}
-
+
/** {@inheritDoc} */
public int windowTypeToLayerLw(int type) {
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
diff --git a/policy/src/com/android/internal/policy/impl/StatusView.java b/policy/src/com/android/internal/policy/impl/StatusView.java
index 1caf0b7..4b91b65 100644
--- a/policy/src/com/android/internal/policy/impl/StatusView.java
+++ b/policy/src/com/android/internal/policy/impl/StatusView.java
@@ -19,10 +19,10 @@
import android.widget.TextView;
class StatusView {
- private static final int LOCK_ICON = R.drawable.ic_lock_idle_lock;
- private static final int ALARM_ICON = R.drawable.ic_lock_idle_alarm;
- private static final int CHARGING_ICON = R.drawable.ic_lock_idle_charging;
- private static final int BATTERY_LOW_ICON = R.drawable.ic_lock_idle_low_battery;
+ public static final int LOCK_ICON = R.drawable.ic_lock_idle_lock;
+ public static final int ALARM_ICON = R.drawable.ic_lock_idle_alarm;
+ public static final int CHARGING_ICON = R.drawable.ic_lock_idle_charging;
+ public static final int BATTERY_LOW_ICON = R.drawable.ic_lock_idle_low_battery;
private String mDateFormatString;
@@ -49,6 +49,8 @@
private TextView mAlarmStatus;
private LockPatternUtils mLockPatternUtils;
+ private int mHelpMessageId;
+ private int mHelpIconId;
private View findViewById(int id) {
return mView.findViewById(id);
@@ -123,13 +125,13 @@
void setInstructionText(int stringId) {
mStatus1.setText(stringId);
mStatus1.setCompoundDrawablesWithIntrinsicBounds(LOCK_ICON, 0, 0, 0);
- mStatus1.setVisibility(View.VISIBLE);
+ mStatus1.setVisibility(stringId != 0 ? View.VISIBLE : View.INVISIBLE);
}
void setInstructionText(String string) {
mStatus1.setText(string);
mStatus1.setCompoundDrawablesWithIntrinsicBounds(LOCK_ICON, 0, 0, 0);
- mStatus1.setVisibility(View.VISIBLE);
+ mStatus1.setVisibility(TextUtils.isEmpty(string) ? View.INVISIBLE : View.VISIBLE);
}
void setCarrierText(int stringId) {
@@ -148,8 +150,8 @@
*/
void updateStatusLines(boolean showStatusLines) {
if (!showStatusLines) {
- mStatus1.setVisibility(showStatusLines ? View.VISIBLE : View.GONE);
- mAlarmStatus.setVisibility(showStatusLines ? View.VISIBLE : View.GONE);
+ mStatus1.setVisibility(showStatusLines ? View.VISIBLE : View.INVISIBLE);
+ mAlarmStatus.setVisibility(showStatusLines ? View.VISIBLE : View.INVISIBLE);
return;
}
@@ -171,15 +173,14 @@
mAlarmStatus.setText(nextAlarm);
mAlarmStatus.setVisibility(View.VISIBLE);
} else {
- mAlarmStatus.setVisibility(View.GONE);
+ mAlarmStatus.setVisibility(View.INVISIBLE);
}
// Update Status1
- if (mInstructions != null) {
+ if (!TextUtils.isEmpty(mInstructions)) {
// Instructions only
- final int resId = TextUtils.isEmpty(mInstructions) ? 0 : LOCK_ICON;
mStatus1.setText(mInstructions);
- mStatus1.setCompoundDrawablesWithIntrinsicBounds(resId, 0, 0, 0);
+ mStatus1.setCompoundDrawablesWithIntrinsicBounds(LOCK_ICON, 0, 0, 0);
mStatus1.setVisibility(View.VISIBLE);
} else if (mShowingBatteryInfo) {
// Battery status
@@ -199,13 +200,22 @@
}
mStatus1.setVisibility(View.VISIBLE);
} else {
- // nothing specific to show; show general instructions
- mStatus1.setText(R.string.lockscreen_pattern_instructions);
- mStatus1.setCompoundDrawablesWithIntrinsicBounds(LOCK_ICON, 0,0, 0);
- mStatus1.setVisibility(View.VISIBLE);
+ // nothing specific to show; show help message and icon, if provided
+ if (mHelpMessageId != 0) {
+ mStatus1.setText(mHelpMessageId);
+ mStatus1.setCompoundDrawablesWithIntrinsicBounds(mHelpIconId, 0,0, 0);
+ mStatus1.setVisibility(View.VISIBLE);
+ } else {
+ mStatus1.setVisibility(View.INVISIBLE);
+ }
}
}
+ void setHelpMessage(int messageId, int iconId) {
+ mHelpMessageId = messageId;
+ mHelpIconId = iconId;
+ }
+
void refreshTimeAndDateDisplay() {
if (mHasDate) {
mDate.setText(DateFormat.format(mDateFormatString, new Date()));
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index b5a4bd2..e314145 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -154,6 +154,24 @@
return true;
}
+static void dumpRegion(String8& dump, const SkRegion& region) {
+ if (region.isEmpty()) {
+ dump.append("<empty>");
+ return;
+ }
+
+ bool first = true;
+ for (SkRegion::Iterator it(region); !it.done(); it.next()) {
+ if (first) {
+ first = false;
+ } else {
+ dump.append("|");
+ }
+ const SkIRect& rect = it.rect();
+ dump.appendFormat("[%d,%d][%d,%d]", rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
+ }
+}
+
// --- InputDispatcher ---
@@ -495,7 +513,7 @@
if (!(flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
| InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
- if (isTouchModal || window->touchableAreaContainsPoint(x, y)) {
+ if (isTouchModal || window->touchableRegionContainsPoint(x, y)) {
// Found window.
return window;
}
@@ -1188,7 +1206,7 @@
if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
| InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
- if (isTouchModal || window->touchableAreaContainsPoint(x, y)) {
+ if (isTouchModal || window->touchableRegionContainsPoint(x, y)) {
if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) {
newTouchedWindow = window;
}
@@ -2884,9 +2902,7 @@
dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, "
"visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
"frame=[%d,%d][%d,%d], "
- "visibleFrame=[%d,%d][%d,%d], "
- "touchableArea=[%d,%d][%d,%d], "
- "ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
+ "touchableRegion=",
i, window.name.string(),
toString(window.paused),
toString(window.hasFocus),
@@ -2896,11 +2912,9 @@
window.layoutParamsFlags, window.layoutParamsType,
window.layer,
window.frameLeft, window.frameTop,
- window.frameRight, window.frameBottom,
- window.visibleFrameLeft, window.visibleFrameTop,
- window.visibleFrameRight, window.visibleFrameBottom,
- window.touchableAreaLeft, window.touchableAreaTop,
- window.touchableAreaRight, window.touchableAreaBottom,
+ window.frameRight, window.frameBottom);
+ dumpRegion(dump, window.touchableRegion);
+ dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
window.ownerPid, window.ownerUid,
window.dispatchingTimeout / 1000000.0);
}
diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp
index 9ce45f5..b552f6d 100644
--- a/services/input/InputWindow.cpp
+++ b/services/input/InputWindow.cpp
@@ -24,9 +24,8 @@
// --- InputWindow ---
-bool InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const {
- return x >= touchableAreaLeft && x <= touchableAreaRight
- && y >= touchableAreaTop && y <= touchableAreaBottom;
+bool InputWindow::touchableRegionContainsPoint(int32_t x, int32_t y) const {
+ return touchableRegion.contains(x, y);
}
bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const {
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index b3d5a65..9c43067 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -23,6 +23,8 @@
#include <utils/Timers.h>
#include <utils/String8.h>
+#include <SkRegion.h>
+
#include "InputApplication.h"
namespace android {
@@ -129,14 +131,7 @@
int32_t frameTop;
int32_t frameRight;
int32_t frameBottom;
- int32_t visibleFrameLeft;
- int32_t visibleFrameTop;
- int32_t visibleFrameRight;
- int32_t visibleFrameBottom;
- int32_t touchableAreaLeft;
- int32_t touchableAreaTop;
- int32_t touchableAreaRight;
- int32_t touchableAreaBottom;
+ SkRegion touchableRegion;
bool visible;
bool canReceiveKeys;
bool hasFocus;
@@ -146,7 +141,7 @@
int32_t ownerPid;
int32_t ownerUid;
- bool touchableAreaContainsPoint(int32_t x, int32_t y) const;
+ bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
bool frameContainsPoint(int32_t x, int32_t y) const;
/* Returns true if the window is of a trusted type that is allowed to silently
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/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 2b98795..7b4f246 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -2540,16 +2540,16 @@
ArrayList<String>>> enabledImes, String imeId, String subtypeHashCode) {
for (Pair<String, ArrayList<String>> enabledIme: enabledImes) {
if (enabledIme.first.equals(imeId)) {
- final ArrayList<String> enabledSubtypes = enabledIme.second;
- if (enabledSubtypes.size() == 0) {
- // If there are no enabled subtypes, applicable subtypes are enabled
- // implicitly.
+ final ArrayList<String> explicitlyEnabledSubtypes = enabledIme.second;
+ if (explicitlyEnabledSubtypes.size() == 0) {
+ // If there are no explicitly enabled subtypes, applicable subtypes are
+ // enabled implicitly.
InputMethodInfo ime = mMethodMap.get(imeId);
// If IME is enabled and no subtypes are enabled, applicable subtypes
// are enabled implicitly, so needs to treat them to be enabled.
if (ime != null && ime.getSubtypes().size() > 0) {
List<InputMethodSubtype> implicitlySelectedSubtypes =
- getApplicableSubtypesLocked(mRes, ime.getSubtypes());
+ getApplicableSubtypesLocked(mRes, ime.getSubtypes());
if (implicitlySelectedSubtypes != null) {
final int N = implicitlySelectedSubtypes.size();
for (int i = 0; i < N; ++i) {
@@ -2561,7 +2561,7 @@
}
}
} else {
- for (String s: enabledSubtypes) {
+ for (String s: explicitlyEnabledSubtypes) {
if (s.equals(subtypeHashCode)) {
// If both imeId and subtypeId are enabled, return subtypeId.
return s;
diff --git a/services/java/com/android/server/InputWindow.java b/services/java/com/android/server/InputWindow.java
index 1515290..2c2cdfe 100644
--- a/services/java/com/android/server/InputWindow.java
+++ b/services/java/com/android/server/InputWindow.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.graphics.Region;
import android.view.InputChannel;
/**
@@ -39,23 +40,14 @@
// Dispatching timeout.
public long dispatchingTimeoutNanos;
- // Window frame area.
+ // Window frame.
public int frameLeft;
public int frameTop;
public int frameRight;
public int frameBottom;
- // Window visible frame area.
- public int visibleFrameLeft;
- public int visibleFrameTop;
- public int visibleFrameRight;
- public int visibleFrameBottom;
-
- // Window touchable area.
- public int touchableAreaLeft;
- public int touchableAreaTop;
- public int touchableAreaRight;
- public int touchableAreaBottom;
+ // Window touchable region.
+ public final Region touchableRegion = new Region();
// Window is visible.
public boolean visible;
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 1efc645..1eebd6a 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -1050,7 +1050,7 @@
void cleanupInstallFailedPackage(PackageSetting ps) {
Slog.i(TAG, "Cleaning up incompletely installed app: " + ps.name);
if (mInstaller != null) {
- boolean useSecureFS = useEncryptedFilesystemForPackage(ps.pkg);
+ boolean useSecureFS = false;
int retCode = mInstaller.remove(ps.name, useSecureFS);
if (retCode < 0) {
Slog.w(TAG, "Couldn't remove app data directory for package: "
@@ -2780,11 +2780,6 @@
return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
}
- private static boolean useEncryptedFilesystemForPackage(PackageParser.Package pkg) {
- return Environment.isEncryptedFilesystemEnabled() &&
- ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_NEVER_ENCRYPT) == 0);
- }
-
private boolean verifyPackageUpdate(PackageSetting oldPkg, PackageParser.Package newPkg) {
if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
Slog.w(TAG, "Unable to update from " + oldPkg.name
@@ -2801,7 +2796,7 @@
}
private File getDataPathForPackage(PackageParser.Package pkg) {
- boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(pkg);
+ boolean useEncryptedFSDir = false;
File dataPath;
if (useEncryptedFSDir) {
dataPath = new File(mSecureAppDataDir, pkg.packageName);
@@ -3157,7 +3152,7 @@
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
// This is a normal package, need to make its data directory.
- boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(pkg);
+ boolean useEncryptedFSDir = false;
dataPath = getDataPathForPackage(pkg);
boolean uidError = false;
@@ -4395,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();
@@ -4646,64 +4639,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() {
@@ -4811,6 +4746,79 @@
abstract void handleReturnCode();
}
+ class MeasureParams extends HandlerParams {
+ private final PackageStats mStats;
+ private boolean mSuccess;
+
+ private final IPackageStatsObserver mObserver;
+
+ public MeasureParams(PackageStats stats, boolean success,
+ IPackageStatsObserver observer) {
+ mObserver = observer;
+ mStats = stats;
+ mSuccess = success;
+ }
+
+ @Override
+ void handleStartCopy() throws RemoteException {
+ final boolean mounted;
+
+ if (Environment.isExternalStorageEmulated()) {
+ mounted = true;
+ } else {
+ final String status = Environment.getExternalStorageState();
+
+ mounted = status.equals(Environment.MEDIA_MOUNTED)
+ || status.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
+ }
+
+ if (mounted) {
+ final File externalCacheDir = Environment
+ .getExternalStorageAppCacheDirectory(mStats.packageName);
+ final long externalCacheSize = mContainerService
+ .calculateDirectorySize(externalCacheDir.getPath());
+ mStats.externalCacheSize = externalCacheSize;
+
+ final File externalDataDir = Environment
+ .getExternalStorageAppDataDirectory(mStats.packageName);
+ long externalDataSize = mContainerService.calculateDirectorySize(externalDataDir
+ .getPath());
+
+ if (externalCacheDir.getParentFile().equals(externalDataDir)) {
+ externalDataSize -= externalCacheSize;
+ }
+ mStats.externalDataSize = externalDataSize;
+
+ final File externalMediaDir = Environment
+ .getExternalStorageAppMediaDirectory(mStats.packageName);
+ mStats.externalMediaSize = mContainerService
+ .calculateDirectorySize(externalCacheDir.getPath());
+
+ final File externalObbDir = Environment
+ .getExternalStorageAppObbDirectory(mStats.packageName);
+ mStats.externalObbSize = mContainerService.calculateDirectorySize(externalObbDir
+ .getPath());
+ }
+ }
+
+ @Override
+ void handleReturnCode() {
+ if (mObserver != null) {
+ try {
+ mObserver.onGetStatsCompleted(mStats, mSuccess);
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Observer no longer exists.");
+ }
+ }
+ }
+
+ @Override
+ void handleServiceError() {
+ Slog.e(TAG, "Could not measure application " + mStats.packageName
+ + " external storage");
+ }
+ }
+
class InstallParams extends HandlerParams {
final IPackageInstallObserver observer;
int flags;
@@ -6296,7 +6304,7 @@
deletedPs = mSettings.mPackages.get(packageName);
}
if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
- boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(p);
+ boolean useEncryptedFSDir = false;
if (mInstaller != null) {
int retCode = mInstaller.remove(packageName, useEncryptedFSDir);
if (retCode < 0) {
@@ -6540,7 +6548,7 @@
}
boolean useEncryptedFSDir = false;
- if(!dataOnly) {
+ if (!dataOnly) {
//need to check this only for fully installed applications
if (p == null) {
Slog.w(TAG, "Package named '" + packageName +"' doesn't exist.");
@@ -6551,7 +6559,6 @@
Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
return false;
}
- useEncryptedFSDir = useEncryptedFilesystemForPackage(p);
}
if (mInstaller != null) {
int retCode = mInstaller.clearUserData(packageName, useEncryptedFSDir);
@@ -6605,7 +6612,7 @@
Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
return false;
}
- boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(p);
+ boolean useEncryptedFSDir = false;
if (mInstaller != null) {
int retCode = mInstaller.deleteCacheFiles(packageName, useEncryptedFSDir);
if (retCode < 0) {
@@ -6625,18 +6632,16 @@
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
- PackageStats lStats = new PackageStats(packageName);
- final boolean succeded;
+ PackageStats stats = new PackageStats(packageName);
+
+ final boolean success;
synchronized (mInstallLock) {
- succeded = getPackageSizeInfoLI(packageName, lStats);
+ success = getPackageSizeInfoLI(packageName, stats);
}
- if(observer != null) {
- try {
- observer.onGetStatsCompleted(lStats, succeded);
- } catch (RemoteException e) {
- Log.i(TAG, "Observer no longer exists.");
- }
- } //end if observer
+
+ Message msg = mHandler.obtainMessage(INIT_COPY);
+ msg.obj = new MeasureParams(stats, success, observer);
+ mHandler.sendMessage(msg);
} //end run
});
}
@@ -6669,7 +6674,7 @@
}
publicSrcDir = isForwardLocked(p) ? applicationInfo.publicSourceDir : null;
}
- boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(p);
+ boolean useEncryptedFSDir = false;
if (mInstaller != null) {
int res = mInstaller.getSizeInfo(packageName, p.mPath,
publicSrcDir, pStats, useEncryptedFSDir);
@@ -7273,7 +7278,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);
@@ -7842,8 +7846,7 @@
this.pkgFlags = pkgFlags & (
ApplicationInfo.FLAG_SYSTEM |
ApplicationInfo.FLAG_FORWARD_LOCK |
- ApplicationInfo.FLAG_EXTERNAL_STORAGE |
- ApplicationInfo.FLAG_NEVER_ENCRYPT);
+ ApplicationInfo.FLAG_EXTERNAL_STORAGE);
}
}
@@ -7858,7 +7861,6 @@
File resourcePath;
String resourcePathString;
String nativeLibraryPathString;
- String[] obbPathStrings;
long timeStamp;
long firstInstallTime;
long lastUpdateTime;
@@ -7904,11 +7906,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;
@@ -8967,16 +8964,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");
@@ -9569,8 +9556,6 @@
readGrantedPermissionsLP(parser,
packageSetting.grantedPermissions);
packageSetting.permissionsFixed = true;
- } else if (tagName.equals("obbs")) {
- readObbPathsLP(packageSetting, parser);
} else {
reportSettingsProblem(Log.WARN,
"Unknown element under <package>: "
@@ -9775,34 +9760,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/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6f4b4c5..978946f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -204,11 +204,9 @@
// TODO: Use a more reliable check to see if this product should
// support Bluetooth - see bug 988521
if (SystemProperties.get("ro.kernel.qemu").equals("1")) {
- Slog.i(TAG, "Registering null Bluetooth Service (emulator)");
- ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, null);
+ Slog.i(TAG, "No Bluetooh Service (emulator)");
} else if (factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
- Slog.i(TAG, "Registering null Bluetooth Service (factory test)");
- ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, null);
+ Slog.i(TAG, "No Bluetooth Service (factory test)");
} else {
Slog.i(TAG, "Bluetooth Service");
bluetooth = new BluetoothService(context);
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 1b590ba..cf07239 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -37,6 +37,7 @@
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WpsConfiguration;
+import android.net.wifi.WpsResult;
import android.net.ConnectivityManager;
import android.net.InterfaceConfiguration;
import android.net.DhcpInfo;
@@ -841,13 +842,13 @@
mWifiStateMachine.forgetNetwork(netId);
}
- public String startWps(WpsConfiguration config) {
+ public WpsResult startWps(WpsConfiguration config) {
enforceChangePermission();
if (mChannel != null) {
return mWifiStateMachine.startWps(mChannel, config);
} else {
Slog.e(TAG, "mChannel is not initialized");
- return "";
+ return new WpsResult(WpsResult.Status.FAILURE);
}
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index bdc779c..1b3725c 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -520,7 +520,7 @@
int mRotation;
int mAnimFlags;
- private final Rect tmpRect = new Rect();
+ private final Region mTmpRegion = new Region();
DragState(IBinder token, Surface surface, int flags, IBinder localWin) {
mToken = token;
@@ -816,31 +816,13 @@
// not touchable == don't tell about drags
continue;
}
- // account for the window's decor etc
- tmpRect.set(child.mFrame);
- if (child.mTouchableInsets == ViewTreeObserver
- .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
- // The point is inside of the window if it is
- // inside the frame, AND the content part of that
- // frame that was given by the application.
- tmpRect.left += child.mGivenContentInsets.left;
- tmpRect.top += child.mGivenContentInsets.top;
- tmpRect.right -= child.mGivenContentInsets.right;
- tmpRect.bottom -= child.mGivenContentInsets.bottom;
- } else if (child.mTouchableInsets == ViewTreeObserver
- .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
- // The point is inside of the window if it is
- // inside the frame, AND the visible part of that
- // frame that was given by the application.
- tmpRect.left += child.mGivenVisibleInsets.left;
- tmpRect.top += child.mGivenVisibleInsets.top;
- tmpRect.right -= child.mGivenVisibleInsets.right;
- tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
- }
+
+ child.getTouchableRegion(mTmpRegion);
+
final int touchFlags = flags &
- (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
- if (tmpRect.contains(x, y) || touchFlags == 0) {
+ (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
+ if (mTmpRegion.contains(x, y) || touchFlags == 0) {
// Found it
touchedWin = child;
break;
@@ -2667,7 +2649,7 @@
void setInsetsWindow(Session session, IWindow client,
int touchableInsets, Rect contentInsets,
- Rect visibleInsets) {
+ Rect visibleInsets, Region touchableRegion) {
long origId = Binder.clearCallingIdentity();
try {
synchronized (mWindowMap) {
@@ -2676,6 +2658,7 @@
w.mGivenInsetsPending = false;
w.mGivenContentInsets.set(contentInsets);
w.mGivenVisibleInsets.set(visibleInsets);
+ w.mGivenTouchableRegion.set(touchableRegion);
w.mTouchableInsets = touchableInsets;
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
@@ -5882,7 +5865,7 @@
final InputWindow inputWindow = windowList.add();
inputWindow.inputChannel = mDragState.mServerChannel;
inputWindow.name = "drag";
- inputWindow.layoutParamsFlags = 0;
+ inputWindow.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
inputWindow.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
inputWindow.dispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
inputWindow.visible = true;
@@ -5900,15 +5883,8 @@
inputWindow.frameRight = mDisplay.getWidth();
inputWindow.frameBottom = mDisplay.getHeight();
- inputWindow.visibleFrameLeft = inputWindow.frameLeft;
- inputWindow.visibleFrameTop = inputWindow.frameTop;
- inputWindow.visibleFrameRight = inputWindow.frameRight;
- inputWindow.visibleFrameBottom = inputWindow.frameBottom;
-
- inputWindow.touchableAreaLeft = inputWindow.frameLeft;
- inputWindow.touchableAreaTop = inputWindow.frameTop;
- inputWindow.touchableAreaRight = inputWindow.frameRight;
- inputWindow.touchableAreaBottom = inputWindow.frameBottom;
+ // The drag window cannot receive new touches.
+ inputWindow.touchableRegion.setEmpty();
}
/* Updates the cached window information provided to the input dispatcher. */
@@ -5973,40 +5949,8 @@
inputWindow.frameTop = frame.top;
inputWindow.frameRight = frame.right;
inputWindow.frameBottom = frame.bottom;
-
- final Rect visibleFrame = child.mVisibleFrame;
- inputWindow.visibleFrameLeft = visibleFrame.left;
- inputWindow.visibleFrameTop = visibleFrame.top;
- inputWindow.visibleFrameRight = visibleFrame.right;
- inputWindow.visibleFrameBottom = visibleFrame.bottom;
-
- switch (child.mTouchableInsets) {
- default:
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
- inputWindow.touchableAreaLeft = frame.left;
- inputWindow.touchableAreaTop = frame.top;
- inputWindow.touchableAreaRight = frame.right;
- inputWindow.touchableAreaBottom = frame.bottom;
- break;
-
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: {
- Rect inset = child.mGivenContentInsets;
- inputWindow.touchableAreaLeft = frame.left + inset.left;
- inputWindow.touchableAreaTop = frame.top + inset.top;
- inputWindow.touchableAreaRight = frame.right - inset.right;
- inputWindow.touchableAreaBottom = frame.bottom - inset.bottom;
- break;
- }
-
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: {
- Rect inset = child.mGivenVisibleInsets;
- inputWindow.touchableAreaLeft = frame.left + inset.left;
- inputWindow.touchableAreaTop = frame.top + inset.top;
- inputWindow.touchableAreaRight = frame.right - inset.right;
- inputWindow.touchableAreaBottom = frame.bottom - inset.bottom;
- break;
- }
- }
+
+ child.getTouchableRegion(inputWindow.touchableRegion);
}
// Send windows to native code.
@@ -6516,9 +6460,9 @@
}
public void setInsets(IWindow window, int touchableInsets,
- Rect contentInsets, Rect visibleInsets) {
+ Rect contentInsets, Rect visibleInsets, Region touchableArea) {
setInsetsWindow(this, window, touchableInsets, contentInsets,
- visibleInsets);
+ visibleInsets, touchableArea);
}
public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
@@ -6648,7 +6592,7 @@
synchronized (mWindowMap) {
long ident = Binder.clearCallingIdentity();
try {
- if (mDragState.mToken != token) {
+ if (mDragState == null || mDragState.mToken != token) {
Slog.w(TAG, "Invalid drop-result claim by " + window);
throw new IllegalStateException("reportDropResult() by non-recipient");
}
@@ -6857,6 +6801,11 @@
final Rect mGivenVisibleInsets = new Rect();
/**
+ * This is the given touchable area relative to the window frame, or null if none.
+ */
+ final Region mGivenTouchableRegion = new Region();
+
+ /**
* Flag indicating whether the touchable region should be adjusted by
* the visible insets; if false the area outside the visible insets is
* NOT touchable, so we must use those to adjust the frame during hit
@@ -8139,6 +8088,36 @@
return true;
}
+ public void getTouchableRegion(Region outRegion) {
+ final Rect frame = mFrame;
+ switch (mTouchableInsets) {
+ default:
+ case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
+ outRegion.set(frame);
+ break;
+ case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: {
+ final Rect inset = mGivenContentInsets;
+ outRegion.set(
+ frame.left + inset.left, frame.top + inset.top,
+ frame.right - inset.right, frame.bottom - inset.bottom);
+ break;
+ }
+ case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: {
+ final Rect inset = mGivenVisibleInsets;
+ outRegion.set(
+ frame.left + inset.left, frame.top + inset.top,
+ frame.right - inset.right, frame.bottom - inset.bottom);
+ break;
+ }
+ case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION: {
+ final Region givenTouchableRegion = mGivenTouchableRegion;
+ outRegion.set(givenTouchableRegion);
+ outRegion.translate(frame.left, frame.top);
+ break;
+ }
+ }
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mSession="); pw.print(mSession);
pw.print(" mClient="); pw.println(mClient.asBinder());
diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp
index a4609a0..75154567c 100644
--- a/services/jni/com_android_server_InputWindow.cpp
+++ b/services/jni/com_android_server_InputWindow.cpp
@@ -21,6 +21,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_view_InputChannel.h>
+#include <android/graphics/Region.h>
#include "com_android_server_InputWindow.h"
#include "com_android_server_InputWindowHandle.h"
@@ -39,14 +40,7 @@
jfieldID frameTop;
jfieldID frameRight;
jfieldID frameBottom;
- jfieldID visibleFrameLeft;
- jfieldID visibleFrameTop;
- jfieldID visibleFrameRight;
- jfieldID visibleFrameBottom;
- jfieldID touchableAreaLeft;
- jfieldID touchableAreaTop;
- jfieldID touchableAreaRight;
- jfieldID touchableAreaBottom;
+ jfieldID touchableRegion;
jfieldID visible;
jfieldID canReceiveKeys;
jfieldID hasFocus;
@@ -108,22 +102,17 @@
gInputWindowClassInfo.frameRight);
outInputWindow->frameBottom = env->GetIntField(inputWindowObj,
gInputWindowClassInfo.frameBottom);
- outInputWindow->visibleFrameLeft = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.visibleFrameLeft);
- outInputWindow->visibleFrameTop = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.visibleFrameTop);
- outInputWindow->visibleFrameRight = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.visibleFrameRight);
- outInputWindow->visibleFrameBottom = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.visibleFrameBottom);
- outInputWindow->touchableAreaLeft = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.touchableAreaLeft);
- outInputWindow->touchableAreaTop = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.touchableAreaTop);
- outInputWindow->touchableAreaRight = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.touchableAreaRight);
- outInputWindow->touchableAreaBottom = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.touchableAreaBottom);
+
+ jobject regionObj = env->GetObjectField(inputWindowObj,
+ gInputWindowClassInfo.touchableRegion);
+ if (regionObj) {
+ SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
+ outInputWindow->touchableRegion.set(*region);
+ env->DeleteLocalRef(regionObj);
+ } else {
+ outInputWindow->touchableRegion.setEmpty();
+ }
+
outInputWindow->visible = env->GetBooleanField(inputWindowObj,
gInputWindowClassInfo.visible);
outInputWindow->canReceiveKeys = env->GetBooleanField(inputWindowObj,
@@ -187,29 +176,8 @@
GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz,
"frameBottom", "I");
- GET_FIELD_ID(gInputWindowClassInfo.visibleFrameLeft, gInputWindowClassInfo.clazz,
- "visibleFrameLeft", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.visibleFrameTop, gInputWindowClassInfo.clazz,
- "visibleFrameTop", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.visibleFrameRight, gInputWindowClassInfo.clazz,
- "visibleFrameRight", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.visibleFrameBottom, gInputWindowClassInfo.clazz,
- "visibleFrameBottom", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.touchableAreaLeft, gInputWindowClassInfo.clazz,
- "touchableAreaLeft", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.touchableAreaTop, gInputWindowClassInfo.clazz,
- "touchableAreaTop", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.touchableAreaRight, gInputWindowClassInfo.clazz,
- "touchableAreaRight", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.touchableAreaBottom, gInputWindowClassInfo.clazz,
- "touchableAreaBottom", "I");
+ GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, gInputWindowClassInfo.clazz,
+ "touchableRegion", "Landroid/graphics/Region;");
GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz,
"visible", "Z");
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 154b822..65ad956 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2132,6 +2132,9 @@
sh = (!sh) ? hw_h : sh;
const size_t size = sw * sh * 4;
+ LOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d",
+ sw, sh, minLayerZ, maxLayerZ);
+
// make sure to clear all GL error flags
while ( glGetError() != GL_NO_ERROR ) ;
@@ -2146,6 +2149,9 @@
GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);
GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
+
+ LOGD("screenshot: FBO created, status=0x%x", status);
+
if (status == GL_FRAMEBUFFER_COMPLETE_OES) {
// invert everything, b/c glReadPixel() below will invert the FB
@@ -2161,6 +2167,8 @@
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
+ LOGD("screenshot: glClear() issued");
+
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; ++i) {
@@ -2171,6 +2179,8 @@
}
}
+ LOGD("screenshot: All layers rendered");
+
// XXX: this is needed on tegra
glScissor(0, 0, sw, sh);
@@ -2185,6 +2195,10 @@
new MemoryHeapBase(size, 0, "screen-capture") );
void* const ptr = base->getBase();
if (ptr) {
+
+ LOGD("screenshot: about to call glReadPixels(0,0,%d,%d,...,%p)",
+ sw, sh, ptr);
+
// capture the screen with glReadPixels()
glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
if (glGetError() == GL_NO_ERROR) {
@@ -2197,25 +2211,32 @@
} else {
result = NO_MEMORY;
}
+
+ LOGD("screenshot: glReadPixels() returned %s", strerror(result));
+
}
glEnable(GL_SCISSOR_TEST);
glViewport(0, 0, hw_w, hw_h);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
-
-
} else {
result = BAD_VALUE;
}
+ LOGD("screenshot: about to release FBO resources");
+
// release FBO resources
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
glDeleteRenderbuffersOES(1, &tname);
glDeleteFramebuffersOES(1, &name);
+ LOGD("screenshot: about to call compositionComplete()");
+
hw.compositionComplete();
+ LOGD("screenshot: result = %s", strerror(result));
+
return result;
}
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 3b52252..0b4fc51 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -164,6 +164,11 @@
}
@Override
+ public File getObbDir() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public File getCacheDir() {
throw new UnsupportedOperationException();
}
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 2e4199e..c021c95 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -499,14 +499,4 @@
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/StatusBar/res/drawable-mdpi/pineapple2.png b/tests/StatusBar/res/drawable-mdpi/pineapple2.png
new file mode 100644
index 0000000..ddc1038
--- /dev/null
+++ b/tests/StatusBar/res/drawable-mdpi/pineapple2.png
Binary files differ
diff --git a/tests/StatusBar/res/layout/notification_builder_test.xml b/tests/StatusBar/res/layout/notification_builder_test.xml
index 1b27e97..3c37a73 100644
--- a/tests/StatusBar/res/layout/notification_builder_test.xml
+++ b/tests/StatusBar/res/layout/notification_builder_test.xml
@@ -238,7 +238,7 @@
/>
<RadioButton
android:id="@+id/when_midnight"
- style="@style/FieldContents.Disabled"
+ style="@style/FieldContents"
android:text="midnight"
/>
<RadioButton
@@ -604,6 +604,11 @@
style="@style/FieldContents"
android:text="pineapple"
/>
+ <RadioButton
+ android:id="@+id/large_icon_pineapple2"
+ style="@style/FieldContents"
+ android:text="pineapple2"
+ />
</RadioGroup>
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
index e9a3513c..5a2ebac 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
@@ -16,6 +16,8 @@
package com.android.statusbartest;
+import java.util.GregorianCalendar;
+
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
@@ -190,8 +192,14 @@
// when
switch (getRadioChecked(R.id.group_when)) {
- case R.id.when_midnight:
+ case R.id.when_midnight: {
+ GregorianCalendar c = new GregorianCalendar();
+ c.set(GregorianCalendar.HOUR_OF_DAY, 0);
+ c.set(GregorianCalendar.MINUTE, 0);
+ c.set(GregorianCalendar.SECOND, 0);
+ b.setWhen(c.getTimeInMillis());
break;
+ }
case R.id.when_now:
b.setWhen(System.currentTimeMillis());
break;
@@ -276,6 +284,9 @@
case R.id.large_icon_pineapple:
b.setLargeIcon(loadBitmap(R.drawable.pineapple));
break;
+ case R.id.large_icon_pineapple2:
+ b.setLargeIcon(loadBitmap(R.drawable.pineapple2));
+ break;
}
// sound TODO
diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk
index 9b7bc5f..a0a7307 100644
--- a/tools/layoutlib/bridge/Android.mk
+++ b/tools/layoutlib/bridge/Android.mk
@@ -20,10 +20,11 @@
LOCAL_JAVA_LIBRARIES := \
kxml2-2.3.0 \
- layoutlib_api-prebuilt \
- ninepatch-prebuilt
+ layoutlib_api-prebuilt
-LOCAL_STATIC_JAVA_LIBRARIES := temp_layoutlib
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ temp_layoutlib \
+ ninepatch-prebuilt
LOCAL_MODULE := layoutlib
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
new file mode 100644
index 0000000..4c500e7
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/ide/common/resources/ResourceResolver.java
@@ -0,0 +1,560 @@
+/*
+ * 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:]<name></li>
+ * <li>[android:]style/<name></li>
+ * <li>@[android:]style/<name></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/BridgeConstants.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
index 194687e..112af1e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
@@ -41,25 +41,6 @@
public final static String R = "com.android.internal.R";
- public final static String PREFIX_ANDROID_RESOURCE_REF = "@android:";
- public final static String PREFIX_RESOURCE_REF = "@";
- public final static String PREFIX_ANDROID_THEME_REF = "?android:";
- public final static String PREFIX_THEME_REF = "?";
-
- public final static String PREFIX_ANDROID = "android:";
-
- 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_STYLE = RES_STYLE + "/";
- public final static String REFERENCE_NULL = "@null";
public final static String MATCH_PARENT = "match_parent";
public final static String FILL_PARENT = "fill_parent";
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 82e217a..f633201 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
@@ -20,6 +20,7 @@
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 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;
@@ -76,12 +77,9 @@
private Resources mResources;
private Theme mTheme;
private final HashMap<View, Object> mViewKeyMap = new HashMap<View, Object>();
- private final StyleResourceValue mThemeValues;
private final Object mProjectKey;
private final DisplayMetrics mMetrics;
- private final Map<String, Map<String, ResourceValue>> mProjectResources;
- private final Map<String, Map<String, ResourceValue>> mFrameworkResources;
- private final Map<StyleResourceValue, StyleResourceValue> mStyleInheritanceMap;
+ private final ResourceResolver mResourceResolver;
private final Map<Object, Map<String, String>> mDefaultPropMaps =
new IdentityHashMap<Object, Map<String,String>>();
@@ -116,19 +114,13 @@
* @param projectCallback
*/
public BridgeContext(Object projectKey, DisplayMetrics metrics,
- StyleResourceValue currentTheme,
- Map<String, Map<String, ResourceValue>> projectResources,
- Map<String, Map<String, ResourceValue>> frameworkResources,
- Map<StyleResourceValue, StyleResourceValue> styleInheritanceMap,
+ ResourceResolver resourceResolver,
IProjectCallback projectCallback) {
mProjectKey = projectKey;
mMetrics = metrics;
mProjectCallback = projectCallback;
- mThemeValues = currentTheme;
- mProjectResources = projectResources;
- mFrameworkResources = frameworkResources;
- mStyleInheritanceMap = styleInheritanceMap;
+ mResourceResolver = resourceResolver;
mFragments.mCurState = Fragment.CREATED;
mFragments.mActivity = this;
@@ -180,6 +172,10 @@
return mProjectCallback;
}
+ public ResourceResolver getResolver() {
+ return mResourceResolver;
+ }
+
public Map<String, String> getDefaultPropMap(Object key) {
return mDefaultPropMaps.get(key);
}
@@ -265,7 +261,7 @@
@Override
public final TypedArray obtainStyledAttributes(int[] attrs) {
- return createStyleBasedTypedArray(mThemeValues, attrs);
+ return createStyleBasedTypedArray(mResourceResolver.getTheme(), attrs);
}
@Override
@@ -362,7 +358,8 @@
customStyle = set.getAttributeValue(null /* namespace*/, "style");
}
if (customStyle != null) {
- ResourceValue item = findResValue(customStyle, false /*forceFrameworkOnly*/);
+ ResourceValue item = mResourceResolver.findResValue(customStyle,
+ false /*forceFrameworkOnly*/);
if (item instanceof StyleResourceValue) {
defStyleValues = (StyleResourceValue)item;
@@ -378,22 +375,21 @@
}
// look for the style in the current theme, and its parent:
- if (mThemeValues != null) {
- ResourceValue item = findItemInStyle(mThemeValues, defStyleName);
+ ResourceValue item = mResourceResolver.findItemInTheme(defStyleName);
- if (item != null) {
- // item is a reference to a style entry. Search for it.
- item = findResValue(item.getValue(), false /*forceFrameworkOnly*/);
+ if (item != null) {
+ // item is a reference to a style entry. Search for it.
+ item = mResourceResolver.findResValue(item.getValue(),
+ false /*forceFrameworkOnly*/);
- if (item instanceof StyleResourceValue) {
- defStyleValues = (StyleResourceValue)item;
- }
- } else {
- Bridge.getLog().error(null,
- String.format(
- "Failed to find style '%s' in current theme", defStyleName),
- null /*data*/);
+ if (item instanceof StyleResourceValue) {
+ defStyleValues = (StyleResourceValue)item;
}
+ } else {
+ Bridge.getLog().error(null,
+ String.format(
+ "Failed to find style '%s' in current theme", defStyleName),
+ null /*data*/);
}
}
@@ -425,13 +421,13 @@
// look for the value in the defStyle first (and its parent if needed)
if (defStyleValues != null) {
- resValue = findItemInStyle(defStyleValues, name);
+ resValue = mResourceResolver.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 && mThemeValues != null) {
- resValue = findItemInStyle(mThemeValues, name);
+ if (resValue == null) {
+ resValue = mResourceResolver.findItemInTheme(name);
}
// if we found a value, we make sure this doesn't reference another value.
@@ -442,14 +438,15 @@
defaultPropMap.put(name, resValue.getValue());
}
- resValue = resolveResValue(resValue);
+ resValue = mResourceResolver.resolveResValue(resValue);
}
ta.bridgeSetValue(index, name, resValue);
} else {
// 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, resolveValue(null, name, value, isPlatformFile));
+ ta.bridgeSetValue(index, name,
+ mResourceResolver.resolveValue(null, name, value, isPlatformFile));
}
}
}
@@ -487,10 +484,10 @@
String name = styleAttribute.getValue();
// get the value from the style, or its parent styles.
- ResourceValue resValue = findItemInStyle(style, name);
+ ResourceValue resValue = mResourceResolver.findItemInStyle(style, name);
// resolve it to make sure there are no references left.
- ta.bridgeSetValue(index, name, resolveResValue(resValue));
+ ta.bridgeSetValue(index, name, mResourceResolver.resolveResValue(resValue));
}
ta.sealArray();
@@ -500,295 +497,6 @@
/**
- * 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.
- */
- private 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 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>.
- */
- ResourceValue findResValue(String reference, boolean forceFrameworkOnly) {
- if (reference == null) {
- return null;
- }
- if (reference.startsWith(BridgeConstants.PREFIX_THEME_REF)) {
- // no theme? no need to go further!
- if (mThemeValues == null) {
- return null;
- }
-
- boolean frameworkOnly = false;
-
- // eliminate the prefix from the string
- if (reference.startsWith(BridgeConstants.PREFIX_ANDROID_THEME_REF)) {
- frameworkOnly = true;
- reference = reference.substring(BridgeConstants.PREFIX_ANDROID_THEME_REF.length());
- } else {
- reference = reference.substring(BridgeConstants.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 (BridgeConstants.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(BridgeConstants.PREFIX_ANDROID)) {
- frameworkOnly = true;
- referenceName = referenceName.substring(BridgeConstants.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(mThemeValues, referenceName);
- }
-
- return findItemInStyle(mThemeValues, referenceName);
- } else if (reference.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) {
- boolean frameworkOnly = false;
-
- // check for the specific null reference value.
- if (BridgeConstants.REFERENCE_NULL.equals(reference)) {
- return null;
- }
-
- // Eliminate the prefix from the string.
- if (reference.startsWith(BridgeConstants.PREFIX_ANDROID_RESOURCE_REF)) {
- frameworkOnly = true;
- reference = reference.substring(
- BridgeConstants.PREFIX_ANDROID_RESOURCE_REF.length());
- } else {
- reference = reference.substring(BridgeConstants.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(BridgeConstants.PREFIX_ANDROID)) {
- frameworkOnly = true;
- segments[1] = segments[1].substring(BridgeConstants.PREFIX_ANDROID.length());
- }
-
- return findResValue(segments[0], segments[1],
- forceFrameworkOnly ? true :frameworkOnly);
- }
-
- // Looks like the value didn't reference anything. Return null.
- return null;
- }
-
- /**
- * 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 (BridgeConstants.RES_ID.equals(resType)) {
- if (Bridge.getResourceValue(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$
- Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE,
- "Couldn't resolve resource @" +
- (frameworkOnly ? "android:" : "") + resType + "/" + resName,
- new ResourceValue(resType, resName, frameworkOnly));
- }
- return null;
- }
-
- /**
- * 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);
- }
-
- 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;
-
- }
-
- /**
- * 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;
- }
-
- /**
* The input int[] attrs is one of com.android.internal.R.styleable fields where the name
* of the field is the style being referenced and the array contains one index per attribute.
* <p/>
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 e95d295..61f47ba 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
@@ -19,8 +19,8 @@
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.LayoutLog;
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;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
@@ -155,14 +155,14 @@
String[] layoutInfo = Bridge.resolveResourceValue(resource);
if (layoutInfo != null) {
- value = bridgeContext.getFrameworkResource(BridgeConstants.RES_LAYOUT,
- layoutInfo[0]);
+ value = bridgeContext.getResolver().getFrameworkResource(
+ ResourceResolver.RES_LAYOUT, layoutInfo[0]);
} else {
layoutInfo = mProjectCallback.resolveResourceValue(resource);
if (layoutInfo != null) {
- value = bridgeContext.getProjectResource(BridgeConstants.RES_LAYOUT,
- layoutInfo[0]);
+ value = bridgeContext.getResolver().getProjectResource(
+ ResourceResolver.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 23d81a2..3af6a1b 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,7 @@
if (resourceInfo != null) {
platformResFlag_out[0] = true;
- return mContext.getFrameworkResource(resourceInfo[1], resourceInfo[0]);
+ return mContext.getResolver().getFrameworkResource(resourceInfo[1], resourceInfo[0]);
}
// didn't find a match in the framework? look in the project.
@@ -113,7 +113,7 @@
if (resourceInfo != null) {
platformResFlag_out[0] = false;
- return mContext.getProjectResource(resourceInfo[1], resourceInfo[0]);
+ return mContext.getResolver().getProjectResource(resourceInfo[1], resourceInfo[0]);
}
}
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 84bb4d1..b166da5 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
@@ -19,6 +19,7 @@
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 com.android.ide.common.resources.ResourceResolver;
import com.android.internal.util.XmlUtils;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
@@ -633,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(BridgeConstants.RES_ID, idName, defValue);
+ return mContext.getFrameworkResourceValue(ResourceResolver.RES_ID, idName, defValue);
}
// look for idName in the project R class.
- return mContext.getProjectResourceValue(BridgeConstants.RES_ID, idName, defValue);
+ return mContext.getProjectResourceValue(ResourceResolver.RES_ID, idName, defValue);
}
// not a direct id valid reference? resolve it
@@ -682,7 +683,7 @@
ResourceValue value = mResourceData[index];
String stringValue = value.getValue();
- if (stringValue == null || BridgeConstants.REFERENCE_NULL.equals(stringValue)) {
+ if (stringValue == null || ResourceResolver.REFERENCE_NULL.equals(stringValue)) {
return null;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 443d881..8422d48 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -102,7 +102,7 @@
}
public void setInsets(IWindow window, int touchable, Rect contentInsets,
- Rect visibleInsets) {
+ Rect visibleInsets, Region touchableRegion) {
// pass for now.
}
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 ba45217..45d8e26 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
@@ -17,6 +17,7 @@
package com.android.layoutlib.bridge.android;
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;
@@ -57,7 +58,7 @@
String ns = mParser.getAttributeNamespace(index);
if (BridgeConstants.NS_RESOURCES.equals(ns)) {
- Integer v = Bridge.getResourceValue(BridgeConstants.RES_ATTR, name);
+ Integer v = Bridge.getResourceValue(ResourceResolver.RES_ATTR, name);
if (v != null) {
return v.intValue();
}
@@ -68,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(BridgeConstants.RES_ATTR,
+ Integer v = mContext.getProjectCallback().getResourceValue(ResourceResolver.RES_ATTR,
name);
if (v != null) {
return v.intValue();
@@ -102,8 +103,9 @@
private int resolveResourceValue(String value, int defaultValue) {
// now look for this particular value
- ResourceValue resource = mContext.resolveResValue(
- mContext.findResValue(value, mPlatformFile));
+ ResourceResolver resolver = mContext.getResolver();
+ ResourceValue resource = resolver.resolveResValue(
+ resolver.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 2439791..a227d0c 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
@@ -38,9 +38,10 @@
import com.android.ide.common.rendering.api.ViewInfo;
import com.android.ide.common.rendering.api.Params.RenderingMode;
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.BridgeConstants;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeInflater;
import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
@@ -73,8 +74,6 @@
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -106,7 +105,6 @@
private BridgeContext mContext;
private BridgeXmlBlockParser mBlockParser;
private BridgeInflater mInflater;
- private StyleResourceValue mCurrentTheme;
private int mScreenOffset;
private ResourceValue mWindowBackground;
private FrameLayout mViewRoot;
@@ -170,18 +168,23 @@
metrics.xdpi = mParams.getXdpi();
metrics.ydpi = mParams.getYdpi();
- // find the current theme and compute the style inheritance map
- Map<StyleResourceValue, StyleResourceValue> styleParentMap =
- new HashMap<StyleResourceValue, StyleResourceValue>();
+ // 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());
- mCurrentTheme = computeStyleMaps(mParams.getThemeName(), mParams.isProjectTheme(),
- mParams.getProjectResources().get(BridgeConstants.RES_STYLE),
- mParams.getFrameworkResources().get(BridgeConstants.RES_STYLE), styleParentMap);
// build the context
- mContext = new BridgeContext(mParams.getProjectKey(), metrics, mCurrentTheme,
- mParams.getProjectResources(), mParams.getFrameworkResources(),
- styleParentMap, mParams.getProjectCallback());
+ mContext = new BridgeContext(mParams.getProjectKey(), metrics, resolver,
+ mParams.getProjectCallback());
// set the current rendering context
sCurrentContext = mContext;
@@ -193,12 +196,12 @@
// get the screen offset and window-background resource
mWindowBackground = null;
mScreenOffset = 0;
- if (mCurrentTheme != null && mParams.isBgColorOverridden() == false) {
- mWindowBackground = mContext.findItemInStyle(mCurrentTheme, "windowBackground");
- mWindowBackground = mContext.resolveResValue(mWindowBackground);
+ StyleResourceValue theme = resolver.getTheme();
+ if (theme != null && mParams.isBgColorOverridden() == false) {
+ mWindowBackground = resolver.findItemInTheme("windowBackground");
+ mWindowBackground = resolver.resolveResValue(mWindowBackground);
- mScreenOffset = getScreenOffset(mParams.getFrameworkResources(), mCurrentTheme,
- mContext);
+ mScreenOffset = getScreenOffset(resolver, metrics);
}
// build the inflater and parser.
@@ -499,18 +502,18 @@
ResourceValue animationResource = null;
int animationId = 0;
if (isFrameworkAnimation) {
- animationResource = mContext.getFrameworkResource(BridgeConstants.RES_ANIMATOR,
- animationName);
+ animationResource = mContext.getResolver().getFrameworkResource(
+ ResourceResolver.RES_ANIMATOR, animationName);
if (animationResource != null) {
- animationId = Bridge.getResourceValue(BridgeConstants.RES_ANIMATOR,
+ animationId = Bridge.getResourceValue(ResourceResolver.RES_ANIMATOR,
animationName);
}
} else {
- animationResource = mContext.getProjectResource(BridgeConstants.RES_ANIMATOR,
- animationName);
+ animationResource = mContext.getResolver().getProjectResource(
+ ResourceResolver.RES_ANIMATOR, animationName);
if (animationResource != null) {
animationId = mContext.getProjectCallback().getResourceValue(
- BridgeConstants.RES_ANIMATOR, animationName);
+ ResourceResolver.RES_ANIMATOR, animationName);
}
}
@@ -905,182 +908,21 @@
}
}
-
- /**
- * Compute style information from the given list of style for the project and framework.
- * @param themeName the name of the current theme. In order to differentiate project and
- * platform themes sharing the same name, all project themes must be prepended with
- * a '*' character.
- * @param isProjectTheme Is this a project theme
- * @param inProjectStyleMap the project style map
- * @param inFrameworkStyleMap the framework style map
- * @param outInheritanceMap the map of style inheritance. This is filled by the method
- * @return the {@link StyleResourceValue} matching <var>themeName</var>
- */
- private StyleResourceValue computeStyleMaps(
- String themeName, boolean isProjectTheme, Map<String,
- ResourceValue> inProjectStyleMap, Map<String, ResourceValue> inFrameworkStyleMap,
- Map<StyleResourceValue, StyleResourceValue> outInheritanceMap) {
-
- if (inProjectStyleMap != null && inFrameworkStyleMap != null) {
- // first, get the theme
- ResourceValue theme = null;
-
- // project theme names have been prepended with a *
- if (isProjectTheme) {
- theme = inProjectStyleMap.get(themeName);
- } else {
- theme = inFrameworkStyleMap.get(themeName);
- }
-
- if (theme instanceof StyleResourceValue) {
- // compute the inheritance map for both the project and framework styles
- computeStyleInheritance(inProjectStyleMap.values(), inProjectStyleMap,
- inFrameworkStyleMap, outInheritanceMap);
-
- // 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(inFrameworkStyleMap.values(), null /*inProjectStyleMap */,
- inFrameworkStyleMap, outInheritanceMap);
-
- return (StyleResourceValue)theme;
- }
- }
-
- return null;
- }
-
- /**
- * 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,
- Map<StyleResourceValue, StyleResourceValue> outInheritanceMap) {
- 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) {
- outInheritanceMap.put(style, parentStyle);
- }
- }
- }
- }
- }
-
- /**
- * Searches for and returns the {@link StyleResourceValue} from a given name.
- * <p/>The format of the name can be:
- * <ul>
- * <li>[android:]<name></li>
- * <li>[android:]style/<name></li>
- * <li>@[android:]style/<name></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(BridgeConstants.PREFIX_RESOURCE_REF)) {
- name = name.substring(BridgeConstants.PREFIX_RESOURCE_REF.length());
- }
-
- // check for framework identifier.
- if (name.startsWith(BridgeConstants.PREFIX_ANDROID)) {
- frameworkOnly = true;
- name = name.substring(BridgeConstants.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(BridgeConstants.REFERENCE_STYLE)) {
- name = name.substring(BridgeConstants.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;
- mParams.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
- String.format("Unable to resolve parent style name: %s", parentName),
- null /*data*/);
-
- return null;
- }
-
- /**
- * 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;
- }
-
/**
* Returns the top screen offset. This depends on whether the current theme defines the user
* of the title and status bars.
- * @param frameworkResources The framework resources
- * @param currentTheme The current theme
- * @param context The context
+ * @param resolver The {@link ResourceResolver}
+ * @param metrics The display metrics
* @return the pixel height offset
*/
- private int getScreenOffset(Map<String, Map<String, ResourceValue>> frameworkResources,
- StyleResourceValue currentTheme, BridgeContext context) {
+ private int getScreenOffset(ResourceResolver resolver, DisplayMetrics metrics) {
int offset = 0;
// get the title bar flag from the current theme.
- ResourceValue value = context.findItemInStyle(currentTheme, "windowNoTitle");
+ ResourceValue value = resolver.findItemInTheme("windowNoTitle");
// because it may reference something else, we resolve it.
- value = context.resolveResValue(value);
+ value = resolver.resolveResValue(value);
// if there's a value and it's true (default is false)
if (value == null || value.getValue() == null ||
@@ -1089,17 +931,17 @@
int defaultOffset = DEFAULT_TITLE_BAR_HEIGHT;
// get value from the theme.
- value = context.findItemInStyle(currentTheme, "windowTitleSize");
+ value = resolver.findItemInTheme("windowTitleSize");
// resolve it
- value = context.resolveResValue(value);
+ value = resolver.resolveResValue(value);
if (value != null) {
// get the numerical value, if available
TypedValue typedValue = ResourceHelper.getValue(value.getValue());
if (typedValue != null) {
// compute the pixel value based on the display metrics
- defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics);
+ defaultOffset = (int)typedValue.getDimension(metrics);
}
}
@@ -1107,10 +949,10 @@
}
// get the fullscreen flag from the current theme.
- value = context.findItemInStyle(currentTheme, "windowFullscreen");
+ value = resolver.findItemInTheme("windowFullscreen");
// because it may reference something else, we resolve it.
- value = context.resolveResValue(value);
+ value = resolver.resolveResValue(value);
if (value == null || value.getValue() == null ||
XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
@@ -1118,16 +960,13 @@
// default value
int defaultOffset = DEFAULT_STATUS_BAR_HEIGHT;
- // get the real value, first the list of Dimensions from the framework map
- Map<String, ResourceValue> dimens = frameworkResources.get(BridgeConstants.RES_DIMEN);
-
- // now get the value
- value = dimens.get("status_bar_height");
+ // get the real value
+ value = resolver.getFrameworkResource(ResourceResolver.RES_DIMEN, "status_bar_height");
if (value != null) {
TypedValue typedValue = ResourceHelper.getValue(value.getValue());
if (typedValue != null) {
// compute the pixel value based on the display metrics
- defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics);
+ defaultOffset = (int)typedValue.getDimension(metrics);
}
}
@@ -1136,7 +975,6 @@
}
return offset;
-
}
/**
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 9dbba20..847577f 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -19,6 +19,7 @@
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WpsConfiguration;
+import android.net.wifi.WpsResult;
import android.net.wifi.ScanResult;
import android.net.DhcpInfo;
@@ -109,6 +110,6 @@
void forgetNetwork(int networkId);
- String startWps(in WpsConfiguration config);
+ WpsResult startWps(in WpsConfiguration config);
}
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index 56bc5d7..73c24cf 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -370,44 +370,52 @@
* Start WPS pin method configuration with pin obtained
* from the access point
*/
- static boolean startWpsWithPinFromAccessPoint(WpsConfiguration config) {
+ static WpsResult startWpsWithPinFromAccessPoint(WpsConfiguration config) {
+ WpsResult result = new WpsResult();
if (WifiNative.startWpsWithPinFromAccessPointCommand(config.BSSID, config.pin)) {
/* WPS leaves all networks disabled */
markAllNetworksDisabled();
- return true;
+ result.status = WpsResult.Status.SUCCESS;
+ } else {
+ Log.e(TAG, "Failed to start WPS pin method configuration");
+ result.status = WpsResult.Status.FAILURE;
}
- Log.e(TAG, "Failed to start WPS pin method configuration");
- return false;
+ return result;
}
/**
* Start WPS pin method configuration with pin obtained
* from the device
- * @return empty string on failure. null is never returned.
+ * @return WpsResult indicating status and pin
*/
- static String startWpsWithPinFromDevice(WpsConfiguration config) {
- String pin = WifiNative.startWpsWithPinFromDeviceCommand(config.BSSID);
+ static WpsResult startWpsWithPinFromDevice(WpsConfiguration config) {
+ WpsResult result = new WpsResult();
+ result.pin = WifiNative.startWpsWithPinFromDeviceCommand(config.BSSID);
/* WPS leaves all networks disabled */
- if (!TextUtils.isEmpty(pin)) {
+ if (!TextUtils.isEmpty(result.pin)) {
markAllNetworksDisabled();
+ result.status = WpsResult.Status.SUCCESS;
} else {
Log.e(TAG, "Failed to start WPS pin method configuration");
- pin = "";
+ result.status = WpsResult.Status.FAILURE;
}
- return pin;
+ return result;
}
/**
* Start WPS push button configuration
*/
- static boolean startWpsPbc(WpsConfiguration config) {
+ static WpsResult startWpsPbc(WpsConfiguration config) {
+ WpsResult result = new WpsResult();
if (WifiNative.startWpsPbcCommand(config.BSSID)) {
/* WPS leaves all networks disabled */
markAllNetworksDisabled();
- return true;
+ result.status = WpsResult.Status.SUCCESS;
+ } else {
+ Log.e(TAG, "Failed to start WPS push button configuration");
+ result.status = WpsResult.Status.FAILURE;
}
- Log.e(TAG, "Failed to start WPS push button configuration");
- return false;
+ return result;
}
/**
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 4623721..d05918f 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -274,6 +274,25 @@
* @see #ERROR_AUTHENTICATING
*/
public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
+
+ /**
+ * Broadcast intent action for reporting errors
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ERROR_ACTION = "android.net.wifi.ERROR";
+ /**
+ * The type of error being reported
+ * @hide
+ */
+ public static final String EXTRA_ERROR_CODE = "errorCode";
+
+ /**
+ * Valid error codes
+ * @hide
+ */
+ public static final int WPS_OVERLAP_ERROR = 1;
+
/**
* Broadcast intent action indicating that the configured networks changed.
* This can be as a result of adding/updating/deleting a network
@@ -1074,15 +1093,15 @@
* Start Wi-fi Protected Setup
*
* @param config WPS configuration
- * @return pin generated by device, if any
+ * @return WpsResult containing pin and status
* @hide
* TODO: with use of AsyncChannel, return value should go away
*/
- public String startWps(WpsConfiguration config) {
+ public WpsResult startWps(WpsConfiguration config) {
try {
return mService.startWps(config);
} catch (RemoteException e) {
- return null;
+ return new WpsResult(WpsResult.Status.FAILURE);
}
}
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index 934e509..090ad3b 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -53,6 +53,9 @@
private static final String passwordKeyMayBeIncorrectEvent =
"pre-shared key may be incorrect";
+ /* WPS events */
+ private static final String wpsOverlapEvent = "WPS-OVERLAP-DETECTED";
+
/**
* Names of events from wpa_supplicant (minus the prefix). In the
* format descriptions, * "<code>x</code>"
@@ -174,6 +177,8 @@
if (eventStr.startsWith(wpaEventPrefix) &&
0 < eventStr.indexOf(passwordKeyMayBeIncorrectEvent)) {
handlePasswordKeyMayBeIncorrect();
+ } else if (eventStr.startsWith(wpsOverlapEvent)) {
+ mWifiStateMachine.notifyWpsOverlap();
}
continue;
}
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 8718117..0548b4d 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -47,6 +47,7 @@
import android.net.NetworkInfo.DetailedState;
import android.net.LinkProperties;
import android.net.wifi.NetworkUpdateResult;
+import android.net.wifi.WpsResult.Status;
import android.os.Binder;
import android.os.Message;
import android.os.IBinder;
@@ -214,6 +215,9 @@
static final int SUPPLICANT_STATE_CHANGE_EVENT = 39;
/* Password may be incorrect */
static final int PASSWORD_MAY_BE_INCORRECT_EVENT = 40;
+ /* WPS overlap detected */
+ static final int WPS_OVERLAP_EVENT = 41;
+
/* Supplicant commands */
/* Is supplicant alive ? */
@@ -302,10 +306,11 @@
/* Reset the supplicant state tracker */
static final int CMD_RESET_SUPPLICANT_STATE = 111;
-
/* Commands/events reported by WpsStateMachine */
/* Indicates the completion of WPS activity */
static final int WPS_COMPLETED_EVENT = 121;
+ /* Reset the WPS state machine */
+ static final int CMD_RESET_WPS_STATE = 122;
private static final int CONNECT_MODE = 1;
private static final int SCAN_ONLY_MODE = 2;
@@ -793,18 +798,19 @@
sendMessage(obtainMessage(CMD_FORGET_NETWORK, netId, 0));
}
- public String startWps(AsyncChannel channel, WpsConfiguration config) {
- String result = null;
+ public WpsResult startWps(AsyncChannel channel, WpsConfiguration config) {
+ WpsResult result;
switch (config.setup) {
case PIN_FROM_DEVICE:
- //TODO: will go away with AsyncChannel use from settings
- Message resultMsg = channel.sendMessageSynchronously(CMD_START_WPS, config);
- result = (String) resultMsg.obj;
- resultMsg.recycle();
- break;
case PBC:
case PIN_FROM_ACCESS_POINT:
- sendMessage(obtainMessage(CMD_START_WPS, config));
+ //TODO: will go away with AsyncChannel use from settings
+ Message resultMsg = channel.sendMessageSynchronously(CMD_START_WPS, config);
+ result = (WpsResult) resultMsg.obj;
+ resultMsg.recycle();
+ break;
+ default:
+ result = new WpsResult(Status.FAILURE);
break;
}
return result;
@@ -1284,6 +1290,13 @@
mContext.sendStickyBroadcast(intent);
}
+ private void sendErrorBroadcast(int errorCode) {
+ Intent intent = new Intent(WifiManager.ERROR_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.putExtra(WifiManager.EXTRA_ERROR_CODE, errorCode);
+ mContext.sendBroadcast(intent);
+ }
+
private void sendLinkConfigurationChangedBroadcast() {
Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -1379,6 +1392,14 @@
}
/**
+ * Send a notification that the supplicant has detected overlapped
+ * WPS sessions
+ */
+ void notifyWpsOverlap() {
+ sendMessage(WPS_OVERLAP_EVENT);
+ }
+
+ /**
* Send the tracker a notification that a connection to the supplicant
* daemon has been established.
*/
@@ -1496,6 +1517,7 @@
case SCAN_RESULTS_EVENT:
case SUPPLICANT_STATE_CHANGE_EVENT:
case PASSWORD_MAY_BE_INCORRECT_EVENT:
+ case WPS_OVERLAP_EVENT:
case CMD_BLACKLIST_NETWORK:
case CMD_CLEAR_BLACKLIST:
case CMD_SET_SCAN_MODE:
@@ -1511,13 +1533,9 @@
case CMD_ENABLE_ALL_NETWORKS:
break;
case CMD_START_WPS:
- WpsConfiguration config = (WpsConfiguration) message.obj;
- switch (config.setup) {
- case PIN_FROM_DEVICE:
- String pin = "";
- mReplyChannel.replyToMessage(message, message.what, pin);
- break;
- }
+ /* Return failure when the state machine cannot handle WPS initiation*/
+ mReplyChannel.replyToMessage(message, message.what,
+ new WpsResult(Status.FAILURE));
break;
default:
Log.e(TAG, "Error! unhandled message" + message);
@@ -1803,6 +1821,7 @@
/* Reset the supplicant state to indicate the supplicant
* state is not known at this time */
mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
+ mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
/* Initialize data structures */
mLastBssid = null;
mLastNetworkId = -1;
@@ -1884,6 +1903,7 @@
setWifiState(WIFI_STATE_DISABLING);
sendSupplicantConnectionChangedBroadcast(false);
mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
+ mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
transitionTo(mSupplicantStoppingState);
break;
case SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */
@@ -1894,6 +1914,7 @@
handleNetworkDisconnect();
sendSupplicantConnectionChangedBroadcast(false);
mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
+ mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
transitionTo(mDriverLoadedState);
sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
break;
@@ -2040,6 +2061,7 @@
case NETWORK_CONNECTION_EVENT:
case NETWORK_DISCONNECTION_EVENT:
case PASSWORD_MAY_BE_INCORRECT_EVENT:
+ case WPS_OVERLAP_EVENT:
case CMD_SET_SCAN_TYPE:
case CMD_SET_HIGH_PERF_MODE:
case CMD_SET_COUNTRY_CODE:
@@ -2274,6 +2296,10 @@
case PASSWORD_MAY_BE_INCORRECT_EVENT:
mSupplicantStateTracker.sendMessage(PASSWORD_MAY_BE_INCORRECT_EVENT);
break;
+ case WPS_OVERLAP_EVENT:
+ /* We just need to broadcast the error */
+ sendErrorBroadcast(WifiManager.WPS_OVERLAP_ERROR);
+ break;
case SUPPLICANT_STATE_CHANGE_EVENT:
stateChangeResult = (StateChangeResult) message.obj;
SupplicantState state = stateChangeResult.state;
diff --git a/wifi/java/android/net/wifi/WpsResult.aidl b/wifi/java/android/net/wifi/WpsResult.aidl
new file mode 100644
index 0000000..eb4c4f5
--- /dev/null
+++ b/wifi/java/android/net/wifi/WpsResult.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.net.wifi;
+
+parcelable WpsResult;
diff --git a/wifi/java/android/net/wifi/WpsResult.java b/wifi/java/android/net/wifi/WpsResult.java
new file mode 100644
index 0000000..d4fd3e2
--- /dev/null
+++ b/wifi/java/android/net/wifi/WpsResult.java
@@ -0,0 +1,90 @@
+/*
+ * 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.net.wifi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class representing the result of a WPS request
+ * @hide
+ */
+public class WpsResult implements Parcelable {
+
+ public enum Status {
+ SUCCESS,
+ FAILURE,
+ IN_PROGRESS,
+ }
+
+ public Status status;
+
+ public String pin;
+
+ public WpsResult() {
+ status = Status.FAILURE;
+ pin = null;
+ }
+
+ public WpsResult(Status s) {
+ status = s;
+ pin = null;
+ }
+
+ public String toString() {
+ StringBuffer sbuf = new StringBuffer();
+ sbuf.append(" status: ").append(status.toString());
+ sbuf.append('\n');
+ sbuf.append(" pin: ").append(pin);
+ sbuf.append("\n");
+ return sbuf.toString();
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** copy constructor {@hide} */
+ public WpsResult(WpsResult source) {
+ if (source != null) {
+ status = source.status;
+ pin = source.pin;
+ }
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(status.name());
+ dest.writeString(pin);
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<WpsResult> CREATOR =
+ new Creator<WpsResult>() {
+ public WpsResult createFromParcel(Parcel in) {
+ WpsResult result = new WpsResult();
+ result.status = Status.valueOf(in.readString());
+ result.pin = in.readString();
+ return result;
+ }
+
+ public WpsResult[] newArray(int size) {
+ return new WpsResult[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/WpsStateMachine.java b/wifi/java/android/net/wifi/WpsStateMachine.java
index 381444c..92f9f57 100644
--- a/wifi/java/android/net/wifi/WpsStateMachine.java
+++ b/wifi/java/android/net/wifi/WpsStateMachine.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiStateMachine.StateChangeResult;
+import android.net.wifi.WpsResult.Status;
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
@@ -93,29 +94,32 @@
switch (message.what) {
case WifiStateMachine.CMD_START_WPS:
mWpsConfig = (WpsConfiguration) message.obj;
- boolean success = false;
+ WpsResult result;
switch (mWpsConfig.setup) {
case PBC:
- success = WifiConfigStore.startWpsPbc(mWpsConfig);
+ result = WifiConfigStore.startWpsPbc(mWpsConfig);
break;
case PIN_FROM_ACCESS_POINT:
- success = WifiConfigStore.startWpsWithPinFromAccessPoint(mWpsConfig);
+ result = WifiConfigStore.startWpsWithPinFromAccessPoint(mWpsConfig);
break;
case PIN_FROM_DEVICE:
- String pin = WifiConfigStore.startWpsWithPinFromDevice(mWpsConfig);
- success = (pin != null);
- mReplyChannel.replyToMessage(message, message.what, pin);
+ result = WifiConfigStore.startWpsWithPinFromDevice(mWpsConfig);
break;
default:
+ result = new WpsResult(Status.FAILURE);
Log.e(TAG, "Invalid setup for WPS");
break;
}
- if (success) {
+ mReplyChannel.replyToMessage(message, message.what, result);
+ if (result.status == Status.SUCCESS) {
transitionTo(mActiveState);
} else {
Log.e(TAG, "Failed to start WPS with config " + mWpsConfig.toString());
}
break;
+ case WifiStateMachine.CMD_RESET_WPS_STATE:
+ transitionTo(mInactiveState);
+ break;
default:
Log.e(TAG, "Failed to handle " + message);
break;
@@ -167,7 +171,9 @@
}
break;
case WifiStateMachine.CMD_START_WPS:
- deferMessage(message);
+ /* Ignore request and send an in progress message */
+ mReplyChannel.replyToMessage(message, message.what,
+ new WpsResult(Status.IN_PROGRESS));
break;
default:
retValue = NOT_HANDLED;
@@ -197,4 +203,4 @@
}
}
-}
\ No newline at end of file
+}