diff options
116 files changed, 7123 insertions, 5276 deletions
diff --git a/api/current.xml b/api/current.xml index 07aabed..80428bd 100644 --- a/api/current.xml +++ b/api/current.xml @@ -21741,6 +21741,17 @@ visibility="public" > </method> +<method name="removeAllUpdateListeners" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="removeUpdateListener" return="void" abstract="false" @@ -94661,1079 +94672,6 @@ > </method> </class> -<class name="AudioEffect" - extends="java.lang.Object" - abstract="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="AudioEffect" - type="android.media.AudioEffect" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="type" type="java.util.UUID"> -</parameter> -<parameter name="uuid" type="java.util.UUID"> -</parameter> -<parameter name="priority" type="int"> -</parameter> -<parameter name="audioSession" type="int"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="RuntimeException" type="java.lang.RuntimeException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</constructor> -<method name="byteArrayToInt" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="valueBuf" type="byte[]"> -</parameter> -</method> -<method name="byteArrayToInt" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="valueBuf" type="byte[]"> -</parameter> -<parameter name="offset" type="int"> -</parameter> -</method> -<method name="byteArrayToShort" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="valueBuf" type="byte[]"> -</parameter> -</method> -<method name="byteArrayToShort" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="valueBuf" type="byte[]"> -</parameter> -<parameter name="offset" type="int"> -</parameter> -</method> -<method name="checkState" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="methodName" type="java.lang.String"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="checkStatus" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="status" type="int"> -</parameter> -</method> -<method name="command" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="cmdCode" type="int"> -</parameter> -<parameter name="command" type="byte[]"> -</parameter> -<parameter name="reply" type="byte[]"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="concatArrays" - return="byte[]" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="arrays" type="byte..."> -</parameter> -</method> -<method name="getDescriptor" - return="android.media.AudioEffect.Descriptor" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="getEnabled" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="getId" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="getParameter" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="param" type="byte[]"> -</parameter> -<parameter name="value" type="byte[]"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="getParameter" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="param" type="int"> -</parameter> -<parameter name="value" type="byte[]"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="getParameter" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="param" type="int"> -</parameter> -<parameter name="value" type="int[]"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="getParameter" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="param" type="int"> -</parameter> -<parameter name="value" type="short[]"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="getParameter" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="param" type="int[]"> -</parameter> -<parameter name="value" type="int[]"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="getParameter" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="param" type="int[]"> -</parameter> -<parameter name="value" type="short[]"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="getParameter" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="param" type="int[]"> -</parameter> -<parameter name="value" type="byte[]"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="hasControl" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="intToByteArray" - return="byte[]" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="value" type="int"> -</parameter> -</method> -<method name="queryEffects" - return="android.media.AudioEffect.Descriptor[]" - abstract="false" - native="false" - synchronized="false" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="release" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="setControlStatusListener" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="listener" type="android.media.AudioEffect.OnControlStatusChangeListener"> -</parameter> -</method> -<method name="setEnableStatusListener" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="listener" type="android.media.AudioEffect.OnEnableStatusChangeListener"> -</parameter> -</method> -<method name="setEnabled" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="enabled" type="boolean"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="setParameter" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="param" type="byte[]"> -</parameter> -<parameter name="value" type="byte[]"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="setParameter" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="param" type="int"> -</parameter> -<parameter name="value" type="int"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="setParameter" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="param" type="int"> -</parameter> -<parameter name="value" type="short"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="setParameter" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="param" type="int"> -</parameter> -<parameter name="value" type="byte[]"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="setParameter" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="param" type="int[]"> -</parameter> -<parameter name="value" type="int[]"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="setParameter" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="param" type="int[]"> -</parameter> -<parameter name="value" type="short[]"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="setParameter" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="param" type="int[]"> -</parameter> -<parameter name="value" type="byte[]"> -</parameter> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -</method> -<method name="setParameterListener" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="listener" type="android.media.AudioEffect.OnParameterChangeListener"> -</parameter> -</method> -<method name="shortToByteArray" - return="byte[]" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="value" type="short"> -</parameter> -</method> -<field name="ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ALREADY_EXISTS" - type="int" - transient="false" - volatile="false" - value="-2" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="CONTENT_TYPE_GAME" - type="int" - transient="false" - volatile="false" - value="2" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="CONTENT_TYPE_MOVIE" - type="int" - transient="false" - volatile="false" - value="1" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="CONTENT_TYPE_MUSIC" - type="int" - transient="false" - volatile="false" - value="0" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="CONTENT_TYPE_VOICE" - type="int" - transient="false" - volatile="false" - value="3" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="EFFECT_AUXILIARY" - type="java.lang.String" - transient="false" - volatile="false" - value=""Auxiliary"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="EFFECT_INSERT" - type="java.lang.String" - transient="false" - volatile="false" - value=""Insert"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="EFFECT_TYPE_BASS_BOOST" - type="java.util.UUID" - transient="false" - volatile="false" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="EFFECT_TYPE_ENV_REVERB" - type="java.util.UUID" - transient="false" - volatile="false" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="EFFECT_TYPE_EQUALIZER" - type="java.util.UUID" - transient="false" - volatile="false" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="EFFECT_TYPE_NULL" - type="java.util.UUID" - transient="false" - volatile="false" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="EFFECT_TYPE_PRESET_REVERB" - type="java.util.UUID" - transient="false" - volatile="false" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="EFFECT_TYPE_VIRTUALIZER" - type="java.util.UUID" - transient="false" - volatile="false" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR" - type="int" - transient="false" - volatile="false" - value="-1" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR_BAD_VALUE" - type="int" - transient="false" - volatile="false" - value="-4" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR_DEAD_OBJECT" - type="int" - transient="false" - volatile="false" - value="-7" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR_INVALID_OPERATION" - type="int" - transient="false" - volatile="false" - value="-5" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR_NO_INIT" - type="int" - transient="false" - volatile="false" - value="-3" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="ERROR_NO_MEMORY" - type="int" - transient="false" - volatile="false" - value="-6" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="EXTRA_AUDIO_SESSION" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.media.extra.AUDIO_SESSION"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="EXTRA_CONTENT_TYPE" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.media.extra.CONTENT_TYPE"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="EXTRA_PACKAGE_NAME" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.media.extra.PACKAGE_NAME"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="NATIVE_EVENT_CONTROL_STATUS" - type="int" - transient="false" - volatile="false" - value="0" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="NATIVE_EVENT_ENABLED_STATUS" - type="int" - transient="false" - volatile="false" - value="1" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="NATIVE_EVENT_PARAMETER_CHANGED" - type="int" - transient="false" - volatile="false" - value="2" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="STATE_INITIALIZED" - type="int" - transient="false" - volatile="false" - value="1" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="STATE_UNINITIALIZED" - type="int" - transient="false" - volatile="false" - value="0" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="SUCCESS" - type="int" - transient="false" - volatile="false" - value="0" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="mListenerLock" - type="java.lang.Object" - transient="false" - volatile="false" - static="false" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="mNativeEventHandler" - type="android.media.AudioEffect.NativeEventHandler" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -</class> -<class name="AudioEffect.Descriptor" - extends="java.lang.Object" - abstract="false" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="AudioEffect.Descriptor" - type="android.media.AudioEffect.Descriptor" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</constructor> -<constructor name="AudioEffect.Descriptor" - type="android.media.AudioEffect.Descriptor" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="type" type="java.lang.String"> -</parameter> -<parameter name="uuid" type="java.lang.String"> -</parameter> -<parameter name="connectMode" type="java.lang.String"> -</parameter> -<parameter name="name" type="java.lang.String"> -</parameter> -<parameter name="implementor" type="java.lang.String"> -</parameter> -</constructor> -<field name="mConnectMode" - type="java.lang.String" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="mImplementor" - type="java.lang.String" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="mName" - type="java.lang.String" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="mType" - type="java.util.UUID" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="mUuid" - type="java.util.UUID" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -</class> -<class name="AudioEffect.NativeEventHandler" - extends="android.os.Handler" - abstract="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="private" -> -<constructor name="AudioEffect.NativeEventHandler" - type="android.media.AudioEffect.NativeEventHandler" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="ae" type="android.media.AudioEffect"> -</parameter> -<parameter name="looper" type="android.os.Looper"> -</parameter> -</constructor> -</class> -<interface name="AudioEffect.OnControlStatusChangeListener" - abstract="true" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<method name="onControlStatusChange" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="effect" type="android.media.AudioEffect"> -</parameter> -<parameter name="controlGranted" type="boolean"> -</parameter> -</method> -</interface> -<interface name="AudioEffect.OnEnableStatusChangeListener" - abstract="true" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<method name="onEnableStatusChange" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="effect" type="android.media.AudioEffect"> -</parameter> -<parameter name="enabled" type="boolean"> -</parameter> -</method> -</interface> -<interface name="AudioEffect.OnParameterChangeListener" - abstract="true" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<method name="onParameterChange" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="effect" type="android.media.AudioEffect"> -</parameter> -<parameter name="status" type="int"> -</parameter> -<parameter name="param" type="byte[]"> -</parameter> -<parameter name="value" type="byte[]"> -</parameter> -</method> -</interface> <class name="AudioFormat" extends="java.lang.Object" abstract="false" @@ -98575,217 +97513,6 @@ </parameter> </method> </interface> -<class name="BassBoost" - extends="android.media.AudioEffect" - abstract="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="BassBoost" - type="android.media.BassBoost" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="priority" type="int"> -</parameter> -<parameter name="audioSession" type="int"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="RuntimeException" type="java.lang.RuntimeException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</constructor> -<method name="getProperties" - return="android.media.BassBoost.Settings" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getRoundedStrength" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getStrengthSupported" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="setParameterListener" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="listener" type="android.media.BassBoost.OnParameterChangeListener"> -</parameter> -</method> -<method name="setProperties" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="settings" type="android.media.BassBoost.Settings"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setStrength" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="strength" type="short"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<field name="PARAM_STRENGTH" - type="int" - transient="false" - volatile="false" - value="1" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_STRENGTH_SUPPORTED" - type="int" - transient="false" - volatile="false" - value="0" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -</class> -<interface name="BassBoost.OnParameterChangeListener" - abstract="true" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<method name="onParameterChange" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="effect" type="android.media.BassBoost"> -</parameter> -<parameter name="status" type="int"> -</parameter> -<parameter name="param" type="int"> -</parameter> -<parameter name="value" type="short"> -</parameter> -</method> -</interface> -<class name="BassBoost.Settings" - extends="java.lang.Object" - abstract="false" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="BassBoost.Settings" - type="android.media.BassBoost.Settings" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</constructor> -<constructor name="BassBoost.Settings" - type="android.media.BassBoost.Settings" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="settings" type="java.lang.String"> -</parameter> -</constructor> -<field name="strength" - type="short" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -</class> <class name="CamcorderProfile" extends="java.lang.Object" abstract="false" @@ -99203,1178 +97930,6 @@ > </field> </class> -<class name="EnvironmentalReverb" - extends="android.media.AudioEffect" - abstract="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="EnvironmentalReverb" - type="android.media.EnvironmentalReverb" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="priority" type="int"> -</parameter> -<parameter name="audioSession" type="int"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="RuntimeException" type="java.lang.RuntimeException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</constructor> -<method name="getDecayHFRatio" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getDecayTime" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getDensity" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getDiffusion" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getProperties" - return="android.media.EnvironmentalReverb.Settings" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getReflectionsDelay" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getReflectionsLevel" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getReverbDelay" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getReverbLevel" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getRoomHFLevel" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getRoomLevel" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setDecayHFRatio" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="decayHFRatio" type="short"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setDecayTime" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="decayTime" type="int"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setDensity" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="density" type="short"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setDiffusion" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="diffusion" type="short"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setParameterListener" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="listener" type="android.media.EnvironmentalReverb.OnParameterChangeListener"> -</parameter> -</method> -<method name="setProperties" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="settings" type="android.media.EnvironmentalReverb.Settings"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setReflectionsDelay" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="reflectionsDelay" type="int"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setReflectionsLevel" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="reflectionsLevel" type="short"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setReverbDelay" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="reverbDelay" type="int"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setReverbLevel" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="reverbLevel" type="short"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setRoomHFLevel" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="roomHF" type="short"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setRoomLevel" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="room" type="short"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<field name="PARAM_DECAY_HF_RATIO" - type="int" - transient="false" - volatile="false" - value="3" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_DECAY_TIME" - type="int" - transient="false" - volatile="false" - value="2" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_DENSITY" - type="int" - transient="false" - volatile="false" - value="9" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_DIFFUSION" - type="int" - transient="false" - volatile="false" - value="8" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_REFLECTIONS_DELAY" - type="int" - transient="false" - volatile="false" - value="5" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_REFLECTIONS_LEVEL" - type="int" - transient="false" - volatile="false" - value="4" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_REVERB_DELAY" - type="int" - transient="false" - volatile="false" - value="7" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_REVERB_LEVEL" - type="int" - transient="false" - volatile="false" - value="6" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_ROOM_HF_LEVEL" - type="int" - transient="false" - volatile="false" - value="1" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_ROOM_LEVEL" - type="int" - transient="false" - volatile="false" - value="0" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -</class> -<interface name="EnvironmentalReverb.OnParameterChangeListener" - abstract="true" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<method name="onParameterChange" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="effect" type="android.media.EnvironmentalReverb"> -</parameter> -<parameter name="status" type="int"> -</parameter> -<parameter name="param" type="int"> -</parameter> -<parameter name="value" type="int"> -</parameter> -</method> -</interface> -<class name="EnvironmentalReverb.Settings" - extends="java.lang.Object" - abstract="false" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="EnvironmentalReverb.Settings" - type="android.media.EnvironmentalReverb.Settings" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</constructor> -<constructor name="EnvironmentalReverb.Settings" - type="android.media.EnvironmentalReverb.Settings" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="settings" type="java.lang.String"> -</parameter> -</constructor> -<field name="decayHFRatio" - type="short" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="decayTime" - type="int" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="density" - type="short" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="diffusion" - type="short" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="reflectionsDelay" - type="int" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="reflectionsLevel" - type="short" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="reverbDelay" - type="int" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="reverbLevel" - type="short" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="roomHFLevel" - type="short" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="roomLevel" - type="short" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -</class> -<class name="Equalizer" - extends="android.media.AudioEffect" - abstract="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="Equalizer" - type="android.media.Equalizer" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="priority" type="int"> -</parameter> -<parameter name="audioSession" type="int"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="RuntimeException" type="java.lang.RuntimeException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</constructor> -<method name="getBand" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="frequency" type="int"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getBandFreqRange" - return="int[]" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="band" type="short"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getBandLevel" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="band" type="short"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getBandLevelRange" - return="short[]" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getCenterFreq" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="band" type="short"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getCurrentPreset" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getNumberOfBands" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getNumberOfPresets" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getPresetName" - return="java.lang.String" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="preset" type="short"> -</parameter> -</method> -<method name="getProperties" - return="android.media.Equalizer.Settings" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setBandLevel" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="band" type="short"> -</parameter> -<parameter name="level" type="short"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setParameterListener" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="listener" type="android.media.Equalizer.OnParameterChangeListener"> -</parameter> -</method> -<method name="setProperties" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="settings" type="android.media.Equalizer.Settings"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="usePreset" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="preset" type="short"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<field name="PARAM_BAND_FREQ_RANGE" - type="int" - transient="false" - volatile="false" - value="4" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_BAND_LEVEL" - type="int" - transient="false" - volatile="false" - value="2" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_CENTER_FREQ" - type="int" - transient="false" - volatile="false" - value="3" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_CURRENT_PRESET" - type="int" - transient="false" - volatile="false" - value="6" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_GET_BAND" - type="int" - transient="false" - volatile="false" - value="5" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_GET_NUM_OF_PRESETS" - type="int" - transient="false" - volatile="false" - value="7" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_GET_PRESET_NAME" - type="int" - transient="false" - volatile="false" - value="8" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_LEVEL_RANGE" - type="int" - transient="false" - volatile="false" - value="1" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_NUM_BANDS" - type="int" - transient="false" - volatile="false" - value="0" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PARAM_STRING_SIZE_MAX" - type="int" - transient="false" - volatile="false" - value="32" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -</class> -<interface name="Equalizer.OnParameterChangeListener" - abstract="true" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<method name="onParameterChange" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="effect" type="android.media.Equalizer"> -</parameter> -<parameter name="status" type="int"> -</parameter> -<parameter name="param1" type="int"> -</parameter> -<parameter name="param2" type="int"> -</parameter> -<parameter name="value" type="int"> -</parameter> -</method> -</interface> -<class name="Equalizer.Settings" - extends="java.lang.Object" - abstract="false" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="Equalizer.Settings" - type="android.media.Equalizer.Settings" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</constructor> -<constructor name="Equalizer.Settings" - type="android.media.Equalizer.Settings" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="settings" type="java.lang.String"> -</parameter> -</constructor> -<field name="bandLevels" - type="short[]" - transient="false" - volatile="false" - value="null" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="curPreset" - type="short" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="numBands" - type="short" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -</class> <class name="ExifInterface" extends="java.lang.Object" abstract="false" @@ -103078,270 +100633,6 @@ </parameter> </method> </interface> -<class name="PresetReverb" - extends="android.media.AudioEffect" - abstract="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="PresetReverb" - type="android.media.PresetReverb" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="priority" type="int"> -</parameter> -<parameter name="audioSession" type="int"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="RuntimeException" type="java.lang.RuntimeException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</constructor> -<method name="getPreset" - return="short" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="getProperties" - return="android.media.PresetReverb.Settings" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setParameterListener" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="listener" type="android.media.PresetReverb.OnParameterChangeListener"> -</parameter> -</method> -<method name="setPreset" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="preset" type="short"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<method name="setProperties" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="settings" type="android.media.PresetReverb.Settings"> -</parameter> -<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> -</exception> -<exception name="IllegalStateException" type="java.lang.IllegalStateException"> -</exception> -<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> -</exception> -</method> -<field name="PARAM_PRESET" - type="int" - transient="false" - volatile="false" - value="0" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PRESET_LARGEHALL" - type="short" - transient="false" - volatile="false" - value="5" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PRESET_LARGEROOM" - type="short" - transient="false" - volatile="false" - value="3" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PRESET_MEDIUMHALL" - type="short" - transient="false" - volatile="false" - value="4" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PRESET_MEDIUMROOM" - type="short" - transient="false" - volatile="false" - value="2" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PRESET_NONE" - type="short" - transient="false" - volatile="false" - value="0" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PRESET_PLATE" - type="short" - transient="false" - volatile="false" - value="6" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PRESET_SMALLROOM" - type="short" - transient="false" - volatile="false" - value="1" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -</class> -<interface name="PresetReverb.OnParameterChangeListener" - abstract="true" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<method name="onParameterChange" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="effect" type="android.media.PresetReverb"> -</parameter> -<parameter name="status" type="int"> -</parameter> -<parameter name="param" type="int"> -</parameter> -<parameter name="value" type="short"> -</parameter> -</method> -</interface> -<class name="PresetReverb.Settings" - extends="java.lang.Object" - abstract="false" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="PresetReverb.Settings" - type="android.media.PresetReverb.Settings" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</constructor> -<constructor name="PresetReverb.Settings" - type="android.media.PresetReverb.Settings" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="settings" type="java.lang.String"> -</parameter> -</constructor> -<field name="preset" - type="short" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> -</class> <class name="Ringtone" extends="java.lang.Object" abstract="false" @@ -105416,8 +102707,2133 @@ > </field> </class> +</package> +<package name="android.media.audiofx" +> +<class name="AudioEffect" + extends="java.lang.Object" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="getDescriptor" + return="android.media.audiofx.AudioEffect.Descriptor" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +</method> +<method name="getEnabled" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +</method> +<method name="getId" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +</method> +<method name="hasControl" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +</method> +<method name="queryEffects" + return="android.media.audiofx.AudioEffect.Descriptor[]" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="release" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="setControlStatusListener" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="listener" type="android.media.audiofx.AudioEffect.OnControlStatusChangeListener"> +</parameter> +</method> +<method name="setEnableStatusListener" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="listener" type="android.media.audiofx.AudioEffect.OnEnableStatusChangeListener"> +</parameter> +</method> +<method name="setEnabled" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="enabled" type="boolean"> +</parameter> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +</method> +<field name="ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ALREADY_EXISTS" + type="int" + transient="false" + volatile="false" + value="-2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="CONTENT_TYPE_GAME" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="CONTENT_TYPE_MOVIE" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="CONTENT_TYPE_MUSIC" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="CONTENT_TYPE_VOICE" + type="int" + transient="false" + volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EFFECT_AUXILIARY" + type="java.lang.String" + transient="false" + volatile="false" + value=""Auxiliary"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EFFECT_INSERT" + type="java.lang.String" + transient="false" + volatile="false" + value=""Insert"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR" + type="int" + transient="false" + volatile="false" + value="-1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR_BAD_VALUE" + type="int" + transient="false" + volatile="false" + value="-4" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR_DEAD_OBJECT" + type="int" + transient="false" + volatile="false" + value="-7" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR_INVALID_OPERATION" + type="int" + transient="false" + volatile="false" + value="-5" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR_NO_INIT" + type="int" + transient="false" + volatile="false" + value="-3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ERROR_NO_MEMORY" + type="int" + transient="false" + volatile="false" + value="-6" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_AUDIO_SESSION" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.extra.AUDIO_SESSION"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_CONTENT_TYPE" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.extra.CONTENT_TYPE"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_PACKAGE_NAME" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.extra.PACKAGE_NAME"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="SUCCESS" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<class name="AudioEffect.Descriptor" + extends="java.lang.Object" + abstract="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="AudioEffect.Descriptor" + type="android.media.audiofx.AudioEffect.Descriptor" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<constructor name="AudioEffect.Descriptor" + type="android.media.audiofx.AudioEffect.Descriptor" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="type" type="java.lang.String"> +</parameter> +<parameter name="uuid" type="java.lang.String"> +</parameter> +<parameter name="connectMode" type="java.lang.String"> +</parameter> +<parameter name="name" type="java.lang.String"> +</parameter> +<parameter name="implementor" type="java.lang.String"> +</parameter> +</constructor> +<field name="connectMode" + type="java.lang.String" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="implementor" + type="java.lang.String" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="name" + type="java.lang.String" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="type" + type="java.util.UUID" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="uuid" + type="java.util.UUID" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<interface name="AudioEffect.OnControlStatusChangeListener" + abstract="true" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="onControlStatusChange" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="effect" type="android.media.audiofx.AudioEffect"> +</parameter> +<parameter name="controlGranted" type="boolean"> +</parameter> +</method> +</interface> +<interface name="AudioEffect.OnEnableStatusChangeListener" + abstract="true" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="onEnableStatusChange" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="effect" type="android.media.audiofx.AudioEffect"> +</parameter> +<parameter name="enabled" type="boolean"> +</parameter> +</method> +</interface> +<class name="BassBoost" + extends="android.media.audiofx.AudioEffect" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="BassBoost" + type="android.media.audiofx.BassBoost" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="priority" type="int"> +</parameter> +<parameter name="audioSession" type="int"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="RuntimeException" type="java.lang.RuntimeException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</constructor> +<method name="getProperties" + return="android.media.audiofx.BassBoost.Settings" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getRoundedStrength" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getStrengthSupported" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="setParameterListener" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="listener" type="android.media.audiofx.BassBoost.OnParameterChangeListener"> +</parameter> +</method> +<method name="setProperties" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="settings" type="android.media.audiofx.BassBoost.Settings"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setStrength" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="strength" type="short"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<field name="PARAM_STRENGTH" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_STRENGTH_SUPPORTED" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<interface name="BassBoost.OnParameterChangeListener" + abstract="true" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="onParameterChange" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="effect" type="android.media.audiofx.BassBoost"> +</parameter> +<parameter name="status" type="int"> +</parameter> +<parameter name="param" type="int"> +</parameter> +<parameter name="value" type="short"> +</parameter> +</method> +</interface> +<class name="BassBoost.Settings" + extends="java.lang.Object" + abstract="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="BassBoost.Settings" + type="android.media.audiofx.BassBoost.Settings" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<constructor name="BassBoost.Settings" + type="android.media.audiofx.BassBoost.Settings" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="settings" type="java.lang.String"> +</parameter> +</constructor> +<field name="strength" + type="short" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<class name="EnvironmentalReverb" + extends="android.media.audiofx.AudioEffect" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="EnvironmentalReverb" + type="android.media.audiofx.EnvironmentalReverb" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="priority" type="int"> +</parameter> +<parameter name="audioSession" type="int"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="RuntimeException" type="java.lang.RuntimeException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</constructor> +<method name="getDecayHFRatio" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getDecayTime" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getDensity" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getDiffusion" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getProperties" + return="android.media.audiofx.EnvironmentalReverb.Settings" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getReflectionsDelay" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getReflectionsLevel" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getReverbDelay" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getReverbLevel" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getRoomHFLevel" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getRoomLevel" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setDecayHFRatio" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="decayHFRatio" type="short"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setDecayTime" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="decayTime" type="int"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setDensity" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="density" type="short"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setDiffusion" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="diffusion" type="short"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setParameterListener" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="listener" type="android.media.audiofx.EnvironmentalReverb.OnParameterChangeListener"> +</parameter> +</method> +<method name="setProperties" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="settings" type="android.media.audiofx.EnvironmentalReverb.Settings"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setReflectionsDelay" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="reflectionsDelay" type="int"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setReflectionsLevel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="reflectionsLevel" type="short"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setReverbDelay" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="reverbDelay" type="int"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setReverbLevel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="reverbLevel" type="short"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setRoomHFLevel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="roomHF" type="short"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setRoomLevel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="room" type="short"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<field name="PARAM_DECAY_HF_RATIO" + type="int" + transient="false" + volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_DECAY_TIME" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_DENSITY" + type="int" + transient="false" + volatile="false" + value="9" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_DIFFUSION" + type="int" + transient="false" + volatile="false" + value="8" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_REFLECTIONS_DELAY" + type="int" + transient="false" + volatile="false" + value="5" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_REFLECTIONS_LEVEL" + type="int" + transient="false" + volatile="false" + value="4" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_REVERB_DELAY" + type="int" + transient="false" + volatile="false" + value="7" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_REVERB_LEVEL" + type="int" + transient="false" + volatile="false" + value="6" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_ROOM_HF_LEVEL" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_ROOM_LEVEL" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<interface name="EnvironmentalReverb.OnParameterChangeListener" + abstract="true" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="onParameterChange" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="effect" type="android.media.audiofx.EnvironmentalReverb"> +</parameter> +<parameter name="status" type="int"> +</parameter> +<parameter name="param" type="int"> +</parameter> +<parameter name="value" type="int"> +</parameter> +</method> +</interface> +<class name="EnvironmentalReverb.Settings" + extends="java.lang.Object" + abstract="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="EnvironmentalReverb.Settings" + type="android.media.audiofx.EnvironmentalReverb.Settings" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<constructor name="EnvironmentalReverb.Settings" + type="android.media.audiofx.EnvironmentalReverb.Settings" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="settings" type="java.lang.String"> +</parameter> +</constructor> +<field name="decayHFRatio" + type="short" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="decayTime" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="density" + type="short" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="diffusion" + type="short" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="reflectionsDelay" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="reflectionsLevel" + type="short" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="reverbDelay" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="reverbLevel" + type="short" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="roomHFLevel" + type="short" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="roomLevel" + type="short" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<class name="Equalizer" + extends="android.media.audiofx.AudioEffect" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="Equalizer" + type="android.media.audiofx.Equalizer" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="priority" type="int"> +</parameter> +<parameter name="audioSession" type="int"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="RuntimeException" type="java.lang.RuntimeException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</constructor> +<method name="getBand" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="frequency" type="int"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getBandFreqRange" + return="int[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="band" type="short"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getBandLevel" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="band" type="short"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getBandLevelRange" + return="short[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getCenterFreq" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="band" type="short"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getCurrentPreset" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getNumberOfBands" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getNumberOfPresets" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getPresetName" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="preset" type="short"> +</parameter> +</method> +<method name="getProperties" + return="android.media.audiofx.Equalizer.Settings" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setBandLevel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="band" type="short"> +</parameter> +<parameter name="level" type="short"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setParameterListener" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="listener" type="android.media.audiofx.Equalizer.OnParameterChangeListener"> +</parameter> +</method> +<method name="setProperties" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="settings" type="android.media.audiofx.Equalizer.Settings"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="usePreset" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="preset" type="short"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<field name="PARAM_BAND_FREQ_RANGE" + type="int" + transient="false" + volatile="false" + value="4" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_BAND_LEVEL" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_CENTER_FREQ" + type="int" + transient="false" + volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_CURRENT_PRESET" + type="int" + transient="false" + volatile="false" + value="6" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_GET_BAND" + type="int" + transient="false" + volatile="false" + value="5" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_GET_NUM_OF_PRESETS" + type="int" + transient="false" + volatile="false" + value="7" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_GET_PRESET_NAME" + type="int" + transient="false" + volatile="false" + value="8" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_LEVEL_RANGE" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_NUM_BANDS" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PARAM_STRING_SIZE_MAX" + type="int" + transient="false" + volatile="false" + value="32" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<interface name="Equalizer.OnParameterChangeListener" + abstract="true" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="onParameterChange" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="effect" type="android.media.audiofx.Equalizer"> +</parameter> +<parameter name="status" type="int"> +</parameter> +<parameter name="param1" type="int"> +</parameter> +<parameter name="param2" type="int"> +</parameter> +<parameter name="value" type="int"> +</parameter> +</method> +</interface> +<class name="Equalizer.Settings" + extends="java.lang.Object" + abstract="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="Equalizer.Settings" + type="android.media.audiofx.Equalizer.Settings" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<constructor name="Equalizer.Settings" + type="android.media.audiofx.Equalizer.Settings" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="settings" type="java.lang.String"> +</parameter> +</constructor> +<field name="bandLevels" + type="short[]" + transient="false" + volatile="false" + value="null" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="curPreset" + type="short" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="numBands" + type="short" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<class name="PresetReverb" + extends="android.media.audiofx.AudioEffect" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="PresetReverb" + type="android.media.audiofx.PresetReverb" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="priority" type="int"> +</parameter> +<parameter name="audioSession" type="int"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="RuntimeException" type="java.lang.RuntimeException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</constructor> +<method name="getPreset" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="getProperties" + return="android.media.audiofx.PresetReverb.Settings" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setParameterListener" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="listener" type="android.media.audiofx.PresetReverb.OnParameterChangeListener"> +</parameter> +</method> +<method name="setPreset" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="preset" type="short"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<method name="setProperties" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="settings" type="android.media.audiofx.PresetReverb.Settings"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="IllegalStateException" type="java.lang.IllegalStateException"> +</exception> +<exception name="UnsupportedOperationException" type="java.lang.UnsupportedOperationException"> +</exception> +</method> +<field name="PARAM_PRESET" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PRESET_LARGEHALL" + type="short" + transient="false" + volatile="false" + value="5" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PRESET_LARGEROOM" + type="short" + transient="false" + volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PRESET_MEDIUMHALL" + type="short" + transient="false" + volatile="false" + value="4" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PRESET_MEDIUMROOM" + type="short" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PRESET_NONE" + type="short" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PRESET_PLATE" + type="short" + transient="false" + volatile="false" + value="6" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PRESET_SMALLROOM" + type="short" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<interface name="PresetReverb.OnParameterChangeListener" + abstract="true" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="onParameterChange" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="effect" type="android.media.audiofx.PresetReverb"> +</parameter> +<parameter name="status" type="int"> +</parameter> +<parameter name="param" type="int"> +</parameter> +<parameter name="value" type="short"> +</parameter> +</method> +</interface> +<class name="PresetReverb.Settings" + extends="java.lang.Object" + abstract="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="PresetReverb.Settings" + type="android.media.audiofx.PresetReverb.Settings" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<constructor name="PresetReverb.Settings" + type="android.media.audiofx.PresetReverb.Settings" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="settings" type="java.lang.String"> +</parameter> +</constructor> +<field name="preset" + type="short" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> <class name="Virtualizer" - extends="android.media.AudioEffect" + extends="android.media.audiofx.AudioEffect" abstract="false" static="false" final="false" @@ -105425,7 +104841,7 @@ visibility="public" > <constructor name="Virtualizer" - type="android.media.Virtualizer" + type="android.media.audiofx.Virtualizer" static="false" final="false" deprecated="not deprecated" @@ -105445,7 +104861,7 @@ </exception> </constructor> <method name="getProperties" - return="android.media.Virtualizer.Settings" + return="android.media.audiofx.Virtualizer.Settings" abstract="false" native="false" synchronized="false" @@ -105499,7 +104915,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="listener" type="android.media.Virtualizer.OnParameterChangeListener"> +<parameter name="listener" type="android.media.audiofx.Virtualizer.OnParameterChangeListener"> </parameter> </method> <method name="setProperties" @@ -105512,7 +104928,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="settings" type="android.media.Virtualizer.Settings"> +<parameter name="settings" type="android.media.audiofx.Virtualizer.Settings"> </parameter> <exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> </exception> @@ -105580,7 +104996,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="effect" type="android.media.Virtualizer"> +<parameter name="effect" type="android.media.audiofx.Virtualizer"> </parameter> <parameter name="status" type="int"> </parameter> @@ -105599,7 +105015,7 @@ visibility="public" > <constructor name="Virtualizer.Settings" - type="android.media.Virtualizer.Settings" + type="android.media.audiofx.Virtualizer.Settings" static="false" final="false" deprecated="not deprecated" @@ -105607,7 +105023,7 @@ > </constructor> <constructor name="Virtualizer.Settings" - type="android.media.Virtualizer.Settings" + type="android.media.audiofx.Virtualizer.Settings" static="false" final="false" deprecated="not deprecated" @@ -105636,7 +105052,7 @@ visibility="public" > <constructor name="Visualizer" - type="android.media.Visualizer" + type="android.media.audiofx.Visualizer" static="false" final="false" deprecated="not deprecated" @@ -105774,7 +105190,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="listener" type="android.media.Visualizer.OnDataCaptureListener"> +<parameter name="listener" type="android.media.audiofx.Visualizer.OnDataCaptureListener"> </parameter> <parameter name="rate" type="int"> </parameter> @@ -105937,7 +105353,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="visualizer" type="android.media.Visualizer"> +<parameter name="visualizer" type="android.media.audiofx.Visualizer"> </parameter> <parameter name="fft" type="byte[]"> </parameter> @@ -105954,7 +105370,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="visualizer" type="android.media.Visualizer"> +<parameter name="visualizer" type="android.media.audiofx.Visualizer"> </parameter> <parameter name="waveform" type="byte[]"> </parameter> @@ -106881,6 +106297,21 @@ <parameter name="uri" type="android.net.Uri"> </parameter> </constructor> +<method name="addRequestHeader" + return="android.net.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="header" type="java.lang.String"> +</parameter> +<parameter name="value" type="java.lang.String"> +</parameter> +</method> <method name="setAllowedNetworkTypes" return="android.net.DownloadManager.Request" abstract="false" @@ -106917,10 +106348,10 @@ deprecated="not deprecated" visibility="public" > -<parameter name="description" type="java.lang.String"> +<parameter name="description" type="java.lang.CharSequence"> </parameter> </method> -<method name="setDestinationUri" +<method name="setDestinationInExternalFilesDir" return="android.net.DownloadManager.Request" abstract="false" native="false" @@ -106930,10 +106361,14 @@ deprecated="not deprecated" visibility="public" > -<parameter name="uri" type="android.net.Uri"> +<parameter name="context" type="android.content.Context"> +</parameter> +<parameter name="dirType" type="java.lang.String"> +</parameter> +<parameter name="subPath" type="java.lang.String"> </parameter> </method> -<method name="setMediaType" +<method name="setDestinationInExternalPublicDir" return="android.net.DownloadManager.Request" abstract="false" native="false" @@ -106943,10 +106378,12 @@ deprecated="not deprecated" visibility="public" > -<parameter name="mediaType" type="java.lang.String"> +<parameter name="dirType" type="java.lang.String"> +</parameter> +<parameter name="subPath" type="java.lang.String"> </parameter> </method> -<method name="setRequestHeader" +<method name="setDestinationUri" return="android.net.DownloadManager.Request" abstract="false" native="false" @@ -106956,9 +106393,20 @@ deprecated="not deprecated" visibility="public" > -<parameter name="header" type="java.lang.String"> +<parameter name="uri" type="android.net.Uri"> </parameter> -<parameter name="value" type="java.lang.String"> +</method> +<method name="setMimeType" + return="android.net.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="mimeType" type="java.lang.String"> </parameter> </method> <method name="setShowRunningNotification" @@ -106984,7 +106432,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="title" type="java.lang.String"> +<parameter name="title" type="java.lang.CharSequence"> </parameter> </method> <method name="setVisibleInDownloadsUi" @@ -107022,17 +106470,6 @@ visibility="public" > </field> -<field name="NETWORK_WIMAX" - type="int" - transient="false" - volatile="false" - value="4" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> </class> <class name="LocalServerSocket" extends="java.lang.Object" diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index f901bfb..4dee350 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -19,6 +19,7 @@ package com.android.commands.am; import android.app.ActivityManagerNative; +import android.app.IActivityController; import android.app.IActivityManager; import android.app.IInstrumentationWatcher; import android.app.Instrumentation; @@ -28,12 +29,18 @@ import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.ParcelFileDescriptor; +import android.os.RemoteException; import android.os.ServiceManager; import android.util.AndroidException; import android.view.IWindowManager; +import java.io.BufferedReader; +import java.io.DataInputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; import java.io.PrintStream; import java.net.URISyntaxException; import java.util.Iterator; @@ -99,6 +106,8 @@ public class Am { runProfile(); } else if (op.equals("dumpheap")) { runDumpHeap(); + } else if (op.equals("monitor")) { + runMonitor(); } else { throw new IllegalArgumentException("Unknown command: " + op); } @@ -472,6 +481,210 @@ public class Am { } } + class MyActivityController extends IActivityController.Stub { + static final int STATE_NORMAL = 0; + static final int STATE_CRASHED = 1; + static final int STATE_EARLY_ANR = 2; + static final int STATE_ANR = 3; + + int mState; + + static final int RESULT_DEFAULT = 0; + + static final int RESULT_CRASH_DIALOG = 0; + static final int RESULT_CRASH_KILL = 1; + + static final int RESULT_EARLY_ANR_CONTINUE = 0; + static final int RESULT_EARLY_ANR_KILL = 1; + + static final int RESULT_ANR_DIALOG = 0; + static final int RESULT_ANR_KILL = 1; + static final int RESULT_ANR_WAIT = 1; + + int mResult; + + @Override + public boolean activityResuming(String pkg) throws RemoteException { + synchronized (this) { + System.out.println("** Activity resuming: " + pkg); + } + return true; + } + + @Override + public boolean activityStarting(Intent intent, String pkg) throws RemoteException { + synchronized (this) { + System.out.println("** Activity starting: " + pkg); + } + return true; + } + + @Override + public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg, + long timeMillis, String stackTrace) throws RemoteException { + synchronized (this) { + System.out.println("** ERROR: PROCESS CRASHED"); + System.out.println("processName: " + processName); + System.out.println("processPid: " + pid); + System.out.println("shortMsg: " + shortMsg); + System.out.println("longMsg: " + longMsg); + System.out.println("timeMillis: " + timeMillis); + System.out.println("stack:"); + System.out.print(stackTrace); + System.out.println("#"); + int result = waitControllerLocked(STATE_CRASHED); + return result == RESULT_CRASH_KILL ? false : true; + } + } + + @Override + public int appEarlyNotResponding(String processName, int pid, String annotation) + throws RemoteException { + synchronized (this) { + System.out.println("** ERROR: EARLY PROCESS NOT RESPONDING"); + System.out.println("processName: " + processName); + System.out.println("processPid: " + pid); + System.out.println("annotation: " + annotation); + int result = waitControllerLocked(STATE_EARLY_ANR); + if (result == RESULT_EARLY_ANR_KILL) return -1; + return 0; + } + } + + @Override + public int appNotResponding(String processName, int pid, String processStats) + throws RemoteException { + synchronized (this) { + System.out.println("** ERROR: PROCESS NOT RESPONDING"); + System.out.println("processName: " + processName); + System.out.println("processPid: " + pid); + System.out.println("processStats:"); + System.out.print(processStats); + System.out.println("#"); + int result = waitControllerLocked(STATE_ANR); + if (result == RESULT_ANR_KILL) return -1; + if (result == RESULT_ANR_WAIT) return 1; + return 0; + } + } + + int waitControllerLocked(int state) { + mState = state; + System.out.println(""); + printMessageForState(); + + while (mState != STATE_NORMAL) { + try { + wait(); + } catch (InterruptedException e) { + } + } + + return mResult; + } + + void resumeController(int result) { + synchronized (this) { + mState = STATE_NORMAL; + mResult = result; + notifyAll(); + } + } + + void printMessageForState() { + switch (mState) { + case STATE_NORMAL: + System.out.println("Monitoring activity manager... available commands:"); + break; + case STATE_CRASHED: + System.out.println("Waiting after crash... available commands:"); + System.out.println("(c)ontinue: show crash dialog"); + System.out.println("(k)ill: immediately kill app"); + break; + case STATE_EARLY_ANR: + System.out.println("Waiting after early ANR... available commands:"); + System.out.println("(c)ontinue: standard ANR processing"); + System.out.println("(k)ill: immediately kill app"); + break; + case STATE_ANR: + System.out.println("Waiting after ANR... available commands:"); + System.out.println("(c)ontinue: show ANR dialog"); + System.out.println("(k)ill: immediately kill app"); + System.out.println("(w)ait: wait some more"); + break; + } + System.out.println("(q)uit: finish monitoring"); + } + + void run() throws RemoteException { + try { + printMessageForState(); + + mAm.setActivityController(this); + mState = STATE_NORMAL; + + InputStreamReader converter = new InputStreamReader(System.in); + BufferedReader in = new BufferedReader(converter); + String line; + + while ((line = in.readLine()) != null) { + boolean addNewline = true; + if (line.length() <= 0) { + addNewline = false; + } else if ("q".equals(line) || "quit".equals(line)) { + resumeController(RESULT_DEFAULT); + break; + } else if (mState == STATE_CRASHED) { + if ("c".equals(line) || "continue".equals(line)) { + resumeController(RESULT_CRASH_DIALOG); + } else if ("k".equals(line) || "kill".equals(line)) { + resumeController(RESULT_CRASH_KILL); + } else { + System.out.println("Invalid command: " + line); + } + } else if (mState == STATE_ANR) { + if ("c".equals(line) || "continue".equals(line)) { + resumeController(RESULT_ANR_DIALOG); + } else if ("k".equals(line) || "kill".equals(line)) { + resumeController(RESULT_ANR_KILL); + } else if ("w".equals(line) || "wait".equals(line)) { + resumeController(RESULT_ANR_WAIT); + } else { + System.out.println("Invalid command: " + line); + } + } else if (mState == STATE_EARLY_ANR) { + if ("c".equals(line) || "continue".equals(line)) { + resumeController(RESULT_EARLY_ANR_CONTINUE); + } else if ("k".equals(line) || "kill".equals(line)) { + resumeController(RESULT_EARLY_ANR_KILL); + } else { + System.out.println("Invalid command: " + line); + } + } else { + System.out.println("Invalid command: " + line); + } + + synchronized (this) { + if (addNewline) { + System.out.println(""); + } + printMessageForState(); + } + } + + } catch (IOException e) { + e.printStackTrace(); + } finally { + mAm.setActivityController(null); + } + } + } + + private void runMonitor() throws Exception { + MyActivityController controller = new MyActivityController(); + controller.run(); + } + private class IntentReceiver extends IIntentReceiver.Stub { private boolean mFinished = false; @@ -649,6 +862,8 @@ public class Am { " dump heap: am dumpheap [flags] <PROCESS> <FILE>\n" + " -n: dump native heap instead of managed heap\n" + "\n" + + " start monitoring: am monitor\n" + + "\n" + " <INTENT> specifications include these flags:\n" + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 1e2bbcc..02b2dce 100755 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -614,6 +614,17 @@ public class ValueAnimator<T> extends Animator { } /** + * Removes all listeners from the set listening to frame updates for this animation. + */ + public void removeAllUpdateListeners() { + if (mUpdateListeners == null) { + return; + } + mUpdateListeners.clear(); + mUpdateListeners = null; + } + + /** * Removes a listener from the set listening to frame updates for this animation. * * @param listener the listener to be removed from the current set of update listeners @@ -685,7 +696,15 @@ public class ValueAnimator<T> extends Animator { */ private void start(boolean playBackwards) { mPlayingBackwards = playBackwards; - if ((mStartDelay == 0) && (Thread.currentThread() == Looper.getMainLooper().getThread())) { + Looper looper = Looper.getMainLooper(); + final boolean isUiThread; + if (looper != null) { + isUiThread = Thread.currentThread() == looper.getThread(); + } else { + // ignore check if we don't have a Looper (this isn't an Activity) + isUiThread = true; + } + if ((mStartDelay == 0) && isUiThread) { if (mListeners != null) { ArrayList<AnimatorListener> tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 3f74904..2ff88da 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -61,6 +61,7 @@ import android.util.Config; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; +import android.util.LogPrinter; import android.util.Slog; import android.view.Display; import android.view.HardwareRenderer; @@ -121,6 +122,7 @@ public final class ActivityThread { private static final android.graphics.Bitmap.Config THUMBNAIL_FORMAT = Bitmap.Config.RGB_565; private static final boolean DEBUG = false; static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; + static final boolean DEBUG_MESSAGES = false; static final boolean DEBUG_BROADCAST = false; private static final boolean DEBUG_RESULTS = false; private static final boolean DEBUG_BACKUP = false; @@ -913,7 +915,7 @@ public final class ActivityThread { public static final int DUMP_HEAP = 135; public static final int DUMP_ACTIVITY = 136; String codeToString(int code) { - if (localLOGV) { + if (DEBUG_MESSAGES) { switch (code) { case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY"; case PAUSE_ACTIVITY: return "PAUSE_ACTIVITY"; @@ -957,6 +959,7 @@ public final class ActivityThread { return "(unknown)"; } public void handleMessage(Message msg) { + if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + msg.what); switch (msg.what) { case LAUNCH_ACTIVITY: { ActivityClientRecord r = (ActivityClientRecord)msg.obj; @@ -1084,6 +1087,7 @@ public final class ActivityThread { handleDumpActivity((DumpComponentInfo)msg.obj); break; } + if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what); } void maybeSnapshot() { @@ -1550,7 +1554,7 @@ public final class ActivityThread { private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) { synchronized (this) { - if (localLOGV) Slog.v( + if (DEBUG_MESSAGES) Slog.v( TAG, "SCHEDULE " + what + " " + mH.codeToString(what) + ": " + arg1 + " / " + obj); Message msg = Message.obtain(); @@ -3699,6 +3703,11 @@ public final class ActivityThread { ActivityThread thread = new ActivityThread(); thread.attach(false); + if (false) { + Looper.myLooper().setMessageLogging(new + LogPrinter(Log.DEBUG, "ActivityThread")); + } + Looper.loop(); if (Process.supportsProcesses()) { diff --git a/core/java/android/app/IActivityController.aidl b/core/java/android/app/IActivityController.aidl index c76a517..aca8305 100644 --- a/core/java/android/app/IActivityController.aidl +++ b/core/java/android/app/IActivityController.aidl @@ -48,6 +48,11 @@ interface IActivityController long timeMillis, String stackTrace); /** + * Early call as soon as an ANR is detected. + */ + int appEarlyNotResponding(String processName, int pid, String annotation); + + /** * An application process is not responding. Return 0 to show the "app * not responding" dialog, 1 to continue waiting, or -1 to kill it * immediately. diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/net/DownloadManager.java index fc5ebb3..12c05cc 100644 --- a/core/java/android/net/DownloadManager.java +++ b/core/java/android/net/DownloadManager.java @@ -19,19 +19,21 @@ package android.net; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; +import android.content.Context; import android.database.Cursor; import android.database.CursorWrapper; +import android.os.Environment; import android.os.ParcelFileDescriptor; import android.provider.BaseColumns; import android.provider.Downloads; +import android.util.Pair; +import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; /** @@ -245,6 +247,7 @@ public class DownloadManager { Downloads.COLUMN_LAST_MODIFICATION, Downloads.COLUMN_DESTINATION, Downloads.Impl.COLUMN_FILE_NAME_HINT, + Downloads.Impl._DATA, }; private static final Set<String> LONG_COLUMNS = new HashSet<String>( @@ -252,8 +255,12 @@ public class DownloadManager { COLUMN_BYTES_DOWNLOADED_SO_FAR, COLUMN_LAST_MODIFIED_TIMESTAMP)); /** - * This class contains all the information necessary to request a new download. The URI is the + * This class contains all the information necessary to request a new download. The URI is the * only required parameter. + * + * Note that the default download destination is a shared volume where the system might delete + * your file if it needs to reclaim space for system use. If this is a problem, use a location + * on external storage (see {@link #setDestinationUri(Uri)}. */ public static class Request { /** @@ -268,19 +275,13 @@ public class DownloadManager { */ public static final int NETWORK_WIFI = 1 << 1; - /** - * Bit flag for {@link #setAllowedNetworkTypes} corresponding to - * {@link ConnectivityManager#TYPE_WIMAX}. - */ - public static final int NETWORK_WIMAX = 1 << 2; - private Uri mUri; private Uri mDestinationUri; - private Map<String, String> mRequestHeaders = new HashMap<String, String>(); - private String mTitle; - private String mDescription; + private List<Pair<String, String>> mRequestHeaders = new ArrayList<Pair<String, String>>(); + private CharSequence mTitle; + private CharSequence mDescription; private boolean mShowNotification = true; - private String mMediaType; + private String mMimeType; private boolean mRoamingAllowed = true; private int mAllowedNetworkTypes = ~0; // default to all network types allowed private boolean mIsVisibleInDownloadsUi = true; @@ -300,12 +301,12 @@ public class DownloadManager { } /** - * Set the local destination for the downloaded data. Must be a file URI to a path on + * Set the local destination for the downloaded file. Must be a file URI to a path on * external storage, and the calling application must have the WRITE_EXTERNAL_STORAGE * permission. * - * By default, downloads are saved to a generated file in the download cache and may be - * deleted by the download manager at any time. + * By default, downloads are saved to a generated filename in the shared download cache and + * may be deleted by the system at any time to reclaim space. * * @return this object */ @@ -315,13 +316,62 @@ public class DownloadManager { } /** - * Set an HTTP header to be included with the download request. + * Set the local destination for the downloaded file to a path within the application's + * external files directory (as returned by {@link Context#getExternalFilesDir(String)}. + * + * @param context the {@link Context} to use in determining the external files directory + * @param dirType the directory type to pass to {@link Context#getExternalFilesDir(String)} + * @param subPath the path within the external directory, including the destination filename + * @return this object + */ + public Request setDestinationInExternalFilesDir(Context context, String dirType, + String subPath) { + setDestinationFromBase(context.getExternalFilesDir(dirType), subPath); + return this; + } + + /** + * Set the local destination for the downloaded file to a path within the public external + * storage directory (as returned by + * {@link Environment#getExternalStoragePublicDirectory(String)}. + * + * @param dirType the directory type to pass to + * {@link Environment#getExternalStoragePublicDirectory(String)} + * @param subPath the path within the external directory, including the destination filename + * @return this object + */ + public Request setDestinationInExternalPublicDir(String dirType, String subPath) { + setDestinationFromBase(Environment.getExternalStoragePublicDirectory(dirType), subPath); + return this; + } + + private void setDestinationFromBase(File base, String subPath) { + if (subPath == null) { + throw new NullPointerException("subPath cannot be null"); + } + mDestinationUri = Uri.withAppendedPath(Uri.fromFile(base), subPath); + } + + /** + * Add an HTTP header to be included with the download request. The header will be added to + * the end of the list. * @param header HTTP header name * @param value header value * @return this object + * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2">HTTP/1.1 + * Message Headers</a> */ - public Request setRequestHeader(String header, String value) { - mRequestHeaders.put(header, value); + public Request addRequestHeader(String header, String value) { + if (header == null) { + throw new NullPointerException("header cannot be null"); + } + if (header.contains(":")) { + throw new IllegalArgumentException("header may not contain ':'"); + } + if (value == null) { + value = ""; + } + mRequestHeaders.add(Pair.create(header, value)); return this; } @@ -329,7 +379,7 @@ public class DownloadManager { * Set the title of this download, to be displayed in notifications (if enabled) * @return this object */ - public Request setTitle(String title) { + public Request setTitle(CharSequence title) { mTitle = title; return this; } @@ -338,19 +388,20 @@ public class DownloadManager { * Set a description of this download, to be displayed in notifications (if enabled) * @return this object */ - public Request setDescription(String description) { + public Request setDescription(CharSequence description) { mDescription = description; return this; } /** - * Set the Internet Media Type of this download. This will override the media type declared + * Set the MIME content type of this download. This will override the content type declared * in the server's response. - * @see <a href="http://www.ietf.org/rfc/rfc1590.txt">RFC 1590, defining Media Types</a> + * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7">HTTP/1.1 + * Media Types</a> * @return this object */ - public Request setMediaType(String mediaType) { - mMediaType = mediaType; + public Request setMimeType(String mimeType) { + mMimeType = mimeType; return this; } @@ -428,7 +479,7 @@ public class DownloadManager { putIfNonNull(values, Downloads.COLUMN_TITLE, mTitle); putIfNonNull(values, Downloads.COLUMN_DESCRIPTION, mDescription); - putIfNonNull(values, Downloads.COLUMN_MIME_TYPE, mMediaType); + putIfNonNull(values, Downloads.COLUMN_MIME_TYPE, mMimeType); values.put(Downloads.COLUMN_VISIBILITY, mShowNotification ? Downloads.VISIBILITY_VISIBLE @@ -443,16 +494,16 @@ public class DownloadManager { private void encodeHttpHeaders(ContentValues values) { int index = 0; - for (Map.Entry<String, String> entry : mRequestHeaders.entrySet()) { - String headerString = entry.getKey() + ": " + entry.getValue(); + for (Pair<String, String> header : mRequestHeaders) { + String headerString = header.first + ": " + header.second; values.put(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX + index, headerString); index++; } } - private void putIfNonNull(ContentValues contentValues, String key, String value) { + private void putIfNonNull(ContentValues contentValues, String key, Object value) { if (value != null) { - contentValues.put(key, value); + contentValues.put(key, value.toString()); } } } @@ -831,6 +882,11 @@ public class DownloadManager { return getUnderlyingString(Downloads.Impl.COLUMN_FILE_NAME_HINT); } + if (destinationType == Downloads.Impl.DESTINATION_EXTERNAL) { + // return stored destination for legacy external download + return Uri.fromFile(new File(getUnderlyingString(Downloads.Impl._DATA))).toString(); + } + // return content URI for cache download long downloadId = getUnderlyingLong(Downloads.Impl._ID); return ContentUris.withAppendedId(mBaseUri, downloadId).toString(); diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index ba8014f..d49c8be 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -301,7 +301,11 @@ public abstract class BatteryStats implements Parcelable { */ public static abstract class Proc { - public static class ExcessiveWake { + public static class ExcessivePower { + public static final int TYPE_WAKE = 1; + public static final int TYPE_CPU = 2; + + public int type; public long overTime; public long usedTime; } @@ -343,9 +347,9 @@ public abstract class BatteryStats implements Parcelable { */ public abstract long getTimeAtCpuSpeedStep(int speedStep, int which); - public abstract int countExcessiveWakes(); + public abstract int countExcessivePowers(); - public abstract ExcessiveWake getExcessiveWake(int i); + public abstract ExcessivePower getExcessivePower(int i); } /** @@ -1593,7 +1597,7 @@ public abstract class BatteryStats implements Parcelable { systemTime = ps.getSystemTime(which); starts = ps.getStarts(which); numExcessive = which == STATS_SINCE_CHARGED - ? ps.countExcessiveWakes() : 0; + ? ps.countExcessivePowers() : 0; if (userTime != 0 || systemTime != 0 || starts != 0 || numExcessive != 0) { @@ -1609,9 +1613,17 @@ public abstract class BatteryStats implements Parcelable { } pw.println(sb.toString()); for (int e=0; e<numExcessive; e++) { - Uid.Proc.ExcessiveWake ew = ps.getExcessiveWake(e); + Uid.Proc.ExcessivePower ew = ps.getExcessivePower(e); if (ew != null) { - pw.print(prefix); pw.print(" * Killed for wake lock use: "); + pw.print(prefix); pw.print(" * Killed for "); + if (ew.type == Uid.Proc.ExcessivePower.TYPE_WAKE) { + pw.print("wake lock"); + } else if (ew.type == Uid.Proc.ExcessivePower.TYPE_CPU) { + pw.print("cpu"); + } else { + pw.print("unknown"); + } + pw.print(" use: "); TimeUtils.formatDuration(ew.usedTime, pw); pw.print(" over "); TimeUtils.formatDuration(ew.overTime, pw); diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java index 479497a..7629c31 100644 --- a/core/java/android/preference/PreferenceFragment.java +++ b/core/java/android/preference/PreferenceFragment.java @@ -144,6 +144,7 @@ public abstract class PreferenceFragment extends Fragment implements public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPreferenceManager = new PreferenceManager(getActivity(), FIRST_REQUEST_CODE); + mPreferenceManager.setFragment(this); mPreferenceManager.setOnPreferenceTreeClickListener(this); } diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java index fa83897..42150ed 100644 --- a/core/java/android/preference/PreferenceManager.java +++ b/core/java/android/preference/PreferenceManager.java @@ -16,12 +16,7 @@ package android.preference; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - import android.app.Activity; -import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -34,6 +29,10 @@ import android.content.res.XmlResourceParser; import android.os.Bundle; import android.util.Log; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + /** * Used to help create {@link Preference} hierarchies * from activities or XML. @@ -61,6 +60,11 @@ public class PreferenceManager { private Activity mActivity; /** + * Fragment that owns this instance. + */ + private PreferenceFragment mFragment; + + /** * The context to use. This should always be set. * * @see #mActivity @@ -158,7 +162,21 @@ public class PreferenceManager { setSharedPreferencesName(getDefaultSharedPreferencesName(context)); } - + + /** + * Sets the owning preference fragment + */ + void setFragment(PreferenceFragment fragment) { + mFragment = fragment; + } + + /** + * Returns the owning preference fragment, if any. + */ + PreferenceFragment getFragment() { + return mFragment; + } + /** * Returns a list of {@link Activity} (indirectly) that match a given * {@link Intent}. diff --git a/core/java/android/preference/RingtonePreference.java b/core/java/android/preference/RingtonePreference.java index b46f180..cf14097 100644 --- a/core/java/android/preference/RingtonePreference.java +++ b/core/java/android/preference/RingtonePreference.java @@ -24,7 +24,6 @@ import android.net.Uri; import android.provider.Settings.System; import android.text.TextUtils; import android.util.AttributeSet; -import android.util.Log; /** * A {@link Preference} that allows the user to choose a ringtone from those on the device. @@ -137,7 +136,12 @@ public class RingtonePreference extends Preference implements // Launch the ringtone picker Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); onPrepareRingtonePickerIntent(intent); - getPreferenceManager().getActivity().startActivityForResult(intent, mRequestCode); + PreferenceFragment owningFragment = getPreferenceManager().getFragment(); + if (owningFragment != null) { + owningFragment.startActivityForResult(intent, mRequestCode); + } else { + getPreferenceManager().getActivity().startActivityForResult(intent, mRequestCode); + } } /** diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 3796994..fbb13af 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -19,6 +19,7 @@ package android.view; import android.graphics.Canvas; import android.os.SystemClock; +import android.util.EventLog; import android.util.Log; import javax.microedition.khronos.egl.EGL10; @@ -406,6 +407,11 @@ public abstract class HardwareRenderer { attachInfo.mDrawingTime = SystemClock.uptimeMillis(); attachInfo.mIgnoreDirtyState = true; view.mPrivateFlags |= View.DRAWN; + + long startTime; + if (ViewDebug.DEBUG_PROFILE_DRAWING) { + startTime = SystemClock.elapsedRealtime(); + } checkCurrent(); @@ -423,6 +429,10 @@ public abstract class HardwareRenderer { onPostDraw(); + if (ViewDebug.DEBUG_PROFILE_DRAWING) { + EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime); + } + attachInfo.mIgnoreDirtyState = false; sEgl.eglSwapBuffers(sEglDisplay, mEglSurface); diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 2b92e87..12c49c4 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -1973,8 +1973,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (hasNoCache) { final int multipliedAlpha = (int) (255 * alpha); if (!child.onSetAlpha(multipliedAlpha)) { + int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; + if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) { + layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG; + } canvas.saveLayerAlpha(sx, sy, sx + cr - cl, sy + cb - ct, multipliedAlpha, - Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); + layerFlags); } else { child.mPrivateFlags |= ALPHA_SET; } diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 0321be0..6917bca 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -1711,6 +1711,9 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn deliverPointerEvent(event); } finally { event.recycle(); + if (msg.arg1 != 0) { + finishInputEvent(); + } if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!"); } } break; @@ -1720,6 +1723,9 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn deliverTrackballEvent(event); } finally { event.recycle(); + if (msg.arg1 != 0) { + finishInputEvent(); + } } } break; case DISPATCH_APP_VISIBILITY: @@ -1843,15 +1849,24 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn } } - private void finishKeyEvent(KeyEvent event) { - if (LOCAL_LOGV) Log.v(TAG, "Telling window manager key is finished"); + private void startInputEvent(Runnable finishedCallback) { + if (mFinishedCallback != null) { + Slog.w(TAG, "Received a new input event from the input queue but there is " + + "already an unfinished input event in progress."); + } + + mFinishedCallback = finishedCallback; + } + + private void finishInputEvent() { + if (LOCAL_LOGV) Log.v(TAG, "Telling window manager input event is finished"); if (mFinishedCallback != null) { mFinishedCallback.run(); mFinishedCallback = null; } else { - Slog.w(TAG, "Attempted to tell the input queue that the current key event " - + "is finished but there is no key event actually in progress."); + Slog.w(TAG, "Attempted to tell the input queue that the current input event " + + "is finished but there is no input event actually in progress."); } } @@ -2310,7 +2325,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn boolean handled = mView == null || mView.dispatchKeyEventPreIme(event); if (handled) { if (sendDone) { - finishKeyEvent(event); + finishInputEvent(); } return; } @@ -2340,7 +2355,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn if (!handled) { deliverKeyEventToViewHierarchy(event, sendDone); } else if (sendDone) { - finishKeyEvent(event); + finishInputEvent(); } else { Log.w(TAG, "handleFinishedEvent(seq=" + seq + " handled=" + handled + " ev=" + event @@ -2413,7 +2428,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn } finally { if (sendDone) { - finishKeyEvent(event); + finishInputEvent(); } // Let the exception fall through -- the looper will catch // it and take care of the bad app for us. @@ -2606,20 +2621,13 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn private final InputHandler mInputHandler = new InputHandler() { public void handleKey(KeyEvent event, Runnable finishedCallback) { - if (mFinishedCallback != null) { - Slog.w(TAG, "Received a new key event from the input queue but there is " - + "already an unfinished key event in progress."); - } - - mFinishedCallback = finishedCallback; - + startInputEvent(finishedCallback); dispatchKey(event, true); } public void handleMotion(MotionEvent event, Runnable finishedCallback) { - finishedCallback.run(); - - dispatchMotion(event); + startInputEvent(finishedCallback); + dispatchMotion(event, true); } }; @@ -2651,26 +2659,43 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn } public void dispatchMotion(MotionEvent event) { + dispatchMotion(event, false); + } + + private void dispatchMotion(MotionEvent event, boolean sendDone) { int source = event.getSource(); if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { - dispatchPointer(event); + dispatchPointer(event, sendDone); } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { - dispatchTrackball(event); + dispatchTrackball(event, sendDone); } else { // TODO Log.v(TAG, "Dropping unsupported motion event (unimplemented): " + event); + if (sendDone) { + finishInputEvent(); + } } } public void dispatchPointer(MotionEvent event) { + dispatchPointer(event, false); + } + + private void dispatchPointer(MotionEvent event, boolean sendDone) { Message msg = obtainMessage(DISPATCH_POINTER); msg.obj = event; + msg.arg1 = sendDone ? 1 : 0; sendMessageAtTime(msg, event.getEventTime()); } public void dispatchTrackball(MotionEvent event) { + dispatchTrackball(event, false); + } + + private void dispatchTrackball(MotionEvent event, boolean sendDone) { Message msg = obtainMessage(DISPATCH_TRACKBALL); msg.obj = event; + msg.arg1 = sendDone ? 1 : 0; sendMessageAtTime(msg, event.getEventTime()); } diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java index 3801948..f7c869b 100644 --- a/core/java/android/view/inputmethod/BaseInputConnection.java +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -428,8 +428,12 @@ public class BaseInputConnection implements InputConnection { a = b; b = tmp; } + // Clip the end points to be within the content bounds. + final int length = content.length(); if (a < 0) a = 0; - if (b > content.length()) b = content.length(); + if (b < 0) b = 0; + if (a > length) a = length; + if (b > length) b = length; ensureDefaultComposingSpans(); if (mDefaultComposingSpans != null) { diff --git a/core/java/android/widget/Button.java b/core/java/android/widget/Button.java index 176233e..8d58a6d 100644 --- a/core/java/android/widget/Button.java +++ b/core/java/android/widget/Button.java @@ -25,13 +25,13 @@ import android.widget.RemoteViews.RemoteView; /** - * <p> - * <code>Button</code> represents a push-button widget. Push-buttons can be - * pressed, or clicked, by the user to perform an action. A typical use of a - * push-button in an activity would be the following: + * Represents a push-button widget. Push-buttons can be + * pressed, or clicked, by the user to perform an action. + + * <p>A typical use of a push-button in an activity would be the following: * </p> * - * <pre class="prettyprint"> + * <pre> * public class MyActivity extends Activity { * protected void onCreate(Bundle icicle) { * super.onCreate(icicle); @@ -45,16 +45,52 @@ import android.widget.RemoteViews.RemoteView; * } * }); * } - * } - * </pre> + * }</pre> + * + * <p>However, instead of applying an {@link android.view.View.OnClickListener OnClickListener} to + * the button in your activity, you can assign a method to your button in the XML layout, + * using the {@link android.R.attr#onClick android:onClick} attribute. For example:</p> + * + * <pre> + * <Button + * android:layout_height="wrap_content" + * android:layout_width="wrap_content" + * android:text="@string/self_destruct" + * android:onClick="selfDestruct" /></pre> + * + * <p>Now, when a user clicks the button, the Android system calls the activity's {@code + * selfDestruct(View)} method. In order for this to work, the method must be public and accept + * a {@link android.view.View} as its only parameter. For example:</p> * - * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-formstuff.html">Form Stuff - * tutorial</a>.</p> + * <pre> + * public void selfDestruct(View view) { + * // Kabloey + * }</pre> + * + * <p>The {@link android.view.View} passed into the method is a reference to the widget + * that was clicked.</p> + * + * <h3>Button style</h3> + * + * <p>Every Button is styled using the system's default button background, which is often different + * from one device to another and from one version of the platform to another. If you're not + * satisfied with the default button style and want to customize it to match the design of your + * application, then you can replace the button's background image with a <a + * href="{@docRoot}guide/topics/resources/drawable-resource.html#StateList">state list drawable</a>. + * A state list drawable is a drawable resource defined in XML that changes its image based on + * the current state of the button. Once you've defined a state list drawable in XML, you can apply + * it to your Button with the {@link android.R.attr#background android:background} + * attribute. For more information and an example, see <a + * href="{@docRoot}guide/topics/resources/drawable-resource.html#StateList">State List + * Drawable</a>.</p> + * + * <p>Also see the <a href="{@docRoot}resources/tutorials/views/hello-formstuff.html">Form Stuff + * tutorial</a> for an example implementation of a button.</p> * * <p><strong>XML attributes</strong></p> - * <p> - * See {@link android.R.styleable#Button Button Attributes}, - * {@link android.R.styleable#TextView TextView Attributes}, + * <p> + * See {@link android.R.styleable#Button Button Attributes}, + * {@link android.R.styleable#TextView TextView Attributes}, * {@link android.R.styleable#View View Attributes} * </p> */ diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 4e61ddf..66149ac 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -67,7 +67,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 51; + private static final int VERSION = 52; // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -85,7 +85,7 @@ public final class BatteryStatsImpl extends BatteryStats { static final int MSG_UPDATE_WAKELOCKS = 1; static final int MSG_REPORT_POWER_CHANGE = 2; - static final long DELAY_UPDATE_WAKELOCKS = 15*1000; + static final long DELAY_UPDATE_WAKELOCKS = 5*1000; public interface BatteryCallback { public void batteryNeedsCpuUpdate(); @@ -1476,6 +1476,13 @@ public final class BatteryStatsImpl extends BatteryStats { } } + public void reportExcessiveCpuLocked(int uid, String proc, long overTime, long usedTime) { + Uid u = mUidStats.get(uid); + if (u != null) { + u.reportExcessiveCpuLocked(proc, overTime, usedTime); + } + } + int mSensorNesting; public void noteStartSensorLocked(int uid, int sensor) { @@ -2977,7 +2984,7 @@ public final class BatteryStatsImpl extends BatteryStats { SamplingCounter[] mSpeedBins; - ArrayList<ExcessiveWake> mExcessiveWake; + ArrayList<ExcessivePower> mExcessivePower; Proc() { mUnpluggables.add(this); @@ -3005,55 +3012,69 @@ public final class BatteryStatsImpl extends BatteryStats { } } - public int countExcessiveWakes() { - return mExcessiveWake != null ? mExcessiveWake.size() : 0; + public int countExcessivePowers() { + return mExcessivePower != null ? mExcessivePower.size() : 0; } - public ExcessiveWake getExcessiveWake(int i) { - if (mExcessiveWake != null) { - return mExcessiveWake.get(i); + public ExcessivePower getExcessivePower(int i) { + if (mExcessivePower != null) { + return mExcessivePower.get(i); } return null; } public void addExcessiveWake(long overTime, long usedTime) { - if (mExcessiveWake == null) { - mExcessiveWake = new ArrayList<ExcessiveWake>(); + if (mExcessivePower == null) { + mExcessivePower = new ArrayList<ExcessivePower>(); } - ExcessiveWake ew = new ExcessiveWake(); + ExcessivePower ew = new ExcessivePower(); + ew.type = ExcessivePower.TYPE_WAKE; ew.overTime = overTime; ew.usedTime = usedTime; - mExcessiveWake.add(ew); + mExcessivePower.add(ew); } - void writeExcessiveWakeToParcelLocked(Parcel out) { - if (mExcessiveWake == null) { + public void addExcessiveCpu(long overTime, long usedTime) { + if (mExcessivePower == null) { + mExcessivePower = new ArrayList<ExcessivePower>(); + } + ExcessivePower ew = new ExcessivePower(); + ew.type = ExcessivePower.TYPE_CPU; + ew.overTime = overTime; + ew.usedTime = usedTime; + mExcessivePower.add(ew); + } + + void writeExcessivePowerToParcelLocked(Parcel out) { + if (mExcessivePower == null) { out.writeInt(0); return; } - final int N = mExcessiveWake.size(); + final int N = mExcessivePower.size(); out.writeInt(N); for (int i=0; i<N; i++) { - ExcessiveWake ew = mExcessiveWake.get(i); + ExcessivePower ew = mExcessivePower.get(i); + out.writeInt(ew.type); out.writeLong(ew.overTime); out.writeLong(ew.usedTime); } } - void readExcessiveWakeFromParcelLocked(Parcel in) { + void readExcessivePowerFromParcelLocked(Parcel in) { final int N = in.readInt(); if (N == 0) { - mExcessiveWake = null; + mExcessivePower = null; return; } - mExcessiveWake = new ArrayList<ExcessiveWake>(); + mExcessivePower = new ArrayList<ExcessivePower>(); for (int i=0; i<N; i++) { - ExcessiveWake ew = new ExcessiveWake(); + ExcessivePower ew = new ExcessivePower(); + ew.type = in.readInt(); ew.overTime = in.readLong(); ew.usedTime = in.readLong(); - mExcessiveWake.add(ew); + mExcessivePower.add(ew); } } @@ -3082,7 +3103,7 @@ public final class BatteryStatsImpl extends BatteryStats { } } - writeExcessiveWakeToParcelLocked(out); + writeExcessivePowerToParcelLocked(out); } void readFromParcelLocked(Parcel in) { @@ -3112,7 +3133,7 @@ public final class BatteryStatsImpl extends BatteryStats { } } - readExcessiveWakeFromParcelLocked(in); + readExcessivePowerFromParcelLocked(in); } public BatteryStatsImpl getBatteryStats() { @@ -3746,6 +3767,13 @@ public final class BatteryStatsImpl extends BatteryStats { } } + public void reportExcessiveCpuLocked(String proc, long overTime, long usedTime) { + Proc p = getProcessStatsLocked(proc); + if (p != null) { + p.addExcessiveCpu(overTime, usedTime); + } + } + public void noteStartSensor(int sensor) { StopwatchTimer t = getSensorTimerLocked(sensor, true); if (t != null) { @@ -4688,7 +4716,7 @@ public final class BatteryStatsImpl extends BatteryStats { p.mSpeedBins[i].readSummaryFromParcelLocked(in); } } - p.readExcessiveWakeFromParcelLocked(in); + p.readExcessivePowerFromParcelLocked(in); } NP = in.readInt(); @@ -4887,7 +4915,7 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(0); } } - ps.writeExcessiveWakeToParcelLocked(out); + ps.writeExcessivePowerToParcelLocked(out); } } diff --git a/core/java/com/android/internal/widget/DrawableHolder.java b/core/java/com/android/internal/widget/DrawableHolder.java new file mode 100644 index 0000000..d53860c --- /dev/null +++ b/core/java/com/android/internal/widget/DrawableHolder.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +import java.util.ArrayList; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.animation.Animator.AnimatorListener; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.util.Log; +import android.view.animation.DecelerateInterpolator; + +/** + * This class is a container for a Drawable with multiple animated properties. + * + */ +public class DrawableHolder implements AnimatorListener { + public static final DecelerateInterpolator EASE_OUT_INTERPOLATOR = new DecelerateInterpolator(); + private static final String TAG = "DrawableHolder"; + private static final boolean DBG = false; + private float mX = 0.0f; + private float mY = 0.0f; + private float mScaleX = 1.0f; + private float mScaleY = 1.0f; + private BitmapDrawable mDrawable; + private float mAlpha = 1f; + private ArrayList<ObjectAnimator<Float>> mAnimators = new ArrayList<ObjectAnimator<Float>>(); + private ArrayList<ObjectAnimator<Float>> mNeedToStart = new ArrayList<ObjectAnimator<Float>>(); + + public DrawableHolder(BitmapDrawable drawable) { + this(drawable, 0.0f, 0.0f); + } + + public DrawableHolder(BitmapDrawable drawable, float x, float y) { + mDrawable = drawable; + mX = x; + mY = y; + mDrawable.getPaint().setAntiAlias(true); // Force AA + mDrawable.setBounds(0, 0, mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight()); + } + + /** + * + * Adds an animation that interpolates given property from its current value + * to the given value. + * + * @param duration the duration, in ms. + * @param delay the delay to start the animation, in ms. + * @param property the property to animate + * @param toValue the target value + * @param replace if true, replace the current animation with this one. + */ + public ObjectAnimator<Float> addAnimTo(long duration, long delay, + String property, float toValue, boolean replace) { + + if (replace) removeAnimationFor(property); + + ObjectAnimator<Float> anim = new ObjectAnimator<Float>(duration, this, property, toValue); + anim.setStartDelay(delay); + anim.setInterpolator(EASE_OUT_INTERPOLATOR); + this.addAnimation(anim, replace); + if (DBG) Log.v(TAG, "animationCount = " + mAnimators.size()); + return anim; + } + + /** + * Stops all animations for the given property and removes it from the list. + * + * @param property + */ + public void removeAnimationFor(String property) { + ArrayList<ObjectAnimator<Float>> removalList = new ArrayList<ObjectAnimator<Float>>(); + for (ObjectAnimator<Float> currentAnim : mAnimators) { + if (property.equals(currentAnim.getPropertyName())) { + currentAnim.cancel(); + removalList.add(currentAnim); + } + } + if (DBG) Log.v(TAG, "Remove list size: " + removalList.size()); + mAnimators.removeAll(removalList); + } + + /** + * Stops all animations and removes them from the list. + */ + public void clearAnimations() { + for (ObjectAnimator<Float> currentAnim : mAnimators) { + currentAnim.cancel(); + } + mAnimators.clear(); + } + + /** + * Adds the given animation to the list of animations for this object. + * + * @param anim + * @param overwrite + * @return + */ + private DrawableHolder addAnimation(ObjectAnimator<Float> anim, boolean overwrite) { + if (anim != null) + mAnimators.add(anim); + mNeedToStart.add(anim); + return this; + } + + /** + * Draw this object to the canvas using the properties defined in this class. + * + * @param canvas canvas to draw into + */ + public void draw(Canvas canvas) { + final float threshold = 1.0f / 256.0f; // contribution less than 1 LSB of RGB byte + if (mAlpha <= threshold) // don't bother if it won't show up + return; + canvas.save(Canvas.MATRIX_SAVE_FLAG); + canvas.translate(mX, mY); + canvas.scale(mScaleX, mScaleY); + canvas.translate(-0.5f*getWidth(), -0.5f*getHeight()); + mDrawable.setAlpha((int) Math.round(mAlpha * 255f)); + mDrawable.draw(canvas); + canvas.restore(); + } + + /** + * Starts all animations added since the last call to this function. Used to synchronize + * animations. + * + * @param listener an optional listener to add to the animations. Typically used to know when + * to invalidate the surface these are being drawn to. + */ + public void startAnimations(ValueAnimator.AnimatorUpdateListener listener) { + for (int i = 0; i < mNeedToStart.size(); i++) { + ObjectAnimator<Float> anim = mNeedToStart.get(i); + anim.addUpdateListener(listener); + anim.addListener(this); + anim.start(); + } + mNeedToStart.clear(); + } + + + public DrawableHolder setX(float value) { + mX = value; + return this; + } + + public DrawableHolder setY(float value) { + mY = value; + return this; + } + + public DrawableHolder setScaleX(float value) { + mScaleX = value; + return this; + } + + public DrawableHolder setScaleY(float value) { + mScaleY = value; + return this; + } + + public DrawableHolder setAlpha(float alpha) { + mAlpha = alpha; + return this; + } + + public float getX() { + return mX; + } + + public float getY() { + return mY; + } + + public float getScaleX() { + return mScaleX; + } + + public float getScaleY() { + return mScaleY; + } + + public float getAlpha() { + return mAlpha; + } + + public BitmapDrawable getDrawable() { + return mDrawable; + } + + public int getWidth() { + return mDrawable.getIntrinsicWidth(); + } + + public int getHeight() { + return mDrawable.getIntrinsicHeight(); + } + + public void onAnimationCancel(Animator animation) { + + } + + public void onAnimationEnd(Animator animation) { + mAnimators.remove(animation); + } + + public void onAnimationRepeat(Animator animation) { + + } + + public void onAnimationStart(Animator animation) { + + } +} diff --git a/core/java/com/android/internal/widget/WaveView.java b/core/java/com/android/internal/widget/WaveView.java new file mode 100644 index 0000000..f4ee7ee --- /dev/null +++ b/core/java/com/android/internal/widget/WaveView.java @@ -0,0 +1,573 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +import java.util.ArrayList; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.os.Vibrator; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; + +import com.android.internal.R; + +/** + * A special widget containing a center and outer ring. Moving the center ring to the outer ring + * causes an event that can be caught by implementing OnTriggerListener. + */ +public class WaveView extends View implements ValueAnimator.AnimatorUpdateListener { + private static final String TAG = "WaveView"; + private static final boolean DBG = false; + private static final int WAVE_COUNT = 5; // default wave count + private static final long VIBRATE_SHORT = 20; // msec + private static final long VIBRATE_LONG = 20; // msec + + // Lock state machine states + private static final int STATE_RESET_LOCK = 0; + private static final int STATE_READY = 1; + private static final int STATE_START_ATTEMPT = 2; + private static final int STATE_ATTEMPTING = 3; + private static final int STATE_UNLOCK_ATTEMPT = 4; + private static final int STATE_UNLOCK_SUCCESS = 5; + + // Animation properties. + private static final long DURATION = 500; // duration of transitional animations + private static final long FINAL_DELAY = 1300; // delay for final animations + private static final long SHORT_DELAY = 100; // for starting one animation after another. + private static final long WAVE_DURATION = 2000; // amount of time for way to expand/decay + private static final long RESET_TIMEOUT = 3000; // elapsed time of inactivity before we reset + private static final long DELAY_INCREMENT = 15; // increment per wave while tracking motion + private static final long DELAY_INCREMENT2 = 12; // increment per wave while not tracking + + private Vibrator mVibrator; + private OnTriggerListener mOnTriggerListener; + private ArrayList<DrawableHolder> mDrawables = new ArrayList<DrawableHolder>(3); + private ArrayList<DrawableHolder> mLightWaves = new ArrayList<DrawableHolder>(WAVE_COUNT); + private boolean mFingerDown = false; + private float mRingRadius = 182.0f; // Radius of bitmap ring. Used to snap halo to it + private int mSnapRadius = 136; // minimum threshold for drag unlock + private int mWaveDelay = 240; // time to delay + private int mWaveCount = WAVE_COUNT; // number of waves + private long mWaveTimerDelay = mWaveDelay; + private int mCurrentWave = 0; + private float mLockCenterX; // center of widget as dictated by widget size + private float mLockCenterY; + private float mMouseX; // current mouse position as of last touch event + private float mMouseY; + private DrawableHolder mUnlockRing; + private DrawableHolder mUnlockDefault; + private DrawableHolder mUnlockHalo; + private int mLockState = STATE_RESET_LOCK; + private int mGrabbedState = OnTriggerListener.NO_HANDLE; + + public WaveView(Context context) { + this(context, null); + } + + public WaveView(Context context, AttributeSet attrs) { + super(context, attrs); + + // TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WaveView); + // mOrientation = a.getInt(R.styleable.WaveView_orientation, HORIZONTAL); + // a.recycle(); + + initDrawables(); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + mLockCenterX = 0.5f * w; + mLockCenterY = 0.5f * h; + super.onSizeChanged(w, h, oldw, oldh); + } + + @Override + protected int getSuggestedMinimumWidth() { + // View should be large enough to contain the unlock ring + halo + return mUnlockRing.getWidth() + mUnlockHalo.getWidth(); + } + + @Override + protected int getSuggestedMinimumHeight() { + // View should be large enough to contain the unlock ring + halo + return mUnlockRing.getHeight() + mUnlockHalo.getHeight(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); + int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); + int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); + int width; + int height; + + if (widthSpecMode == MeasureSpec.AT_MOST) { + width = Math.min(widthSpecSize, getSuggestedMinimumWidth()); + } else if (widthSpecMode == MeasureSpec.EXACTLY) { + width = widthSpecSize; + } else { + width = getSuggestedMinimumWidth(); + } + + if (heightSpecMode == MeasureSpec.AT_MOST) { + height = Math.min(heightSpecSize, getSuggestedMinimumWidth()); + } else if (heightSpecMode == MeasureSpec.EXACTLY) { + height = heightSpecSize; + } else { + height = getSuggestedMinimumHeight(); + } + + setMeasuredDimension(width, height); + } + + private void initDrawables() { + mUnlockRing = new DrawableHolder(createDrawable(R.drawable.unlock_ring)) + .setX(mLockCenterX).setY(mLockCenterY).setScaleX(0.1f).setScaleY(0.1f).setAlpha(0.0f); + mDrawables.add(mUnlockRing); + + mUnlockDefault = new DrawableHolder(createDrawable(R.drawable.unlock_default)) + .setX(mLockCenterX).setY(mLockCenterY).setScaleX(0.1f).setScaleY(0.1f).setAlpha(0.0f); + mDrawables.add(mUnlockDefault); + + mUnlockHalo = new DrawableHolder(createDrawable(R.drawable.unlock_halo)) + .setX(mLockCenterX).setY(mLockCenterY).setScaleX(0.1f).setScaleY(0.1f).setAlpha(0.0f); + mDrawables.add(mUnlockHalo); + + BitmapDrawable wave = createDrawable(R.drawable.unlock_wave); + for (int i = 0; i < mWaveCount; i++) { + DrawableHolder holder = new DrawableHolder(wave); + mLightWaves.add(holder); + holder.setAlpha(0.0f); + } + } + + private void waveUpdateFrame(float mouseX, float mouseY, boolean fingerDown) { + double distX = mouseX - mLockCenterX; + double distY = mouseY - mLockCenterY; + int dragDistance = (int) Math.ceil(Math.hypot(distX, distY)); + double touchA = Math.atan2(distX, distY); + float ringX = (float) (mLockCenterX + mRingRadius * Math.sin(touchA)); + float ringY = (float) (mLockCenterY + mRingRadius * Math.cos(touchA)); + + switch (mLockState) { + case STATE_RESET_LOCK: + if (DBG) Log.v(TAG, "State RESET_LOCK"); + mWaveTimerDelay = mWaveDelay; + for (int i = 0; i < mLightWaves.size(); i++) { + //TweenMax.to(mLightWave.get(i), .3, {alpha:0, ease:Quint.easeOut}); + DrawableHolder holder = mLightWaves.get(i); + holder.addAnimTo(300, 0, "alpha", 0.0f, false); + } + for (int i = 0; i < mLightWaves.size(); i++) { + mLightWaves.get(i).startAnimations(this); + } + + //TweenMax.to(unlockRing, .5, { x: lockX, y: lockY, scaleX: .1, scaleY: .1, + // alpha: 0, overwrite: true, ease:Quint.easeOut }); + mUnlockRing.addAnimTo(DURATION, 0, "x", mLockCenterX, true); + mUnlockRing.addAnimTo(DURATION, 0, "y", mLockCenterY, true); + mUnlockRing.addAnimTo(DURATION, 0, "scaleX", 0.1f, true); + mUnlockRing.addAnimTo(DURATION, 0, "scaleY", 0.1f, true); + mUnlockRing.addAnimTo(DURATION, 0, "alpha", 0.0f, true); + + //TweenMax.to(unlockDefault, 0, { x: lockX, y: lockY, scaleX: .1, scaleY: .1, + // alpha: 0 , overwrite: true }); + mUnlockDefault.removeAnimationFor("x"); + mUnlockDefault.removeAnimationFor("y"); + mUnlockDefault.removeAnimationFor("scaleX"); + mUnlockDefault.removeAnimationFor("scaleY"); + mUnlockDefault.removeAnimationFor("alpha"); + mUnlockDefault.setX(mLockCenterX).setY(mLockCenterY).setScaleX(0.1f).setScaleY(0.1f) + .setAlpha(0.0f); + + //TweenMax.to(unlockDefault, .5, { delay: .1, scaleX: 1, scaleY: 1, + // alpha: 1, overwrite: true, ease:Quint.easeOut }); + mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, true); + mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, true); + mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, true); + + //TweenMax.to(unlockHalo, 0, { x: lockX, y: lockY, scaleX:.1, scaleY: .1, + // alpha: 0 , overwrite: true }); + mUnlockHalo.removeAnimationFor("x"); + mUnlockHalo.removeAnimationFor("y"); + mUnlockHalo.removeAnimationFor("scaleX"); + mUnlockHalo.removeAnimationFor("scaleY"); + mUnlockHalo.removeAnimationFor("alpha"); + mUnlockHalo.setX(mLockCenterX).setY(mLockCenterY).setScaleX(0.1f).setScaleY(0.1f) + .setAlpha(0.0f); + + //TweenMax.to(unlockHalo, .5, { x: lockX, y: lockY, scaleX: 1, scaleY: 1, + // alpha: 1 , overwrite: true, ease:Quint.easeOut }); + mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "x", mLockCenterX, true); + mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "y", mLockCenterY, true); + mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, true); + mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, true); + mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, true); + + //lockTimer.stop(); + removeCallbacks(mLockTimerActions); + + mLockState = STATE_READY; + break; + + case STATE_READY: + if (DBG) Log.v(TAG, "State READY"); + break; + + case STATE_START_ATTEMPT: + if (DBG) Log.v(TAG, "State START_ATTEMPT"); + //TweenMax.to(unlockDefault, 0, {scaleX: .1, scaleY:.1, alpha: 0, + // x:lockX +182, y: lockY , overwrite: true }); + mUnlockDefault.removeAnimationFor("x"); + mUnlockDefault.removeAnimationFor("y"); + mUnlockDefault.removeAnimationFor("scaleX"); + mUnlockDefault.removeAnimationFor("scaleY"); + mUnlockDefault.removeAnimationFor("alpha"); + mUnlockDefault.setX(mLockCenterX + 182).setY(mLockCenterY).setScaleX(0.1f) + .setScaleY(0.1f).setAlpha(0.0f); + + //TweenMax.to(unlockDefault, 0.5, { delay: .1 , scaleX: 1, scaleY: 1, + // alpha: 1, ease:Quint.easeOut }); + mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, false); + mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, false); + mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, false); + + //TweenMax.to(unlockRing, 0.5, {scaleX: 1, scaleY: 1, + // alpha: 1, ease:Quint.easeOut, overwrite: true }); + mUnlockRing.addAnimTo(DURATION, 0, "scaleX", 1.0f, true); + mUnlockRing.addAnimTo(DURATION, 0, "scaleY", 1.0f, true); + mUnlockRing.addAnimTo(DURATION, 0, "alpha", 1.0f, true); + + postDelayed(mAddWaveAction, mWaveTimerDelay); + + mLockState = STATE_ATTEMPTING; + break; + + case STATE_ATTEMPTING: + if (DBG) Log.v(TAG, "State ATTEMPTING"); + //TweenMax.to(unlockHalo, 0.4, { x:mouseX, y:mouseY, scaleX:1, scaleY:1, + // alpha: 1, ease:Quint.easeOut }); + if (dragDistance > mSnapRadius) { + if (fingerDown) { + //TweenMax.to(unlockHalo, 0.4, {x:ringX, y:ringY, scaleX:1, scaleY:1, + // alpha: 1 , ease:Quint.easeOut , overwrite: true }); + mUnlockHalo.addAnimTo(0, 0, "x", ringX, true); + mUnlockHalo.addAnimTo(0, 0, "y", ringY, true); + mUnlockHalo.addAnimTo(0, 0, "scaleX", 1.0f, true); + mUnlockHalo.addAnimTo(0, 0, "scaleY", 1.0f, true); + mUnlockHalo.addAnimTo(0, 0, "alpha", 1.0f, true); + } else { + mLockState = STATE_UNLOCK_ATTEMPT; + } + } else { + mUnlockHalo.addAnimTo(0, 0, "x", mouseX, true); + mUnlockHalo.addAnimTo(0, 0, "y", mouseY, true); + mUnlockHalo.addAnimTo(0, 0, "scaleX", 1.0f, true); + mUnlockHalo.addAnimTo(0, 0, "scaleY", 1.0f, true); + mUnlockHalo.addAnimTo(0, 0, "alpha", 1.0f, true); + } + break; + + case STATE_UNLOCK_ATTEMPT: + if (DBG) Log.v(TAG, "State UNLOCK_ATTEMPT"); + if (dragDistance > mSnapRadius) { + for (int n = 0; n < mLightWaves.size(); n++) { + //TweenMax.to(this["lightWave"+n], .5,{alpha:0, delay: (6+n-currentWave)*.1, + // x:ringX, y:ringY, scaleX: .1, scaleY: .1, ease:Quint.easeOut}); + DrawableHolder wave = mLightWaves.get(n); + long delay = 1000L*(6 + n - mCurrentWave)/10L; + wave.addAnimTo(DURATION, delay, "x", ringX, true); + wave.addAnimTo(DURATION, delay, "y", ringY, true); + wave.addAnimTo(DURATION, delay, "scaleX", 0.1f, true); + wave.addAnimTo(DURATION, delay, "scaleY", 0.1f, true); + wave.addAnimTo(DURATION, delay, "alpha", 0.0f, true); + } + for (int i = 0; i < mLightWaves.size(); i++) { + mLightWaves.get(i).startAnimations(this); + } + + //TweenMax.to(unlockRing, .5, {x:ringX, y: ringY, scaleX: .1, scaleY: .1, + // alpha: 0, ease: Quint.easeOut }); + mUnlockRing.addAnimTo(DURATION, 0, "x", ringX, false); + mUnlockRing.addAnimTo(DURATION, 0, "y", ringY, false); + mUnlockRing.addAnimTo(DURATION, 0, "scaleX", 0.1f, false); + mUnlockRing.addAnimTo(DURATION, 0, "scaleY", 0.1f, false); + mUnlockRing.addAnimTo(DURATION, 0, "alpha", 0.0f, false); + + //TweenMax.to(unlockRing, .5, { delay: 1.3, alpha: 0 , ease: Quint.easeOut }); + mUnlockRing.addAnimTo(DURATION, FINAL_DELAY, "alpha", 0.0f, false); + + //TweenMax.to(unlockDefault, 0, { x:ringX, y: ringY, scaleX: .1, scaleY: .1, + // alpha: 0 , overwrite: true }); + mUnlockDefault.removeAnimationFor("x"); + mUnlockDefault.removeAnimationFor("y"); + mUnlockDefault.removeAnimationFor("scaleX"); + mUnlockDefault.removeAnimationFor("scaleY"); + mUnlockDefault.removeAnimationFor("alpha"); + mUnlockDefault.setX(ringX).setY(ringY).setScaleX(0.1f).setScaleY(0.1f) + .setAlpha(0.0f); + + //TweenMax.to(unlockDefault, .5, { x:ringX, y: ringY, scaleX: 1, scaleY: 1, + // alpha: 1 , ease: Quint.easeOut , overwrite: true }); + mUnlockDefault.addAnimTo(DURATION, 0, "x", ringX, true); + mUnlockDefault.addAnimTo(DURATION, 0, "y", ringY, true); + mUnlockDefault.addAnimTo(DURATION, 0, "scaleX", 1.0f, true); + mUnlockDefault.addAnimTo(DURATION, 0, "scaleY", 1.0f, true); + mUnlockDefault.addAnimTo(DURATION, 0, "alpha", 1.0f, true); + + //TweenMax.to(unlockDefault, .5, { delay: 1.3, scaleX: 3, scaleY: 3, + // alpha: 1, ease: Quint.easeOut }); + mUnlockDefault.addAnimTo(DURATION, FINAL_DELAY, "scaleX", 3.0f, false); + mUnlockDefault.addAnimTo(DURATION, FINAL_DELAY, "scaleY", 3.0f, false); + mUnlockDefault.addAnimTo(DURATION, FINAL_DELAY, "alpha", 1.0f, false); + + //TweenMax.to(unlockHalo, .5, { x:ringX, y: ringY , ease: Back.easeOut }); + mUnlockHalo.addAnimTo(DURATION, 0, "x", ringX, false); + mUnlockHalo.addAnimTo(DURATION, 0, "y", ringY, false); + + //TweenMax.to(unlockHalo, .5, { delay: 1.3, scaleX: 3, scaleY: 3, + // alpha: 1, ease: Quint.easeOut }); + mUnlockHalo.addAnimTo(DURATION, FINAL_DELAY, "scaleX", 3.0f, false); + mUnlockHalo.addAnimTo(DURATION, FINAL_DELAY, "scaleY", 3.0f, false); + mUnlockHalo.addAnimTo(DURATION, FINAL_DELAY, "alpha", 1.0f, false); + + removeCallbacks(mLockTimerActions); + + postDelayed(mLockTimerActions, RESET_TIMEOUT); + + dispatchTriggerEvent(OnTriggerListener.CENTER_HANDLE); + mLockState = STATE_UNLOCK_SUCCESS; + } else { + mLockState = STATE_RESET_LOCK; + } + break; + + case STATE_UNLOCK_SUCCESS: + if (DBG) Log.v(TAG, "State UNLOCK_SUCCESS"); + removeCallbacks(mAddWaveAction); + break; + + default: + if (DBG) Log.v(TAG, "Unknown state " + mLockState); + break; + } + mUnlockDefault.startAnimations(this); + mUnlockHalo.startAnimations(this); + mUnlockRing.startAnimations(this); + } + + BitmapDrawable createDrawable(int resId) { + Resources res = getResources(); + Bitmap bitmap = BitmapFactory.decodeResource(res, resId); + return new BitmapDrawable(res, bitmap); + } + + @Override + protected void onDraw(Canvas canvas) { + waveUpdateFrame(mMouseX, mMouseY, mFingerDown); + for (int i = 0; i < mDrawables.size(); ++i) { + mDrawables.get(i).draw(canvas); + } + for (int i = 0; i < mLightWaves.size(); ++i) { + mLightWaves.get(i).draw(canvas); + } + } + + private final Runnable mLockTimerActions = new Runnable() { + public void run() { + if (DBG) Log.v(TAG, "LockTimerActions"); + // reset lock after inactivity + if (mLockState == STATE_ATTEMPTING) { + mLockState = STATE_RESET_LOCK; + } + // for prototype, reset after successful unlock + if (mLockState == STATE_UNLOCK_SUCCESS) { + mLockState = STATE_RESET_LOCK; + } + invalidate(); + } + }; + + private final Runnable mAddWaveAction = new Runnable() { + public void run() { + double distX = mMouseX - mLockCenterX; + double distY = mMouseY - mLockCenterY; + int dragDistance = (int) Math.ceil(Math.hypot(distX, distY)); + if (mLockState == STATE_ATTEMPTING && dragDistance < mSnapRadius + && mWaveTimerDelay >= mWaveDelay) { + mWaveTimerDelay = Math.min(WAVE_DURATION, mWaveTimerDelay + DELAY_INCREMENT); + + DrawableHolder wave = mLightWaves.get(mCurrentWave); + wave.setAlpha(0.0f); + wave.setScaleX(0.2f); + wave.setScaleY(0.2f); + wave.setX(mMouseX); + wave.setY(mMouseY); + + //TweenMax.to(this["lightWave"+currentWave], 2, { x:lockX , y:lockY, alpha: 1.5, + // scaleX: 1, scaleY:1, ease:Cubic.easeOut}); + wave.addAnimTo(WAVE_DURATION, 0, "x", mLockCenterX, true); + wave.addAnimTo(WAVE_DURATION, 0, "y", mLockCenterY, true); + wave.addAnimTo(WAVE_DURATION*2/3, 0, "alpha", 1.0f, true); + wave.addAnimTo(WAVE_DURATION, 0, "scaleX", 1.0f, true); + wave.addAnimTo(WAVE_DURATION, 0, "scaleY", 1.0f, true); + + //TweenMax.to(this["lightWave"+currentWave], 1, { delay: 1.3 + // , alpha: 0 , ease:Quint.easeOut}); + wave.addAnimTo(1000, FINAL_DELAY, "alpha", 0.0f, false); + wave.startAnimations(WaveView.this); + + mCurrentWave = (mCurrentWave+1) % mWaveCount; + if (DBG) Log.v(TAG, "WaveTimerDelay: start new wave in " + mWaveTimerDelay); + postDelayed(mAddWaveAction, mWaveTimerDelay); + } else { + mWaveTimerDelay += DELAY_INCREMENT2; + } + } + }; + + @Override + public boolean onTouchEvent(MotionEvent event) { + final int action = event.getAction(); + mMouseX = event.getX(); + mMouseY = event.getY(); + boolean handled = false; + switch (action) { + case MotionEvent.ACTION_DOWN: + removeCallbacks(mLockTimerActions); + mFingerDown = true; + setGrabbedState(OnTriggerListener.CENTER_HANDLE); + { + float x = mMouseX - mUnlockHalo.getX(); + float y = mMouseY - mUnlockHalo.getY(); + float dist = (float) Math.hypot(x, y); + if (dist < mUnlockHalo.getWidth()*0.5f) { + if (mLockState == STATE_READY) { + mLockState = STATE_START_ATTEMPT; + } + } + } + handled = true; + break; + + case MotionEvent.ACTION_MOVE: + handled = true; + break; + + case MotionEvent.ACTION_UP: + mFingerDown = false; + postDelayed(mLockTimerActions, RESET_TIMEOUT); + setGrabbedState(OnTriggerListener.NO_HANDLE); + handled = true; + break; + + case MotionEvent.ACTION_CANCEL: + mFingerDown = false; + handled = true; + break; + } + invalidate(); + return handled ? true : super.onTouchEvent(event); + } + + /** + * Triggers haptic feedback. + */ + private synchronized void vibrate(long duration) { + if (mVibrator == null) { + mVibrator = (android.os.Vibrator) + getContext().getSystemService(Context.VIBRATOR_SERVICE); + } + mVibrator.vibrate(duration); + } + + /** + * Registers a callback to be invoked when the user triggers an event. + * + * @param listener the OnDialTriggerListener to attach to this view + */ + public void setOnTriggerListener(OnTriggerListener listener) { + mOnTriggerListener = listener; + } + + /** + * Dispatches a trigger event to listener. Ignored if a listener is not set. + * @param whichHandle the handle that triggered the event. + */ + private void dispatchTriggerEvent(int whichHandle) { + vibrate(VIBRATE_LONG); + if (mOnTriggerListener != null) { + mOnTriggerListener.onTrigger(this, whichHandle); + } + } + + /** + * Sets the current grabbed state, and dispatches a grabbed state change + * event to our listener. + */ + private void setGrabbedState(int newState) { + if (newState != mGrabbedState) { + mGrabbedState = newState; + if (mOnTriggerListener != null) { + mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState); + } + } + } + + public interface OnTriggerListener { + /** + * Sent when the user releases the handle. + */ + public static final int NO_HANDLE = 0; + + /** + * Sent when the user grabs the center handle + */ + public static final int CENTER_HANDLE = 10; + + /** + * Called when the user drags the center ring beyond a threshold. + */ + void onTrigger(View v, int whichHandle); + + /** + * Called when the "grabbed state" changes (i.e. when the user either grabs or releases + * one of the handles.) + * + * @param v the view that was triggered + * @param grabbedState the new state: {@link #NO_HANDLE}, {@link #CENTER_HANDLE}, + */ + void onGrabbedStateChange(View v, int grabbedState); + } + + public void onAnimationUpdate(ValueAnimator animation) { + invalidate(); + } + + public void reset() { + mLockState = STATE_RESET_LOCK; + } +} diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp index c5ccc43..defd0a0 100644 --- a/core/jni/android_net_wifi_Wifi.cpp +++ b/core/jni/android_net_wifi_Wifi.cpp @@ -30,6 +30,8 @@ namespace android { static jboolean sScanModeActive = false; +//TODO: check general errors in addition to overflow on snprintf + /* * The following remembers the jfieldID's of the fields * of the DhcpInfo Java object, so that we don't have @@ -155,6 +157,36 @@ static jint android_net_wifi_addNetworkCommand(JNIEnv* env, jobject clazz) return doIntCommand("ADD_NETWORK"); } +static jboolean android_net_wifi_wpsPbcCommand(JNIEnv* env, jobject clazz, jstring bssid) +{ + char cmdstr[50]; + jboolean isCopy; + + const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy); + int numWritten = snprintf(cmdstr, sizeof(cmdstr), "WPS_PBC %s", bssidStr); + env->ReleaseStringUTFChars(bssid, bssidStr); + + if ((numWritten == -1) || (numWritten >= sizeof(cmdstr))) { + return false; + } + return doBooleanCommand(cmdstr, "OK"); +} + +static jboolean android_net_wifi_wpsPinCommand(JNIEnv* env, jobject clazz, jstring bssid, int apPin) +{ + char cmdstr[50]; + jboolean isCopy; + + const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy); + int numWritten = snprintf(cmdstr, sizeof(cmdstr), "WPS_REG %s %d", bssidStr, apPin); + env->ReleaseStringUTFChars(bssid, bssidStr); + + if ((numWritten == -1) || (numWritten >= (int)sizeof(cmdstr))) { + return false; + } + return doBooleanCommand(cmdstr, "OK"); +} + static jboolean android_net_wifi_setNetworkVariableCommand(JNIEnv* env, jobject clazz, jint netId, @@ -603,7 +635,8 @@ static JNINativeMethod gWifiMethods[] = { { "setScanResultHandlingCommand", "(I)Z", (void*) android_net_wifi_setScanResultHandlingCommand }, { "addToBlacklistCommand", "(Ljava/lang/String;)Z", (void*) android_net_wifi_addToBlacklistCommand }, { "clearBlacklistCommand", "()Z", (void*) android_net_wifi_clearBlacklistCommand }, - + { "startWpsPbcCommand", "(Ljava/lang/String;)Z", (void*) android_net_wifi_wpsPbcCommand }, + { "startWpsPinCommand", "(Ljava/lang/String;I)Z", (void*) android_net_wifi_wpsPinCommand }, { "doDhcpRequest", "(Landroid/net/DhcpInfo;)Z", (void*) android_net_wifi_doDhcpRequest }, { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_wifi_getDhcpError }, }; diff --git a/core/res/res/drawable-xlarge/unlock_default.png b/core/res/res/drawable-xlarge/unlock_default.png Binary files differnew file mode 100644 index 0000000..0a441c0 --- /dev/null +++ b/core/res/res/drawable-xlarge/unlock_default.png diff --git a/core/res/res/drawable-xlarge/unlock_halo.png b/core/res/res/drawable-xlarge/unlock_halo.png Binary files differnew file mode 100644 index 0000000..09b0526 --- /dev/null +++ b/core/res/res/drawable-xlarge/unlock_halo.png diff --git a/core/res/res/drawable-xlarge/unlock_ring.png b/core/res/res/drawable-xlarge/unlock_ring.png Binary files differnew file mode 100644 index 0000000..1ac6d54 --- /dev/null +++ b/core/res/res/drawable-xlarge/unlock_ring.png diff --git a/core/res/res/drawable-xlarge/unlock_wave.png b/core/res/res/drawable-xlarge/unlock_wave.png Binary files differnew file mode 100644 index 0000000..21bfa24 --- /dev/null +++ b/core/res/res/drawable-xlarge/unlock_wave.png diff --git a/core/res/res/layout-xlarge/keyguard_screen_tab_unlock.xml b/core/res/res/layout-xlarge/keyguard_screen_tab_unlock.xml index 4761800..b3645aa 100644 --- a/core/res/res/layout-xlarge/keyguard_screen_tab_unlock.xml +++ b/core/res/res/layout-xlarge/keyguard_screen_tab_unlock.xml @@ -57,13 +57,10 @@ android:drawablePadding="4dip" /> - <com.android.internal.widget.SlidingTab - android:id="@+id/tab_selector" - android:orientation="horizontal" - android:layout_width="match_parent" + <com.android.internal.widget.WaveView + android:id="@+id/wave_view" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentBottom="true" - android:layout_marginBottom="80dip" /> <!-- "emergency calls only" shown when sim is missing or PUKd --> diff --git a/core/res/res/layout-xlarge/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout-xlarge/keyguard_screen_tab_unlock_land.xml index bb398f6..6c99cca 100644 --- a/core/res/res/layout-xlarge/keyguard_screen_tab_unlock_land.xml +++ b/core/res/res/layout-xlarge/keyguard_screen_tab_unlock_land.xml @@ -58,15 +58,14 @@ android:drawablePadding="4dip" /> - <com.android.internal.widget.SlidingTab - android:id="@+id/tab_selector" - android:orientation="vertical" + <com.android.internal.widget.WaveView + android:id="@+id/wave_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_marginRight="0dip" android:layout_weight="1.0" /> - + <!-- "emergency calls only" shown when sim is missing or PUKd --> <TextView android:id="@+id/emergencyCallText" diff --git a/core/res/res/values-rm/donottranslate-cldr.xml b/core/res/res/values-rm/donottranslate-cldr.xml index 4b9f9db..ccdb17c 100644 --- a/core/res/res/values-rm/donottranslate-cldr.xml +++ b/core/res/res/values-rm/donottranslate-cldr.xml @@ -53,14 +53,6 @@ <string name="month_shortest_november">N</string> <string name="month_shortest_december">D</string> - <string name="sunday">dumengia</string> - <string name="monday">glindesdi</string> - <string name="tuesday">mardi</string> - <string name="wednesday">mesemna</string> - <string name="thursday">gievgia</string> - <string name="friday">venderdi</string> - <string name="saturday">sonda</string> - <string name="day_of_week_long_sunday">dumengia</string> <string name="day_of_week_long_monday">glindesdi</string> <string name="day_of_week_long_tuesday">mardi</string> @@ -85,14 +77,6 @@ <string name="day_of_week_short_friday">ve</string> <string name="day_of_week_short_saturday">so</string> - <string name="day_of_week_shorter_sunday">D</string> - <string name="day_of_week_shorter_monday">G</string> - <string name="day_of_week_shorter_tuesday">M</string> - <string name="day_of_week_shorter_wednesday">M</string> - <string name="day_of_week_shorter_thursday">G</string> - <string name="day_of_week_shorter_friday">V</string> - <string name="day_of_week_shorter_saturday">S</string> - <string name="day_of_week_shortest_sunday">D</string> <string name="day_of_week_shortest_monday">G</string> <string name="day_of_week_shortest_tuesday">M</string> @@ -114,12 +98,7 @@ <string name="numeric_date_format">dd.MM.yyyy</string> <string name="numeric_date_template">"%s.%s.%s"</string> <string name="month_day_year">%-e. %B %Y</string> - <string name="full_date_month_first">d. MMMM y</string> - <string name="full_date_day_first">d. MMMM y</string> - <string name="medium_date_month_first">d. MMM y</string> - <string name="medium_date_day_first">d. MMM y</string> <string name="time_of_day">%H:%M:%S</string> - <string name="status_bar_time_format">HH:mm</string> <string name="date_and_time">%H:%M:%S %d.%m.%Y</string> <string name="date_time">%1$s, %2$s</string> <string name="time_date">%3$s, %1$s</string> diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java index 975a4c2..1289a9e 100755 --- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java +++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java @@ -167,8 +167,7 @@ public class PackageManagerTests extends AndroidTestCase { return ipm; } - public boolean invokeInstallPackage(Uri packageURI, int flags, - GenericReceiver receiver) throws Exception { + public boolean invokeInstallPackage(Uri packageURI, int flags, GenericReceiver receiver) { PackageInstallObserver observer = new PackageInstallObserver(); final boolean received = false; mContext.registerReceiver(receiver, receiver.filter); @@ -180,11 +179,15 @@ public class PackageManagerTests extends AndroidTestCase { getPm().installPackage(packageURI, observer, flags, null); long waitTime = 0; while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { - observer.wait(WAIT_TIME_INCR); - waitTime += WAIT_TIME_INCR; + try { + observer.wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } catch (InterruptedException e) { + Log.i(TAG, "Interrupted during sleep", e); + } } if(!observer.isDone()) { - throw new Exception("Timed out waiting for packageInstalled callback"); + fail("Timed out waiting for packageInstalled callback"); } if (observer.returnCode != PackageManager.INSTALL_SUCCEEDED) { Log.i(TAG, "Failed to install with error code = " + observer.returnCode); @@ -193,11 +196,15 @@ public class PackageManagerTests extends AndroidTestCase { // Verify we received the broadcast waitTime = 0; while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) { - receiver.wait(WAIT_TIME_INCR); - waitTime += WAIT_TIME_INCR; + try { + receiver.wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } catch (InterruptedException e) { + Log.i(TAG, "Interrupted during sleep", e); + } } if(!receiver.isDone()) { - throw new Exception("Timed out waiting for PACKAGE_ADDED notification"); + fail("Timed out waiting for PACKAGE_ADDED notification"); } return receiver.received; } @@ -207,7 +214,7 @@ public class PackageManagerTests extends AndroidTestCase { } } - public void invokeInstallPackageFail(Uri packageURI, int flags, int result) throws Exception { + public void invokeInstallPackageFail(Uri packageURI, int flags, int result) { PackageInstallObserver observer = new PackageInstallObserver(); try { // Wait on observer @@ -215,11 +222,15 @@ public class PackageManagerTests extends AndroidTestCase { getPm().installPackage(packageURI, observer, flags, null); long waitTime = 0; while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { - observer.wait(WAIT_TIME_INCR); - waitTime += WAIT_TIME_INCR; + try { + observer.wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } catch (InterruptedException e) { + Log.i(TAG, "Interrupted during sleep", e); + } } if(!observer.isDone()) { - throw new Exception("Timed out waiting for packageInstalled callback"); + fail("Timed out waiting for packageInstalled callback"); } assertEquals(observer.returnCode, result); } @@ -265,7 +276,7 @@ public class PackageManagerTests extends AndroidTestCase { Environment.getExternalStorageDirectory().getPath()); sdSize = (long)sdStats.getAvailableBlocks() * (long)sdStats.getBlockSize(); - // TODO check for thesholds here + // TODO check for thresholds here return pkgLen <= sdSize; } @@ -368,12 +379,21 @@ public class PackageManagerTests extends AndroidTestCase { assertFalse((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); assertTrue(info.nativeLibraryDir.startsWith(dataDir.getPath())); } else if (rLoc == INSTALL_LOC_SD){ - assertTrue((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); - assertTrue(srcPath.startsWith(SECURE_CONTAINERS_PREFIX)); - assertTrue(publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX)); - assertTrue(info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX)); + assertTrue("Application flags (" + info.flags + + ") should contain FLAG_EXTERNAL_STORAGE", + (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); + assertTrue("The APK path (" + srcPath + ") should start with " + + SECURE_CONTAINERS_PREFIX, srcPath + .startsWith(SECURE_CONTAINERS_PREFIX)); + assertTrue("The public APK path (" + publicSrcPath + ") should start with " + + SECURE_CONTAINERS_PREFIX, publicSrcPath + .startsWith(SECURE_CONTAINERS_PREFIX)); + assertTrue("The native library path (" + info.nativeLibraryDir + + ") should start with " + SECURE_CONTAINERS_PREFIX, + info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX)); } else { // TODO handle error. Install should have failed. + fail("Install should have failed"); } } } catch (NameNotFoundException e) { @@ -544,8 +564,6 @@ public class PackageManagerTests extends AndroidTestCase { // Verify installed information assertInstall(pkg, flags, expInstallLocation); } - } catch (Exception e) { - failStr("Failed with exception : " + e); } finally { if (cleanUp) { cleanUpInstall(ip); diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java index 0293ded..f21e7ac 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java @@ -241,7 +241,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { Uri remoteUri = getExternalFileUri(filename); Request request = new Request(remoteUri); - request.setMediaType(getMimeMapping(DownloadFileType.APK)); + request.setMimeType(getMimeMapping(DownloadFileType.APK)); dlRequest = mDownloadManager.enqueue(request); diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml index 6bcaaaf..1fd7bba 100644 --- a/data/fonts/fonts.xml +++ b/data/fonts/fonts.xml @@ -44,5 +44,5 @@ <name>monaco</name> </font> <fallback ttf="DroidSansFallback" /> - <fallback ttf="DroidSansJapanese" /> -</fonts>
\ No newline at end of file + <fallback ttf="MTLmr3m" /> +</fonts> diff --git a/docs/html/guide/topics/resources/drawable-resource.jd b/docs/html/guide/topics/resources/drawable-resource.jd index 035ddb9..9ebed56 100644 --- a/docs/html/guide/topics/resources/drawable-resource.jd +++ b/docs/html/guide/topics/resources/drawable-resource.jd @@ -434,7 +434,7 @@ screen).</dd> <h2 id="LayerList">Layer List</h2> <p>A {@link android.graphics.drawable.LayerDrawable} is a drawable object -that manages an array of other drawables. Each drawable in the list is drawn in the order of the +that manages an array of other drawables. Each drawable in the list is drawn in the order of the list—the last drawable in the list is drawn on top.</p> <p>Each drawable is represented by an {@code <item>} element inside a single {@code @@ -641,7 +641,7 @@ In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> android:state_checkable=["true" | "false"] android:state_checked=["true" | "false"] android:state_enabled=["true" | "false"] - android:state_window_focused=["true" | "false"] /> + android:state_window_focused=["true" | "false"] /> </selector> </pre> </dd> @@ -729,12 +729,12 @@ default value should always be last (as demonstrated in the following example).< </selector> </pre> -<p>This layout XML applies the drawable to a View:</p> +<p>This layout XML applies the state list drawable to a Button:</p> <pre> -<ImageView +<Button android:layout_height="wrap_content" android:layout_width="wrap_content" - android:src="@drawable/button" /> + android:background="@drawable/button" /> </pre> </dd> <!-- end example --> @@ -1670,13 +1670,13 @@ android:dashGap} is set.</dd> <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> - <gradient - android:startColor="#FFFF0000" + <gradient + android:startColor="#FFFF0000" android:endColor="#80FF00FF" android:angle="45"/> - <padding android:left="7dp" + <padding android:left="7dp" android:top="7dp" - android:right="7dp" + android:right="7dp" android:bottom="7dp" /> <corners android:radius="8dp" /> </shape> diff --git a/docs/html/guide/tutorials/notepad/notepad-ex2.jd b/docs/html/guide/tutorials/notepad/notepad-ex2.jd index a945a62..854731f 100644 --- a/docs/html/guide/tutorials/notepad/notepad-ex2.jd +++ b/docs/html/guide/tutorials/notepad/notepad-ex2.jd @@ -87,8 +87,8 @@ Open the Notepadv2 class.</p> menu callback used for the options menu. Here, we add just one line, which will add a menu item to delete a note. Call <code>menu.add()</code> like so: <pre> -public boolean onCreateContextMenu(Menu menu, View v - ContextMenuInfo menuInfo) { +public void onCreateContextMenu(Menu menu, View v, + ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); menu.add(0, DELETE_ID, 0, R.string.menu_delete); }</pre> diff --git a/docs/html/resources/tutorials/notepad/notepad-ex2.jd b/docs/html/resources/tutorials/notepad/notepad-ex2.jd index 289b5fe..499b796 100644 --- a/docs/html/resources/tutorials/notepad/notepad-ex2.jd +++ b/docs/html/resources/tutorials/notepad/notepad-ex2.jd @@ -87,8 +87,8 @@ Open the Notepadv2 class.</p> menu callback used for the options menu. Here, we add just one line, which will add a menu item to delete a note. Call <code>menu.add()</code> like so: <pre> -public boolean onCreateContextMenu(Menu menu, View v - ContextMenuInfo menuInfo) { +public void onCreateContextMenu(Menu menu, View v, + ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); menu.add(0, DELETE_ID, 0, R.string.menu_delete); }</pre> diff --git a/docs/html/sdk/adt_download.jd b/docs/html/sdk/adt_download.jd index 5e642d7..3da576a 100644 --- a/docs/html/sdk/adt_download.jd +++ b/docs/html/sdk/adt_download.jd @@ -22,10 +22,17 @@ ADT Installation</a>.</p> <th>Notes</th> </tr> <tr> + <td>0.9.9</td> + <td><a href="http://dl-ssl.google.com/android/ADT-0.9.9.zip">ADT-0.9.9.zip</a></td> + <td><nobr>8301681 bytes</nobr></td> + <td>7deff0c9b25940a74cea7a0815a3bc36</td> + <td>Requires SDK Tools, Revision 7 <em><nobr>September 2010</nobr></em></td> + </tr> + <tr> <td>0.9.8</td> <td><a href="http://dl-ssl.google.com/android/ADT-0.9.8.zip">ADT-0.9.8.zip</a></td> - <td><nobr>8703591 bytes</nobr></td> - <td>22070f8e52924605a3b3abf87c1ba39f</td> + <td><nobr>8301417 bytes</nobr></td> + <td>27e0de800512f13feae46fb554e6ee2f</td> <td>Requires SDK Tools, Revision 7 <em><nobr>September 2010</nobr></em></td> </tr> <tr> diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd index a984d56..9f3c8b0 100644 --- a/docs/html/sdk/eclipse-adt.jd +++ b/docs/html/sdk/eclipse-adt.jd @@ -1,9 +1,9 @@ page.title=ADT Plugin for Eclipse sdk.preview=0 -adt.zip.version=0.9.8 -adt.zip.download=ADT-0.9.8.zip -adt.zip.bytes=8703591 -adt.zip.checksum=22070f8e52924605a3b3abf87c1ba39f +adt.zip.version=0.9.9 +adt.zip.download=ADT-0.9.9.zip +adt.zip.bytes=8301681 +adt.zip.checksum=7deff0c9b25940a74cea7a0815a3bc36 @jd:body @@ -100,11 +100,40 @@ padding: .25em 1em; </style> - - <div class="toggleable opened"> <a href="#" onclick="return toggleDiv(this)"> <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" /> +ADT 0.9.9</a> <em>(September 2010)</em> + <div class="toggleme"> + + +</ul> +</dd> + +<dl> + +<dt>Dependencies:</dt> + +<dd><p>ADT 0.9.9 replaces ADT 0.9.8 and is designed for use with SDK Tools r7 +and later. ADT 0.9.9 includes the ADT 0.9.8 features as well as an important +bugfix, so we recommend that you upgrade as soon as possible. If you haven't +already installed SDK Tools r7 into your SDK, use the Android SDK Manager to do +so.</p></dd> + +<dt>General notes:</dt> +<dd> +<ul> +<li>Fixes a problem in project import, in which source files were deleted in some cases.</li> +<li>Includes all other ADT 0.9.8 features (see below).</li> +</ul> +</dd> +</dl> + </div> +</div> + +<div class="toggleable closed"> + <a href="#" onclick="return toggleDiv(this)"> + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" /> ADT 0.9.8</a> <em>(September 2010)</em> <div class="toggleme"> @@ -116,9 +145,7 @@ ADT 0.9.8</a> <em>(September 2010)</em> <dt>Dependencies:</dt> -<dd><p>ADT 0.9.8 is designed for use with SDK Tools r7 and later. Before -updating to ADT 0.9.8, we highly recommend that you use the Android SDK and -AVD Manager to install SDK Tools r7 into your SDK.</p></dd> +<dd><p>ADT 0.9.8 is now deprecated. Please use ADT 0.9.9 instead.</p></dd> <dt>General notes:</dt> <dd> diff --git a/docs/html/sdk/requirements.jd b/docs/html/sdk/requirements.jd index d710b8e..7b11654 100644 --- a/docs/html/sdk/requirements.jd +++ b/docs/html/sdk/requirements.jd @@ -6,7 +6,7 @@ Android applications using the Android SDK. </p> <h3>Supported Operating Systems</h3> <ul> - <li>Windows XP (32-bit) or Vista (32- or 64-bit)</li> + <li>Windows XP (32-bit), Vista (32- or 64-bit), or Windows 7 (32- or 64-bit)</li> <li>Mac OS X 10.5.8 or later (x86 only)</li> <li>Linux (tested on Linux Ubuntu Hardy Heron) <ul> diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs index a665e95..fdf4438 100644 --- a/docs/html/sdk/sdk_toc.cs +++ b/docs/html/sdk/sdk_toc.cs @@ -94,7 +94,7 @@ <span style="display:none" class="zh-TW"></span> </h2> <ul> - <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 0.9.8 + <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 0.9.9 <span style="display:none" class="de"></span> <span style="display:none" class="es"></span> <span style="display:none" class="fr"></span> diff --git a/libs/rs/java/Samples/src/com/android/samples/RsList.java b/libs/rs/java/Samples/src/com/android/samples/RsList.java index d8c733d..0f6b1ac 100644 --- a/libs/rs/java/Samples/src/com/android/samples/RsList.java +++ b/libs/rs/java/Samples/src/com/android/samples/RsList.java @@ -54,7 +54,7 @@ public class RsList extends Activity { @Override protected void onResume() { // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus + // to take appropriate action when the activity loses focus super.onResume(); mView.onResume(); } @@ -62,7 +62,7 @@ public class RsList extends Activity { @Override protected void onPause() { // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus + // to take appropriate action when the activity loses focus super.onPause(); mView.onPause(); } diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java index cf9c6be..da64e02 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java +++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java @@ -19,10 +19,13 @@ package com.android.rs.test; import android.content.res.Resources; import android.renderscript.*; import android.util.Log; +import java.util.ArrayList; +import java.util.ListIterator; public class RSTestCore { - public static final int PART_COUNT = 50000; + int mWidth; + int mHeight; public RSTestCore() { } @@ -30,31 +33,85 @@ public class RSTestCore { private Resources mRes; private RenderScriptGL mRS; - private ScriptC_test_root mRootScript; + private Font mFont; + ScriptField_ListAllocs_s mListAllocs; + int mLastX; + int mLastY; + private ScriptC_rslist mScript; - private boolean fp_mad() { - ScriptC_fp_mad s = new ScriptC_fp_mad(mRS, mRes, R.raw.fp_mad, true); - s.invoke_doTest(0, 0); - return true; - } - - private boolean rs_primitives_test() { - ScriptC_primitives s = new ScriptC_primitives(mRS, mRes, R.raw.primitives, true); - s.invoke_rs_primitives_test(0, 0); - return true; - } + private ArrayList<UnitTest> unitTests; public void init(RenderScriptGL rs, Resources res, int width, int height) { mRS = rs; mRes = res; + mWidth = width; + mHeight = height; + + mScript = new ScriptC_rslist(mRS, mRes, R.raw.rslist, true); + + unitTests = new ArrayList<UnitTest>(); + + unitTests.add(new UT_primitives(mRes)); + unitTests.add(new UT_fp_mad(mRes)); + /* + unitTests.add(new UnitTest("<Pass>", 1)); + unitTests.add(new UnitTest()); + unitTests.add(new UnitTest("<Fail>", -1)); + */ + + UnitTest [] uta = new UnitTest[unitTests.size()]; + uta = unitTests.toArray(uta); + + /* Run the actual unit tests */ + ListIterator<UnitTest> test_iter = unitTests.listIterator(); + while (test_iter.hasNext()) { + UnitTest t = test_iter.next(); + t.start(); + try { + t.join(); + } catch (InterruptedException e) { + } + } + + mListAllocs = new ScriptField_ListAllocs_s(mRS, uta.length); + for (int i = 0; i < uta.length; i++) { + ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item(); + listElem.text = Allocation.createFromString(mRS, uta[i].name); + listElem.result = uta[i].result; + mListAllocs.set(listElem, i, false); + } - mRootScript = new ScriptC_test_root(mRS, mRes, R.raw.test_root, true); + mListAllocs.copyAll(); - rs_primitives_test(); - fp_mad(); + mScript.bind_gList(mListAllocs); + mFont = Font.createFromFamily(mRS, mRes, "serif", Font.Style.BOLD, 8); + mScript.set_gFont(mFont); + + mRS.contextBindRootScript(mScript); + mRS.finish(); } public void newTouchPosition(float x, float y, float pressure, int id) { } + + public void onActionDown(int x, int y) { + mScript.set_gDY(0.0f); + mLastX = x; + mLastY = y; + } + + public void onActionMove(int x, int y) { + int dx = mLastX - x; + int dy = mLastY - y; + + if (Math.abs(dy) <= 2) { + dy = 0; + } + + mScript.set_gDY(dy); + + mLastX = x; + mLastY = y; + } } diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java index 7ae0c08..ce99c6d 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java +++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java @@ -67,40 +67,28 @@ public class RSTestView extends RSSurfaceView { } } -/* + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) + { + return super.onKeyDown(keyCode, event); + } + @Override public boolean onTouchEvent(MotionEvent ev) { - int act = ev.getActionMasked(); - if (act == ev.ACTION_UP) { - mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0)); - return false; - } else if (act == MotionEvent.ACTION_POINTER_UP) { - // only one pointer going up, we can get the index like this - int pointerIndex = ev.getActionIndex(); - int pointerId = ev.getPointerId(pointerIndex); - mRender.newTouchPosition(0, 0, 0, pointerId); + boolean ret = false; + int act = ev.getAction(); + if (act == ev.ACTION_DOWN) { + mRender.onActionDown((int)ev.getX(), (int)ev.getY()); + ret = true; } - int count = ev.getHistorySize(); - int pcount = ev.getPointerCount(); - - for (int p=0; p < pcount; p++) { - int id = ev.getPointerId(p); - mRender.newTouchPosition(ev.getX(p), - ev.getY(p), - ev.getPressure(p), - id); - - for (int i=0; i < count; i++) { - mRender.newTouchPosition(ev.getHistoricalX(p, i), - ev.getHistoricalY(p, i), - ev.getHistoricalPressure(p, i), - id); - } + else if (act == ev.ACTION_MOVE) { + mRender.onActionMove((int)ev.getX(), (int)ev.getY()); + ret = true; } - return true; + + return ret; } - */ } diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_fp_mad.java b/libs/rs/java/tests/src/com/android/rs/test/UT_fp_mad.java new file mode 100644 index 0000000..c4e57e8 --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/UT_fp_mad.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.test; + +import android.content.res.Resources; +import android.renderscript.*; + +public class UT_fp_mad extends UnitTest { + private Resources mRes; + + protected UT_fp_mad(Resources res) { + super("Fp_Mad"); + mRes = res; + } + + public void run() { + RenderScript pRS = RenderScript.create(); + ScriptC_fp_mad s = new ScriptC_fp_mad(pRS, mRes, R.raw.fp_mad, true); + pRS.mMessageCallback = mRsMessage; + s.invoke_fp_mad_test(0, 0); + pRS.finish(); + pRS.destroy(); + } +} + diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java b/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java new file mode 100644 index 0000000..629f0b2 --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.test; + +import android.content.res.Resources; +import android.renderscript.*; + +public class UT_primitives extends UnitTest { + private Resources mRes; + + protected UT_primitives(Resources res) { + super("Primitives"); + mRes = res; + } + + public void run() { + RenderScript pRS = RenderScript.create(); + ScriptC_primitives s = new ScriptC_primitives(pRS, mRes, R.raw.primitives, true); + pRS.mMessageCallback = mRsMessage; + s.invoke_primitives_test(0, 0); + pRS.finish(); + //android.util.Log.v("UT", "After pRS.finish"); + + pRS.destroy(); + } +} + diff --git a/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java b/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java new file mode 100644 index 0000000..5b55779 --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.test; +import android.renderscript.RenderScript.RSMessage; + +public class UnitTest extends Thread { + public String name; + public int result; + + /* These constants must match those in shared.rsh */ + public static final int RS_MSG_TEST_PASSED = 100; + public static final int RS_MSG_TEST_FAILED = 101; + + protected UnitTest(String n, int initResult) { + super(); + name = n; + result = initResult; + } + + protected UnitTest(String n) { + this(n, 0); + } + + protected UnitTest() { + this ("<Unknown>"); + } + + protected RSMessage mRsMessage = new RSMessage() { + public void run() { + switch (mID) { + case RS_MSG_TEST_PASSED: + result = 1; + break; + case RS_MSG_TEST_FAILED: + result = -1; + break; + default: + break; + } + } + }; + + public void run() { + /* This method needs to be implemented for each subclass */ + } +} + diff --git a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs index 494ff35..eb82e56 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs +++ b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs @@ -3,8 +3,7 @@ const int TEST_COUNT = 1; #pragma rs export_var(g_results) -#pragma rs export_func(doTest) - +#pragma rs export_func(fp_mad_test) static float data_f1[1025]; static float4 data_f4[1025]; @@ -143,7 +142,7 @@ static void test_clamp4(uint32_t index) { rsDebug("fp_clamp4 M ops", 100.f / time); } -void doTest(uint32_t index, int test_num) { +void fp_mad_test(uint32_t index, int test_num) { for (int x=0; x < 1025; x++) { data_f1[x] = (x & 0xf) * 0.1f; data_f4[x].x = (x & 0xf) * 0.1f; @@ -168,6 +167,10 @@ void doTest(uint32_t index, int test_num) { test_sincos(index); test_clamp4(index); test_clamp(index); + + // TODO Actually verify test result accuracy + rsDebug("fp_mad_test PASSED", 0); + rsSendToClient(RS_MSG_TEST_PASSED); } diff --git a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs index 39bd2c4..2ba5d52 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs +++ b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs @@ -1,10 +1,8 @@ #include "shared.rsh" -#pragma rs export_func(rs_primitives_test) +#pragma rs export_func(primitives_test) // Testing primitive types -#pragma rs export_var(floatTest) -#pragma rs export_var(doubleTest) static float floatTest = 1.99f; static double doubleTest = 2.05; static char charTest = -8; @@ -14,7 +12,7 @@ static uchar ucharTest = 8; static ushort ushortTest = 16; static uint uintTest = 32; -static void test_primitive_types(uint32_t index) { +static bool test_primitive_types(uint32_t index) { bool failed = false; start(); @@ -28,17 +26,26 @@ static void test_primitive_types(uint32_t index) { _RS_ASSERT(uintTest == 32); float time = end(index); + if (failed) { - rsDebug("test_primitives FAILED ", time); + rsDebug("test_primitives FAILED", time); } else { - rsDebug("test_primitives PASSED ", time); + rsDebug("test_primitives PASSED", time); } + + return failed; } +void primitives_test(uint32_t index, int test_num) { + bool failed = false; + failed |= test_primitive_types(index); -void rs_primitives_test(uint32_t index, int test_num) { - test_primitive_types(index); + if (failed) { + rsSendToClient(RS_MSG_TEST_FAILED); + } + else { + rsSendToClient(RS_MSG_TEST_PASSED); + } } - diff --git a/libs/rs/java/tests/src/com/android/rs/test/rslist.rs b/libs/rs/java/tests/src/com/android/rs/test/rslist.rs new file mode 100644 index 0000000..fcea3ab --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/rslist.rs @@ -0,0 +1,86 @@ +// Copyright (C) 2009 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. + +#pragma version(1) + +#pragma rs java_package_name(com.android.rs.test) + +#include "rs_graphics.rsh" + +float gDY; + +rs_font gFont; + +typedef struct ListAllocs_s { + rs_allocation text; + int result; +} ListAllocs; + +ListAllocs *gList; + +#pragma rs export_var(gDY, gFont, gList) + +void init() { + gDY = 0.0f; +} + +int textPos = 0; + +int root(int launchID) { + + rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f); + rsgClearDepth(1.0f); + + textPos -= (int)gDY*2; + gDY *= 0.95; + + rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f); + rsgBindFont(gFont); + color(0.2, 0.2, 0.2, 0); + + rs_allocation listAlloc = rsGetAllocation(gList); + int allocSize = rsAllocationGetDimX(listAlloc); + + int width = rsgGetWidth(); + int height = rsgGetHeight(); + + int itemHeight = 80; + int currentYPos = itemHeight + textPos; + + for(int i = 0; i < allocSize; i ++) { + if(currentYPos - itemHeight > height) { + break; + } + + if(currentYPos > 0) { + switch(gList[i].result) { + case 1: /* Passed */ + rsgFontColor(0.5f, 0.9f, 0.5f, 1.0f); + break; + case -1: /* Failed */ + rsgFontColor(0.9f, 0.5f, 0.5f, 1.0f); + break; + case 0: /* Unknown */ + default: + rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f); + break; + } + rsgDrawRect(0, currentYPos - 1, width, currentYPos, 0); + rsgDrawText(gList[i].text, 30, currentYPos - 32); + } + currentYPos += itemHeight; + } + + return 10; +} diff --git a/libs/rs/java/tests/src/com/android/rs/test/shared.rsh b/libs/rs/java/tests/src/com/android/rs/test/shared.rsh index 8c3e5f4..820fffd 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/shared.rsh +++ b/libs/rs/java/tests/src/com/android/rs/test/shared.rsh @@ -25,7 +25,6 @@ static float end(uint32_t idx) { #define _RS_ASSERT(b) \ do { \ - rsDebug("Checking " #b, ((int) (b))); \ if (!(b)) { \ failed = true; \ rsDebug(#b " FAILED", 0); \ @@ -33,3 +32,7 @@ do { \ \ } while (0) +/* These constants must match those in UnitTest.java */ +static const int RS_MSG_TEST_PASSED = 100; +static const int RS_MSG_TEST_FAILED = 101; + diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 7469133..b97c3c4 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -963,14 +963,17 @@ public class AudioTrack //-------------------- /** - * Attaches an auxiliary effect to the audio track. A typical auxiliary effect is a - * reverberation effect which can be applied on any sound source that directs a certain - * amount of its energy to this effect. This amount is defined by setAuxEffectSendLevel(). + * Attaches an auxiliary effect to the audio track. A typical auxiliary + * effect is a reverberation effect which can be applied on any sound source + * that directs a certain amount of its energy to this effect. This amount + * is defined by setAuxEffectSendLevel(). * {@see #setAuxEffectSendLevel(float)}. - * <p>After creating an auxiliary effect (e.g. {@link android.media.EnvironmentalReverb}), - * retrieve its ID with {@link android.media.AudioEffect#getId()} and use it when calling + * <p>After creating an auxiliary effect (e.g. + * {@link android.media.audiofx.EnvironmentalReverb}), retrieve its ID with + * {@link android.media.audiofx.AudioEffect#getId()} and use it when calling * this method to attach the audio track to the effect. - * <p>To detach the effect from the audio track, call this method with a null effect id. + * <p>To detach the effect from the audio track, call this method with a + * null effect id. * * @param effectId system wide unique id of the effect to attach * @return error code or success, see {@link #SUCCESS}, diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 280def9..cb46a29 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -1210,9 +1210,10 @@ public class MediaPlayer * effect which can be applied on any sound source that directs a certain amount of its * energy to this effect. This amount is defined by setAuxEffectSendLevel(). * {@see #setAuxEffectSendLevel(float)}. - * <p>After creating an auxiliary effect (e.g. {@link android.media.EnvironmentalReverb}), - * retrieve its ID with {@link android.media.AudioEffect#getId()} and use it when calling - * this method to attach the player to the effect. + * <p>After creating an auxiliary effect (e.g. + * {@link android.media.audiofx.EnvironmentalReverb}), retrieve its ID with + * {@link android.media.audiofx.AudioEffect#getId()} and use it when calling this method + * to attach the player to the effect. * <p>To detach the effect from the player, call this method with a null effect id. * <p>This method must be called after one of the overloaded <code> setDataSource </code> * methods. diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java index b64299a..403ed58 100644 --- a/media/java/android/media/MtpDatabase.java +++ b/media/java/android/media/MtpDatabase.java @@ -246,8 +246,30 @@ public class MtpDatabase { return new int[] { // allow transfering arbitrary files MtpConstants.FORMAT_UNDEFINED, + MtpConstants.FORMAT_ASSOCIATION, + MtpConstants.FORMAT_TEXT, + MtpConstants.FORMAT_HTML, + MtpConstants.FORMAT_WAV, + MtpConstants.FORMAT_MP3, + MtpConstants.FORMAT_MPEG, + MtpConstants.FORMAT_EXIF_JPEG, + MtpConstants.FORMAT_TIFF_EP, + MtpConstants.FORMAT_GIF, + MtpConstants.FORMAT_JFIF, + MtpConstants.FORMAT_PNG, + MtpConstants.FORMAT_TIFF, + MtpConstants.FORMAT_WMA, + MtpConstants.FORMAT_OGG, + MtpConstants.FORMAT_AAC, + MtpConstants.FORMAT_MP4_CONTAINER, + MtpConstants.FORMAT_MP2, + MtpConstants.FORMAT_3GP_CONTAINER, MtpConstants.FORMAT_ABSTRACT_AV_PLAYLIST, + MtpConstants.FORMAT_WPL_PLAYLIST, + MtpConstants.FORMAT_M3U_PLAYLIST, + MtpConstants.FORMAT_PLS_PLAYLIST, + MtpConstants.FORMAT_XML_DOCUMENT, }; } @@ -260,9 +282,13 @@ public class MtpDatabase { return new int[] { MtpConstants.PROPERTY_STORAGE_ID, MtpConstants.PROPERTY_OBJECT_FORMAT, + MtpConstants.PROPERTY_PROTECTION_STATUS, MtpConstants.PROPERTY_OBJECT_SIZE, MtpConstants.PROPERTY_OBJECT_FILE_NAME, + MtpConstants.PROPERTY_DATE_MODIFIED, MtpConstants.PROPERTY_PARENT_OBJECT, + MtpConstants.PROPERTY_PERSISTENT_UID, + MtpConstants.PROPERTY_NAME, }; } @@ -279,6 +305,11 @@ public class MtpDatabase { String column = null; boolean isString = false; + // temporary hack + if (property == MtpConstants.PROPERTY_NAME) { + property = MtpConstants.PROPERTY_OBJECT_FILE_NAME; + } + switch (property) { case MtpConstants.PROPERTY_STORAGE_ID: outIntValue[0] = mStorageID; diff --git a/media/java/android/media/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index ed7601e..3e54627 100644 --- a/media/java/android/media/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.media; +package android.media.audiofx; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -29,22 +29,35 @@ import java.nio.ByteBuffer; import java.util.UUID; /** - * AudioEffect is the base class for implementing audio effect control in Java - * applications. - * <p>Creating an AudioEffect object will create the effect engine in - * audio framework if no instance of the same effect type exists in the - * specified audio session. If one exists, this instance will be used. - * <p>The application creating the AudioEffect object (or a derived class) will either - * receive control of the effect engine or not depending on the priority - * parameter. If priority is higher than the priority used by the current effect - * engine owner, the control will be transfered to the new object. Otherwise - * control will remain with the previous object. In this case, the new - * application will be notified of changes in effect engine state or control - * ownership by the appropiate listener. - * <p>If the effect is to be applied to a specific AudioTrack or MediaPlayer instance, - * the application must specify the audio session ID of that instance when calling the AudioEffect - * constructor. + * AudioEffect is the base class for controlling audio effects provided by the android audio + * framework. + * <p>Applications should not use the AudioEffect class directly but one of its derived classes to + * control specific effects: + * <ul> + * <li> {@link android.media.audiofx.Equalizer}</li> + * <li> {@link android.media.audiofx.Virtualizer}</li> + * <li> {@link android.media.audiofx.BassBoost}</li> + * <li> {@link android.media.audiofx.PresetReverb}</li> + * <li> {@link android.media.audiofx.EnvironmentalReverb}</li> + * </ul> + * <p>If the audio effect is to be applied to a specific AudioTrack or MediaPlayer instance, + * the application must specify the audio session ID of that instance when creating the AudioEffect. + * (see {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions). + * To apply an effect to the global audio output mix, session 0 must be specified when creating the + * AudioEffect. + * <p>Creating an effect on the output mix (audio session 0) requires permission + * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS} + * <p>Creating an AudioEffect object will create the corresponding effect engine in the audio + * framework if no instance of the same effect type exists in the specified audio session. + * If one exists, this instance will be used. + * <p>The application creating the AudioEffect object (or a derived class) will either receive + * control of the effect engine or not depending on the priority parameter. If priority is higher + * than the priority used by the current effect engine owner, the control will be transfered to the + * new object. Otherwise control will remain with the previous object. In this case, the new + * application will be notified of changes in effect engine state or control ownership by the + * appropiate listener. */ + public class AudioEffect { static { System.loadLibrary("audioeffect_jni"); @@ -62,32 +75,38 @@ public class AudioEffect { /** * UUID for environmental reverb effect + * @hide */ public static final UUID EFFECT_TYPE_ENV_REVERB = UUID .fromString("c2e5d5f0-94bd-4763-9cac-4e234d06839e"); /** * UUID for preset reverb effect + * @hide */ public static final UUID EFFECT_TYPE_PRESET_REVERB = UUID .fromString("47382d60-ddd8-11db-bf3a-0002a5d5c51b"); /** * UUID for equalizer effect + * @hide */ public static final UUID EFFECT_TYPE_EQUALIZER = UUID .fromString("0bed4300-ddd6-11db-8f34-0002a5d5c51b"); /** * UUID for bass boost effect + * @hide */ public static final UUID EFFECT_TYPE_BASS_BOOST = UUID .fromString("0634f220-ddd4-11db-a0fc-0002a5d5c51b"); /** * UUID for virtualizer effect + * @hide */ public static final UUID EFFECT_TYPE_VIRTUALIZER = UUID .fromString("37cc2c00-dddd-11db-8577-0002a5d5c51b"); /** * Null effect UUID. Used when the UUID for effect type of + * @hide */ public static final UUID EFFECT_TYPE_NULL = UUID .fromString("ec7178ec-e5e1-4432-a3f4-4657e6795210"); @@ -95,10 +114,12 @@ public class AudioEffect { /** * State of an AudioEffect object that was not successfully initialized upon * creation + * @hide */ public static final int STATE_UNINITIALIZED = 0; /** * State of an AudioEffect object that is ready to be used. + * @hide */ public static final int STATE_INITIALIZED = 1; @@ -106,14 +127,17 @@ public class AudioEffect { // frameworks/base/include/media/AudioEffect.h /** * Event id for engine control ownership change notification. + * @hide */ public static final int NATIVE_EVENT_CONTROL_STATUS = 0; /** * Event id for engine state change notification. + * @hide */ public static final int NATIVE_EVENT_ENABLED_STATUS = 1; /** * Event id for engine parameter change notification. + * @hide */ public static final int NATIVE_EVENT_PARAMETER_CHANGED = 2; @@ -151,15 +175,17 @@ public class AudioEffect { public static final int ERROR_DEAD_OBJECT = -7; /** - * The effect descriptor contains necessary information to facilitate - * effects enumeration:<br> + * The effect descriptor contains information on a particular effect implemented in the + * audio framework:<br> * <ul> - * <li>mType: UUID corresponding to the OpenSL ES interface implemented by this effect</li> - * <li>mUuid: UUID for this particular implementation</li> - * <li>mConnectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}</li> - * <li>mName: human readable effect name</li> - * <li>mImplementor: human readable effect implementor name</li> + * <li>type: UUID corresponding to the OpenSL ES interface implemented by this effect</li> + * <li>uuid: UUID for this particular implementation</li> + * <li>connectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}</li> + * <li>name: human readable effect name</li> + * <li>implementor: human readable effect implementor name</li> * </ul> + * The method {@link #queryEffects()} returns an array of Descriptors to facilitate effects + * enumeration. */ public static class Descriptor { @@ -168,18 +194,39 @@ public class AudioEffect { public Descriptor(String type, String uuid, String connectMode, String name, String implementor) { - mType = UUID.fromString(type); - mUuid = UUID.fromString(uuid); - mConnectMode = connectMode; - mName = name; - mImplementor = implementor; + this.type = UUID.fromString(type); + this.uuid = UUID.fromString(uuid); + this.connectMode = connectMode; + this.name = name; + this.implementor = implementor; } - public UUID mType; - public UUID mUuid; - public String mConnectMode; - public String mName; - public String mImplementor; + /** + * Indicates the generic type of the effect (Equalizer, Bass boost ...). The UUID + * corresponds to the OpenSL ES Interface ID for this type of effect. + */ + public UUID type; + /** + * Indicates the particular implementation of the effect in that type. Several effects + * can have the same type but this uuid is unique to a given implementation. + */ + public UUID uuid; + /** + * Indicates if the effect is of insert category {@link #EFFECT_INSERT} or auxiliary + * category {@link #EFFECT_AUXILIARY}. Insert effects (Typically an Equalizer) are applied + * to the entire audio source and usually not shared by several sources. Auxiliary effects + * (typically a reverberator) are applied to part of the signal (wet) and the effect output + * is added to the original signal (dry). + */ + public String connectMode; + /** + * Human readable effect name + */ + public String name; + /** + * Human readable effect implementor name + */ + public String implementor; }; /** @@ -242,10 +289,12 @@ public class AudioEffect { private OnParameterChangeListener mParameterChangeListener = null; /** * Lock to protect listeners updates against event notifications + * @hide */ public final Object mListenerLock = new Object(); /** * Handler for events coming from the native code + * @hide */ public NativeEventHandler mNativeEventHandler = null; @@ -283,6 +332,7 @@ public class AudioEffect { * @throws java.lang.IllegalArgumentException * @throws java.lang.UnsupportedOperationException * @throws java.lang.RuntimeException + * @hide */ public AudioEffect(UUID type, UUID uuid, int priority, int audioSession) @@ -337,7 +387,7 @@ public class AudioEffect { /** * Get the effect descriptor. * - * @see android.media.AudioEffect.Descriptor + * @see android.media.audiofx.AudioEffect.Descriptor * @throws IllegalStateException */ public Descriptor getDescriptor() throws IllegalStateException { @@ -351,7 +401,7 @@ public class AudioEffect { /** * Query all effects available on the platform. Returns an array of - * {@link android.media.AudioEffect.Descriptor} objects + * {@link android.media.audiofx.AudioEffect.Descriptor} objects * * @throws IllegalStateException */ @@ -365,7 +415,11 @@ public class AudioEffect { // -------------------- /** - * Enable or disable effect engine. + * Enable or disable the effect. + * Creating an audio effect does not automatically apply this effect on the audio source. It + * creates the resources necessary to process this effect but the audio signal is still bypassed + * through the effect engine. Calling this method will make that the effect is actually applied + * or not to the audio content being played in the corresponding audio session. * * @param enabled the requested enable state * @return {@link #SUCCESS} in case of success, {@link #ERROR_INVALID_OPERATION} @@ -392,6 +446,7 @@ public class AudioEffect { * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or * {@link #ERROR_DEAD_OBJECT} in case of failure * @throws IllegalStateException + * @hide */ public int setParameter(byte[] param, byte[] value) throws IllegalStateException { @@ -403,6 +458,7 @@ public class AudioEffect { * Set effect parameter. The parameter and its value are integers. * * @see #setParameter(byte[], byte[]) + * @hide */ public int setParameter(int param, int value) throws IllegalStateException { byte[] p = intToByteArray(param); @@ -415,6 +471,7 @@ public class AudioEffect { * short integer. * * @see #setParameter(byte[], byte[]) + * @hide */ public int setParameter(int param, short value) throws IllegalStateException { @@ -428,6 +485,7 @@ public class AudioEffect { * array of bytes. * * @see #setParameter(byte[], byte[]) + * @hide */ public int setParameter(int param, byte[] value) throws IllegalStateException { @@ -440,6 +498,7 @@ public class AudioEffect { * the value is also an array of 1 or 2 integers * * @see #setParameter(byte[], byte[]) + * @hide */ public int setParameter(int[] param, int[] value) throws IllegalStateException { @@ -464,6 +523,7 @@ public class AudioEffect { * the value is an array of 1 or 2 short integers * * @see #setParameter(byte[], byte[]) + * @hide */ public int setParameter(int[] param, short[] value) throws IllegalStateException { @@ -489,6 +549,7 @@ public class AudioEffect { * the value is an array of bytes * * @see #setParameter(byte[], byte[]) + * @hide */ public int setParameter(int[] param, byte[] value) throws IllegalStateException { @@ -519,6 +580,7 @@ public class AudioEffect { * returning, value.length is updated with the actual size of the * returned value. * @throws IllegalStateException + * @hide */ public int getParameter(byte[] param, byte[] value) throws IllegalStateException { @@ -539,6 +601,7 @@ public class AudioEffect { * array of bytes. * * @see #getParameter(byte[], byte[]) + * @hide */ public int getParameter(int param, byte[] value) throws IllegalStateException { @@ -552,6 +615,7 @@ public class AudioEffect { * array of 1 or 2 integers * * @see #getParameter(byte[], byte[]) + * @hide */ public int getParameter(int param, int[] value) throws IllegalStateException { @@ -576,6 +640,7 @@ public class AudioEffect { * array of 1 or 2 short integers * * @see #getParameter(byte[], byte[]) + * @hide */ public int getParameter(int param, short[] value) throws IllegalStateException { @@ -600,6 +665,7 @@ public class AudioEffect { * the value is also an array of 1 or 2 integers * * @see #getParameter(byte[], byte[]) + * @hide */ public int getParameter(int[] param, int[] value) throws IllegalStateException { @@ -627,6 +693,7 @@ public class AudioEffect { * the value is an array of 1 or 2 short integers * * @see #getParameter(byte[], byte[]) + * @hide */ public int getParameter(int[] param, short[] value) throws IllegalStateException { @@ -654,6 +721,7 @@ public class AudioEffect { * the value is an array of bytes * * @see #getParameter(byte[], byte[]) + * @hide */ public int getParameter(int[] param, byte[] value) throws IllegalStateException { @@ -673,6 +741,7 @@ public class AudioEffect { * Send a command to the effect engine. This method is intended to send * proprietary commands to a particular effect implementation. * + * @hide */ public int command(int cmdCode, byte[] command, byte[] reply) throws IllegalStateException { @@ -709,7 +778,7 @@ public class AudioEffect { } /** - * Returns effect engine enable state + * Returns effect enabled state * * @return true if the effect is enabled, false otherwise. * @throws IllegalStateException @@ -768,6 +837,7 @@ public class AudioEffect { * Sets the listener AudioEffect notifies when a parameter is changed. * * @param listener + * @hide */ public void setParameterListener(OnParameterChangeListener listener) { synchronized (mListenerLock) { @@ -828,6 +898,7 @@ public class AudioEffect { /** * The OnParameterChangeListener interface defines a method called by the AudioEffect * when a parameter is changed in the effect engine by the controlling application. + * @hide */ public interface OnParameterChangeListener { /** @@ -914,8 +985,7 @@ public class AudioEffect { * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents. * <p>The extra value is of type int and is the audio session ID. - * - * @see android.media.MediaPlayer#setAudioSessionId(int) + * @see android.media.MediaPlayer#getAudioSessionId() for details on audio sessions. */ public static final String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION"; @@ -1086,6 +1156,9 @@ public class AudioEffect { // Utility methods // ------------------ + /** + * @hide + */ public void checkState(String methodName) throws IllegalStateException { synchronized (mStateLock) { if (mState != STATE_INITIALIZED) { @@ -1095,6 +1168,9 @@ public class AudioEffect { } } + /** + * @hide + */ public void checkStatus(int status) { switch (status) { case AudioEffect.SUCCESS: @@ -1110,11 +1186,17 @@ public class AudioEffect { } } + /** + * @hide + */ public int byteArrayToInt(byte[] valueBuf) { return byteArrayToInt(valueBuf, 0); } + /** + * @hide + */ public int byteArrayToInt(byte[] valueBuf, int offset) { ByteBuffer converter = ByteBuffer.wrap(valueBuf); converter.order(ByteOrder.nativeOrder()); @@ -1122,6 +1204,9 @@ public class AudioEffect { } + /** + * @hide + */ public byte[] intToByteArray(int value) { ByteBuffer converter = ByteBuffer.allocate(4); converter.order(ByteOrder.nativeOrder()); @@ -1129,10 +1214,16 @@ public class AudioEffect { return converter.array(); } + /** + * @hide + */ public short byteArrayToShort(byte[] valueBuf) { return byteArrayToShort(valueBuf, 0); } + /** + * @hide + */ public short byteArrayToShort(byte[] valueBuf, int offset) { ByteBuffer converter = ByteBuffer.wrap(valueBuf); converter.order(ByteOrder.nativeOrder()); @@ -1140,6 +1231,9 @@ public class AudioEffect { } + /** + * @hide + */ public byte[] shortToByteArray(short value) { ByteBuffer converter = ByteBuffer.allocate(2); converter.order(ByteOrder.nativeOrder()); @@ -1148,6 +1242,9 @@ public class AudioEffect { return converter.array(); } + /** + * @hide + */ public byte[] concatArrays(byte[]... arrays) { int len = 0; for (byte[] a : arrays) { @@ -1162,5 +1259,4 @@ public class AudioEffect { } return b; } - } diff --git a/media/java/android/media/BassBoost.java b/media/java/android/media/audiofx/BassBoost.java index 476b056..ca55f0f 100644 --- a/media/java/android/media/BassBoost.java +++ b/media/java/android/media/audiofx/BassBoost.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package android.media; +package android.media.audiofx; import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.media.AudioEffect; +import android.media.audiofx.AudioEffect; import android.os.Bundle; import android.util.Log; @@ -32,15 +32,19 @@ import java.util.StringTokenizer; /** * Bass boost is an audio effect to boost or amplify low frequencies of the sound. It is comparable * to a simple equalizer but limited to one band amplification in the low frequency range. - * <p>An application creates a BassBoost object to instantiate and control a bass boost engine - * in the audio framework. + * <p>An application creates a BassBoost object to instantiate and control a bass boost engine in + * the audio framework. * <p>The methods, parameter types and units exposed by the BassBoost implementation are directly * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/) * for the SLBassBoostItf interface. Please refer to this specification for more details. * <p>To attach the BassBoost to a particular AudioTrack or MediaPlayer, specify the audio session - * ID of this AudioTrack or MediaPlayer when constructing the BassBoost. If the audio session ID 0 - * is specified, the BassBoost applies to the main audio output mix. - * <p> See {@link android.media.AudioEffect} class for more details on controlling audio effects. + * ID of this AudioTrack or MediaPlayer when constructing the BassBoost. + * If the audio session ID 0 is specified, the BassBoost applies to the main audio output mix. + * <p>Creating a BassBoost on the output mix (audio session 0) requires permission + * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS} + * <p>See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions. + * <p>See {@link android.media.audiofx.AudioEffect} class for more details on + * controlling audio effects. */ public class BassBoost extends AudioEffect { @@ -55,7 +59,7 @@ public class BassBoost extends AudioEffect { public static final int PARAM_STRENGTH_SUPPORTED = 0; /** * Bass boost effect strength. Parameter ID for - * {@link android.media.BassBoost.OnParameterChangeListener} + * {@link android.media.audiofx.BassBoost.OnParameterChangeListener} */ public static final int PARAM_STRENGTH = 1; @@ -155,7 +159,6 @@ public class BassBoost extends AudioEffect { * BassBoost engine. * @param effect the BassBoost on which the interface is registered. * @param status status of the set parameter operation. - * See {@link android.media.AudioEffect#setParameter(byte[], byte[])}. * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ... * @param value the new parameter value. */ diff --git a/media/java/android/media/EnvironmentalReverb.java b/media/java/android/media/audiofx/EnvironmentalReverb.java index b50febc..f1f582e 100644 --- a/media/java/android/media/EnvironmentalReverb.java +++ b/media/java/android/media/audiofx/EnvironmentalReverb.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package android.media; +package android.media.audiofx; import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.media.AudioEffect; +import android.media.audiofx.AudioEffect; import android.os.Bundle; import android.util.Log; @@ -28,18 +28,18 @@ import java.nio.ByteBuffer; import java.util.StringTokenizer; /** - * A sound generated within a room travels in many directions. The listener first hears the - * direct sound from the source itself. Later, he or she hears discrete echoes caused by sound - * bouncing off nearby walls, the ceiling and the floor. As sound waves arrive after - * undergoing more and more reflections, individual reflections become indistinguishable and - * the listener hears continuous reverberation that decays over time. + * A sound generated within a room travels in many directions. The listener first hears the direct + * sound from the source itself. Later, he or she hears discrete echoes caused by sound bouncing off + * nearby walls, the ceiling and the floor. As sound waves arrive after undergoing more and more + * reflections, individual reflections become indistinguishable and the listener hears continuous + * reverberation that decays over time. * Reverb is vital for modeling a listener's environment. It can be used in music applications * to simulate music being played back in various environments, or in games to immerse the * listener within the game's environment. * The EnvironmentalReverb class allows an application to control each reverb engine property in a * global reverb environment and is more suitable for games. For basic control, more suitable for * music applications, it is recommended to use the - * {@link android.media.PresetReverb} class. + * {@link android.media.audiofx.PresetReverb} class. * <p>An application creates a EnvironmentalReverb object to instantiate and control a reverb engine * in the audio framework. * <p>The methods, parameter types and units exposed by the EnvironmentalReverb implementation are @@ -51,7 +51,9 @@ import java.util.StringTokenizer; * they must be explicitely attached to it and a send level must be specified. Use the effect ID * returned by getId() method to designate this particular effect when attaching it to the * MediaPlayer or AudioTrack. - * <p> See {@link android.media.AudioEffect} class for more details on controlling + * <p>Creating a reverb on the output mix (audio session 0) requires permission + * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS} + * <p>See {@link android.media.audiofx.AudioEffect} class for more details on controlling * audio effects. */ @@ -76,7 +78,7 @@ public class EnvironmentalReverb extends AudioEffect { public static final int PARAM_DECAY_TIME = 2; /** * Decay HF ratio. Parameter ID for - * {@link android.media.EnvironmentalReverb.OnParameterChangeListener} + * {@link android.media.audiofx.EnvironmentalReverb.OnParameterChangeListener} */ public static final int PARAM_DECAY_HF_RATIO = 3; /** @@ -444,7 +446,6 @@ public class EnvironmentalReverb extends AudioEffect { * EnvironmentalReverb engine. * @param effect the EnvironmentalReverb on which the interface is registered. * @param status status of the set parameter operation. - * See {@link android.media.AudioEffect#setParameter(byte[], byte[])}. * @param param ID of the modified parameter. See {@link #PARAM_ROOM_LEVEL} ... * @param value the new parameter value. */ diff --git a/media/java/android/media/Equalizer.java b/media/java/android/media/audiofx/Equalizer.java index 6fa48c5..b3bafa9 100644 --- a/media/java/android/media/Equalizer.java +++ b/media/java/android/media/audiofx/Equalizer.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package android.media; +package android.media.audiofx; import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.media.AudioEffect; +import android.media.audiofx.AudioEffect; import android.os.Bundle; import android.util.Log; @@ -41,7 +41,11 @@ import java.util.StringTokenizer; * <p>To attach the Equalizer to a particular AudioTrack or MediaPlayer, specify the audio session * ID of this AudioTrack or MediaPlayer when constructing the Equalizer. If the audio session ID 0 * is specified, the Equalizer applies to the main audio output mix. - * <p> See {@link android.media.AudioEffect} class for more details on controlling audio effects. + * <p>Creating an Equalizer on the output mix (audio session 0) requires permission + * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS} + * <p>See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions. + * <p>See {@link android.media.audiofx.AudioEffect} class for more details on controlling audio + * effects. */ public class Equalizer extends AudioEffect { @@ -68,7 +72,7 @@ public class Equalizer extends AudioEffect { public static final int PARAM_CENTER_FREQ = 3; /** * Band frequency range. Parameter ID for - * {@link android.media.Equalizer.OnParameterChangeListener} + * {@link android.media.audiofx.Equalizer.OnParameterChangeListener} */ public static final int PARAM_BAND_FREQ_RANGE = 4; /** @@ -380,7 +384,6 @@ public class Equalizer extends AudioEffect { * Equalizer engine. * @param effect the Equalizer on which the interface is registered. * @param status status of the set parameter operation. - * See {@link android.media.AudioEffect#setParameter(byte[], byte[])}. * @param param1 ID of the modified parameter. See {@link #PARAM_BAND_LEVEL} ... * @param param2 additional parameter qualifier (e.g the band for band level parameter). * @param value the new parameter value. diff --git a/media/java/android/media/PresetReverb.java b/media/java/android/media/audiofx/PresetReverb.java index 65175ff..7a89ae7 100644 --- a/media/java/android/media/PresetReverb.java +++ b/media/java/android/media/audiofx/PresetReverb.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package android.media; +package android.media.audiofx; import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.media.AudioEffect; +import android.media.audiofx.AudioEffect; import android.os.Bundle; import android.util.Log; @@ -40,7 +40,7 @@ import java.util.StringTokenizer; * The PresetReverb class allows an application to configure the global reverb using a reverb preset. * This is primarily used for adding some reverb in a music playback context. Applications * requiring control over a more advanced environmental reverb are advised to use the - * {@link android.media.EnvironmentalReverb} class. + * {@link android.media.audiofx.EnvironmentalReverb} class. * <p>An application creates a PresetReverb object to instantiate and control a reverb engine in the * audio framework. * <p>The methods, parameter types and units exposed by the PresetReverb implementation are @@ -52,7 +52,10 @@ import java.util.StringTokenizer; * they must be explicitely attached to it and a send level must be specified. Use the effect ID * returned by getId() method to designate this particular effect when attaching it to the * MediaPlayer or AudioTrack. - * <p> See {@link android.media.AudioEffect} class for more details on controlling audio effects. + * <p>Creating a reverb on the output mix (audio session 0) requires permission + * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS} + * <p>See {@link android.media.audiofx.AudioEffect} class for more details on controlling + * audio effects. */ public class PresetReverb extends AudioEffect { @@ -64,7 +67,7 @@ public class PresetReverb extends AudioEffect { /** * Preset. Parameter ID for - * {@link android.media.PresetReverb.OnParameterChangeListener} + * {@link android.media.audiofx.PresetReverb.OnParameterChangeListener} */ public static final int PARAM_PRESET = 0; @@ -174,7 +177,6 @@ public class PresetReverb extends AudioEffect { * PresetReverb engine. * @param effect the PresetReverb on which the interface is registered. * @param status status of the set parameter operation. - * See {@link android.media.AudioEffect#setParameter(byte[], byte[])}. * @param param ID of the modified parameter. See {@link #PARAM_PRESET} ... * @param value the new parameter value. */ diff --git a/media/java/android/media/Virtualizer.java b/media/java/android/media/audiofx/Virtualizer.java index b08f36e..a682a45 100644 --- a/media/java/android/media/Virtualizer.java +++ b/media/java/android/media/audiofx/Virtualizer.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package android.media; +package android.media.audiofx; import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.media.AudioEffect; +import android.media.audiofx.AudioEffect; import android.os.Bundle; import android.util.Log; @@ -42,7 +42,11 @@ import java.util.StringTokenizer; * <p>To attach the Virtualizer to a particular AudioTrack or MediaPlayer, specify the audio session * ID of this AudioTrack or MediaPlayer when constructing the Virtualizer. If the audio session ID 0 * is specified, the Virtualizer applies to the main audio output mix. - * <p> See {@link android.media.AudioEffect} class for more details on controlling audio effects. + * <p>Creating a Virtualizer on the output mix (audio session 0) requires permission + * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS} + * <p>See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions. + * <p>See {@link android.media.audiofx.AudioEffect} class for more details on controlling + * audio effects. */ public class Virtualizer extends AudioEffect { @@ -56,7 +60,7 @@ public class Virtualizer extends AudioEffect { public static final int PARAM_STRENGTH_SUPPORTED = 0; /** * Virtualizer effect strength. Parameter ID for - * {@link android.media.Virtualizer.OnParameterChangeListener} + * {@link android.media.audiofx.Virtualizer.OnParameterChangeListener} */ public static final int PARAM_STRENGTH = 1; @@ -156,7 +160,6 @@ public class Virtualizer extends AudioEffect { * Virtualizer engine. * @param effect the Virtualizer on which the interface is registered. * @param status status of the set parameter operation. - * See {@link android.media.AudioEffect#setParameter(byte[], byte[])}. * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ... * @param value the new parameter value. */ diff --git a/media/java/android/media/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java index 33222ff..0c48556 100755 --- a/media/java/android/media/Visualizer.java +++ b/media/java/android/media/audiofx/Visualizer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.media; +package android.media.audiofx; import android.util.Log; import java.lang.ref.WeakReference; @@ -32,8 +32,8 @@ import android.os.Message; * visualized:<br> * <ul> * <li>If the session is 0, the audio output mix is visualized</li> - * <li>If the session is not 0, the audio from a particular {@link MediaPlayer} or - * {@link AudioTrack} + * <li>If the session is not 0, the audio from a particular {@link android.media.MediaPlayer} or + * {@link android.media.AudioTrack} * using this audio session is visualized </li> * </ul> * <p>Two types of representation of audio content can be captured: <br> @@ -57,6 +57,8 @@ import android.os.Message; * When data capture is not needed any more, the Visualizer should be disabled. * <p>It is good practice to call the {@link #release()} method when the Visualizer is not used * anymore to free up native resources associated to the Visualizer instance. + * <p>Creating a Visualizer on the output mix (audio session 0) requires permission + * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS} */ public class Visualizer { diff --git a/media/java/android/media/audiofx/package.html b/media/java/android/media/audiofx/package.html new file mode 100644 index 0000000..c6e4892 --- /dev/null +++ b/media/java/android/media/audiofx/package.html @@ -0,0 +1,5 @@ +<HTML> +<BODY> +Provides classes that manage audio effects implemented in the media framework. +</BODY> +</HTML> diff --git a/media/java/android/media/videoeditor/Effect.java b/media/java/android/media/videoeditor/Effect.java index 177b863..8c39577 100755 --- a/media/java/android/media/videoeditor/Effect.java +++ b/media/java/android/media/videoeditor/Effect.java @@ -84,7 +84,7 @@ public abstract class Effect { * 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 begining
+ * @param startTimeMs The start time of the effect relative to the beginning
* of the media item in milliseconds
*/
public void setStartTime(long startTimeMs) {
diff --git a/media/java/android/media/videoeditor/MediaItem.java b/media/java/android/media/videoeditor/MediaItem.java index 9e32744..e7be35d 100755 --- a/media/java/android/media/videoeditor/MediaItem.java +++ b/media/java/android/media/videoeditor/MediaItem.java @@ -64,8 +64,8 @@ public abstract class MediaItem { private int mRenderingMode;
// Beginning and end transitions
- private Transition mBeginTransition;
- private Transition mEndTransition;
+ protected Transition mBeginTransition;
+ protected Transition mEndTransition;
/**
* Constructor
@@ -113,6 +113,13 @@ public abstract class MediaItem { */
public void setRenderingMode(int renderingMode) {
mRenderingMode = renderingMode;
+ if (mBeginTransition != null) {
+ mBeginTransition.invalidate();
+ }
+
+ if (mEndTransition != null) {
+ mEndTransition.invalidate();
+ }
}
/**
@@ -271,7 +278,9 @@ public abstract class MediaItem { *
* @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.
+ * 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 (mOverlays.contains(overlay)) {
@@ -283,6 +292,23 @@ public abstract class MediaItem { "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");
+ }
+
+ // The dimensions of the overlay bitmap must be the same as the
+ // media item dimensions
+ if (bitmap.getWidth() != getWidth() || bitmap.getHeight() != getHeight()) {
+ throw new IllegalArgumentException(
+ "Bitmap dimensions must match media item dimensions");
+ }
+ } else {
+ throw new IllegalArgumentException("Overlay not supported");
+ }
+
mOverlays.add(overlay);
invalidateTransitions(overlay);
}
@@ -302,6 +328,9 @@ public abstract class MediaItem { for (Overlay overlay : mOverlays) {
if (overlay.getId().equals(overlayId)) {
mOverlays.remove(overlay);
+ if (overlay instanceof OverlayFrame) {
+ ((OverlayFrame)overlay).invalidate();
+ }
invalidateTransitions(overlay);
return overlay;
}
diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java index 87e9a22..af50b83 100755 --- a/media/java/android/media/videoeditor/MediaVideoItem.java +++ b/media/java/android/media/videoeditor/MediaVideoItem.java @@ -264,8 +264,19 @@ public class MediaVideoItem extends MediaItem { throw new IllegalArgumentException("Invalid end time");
}
- mBeginBoundaryTimeMs = beginMs;
- mEndBoundaryTimeMs = endMs;
+ if (beginMs != mBeginBoundaryTimeMs) {
+ mBeginBoundaryTimeMs = beginMs;
+ if (mBeginTransition != null) {
+ mBeginTransition.invalidate();
+ }
+ }
+
+ if (endMs == mEndBoundaryTimeMs) {
+ mEndBoundaryTimeMs = endMs;
+ if (mEndTransition != null) {
+ mEndTransition.invalidate();
+ }
+ }
// TODO: Validate/modify the start and the end time of effects and overlays
}
diff --git a/media/java/android/media/videoeditor/OverlayFrame.java b/media/java/android/media/videoeditor/OverlayFrame.java index e5d9b81..3abac6c 100755 --- a/media/java/android/media/videoeditor/OverlayFrame.java +++ b/media/java/android/media/videoeditor/OverlayFrame.java @@ -16,16 +16,24 @@ 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. This class
- * does not manage deletion of the overlay file so application may use
- * {@link #getFilename()} for this purpose.
+ * This class is used to overlay an image on top of a media item.
* {@hide}
*/
public class OverlayFrame extends Overlay {
// Instance variables
- private final String mFilename;
+ private final Bitmap mBitmap;
+ private String mFilename;
/**
* An object of this type cannot be instantiated by using the default
@@ -33,30 +41,90 @@ public class OverlayFrame extends Overlay { */
@SuppressWarnings("unused")
private OverlayFrame() {
- this(null, null, 0, 0);
+ this(null, (String)null, 0, 0);
}
/**
* Constructor for an OverlayFrame
*
* @param overlayId The overlay id
- * @param filename The file name that contains the overlay. Only PNG
- * supported.
+ * @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(String overlayId, String filename, long startTimeMs, long durationMs) {
+ public OverlayFrame(String overlayId, Bitmap bitmap, long startTimeMs,
+ long durationMs) {
+ super(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 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(String overlayId, String filename, long startTimeMs, long durationMs) {
super(overlayId, startTimeMs, durationMs);
mFilename = filename;
+ mBitmap = BitmapFactory.decodeFile(mFilename);
+ }
+
+ /**
+ * @return Get the overlay bitmap
+ */
+ public Bitmap getBitmap() {
+ return mBitmap;
}
/**
* Get the file name of this overlay
*/
- public String getFilename() {
+ String getFilename() {
return mFilename;
}
+
+ /**
+ * Save the overlay to the project folder
+ *
+ * @param editor The video editor
+ *
+ * @return
+ * @throws FileNotFoundException if the bitmap cannot be saved
+ * @throws IOException if the bitmap file cannot be saved
+ */
+ String save(VideoEditor editor) throws FileNotFoundException, IOException {
+ if (mFilename != null) {
+ return mFilename;
+ }
+
+ mFilename = editor.getPath() + "/" + 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();
+ }
+ }
}
diff --git a/media/java/android/media/videoeditor/TransitionAlpha.java b/media/java/android/media/videoeditor/TransitionAlpha.java index 0a4a12f..30e66fc 100755 --- a/media/java/android/media/videoeditor/TransitionAlpha.java +++ b/media/java/android/media/videoeditor/TransitionAlpha.java @@ -58,17 +58,19 @@ public class TransitionAlpha extends Transition { * 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 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
+ * @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.
*/
diff --git a/media/java/android/media/videoeditor/VideoEditorTestImpl.java b/media/java/android/media/videoeditor/VideoEditorTestImpl.java index 14e2658..7226d5d 100644 --- a/media/java/android/media/videoeditor/VideoEditorTestImpl.java +++ b/media/java/android/media/videoeditor/VideoEditorTestImpl.java @@ -48,8 +48,8 @@ public class VideoEditorTestImpl implements VideoEditor { 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"; - private static final String TAG_BEGIN_TRANSITION = "begin_transition"; - private static final String TAG_END_TRANSITION = "end_transition"; + private static final String TAG_TRANSITIONS = "transitions"; + private static final String TAG_TRANSITION = "transition"; private static final String ATTR_ID = "id"; private static final String ATTR_FILENAME = "filename"; private static final String ATTR_AUDIO_WAVEFORM_FILENAME = "wavefoem"; @@ -65,6 +65,8 @@ public class VideoEditorTestImpl implements VideoEditor { private static final String ATTR_BLENDING = "blending"; private static final String ATTR_INVERT = "invert"; private static final String ATTR_MASK = "mask"; + private static final String ATTR_BEFORE_MEDIA_ITEM_ID = "before_media_item"; + private static final String ATTR_AFTER_MEDIA_ITEM_ID = "after_media_item"; // Instance variables private long mDurationMs; @@ -400,6 +402,7 @@ public class VideoEditorTestImpl implements VideoEditor { } beforeMediaItem.setBeginTransition(transition); } + computeTimelineDuration(); } @@ -412,22 +415,25 @@ public class VideoEditorTestImpl implements VideoEditor { } final Transition transition = getTransition(transitionId); - if (transition != null) { - mTransitions.remove(transition); - transition.invalidate(); - computeTimelineDuration(); + if (transition == null) { + throw new IllegalStateException("Transition not found: " + transitionId); } - // Cross reference the transitions + // 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(); + return transition; } @@ -543,15 +549,14 @@ public class VideoEditorTestImpl implements VideoEditor { serializer.startTag("", TAG_PROJECT); serializer.attribute("", ATTR_ASPECT_RATIO, Integer.toString(mAspectRatio)); - boolean firstMediaItem = true; 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())); + serializer.attribute("", ATTR_RENDERING_MODE, Integer.toString( + mediaItem.getRenderingMode())); if (mediaItem instanceof MediaVideoItem) { final MediaVideoItem mvi = (MediaVideoItem)mediaItem; serializer @@ -559,54 +564,49 @@ public class VideoEditorTestImpl implements VideoEditor { serializer.attribute("", ATTR_END_TIME, Long.toString(mvi.getBoundaryEndTime())); serializer.attribute("", ATTR_VOLUME, Integer.toString(mvi.getVolume())); if (mvi.getAudioWaveformFilename() != null) { - serializer.attribute("", ATTR_AUDIO_WAVEFORM_FILENAME, mvi - .getAudioWaveformFilename()); + serializer.attribute("", ATTR_AUDIO_WAVEFORM_FILENAME, + mvi.getAudioWaveformFilename()); } } else if (mediaItem instanceof MediaImageItem) { serializer.attribute("", ATTR_DURATION, Long.toString(mediaItem.getDuration())); } - if (firstMediaItem) { - firstMediaItem = false; - final Transition beginTransition = mediaItem.getBeginTransition(); - if (beginTransition != null) { - serializer.startTag("", TAG_BEGIN_TRANSITION); - serializer.attribute("", ATTR_ID, beginTransition.getId()); - serializer.attribute("", ATTR_TYPE, beginTransition.getClass() - .getSimpleName()); - serializer.attribute("", ATTR_DURATION, Long.toString(beginTransition - .getDuration())); - serializer.attribute("", ATTR_BEHAVIOR, Integer.toString(beginTransition - .getBehavior())); - serializer.endTag("", TAG_BEGIN_TRANSITION); - } + 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()); } - final Transition endTransition = mediaItem.getEndTransition(); - if (endTransition != null) { - serializer.startTag("", TAG_END_TRANSITION); - serializer.attribute("", ATTR_ID, endTransition.getId()); - serializer.attribute("", ATTR_TYPE, endTransition.getClass().getSimpleName()); - serializer.attribute("", ATTR_DURATION, Long.toString(endTransition - .getDuration())); - serializer.attribute("", ATTR_BEHAVIOR, Integer.toString(endTransition - .getBehavior())); - if (endTransition instanceof TransitionSliding) { - serializer.attribute("", ATTR_DIRECTION, Integer - .toString(((TransitionSliding)endTransition).getDirection())); - } else if (endTransition instanceof TransitionAlpha) { - TransitionAlpha ta = (TransitionAlpha)endTransition; - serializer.attribute("", ATTR_BLENDING, Integer.toString(ta - .getBlendingPercent())); - serializer.attribute("", ATTR_INVERT, Boolean.toString(ta.isInvert())); + 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_END_TRANSITION); } - - serializer.endTag("", TAG_MEDIA_ITEM); + serializer.endTag("", TAG_TRANSITION); } - serializer.endTag("", TAG_MEDIA_ITEMS); + serializer.endTag("", TAG_TRANSITIONS); serializer.endTag("", TAG_PROJECT); serializer.endDocument(); @@ -628,8 +628,6 @@ public class VideoEditorTestImpl implements VideoEditor { parser.setInput(new FileInputStream(file), "UTF-8"); int eventType = parser.getEventType(); String name; - MediaItem currentMediaItem = null; - MediaItem previousMediaItem = null; while (eventType != XmlPullParser.END_DOCUMENT) { switch (eventType) { case XmlPullParser.START_TAG: { @@ -644,6 +642,7 @@ public class VideoEditorTestImpl implements VideoEditor { final int renderingMode = Integer.parseInt(parser.getAttributeValue("", ATTR_RENDERING_MODE)); + MediaItem currentMediaItem; if (MediaImageItem.class.getSimpleName().equals(type)) { final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION)); @@ -671,29 +670,13 @@ public class VideoEditorTestImpl implements VideoEditor { } if (currentMediaItem != null) { - if (previousMediaItem != null) { - currentMediaItem.setBeginTransition(previousMediaItem - .getEndTransition()); - } mMediaItems.add(currentMediaItem); } - } else if (name.equals(TAG_BEGIN_TRANSITION)) { - final Transition transition = parseTransition(parser, currentMediaItem, - null); - currentMediaItem.setBeginTransition(transition); - } else if (name.equals(TAG_END_TRANSITION)) { - final Transition transition = parseTransition(parser, previousMediaItem, - currentMediaItem); - currentMediaItem.setEndTransition(transition); - } - break; - } - - case XmlPullParser.END_TAG: { - name = parser.getName(); - if (name.equals(TAG_MEDIA_ITEM)) { - previousMediaItem = currentMediaItem; - currentMediaItem = null; + } else if (name.equals(TAG_TRANSITION)) { + final Transition transition = parseTransition(parser); + if (transition != null) { + mTransitions.add(transition); + } } break; } @@ -712,47 +695,72 @@ public class VideoEditorTestImpl implements VideoEditor { * Parse the transition * * @param parser The parser - * @param afterMediaItem The transition is at the end of this media item - * @param beforeMediaItem The transition is at the beginning of this media - * item * @return The transition */ - private Transition parseTransition(XmlPullParser parser, MediaItem beforeMediaItem, - MediaItem afterMediaItem) { + 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 String beforeMediaItemId = parser.getAttributeValue("", ATTR_BEFORE_MEDIA_ITEM_ID); + final MediaItem beforeMediaItem; + if (beforeMediaItemId != null) { + beforeMediaItem = getMediaItem(beforeMediaItemId); + } else { + beforeMediaItem = null; + } + + final String afterMediaItemId = parser.getAttributeValue("", ATTR_AFTER_MEDIA_ITEM_ID); + final MediaItem afterMediaItem; + if (afterMediaItemId != null) { + afterMediaItem = getMediaItem(afterMediaItemId); + } else { + afterMediaItem = null; + } + + final Transition transition; if (TransitionStartCurtainOpening.class.getSimpleName().equals(type)) { - return new TransitionStartCurtainOpening(transitionId, beforeMediaItem, durationMs, - behavior); + transition = new TransitionStartCurtainOpening(transitionId, beforeMediaItem, + durationMs, behavior); } else if (TransitionStartFadeFromBlack.class.getSimpleName().equals(type)) { - return new TransitionStartFadeFromBlack(transitionId, beforeMediaItem, durationMs, - behavior); + transition = new TransitionStartFadeFromBlack(transitionId, beforeMediaItem, + durationMs, behavior); } else if (TransitionAlpha.class.getSimpleName().equals(type)) { final int blending = Integer.parseInt(parser.getAttributeValue("", ATTR_BLENDING)); final String maskFilename = parser.getAttributeValue("", ATTR_MASK); final boolean invert = Boolean.getBoolean(parser.getAttributeValue("", ATTR_INVERT)); - return new TransitionAlpha(transitionId, afterMediaItem, beforeMediaItem, durationMs, - behavior, maskFilename, blending, invert); - } else if (TransitionAlpha.class.getSimpleName().equals(type)) { - return new TransitionCrossfade(transitionId, afterMediaItem, beforeMediaItem, + transition = new TransitionAlpha(transitionId, afterMediaItem, beforeMediaItem, + durationMs, behavior, maskFilename, blending, invert); + } else if (TransitionCrossfade.class.getSimpleName().equals(type)) { + transition = new TransitionCrossfade(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior); } else if (TransitionSliding.class.getSimpleName().equals(type)) { final int direction = Integer.parseInt(parser.getAttributeValue("", ATTR_DIRECTION)); - return new TransitionSliding(transitionId, afterMediaItem, beforeMediaItem, durationMs, - behavior, direction); + transition = new TransitionSliding(transitionId, afterMediaItem, beforeMediaItem, + durationMs, behavior, direction); } else if (TransitionFadeToBlack.class.getSimpleName().equals(type)) { - return new TransitionFadeToBlack(transitionId, afterMediaItem, beforeMediaItem, + transition = new TransitionFadeToBlack(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior); } else if (TransitionEndCurtainClosing.class.getSimpleName().equals(type)) { - return new TransitionEndCurtainClosing(transitionId, beforeMediaItem, durationMs, + transition = new TransitionEndCurtainClosing(transitionId, afterMediaItem, durationMs, behavior); } else if (TransitionEndFadeToBlack.class.getSimpleName().equals(type)) { - return new TransitionEndFadeToBlack(transitionId, beforeMediaItem, durationMs, behavior); + transition = new TransitionEndFadeToBlack(transitionId, afterMediaItem, durationMs, + behavior); + } else { + transition = null; } - return null; + if (beforeMediaItem != null) { + beforeMediaItem.setBeginTransition(transition); + } + + if (afterMediaItem != null) { + afterMediaItem.setEndTransition(transition); + } + + return transition; } public void cancelExport(String filename) { diff --git a/media/jni/android_media_MtpDatabase.cpp b/media/jni/android_media_MtpDatabase.cpp index 1842cb2..227ee92 100644 --- a/media/jni/android_media_MtpDatabase.cpp +++ b/media/jni/android_media_MtpDatabase.cpp @@ -672,12 +672,15 @@ struct PropertyTableEntry { }; static const PropertyTableEntry kObjectPropertyTable[] = { - { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32 }, - { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32 }, - { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16 }, - { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR }, - { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64 }, - { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR }, + { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32 }, + { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16 }, + { MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16 }, + { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64 }, + { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR }, + { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR }, + { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32 }, + { MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128 }, + { MTP_PROPERTY_NAME, MTP_TYPE_STR }, }; static const PropertyTableEntry kDevicePropertyTable[] = { @@ -764,6 +767,7 @@ MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property, case MTP_PROPERTY_PERSISTENT_UID: result = new MtpProperty(property, MTP_TYPE_UINT128); break; + case MTP_PROPERTY_NAME: case MTP_PROPERTY_OBJECT_FILE_NAME: case MTP_PROPERTY_DATE_MODIFIED: result = new MtpProperty(property, MTP_TYPE_STR); @@ -780,6 +784,7 @@ MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) { case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME: // writeable string properties result = new MtpProperty(property, MTP_TYPE_STR, true); + // FIXME - set current value here! break; } diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp index 8d9f4fe..b16372d 100644 --- a/media/jni/audioeffect/android_media_AudioEffect.cpp +++ b/media/jni/audioeffect/android_media_AudioEffect.cpp @@ -37,7 +37,7 @@ using namespace android; #define AUDIOEFFECT_ERROR_DEAD_OBJECT -7 // ---------------------------------------------------------------------------- -static const char* const kClassPathName = "android/media/AudioEffect"; +static const char* const kClassPathName = "android/media/audiofx/AudioEffect"; struct fields_t { // these fields provide access from C++ to the... @@ -228,9 +228,9 @@ android_media_AudioEffect_native_init(JNIEnv *env) return; } - clazz = env->FindClass("android/media/AudioEffect$Descriptor"); + clazz = env->FindClass("android/media/audiofx/AudioEffect$Descriptor"); if (clazz == NULL) { - LOGE("Can't find android/media/AudioEffect$Descriptor class"); + LOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class"); return; } fields.clazzDesc = (jclass)env->NewGlobalRef(clazz); @@ -241,7 +241,7 @@ android_media_AudioEffect_native_init(JNIEnv *env) "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); if (fields.midDescCstor == NULL) { - LOGE("Can't find android/media/AudioEffect$Descriptor class constructor"); + LOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class constructor"); return; } } diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp index 31119f8..7b271ce 100644 --- a/media/jni/audioeffect/android_media_Visualizer.cpp +++ b/media/jni/audioeffect/android_media_Visualizer.cpp @@ -40,7 +40,7 @@ using namespace android; #define NATIVE_EVENT_FFT_CAPTURE 1 // ---------------------------------------------------------------------------- -static const char* const kClassPathName = "android/media/Visualizer"; +static const char* const kClassPathName = "android/media/audiofx/Visualizer"; struct fields_t { // these fields provide access from C++ to the... diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index f0d8943..ba1e218 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -2111,7 +2111,15 @@ void MPEG4Writer::Track::writeTrackHeader( mOwner->endBox(); // d263 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { CHECK(mCodecSpecificData); - CHECK(mCodecSpecificDataSize > 0); + CHECK(mCodecSpecificDataSize >= 5); + + // Patch avcc's lengthSize field to match the number + // of bytes we use to indicate the size of a nal unit. + uint8_t *ptr = (uint8_t *)mCodecSpecificData; + ptr[4] = + (ptr[4] & 0xfc) + | (mOwner->useNalLengthFour() ? 3 : 1); + mOwner->beginBox("avcC"); mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); mOwner->endBox(); // avcC diff --git a/media/mtp/MtpCursor.cpp b/media/mtp/MtpCursor.cpp index 8c964b4..865a294 100644 --- a/media/mtp/MtpCursor.cpp +++ b/media/mtp/MtpCursor.cpp @@ -66,7 +66,8 @@ namespace android { #define OBJECT_THUMB 221 MtpCursor::MtpCursor(MtpClient* client, int queryType, int deviceID, - int storageID, int objectID, int columnCount, int* columns) + MtpStorageID storageID, MtpObjectHandle objectID, + int columnCount, int* columns) : mClient(client), mQueryType(queryType), mDeviceID(deviceID), @@ -427,7 +428,8 @@ bool MtpCursor::putString(CursorWindow* window, const char* text, int row, int c return true; } -bool MtpCursor::putThumbnail(CursorWindow* window, int objectID, int format, int row, int column) { +bool MtpCursor::putThumbnail(CursorWindow* window, MtpObjectHandle objectID, + MtpObjectFormat format, int row, int column) { MtpDevice* device = mClient->getDevice(mDeviceID); void* thumbnail; int size, offset; diff --git a/media/mtp/MtpCursor.h b/media/mtp/MtpCursor.h index 3f84753..9e9833f 100644 --- a/media/mtp/MtpCursor.h +++ b/media/mtp/MtpCursor.h @@ -36,17 +36,18 @@ private: OBJECT_CHILDREN = 8, }; - MtpClient* mClient; - int mQueryType; - int mDeviceID; - int mStorageID; - int mQbjectID; - int mColumnCount; - int* mColumns; + MtpClient* mClient; + int mQueryType; + int mDeviceID; + MtpStorageID mStorageID; + MtpObjectHandle mQbjectID; + int mColumnCount; + int* mColumns; public: MtpCursor(MtpClient* client, int queryType, int deviceID, - int storageID, int objectID, int columnCount, int* columns); + MtpStorageID storageID, MtpObjectHandle objectID, + int columnCount, int* columns); virtual ~MtpCursor(); int fillWindow(CursorWindow* window, int startPos); @@ -68,7 +69,8 @@ private: bool prepareRow(CursorWindow* window); bool putLong(CursorWindow* window, int value, int row, int column); bool putString(CursorWindow* window, const char* text, int row, int column); - bool putThumbnail(CursorWindow* window, int objectID, int format, int row, int column); + bool putThumbnail(CursorWindow* window, MtpObjectHandle objectID, + MtpObjectFormat format, int row, int column); }; }; // namespace android diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp index 6332b4e..84a3e2c 100644 --- a/media/mtp/MtpServer.cpp +++ b/media/mtp/MtpServer.cpp @@ -26,6 +26,8 @@ #include <cutils/properties.h> +#define LOG_TAG "MtpServer" + #include "MtpDebug.h" #include "MtpDatabase.h" #include "MtpProperty.h" @@ -68,8 +70,8 @@ static const MtpOperationCode kSupportedOperationCodes[] = { // MTP_OPERATION_INITIATE_OPEN_CAPTURE, MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED, MTP_OPERATION_GET_OBJECT_PROP_DESC, -// MTP_OPERATION_GET_OBJECT_PROP_VALUE, -// MTP_OPERATION_SET_OBJECT_PROP_VALUE, + MTP_OPERATION_GET_OBJECT_PROP_VALUE, + MTP_OPERATION_SET_OBJECT_PROP_VALUE, MTP_OPERATION_GET_OBJECT_REFERENCES, MTP_OPERATION_SET_OBJECT_REFERENCES, // MTP_OPERATION_SKIP, @@ -294,6 +296,7 @@ bool MtpServer::handleRequest() { response = doGetDevicePropDesc(); break; default: + LOGE("got unsupported command %s", MtpDebug::getOperationCodeName(operation)); response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED; break; } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/EnergyProbe.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/EnergyProbe.java index d339e06..4e4df3b 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/EnergyProbe.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/EnergyProbe.java @@ -16,7 +16,7 @@ package com.android.mediaframeworktest.functional; -import android.media.Visualizer; +import android.media.audiofx.Visualizer; import android.util.Log; /** diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java index fd939ae..34025f6 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java @@ -19,12 +19,12 @@ package com.android.mediaframeworktest.functional; import com.android.mediaframeworktest.MediaFrameworkTest; import com.android.mediaframeworktest.MediaNames; import android.content.res.AssetFileDescriptor; -import android.media.AudioEffect; +import android.media.audiofx.AudioEffect; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; -import android.media.EnvironmentalReverb; -import android.media.Equalizer; +import android.media.audiofx.EnvironmentalReverb; +import android.media.audiofx.Equalizer; import android.media.MediaPlayer; import android.os.Looper; @@ -103,14 +103,14 @@ public class MediaAudioEffectTest extends ActivityInstrumentationTestCase2<Media boolean hasEnvReverb = false; for (int i = 0; i < desc.length; i++) { - if (desc[i].mType.equals(AudioEffect.EFFECT_TYPE_EQUALIZER)) { + if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_EQUALIZER)) { hasEQ = true; - } if (desc[i].mType.equals(AudioEffect.EFFECT_TYPE_BASS_BOOST)) { + } if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_BASS_BOOST)) { hasBassBoost = true; - } else if (desc[i].mType.equals(AudioEffect.EFFECT_TYPE_VIRTUALIZER)) { + } else if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_VIRTUALIZER)) { hasVirtualizer = true; } - else if (desc[i].mType.equals(AudioEffect.EFFECT_TYPE_ENV_REVERB)) { + else if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_ENV_REVERB)) { hasEnvReverb = true; } } @@ -132,7 +132,7 @@ public class MediaAudioEffectTest extends ActivityInstrumentationTestCase2<Media AudioEffect.Descriptor[] desc = AudioEffect.queryEffects(); assertTrue(msg+": no effects found", (desc.length != 0)); try { - AudioEffect effect = new AudioEffect(desc[0].mType, + AudioEffect effect = new AudioEffect(desc[0].type, AudioEffect.EFFECT_TYPE_NULL, 0, 0); @@ -146,7 +146,7 @@ public class MediaAudioEffectTest extends ActivityInstrumentationTestCase2<Media effect.release(); } } catch (IllegalArgumentException e) { - msg = msg.concat(": Effect not found: "+desc[0].mName); + msg = msg.concat(": Effect not found: "+desc[0].name); result = false; } catch (UnsupportedOperationException e) { msg = msg.concat(": Effect library not loaded"); @@ -164,13 +164,13 @@ public class MediaAudioEffectTest extends ActivityInstrumentationTestCase2<Media assertTrue(msg+"no effects found", (desc.length != 0)); try { AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_NULL, - desc[0].mUuid, + desc[0].uuid, 0, 0); assertNotNull(msg + ": could not create AudioEffect", effect); effect.release(); } catch (IllegalArgumentException e) { - msg = msg.concat(": Effect not found: "+desc[0].mName); + msg = msg.concat(": Effect not found: "+desc[0].name); result = false; } catch (UnsupportedOperationException e) { msg = msg.concat(": Effect library not loaded"); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaBassBoostTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaBassBoostTest.java index b5b1c3e..aa5c4d7 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaBassBoostTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaBassBoostTest.java @@ -20,10 +20,10 @@ import com.android.mediaframeworktest.MediaFrameworkTest; import com.android.mediaframeworktest.MediaNames; import android.content.Context; import android.content.res.AssetFileDescriptor; -import android.media.AudioEffect; +import android.media.audiofx.AudioEffect; import android.media.AudioManager; -import android.media.BassBoost; -import android.media.Visualizer; +import android.media.audiofx.BassBoost; +import android.media.audiofx.Visualizer; import android.media.MediaPlayer; import android.os.Looper; diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEnvReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEnvReverbTest.java index d5538f1..ba202a7 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEnvReverbTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEnvReverbTest.java @@ -20,10 +20,10 @@ import com.android.mediaframeworktest.MediaFrameworkTest; import com.android.mediaframeworktest.MediaNames; import android.content.Context; import android.content.res.AssetFileDescriptor; -import android.media.AudioEffect; +import android.media.audiofx.AudioEffect; import android.media.AudioManager; -import android.media.EnvironmentalReverb; -import android.media.Visualizer; +import android.media.audiofx.EnvironmentalReverb; +import android.media.audiofx.Visualizer; import android.media.MediaPlayer; import android.os.Looper; diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEqualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEqualizerTest.java index a78668c..9146fb8 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEqualizerTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEqualizerTest.java @@ -20,10 +20,10 @@ import com.android.mediaframeworktest.MediaFrameworkTest; import com.android.mediaframeworktest.MediaNames; import android.content.Context; import android.content.res.AssetFileDescriptor; -import android.media.AudioEffect; +import android.media.audiofx.AudioEffect; import android.media.AudioManager; -import android.media.Equalizer; -import android.media.Visualizer; +import android.media.audiofx.Equalizer; +import android.media.audiofx.Visualizer; import android.media.MediaPlayer; import android.os.Looper; diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPresetReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPresetReverbTest.java index fbd8a78..242e6bb 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPresetReverbTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPresetReverbTest.java @@ -20,10 +20,10 @@ import com.android.mediaframeworktest.MediaFrameworkTest; import com.android.mediaframeworktest.MediaNames; import android.content.Context; import android.content.res.AssetFileDescriptor; -import android.media.AudioEffect; +import android.media.audiofx.AudioEffect; import android.media.AudioManager; -import android.media.PresetReverb; -import android.media.Visualizer; +import android.media.audiofx.PresetReverb; +import android.media.audiofx.Visualizer; import android.media.MediaPlayer; import android.os.Looper; diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVirtualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVirtualizerTest.java index 7123db4..7a35429 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVirtualizerTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVirtualizerTest.java @@ -20,10 +20,10 @@ import com.android.mediaframeworktest.MediaFrameworkTest; import com.android.mediaframeworktest.MediaNames; import android.content.Context; import android.content.res.AssetFileDescriptor; -import android.media.AudioEffect; +import android.media.audiofx.AudioEffect; import android.media.AudioManager; -import android.media.Virtualizer; -import android.media.Visualizer; +import android.media.audiofx.Virtualizer; +import android.media.audiofx.Visualizer; import android.media.MediaPlayer; import android.os.Looper; diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVisualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVisualizerTest.java index 26fdbfe..542ca8d 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVisualizerTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVisualizerTest.java @@ -20,9 +20,9 @@ import com.android.mediaframeworktest.MediaFrameworkTest; import com.android.mediaframeworktest.MediaNames; import android.content.Context; import android.content.res.AssetFileDescriptor; -import android.media.AudioEffect; +import android.media.audiofx.AudioEffect; import android.media.AudioManager; -import android.media.Visualizer; +import android.media.audiofx.Visualizer; import android.media.MediaPlayer; import android.os.Looper; diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index a8200be..bc944a0 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -444,13 +444,14 @@ static void(*findProcAddress(const char* name, // ---------------------------------------------------------------------------- -static void gl_no_context() { +static int gl_no_context() { tls_t* tls = getTLS(); if (tls->logCallWithNoContext == EGL_TRUE) { tls->logCallWithNoContext = EGL_FALSE; LOGE("call to OpenGL ES API with no current context " "(logged once per thread)"); } + return 0; } static void early_egl_init(void) @@ -463,6 +464,7 @@ static void early_egl_init(void) (uint32_t*)(void*)&gHooksNoContext, addr, sizeof(gHooksNoContext)); + setGlThreadSpecific(&gHooksNoContext); } diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp index a12edf2..fee4609 100644 --- a/opengl/libs/GLES2/gl2.cpp +++ b/opengl/libs/GLES2/gl2.cpp @@ -60,6 +60,7 @@ using namespace android; "ldr r12, [r12, %[tls]] \n" \ "cmp r12, #0 \n" \ "ldrne pc, [r12, %[api]] \n" \ + "mov r0, #0 \n" \ "bx lr \n" \ : \ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \ diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp index d71ff76..ee29f12 100644 --- a/opengl/libs/GLES_CM/gl.cpp +++ b/opengl/libs/GLES_CM/gl.cpp @@ -114,6 +114,7 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, "ldr r12, [r12, %[tls]] \n" \ "cmp r12, #0 \n" \ "ldrne pc, [r12, %[api]] \n" \ + "mov r0, #0 \n" \ "bx lr \n" \ : \ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index d98bd7d..0ca0572 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -22,6 +22,7 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.graphics.Canvas; import android.util.Slog; +import android.util.Log; import android.view.ViewDebug; import android.widget.FrameLayout; @@ -124,4 +125,10 @@ public class StatusBarIconView extends AnimatedImageView { public StatusBarIcon getStatusBarIcon() { return mIcon; } + + protected void debug(int depth) { + super.debug(depth); + Log.d("View", debugIndent(depth) + "slot=" + mSlot); + Log.d("View", debugIndent(depth) + "icon=" + mIcon); + } } diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java index f8c0aba..3583ab9 100644 --- a/policy/src/com/android/internal/policy/impl/LockScreen.java +++ b/policy/src/com/android/internal/policy/impl/LockScreen.java @@ -20,6 +20,8 @@ import com.android.internal.R; import com.android.internal.telephony.IccCard; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.SlidingTab; +import com.android.internal.widget.WaveView; +import com.android.internal.widget.WaveView.OnTriggerListener; import android.content.Context; import android.content.res.Configuration; @@ -46,8 +48,9 @@ import java.io.File; * information about the device depending on its state, and how to get * past it, as applicable. */ -class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateMonitor.InfoCallback, - KeyguardUpdateMonitor.SimStateCallback, SlidingTab.OnTriggerListener { +class LockScreen extends LinearLayout implements KeyguardScreen, + KeyguardUpdateMonitor.InfoCallback, + KeyguardUpdateMonitor.SimStateCallback { private static final boolean DBG = false; private static final String TAG = "LockScreen"; @@ -59,7 +62,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private final KeyguardUpdateMonitor mUpdateMonitor; private final KeyguardScreenCallback mCallback; - private SlidingTab mSelector; + private SlidingTab mSlidingTab; private TextView mScreenLocked; private TextView mEmergencyCallText; private Button mEmergencyCallButton; @@ -89,6 +92,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM private boolean mEnableMenuKeyInLockScreen; private StatusView mStatusView; + private WaveView mEnergyWave; + private SlidingTabMethods mSlidingTabMethods; + private WaveViewMethods mWaveViewMethods; /** * The status of this lock screen. @@ -141,6 +147,91 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } } + class SlidingTabMethods implements SlidingTab.OnTriggerListener { + + private void updateRightTabResources() { + boolean vibe = mSilentMode + && (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE); + + mSlidingTab.setRightTabResources( + mSilentMode ? ( vibe ? R.drawable.ic_jog_dial_vibrate_on + : R.drawable.ic_jog_dial_sound_off ) + : R.drawable.ic_jog_dial_sound_on, + mSilentMode ? R.drawable.jog_tab_target_yellow + : R.drawable.jog_tab_target_gray, + mSilentMode ? R.drawable.jog_tab_bar_right_sound_on + : R.drawable.jog_tab_bar_right_sound_off, + mSilentMode ? R.drawable.jog_tab_right_sound_on + : R.drawable.jog_tab_right_sound_off); + } + + /** {@inheritDoc} */ + public void onTrigger(View v, int whichHandle) { + if (whichHandle == SlidingTab.OnTriggerListener.LEFT_HANDLE) { + mCallback.goToUnlockScreen(); + } else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { + // toggle silent mode + mSilentMode = !mSilentMode; + if (mSilentMode) { + final boolean vibe = (Settings.System.getInt( + getContext().getContentResolver(), + Settings.System.VIBRATE_IN_SILENT, 1) == 1); + + mAudioManager.setRingerMode(vibe + ? AudioManager.RINGER_MODE_VIBRATE + : AudioManager.RINGER_MODE_SILENT); + } else { + mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); + } + + updateRightTabResources(); + + String message = mSilentMode ? + getContext().getString(R.string.global_action_silent_mode_on_status) : + getContext().getString(R.string.global_action_silent_mode_off_status); + + final int toastIcon = mSilentMode + ? R.drawable.ic_lock_ringer_off + : R.drawable.ic_lock_ringer_on; + + final int toastColor = mSilentMode + ? getContext().getResources().getColor(R.color.keyguard_text_color_soundoff) + : getContext().getResources().getColor(R.color.keyguard_text_color_soundon); + toastMessage(mScreenLocked, message, toastColor, toastIcon); + mCallback.pokeWakelock(); + } + } + + /** {@inheritDoc} */ + public void onGrabbedStateChange(View v, int grabbedState) { + if (grabbedState == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { + mSilentMode = isSilentMode(); + mSlidingTab.setRightHintText(mSilentMode ? R.string.lockscreen_sound_on_label + : R.string.lockscreen_sound_off_label); + } + mCallback.pokeWakelock(); + } + } + + class WaveViewMethods implements WaveView.OnTriggerListener { + /** {@inheritDoc} */ + public void onTrigger(View v, int whichHandle) { + if (whichHandle == WaveView.OnTriggerListener.CENTER_HANDLE) { + // Delay hiding lock screen long enough for animation to finish + postDelayed(new Runnable() { + public void run() { + mCallback.goToUnlockScreen(); + } + }, 500); + } + } + + /** {@inheritDoc} */ + public void onGrabbedStateChange(View v, int grabbedState) { + mCallback.pokeWakelock(); + } + } + /** * In general, we enable unlocking the insecure key guard with the menu key. However, there are * some cases where we wish to disable it, notably when the menu button placement or technology @@ -195,9 +286,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mStatusView = new StatusView(this, mUpdateMonitor, mLockPatternUtils); mScreenLocked = (TextView) findViewById(R.id.screenLocked); - mSelector = (SlidingTab) findViewById(R.id.tab_selector); - mSelector.setHoldAfterTrigger(true, false); - mSelector.setLeftHintText(R.string.lockscreen_unlock_label); mEmergencyCallText = (TextView) findViewById(R.id.emergencyCallText); mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); @@ -220,15 +308,25 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mSilentMode = isSilentMode(); - mSelector.setLeftTabResources( - R.drawable.ic_jog_dial_unlock, - R.drawable.jog_tab_target_green, - R.drawable.jog_tab_bar_left_unlock, - R.drawable.jog_tab_left_unlock); - - updateRightTabResources(); - - mSelector.setOnTriggerListener(this); + mSlidingTab = (SlidingTab) findViewById(R.id.tab_selector); + mEnergyWave = (WaveView) findViewById(R.id.wave_view); + if (mSlidingTab != null) { + mSlidingTab.setHoldAfterTrigger(true, false); + mSlidingTab.setLeftHintText(R.string.lockscreen_unlock_label); + mSlidingTab.setLeftTabResources( + R.drawable.ic_jog_dial_unlock, + R.drawable.jog_tab_target_green, + R.drawable.jog_tab_bar_left_unlock, + R.drawable.jog_tab_left_unlock); + mSlidingTabMethods = new SlidingTabMethods(); + mSlidingTab.setOnTriggerListener(mSlidingTabMethods); + mSlidingTabMethods.updateRightTabResources(); + } else if (mEnergyWave != null) { + mWaveViewMethods = new WaveViewMethods(); + mEnergyWave.setOnTriggerListener(mWaveViewMethods); + } else { + throw new IllegalStateException("Must have either SlidingTab or WaveView defined"); + } resetStatusInfo(updateMonitor); } @@ -237,22 +335,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM return mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; } - private void updateRightTabResources() { - boolean vibe = mSilentMode - && (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE); - - mSelector.setRightTabResources( - mSilentMode ? ( vibe ? R.drawable.ic_jog_dial_vibrate_on - : R.drawable.ic_jog_dial_sound_off ) - : R.drawable.ic_jog_dial_sound_on, - mSilentMode ? R.drawable.jog_tab_target_yellow - : R.drawable.jog_tab_target_gray, - mSilentMode ? R.drawable.jog_tab_bar_right_sound_on - : R.drawable.jog_tab_bar_right_sound_off, - mSilentMode ? R.drawable.jog_tab_right_sound_on - : R.drawable.jog_tab_right_sound_off); - } - private void resetStatusInfo(KeyguardUpdateMonitor updateMonitor) { mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo(); mPluggedIn = updateMonitor.isDevicePluggedIn(); @@ -278,53 +360,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM return false; } - /** {@inheritDoc} */ - public void onTrigger(View v, int whichHandle) { - if (whichHandle == SlidingTab.OnTriggerListener.LEFT_HANDLE) { - mCallback.goToUnlockScreen(); - } else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { - // toggle silent mode - mSilentMode = !mSilentMode; - if (mSilentMode) { - final boolean vibe = (Settings.System.getInt( - getContext().getContentResolver(), - Settings.System.VIBRATE_IN_SILENT, 1) == 1); - - mAudioManager.setRingerMode(vibe - ? AudioManager.RINGER_MODE_VIBRATE - : AudioManager.RINGER_MODE_SILENT); - } else { - mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); - } - - updateRightTabResources(); - - String message = mSilentMode ? - getContext().getString(R.string.global_action_silent_mode_on_status) : - getContext().getString(R.string.global_action_silent_mode_off_status); - - final int toastIcon = mSilentMode - ? R.drawable.ic_lock_ringer_off - : R.drawable.ic_lock_ringer_on; - - final int toastColor = mSilentMode - ? getContext().getResources().getColor(R.color.keyguard_text_color_soundoff) - : getContext().getResources().getColor(R.color.keyguard_text_color_soundon); - toastMessage(mScreenLocked, message, toastColor, toastIcon); - mCallback.pokeWakelock(); - } - } - - /** {@inheritDoc} */ - public void onGrabbedStateChange(View v, int grabbedState) { - if (grabbedState == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { - mSilentMode = isSilentMode(); - mSelector.setRightHintText(mSilentMode ? R.string.lockscreen_sound_on_label - : R.string.lockscreen_sound_off_label); - } - mCallback.pokeWakelock(); - } - /** * Displays a message in a text view and then restores the previous text. * @param textView The text view. @@ -460,6 +495,22 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } /** + * Enables unlocking of this screen. Typically just shows the unlock widget. + */ + private void enableUnlock() { + if (mEnergyWave != null) mEnergyWave.setVisibility(View.VISIBLE); + if (mSlidingTab != null) mSlidingTab.setVisibility(View.VISIBLE); + } + + /** + * Disable unlocking of this screen. Typically just hides the unlock widget. + */ + private void disableUnlock() { + if (mEnergyWave != null) mEnergyWave.setVisibility(View.GONE); + if (mSlidingTab != null) mSlidingTab.setVisibility(View.GONE); + } + + /** * Update the layout to match the current status. */ private void updateLayout(Status status) { @@ -481,9 +532,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.INVISIBLE); - mSelector.setVisibility(View.VISIBLE); mEmergencyCallText.setVisibility(View.GONE); + enableUnlock(); break; + case NetworkLocked: // The carrier string shows both sim card status (i.e. No Sim Card) and // carrier's name and/or "Emergency Calls Only" status @@ -495,9 +547,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mSelector.setVisibility(View.VISIBLE); mEmergencyCallText.setVisibility(View.GONE); + enableUnlock(); break; + case SimMissing: // text mStatusView.setCarrierText(R.string.lockscreen_missing_sim_message_short); @@ -505,10 +558,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mSelector.setVisibility(View.VISIBLE); mEmergencyCallText.setVisibility(View.VISIBLE); - // do not need to show the e-call button; user may unlock + enableUnlock(); // do not need to show the e-call button; user may unlock break; + case SimMissingLocked: // text mStatusView.setCarrierText( @@ -519,10 +572,11 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mSelector.setVisibility(View.GONE); // cannot unlock mEmergencyCallText.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.VISIBLE); + disableUnlock(); break; + case SimLocked: // text mStatusView.setCarrierText( @@ -532,9 +586,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.INVISIBLE); - mSelector.setVisibility(View.VISIBLE); mEmergencyCallText.setVisibility(View.GONE); + enableUnlock(); break; + case SimPukLocked: // text mStatusView.setCarrierText( @@ -545,9 +600,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM // layout mScreenLocked.setVisibility(View.VISIBLE); - mSelector.setVisibility(View.GONE); // cannot unlock mEmergencyCallText.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.VISIBLE); + disableUnlock(); break; } } @@ -614,7 +669,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM /** {@inheritDoc} */ public void onPause() { - + if (mEnergyWave != null) { + mEnergyWave.reset(); + } } /** {@inheritDoc} */ @@ -632,7 +689,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM boolean silent = AudioManager.RINGER_MODE_NORMAL != state; if (silent != mSilentMode) { mSilentMode = silent; - updateRightTabResources(); + if (mSlidingTabMethods != null) mSlidingTabMethods.updateRightTabResources(); } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 7009c65..c047522 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -235,8 +235,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void handleMotion(MotionEvent event, Runnable finishedCallback) { finishedCallback.run(); + synchronized (mLock) { - mPointerLocationView.addTouchEvent(event); + if (mPointerLocationView != null) { + mPointerLocationView.addTouchEvent(event); + } } } }; @@ -287,7 +290,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // (See Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR.) int mIncallPowerBehavior; - int mLandscapeRotation = -1; + int mLandscapeRotation = -1; // default landscape rotation + int mSeascapeRotation = -1; // "other" landscape rotation, 180 degrees from mLandscapeRotation int mPortraitRotation = -1; // Nothing to see here, move along... @@ -360,9 +364,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { return true; } // The user preference says we can rotate, and the app is willing to rotate. + // Note we include SCREEN_ORIENTATION_LANDSCAPE since we can use the sensor to choose + // between the two possible landscape rotations. if (mAccelerometerDefault != 0 && (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER - || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { + || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + || appOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)) { return true; } // We're in a dock that has a rotation affinity, an the app is willing to rotate. @@ -371,7 +378,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Note we override the nosensor flag here. if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { + || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR + || appOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { return true; } } @@ -2117,20 +2125,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (d.getWidth() > d.getHeight()) { mPortraitRotation = Surface.ROTATION_90; mLandscapeRotation = Surface.ROTATION_0; + mSeascapeRotation = Surface.ROTATION_180; } else { mPortraitRotation = Surface.ROTATION_0; mLandscapeRotation = Surface.ROTATION_90; + mSeascapeRotation = Surface.ROTATION_270; } } synchronized (mLock) { - switch (orientation) { - case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: - //always return landscape if orientation set to landscape - return mLandscapeRotation; - case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: - //always return portrait if orientation set to portrait - return mPortraitRotation; + if (orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) { + //always return portrait if orientation set to portrait + return mPortraitRotation; + } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { + return getCurrentLandscapeRotation(lastRotation); } // case for nosensor meaning ignore sensor and consider only lid // or orientation sensor disabled @@ -2150,6 +2158,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private int getCurrentLandscapeRotation(int lastRotation) { + // landscape-only apps can take either landscape rotation + if (useSensorForOrientationLp(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)) { + int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation); + if (isLandscapeOrSeascape(sensorRotation)) { + return sensorRotation; + } + } + // try to preserve the old rotation if it was landscape + if (isLandscapeOrSeascape(lastRotation)) { + return lastRotation; + } + // default to one of the two landscape rotations + return mLandscapeRotation; + } + + private boolean isLandscapeOrSeascape(int sensorRotation) { + return sensorRotation == mLandscapeRotation || sensorRotation == mSeascapeRotation; + } + public boolean detectSafeMode() { try { int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU); diff --git a/services/java/com/android/server/ProcessStats.java b/services/java/com/android/server/ProcessStats.java index 5bdadcc..43dbcc0 100644 --- a/services/java/com/android/server/ProcessStats.java +++ b/services/java/com/android/server/ProcessStats.java @@ -80,16 +80,24 @@ public class ProcessStats { PROC_SPACE_TERM|PROC_OUT_LONG, // 11: major faults PROC_SPACE_TERM, PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime - PROC_SPACE_TERM|PROC_OUT_LONG // 14: stime + PROC_SPACE_TERM|PROC_OUT_LONG, // 14: stime + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM|PROC_OUT_LONG, // 21: vsize }; static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1; static final int PROCESS_FULL_STAT_MAJOR_FAULTS = 2; static final int PROCESS_FULL_STAT_UTIME = 3; static final int PROCESS_FULL_STAT_STIME = 4; + static final int PROCESS_FULL_STAT_VSIZE = 5; - private final String[] mProcessFullStatsStringData = new String[5]; - private final long[] mProcessFullStatsData = new long[5]; + private final String[] mProcessFullStatsStringData = new String[6]; + private final long[] mProcessFullStatsData = new long[6]; private static final int[] SYSTEM_CPU_FORMAT = new int[] { PROC_SPACE_TERM|PROC_COMBINE, @@ -171,6 +179,8 @@ public class ProcessStats { final ArrayList<Stats> threadStats; final ArrayList<Stats> workingThreads; + public boolean interesting; + public String baseName; public String name; int nameWidth; @@ -349,59 +359,62 @@ public class ProcessStats { + (parentPid < 0 ? "process" : "thread") + " pid " + pid + ": " + st); - final long uptime = SystemClock.uptimeMillis(); + if (st.interesting) { + final long uptime = SystemClock.uptimeMillis(); - final long[] procStats = mProcessStatsData; - if (!Process.readProcFile(st.statFile.toString(), - PROCESS_STATS_FORMAT, null, procStats, null)) { - continue; - } - - final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS]; - final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS]; - final long utime = procStats[PROCESS_STAT_UTIME]; - final long stime = procStats[PROCESS_STAT_STIME]; - - if (utime == st.base_utime && stime == st.base_stime) { - st.rel_utime = 0; - st.rel_stime = 0; - st.rel_minfaults = 0; - st.rel_majfaults = 0; - if (st.active) { - st.active = false; + final long[] procStats = mProcessStatsData; + if (!Process.readProcFile(st.statFile.toString(), + PROCESS_STATS_FORMAT, null, procStats, null)) { + continue; } - continue; - } - if (!st.active) { - st.active = true; - } + final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS]; + final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS]; + final long utime = procStats[PROCESS_STAT_UTIME]; + final long stime = procStats[PROCESS_STAT_STIME]; + + if (utime == st.base_utime && stime == st.base_stime) { + st.rel_utime = 0; + st.rel_stime = 0; + st.rel_minfaults = 0; + st.rel_majfaults = 0; + if (st.active) { + st.active = false; + } + continue; + } - if (parentPid < 0) { - getName(st, st.cmdlineFile); - if (st.threadStats != null) { - mCurThreadPids = collectStats(st.threadsDir, pid, false, - mCurThreadPids, st.threadStats); + if (!st.active) { + st.active = true; } + + if (parentPid < 0) { + getName(st, st.cmdlineFile); + if (st.threadStats != null) { + mCurThreadPids = collectStats(st.threadsDir, pid, false, + mCurThreadPids, st.threadStats); + } + } + + if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid + + " utime=" + utime + "-" + st.base_utime + + " stime=" + stime + "-" + st.base_stime + + " minfaults=" + minfaults + "-" + st.base_minfaults + + " majfaults=" + majfaults + "-" + st.base_majfaults); + + st.rel_uptime = uptime - st.base_uptime; + st.base_uptime = uptime; + st.rel_utime = (int)(utime - st.base_utime); + st.rel_stime = (int)(stime - st.base_stime); + st.base_utime = utime; + st.base_stime = stime; + st.rel_minfaults = (int)(minfaults - st.base_minfaults); + st.rel_majfaults = (int)(majfaults - st.base_majfaults); + st.base_minfaults = minfaults; + st.base_majfaults = majfaults; + st.working = true; } - if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid - + " utime=" + utime + "-" + st.base_utime - + " stime=" + stime + "-" + st.base_stime - + " minfaults=" + minfaults + "-" + st.base_minfaults - + " majfaults=" + majfaults + "-" + st.base_majfaults); - - st.rel_uptime = uptime - st.base_uptime; - st.base_uptime = uptime; - st.rel_utime = (int)(utime - st.base_utime); - st.rel_stime = (int)(stime - st.base_stime); - st.base_utime = utime; - st.base_stime = stime; - st.rel_minfaults = (int)(minfaults - st.base_minfaults); - st.rel_majfaults = (int)(majfaults - st.base_majfaults); - st.base_minfaults = minfaults; - st.base_majfaults = majfaults; - st.working = true; continue; } @@ -421,12 +434,24 @@ public class ProcessStats { if (Process.readProcFile(st.statFile.toString(), PROCESS_FULL_STATS_FORMAT, procStatsString, procStats, null)) { - st.baseName = procStatsString[0]; - st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS]; - st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS]; - st.base_utime = procStats[PROCESS_FULL_STAT_UTIME]; - st.base_stime = procStats[PROCESS_FULL_STAT_STIME]; + // This is a possible way to filter out processes that + // are actually kernel threads... do we want to? Some + // of them do use CPU, but there can be a *lot* that are + // not doing anything. + if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) { + st.interesting = true; + st.baseName = procStatsString[0]; + st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS]; + st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS]; + st.base_utime = procStats[PROCESS_FULL_STAT_UTIME]; + st.base_stime = procStats[PROCESS_FULL_STAT_STIME]; + } else { + Slog.i(TAG, "Skipping kernel process pid " + pid + + " name " + procStatsString[0]); + st.baseName = procStatsString[0]; + } } else { + Slog.w(TAG, "Skipping unknown process pid " + pid); st.baseName = "<unknown>"; st.base_utime = st.base_stime = 0; st.base_minfaults = st.base_majfaults = 0; @@ -438,7 +463,7 @@ public class ProcessStats { mCurThreadPids = collectStats(st.threadsDir, pid, true, mCurThreadPids, st.threadStats); } - } else { + } else if (st.interesting) { st.name = st.baseName; st.nameWidth = onMeasureProcessName(st.name); } @@ -452,7 +477,7 @@ public class ProcessStats { st.rel_minfaults = 0; st.rel_majfaults = 0; st.added = true; - if (!first) { + if (!first && st.interesting) { st.working = true; } continue; @@ -624,6 +649,14 @@ public class ProcessStats { } } + final public int countStats() { + return mProcStats.size(); + } + + final public Stats getStats(int index) { + return mProcStats.get(index); + } + final public int countWorkingStats() { buildWorkingProcs(); return mWorkingProcs.size(); @@ -788,7 +821,8 @@ public class ProcessStats { private void getName(Stats st, String cmdlineFile) { String newName = st.name; - if (st.name == null || st.name.equals("app_process")) { + if (st.name == null || st.name.equals("app_process") + || st.name.equals("<pre-initialized>")) { String cmdName = readFile(cmdlineFile, '\0'); if (cmdName != null && cmdName.length() > 1) { newName = cmdName; diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index c52567a..7b2a570 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -804,6 +804,16 @@ public class WifiService extends IWifiManager.Stub { mWifiStateMachine.forgetNetwork(netId); } + public void startWpsPbc(String bssid) { + enforceChangePermission(); + mWifiStateMachine.startWpsPbc(bssid); + } + + public void startWpsPin(String bssid, int apPin) { + enforceChangePermission(); + mWifiStateMachine.startWpsPin(bssid, apPin); + } + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index c896c94..8e22652 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -122,6 +122,8 @@ import java.io.PrintWriter; import java.lang.IllegalStateException; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -145,6 +147,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final boolean DEBUG_BROADCAST = localLOGV || false; static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false; static final boolean DEBUG_SERVICE = localLOGV || false; + static final boolean DEBUG_SERVICE_EXECUTING = localLOGV || false; static final boolean DEBUG_VISBILITY = localLOGV || false; static final boolean DEBUG_PROCESSES = localLOGV || false; static final boolean DEBUG_PROVIDER = localLOGV || false; @@ -153,6 +156,8 @@ public final class ActivityManagerService extends ActivityManagerNative static final boolean DEBUG_RESULTS = localLOGV || false; static final boolean DEBUG_BACKUP = localLOGV || false; static final boolean DEBUG_CONFIGURATION = localLOGV || false; + static final boolean DEBUG_POWER = localLOGV || false; + static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false; static final boolean VALIDATE_TOKENS = false; static final boolean SHOW_ACTIVITY_START_TIME = true; @@ -198,8 +203,16 @@ public final class ActivityManagerService extends ActivityManagerNative // The minimum amount of time between successive GC requests for a process. static final int GC_MIN_INTERVAL = 60*1000; - // The rate at which we check for apps using excessive wake locks -- 15 mins. - static final int WAKE_LOCK_CHECK_DELAY = 15*60*1000; + // The rate at which we check for apps using excessive power -- 15 mins. + static final int POWER_CHECK_DELAY = (DEBUG_POWER_QUICK ? 2 : 15) * 60*1000; + + // The minimum sample duration we will allow before deciding we have + // enough data on wake locks to start killing things. + static final int WAKE_LOCK_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000; + + // The minimum sample duration we will allow before deciding we have + // enough data on CPU usage to start killing things. + static final int CPU_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000; // How long we allow a receiver to run before giving up on it. static final int BROADCAST_TIMEOUT = 10*1000; @@ -780,9 +793,14 @@ public final class ActivityManagerService extends ActivityManagerNative boolean mDidAppSwitch; /** - * Last time (in realtime) at which we checked for wake lock usage. + * Last time (in realtime) at which we checked for power usage. + */ + long mLastPowerCheckRealtime; + + /** + * Last time (in uptime) at which we checked for power usage. */ - long mLastWakeLockCheckTime; + long mLastPowerCheckUptime; /** * Set while we are wanting to sleep, to prevent any @@ -1195,12 +1213,10 @@ public final class ActivityManagerService extends ActivityManagerNative } break; case CHECK_EXCESSIVE_WAKE_LOCKS_MSG: { synchronized (ActivityManagerService.this) { - checkExcessiveWakeLocksLocked(true); + checkExcessivePowerUsageLocked(true); removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); - if (mSleeping) { - Message nmsg = obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); - sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY); - } + Message nmsg = obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); + sendMessageDelayed(nmsg, POWER_CHECK_DELAY); } } break; } @@ -1395,7 +1411,8 @@ public final class ActivityManagerService extends ActivityManagerNative systemDir, "batterystats.bin").toString()); mBatteryStatsService.getActiveStatistics().readLocked(); mBatteryStatsService.getActiveStatistics().writeAsyncLocked(); - mOnBattery = mBatteryStatsService.getActiveStatistics().getIsOnBattery(); + mOnBattery = DEBUG_POWER ? true + : mBatteryStatsService.getActiveStatistics().getIsOnBattery(); mBatteryStatsService.getActiveStatistics().setCallback(this); mUsageStatsService = new UsageStatsService(new File( @@ -1515,10 +1532,12 @@ public final class ActivityManagerService extends ActivityManagerNative int perc = bstats.startAddingCpuLocked(); int totalUTime = 0; int totalSTime = 0; - final int N = mProcessStats.countWorkingStats(); + final int N = mProcessStats.countStats(); for (int i=0; i<N; i++) { - ProcessStats.Stats st - = mProcessStats.getWorkingStats(i); + ProcessStats.Stats st = mProcessStats.getStats(i); + if (!st.working) { + continue; + } ProcessRecord pr = mPidsSelfLocked.get(st.pid); int otherUTime = (st.rel_utime*perc)/100; int otherSTime = (st.rel_stime*perc)/100; @@ -1529,6 +1548,7 @@ public final class ActivityManagerService extends ActivityManagerNative ps.addCpuTimeLocked(st.rel_utime-otherUTime, st.rel_stime-otherSTime); ps.addSpeedStepTimes(cpuSpeedTimes); + pr.curCpuTime += (st.rel_utime+st.rel_stime) * 10; } else { BatteryStatsImpl.Uid.Proc ps = bstats.getProcessStatsLocked(st.name, st.pid); @@ -1565,7 +1585,7 @@ public final class ActivityManagerService extends ActivityManagerNative updateCpuStatsNow(); synchronized (this) { synchronized(mPidsSelfLocked) { - mOnBattery = onBattery; + mOnBattery = DEBUG_POWER ? true : onBattery; } } } @@ -2795,6 +2815,16 @@ public final class ActivityManagerService extends ActivityManagerNative ArrayList<Integer> firstPids = new ArrayList<Integer>(5); SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20); + if (mController != null) { + try { + // 0 == continue, -1 = kill process immediately + int res = mController.appEarlyNotResponding(app.processName, app.pid, annotation); + if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid); + } catch (RemoteException e) { + mController = null; + } + } + long anrTime = SystemClock.uptimeMillis(); if (MONITOR_CPU_USAGE) { updateCpuStatsNow(); @@ -2845,10 +2875,6 @@ public final class ActivityManagerService extends ActivityManagerNative } } - final ProcessStats processStats = new ProcessStats(true); - - File tracesFile = dumpStackTraces(true, firstPids, processStats, lastPids); - // Log the ANR to the main log. StringBuilder info = mStringBuilder; info.setLength(0); @@ -2864,6 +2890,10 @@ public final class ActivityManagerService extends ActivityManagerNative info.append("Parent: ").append(parent.shortComponentName).append("\n"); } + final ProcessStats processStats = new ProcessStats(true); + + File tracesFile = dumpStackTraces(true, firstPids, processStats, lastPids); + String cpuInfo = null; if (MONITOR_CPU_USAGE) { updateCpuStatsNow(); @@ -3742,7 +3772,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { // Start looking for apps that are abusing wake locks. Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); - mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY); + mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY); // Tell anyone interested that we are done booting! SystemProperties.set("sys.boot_completed", "1"); broadcastIntentLocked(null, null, @@ -5655,10 +5685,10 @@ public final class ActivityManagerService extends ActivityManagerNative } // Initialize the wake times of all processes. - checkExcessiveWakeLocksLocked(false); + checkExcessivePowerUsageLocked(false); mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); - mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY); + mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY); } } @@ -5708,7 +5738,6 @@ public final class ActivityManagerService extends ActivityManagerNative mWindowManager.setEventDispatching(true); mSleeping = false; mMainStack.resumeTopActivityLocked(null); - mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); } } @@ -7055,12 +7084,13 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println("Activity manager dump options:"); pw.println(" [-a] [-h] [cmd] ..."); pw.println(" cmd may be one of:"); - pw.println(" activities: activity stack state"); - pw.println(" broadcasts: broadcast state"); - pw.println(" intents: pending intent state"); - pw.println(" processes: process state"); - pw.println(" providers: content provider state"); - pw.println(" services: service state"); + pw.println(" a[ctivities]: activity stack state"); + pw.println(" b[roadcasts]: broadcast state"); + pw.println(" i[ntents]: pending intent state"); + pw.println(" p[rocesses]: process state"); + pw.println(" o[om]: out of memory management"); + pw.println(" prov[iders]: content provider state"); + pw.println(" s[ervices]: service state"); pw.println(" service [name]: service client-side state"); return; } else { @@ -7092,6 +7122,11 @@ public final class ActivityManagerService extends ActivityManagerNative dumpProcessesLocked(fd, pw, args, opti, true); } return; + } else if ("oom".equals(cmd) || "o".equals(cmd)) { + synchronized (this) { + dumpOomLocked(fd, pw, args, opti, true); + } + return; } else if ("providers".equals(cmd) || "prov".equals(cmd)) { synchronized (this) { dumpProvidersLocked(fd, pw, args, opti, true); @@ -7213,7 +7248,7 @@ public final class ActivityManagerService extends ActivityManagerNative return true; } - + boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll) { boolean needSep = false; @@ -7243,8 +7278,8 @@ public final class ActivityManagerService extends ActivityManagerNative if (needSep) pw.println(" "); needSep = true; pw.println(" Running processes (most recent first):"); - dumpProcessList(pw, this, mLruProcesses, " ", - "Proc", "PERS", true); + dumpProcessOomList(pw, this, mLruProcesses, " ", + "Proc", "PERS", false); needSep = true; } @@ -7275,7 +7310,7 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = true; pw.println(" Persisent processes that are starting:"); dumpProcessList(pw, this, mPersistentStartingProcesses, " ", - "Starting Norm", "Restarting PERS", false); + "Starting Norm", "Restarting PERS"); } if (mStartingProcesses.size() > 0) { @@ -7283,7 +7318,7 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = true; pw.println(" Processes that are starting:"); dumpProcessList(pw, this, mStartingProcesses, " ", - "Starting Norm", "Starting PERS", false); + "Starting Norm", "Starting PERS"); } if (mRemovedProcesses.size() > 0) { @@ -7291,7 +7326,7 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = true; pw.println(" Processes that are being removed:"); dumpProcessList(pw, this, mRemovedProcesses, " ", - "Removed Norm", "Removed PERS", false); + "Removed Norm", "Removed PERS"); } if (mProcessesOnHold.size() > 0) { @@ -7299,26 +7334,10 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = true; pw.println(" Processes that are on old until the system is ready:"); dumpProcessList(pw, this, mProcessesOnHold, " ", - "OnHold Norm", "OnHold PERS", false); + "OnHold Norm", "OnHold PERS"); } - if (mProcessesToGc.size() > 0) { - if (needSep) pw.println(" "); - needSep = true; - pw.println(" Processes that are waiting to GC:"); - long now = SystemClock.uptimeMillis(); - for (int i=0; i<mProcessesToGc.size(); i++) { - ProcessRecord proc = mProcessesToGc.get(i); - pw.print(" Process "); pw.println(proc); - pw.print(" lowMem="); pw.print(proc.reportLowMemory); - pw.print(", last gced="); - pw.print(now-proc.lastRequestedGc); - pw.print(" ms ago, last lowMem="); - pw.print(now-proc.lastLowMemory); - pw.println(" ms ago"); - - } - } + needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll); if (mProcessCrashTimes.getMap().size() > 0) { if (needSep) pw.println(" "); @@ -7382,6 +7401,12 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" mBooting=" + mBooting + " mBooted=" + mBooted + " mFactoryTest=" + mFactoryTest); + pw.print(" mLastPowerCheckRealtime="); + TimeUtils.formatDuration(mLastPowerCheckRealtime, pw); + pw.println(""); + pw.print(" mLastPowerCheckUptime="); + TimeUtils.formatDuration(mLastPowerCheckUptime, pw); + pw.println(""); pw.println(" mGoingToSleep=" + mMainStack.mGoingToSleep); pw.println(" mLaunchingActivity=" + mMainStack.mLaunchingActivity); pw.println(" mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq); @@ -7390,6 +7415,75 @@ public final class ActivityManagerService extends ActivityManagerNative return true; } + boolean dumpProcessesToGc(FileDescriptor fd, PrintWriter pw, String[] args, + int opti, boolean needSep, boolean dumpAll) { + if (mProcessesToGc.size() > 0) { + if (needSep) pw.println(" "); + needSep = true; + pw.println(" Processes that are waiting to GC:"); + long now = SystemClock.uptimeMillis(); + for (int i=0; i<mProcessesToGc.size(); i++) { + ProcessRecord proc = mProcessesToGc.get(i); + pw.print(" Process "); pw.println(proc); + pw.print(" lowMem="); pw.print(proc.reportLowMemory); + pw.print(", last gced="); + pw.print(now-proc.lastRequestedGc); + pw.print(" ms ago, last lowMem="); + pw.print(now-proc.lastLowMemory); + pw.println(" ms ago"); + + } + } + return needSep; + } + + boolean dumpOomLocked(FileDescriptor fd, PrintWriter pw, String[] args, + int opti, boolean dumpAll) { + boolean needSep = false; + + if (mLruProcesses.size() > 0) { + ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(mLruProcesses); + + Comparator<ProcessRecord> comparator = new Comparator<ProcessRecord>() { + @Override + public int compare(ProcessRecord object1, ProcessRecord object2) { + if (object1.setAdj != object2.setAdj) { + return object1.setAdj > object2.setAdj ? -1 : 1; + } + if (object1.setSchedGroup != object2.setSchedGroup) { + return object1.setSchedGroup > object2.setSchedGroup ? -1 : 1; + } + if (object1.keeping != object2.keeping) { + return object1.keeping ? -1 : 1; + } + if (object1.pid != object2.pid) { + return object1.pid > object2.pid ? -1 : 1; + } + return 0; + } + }; + + Collections.sort(procs, comparator); + + if (needSep) pw.println(" "); + needSep = true; + pw.println(" Process OOM control:"); + dumpProcessOomList(pw, this, procs, " ", + "Proc", "PERS", true); + needSep = true; + } + + needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll); + + pw.println(" "); + pw.println(" mHomeProcess: " + mHomeProcess); + if (mHeavyWeightProcess != null) { + pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess); + } + + return true; + } + /** * There are three ways to call this: * - no service specified: dump all the services @@ -7833,89 +7927,145 @@ public final class ActivityManagerService extends ActivityManagerNative private static final int dumpProcessList(PrintWriter pw, ActivityManagerService service, List list, - String prefix, String normalLabel, String persistentLabel, - boolean inclOomAdj) { + String prefix, String normalLabel, String persistentLabel) { int numPers = 0; final int N = list.size()-1; for (int i=N; i>=0; i--) { ProcessRecord r = (ProcessRecord)list.get(i); - if (false) { - pw.println(prefix + (r.persistent ? persistentLabel : normalLabel) - + " #" + i + ":"); - r.dump(pw, prefix + " "); - } else if (inclOomAdj) { - String oomAdj; - if (r.setAdj >= EMPTY_APP_ADJ) { - oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ); - } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) { - oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ); - } else if (r.setAdj >= HOME_APP_ADJ) { - oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ); - } else if (r.setAdj >= SECONDARY_SERVER_ADJ) { - oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ); - } else if (r.setAdj >= BACKUP_APP_ADJ) { - oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ); - } else if (r.setAdj >= HEAVY_WEIGHT_APP_ADJ) { - oomAdj = buildOomTag("hvy ", null, r.setAdj, HEAVY_WEIGHT_APP_ADJ); - } else if (r.setAdj >= PERCEPTIBLE_APP_ADJ) { - oomAdj = buildOomTag("prcp ", null, r.setAdj, PERCEPTIBLE_APP_ADJ); - } else if (r.setAdj >= VISIBLE_APP_ADJ) { - oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ); - } else if (r.setAdj >= FOREGROUND_APP_ADJ) { - oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ); - } else if (r.setAdj >= CORE_SERVER_ADJ) { - oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ); - } else if (r.setAdj >= SYSTEM_ADJ) { - oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ); + pw.println(String.format("%s%s #%2d: %s", + prefix, (r.persistent ? persistentLabel : normalLabel), + i, r.toString())); + if (r.persistent) { + numPers++; + } + } + return numPers; + } + + private static final void dumpProcessOomList(PrintWriter pw, + ActivityManagerService service, List<ProcessRecord> list, + String prefix, String normalLabel, String persistentLabel, + boolean inclDetails) { + + final long curRealtime = SystemClock.elapsedRealtime(); + final long realtimeSince = curRealtime - service.mLastPowerCheckRealtime; + final long curUptime = SystemClock.uptimeMillis(); + final long uptimeSince = curUptime - service.mLastPowerCheckUptime; + + final int N = list.size()-1; + for (int i=N; i>=0; i--) { + ProcessRecord r = list.get(i); + String oomAdj; + if (r.setAdj >= EMPTY_APP_ADJ) { + oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ); + } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) { + oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ); + } else if (r.setAdj >= HOME_APP_ADJ) { + oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ); + } else if (r.setAdj >= SECONDARY_SERVER_ADJ) { + oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ); + } else if (r.setAdj >= BACKUP_APP_ADJ) { + oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ); + } else if (r.setAdj >= HEAVY_WEIGHT_APP_ADJ) { + oomAdj = buildOomTag("hvy ", null, r.setAdj, HEAVY_WEIGHT_APP_ADJ); + } else if (r.setAdj >= PERCEPTIBLE_APP_ADJ) { + oomAdj = buildOomTag("prcp ", null, r.setAdj, PERCEPTIBLE_APP_ADJ); + } else if (r.setAdj >= VISIBLE_APP_ADJ) { + oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ); + } else if (r.setAdj >= FOREGROUND_APP_ADJ) { + oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ); + } else if (r.setAdj >= CORE_SERVER_ADJ) { + oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ); + } else if (r.setAdj >= SYSTEM_ADJ) { + oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ); + } else { + oomAdj = Integer.toString(r.setAdj); + } + String schedGroup; + switch (r.setSchedGroup) { + case Process.THREAD_GROUP_BG_NONINTERACTIVE: + schedGroup = "B"; + break; + case Process.THREAD_GROUP_DEFAULT: + schedGroup = "F"; + break; + default: + schedGroup = Integer.toString(r.setSchedGroup); + break; + } + pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)", + prefix, (r.persistent ? persistentLabel : normalLabel), + N-i, oomAdj, schedGroup, r.toShortString(), r.adjType)); + if (r.adjSource != null || r.adjTarget != null) { + pw.print(prefix); + pw.print(" "); + if (r.adjTarget instanceof ComponentName) { + pw.print(((ComponentName)r.adjTarget).flattenToShortString()); + } else if (r.adjTarget != null) { + pw.print(r.adjTarget.toString()); } else { - oomAdj = Integer.toString(r.setAdj); - } - String schedGroup; - switch (r.setSchedGroup) { - case Process.THREAD_GROUP_BG_NONINTERACTIVE: - schedGroup = "B"; - break; - case Process.THREAD_GROUP_DEFAULT: - schedGroup = "F"; - break; - default: - schedGroup = Integer.toString(r.setSchedGroup); - break; + pw.print("{null}"); + } + pw.print("<="); + if (r.adjSource instanceof ProcessRecord) { + pw.print("Proc{"); + pw.print(((ProcessRecord)r.adjSource).toShortString()); + pw.println("}"); + } else if (r.adjSource != null) { + pw.println(r.adjSource.toString()); + } else { + pw.println("{null}"); } - pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)", - prefix, (r.persistent ? persistentLabel : normalLabel), - N-i, oomAdj, schedGroup, r.toShortString(), r.adjType)); - if (r.adjSource != null || r.adjTarget != null) { - pw.print(prefix); - pw.print(" "); - if (r.adjTarget instanceof ComponentName) { - pw.print(((ComponentName)r.adjTarget).flattenToShortString()); - } else if (r.adjTarget != null) { - pw.print(r.adjTarget.toString()); - } else { - pw.print("{null}"); - } - pw.print("<="); - if (r.adjSource instanceof ProcessRecord) { - pw.print("Proc{"); - pw.print(((ProcessRecord)r.adjSource).toShortString()); - pw.println("}"); - } else if (r.adjSource != null) { - pw.println(r.adjSource.toString()); - } else { - pw.println("{null}"); + } + if (inclDetails) { + pw.print(prefix); + pw.print(" "); + pw.print("oom: max="); pw.print(r.maxAdj); + pw.print(" hidden="); pw.print(r.hiddenAdj); + pw.print(" curRaw="); pw.print(r.curRawAdj); + pw.print(" setRaw="); pw.print(r.setRawAdj); + pw.print(" cur="); pw.print(r.curAdj); + pw.print(" set="); pw.println(r.setAdj); + pw.print(prefix); + pw.print(" "); + pw.print("keeping="); pw.print(r.keeping); + pw.print(" hidden="); pw.print(r.hidden); + pw.print(" empty="); pw.println(r.empty); + + if (!r.keeping) { + if (r.lastWakeTime != 0) { + long wtime; + BatteryStatsImpl stats = service.mBatteryStatsService.getActiveStatistics(); + synchronized (stats) { + wtime = stats.getProcessWakeTime(r.info.uid, + r.pid, curRealtime); + } + long timeUsed = wtime - r.lastWakeTime; + pw.print(prefix); + pw.print(" "); + pw.print("keep awake over "); + TimeUtils.formatDuration(realtimeSince, pw); + pw.print(" used "); + TimeUtils.formatDuration(timeUsed, pw); + pw.print(" ("); + pw.print((timeUsed*100)/realtimeSince); + pw.println("%)"); + } + if (r.lastCpuTime != 0) { + long timeUsed = r.curCpuTime - r.lastCpuTime; + pw.print(prefix); + pw.print(" "); + pw.print("run cpu over "); + TimeUtils.formatDuration(uptimeSince, pw); + pw.print(" used "); + TimeUtils.formatDuration(timeUsed, pw); + pw.print(" ("); + pw.print((timeUsed*100)/uptimeSince); + pw.println("%)"); } } - } else { - pw.println(String.format("%s%s #%2d: %s", - prefix, (r.persistent ? persistentLabel : normalLabel), - i, r.toString())); - } - if (r.persistent) { - numPers++; } } - return numPers; } static final void dumpApplicationMemoryUsage(FileDescriptor fd, @@ -8544,7 +8694,11 @@ public final class ActivityManagerService extends ActivityManagerNative return null; } - private final void bumpServiceExecutingLocked(ServiceRecord r) { + private final void bumpServiceExecutingLocked(ServiceRecord r, String why) { + if (DEBUG_SERVICE) Log.v(TAG, ">>> EXECUTING " + + why + " of " + r + " in app " + r.app); + else if (DEBUG_SERVICE_EXECUTING) Log.v(TAG, ">>> EXECUTING " + + why + " of " + r.shortName); long now = SystemClock.uptimeMillis(); if (r.executeNesting == 0 && r.app != null) { if (r.app.executingServices.size() == 0) { @@ -8582,8 +8736,7 @@ public final class ActivityManagerService extends ActivityManagerNative grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid, r.packageName, si.intent, si.getUriPermissionsLocked()); } - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING start of " + r); - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "start"); if (!oomAdjusted) { oomAdjusted = true; updateOomAdjLocked(r.app); @@ -8616,9 +8769,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if ((!i.requested || rebind) && i.apps.size() > 0) { try { - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING bind of " + r - + " in " + i + ": shouldUnbind=" + i.hasBound); - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "bind"); r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind); if (!rebind) { i.requested = true; @@ -8653,8 +8804,7 @@ public final class ActivityManagerService extends ActivityManagerNative r.restartTime = r.lastActivity = SystemClock.uptimeMillis(); app.services.add(r); - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING create of " + r + " " + r.intent); - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "create"); updateLruProcessLocked(app, true, true); boolean created = false; @@ -8906,9 +9056,7 @@ public final class ActivityManagerService extends ActivityManagerNative + ": hasBound=" + ibr.hasBound); if (r.app != null && r.app.thread != null && ibr.hasBound) { try { - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING bring down unbind of " + r - + " for " + ibr); - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "bring down unbind"); updateOomAdjLocked(r.app); ibr.hasBound = false; r.app.thread.scheduleUnbindService(r, @@ -8959,12 +9107,7 @@ public final class ActivityManagerService extends ActivityManagerNative r.app.services.remove(r); if (r.app.thread != null) { try { - if (DEBUG_SERVICE) { - RuntimeException here = new RuntimeException(); - here.fillInStackTrace(); - Slog.v(TAG, ">>> EXECUTING stop of " + r, here); - } - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "stop"); mStoppingServices.add(r); updateOomAdjLocked(r.app); r.app.thread.scheduleStopService(r); @@ -9420,9 +9563,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0 && b.intent.hasBound) { try { - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING unbind of " + s - + " from " + b); - bumpServiceExecutingLocked(s); + bumpServiceExecutingLocked(s, "unbind"); updateOomAdjLocked(s.app); b.intent.hasBound = false; // Assume the client doesn't want to know about a rebind; @@ -9643,14 +9784,20 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r + ": nesting=" + r.executeNesting + ", inStopping=" + inStopping + ", app=" + r.app); + else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, "<<< DONE EXECUTING " + r.shortName); r.executeNesting--; if (r.executeNesting <= 0 && r.app != null) { + if (DEBUG_SERVICE) Slog.v(TAG, + "Nesting at 0 of " + r.shortName); r.app.executingServices.remove(r); if (r.app.executingServices.size() == 0) { + if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG, + "No more executingServices of " + r.shortName); mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app); } if (inStopping) { - if (DEBUG_SERVICE) Slog.v(TAG, "doneExecuting remove stopping " + r); + if (DEBUG_SERVICE) Slog.v(TAG, + "doneExecuting remove stopping " + r); mStoppingServices.remove(r); } updateOomAdjLocked(r.app); @@ -9760,20 +9907,20 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!"); return; } + } - long oldIdent = Binder.clearCallingIdentity(); - try { - IBackupManager bm = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); - bm.agentConnected(agentPackageName, agent); - } catch (RemoteException e) { - // can't happen; the backup manager service is local - } catch (Exception e) { - Slog.w(TAG, "Exception trying to deliver BackupAgent binding: "); - e.printStackTrace(); - } finally { - Binder.restoreCallingIdentity(oldIdent); - } + long oldIdent = Binder.clearCallingIdentity(); + try { + IBackupManager bm = IBackupManager.Stub.asInterface( + ServiceManager.getService(Context.BACKUP_SERVICE)); + bm.agentConnected(agentPackageName, agent); + } catch (RemoteException e) { + // can't happen; the backup manager service is local + } catch (Exception e) { + Slog.w(TAG, "Exception trying to deliver BackupAgent binding: "); + e.printStackTrace(); + } finally { + Binder.restoreCallingIdentity(oldIdent); } } @@ -11326,6 +11473,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjType = "fixed"; app.adjSeq = mAdjSeq; app.curRawAdj = app.maxAdj; + app.keeping = true; app.curSchedGroup = Process.THREAD_GROUP_DEFAULT; return (app.curAdj=app.maxAdj); } @@ -11333,6 +11481,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN; app.adjSource = null; app.adjTarget = null; + app.keeping = false; app.empty = false; app.hidden = false; @@ -11462,6 +11611,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (adj > SECONDARY_SERVER_ADJ) { app.adjType = "started-bg-services"; } + // Don't kill this process because it is doing work; it + // has said it is doing work. + app.keeping = true; } if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) { @@ -11495,6 +11647,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (!client.hidden) { app.hidden = false; } + if (client.keeping) { + app.keeping = true; + } app.adjType = "service"; app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_SERVICE_IN_USE; @@ -11528,7 +11683,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - // Finally, f this process has active services running in it, we + // Finally, if this process has active services running in it, we // would like to avoid killing it unless it would prevent the current // application from running. By default we put the process in // with the rest of the background processes; as we scan through @@ -11570,6 +11725,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (!client.hidden) { app.hidden = false; } + if (client.keeping) { + app.keeping = true; + } app.adjType = "provider"; app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_PROVIDER_IN_USE; @@ -11589,6 +11747,7 @@ public final class ActivityManagerService extends ActivityManagerNative adj = FOREGROUND_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.hidden = false; + app.keeping = true; app.adjType = "provider"; app.adjTarget = cpr.name; } @@ -11606,6 +11765,9 @@ public final class ActivityManagerService extends ActivityManagerNative schedGroup = Process.THREAD_GROUP_DEFAULT; } } + if (adj < HIDDEN_APP_MIN_ADJ) { + app.keeping = true; + } app.curAdj = adj; app.curSchedGroup = schedGroup; @@ -11743,57 +11905,99 @@ public final class ActivityManagerService extends ActivityManagerNative } } - final void checkExcessiveWakeLocksLocked(boolean doKills) { + final void checkExcessivePowerUsageLocked(boolean doKills) { + updateCpuStatsNow(); + BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); - if (mLastWakeLockCheckTime == 0) { - doKills = false; + boolean doWakeKills = doKills; + boolean doCpuKills = doKills; + if (mLastPowerCheckRealtime == 0) { + doWakeKills = false; + } + if (mLastPowerCheckUptime == 0) { + doCpuKills = false; } if (stats.isScreenOn()) { - doKills = false; + doWakeKills = false; } final long curRealtime = SystemClock.elapsedRealtime(); - final long timeSince = curRealtime - mLastWakeLockCheckTime; - mLastWakeLockCheckTime = curRealtime; - if (timeSince < (WAKE_LOCK_CHECK_DELAY/3)) { - doKills = false; + final long realtimeSince = curRealtime - mLastPowerCheckRealtime; + final long curUptime = SystemClock.uptimeMillis(); + final long uptimeSince = curUptime - mLastPowerCheckUptime; + mLastPowerCheckRealtime = curRealtime; + mLastPowerCheckUptime = curUptime; + if (realtimeSince < WAKE_LOCK_MIN_CHECK_DURATION) { + doWakeKills = false; + } + if (uptimeSince < CPU_MIN_CHECK_DURATION) { + doCpuKills = false; } int i = mLruProcesses.size(); while (i > 0) { i--; ProcessRecord app = mLruProcesses.get(i); - if (app.curAdj >= HIDDEN_APP_MIN_ADJ) { + if (!app.keeping) { long wtime; synchronized (stats) { wtime = stats.getProcessWakeTime(app.info.uid, app.pid, curRealtime); } - long timeUsed = wtime - app.lastWakeTime; - if (false) { + long wtimeUsed = wtime - app.lastWakeTime; + long cputimeUsed = app.curCpuTime - app.lastCpuTime; + if (DEBUG_POWER) { StringBuilder sb = new StringBuilder(128); sb.append("Wake for "); app.toShortString(sb); sb.append(": over "); - TimeUtils.formatDuration(timeSince, sb); + TimeUtils.formatDuration(realtimeSince, sb); + sb.append(" used "); + TimeUtils.formatDuration(wtimeUsed, sb); + sb.append(" ("); + sb.append((wtimeUsed*100)/realtimeSince); + sb.append("%)"); + Slog.i(TAG, sb.toString()); + sb.setLength(0); + sb.append("CPU for "); + app.toShortString(sb); + sb.append(": over "); + TimeUtils.formatDuration(uptimeSince, sb); sb.append(" used "); - TimeUtils.formatDuration(timeUsed, sb); + TimeUtils.formatDuration(cputimeUsed, sb); sb.append(" ("); - sb.append((timeUsed*100)/timeSince); + sb.append((cputimeUsed*100)/uptimeSince); sb.append("%)"); Slog.i(TAG, sb.toString()); } // If a process has held a wake lock for more // than 50% of the time during this period, // that sounds pad. Kill! - if (doKills && timeSince > 0 - && ((timeUsed*100)/timeSince) >= 50) { - Slog.i(TAG, "Excessive wake lock in " + app.processName - + " (pid " + app.pid + "): held " + timeUsed - + " during " + timeSince); + if (doWakeKills && realtimeSince > 0 + && ((wtimeUsed*100)/realtimeSince) >= 50) { + synchronized (stats) { + stats.reportExcessiveWakeLocked(app.info.uid, app.processName, + realtimeSince, wtimeUsed); + } + Slog.w(TAG, "Excessive wake lock in " + app.processName + + " (pid " + app.pid + "): held " + wtimeUsed + + " during " + realtimeSince); EventLog.writeEvent(EventLogTags.AM_KILL, app.pid, app.processName, app.setAdj, "excessive wake lock"); Process.killProcessQuiet(app.pid); + } else if (doCpuKills && uptimeSince > 0 + && ((cputimeUsed*100)/uptimeSince) >= 50) { + synchronized (stats) { + stats.reportExcessiveCpuLocked(app.info.uid, app.processName, + uptimeSince, cputimeUsed); + } + Slog.w(TAG, "Excessive CPU in " + app.processName + + " (pid " + app.pid + "): used " + cputimeUsed + + " during " + uptimeSince); + EventLog.writeEvent(EventLogTags.AM_KILL, app.pid, + app.processName, app.setAdj, "excessive cpu"); + Process.killProcessQuiet(app.pid); } else { app.lastWakeTime = wtime; + app.lastCpuTime = app.curCpuTime; } } } @@ -11807,6 +12011,8 @@ public final class ActivityManagerService extends ActivityManagerNative return true; } + final boolean wasKeeping = app.keeping; + int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false); if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) { @@ -11821,13 +12027,20 @@ public final class ActivityManagerService extends ActivityManagerNative // Likewise do a gc when an app is moving in to the // background (such as a service stopping). scheduleAppGcLocked(app); - // And note its current wake lock time. + } + + if (wasKeeping && !app.keeping) { + // This app is no longer something we want to keep. Note + // its current wake lock time to later know to kill it if + // it is not behaving well. BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); synchronized (stats) { app.lastWakeTime = stats.getProcessWakeTime(app.info.uid, app.pid, SystemClock.elapsedRealtime()); } + app.lastCpuTime = app.curCpuTime; } + app.setRawAdj = app.curRawAdj; } if (adj != app.setAdj) { diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 67df707..404c6be 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -60,6 +60,7 @@ class ProcessRecord { int setAdj; // Last set OOM adjustment for this process int curSchedGroup; // Currently desired scheduling class int setSchedGroup; // Last set to background scheduling class + boolean keeping; // Actively running code so don't kill due to that? boolean setIsForeground; // Running foreground UI when last set? boolean foregroundServices; // Running any services that are foreground? boolean bad; // True if disabled in the bad process list @@ -75,6 +76,8 @@ class ProcessRecord { ComponentName instrumentationResultClass;// copy of instrumentationClass BroadcastRecord curReceiver;// receiver currently running in the app long lastWakeTime; // How long proc held wake lock at last check + long lastCpuTime; // How long proc has run CPU at last check + long curCpuTime; // How long proc has run CPU most recently long lastRequestedGc; // When we last asked the app to do a gc long lastLowMemory; // When we last told the app that memory is low boolean reportLowMemory; // Set to true when waiting to report low mem @@ -131,13 +134,6 @@ class ProcessRecord { void dump(PrintWriter pw, String prefix) { final long now = SystemClock.uptimeMillis(); - long wtime; - synchronized (batteryStats.getBatteryStats()) { - wtime = batteryStats.getBatteryStats().getProcessWakeTime(info.uid, - pid, SystemClock.elapsedRealtime()); - } - long timeUsed = wtime - lastWakeTime; - if (info.className != null) { pw.print(prefix); pw.print("class="); pw.println(info.className); } @@ -170,6 +166,7 @@ class ProcessRecord { pw.print(prefix); pw.print("lastActivityTime="); TimeUtils.formatDuration(lastActivityTime, now, pw); pw.print(" lruWeight="); pw.print(lruWeight); + pw.print(" keeping="); pw.print(keeping); pw.print(" hidden="); pw.print(hidden); pw.print(" empty="); pw.println(empty); pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj); @@ -188,9 +185,20 @@ class ProcessRecord { pw.print(" persistentActivities="); pw.println(persistentActivities); pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq); pw.print(" lruSeq="); pw.println(lruSeq); - pw.print(prefix); pw.print("lastWakeTime="); pw.print(lastWakeTime); - pw.print(" time used="); - TimeUtils.formatDuration(timeUsed, pw); pw.println(""); + if (!keeping) { + long wtime; + synchronized (batteryStats.getBatteryStats()) { + wtime = batteryStats.getBatteryStats().getProcessWakeTime(info.uid, + pid, SystemClock.elapsedRealtime()); + } + long timeUsed = wtime - lastWakeTime; + pw.print(prefix); pw.print("lastWakeTime="); pw.print(lastWakeTime); + pw.print(" time used="); + TimeUtils.formatDuration(timeUsed, pw); pw.println(""); + pw.print(prefix); pw.print("lastCpuTime="); pw.print(lastCpuTime); + pw.print(" time used="); + TimeUtils.formatDuration(curCpuTime-lastCpuTime, pw); pw.println(""); + } pw.print(prefix); pw.print("lastRequestedGc="); TimeUtils.formatDuration(lastRequestedGc, now, pw); pw.print(" lastLowMemory="); diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index f35a68e..e5aceb4 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -347,7 +347,9 @@ class ServiceRecord extends Binder { // If it gave us a garbage notification, it doesn't // get to be foreground. ams.setServiceForeground(name, ServiceRecord.this, - localForegroundId, null, true); + 0, null, true); + ams.crashApplication(appUid, appPid, localPackageName, + "Bad notification for startForeground: " + e); } } }); diff --git a/services/java/com/android/server/sip/SipService.java b/services/java/com/android/server/sip/SipService.java index f1dcd5a..3f43e1c 100644 --- a/services/java/com/android/server/sip/SipService.java +++ b/services/java/com/android/server/sip/SipService.java @@ -30,8 +30,8 @@ import android.net.sip.ISipSessionListener; import android.net.sip.SipErrorCode; import android.net.sip.SipManager; import android.net.sip.SipProfile; +import android.net.sip.SipSession; import android.net.sip.SipSessionAdapter; -import android.net.sip.SipSessionState; import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Bundle; @@ -143,7 +143,7 @@ public final class SipService extends ISipService.Stub { } private void openToReceiveCalls(SipProfile localProfile) { - open3(localProfile, SipManager.SIP_INCOMING_CALL_ACTION, null); + open3(localProfile, SipManager.ACTION_SIP_INCOMING_CALL, null); } public synchronized void open3(SipProfile localProfile, @@ -255,15 +255,15 @@ public final class SipService extends ISipService.Stub { private void notifyProfileAdded(SipProfile localProfile) { if (DEBUG) Log.d(TAG, "notify: profile added: " + localProfile); - Intent intent = new Intent(SipManager.SIP_ADD_PHONE_ACTION); - intent.putExtra(SipManager.LOCAL_URI_KEY, localProfile.getUriString()); + Intent intent = new Intent(SipManager.ACTION_SIP_ADD_PHONE); + intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); mContext.sendBroadcast(intent); } private void notifyProfileRemoved(SipProfile localProfile) { if (DEBUG) Log.d(TAG, "notify: profile removed: " + localProfile); - Intent intent = new Intent(SipManager.SIP_REMOVE_PHONE_ACTION); - intent.putExtra(SipManager.LOCAL_URI_KEY, localProfile.getUriString()); + Intent intent = new Intent(SipManager.ACTION_SIP_REMOVE_PHONE); + intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); mContext.sendBroadcast(intent); } @@ -474,8 +474,8 @@ public final class SipService extends ISipService.Stub { // send out incoming call broadcast addPendingSession(session); Intent intent = SipManager.createIncomingCallBroadcast( - mIncomingCallBroadcastAction, session.getCallId(), - sessionDescription); + session.getCallId(), sessionDescription) + .setAction(mIncomingCallBroadcastAction); if (DEBUG) Log.d(TAG, " ringing~~ " + getUri() + ": " + caller.getUri() + ": " + session.getCallId() + " " + mIncomingCallBroadcastAction); @@ -613,10 +613,10 @@ public final class SipService extends ISipService.Stub { try { int state = (mSession == null) - ? SipSessionState.READY_TO_CALL + ? SipSession.State.READY_TO_CALL : mSession.getState(); - if ((state == SipSessionState.REGISTERING) - || (state == SipSessionState.DEREGISTERING)) { + if ((state == SipSession.State.REGISTERING) + || (state == SipSession.State.DEREGISTERING)) { mProxy.onRegistering(mSession); } else if (mRegistered) { int duration = (int) @@ -1138,7 +1138,8 @@ public final class SipService extends ISipService.Stub { event.mTriggerTime += event.mPeriod; // run the callback in a new thread to prevent deadlock - new Thread(event.mCallback).start(); + new Thread(event.mCallback, "SipServiceTimerCallbackThread") + .start(); } if (DEBUG_TIMER) { Log.d(TAG, "after timeout execution"); diff --git a/services/java/com/android/server/sip/SipSessionGroup.java b/services/java/com/android/server/sip/SipSessionGroup.java index b4c2241..66a2c05 100644 --- a/services/java/com/android/server/sip/SipSessionGroup.java +++ b/services/java/com/android/server/sip/SipSessionGroup.java @@ -25,11 +25,10 @@ import gov.nist.javax.sip.message.SIPMessage; import android.net.sip.ISipSession; import android.net.sip.ISipSessionListener; -import android.net.sip.SessionDescription; import android.net.sip.SipErrorCode; import android.net.sip.SipProfile; +import android.net.sip.SipSession; import android.net.sip.SipSessionAdapter; -import android.net.sip.SipSessionState; import android.text.TextUtils; import android.util.Log; @@ -121,7 +120,7 @@ class SipSessionGroup implements SipListener { reset(localIp); } - void reset(String localIp) throws SipException, IOException { + synchronized void reset(String localIp) throws SipException, IOException { mLocalIp = localIp; if (localIp == null) return; @@ -301,7 +300,7 @@ class SipSessionGroup implements SipListener { boolean processed = (session != null) && session.process(event); if (isLoggable && processed) { Log.d(TAG, "new state after: " - + SipSessionState.toString(session.mState)); + + SipSession.State.toString(session.mState)); } } catch (Throwable e) { Log.w(TAG, "event process error: " + event, e); @@ -332,7 +331,7 @@ class SipSessionGroup implements SipListener { public boolean process(EventObject evt) throws SipException { if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": " - + SipSessionState.toString(mState) + ": processing " + + SipSession.State.toString(mState) + ": processing " + log(evt)); if (isRequestEvent(Request.INVITE, evt)) { RequestEvent event = (RequestEvent) evt; @@ -342,13 +341,16 @@ class SipSessionGroup implements SipListener { newSession.mDialog = newSession.mServerTransaction.getDialog(); newSession.mInviteReceived = event; newSession.mPeerProfile = createPeerProfile(event.getRequest()); - newSession.mState = SipSessionState.INCOMING_CALL; + newSession.mState = SipSession.State.INCOMING_CALL; newSession.mPeerSessionDescription = extractContent(event.getRequest()); addSipSession(newSession); mProxy.onRinging(newSession, newSession.mPeerProfile, newSession.mPeerSessionDescription); return true; + } else if (isRequestEvent(Request.OPTIONS, evt)) { + mSipHelper.sendResponse((RequestEvent) evt, Response.OK); + return true; } else { return false; } @@ -358,7 +360,7 @@ class SipSessionGroup implements SipListener { class SipSessionImpl extends ISipSession.Stub { SipProfile mPeerProfile; SipSessionListenerProxy mProxy = new SipSessionListenerProxy(); - int mState = SipSessionState.READY_TO_CALL; + int mState = SipSession.State.READY_TO_CALL; RequestEvent mInviteReceived; Dialog mDialog; ServerTransaction mServerTransaction; @@ -378,7 +380,7 @@ class SipSessionGroup implements SipListener { sleep(timeout); if (mRunning) timeout(); } - }).start(); + }, "SipSessionTimerThread").start(); } synchronized void cancel() { @@ -413,7 +415,7 @@ class SipSessionGroup implements SipListener { mInCall = false; removeSipSession(this); mPeerProfile = null; - mState = SipSessionState.READY_TO_CALL; + mState = SipSession.State.READY_TO_CALL; mInviteReceived = null; mDialog = null; mServerTransaction = null; @@ -470,7 +472,7 @@ class SipSessionGroup implements SipListener { onError(e); } } - }).start(); + }, "SipSessionAsyncCmdThread").start(); } public void makeCall(SipProfile peerProfile, String sessionDescription, @@ -520,10 +522,10 @@ class SipSessionGroup implements SipListener { } public void sendKeepAlive() { - mState = SipSessionState.PINGING; + mState = SipSession.State.PINGING; try { processCommand(new OptionsCommand()); - while (SipSessionState.PINGING == mState) { + while (SipSession.State.PINGING == mState) { Thread.sleep(1000); } } catch (SipException e) { @@ -550,7 +552,7 @@ class SipSessionGroup implements SipListener { try { String s = super.toString(); return s.substring(s.indexOf("@")) + ":" - + SipSessionState.toString(mState); + + SipSession.State.toString(mState); } catch (Throwable e) { return super.toString(); } @@ -558,7 +560,7 @@ class SipSessionGroup implements SipListener { public boolean process(EventObject evt) throws SipException { if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": " - + SipSessionState.toString(mState) + ": processing " + + SipSession.State.toString(mState) + ": processing " + log(evt)); synchronized (SipSessionGroup.this) { if (isClosed()) return false; @@ -574,30 +576,30 @@ class SipSessionGroup implements SipListener { boolean processed; switch (mState) { - case SipSessionState.REGISTERING: - case SipSessionState.DEREGISTERING: + case SipSession.State.REGISTERING: + case SipSession.State.DEREGISTERING: processed = registeringToReady(evt); break; - case SipSessionState.PINGING: + case SipSession.State.PINGING: processed = keepAliveProcess(evt); break; - case SipSessionState.READY_TO_CALL: + case SipSession.State.READY_TO_CALL: processed = readyForCall(evt); break; - case SipSessionState.INCOMING_CALL: + case SipSession.State.INCOMING_CALL: processed = incomingCall(evt); break; - case SipSessionState.INCOMING_CALL_ANSWERING: + case SipSession.State.INCOMING_CALL_ANSWERING: processed = incomingCallToInCall(evt); break; - case SipSessionState.OUTGOING_CALL: - case SipSessionState.OUTGOING_CALL_RING_BACK: + case SipSession.State.OUTGOING_CALL: + case SipSession.State.OUTGOING_CALL_RING_BACK: processed = outgoingCall(evt); break; - case SipSessionState.OUTGOING_CALL_CANCELING: + case SipSession.State.OUTGOING_CALL_CANCELING: processed = outgoingCallToReady(evt); break; - case SipSessionState.IN_CALL: + case SipSession.State.IN_CALL: processed = inCall(evt); break; default: @@ -625,6 +627,9 @@ class SipSessionGroup implements SipListener { (TransactionTerminatedEvent) evt); } return true; + } else if (isRequestEvent(Request.OPTIONS, evt)) { + mSipHelper.sendResponse((RequestEvent) evt, Response.OK); + return true; } else if (evt instanceof DialogTerminatedEvent) { processDialogTerminated((DialogTerminatedEvent) evt); return true; @@ -644,8 +649,8 @@ class SipSessionGroup implements SipListener { private void processTransactionTerminated( TransactionTerminatedEvent event) { switch (mState) { - case SipSessionState.IN_CALL: - case SipSessionState.READY_TO_CALL: + case SipSession.State.IN_CALL: + case SipSession.State.READY_TO_CALL: Log.d(TAG, "Transaction terminated; do nothing"); break; default: @@ -664,27 +669,27 @@ class SipSessionGroup implements SipListener { ? event.getServerTransaction() : event.getClientTransaction(); - if ((current != target) && (mState != SipSessionState.PINGING)) { + if ((current != target) && (mState != SipSession.State.PINGING)) { Log.d(TAG, "not the current transaction; current=" + current + ", timed out=" + target); return; } switch (mState) { - case SipSessionState.REGISTERING: - case SipSessionState.DEREGISTERING: + case SipSession.State.REGISTERING: + case SipSession.State.DEREGISTERING: reset(); mProxy.onRegistrationTimeout(this); break; - case SipSessionState.INCOMING_CALL: - case SipSessionState.INCOMING_CALL_ANSWERING: - case SipSessionState.OUTGOING_CALL: - case SipSessionState.OUTGOING_CALL_CANCELING: + case SipSession.State.INCOMING_CALL: + case SipSession.State.INCOMING_CALL_ANSWERING: + case SipSession.State.OUTGOING_CALL: + case SipSession.State.OUTGOING_CALL_CANCELING: onError(SipErrorCode.TIME_OUT, event.toString()); break; - case SipSessionState.PINGING: + case SipSession.State.PINGING: reset(); mReRegisterFlag = true; - mState = SipSessionState.READY_TO_CALL; + mState = SipSession.State.READY_TO_CALL; break; default: @@ -758,7 +763,7 @@ class SipSessionGroup implements SipListener { switch (statusCode) { case Response.OK: int state = mState; - onRegistrationDone((state == SipSessionState.REGISTERING) + onRegistrationDone((state == SipSession.State.REGISTERING) ? getExpiryTime(((ResponseEvent) evt).getResponse()) : -1); mLastNonce = null; @@ -845,7 +850,7 @@ class SipSessionGroup implements SipListener { generateTag()); mDialog = mClientTransaction.getDialog(); addSipSession(this); - mState = SipSessionState.OUTGOING_CALL; + mState = SipSession.State.OUTGOING_CALL; mProxy.onCalling(this); startSessionTimer(cmd.getTimeout()); return true; @@ -855,7 +860,7 @@ class SipSessionGroup implements SipListener { generateTag(), duration); mDialog = mClientTransaction.getDialog(); addSipSession(this); - mState = SipSessionState.REGISTERING; + mState = SipSession.State.REGISTERING; mProxy.onRegistering(this); return true; } else if (DEREGISTER == evt) { @@ -863,7 +868,7 @@ class SipSessionGroup implements SipListener { generateTag(), 0); mDialog = mClientTransaction.getDialog(); addSipSession(this); - mState = SipSessionState.DEREGISTERING; + mState = SipSession.State.DEREGISTERING; mProxy.onRegistering(this); return true; } @@ -878,7 +883,7 @@ class SipSessionGroup implements SipListener { mLocalProfile, ((MakeCallCommand) evt).getSessionDescription(), mServerTransaction); - mState = SipSessionState.INCOMING_CALL_ANSWERING; + mState = SipSession.State.INCOMING_CALL_ANSWERING; startSessionTimer(((MakeCallCommand) evt).getTimeout()); return true; } else if (END_CALL == evt) { @@ -919,8 +924,8 @@ class SipSessionGroup implements SipListener { int statusCode = response.getStatusCode(); switch (statusCode) { case Response.RINGING: - if (mState == SipSessionState.OUTGOING_CALL) { - mState = SipSessionState.OUTGOING_CALL_RING_BACK; + if (mState == SipSession.State.OUTGOING_CALL) { + mState = SipSession.State.OUTGOING_CALL_RING_BACK; mProxy.onRingingBack(this); cancelSessionTimer(); } @@ -963,7 +968,7 @@ class SipSessionGroup implements SipListener { // response comes back yet. We are cheating for not checking // response. mSipHelper.sendCancel(mClientTransaction); - mState = SipSessionState.OUTGOING_CALL_CANCELING; + mState = SipSession.State.OUTGOING_CALL_CANCELING; startSessionTimer(CANCEL_CALL_TIMER); return true; } @@ -1019,7 +1024,7 @@ class SipSessionGroup implements SipListener { } else if (isRequestEvent(Request.INVITE, evt)) { // got Re-INVITE RequestEvent event = mInviteReceived = (RequestEvent) evt; - mState = SipSessionState.INCOMING_CALL; + mState = SipSession.State.INCOMING_CALL; mPeerSessionDescription = extractContent(event.getRequest()); mServerTransaction = null; mProxy.onRinging(this, mPeerProfile, mPeerSessionDescription); @@ -1032,7 +1037,7 @@ class SipSessionGroup implements SipListener { // to change call mClientTransaction = mSipHelper.sendReinvite(mDialog, ((MakeCallCommand) evt).getSessionDescription()); - mState = SipSessionState.OUTGOING_CALL; + mState = SipSession.State.OUTGOING_CALL; startSessionTimer(((MakeCallCommand) evt).getTimeout()); return true; } @@ -1060,14 +1065,14 @@ class SipSessionGroup implements SipListener { } private void establishCall() { - mState = SipSessionState.IN_CALL; + mState = SipSession.State.IN_CALL; mInCall = true; cancelSessionTimer(); mProxy.onCallEstablished(this, mPeerSessionDescription); } private void fallbackToPreviousInCall(int errorCode, String message) { - mState = SipSessionState.IN_CALL; + mState = SipSession.State.IN_CALL; mProxy.onCallChangeFailed(this, errorCode, message); } @@ -1089,8 +1094,8 @@ class SipSessionGroup implements SipListener { private void onError(int errorCode, String message) { cancelSessionTimer(); switch (mState) { - case SipSessionState.REGISTERING: - case SipSessionState.DEREGISTERING: + case SipSession.State.REGISTERING: + case SipSession.State.DEREGISTERING: onRegistrationFailed(errorCode, message); break; default: @@ -1264,7 +1269,7 @@ class SipSessionGroup implements SipListener { private static boolean isLoggable(SipSessionImpl s) { if (s != null) { switch (s.mState) { - case SipSessionState.PINGING: + case SipSession.State.PINGING: return DEBUG_PING; } } diff --git a/services/java/com/android/server/sip/SipSessionListenerProxy.java b/services/java/com/android/server/sip/SipSessionListenerProxy.java index a4cd102..f8be0a8 100644 --- a/services/java/com/android/server/sip/SipSessionListenerProxy.java +++ b/services/java/com/android/server/sip/SipSessionListenerProxy.java @@ -40,7 +40,7 @@ class SipSessionListenerProxy extends ISipSessionListener.Stub { // One thread for each calling back. // Note: Guarantee ordering if the issue becomes important. Currently, // the chance of handling two callback events at a time is none. - new Thread(runnable).start(); + new Thread(runnable, "SipSessionCallbackThread").start(); } public void onCalling(final ISipSession session) { diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 129be4e..ff887e4 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -21,6 +21,7 @@ #include <sys/types.h> #include <utils/Errors.h> +#include <utils/String8.h> #include <hardware/hardware.h> @@ -100,5 +101,25 @@ hwc_layer_t* HWComposer::getLayers() const { return mList ? mList->hwLayers : 0; } +void HWComposer::dump(String8& result, char* buffer, size_t SIZE) const { + if (mHwc && mList) { + result.append("Hardware Composer state:\n"); + + snprintf(buffer, SIZE, " numHwLayers=%u, flags=%08x\n", + mList->numHwLayers, mList->flags); + result.append(buffer); + + for (size_t i=0 ; i<mList->numHwLayers ; i++) { + const hwc_layer_t& l(mList->hwLayers[i]); + snprintf(buffer, SIZE, " %8s | %08x | %08x | %02x | %04x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d]\n", + l.compositionType ? "OVERLAY" : "FB", + l.hints, l.flags, l.transform, l.blending, + l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom, + l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom); + result.append(buffer); + } + } +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 22ff10c..5a9e9eb 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -27,6 +27,8 @@ namespace android { // --------------------------------------------------------------------------- +class String8; + class HWComposer { public: @@ -54,6 +56,9 @@ public: size_t getNumLayers() const; hwc_layer_t* getLayers() const; + // for debugging + void dump(String8& out, char* scratch, size_t SIZE) const; + private: hw_module_t const* mModule; hwc_composer_device_t* mHwc; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b45f6fe..b353bff 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -85,6 +85,7 @@ SurfaceFlinger::SurfaceFlinger() mFreezeDisplayTime(0), mDebugRegion(0), mDebugBackground(0), + mDebugDisableHWC(0), mDebugInSwapBuffers(0), mLastSwapBufferTime(0), mDebugInTransaction(0), @@ -768,6 +769,10 @@ void SurfaceFlinger::handleWorkList() hwc_layer_t* const cur(hwc.getLayers()); for (size_t i=0 ; cur && i<count ; i++) { currentLayers[i]->setGeometry(&cur[i]); + if (mDebugDisableHWC) { + cur[i].compositionType = HWC_FRAMEBUFFER; + cur[i].flags |= HWC_SKIP_LAYER; + } } } } @@ -901,6 +906,7 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty) continue; } } + const sp<LayerBase>& layer(layers[i]); const Region clip(dirty.intersect(layer->visibleRegionScreen)); if (!clip.isEmpty()) { @@ -1522,6 +1528,13 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) result.append(buffer); } + HWComposer& hwc(hw.getHwComposer()); + snprintf(buffer, SIZE, " h/w composer %s and %s\n", + hwc.initCheck()==NO_ERROR ? "present" : "not present", + mDebugDisableHWC ? "disabled" : "enabled"); + result.append(buffer); + hwc.dump(result, buffer, SIZE); + const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); alloc.dump(result); @@ -1580,6 +1593,11 @@ status_t SurfaceFlinger::onTransact( n = data.readInt32(); mDebugBackground = n ? 1 : 0; return NO_ERROR; + case 1008: // toggle use of hw composer + n = data.readInt32(); + mDebugDisableHWC = n ? 1 : 0; + mHwWorkListDirty = true; + // fall-through... case 1004:{ // repaint everything Mutex::Autolock _l(mStateLock); const DisplayHardware& hw(graphicPlane(0).displayHardware()); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8e286e5..551e8e7 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -382,6 +382,7 @@ private: // don't use a lock for these, we don't care int mDebugRegion; int mDebugBackground; + int mDebugDisableHWC; volatile nsecs_t mDebugInSwapBuffers; nsecs_t mLastSwapBufferTime; volatile nsecs_t mDebugInTransaction; diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java index 9fcf12d..4791fbd 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java @@ -27,7 +27,7 @@ import android.net.sip.SipErrorCode; import android.net.sip.SipException; import android.net.sip.SipManager; import android.net.sip.SipProfile; -import android.net.sip.SipSessionState; +import android.net.sip.SipSession; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; @@ -91,7 +91,7 @@ public class SipPhone extends SipPhoneBase { foregroundCall = new SipCall(); backgroundCall = new SipCall(); mProfile = profile; - mSipManager = SipManager.getInstance(context); + mSipManager = SipManager.newInstance(context); // FIXME: what's this for SIP? //Change the system property @@ -710,8 +710,8 @@ public class SipPhone extends SipPhoneBase { void dial() throws SipException { setState(Call.State.DIALING); - mSipAudioCall = mSipManager.makeAudioCall(mContext, mProfile, - mPeer, null, SESSION_TIMEOUT); + mSipAudioCall = mSipManager.makeAudioCall(mProfile, mPeer, null, + SESSION_TIMEOUT); mSipAudioCall.setRingbackToneEnabled(false); mSipAudioCall.setListener(mAdapter); } @@ -807,20 +807,20 @@ public class SipPhone extends SipPhoneBase { if (sipAudioCall.isOnHold()) return Call.State.HOLDING; int sessionState = sipAudioCall.getState(); switch (sessionState) { - case SipSessionState.READY_TO_CALL: return Call.State.IDLE; - case SipSessionState.INCOMING_CALL: - case SipSessionState.INCOMING_CALL_ANSWERING: return Call.State.INCOMING; - case SipSessionState.OUTGOING_CALL: return Call.State.DIALING; - case SipSessionState.OUTGOING_CALL_RING_BACK: return Call.State.ALERTING; - case SipSessionState.OUTGOING_CALL_CANCELING: return Call.State.DISCONNECTING; - case SipSessionState.IN_CALL: return Call.State.ACTIVE; + case SipSession.State.READY_TO_CALL: return Call.State.IDLE; + case SipSession.State.INCOMING_CALL: + case SipSession.State.INCOMING_CALL_ANSWERING: return Call.State.INCOMING; + case SipSession.State.OUTGOING_CALL: return Call.State.DIALING; + case SipSession.State.OUTGOING_CALL_RING_BACK: return Call.State.ALERTING; + case SipSession.State.OUTGOING_CALL_CANCELING: return Call.State.DISCONNECTING; + case SipSession.State.IN_CALL: return Call.State.ACTIVE; default: Log.w(LOG_TAG, "illegal connection state: " + sessionState); return Call.State.DISCONNECTED; } } - private abstract class SipAudioCallAdapter extends SipAudioCall.Adapter { + private abstract class SipAudioCallAdapter extends SipAudioCall.Listener { protected abstract void onCallEnded(Connection.DisconnectCause cause); protected abstract void onError(Connection.DisconnectCause cause); diff --git a/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java b/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java index 48c4520..5fb09a7 100644 --- a/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java +++ b/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java @@ -25,6 +25,7 @@ import android.os.BatteryManager; import android.os.Bundle; import android.os.PowerManager; import android.view.View; +import android.view.WindowManager; import android.widget.CheckBox; import android.widget.TextView; @@ -38,7 +39,6 @@ public class BatteryWaster extends Activity { TextView mLog; DateFormat mDateFormat; IntentFilter mFilter; - PowerManager.WakeLock mWakeLock; PowerManager.WakeLock mPartialWakeLock; SpinThread mThread; @@ -65,24 +65,26 @@ public class BatteryWaster extends Activity { mFilter.addAction(Intent.ACTION_POWER_CONNECTED); PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "BatteryWaster"); - mWakeLock.setReferenceCounted(false); mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "BatteryWaster"); mPartialWakeLock.setReferenceCounted(false); } @Override - public void onPause() { - super.onPause(); - stopRunning(); + public void onResume() { + super.onResume(); + if (((CheckBox)findViewById(R.id.checkbox)).isChecked()) { + startRunning(); + } + if (((CheckBox)findViewById(R.id.checkbox_wake)).isChecked()) { + mWaking = true; + updateWakeLock(); + } } @Override public void onDestroy() { super.onDestroy(); - if (mWakeLock.isHeld()) { - mWakeLock.release(); - } + stopRunning(); if (mPartialWakeLock.isHeld()) { mPartialWakeLock.release(); } @@ -140,13 +142,9 @@ public class BatteryWaster extends Activity { void updateWakeLock() { if (mWasting) { - if (!mWakeLock.isHeld()) { - mWakeLock.acquire(); - } + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } else { - if (mWakeLock.isHeld()) { - mWakeLock.release(); - } + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } if (mWaking) { if (!mPartialWakeLock.isHeld()) { diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index a1bc241..c5aa573 100644 --- a/tools/aapt/Bundle.h +++ b/tools/aapt/Bundle.h @@ -45,7 +45,7 @@ public: mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL), mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL), mVersionCode(NULL), mVersionName(NULL), mCustomPackage(NULL), - mMaxResVersion(NULL), mDebugMode(false), + mMaxResVersion(NULL), mDebugMode(false), mProduct(NULL), mArgc(0), mArgv(NULL) {} ~Bundle(void) {} @@ -139,6 +139,8 @@ public: void setMaxResVersion(const char * val) { mMaxResVersion = val; } bool getDebugMode() { return mDebugMode; } void setDebugMode(bool val) { mDebugMode = val; } + const char* getProduct() const { return mProduct; } + void setProduct(const char * val) { mProduct = val; } /* * Set and get the file specification. @@ -237,6 +239,7 @@ private: const char* mCustomPackage; const char* mMaxResVersion; bool mDebugMode; + const char* mProduct; /* file specification */ int mArgc; diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp index 71c023d..739b01f 100644 --- a/tools/aapt/Main.cpp +++ b/tools/aapt/Main.cpp @@ -67,6 +67,7 @@ void usage(void) " [-A asset-source-dir] [-G class-list-file] [-P public-definitions-file] \\\n" " [-S resource-sources [-S resource-sources ...]] " " [-F apk-file] [-J R-file-dir] \\\n" + " [--product product1,product2,...] \\\n" " [raw-files-dir [raw-files-dir] ...]\n" "\n" " Package the android resources. It will read assets and resources that are\n" @@ -154,6 +155,9 @@ void usage(void) " components target the given package. Useful when used in\n" " conjunction with --rename-manifest-package to fix tests against\n" " a package that has been renamed.\n" + " --product\n" + " Specifies which variant to choose for strings that have\n" + " product variants\n" " --utf16\n" " changes default encoding for resources to UTF-16. Only useful when API\n" " level is set to 7 or higher where the default encoding is UTF-8.\n"); @@ -484,6 +488,15 @@ int main(int argc, char* const argv[]) bundle.setInstrumentationPackageNameOverride(argv[0]); } else if (strcmp(cp, "-auto-add-overlay") == 0) { bundle.setAutoAddOverlay(true); + } else if (strcmp(cp, "-product") == 0) { + argc--; + argv++; + if (!argc) { + fprintf(stderr, "ERROR: No argument supplied for '--product' option\n"); + wantUsage = true; + goto bail; + } + bundle.setProduct(argv[0]); } else { fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp); wantUsage = true; diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index f40a877..90a6256 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -574,6 +574,7 @@ status_t parseAndAddBag(Bundle* bundle, const String16& itemIdent, int32_t curFormat, bool isFormatted, + const String16& product, bool pseudolocalize, const bool overwrite, ResourceTable* outTable) @@ -606,6 +607,32 @@ status_t parseAndAddBag(Bundle* bundle, return err; } +/* + * Returns true if needle is one of the elements in the comma-separated list + * haystack, false otherwise. + */ +bool isInProductList(const String16& needle, const String16& haystack) { + const char16_t *needle2 = needle.string(); + const char16_t *haystack2 = haystack.string(); + size_t needlesize = needle.size(); + + while (*haystack2 != '\0') { + if (strncmp16(haystack2, needle2, needlesize) == 0) { + if (haystack2[needlesize] == '\0' || haystack2[needlesize] == ',') { + return true; + } + } + + while (*haystack2 != '\0' && *haystack2 != ',') { + haystack2++; + } + if (*haystack2 == ',') { + haystack2++; + } + } + + return false; +} status_t parseAndAddEntry(Bundle* bundle, const sp<AaptFile>& in, @@ -618,6 +645,7 @@ status_t parseAndAddEntry(Bundle* bundle, bool curIsStyled, int32_t curFormat, bool isFormatted, + const String16& product, bool pseudolocalize, const bool overwrite, ResourceTable* outTable) @@ -634,6 +662,47 @@ status_t parseAndAddEntry(Bundle* bundle, return err; } + /* + * If a product type was specified on the command line + * and also in the string, and the two are not the same, + * return without adding the string. + */ + + const char *bundleProduct = bundle->getProduct(); + if (bundleProduct == NULL) { + bundleProduct = ""; + } + + if (product.size() != 0) { + /* + * If the command-line-specified product is empty, only "default" + * matches. Other variants are skipped. This is so generation + * of the R.java file when the product is not known is predictable. + */ + + if (bundleProduct[0] == '\0') { + if (strcmp16(String16("default").string(), product.string()) != 0) { + return NO_ERROR; + } + } else { + /* + * The command-line product is not empty. + * If the product for this string is on the command-line list, + * it matches. "default" also matches, but only if nothing + * else has matched already. + */ + + if (isInProductList(product, String16(bundleProduct))) { + ; + } else if (strcmp16(String16("default").string(), product.string()) == 0 && + !outTable->hasBagOrEntry(myPackage, curType, ident)) { + ; + } else { + return NO_ERROR; + } + } + } + NOISY(printf("Adding resource entry l=%c%c c=%c%c orien=%d d=%d id=%s: %s\n", config.language[0], config.language[1], config.country[0], config.country[1], @@ -713,6 +782,7 @@ status_t compileResourceFile(Bundle* bundle, const String16 translatable16("translatable"); const String16 formatted16("formatted"); const String16 false16("false"); + const String16 product16("product"); const String16 myPackage(assets->getPackage()); @@ -760,6 +830,7 @@ status_t compileResourceFile(Bundle* bundle, bool curIsStyled = false; bool curIsPseudolocalizable = false; bool curIsFormatted = fileIsTranslatable; + String16 curProduct; bool localHasErrors = false; if (strcmp16(block.getElementName(&len), skip16.string()) == 0) { @@ -1157,6 +1228,8 @@ status_t compileResourceFile(Bundle* bundle, translatable.setTo(block.getAttributeStringValue(i, &length)); } else if (strcmp16(attr, formatted16.string()) == 0) { formatted.setTo(block.getAttributeStringValue(i, &length)); + } else if (strcmp16(attr, product16.string()) == 0) { + curProduct.setTo(block.getAttributeStringValue(i, &length)); } } @@ -1374,7 +1447,7 @@ status_t compileResourceFile(Bundle* bundle, err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType, ident, parentIdent, itemIdent, curFormat, curIsFormatted, - false, overwrite, outTable); + curProduct, false, overwrite, outTable); if (err == NO_ERROR) { if (curIsPseudolocalizable && localeIsDefined(curParams) && bundle->getPseudolocalize()) { @@ -1383,7 +1456,7 @@ status_t compileResourceFile(Bundle* bundle, block.setPosition(parserPosition); err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage, curType, ident, parentIdent, itemIdent, curFormat, - curIsFormatted, true, overwrite, outTable); + curIsFormatted, curProduct, true, overwrite, outTable); #endif } } @@ -1407,7 +1480,7 @@ status_t compileResourceFile(Bundle* bundle, err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident, *curTag, curIsStyled, curFormat, curIsFormatted, - false, overwrite, outTable); + curProduct, false, overwrite, outTable); if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR? hasErrors = localHasErrors = true; @@ -1419,7 +1492,8 @@ status_t compileResourceFile(Bundle* bundle, block.setPosition(parserPosition); err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType, ident, *curTag, curIsStyled, curFormat, - curIsFormatted, true, overwrite, outTable); + curIsFormatted, curProduct, + true, overwrite, outTable); if (err != NO_ERROR) { hasErrors = localHasErrors = true; } diff --git a/voip/java/android/net/sip/SdpSessionDescription.java b/voip/java/android/net/sip/SdpSessionDescription.java deleted file mode 100644 index f6ae837..0000000 --- a/voip/java/android/net/sip/SdpSessionDescription.java +++ /dev/null @@ -1,428 +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.net.sip; - -import gov.nist.javax.sdp.SessionDescriptionImpl; -import gov.nist.javax.sdp.fields.AttributeField; -import gov.nist.javax.sdp.fields.ConnectionField; -import gov.nist.javax.sdp.fields.MediaField; -import gov.nist.javax.sdp.fields.OriginField; -import gov.nist.javax.sdp.fields.ProtoVersionField; -import gov.nist.javax.sdp.fields.SessionNameField; -import gov.nist.javax.sdp.fields.TimeField; -import gov.nist.javax.sdp.parser.SDPAnnounceParser; - -import android.util.Log; - -import java.text.ParseException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Vector; -import javax.sdp.Connection; -import javax.sdp.MediaDescription; -import javax.sdp.SdpException; - -/** - * A session description that follows SDP (Session Description Protocol). - * Refer to <a href="http://tools.ietf.org/html/rfc4566">RFC 4566</a>. - * @hide - */ -public class SdpSessionDescription extends SessionDescription { - private static final String TAG = "SDP"; - private static final String AUDIO = "audio"; - private static final String RTPMAP = "rtpmap"; - private static final String PTIME = "ptime"; - private static final String SENDONLY = "sendonly"; - private static final String RECVONLY = "recvonly"; - private static final String INACTIVE = "inactive"; - - private SessionDescriptionImpl mSessionDescription; - - /** - * The audio codec information parsed from "rtpmap". - */ - public static class AudioCodec { - public final int payloadType; - public final String name; - public final int sampleRate; - public final int sampleCount; - - public AudioCodec(int payloadType, String name, int sampleRate, - int sampleCount) { - this.payloadType = payloadType; - this.name = name; - this.sampleRate = sampleRate; - this.sampleCount = sampleCount; - } - } - - /** - * The builder class used to create an {@link SdpSessionDescription} object. - */ - public static class Builder { - private SdpSessionDescription mSdp = new SdpSessionDescription(); - private SessionDescriptionImpl mSessionDescription; - - public Builder(String sessionName) throws SdpException { - mSessionDescription = new SessionDescriptionImpl(); - mSdp.mSessionDescription = mSessionDescription; - try { - ProtoVersionField proto = new ProtoVersionField(); - proto.setVersion(0); - mSessionDescription.addField(proto); - - TimeField time = new TimeField(); - time.setZero(); - mSessionDescription.addField(time); - - SessionNameField session = new SessionNameField(); - session.setValue(sessionName); - mSessionDescription.addField(session); - } catch (Exception e) { - throwSdpException(e); - } - } - - public Builder setConnectionInfo(String networkType, String addressType, - String addr) throws SdpException { - try { - ConnectionField connection = new ConnectionField(); - connection.setNetworkType(networkType); - connection.setAddressType(addressType); - connection.setAddress(addr); - mSessionDescription.addField(connection); - } catch (Exception e) { - throwSdpException(e); - } - return this; - } - - public Builder setOrigin(SipProfile user, long sessionId, - long sessionVersion, String networkType, String addressType, - String address) throws SdpException { - try { - OriginField origin = new OriginField(); - origin.setUsername(user.getUserName()); - origin.setSessionId(sessionId); - origin.setSessionVersion(sessionVersion); - origin.setAddressType(addressType); - origin.setNetworkType(networkType); - origin.setAddress(address); - mSessionDescription.addField(origin); - } catch (Exception e) { - throwSdpException(e); - } - return this; - } - - public Builder addMedia(String media, int port, int numPorts, - String transport, Integer... types) throws SdpException { - MediaField field = new MediaField(); - Vector<Integer> typeVector = new Vector<Integer>(); - Collections.addAll(typeVector, types); - try { - field.setMediaType(media); - field.setMediaPort(port); - field.setPortCount(numPorts); - field.setProtocol(transport); - field.setMediaFormats(typeVector); - mSessionDescription.addField(field); - } catch (Exception e) { - throwSdpException(e); - } - return this; - } - - public Builder addMediaAttribute(String type, String name, String value) - throws SdpException { - try { - MediaDescription md = mSdp.getMediaDescription(type); - if (md == null) { - throw new SdpException("Should add media first!"); - } - AttributeField attribute = new AttributeField(); - attribute.setName(name); - attribute.setValueAllowNull(value); - mSessionDescription.addField(attribute); - } catch (Exception e) { - throwSdpException(e); - } - return this; - } - - public Builder addSessionAttribute(String name, String value) - throws SdpException { - try { - AttributeField attribute = new AttributeField(); - attribute.setName(name); - attribute.setValueAllowNull(value); - mSessionDescription.addField(attribute); - } catch (Exception e) { - throwSdpException(e); - } - return this; - } - - private void throwSdpException(Exception e) throws SdpException { - if (e instanceof SdpException) { - throw (SdpException) e; - } else { - throw new SdpException(e.toString(), e); - } - } - - public String build() { - return mSdp.toString(); - } - } - - private SdpSessionDescription() { - } - - /** - * Constructor. - * - * @param sdpString an SDP session description to parse - */ - public SdpSessionDescription(String sdpString) throws SdpException { - try { - mSessionDescription = new SDPAnnounceParser(sdpString).parse(); - } catch (ParseException e) { - throw new SdpException(e.toString(), e); - } - verify(); - } - - /** - * Constructor. - * - * @param content a raw SDP session description to parse - */ - public SdpSessionDescription(byte[] content) throws SdpException { - this(new String(content)); - } - - private void verify() throws SdpException { - // make sure the syntax is correct over the fields we're interested in - Vector<MediaDescription> descriptions = (Vector<MediaDescription>) - mSessionDescription.getMediaDescriptions(false); - for (MediaDescription md : descriptions) { - md.getMedia().getMediaPort(); - Connection connection = md.getConnection(); - if (connection != null) connection.getAddress(); - md.getMedia().getFormats(); - } - Connection connection = mSessionDescription.getConnection(); - if (connection != null) connection.getAddress(); - } - - /** - * Gets the connection address of the media. - * - * @param type the media type; e.g., "AUDIO" - * @return the media connection address of the peer - */ - public String getPeerMediaAddress(String type) { - try { - MediaDescription md = getMediaDescription(type); - Connection connection = md.getConnection(); - if (connection == null) { - connection = mSessionDescription.getConnection(); - } - return ((connection == null) ? null : connection.getAddress()); - } catch (SdpException e) { - // should not occur - return null; - } - } - - /** - * Gets the connection port number of the media. - * - * @param type the media type; e.g., "AUDIO" - * @return the media connection port number of the peer - */ - public int getPeerMediaPort(String type) { - try { - MediaDescription md = getMediaDescription(type); - return md.getMedia().getMediaPort(); - } catch (SdpException e) { - // should not occur - return -1; - } - } - - private boolean containsAttribute(String type, String name) { - if (name == null) return false; - MediaDescription md = getMediaDescription(type); - Vector<AttributeField> v = (Vector<AttributeField>) - md.getAttributeFields(); - for (AttributeField field : v) { - if (name.equals(field.getAttribute().getName())) return true; - } - return false; - } - - /** - * Checks if the media is "sendonly". - * - * @param type the media type; e.g., "AUDIO" - * @return true if the media is "sendonly" - */ - public boolean isSendOnly(String type) { - boolean answer = containsAttribute(type, SENDONLY); - Log.d(TAG, " sendonly? " + answer); - return answer; - } - - /** - * Checks if the media is "recvonly". - * - * @param type the media type; e.g., "AUDIO" - * @return true if the media is "recvonly" - */ - public boolean isReceiveOnly(String type) { - boolean answer = containsAttribute(type, RECVONLY); - Log.d(TAG, " recvonly? " + answer); - return answer; - } - - /** - * Checks if the media is in sending; i.e., not "recvonly" and not - * "inactive". - * - * @param type the media type; e.g., "AUDIO" - * @return true if the media is sending - */ - public boolean isSending(String type) { - boolean answer = !containsAttribute(type, RECVONLY) - && !containsAttribute(type, INACTIVE); - - Log.d(TAG, " sending? " + answer); - return answer; - } - - /** - * Checks if the media is in receiving; i.e., not "sendonly" and not - * "inactive". - * - * @param type the media type; e.g., "AUDIO" - * @return true if the media is receiving - */ - public boolean isReceiving(String type) { - boolean answer = !containsAttribute(type, SENDONLY) - && !containsAttribute(type, INACTIVE); - Log.d(TAG, " receiving? " + answer); - return answer; - } - - private AudioCodec parseAudioCodec(String rtpmap, int ptime) { - String[] ss = rtpmap.split(" "); - int payloadType = Integer.parseInt(ss[0]); - - ss = ss[1].split("/"); - String name = ss[0]; - int sampleRate = Integer.parseInt(ss[1]); - int channelCount = 1; - if (ss.length > 2) channelCount = Integer.parseInt(ss[2]); - int sampleCount = sampleRate / (1000 / ptime) * channelCount; - return new AudioCodec(payloadType, name, sampleRate, sampleCount); - } - - /** - * Gets the list of audio codecs in this session description. - * - * @return the list of audio codecs in this session description - */ - public List<AudioCodec> getAudioCodecs() { - MediaDescription md = getMediaDescription(AUDIO); - if (md == null) return new ArrayList<AudioCodec>(); - - // FIXME: what happens if ptime is missing - int ptime = 20; - try { - String value = md.getAttribute(PTIME); - if (value != null) ptime = Integer.parseInt(value); - } catch (Throwable t) { - Log.w(TAG, "getCodecs(): ignored: " + t); - } - - List<AudioCodec> codecs = new ArrayList<AudioCodec>(); - Vector<AttributeField> v = (Vector<AttributeField>) - md.getAttributeFields(); - for (AttributeField field : v) { - try { - if (RTPMAP.equals(field.getName())) { - AudioCodec codec = parseAudioCodec(field.getValue(), ptime); - if (codec != null) codecs.add(codec); - } - } catch (Throwable t) { - Log.w(TAG, "getCodecs(): ignored: " + t); - } - } - return codecs; - } - - /** - * Gets the media description of the specified type. - * - * @param type the media type; e.g., "AUDIO" - * @return the media description of the specified type - */ - public MediaDescription getMediaDescription(String type) { - MediaDescription[] all = getMediaDescriptions(); - if ((all == null) || (all.length == 0)) return null; - for (MediaDescription md : all) { - String t = md.getMedia().getMedia(); - if (t.equalsIgnoreCase(type)) return md; - } - return null; - } - - /** - * Gets all the media descriptions in this session description. - * - * @return all the media descriptions in this session description - */ - public MediaDescription[] getMediaDescriptions() { - try { - Vector<MediaDescription> descriptions = (Vector<MediaDescription>) - mSessionDescription.getMediaDescriptions(false); - MediaDescription[] all = new MediaDescription[descriptions.size()]; - return descriptions.toArray(all); - } catch (SdpException e) { - Log.e(TAG, "getMediaDescriptions", e); - } - return null; - } - - @Override - public String getType() { - return "sdp"; - } - - @Override - public byte[] getContent() { - return mSessionDescription.toString().getBytes(); - } - - @Override - public String toString() { - return mSessionDescription.toString(); - } -} diff --git a/voip/java/android/net/sip/SessionDescription.aidl b/voip/java/android/net/sip/SessionDescription.aidl deleted file mode 100644 index a120d16..0000000 --- a/voip/java/android/net/sip/SessionDescription.aidl +++ /dev/null @@ -1,19 +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.net.sip; - -parcelable SessionDescription; diff --git a/voip/java/android/net/sip/SessionDescription.java b/voip/java/android/net/sip/SessionDescription.java deleted file mode 100644 index d476f0b..0000000 --- a/voip/java/android/net/sip/SessionDescription.java +++ /dev/null @@ -1,83 +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.net.sip; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Abstract class of a session description. - * @hide - */ -public abstract class SessionDescription implements Parcelable { - /** @hide */ - public static final Parcelable.Creator<SessionDescription> CREATOR = - new Parcelable.Creator<SessionDescription>() { - public SessionDescription createFromParcel(Parcel in) { - return new SessionDescriptionImpl(in); - } - - public SessionDescription[] newArray(int size) { - return new SessionDescriptionImpl[size]; - } - }; - - /** - * Gets the type of the session description; e.g., "SDP". - * - * @return the session description type - */ - public abstract String getType(); - - /** - * Gets the raw content of the session description. - * - * @return the content of the session description - */ - public abstract byte[] getContent(); - - /** @hide */ - public void writeToParcel(Parcel out, int flags) { - out.writeString(getType()); - out.writeByteArray(getContent()); - } - - /** @hide */ - public int describeContents() { - return 0; - } - - private static class SessionDescriptionImpl extends SessionDescription { - private String mType; - private byte[] mContent; - - SessionDescriptionImpl(Parcel in) { - mType = in.readString(); - mContent = in.createByteArray(); - } - - @Override - public String getType() { - return mType; - } - - @Override - public byte[] getContent() { - return mContent; - } - } -} diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java index 0069fe0..2135fcb 100644 --- a/voip/java/android/net/sip/SipAudioCall.java +++ b/voip/java/android/net/sip/SipAudioCall.java @@ -16,120 +16,184 @@ package android.net.sip; +import android.content.Context; +import android.media.AudioManager; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.media.ToneGenerator; +import android.net.Uri; +import android.net.rtp.AudioCodec; import android.net.rtp.AudioGroup; import android.net.rtp.AudioStream; +import android.net.rtp.RtpStream; +import android.net.sip.SimpleSessionDescription.Media; +import android.net.wifi.WifiManager; import android.os.Message; +import android.os.RemoteException; +import android.os.Vibrator; +import android.provider.Settings; +import android.util.Log; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** - * Interface for making audio calls over SIP. - * @hide + * Class that handles an audio call over SIP. */ -public interface SipAudioCall { +/** @hide */ +public class SipAudioCall extends SipSessionAdapter { + private static final String TAG = SipAudioCall.class.getSimpleName(); + private static final boolean RELEASE_SOCKET = true; + private static final boolean DONT_RELEASE_SOCKET = false; + private static final int SESSION_TIMEOUT = 5; // in seconds + /** Listener class for all event callbacks. */ - public interface Listener { + public static class Listener { /** * Called when the call object is ready to make another call. + * The default implementation calls {@link #onChange}. * * @param call the call object that is ready to make another call */ - void onReadyToCall(SipAudioCall call); + public void onReadyToCall(SipAudioCall call) { + onChanged(call); + } /** * Called when a request is sent out to initiate a new call. + * The default implementation calls {@link #onChange}. * * @param call the call object that carries out the audio call */ - void onCalling(SipAudioCall call); + public void onCalling(SipAudioCall call) { + onChanged(call); + } /** * Called when a new call comes in. + * The default implementation calls {@link #onChange}. * * @param call the call object that carries out the audio call * @param caller the SIP profile of the caller */ - void onRinging(SipAudioCall call, SipProfile caller); + public void onRinging(SipAudioCall call, SipProfile caller) { + onChanged(call); + } /** - * Called when a RINGING response is received for the INVITE request sent + * Called when a RINGING response is received for the INVITE request + * sent. The default implementation calls {@link #onChange}. * * @param call the call object that carries out the audio call */ - void onRingingBack(SipAudioCall call); + public void onRingingBack(SipAudioCall call) { + onChanged(call); + } /** * Called when the session is established. + * The default implementation calls {@link #onChange}. * * @param call the call object that carries out the audio call */ - void onCallEstablished(SipAudioCall call); + public void onCallEstablished(SipAudioCall call) { + onChanged(call); + } /** * Called when the session is terminated. + * The default implementation calls {@link #onChange}. * * @param call the call object that carries out the audio call */ - void onCallEnded(SipAudioCall call); + public void onCallEnded(SipAudioCall call) { + onChanged(call); + } /** * Called when the peer is busy during session initialization. + * The default implementation calls {@link #onChange}. * * @param call the call object that carries out the audio call */ - void onCallBusy(SipAudioCall call); + public void onCallBusy(SipAudioCall call) { + onChanged(call); + } /** * Called when the call is on hold. + * The default implementation calls {@link #onChange}. * * @param call the call object that carries out the audio call */ - void onCallHeld(SipAudioCall call); + public void onCallHeld(SipAudioCall call) { + onChanged(call); + } /** - * Called when an error occurs. + * Called when an error occurs. The default implementation is no op. * * @param call the call object that carries out the audio call * @param errorCode error code of this error * @param errorMessage error message * @see SipErrorCode */ - void onError(SipAudioCall call, int errorCode, String errorMessage); + public void onError(SipAudioCall call, int errorCode, + String errorMessage) { + // no-op + } + + /** + * Called when an event occurs and the corresponding callback is not + * overridden. The default implementation is no op. Error events are + * not re-directed to this callback and are handled in {@link #onError}. + */ + public void onChanged(SipAudioCall call) { + // no-op + } } + private Context mContext; + private SipProfile mLocalProfile; + private SipAudioCall.Listener mListener; + private SipSession mSipSession; + + private long mSessionId = System.currentTimeMillis(); + private String mPeerSd; + + private AudioStream mAudioStream; + private AudioGroup mAudioGroup; + + private boolean mInCall = false; + private boolean mMuted = false; + private boolean mHold = false; + + private boolean mRingbackToneEnabled = true; + private boolean mRingtoneEnabled = true; + private Ringtone mRingtone; + private ToneGenerator mRingbackTone; + + private SipProfile mPendingCallRequest; + private WifiManager mWm; + private WifiManager.WifiLock mWifiHighPerfLock; + + private int mErrorCode = SipErrorCode.NO_ERROR; + private String mErrorMessage; + /** - * The adapter class for {@link Listener}. The default implementation of - * all callback methods is no-op. + * Creates a call object with the local SIP profile. + * @param context the context for accessing system services such as + * ringtone, audio, WIFI etc */ - public class Adapter implements Listener { - protected void onChanged(SipAudioCall call) { - } - public void onReadyToCall(SipAudioCall call) { - onChanged(call); - } - public void onCalling(SipAudioCall call) { - onChanged(call); - } - public void onRinging(SipAudioCall call, SipProfile caller) { - onChanged(call); - } - public void onRingingBack(SipAudioCall call) { - onChanged(call); - } - public void onCallEstablished(SipAudioCall call) { - onChanged(call); - } - public void onCallEnded(SipAudioCall call) { - onChanged(call); - } - public void onCallBusy(SipAudioCall call) { - onChanged(call); - } - public void onCallHeld(SipAudioCall call) { - onChanged(call); - } - public void onError(SipAudioCall call, int errorCode, - String errorMessage) { - onChanged(call); - } + public SipAudioCall(Context context, SipProfile localProfile) { + mContext = context; + mLocalProfile = localProfile; + mWm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); } /** @@ -139,7 +203,9 @@ public interface SipAudioCall { * @param listener to listen to the audio call events of this object * @see #setListener(Listener, boolean) */ - void setListener(Listener listener); + public void setListener(SipAudioCall.Listener listener) { + setListener(listener, false); + } /** * Sets the listener to listen to the audio call events. A @@ -150,44 +216,355 @@ public interface SipAudioCall { * @param callbackImmediately set to true if the caller wants to be called * back immediately on the current state */ - void setListener(Listener listener, boolean callbackImmediately); + public void setListener(SipAudioCall.Listener listener, + boolean callbackImmediately) { + mListener = listener; + try { + if ((listener == null) || !callbackImmediately) { + // do nothing + } else if (mErrorCode != SipErrorCode.NO_ERROR) { + listener.onError(this, mErrorCode, mErrorMessage); + } else if (mInCall) { + if (mHold) { + listener.onCallHeld(this); + } else { + listener.onCallEstablished(this); + } + } else { + int state = getState(); + switch (state) { + case SipSession.State.READY_TO_CALL: + listener.onReadyToCall(this); + break; + case SipSession.State.INCOMING_CALL: + listener.onRinging(this, getPeerProfile()); + break; + case SipSession.State.OUTGOING_CALL: + listener.onCalling(this); + break; + case SipSession.State.OUTGOING_CALL_RING_BACK: + listener.onRingingBack(this); + break; + } + } + } catch (Throwable t) { + Log.e(TAG, "setListener()", t); + } + } + + /** + * Checks if the call is established. + * + * @return true if the call is established + */ + public synchronized boolean isInCall() { + return mInCall; + } + + /** + * Checks if the call is on hold. + * + * @return true if the call is on hold + */ + public synchronized boolean isOnHold() { + return mHold; + } /** * Closes this object. This object is not usable after being closed. */ - void close(); + public void close() { + close(true); + } + + private synchronized void close(boolean closeRtp) { + if (closeRtp) stopCall(RELEASE_SOCKET); + stopRingbackTone(); + stopRinging(); + + mInCall = false; + mHold = false; + mSessionId = System.currentTimeMillis(); + mErrorCode = SipErrorCode.NO_ERROR; + mErrorMessage = null; + + if (mSipSession != null) { + mSipSession.setListener(null); + mSipSession = null; + } + } /** - * Initiates an audio call to the specified profile. The attempt will be - * timed out if the call is not established within {@code timeout} seconds - * and {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} - * will be called. + * Gets the local SIP profile. * - * @param callee the SIP profile to make the call to - * @param sipManager the {@link SipManager} object to help make call with - * @param timeout the timeout value in seconds - * @see Listener.onError + * @return the local SIP profile */ - void makeCall(SipProfile callee, SipManager sipManager, int timeout) - throws SipException; + public synchronized SipProfile getLocalProfile() { + return mLocalProfile; + } /** - * Starts the audio for the established call. This method should be called - * after {@link Listener#onCallEstablished} is called. + * Gets the peer's SIP profile. + * + * @return the peer's SIP profile */ - void startAudio(); + public synchronized SipProfile getPeerProfile() { + return (mSipSession == null) ? null : mSipSession.getPeerProfile(); + } + + /** + * Gets the state of the {@link SipSession} that carries this call. + * The value returned must be one of the states in {@link SipSession.State}. + * + * @return the session state + */ + public synchronized int getState() { + if (mSipSession == null) return SipSession.State.READY_TO_CALL; + return mSipSession.getState(); + } + + + /** + * Gets the {@link SipSession} that carries this call. + * + * @return the session object that carries this call + * @hide + */ + public synchronized SipSession getSipSession() { + return mSipSession; + } + + private SipSession.Listener createListener() { + return new SipSession.Listener() { + @Override + public void onCalling(SipSession session) { + Log.d(TAG, "calling... " + session); + Listener listener = mListener; + if (listener != null) { + try { + listener.onCalling(SipAudioCall.this); + } catch (Throwable t) { + Log.i(TAG, "onCalling(): " + t); + } + } + } + + @Override + public void onRingingBack(SipSession session) { + Log.d(TAG, "sip call ringing back: " + session); + if (!mInCall) startRingbackTone(); + Listener listener = mListener; + if (listener != null) { + try { + listener.onRingingBack(SipAudioCall.this); + } catch (Throwable t) { + Log.i(TAG, "onRingingBack(): " + t); + } + } + } + + @Override + public synchronized void onRinging(SipSession session, + SipProfile peerProfile, String sessionDescription) { + if ((mSipSession == null) || !mInCall + || !session.getCallId().equals(mSipSession.getCallId())) { + // should not happen + session.endCall(); + return; + } + + // session changing request + try { + String answer = createAnswer(sessionDescription).encode(); + mSipSession.answerCall(answer, SESSION_TIMEOUT); + } catch (Throwable e) { + Log.e(TAG, "onRinging()", e); + session.endCall(); + } + } + + @Override + public void onCallEstablished(SipSession session, + String sessionDescription) { + stopRingbackTone(); + stopRinging(); + mPeerSd = sessionDescription; + Log.v(TAG, "onCallEstablished()" + mPeerSd); + + Listener listener = mListener; + if (listener != null) { + try { + if (mHold) { + listener.onCallHeld(SipAudioCall.this); + } else { + listener.onCallEstablished(SipAudioCall.this); + } + } catch (Throwable t) { + Log.i(TAG, "onCallEstablished(): " + t); + } + } + } + + @Override + public void onCallEnded(SipSession session) { + Log.d(TAG, "sip call ended: " + session); + Listener listener = mListener; + if (listener != null) { + try { + listener.onCallEnded(SipAudioCall.this); + } catch (Throwable t) { + Log.i(TAG, "onCallEnded(): " + t); + } + } + close(); + } + + @Override + public void onCallBusy(SipSession session) { + Log.d(TAG, "sip call busy: " + session); + Listener listener = mListener; + if (listener != null) { + try { + listener.onCallBusy(SipAudioCall.this); + } catch (Throwable t) { + Log.i(TAG, "onCallBusy(): " + t); + } + } + close(false); + } + + @Override + public void onCallChangeFailed(SipSession session, int errorCode, + String message) { + Log.d(TAG, "sip call change failed: " + message); + mErrorCode = errorCode; + mErrorMessage = message; + Listener listener = mListener; + if (listener != null) { + try { + listener.onError(SipAudioCall.this, mErrorCode, + message); + } catch (Throwable t) { + Log.i(TAG, "onCallBusy(): " + t); + } + } + } + + @Override + public void onError(SipSession session, int errorCode, + String message) { + SipAudioCall.this.onError(errorCode, message); + } + + @Override + public void onRegistering(SipSession session) { + // irrelevant + } + + @Override + public void onRegistrationTimeout(SipSession session) { + // irrelevant + } + + @Override + public void onRegistrationFailed(SipSession session, int errorCode, + String message) { + // irrelevant + } + + @Override + public void onRegistrationDone(SipSession session, int duration) { + // irrelevant + } + }; + } + + private void onError(int errorCode, String message) { + Log.d(TAG, "sip session error: " + + SipErrorCode.toString(errorCode) + ": " + message); + mErrorCode = errorCode; + mErrorMessage = message; + Listener listener = mListener; + if (listener != null) { + try { + listener.onError(this, errorCode, message); + } catch (Throwable t) { + Log.i(TAG, "onError(): " + t); + } + } + synchronized (this) { + if ((errorCode == SipErrorCode.DATA_CONNECTION_LOST) + || !isInCall()) { + close(true); + } + } + } /** * Attaches an incoming call to this call object. * * @param session the session that receives the incoming call * @param sessionDescription the session description of the incoming call + * @throws SipException if the SIP service fails to attach this object to + * the session + */ + public synchronized void attachCall(SipSession session, + String sessionDescription) throws SipException { + mSipSession = session; + mPeerSd = sessionDescription; + Log.v(TAG, "attachCall()" + mPeerSd); + try { + session.setListener(createListener()); + + if (getState() == SipSession.State.INCOMING_CALL) startRinging(); + } catch (Throwable e) { + Log.e(TAG, "attachCall()", e); + throwSipException(e); + } + } + + /** + * Initiates an audio call to the specified profile. The attempt will be + * timed out if the call is not established within {@code timeout} seconds + * and {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} + * will be called. + * + * @param callee the SIP profile to make the call to + * @param sipManager the {@link SipManager} object to help make call with + * @param timeout the timeout value in seconds. Default value (defined by + * SIP protocol) is used if {@code timeout} is zero or negative. + * @see Listener.onError + * @throws SipException if the SIP service fails to create a session for the + * call */ - void attachCall(ISipSession session, String sessionDescription) - throws SipException; + public synchronized void makeCall(SipProfile peerProfile, + SipManager sipManager, int timeout) throws SipException { + SipSession s = mSipSession = sipManager.createSipSession( + mLocalProfile, createListener()); + if (s == null) { + throw new SipException( + "Failed to create SipSession; network available?"); + } + try { + mAudioStream = new AudioStream(InetAddress.getByName(getLocalIp())); + s.makeCall(peerProfile, createOffer().encode(), timeout); + } catch (IOException e) { + throw new SipException("makeCall()", e); + } + } - /** Ends a call. */ - void endCall() throws SipException; + /** + * Ends a call. + * @throws SipException if the SIP service fails to end the call + */ + public synchronized void endCall() throws SipException { + stopRinging(); + stopCall(RELEASE_SOCKET); + mInCall = false; + + // perform the above local ops first and then network op + if (mSipSession != null) mSipSession.endCall(); + } /** * Puts a call on hold. When succeeds, {@link Listener#onCallHeld} is @@ -196,10 +573,19 @@ public interface SipAudioCall { * {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} * will be called. * - * @param timeout the timeout value in seconds + * @param timeout the timeout value in seconds. Default value (defined by + * SIP protocol) is used if {@code timeout} is zero or negative. * @see Listener.onError + * @throws SipException if the SIP service fails to hold the call */ - void holdCall(int timeout) throws SipException; + public synchronized void holdCall(int timeout) throws SipException { + if (mHold) return; + mSipSession.changeCall(createHoldOffer().encode(), timeout); + mHold = true; + + AudioGroup audioGroup = getAudioGroup(); + if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_ON_HOLD); + } /** * Answers a call. The attempt will be timed out if the call is not @@ -207,10 +593,20 @@ public interface SipAudioCall { * {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} * will be called. * - * @param timeout the timeout value in seconds + * @param timeout the timeout value in seconds. Default value (defined by + * SIP protocol) is used if {@code timeout} is zero or negative. * @see Listener.onError + * @throws SipException if the SIP service fails to answer the call */ - void answerCall(int timeout) throws SipException; + public synchronized void answerCall(int timeout) throws SipException { + stopRinging(); + try { + mAudioStream = new AudioStream(InetAddress.getByName(getLocalIp())); + mSipSession.answerCall(createAnswer(mPeerSd).encode(), timeout); + } catch (IOException e) { + throw new SipException("answerCall()", e); + } + } /** * Continues a call that's on hold. When succeeds, @@ -219,45 +615,191 @@ public interface SipAudioCall { * {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} * will be called. * - * @param timeout the timeout value in seconds + * @param timeout the timeout value in seconds. Default value (defined by + * SIP protocol) is used if {@code timeout} is zero or negative. * @see Listener.onError + * @throws SipException if the SIP service fails to unhold the call */ - void continueCall(int timeout) throws SipException; + public synchronized void continueCall(int timeout) throws SipException { + if (!mHold) return; + mSipSession.changeCall(createContinueOffer().encode(), timeout); + mHold = false; + AudioGroup audioGroup = getAudioGroup(); + if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_NORMAL); + } - /** Puts the device to speaker mode. */ - void setSpeakerMode(boolean speakerMode); + private SimpleSessionDescription createOffer() { + SimpleSessionDescription offer = + new SimpleSessionDescription(mSessionId, getLocalIp()); + AudioCodec[] codecs = AudioCodec.getCodecs(); + Media media = offer.newMedia( + "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); + for (AudioCodec codec : AudioCodec.getCodecs()) { + media.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); + } + media.setRtpPayload(127, "telephone-event/8000", "0-15"); + return offer; + } - /** Toggles mute. */ - void toggleMute(); + private SimpleSessionDescription createAnswer(String offerSd) { + SimpleSessionDescription offer = + new SimpleSessionDescription(offerSd); + SimpleSessionDescription answer = + new SimpleSessionDescription(mSessionId, getLocalIp()); + AudioCodec codec = null; + for (Media media : offer.getMedia()) { + if ((codec == null) && (media.getPort() > 0) + && "audio".equals(media.getType()) + && "RTP/AVP".equals(media.getProtocol())) { + // Find the first audio codec we supported. + for (int type : media.getRtpPayloadTypes()) { + codec = AudioCodec.getCodec(type, media.getRtpmap(type), + media.getFmtp(type)); + if (codec != null) { + break; + } + } + if (codec != null) { + Media reply = answer.newMedia( + "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); + reply.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); - /** - * Checks if the call is on hold. - * - * @return true if the call is on hold - */ - boolean isOnHold(); + // Check if DTMF is supported in the same media. + for (int type : media.getRtpPayloadTypes()) { + String rtpmap = media.getRtpmap(type); + if ((type != codec.type) && (rtpmap != null) + && rtpmap.startsWith("telephone-event")) { + reply.setRtpPayload( + type, rtpmap, media.getFmtp(type)); + } + } + + // Handle recvonly and sendonly. + if (media.getAttribute("recvonly") != null) { + answer.setAttribute("sendonly", ""); + } else if(media.getAttribute("sendonly") != null) { + answer.setAttribute("recvonly", ""); + } else if(offer.getAttribute("recvonly") != null) { + answer.setAttribute("sendonly", ""); + } else if(offer.getAttribute("sendonly") != null) { + answer.setAttribute("recvonly", ""); + } + continue; + } + } + // Reject the media. + Media reply = answer.newMedia( + media.getType(), 0, 1, media.getProtocol()); + for (String format : media.getFormats()) { + reply.setFormat(format, null); + } + } + if (codec == null) { + throw new IllegalStateException("Reject SDP: no suitable codecs"); + } + return answer; + } + + private SimpleSessionDescription createHoldOffer() { + SimpleSessionDescription offer = createContinueOffer(); + offer.setAttribute("sendonly", ""); + return offer; + } + + private SimpleSessionDescription createContinueOffer() { + SimpleSessionDescription offer = + new SimpleSessionDescription(mSessionId, getLocalIp()); + Media media = offer.newMedia( + "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); + AudioCodec codec = mAudioStream.getCodec(); + media.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); + int dtmfType = mAudioStream.getDtmfType(); + if (dtmfType != -1) { + media.setRtpPayload(dtmfType, "telephone-event/8000", "0-15"); + } + return offer; + } + + private void grabWifiHighPerfLock() { + /* not available in master yet + if (mWifiHighPerfLock == null) { + Log.v(TAG, "acquire wifi high perf lock"); + mWifiHighPerfLock = ((WifiManager) + mContext.getSystemService(Context.WIFI_SERVICE)) + .createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, TAG); + mWifiHighPerfLock.acquire(); + } + */ + } + + private void releaseWifiHighPerfLock() { + if (mWifiHighPerfLock != null) { + Log.v(TAG, "release wifi high perf lock"); + mWifiHighPerfLock.release(); + mWifiHighPerfLock = null; + } + } + + private boolean isWifiOn() { + return (mWm.getConnectionInfo().getBSSID() == null) ? false : true; + } + + /** Toggles mute. */ + public synchronized void toggleMute() { + AudioGroup audioGroup = getAudioGroup(); + if (audioGroup != null) { + audioGroup.setMode( + mMuted ? AudioGroup.MODE_NORMAL : AudioGroup.MODE_MUTED); + mMuted = !mMuted; + } + } /** * Checks if the call is muted. * * @return true if the call is muted */ - boolean isMuted(); + public synchronized boolean isMuted() { + return mMuted; + } + + /** Puts the device to speaker mode. */ + public synchronized void setSpeakerMode(boolean speakerMode) { + ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE)) + .setSpeakerphoneOn(speakerMode); + } /** - * Sends a DTMF code. + * Sends a DTMF code. According to RFC2833, event 0--9 maps to decimal + * value 0--9, '*' to 10, '#' to 11, event 'A'--'D' to 12--15, and event + * flash to 16. Currently, event flash is not supported. * - * @param code the DTMF code to send + * @param code the DTMF code to send. Value 0 to 15 (inclusive) are valid + * inputs. + * @see http://tools.ietf.org/html/rfc2833 */ - void sendDtmf(int code); + public void sendDtmf(int code) { + sendDtmf(code, null); + } /** - * Sends a DTMF code. + * Sends a DTMF code. According to RFC2833, event 0--9 maps to decimal + * value 0--9, '*' to 10, '#' to 11, event 'A'--'D' to 12--15, and event + * flash to 16. Currently, event flash is not supported. * - * @param code the DTMF code to send + * @param code the DTMF code to send. Value 0 to 15 (inclusive) are valid + * inputs. * @param result the result message to send when done */ - void sendDtmf(int code, Message result); + public synchronized void sendDtmf(int code, Message result) { + AudioGroup audioGroup = getAudioGroup(); + if ((audioGroup != null) && (mSipSession != null) + && (SipSession.State.IN_CALL == getState())) { + Log.v(TAG, "send DTMF: " + code); + audioGroup.sendDtmf(code); + } + if (result != null) result.sendToTarget(); + } /** * Gets the {@link AudioStream} object used in this call. The object @@ -268,8 +810,11 @@ public interface SipAudioCall { * * @return the {@link AudioStream} object or null if the RTP stream has not * yet been set up + * @hide */ - AudioStream getAudioStream(); + public synchronized AudioStream getAudioStream() { + return mAudioStream; + } /** * Gets the {@link AudioGroup} object which the {@link AudioStream} object @@ -283,8 +828,12 @@ public interface SipAudioCall { * @return the {@link AudioGroup} object or null if the RTP stream has not * yet been set up * @see #getAudioStream + * @hide */ - AudioGroup getAudioGroup(); + public synchronized AudioGroup getAudioGroup() { + if (mAudioGroup != null) return mAudioGroup; + return ((mAudioStream == null) ? null : mAudioStream.getGroup()); + } /** * Sets the {@link AudioGroup} object which the {@link AudioStream} object @@ -292,56 +841,214 @@ public interface SipAudioCall { * will be dynamically created when needed. * * @see #getAudioStream + * @hide */ - void setAudioGroup(AudioGroup audioGroup); + public synchronized void setAudioGroup(AudioGroup group) { + if ((mAudioStream != null) && (mAudioStream.getGroup() != null)) { + mAudioStream.join(group); + } + mAudioGroup = group; + } /** - * Checks if the call is established. - * - * @return true if the call is established + * Starts the audio for the established call. This method should be called + * after {@link Listener#onCallEstablished} is called. */ - boolean isInCall(); + public void startAudio() { + try { + startAudioInternal(); + } catch (UnknownHostException e) { + onError(SipErrorCode.PEER_NOT_REACHABLE, e.getMessage()); + } catch (Throwable e) { + onError(SipErrorCode.CLIENT_ERROR, e.getMessage()); + } + } - /** - * Gets the local SIP profile. - * - * @return the local SIP profile - */ - SipProfile getLocalProfile(); + private synchronized void startAudioInternal() throws UnknownHostException { + if (mPeerSd == null) { + Log.v(TAG, "startAudioInternal() mPeerSd = null"); + throw new IllegalStateException("mPeerSd = null"); + } - /** - * Gets the peer's SIP profile. - * - * @return the peer's SIP profile - */ - SipProfile getPeerProfile(); + stopCall(DONT_RELEASE_SOCKET); + mInCall = true; - /** - * Gets the state of the {@link ISipSession} that carries this call. - * The value returned must be one of the states in {@link SipSessionState}. - * - * @return the session state - */ - int getState(); + // Run exact the same logic in createAnswer() to setup mAudioStream. + SimpleSessionDescription offer = + new SimpleSessionDescription(mPeerSd); + AudioStream stream = mAudioStream; + AudioCodec codec = null; + for (Media media : offer.getMedia()) { + if ((codec == null) && (media.getPort() > 0) + && "audio".equals(media.getType()) + && "RTP/AVP".equals(media.getProtocol())) { + // Find the first audio codec we supported. + for (int type : media.getRtpPayloadTypes()) { + codec = AudioCodec.getCodec( + type, media.getRtpmap(type), media.getFmtp(type)); + if (codec != null) { + break; + } + } + + if (codec != null) { + // Associate with the remote host. + String address = media.getAddress(); + if (address == null) { + address = offer.getAddress(); + } + stream.associate(InetAddress.getByName(address), + media.getPort()); + + stream.setDtmfType(-1); + stream.setCodec(codec); + // Check if DTMF is supported in the same media. + for (int type : media.getRtpPayloadTypes()) { + String rtpmap = media.getRtpmap(type); + if ((type != codec.type) && (rtpmap != null) + && rtpmap.startsWith("telephone-event")) { + stream.setDtmfType(type); + } + } + + // Handle recvonly and sendonly. + if (mHold) { + stream.setMode(RtpStream.MODE_NORMAL); + } else if (media.getAttribute("recvonly") != null) { + stream.setMode(RtpStream.MODE_SEND_ONLY); + } else if(media.getAttribute("sendonly") != null) { + stream.setMode(RtpStream.MODE_RECEIVE_ONLY); + } else if(offer.getAttribute("recvonly") != null) { + stream.setMode(RtpStream.MODE_SEND_ONLY); + } else if(offer.getAttribute("sendonly") != null) { + stream.setMode(RtpStream.MODE_RECEIVE_ONLY); + } else { + stream.setMode(RtpStream.MODE_NORMAL); + } + break; + } + } + } + if (codec == null) { + throw new IllegalStateException("Reject SDP: no suitable codecs"); + } + + if (isWifiOn()) grabWifiHighPerfLock(); + + if (!mHold) { + /* The recorder volume will be very low if the device is in + * IN_CALL mode. Therefore, we have to set the mode to NORMAL + * in order to have the normal microphone level. + */ + ((AudioManager) mContext.getSystemService + (Context.AUDIO_SERVICE)) + .setMode(AudioManager.MODE_NORMAL); + } + + // AudioGroup logic: + AudioGroup audioGroup = getAudioGroup(); + if (mHold) { + if (audioGroup != null) { + audioGroup.setMode(AudioGroup.MODE_ON_HOLD); + } + // don't create an AudioGroup here; doing so will fail if + // there's another AudioGroup out there that's active + } else { + if (audioGroup == null) audioGroup = new AudioGroup(); + stream.join(audioGroup); + if (mMuted) { + audioGroup.setMode(AudioGroup.MODE_MUTED); + } else { + audioGroup.setMode(AudioGroup.MODE_NORMAL); + } + } + } + + private void stopCall(boolean releaseSocket) { + Log.d(TAG, "stop audiocall"); + releaseWifiHighPerfLock(); + if (mAudioStream != null) { + mAudioStream.join(null); + + if (releaseSocket) { + mAudioStream.release(); + mAudioStream = null; + } + } + } + + private String getLocalIp() { + return mSipSession.getLocalIp(); + } - /** - * Gets the {@link ISipSession} that carries this call. - * - * @return the session object that carries this call - */ - ISipSession getSipSession(); /** * Enables/disables the ring-back tone. * * @param enabled true to enable; false to disable */ - void setRingbackToneEnabled(boolean enabled); + public synchronized void setRingbackToneEnabled(boolean enabled) { + mRingbackToneEnabled = enabled; + } /** * Enables/disables the ring tone. * * @param enabled true to enable; false to disable */ - void setRingtoneEnabled(boolean enabled); + public synchronized void setRingtoneEnabled(boolean enabled) { + mRingtoneEnabled = enabled; + } + + private void startRingbackTone() { + if (!mRingbackToneEnabled) return; + if (mRingbackTone == null) { + // The volume relative to other sounds in the stream + int toneVolume = 80; + mRingbackTone = new ToneGenerator( + AudioManager.STREAM_VOICE_CALL, toneVolume); + } + mRingbackTone.startTone(ToneGenerator.TONE_CDMA_LOW_PBX_L); + } + + private void stopRingbackTone() { + if (mRingbackTone != null) { + mRingbackTone.stopTone(); + mRingbackTone.release(); + mRingbackTone = null; + } + } + + private void startRinging() { + if (!mRingtoneEnabled) return; + ((Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE)) + .vibrate(new long[] {0, 1000, 1000}, 1); + AudioManager am = (AudioManager) + mContext.getSystemService(Context.AUDIO_SERVICE); + if (am.getStreamVolume(AudioManager.STREAM_RING) > 0) { + String ringtoneUri = + Settings.System.DEFAULT_RINGTONE_URI.toString(); + mRingtone = RingtoneManager.getRingtone(mContext, + Uri.parse(ringtoneUri)); + mRingtone.play(); + } + } + + private void stopRinging() { + ((Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE)) + .cancel(); + if (mRingtone != null) mRingtone.stop(); + } + + private void throwSipException(Throwable throwable) throws SipException { + if (throwable instanceof SipException) { + throw (SipException) throwable; + } else { + throw new SipException("", throwable); + } + } + + private SipProfile getPeerProfile(SipSession session) { + return session.getPeerProfile(); + } } diff --git a/voip/java/android/net/sip/SipAudioCallImpl.java b/voip/java/android/net/sip/SipAudioCallImpl.java deleted file mode 100644 index 5eecc05..0000000 --- a/voip/java/android/net/sip/SipAudioCallImpl.java +++ /dev/null @@ -1,738 +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.net.sip; - -import android.content.Context; -import android.media.AudioManager; -import android.media.Ringtone; -import android.media.RingtoneManager; -import android.media.ToneGenerator; -import android.net.Uri; -import android.net.rtp.AudioCodec; -import android.net.rtp.AudioGroup; -import android.net.rtp.AudioStream; -import android.net.rtp.RtpStream; -import android.net.sip.SimpleSessionDescription.Media; -import android.net.wifi.WifiManager; -import android.os.Message; -import android.os.RemoteException; -import android.os.Vibrator; -import android.provider.Settings; -import android.util.Log; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Class that handles an audio call over SIP. - */ -/** @hide */ -public class SipAudioCallImpl extends SipSessionAdapter - implements SipAudioCall { - private static final String TAG = SipAudioCallImpl.class.getSimpleName(); - private static final boolean RELEASE_SOCKET = true; - private static final boolean DONT_RELEASE_SOCKET = false; - private static final int SESSION_TIMEOUT = 5; // in seconds - - private Context mContext; - private SipProfile mLocalProfile; - private SipAudioCall.Listener mListener; - private ISipSession mSipSession; - - private long mSessionId = System.currentTimeMillis(); - private String mPeerSd; - - private AudioStream mAudioStream; - private AudioGroup mAudioGroup; - - private boolean mInCall = false; - private boolean mMuted = false; - private boolean mHold = false; - - private boolean mRingbackToneEnabled = true; - private boolean mRingtoneEnabled = true; - private Ringtone mRingtone; - private ToneGenerator mRingbackTone; - - private SipProfile mPendingCallRequest; - - private int mErrorCode = SipErrorCode.NO_ERROR; - private String mErrorMessage; - - public SipAudioCallImpl(Context context, SipProfile localProfile) { - mContext = context; - mLocalProfile = localProfile; - } - - public void setListener(SipAudioCall.Listener listener) { - setListener(listener, false); - } - - public void setListener(SipAudioCall.Listener listener, - boolean callbackImmediately) { - mListener = listener; - try { - if ((listener == null) || !callbackImmediately) { - // do nothing - } else if (mErrorCode != SipErrorCode.NO_ERROR) { - listener.onError(this, mErrorCode, mErrorMessage); - } else if (mInCall) { - if (mHold) { - listener.onCallHeld(this); - } else { - listener.onCallEstablished(this); - } - } else { - int state = getState(); - switch (state) { - case SipSessionState.READY_TO_CALL: - listener.onReadyToCall(this); - break; - case SipSessionState.INCOMING_CALL: - listener.onRinging(this, getPeerProfile(mSipSession)); - break; - case SipSessionState.OUTGOING_CALL: - listener.onCalling(this); - break; - case SipSessionState.OUTGOING_CALL_RING_BACK: - listener.onRingingBack(this); - break; - } - } - } catch (Throwable t) { - Log.e(TAG, "setListener()", t); - } - } - - public synchronized boolean isInCall() { - return mInCall; - } - - public synchronized boolean isOnHold() { - return mHold; - } - - public void close() { - close(true); - } - - private synchronized void close(boolean closeRtp) { - if (closeRtp) stopCall(RELEASE_SOCKET); - stopRingbackTone(); - stopRinging(); - - mInCall = false; - mHold = false; - mSessionId = System.currentTimeMillis(); - mErrorCode = SipErrorCode.NO_ERROR; - mErrorMessage = null; - - if (mSipSession != null) { - try { - mSipSession.setListener(null); - } catch (RemoteException e) { - // don't care - } - mSipSession = null; - } - } - - public synchronized SipProfile getLocalProfile() { - return mLocalProfile; - } - - public synchronized SipProfile getPeerProfile() { - try { - return (mSipSession == null) ? null : mSipSession.getPeerProfile(); - } catch (RemoteException e) { - return null; - } - } - - public synchronized int getState() { - if (mSipSession == null) return SipSessionState.READY_TO_CALL; - try { - return mSipSession.getState(); - } catch (RemoteException e) { - return SipSessionState.REMOTE_ERROR; - } - } - - - public synchronized ISipSession getSipSession() { - return mSipSession; - } - - @Override - public void onCalling(ISipSession session) { - Log.d(TAG, "calling... " + session); - Listener listener = mListener; - if (listener != null) { - try { - listener.onCalling(this); - } catch (Throwable t) { - Log.e(TAG, "onCalling()", t); - } - } - } - - @Override - public void onRingingBack(ISipSession session) { - Log.d(TAG, "sip call ringing back: " + session); - if (!mInCall) startRingbackTone(); - Listener listener = mListener; - if (listener != null) { - try { - listener.onRingingBack(this); - } catch (Throwable t) { - Log.e(TAG, "onRingingBack()", t); - } - } - } - - @Override - public synchronized void onRinging(ISipSession session, - SipProfile peerProfile, String sessionDescription) { - try { - if ((mSipSession == null) || !mInCall - || !session.getCallId().equals(mSipSession.getCallId())) { - // should not happen - session.endCall(); - return; - } - - // session changing request - try { - String answer = createAnswer(sessionDescription).encode(); - mSipSession.answerCall(answer, SESSION_TIMEOUT); - } catch (Throwable e) { - Log.e(TAG, "onRinging()", e); - session.endCall(); - } - } catch (RemoteException e) { - Log.e(TAG, "onRinging()", e); - } - } - - @Override - public void onCallEstablished(ISipSession session, - String sessionDescription) { - stopRingbackTone(); - stopRinging(); - mPeerSd = sessionDescription; - Log.v(TAG, "onCallEstablished()" + mPeerSd); - - Listener listener = mListener; - if (listener != null) { - try { - if (mHold) { - listener.onCallHeld(this); - } else { - listener.onCallEstablished(this); - } - } catch (Throwable t) { - Log.e(TAG, "onCallEstablished()", t); - } - } - } - - @Override - public void onCallEnded(ISipSession session) { - Log.d(TAG, "sip call ended: " + session); - Listener listener = mListener; - if (listener != null) { - try { - listener.onCallEnded(this); - } catch (Throwable t) { - Log.e(TAG, "onCallEnded()", t); - } - } - close(); - } - - @Override - public void onCallBusy(ISipSession session) { - Log.d(TAG, "sip call busy: " + session); - Listener listener = mListener; - if (listener != null) { - try { - listener.onCallBusy(this); - } catch (Throwable t) { - Log.e(TAG, "onCallBusy()", t); - } - } - close(false); - } - - @Override - public void onCallChangeFailed(ISipSession session, int errorCode, - String message) { - Log.d(TAG, "sip call change failed: " + message); - mErrorCode = errorCode; - mErrorMessage = message; - Listener listener = mListener; - if (listener != null) { - try { - listener.onError(this, mErrorCode, message); - } catch (Throwable t) { - Log.e(TAG, "onCallBusy()", t); - } - } - } - - @Override - public void onError(ISipSession session, int errorCode, String message) { - Log.d(TAG, "sip session error: " + SipErrorCode.toString(errorCode) - + ": " + message); - mErrorCode = errorCode; - mErrorMessage = message; - Listener listener = mListener; - if (listener != null) { - try { - listener.onError(this, errorCode, message); - } catch (Throwable t) { - Log.e(TAG, "onError()", t); - } - } - synchronized (this) { - if ((errorCode == SipErrorCode.DATA_CONNECTION_LOST) - || !isInCall()) { - close(true); - } - } - } - - public synchronized void attachCall(ISipSession session, - String sessionDescription) throws SipException { - mSipSession = session; - mPeerSd = sessionDescription; - Log.v(TAG, "attachCall()" + mPeerSd); - try { - session.setListener(this); - if (getState() == SipSessionState.INCOMING_CALL) startRinging(); - } catch (Throwable e) { - Log.e(TAG, "attachCall()", e); - throwSipException(e); - } - } - - public synchronized void makeCall(SipProfile peerProfile, - SipManager sipManager, int timeout) throws SipException { - try { - mSipSession = sipManager.createSipSession(mLocalProfile, this); - if (mSipSession == null) { - throw new SipException( - "Failed to create SipSession; network available?"); - } - mAudioStream = new AudioStream(InetAddress.getByName(getLocalIp())); - mSipSession.makeCall(peerProfile, createOffer().encode(), timeout); - } catch (Throwable e) { - if (e instanceof SipException) { - throw (SipException) e; - } else { - throwSipException(e); - } - } - } - - public synchronized void endCall() throws SipException { - try { - stopRinging(); - stopCall(RELEASE_SOCKET); - mInCall = false; - - // perform the above local ops first and then network op - if (mSipSession != null) mSipSession.endCall(); - } catch (Throwable e) { - throwSipException(e); - } - } - - public synchronized void answerCall(int timeout) throws SipException { - try { - stopRinging(); - mAudioStream = new AudioStream(InetAddress.getByName(getLocalIp())); - mSipSession.answerCall(createAnswer(mPeerSd).encode(), timeout); - } catch (Throwable e) { - Log.e(TAG, "answerCall()", e); - throwSipException(e); - } - } - - public synchronized void holdCall(int timeout) throws SipException { - if (mHold) return; - try { - mSipSession.changeCall(createHoldOffer().encode(), timeout); - } catch (Throwable e) { - throwSipException(e); - } - mHold = true; - AudioGroup audioGroup = getAudioGroup(); - if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_ON_HOLD); - } - - public synchronized void continueCall(int timeout) throws SipException { - if (!mHold) return; - try { - mSipSession.changeCall(createContinueOffer().encode(), timeout); - } catch (Throwable e) { - throwSipException(e); - } - mHold = false; - AudioGroup audioGroup = getAudioGroup(); - if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_NORMAL); - } - - private SimpleSessionDescription createOffer() { - SimpleSessionDescription offer = - new SimpleSessionDescription(mSessionId, getLocalIp()); - AudioCodec[] codecs = AudioCodec.getCodecs(); - Media media = offer.newMedia( - "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); - for (AudioCodec codec : AudioCodec.getCodecs()) { - media.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); - } - media.setRtpPayload(127, "telephone-event/8000", "0-15"); - return offer; - } - - private SimpleSessionDescription createAnswer(String offerSd) { - SimpleSessionDescription offer = - new SimpleSessionDescription(offerSd); - SimpleSessionDescription answer = - new SimpleSessionDescription(mSessionId, getLocalIp()); - AudioCodec codec = null; - for (Media media : offer.getMedia()) { - if ((codec == null) && (media.getPort() > 0) - && "audio".equals(media.getType()) - && "RTP/AVP".equals(media.getProtocol())) { - // Find the first audio codec we supported. - for (int type : media.getRtpPayloadTypes()) { - codec = AudioCodec.getCodec(type, media.getRtpmap(type), - media.getFmtp(type)); - if (codec != null) { - break; - } - } - if (codec != null) { - Media reply = answer.newMedia( - "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); - reply.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); - - // Check if DTMF is supported in the same media. - for (int type : media.getRtpPayloadTypes()) { - String rtpmap = media.getRtpmap(type); - if ((type != codec.type) && (rtpmap != null) - && rtpmap.startsWith("telephone-event")) { - reply.setRtpPayload( - type, rtpmap, media.getFmtp(type)); - } - } - - // Handle recvonly and sendonly. - if (media.getAttribute("recvonly") != null) { - answer.setAttribute("sendonly", ""); - } else if(media.getAttribute("sendonly") != null) { - answer.setAttribute("recvonly", ""); - } else if(offer.getAttribute("recvonly") != null) { - answer.setAttribute("sendonly", ""); - } else if(offer.getAttribute("sendonly") != null) { - answer.setAttribute("recvonly", ""); - } - continue; - } - } - // Reject the media. - Media reply = answer.newMedia( - media.getType(), 0, 1, media.getProtocol()); - for (String format : media.getFormats()) { - reply.setFormat(format, null); - } - } - if (codec == null) { - throw new IllegalStateException("Reject SDP: no suitable codecs"); - } - return answer; - } - - private SimpleSessionDescription createHoldOffer() { - SimpleSessionDescription offer = createContinueOffer(); - offer.setAttribute("sendonly", ""); - return offer; - } - - private SimpleSessionDescription createContinueOffer() { - SimpleSessionDescription offer = - new SimpleSessionDescription(mSessionId, getLocalIp()); - Media media = offer.newMedia( - "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); - AudioCodec codec = mAudioStream.getCodec(); - media.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); - int dtmfType = mAudioStream.getDtmfType(); - if (dtmfType != -1) { - media.setRtpPayload(dtmfType, "telephone-event/8000", "0-15"); - } - return offer; - } - - public synchronized void toggleMute() { - AudioGroup audioGroup = getAudioGroup(); - if (audioGroup != null) { - audioGroup.setMode( - mMuted ? AudioGroup.MODE_NORMAL : AudioGroup.MODE_MUTED); - mMuted = !mMuted; - } - } - - public synchronized boolean isMuted() { - return mMuted; - } - - public synchronized void setSpeakerMode(boolean speakerMode) { - ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE)) - .setSpeakerphoneOn(speakerMode); - } - - public void sendDtmf(int code) { - sendDtmf(code, null); - } - - public synchronized void sendDtmf(int code, Message result) { - AudioGroup audioGroup = getAudioGroup(); - if ((audioGroup != null) && (mSipSession != null) - && (SipSessionState.IN_CALL == getState())) { - Log.v(TAG, "send DTMF: " + code); - audioGroup.sendDtmf(code); - } - if (result != null) result.sendToTarget(); - } - - public synchronized AudioStream getAudioStream() { - return mAudioStream; - } - - public synchronized AudioGroup getAudioGroup() { - if (mAudioGroup != null) return mAudioGroup; - return ((mAudioStream == null) ? null : mAudioStream.getGroup()); - } - - public synchronized void setAudioGroup(AudioGroup group) { - if ((mAudioStream != null) && (mAudioStream.getGroup() != null)) { - mAudioStream.join(group); - } - mAudioGroup = group; - } - - public void startAudio() { - try { - startAudioInternal(); - } catch (UnknownHostException e) { - onError(mSipSession, SipErrorCode.PEER_NOT_REACHABLE, - e.getMessage()); - } catch (Throwable e) { - onError(mSipSession, SipErrorCode.CLIENT_ERROR, - e.getMessage()); - } - } - - private synchronized void startAudioInternal() throws UnknownHostException { - if (mPeerSd == null) { - Log.v(TAG, "startAudioInternal() mPeerSd = null"); - throw new IllegalStateException("mPeerSd = null"); - } - - stopCall(DONT_RELEASE_SOCKET); - mInCall = true; - - // Run exact the same logic in createAnswer() to setup mAudioStream. - SimpleSessionDescription offer = - new SimpleSessionDescription(mPeerSd); - AudioStream stream = mAudioStream; - AudioCodec codec = null; - for (Media media : offer.getMedia()) { - if ((codec == null) && (media.getPort() > 0) - && "audio".equals(media.getType()) - && "RTP/AVP".equals(media.getProtocol())) { - // Find the first audio codec we supported. - for (int type : media.getRtpPayloadTypes()) { - codec = AudioCodec.getCodec( - type, media.getRtpmap(type), media.getFmtp(type)); - if (codec != null) { - break; - } - } - - if (codec != null) { - // Associate with the remote host. - String address = media.getAddress(); - if (address == null) { - address = offer.getAddress(); - } - stream.associate(InetAddress.getByName(address), - media.getPort()); - - stream.setDtmfType(-1); - stream.setCodec(codec); - // Check if DTMF is supported in the same media. - for (int type : media.getRtpPayloadTypes()) { - String rtpmap = media.getRtpmap(type); - if ((type != codec.type) && (rtpmap != null) - && rtpmap.startsWith("telephone-event")) { - stream.setDtmfType(type); - } - } - - // Handle recvonly and sendonly. - if (mHold) { - stream.setMode(RtpStream.MODE_NORMAL); - } else if (media.getAttribute("recvonly") != null) { - stream.setMode(RtpStream.MODE_SEND_ONLY); - } else if(media.getAttribute("sendonly") != null) { - stream.setMode(RtpStream.MODE_RECEIVE_ONLY); - } else if(offer.getAttribute("recvonly") != null) { - stream.setMode(RtpStream.MODE_SEND_ONLY); - } else if(offer.getAttribute("sendonly") != null) { - stream.setMode(RtpStream.MODE_RECEIVE_ONLY); - } else { - stream.setMode(RtpStream.MODE_NORMAL); - } - break; - } - } - } - if (codec == null) { - throw new IllegalStateException("Reject SDP: no suitable codecs"); - } - - if (!mHold) { - /* The recorder volume will be very low if the device is in - * IN_CALL mode. Therefore, we have to set the mode to NORMAL - * in order to have the normal microphone level. - */ - ((AudioManager) mContext.getSystemService - (Context.AUDIO_SERVICE)) - .setMode(AudioManager.MODE_NORMAL); - } - - // AudioGroup logic: - AudioGroup audioGroup = getAudioGroup(); - if (mHold) { - if (audioGroup != null) { - audioGroup.setMode(AudioGroup.MODE_ON_HOLD); - } - // don't create an AudioGroup here; doing so will fail if - // there's another AudioGroup out there that's active - } else { - if (audioGroup == null) audioGroup = new AudioGroup(); - mAudioStream.join(audioGroup); - if (mMuted) { - audioGroup.setMode(AudioGroup.MODE_MUTED); - } else { - audioGroup.setMode(AudioGroup.MODE_NORMAL); - } - } - } - - private void stopCall(boolean releaseSocket) { - Log.d(TAG, "stop audiocall"); - if (mAudioStream != null) { - mAudioStream.join(null); - - if (releaseSocket) { - mAudioStream.release(); - mAudioStream = null; - } - } - } - - private String getLocalIp() { - try { - return mSipSession.getLocalIp(); - } catch (RemoteException e) { - throw new IllegalStateException(e); - } - } - - public synchronized void setRingbackToneEnabled(boolean enabled) { - mRingbackToneEnabled = enabled; - } - - public synchronized void setRingtoneEnabled(boolean enabled) { - mRingtoneEnabled = enabled; - } - - private void startRingbackTone() { - if (!mRingbackToneEnabled) return; - if (mRingbackTone == null) { - // The volume relative to other sounds in the stream - int toneVolume = 80; - mRingbackTone = new ToneGenerator( - AudioManager.STREAM_VOICE_CALL, toneVolume); - } - mRingbackTone.startTone(ToneGenerator.TONE_CDMA_LOW_PBX_L); - } - - private void stopRingbackTone() { - if (mRingbackTone != null) { - mRingbackTone.stopTone(); - mRingbackTone.release(); - mRingbackTone = null; - } - } - - private void startRinging() { - if (!mRingtoneEnabled) return; - ((Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE)) - .vibrate(new long[] {0, 1000, 1000}, 1); - AudioManager am = (AudioManager) - mContext.getSystemService(Context.AUDIO_SERVICE); - if (am.getStreamVolume(AudioManager.STREAM_RING) > 0) { - String ringtoneUri = - Settings.System.DEFAULT_RINGTONE_URI.toString(); - mRingtone = RingtoneManager.getRingtone(mContext, - Uri.parse(ringtoneUri)); - mRingtone.play(); - } - } - - private void stopRinging() { - ((Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE)) - .cancel(); - if (mRingtone != null) mRingtone.stop(); - } - - private void throwSipException(Throwable throwable) throws SipException { - if (throwable instanceof SipException) { - throw (SipException) throwable; - } else { - throw new SipException("", throwable); - } - } - - private SipProfile getPeerProfile(ISipSession session) { - try { - return session.getPeerProfile(); - } catch (RemoteException e) { - return null; - } - } -} diff --git a/voip/java/android/net/sip/SipManager.java b/voip/java/android/net/sip/SipManager.java index 31768d7..5976a04 100644 --- a/voip/java/android/net/sip/SipManager.java +++ b/voip/java/android/net/sip/SipManager.java @@ -30,8 +30,9 @@ import java.text.ParseException; * The class provides API for various SIP related tasks. Specifically, the API * allows an application to: * <ul> - * <li>register a {@link SipProfile} to have the background SIP service listen - * to incoming calls and broadcast them with registered command string. See + * <li>open a {@link SipProfile} to get ready for making outbound calls or have + * the background SIP service listen to incoming calls and broadcast them + * with registered command string. See * {@link #open(SipProfile, String, SipRegistrationListener)}, * {@link #open(SipProfile)}, {@link #close}, {@link #isOpened} and * {@link #isRegistered}. It also facilitates handling of the incoming call @@ -40,39 +41,59 @@ import java.text.ParseException; * {@link #getOfferSessionDescription} and {@link #takeAudioCall}.</li> * <li>make/take SIP-based audio calls. See * {@link #makeAudioCall} and {@link #takeAudioCall}.</li> - * <li>register/unregister with a SIP service provider. See + * <li>register/unregister with a SIP service provider manually. See * {@link #register} and {@link #unregister}.</li> - * <li>process SIP events directly with a {@link ISipSession} created by + * <li>process SIP events directly with a {@link SipSession} created by * {@link #createSipSession}.</li> * </ul> * @hide */ public class SipManager { - /** @hide */ - public static final String SIP_INCOMING_CALL_ACTION = + /** + * Action string for the incoming call intent for the Phone app. + * Internal use only. + * @hide + */ + public static final String ACTION_SIP_INCOMING_CALL = "com.android.phone.SIP_INCOMING_CALL"; - /** @hide */ - public static final String SIP_ADD_PHONE_ACTION = + /** + * Action string for the add-phone intent. + * Internal use only. + * @hide + */ + public static final String ACTION_SIP_ADD_PHONE = "com.android.phone.SIP_ADD_PHONE"; - /** @hide */ - public static final String SIP_REMOVE_PHONE_ACTION = + /** + * Action string for the remove-phone intent. + * Internal use only. + * @hide + */ + public static final String ACTION_SIP_REMOVE_PHONE = "com.android.phone.SIP_REMOVE_PHONE"; - /** @hide */ - public static final String LOCAL_URI_KEY = "LOCAL SIPURI"; + /** + * Part of the ACTION_SIP_ADD_PHONE and ACTION_SIP_REMOVE_PHONE intents. + * Internal use only. + * @hide + */ + public static final String EXTRA_LOCAL_URI = "android:localSipUri"; - private static final String CALL_ID_KEY = "CallID"; - private static final String OFFER_SD_KEY = "OfferSD"; + /** Part of the incoming call intent. */ + public static final String EXTRA_CALL_ID = "android:sipCallID"; + + /** Part of the incoming call intent. */ + public static final String EXTRA_OFFER_SD = "android:sipOfferSD"; private ISipService mSipService; + private Context mContext; /** - * Gets a manager instance. Returns null if SIP API is not supported. + * Creates a manager instance. Returns null if SIP API is not supported. * - * @param context application context for checking if SIP API is supported + * @param context application context for creating the manager object * @return the manager instance or null if SIP API is not supported */ - public static SipManager getInstance(Context context) { - return (isApiSupported(context) ? new SipManager() : null); + public static SipManager newInstance(Context context) { + return (isApiSupported(context) ? new SipManager(context) : null); } /** @@ -80,7 +101,7 @@ public class SipManager { */ public static boolean isApiSupported(Context context) { return true; - /* + /* TODO: uncomment this before ship return context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_SIP); */ @@ -91,7 +112,7 @@ public class SipManager { */ public static boolean isVoipSupported(Context context) { return true; - /* + /* TODO: uncomment this before ship return context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_SIP_VOIP) && isApiSupported(context); */ @@ -105,23 +126,21 @@ public class SipManager { com.android.internal.R.bool.config_sip_wifi_only); } - private SipManager() { + private SipManager(Context context) { + mContext = context; createSipService(); } private void createSipService() { - if (mSipService != null) return; IBinder b = ServiceManager.getService(Context.SIP_SERVICE); mSipService = ISipService.Stub.asInterface(b); } /** - * Opens the profile for making calls and/or receiving calls. Subsequent - * SIP calls can be made through the default phone UI. The caller may also - * make subsequent calls through {@link #makeAudioCall}. - * If the receiving-call option is enabled in the profile, the SIP service - * will register the profile to the corresponding server periodically in - * order to receive calls from the server. + * Opens the profile for making calls. The caller may make subsequent calls + * through {@link #makeAudioCall}. If one also wants to receive calls on the + * profile, use {@link #open(SipProfile, String, SipRegistrationListener)} + * instead. * * @param localProfile the SIP profile to make calls from * @throws SipException if the profile contains incorrect settings or @@ -136,12 +155,11 @@ public class SipManager { } /** - * Opens the profile for making calls and/or receiving calls. Subsequent - * SIP calls can be made through the default phone UI. The caller may also - * make subsequent calls through {@link #makeAudioCall}. - * If the receiving-call option is enabled in the profile, the SIP service - * will register the profile to the corresponding server periodically in - * order to receive calls from the server. + * Opens the profile for making calls and/or receiving calls. The caller may + * make subsequent calls through {@link #makeAudioCall}. If the + * auto-registration option is enabled in the profile, the SIP service + * will register the profile to the corresponding SIP provider periodically + * in order to receive calls from the provider. * * @param localProfile the SIP profile to receive incoming calls for * @param incomingCallBroadcastAction the action to be broadcast when an @@ -195,7 +213,8 @@ public class SipManager { } /** - * Checks if the specified profile is enabled to receive calls. + * Checks if the specified profile is opened in the SIP service for + * making and/or receiving calls. * * @param localProfileUri the URI of the profile in question * @return true if the profile is enabled to receive calls @@ -210,11 +229,16 @@ public class SipManager { } /** - * Checks if the specified profile is registered to the server for - * receiving calls. + * Checks if the SIP service has successfully registered the profile to the + * SIP provider (specified in the profile) for receiving calls. Returning + * true from this method also implies the profile is opened + * ({@link #isOpened}). * * @param localProfileUri the URI of the profile in question - * @return true if the profile is registered to the server + * @return true if the profile is registered to the SIP provider; false if + * the profile has not been opened in the SIP service or the SIP + * service has not yet successfully registered the profile to the SIP + * provider * @throws SipException if calling the SIP service results in an error */ public boolean isRegistered(String localProfileUri) throws SipException { @@ -231,7 +255,6 @@ public class SipManager { * {@code SipAudioCall.Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} * will be called. * - * @param context context to create a {@link SipAudioCall} object * @param localProfile the SIP profile to make the call from * @param peerProfile the SIP profile to make the call to * @param listener to listen to the call events from {@link SipAudioCall}; @@ -241,10 +264,10 @@ public class SipManager { * @throws SipException if calling the SIP service results in an error * @see SipAudioCall.Listener.onError */ - public SipAudioCall makeAudioCall(Context context, SipProfile localProfile, + public SipAudioCall makeAudioCall(SipProfile localProfile, SipProfile peerProfile, SipAudioCall.Listener listener, int timeout) throws SipException { - SipAudioCall call = new SipAudioCallImpl(context, localProfile); + SipAudioCall call = new SipAudioCall(mContext, localProfile); call.setListener(listener); call.makeCall(peerProfile, this, timeout); return call; @@ -257,7 +280,6 @@ public class SipManager { * {@code SipAudioCall.Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} * will be called. * - * @param context context to create a {@link SipAudioCall} object * @param localProfileUri URI of the SIP profile to make the call from * @param peerProfileUri URI of the SIP profile to make the call to * @param listener to listen to the call events from {@link SipAudioCall}; @@ -267,11 +289,11 @@ public class SipManager { * @throws SipException if calling the SIP service results in an error * @see SipAudioCall.Listener.onError */ - public SipAudioCall makeAudioCall(Context context, String localProfileUri, + public SipAudioCall makeAudioCall(String localProfileUri, String peerProfileUri, SipAudioCall.Listener listener, int timeout) throws SipException { try { - return makeAudioCall(context, + return makeAudioCall( new SipProfile.Builder(localProfileUri).build(), new SipProfile.Builder(peerProfileUri).build(), listener, timeout); @@ -281,15 +303,14 @@ public class SipManager { } /** - * The method calls {@code takeAudioCall(context, incomingCallIntent, + * The method calls {@code takeAudioCall(incomingCallIntent, * listener, true}. * - * @see #takeAudioCall(Context, Intent, SipAudioCall.Listener, boolean) + * @see #takeAudioCall(Intent, SipAudioCall.Listener, boolean) */ - public SipAudioCall takeAudioCall(Context context, - Intent incomingCallIntent, SipAudioCall.Listener listener) - throws SipException { - return takeAudioCall(context, incomingCallIntent, listener, true); + public SipAudioCall takeAudioCall(Intent incomingCallIntent, + SipAudioCall.Listener listener) throws SipException { + return takeAudioCall(incomingCallIntent, listener, true); } /** @@ -298,16 +319,15 @@ public class SipManager { * {@link SipAudioCall.Listener#onRinging} * callback. * - * @param context context to create a {@link SipAudioCall} object * @param incomingCallIntent the incoming call broadcast intent * @param listener to listen to the call events from {@link SipAudioCall}; * can be null * @return a {@link SipAudioCall} object * @throws SipException if calling the SIP service results in an error */ - public SipAudioCall takeAudioCall(Context context, - Intent incomingCallIntent, SipAudioCall.Listener listener, - boolean ringtoneEnabled) throws SipException { + public SipAudioCall takeAudioCall(Intent incomingCallIntent, + SipAudioCall.Listener listener, boolean ringtoneEnabled) + throws SipException { if (incomingCallIntent == null) return null; String callId = getCallId(incomingCallIntent); @@ -324,10 +344,10 @@ public class SipManager { try { ISipSession session = mSipService.getPendingSession(callId); if (session == null) return null; - SipAudioCall call = new SipAudioCallImpl( - context, session.getLocalProfile()); + SipAudioCall call = new SipAudioCall( + mContext, session.getLocalProfile()); call.setRingtoneEnabled(ringtoneEnabled); - call.attachCall(session, offerSd); + call.attachCall(new SipSession(session), offerSd); call.setListener(listener); return call; } catch (Throwable t) { @@ -355,7 +375,7 @@ public class SipManager { * @return the call ID or null if the intent does not contain it */ public static String getCallId(Intent incomingCallIntent) { - return incomingCallIntent.getStringExtra(CALL_ID_KEY); + return incomingCallIntent.getStringExtra(EXTRA_CALL_ID); } /** @@ -367,30 +387,30 @@ public class SipManager { * have it */ public static String getOfferSessionDescription(Intent incomingCallIntent) { - return incomingCallIntent.getStringExtra(OFFER_SD_KEY); + return incomingCallIntent.getStringExtra(EXTRA_OFFER_SD); } /** * Creates an incoming call broadcast intent. * - * @param action the action string to broadcast * @param callId the call ID of the incoming call * @param sessionDescription the session description of the incoming call * @return the incoming call intent * @hide */ - public static Intent createIncomingCallBroadcast(String action, - String callId, String sessionDescription) { - Intent intent = new Intent(action); - intent.putExtra(CALL_ID_KEY, callId); - intent.putExtra(OFFER_SD_KEY, sessionDescription); + public static Intent createIncomingCallBroadcast(String callId, + String sessionDescription) { + Intent intent = new Intent(); + intent.putExtra(EXTRA_CALL_ID, callId); + intent.putExtra(EXTRA_OFFER_SD, sessionDescription); return intent; } /** - * Registers the profile to the corresponding server for receiving calls. - * {@link #open} is still needed to be called at least once in order for - * the SIP service to broadcast an intent when an incoming call is received. + * Manually registers the profile to the corresponding SIP provider for + * receiving calls. {@link #open(SipProfile, String, SipRegistrationListener)} + * is still needed to be called at least once in order for the SIP service + * to broadcast an intent when an incoming call is received. * * @param localProfile the SIP profile to register with * @param expiryTime registration expiration time (in seconds) @@ -409,8 +429,10 @@ public class SipManager { } /** - * Unregisters the profile from the corresponding server for not receiving - * further calls. + * Manually unregisters the profile from the corresponding SIP provider for + * stop receiving further calls. This may interference with the auto + * registration process in the SIP service if the auto-registration option + * in the profile is enabled. * * @param localProfile the SIP profile to register with * @param listener to listen to the registration events @@ -460,10 +482,11 @@ public class SipManager { * @param localProfile the SIP profile the session is associated with * @param listener to listen to SIP session events */ - public ISipSession createSipSession(SipProfile localProfile, - ISipSessionListener listener) throws SipException { + public SipSession createSipSession(SipProfile localProfile, + SipSession.Listener listener) throws SipException { try { - return mSipService.createSession(localProfile, listener); + ISipSession s = mSipService.createSession(localProfile, null); + return new SipSession(s, listener); } catch (RemoteException e) { throw new SipException("createSipSession()", e); } diff --git a/voip/java/android/net/sip/SipProfile.java b/voip/java/android/net/sip/SipProfile.java index 88bfba9..6d5cb3c 100644 --- a/voip/java/android/net/sip/SipProfile.java +++ b/voip/java/android/net/sip/SipProfile.java @@ -48,7 +48,6 @@ public class SipProfile implements Parcelable, Serializable, Cloneable { private boolean mAutoRegistration = true; private transient int mCallingUid = 0; - /** @hide */ public static final Parcelable.Creator<SipProfile> CREATOR = new Parcelable.Creator<SipProfile>() { public SipProfile createFromParcel(Parcel in) { @@ -287,7 +286,7 @@ public class SipProfile implements Parcelable, Serializable, Cloneable { mCallingUid = in.readInt(); } - /** @hide */ + @Override public void writeToParcel(Parcel out, int flags) { out.writeSerializable(mAddress); out.writeString(mProxyAddress); @@ -300,7 +299,7 @@ public class SipProfile implements Parcelable, Serializable, Cloneable { out.writeInt(mCallingUid); } - /** @hide */ + @Override public int describeContents() { return 0; } diff --git a/voip/java/android/net/sip/SipSession.java b/voip/java/android/net/sip/SipSession.java new file mode 100644 index 0000000..0cc7206 --- /dev/null +++ b/voip/java/android/net/sip/SipSession.java @@ -0,0 +1,531 @@ +/* + * 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.sip; + +import android.os.RemoteException; +import android.util.Log; + +/** + * A SIP session that is associated with a SIP dialog or a standalone + * transaction not within a dialog. + * @hide + */ +public final class SipSession { + private static final String TAG = "SipSession"; + + /** + * Defines {@link SipSession} states. + * @hide + */ + public static class State { + /** When session is ready to initiate a call or transaction. */ + public static final int READY_TO_CALL = 0; + + /** When the registration request is sent out. */ + public static final int REGISTERING = 1; + + /** When the unregistration request is sent out. */ + public static final int DEREGISTERING = 2; + + /** When an INVITE request is received. */ + public static final int INCOMING_CALL = 3; + + /** When an OK response is sent for the INVITE request received. */ + public static final int INCOMING_CALL_ANSWERING = 4; + + /** When an INVITE request is sent. */ + public static final int OUTGOING_CALL = 5; + + /** When a RINGING response is received for the INVITE request sent. */ + public static final int OUTGOING_CALL_RING_BACK = 6; + + /** When a CANCEL request is sent for the INVITE request sent. */ + public static final int OUTGOING_CALL_CANCELING = 7; + + /** When a call is established. */ + public static final int IN_CALL = 8; + + /** When an OPTIONS request is sent. */ + public static final int PINGING = 9; + + /** Not defined. */ + public static final int NOT_DEFINED = 101; + + /** + * Converts the state to string. + */ + public static String toString(int state) { + switch (state) { + case READY_TO_CALL: + return "READY_TO_CALL"; + case REGISTERING: + return "REGISTERING"; + case DEREGISTERING: + return "DEREGISTERING"; + case INCOMING_CALL: + return "INCOMING_CALL"; + case INCOMING_CALL_ANSWERING: + return "INCOMING_CALL_ANSWERING"; + case OUTGOING_CALL: + return "OUTGOING_CALL"; + case OUTGOING_CALL_RING_BACK: + return "OUTGOING_CALL_RING_BACK"; + case OUTGOING_CALL_CANCELING: + return "OUTGOING_CALL_CANCELING"; + case IN_CALL: + return "IN_CALL"; + case PINGING: + return "PINGING"; + default: + return "NOT_DEFINED"; + } + } + + private State() { + } + } + + /** + * Listener class that listens to {@link SipSession} events. + * @hide + */ + public static class Listener { + /** + * Called when an INVITE request is sent to initiate a new call. + * + * @param session the session object that carries out the transaction + */ + public void onCalling(SipSession session) { + } + + /** + * Called when an INVITE request is received. + * + * @param session the session object that carries out the transaction + * @param caller the SIP profile of the caller + * @param sessionDescription the caller's session description + */ + public void onRinging(SipSession session, SipProfile caller, + String sessionDescription) { + } + + /** + * Called when a RINGING response is received for the INVITE request sent + * + * @param session the session object that carries out the transaction + */ + public void onRingingBack(SipSession session) { + } + + /** + * Called when the session is established. + * + * @param session the session object that is associated with the dialog + * @param sessionDescription the peer's session description + */ + public void onCallEstablished(SipSession session, + String sessionDescription) { + } + + /** + * Called when the session is terminated. + * + * @param session the session object that is associated with the dialog + */ + public void onCallEnded(SipSession session) { + } + + /** + * Called when the peer is busy during session initialization. + * + * @param session the session object that carries out the transaction + */ + public void onCallBusy(SipSession session) { + } + + /** + * Called when an error occurs during session initialization and + * termination. + * + * @param session the session object that carries out the transaction + * @param errorCode error code defined in {@link SipErrorCode} + * @param errorMessage error message + */ + public void onError(SipSession session, int errorCode, + String errorMessage) { + } + + /** + * Called when an error occurs during session modification negotiation. + * + * @param session the session object that carries out the transaction + * @param errorCode error code defined in {@link SipErrorCode} + * @param errorMessage error message + */ + public void onCallChangeFailed(SipSession session, int errorCode, + String errorMessage) { + } + + /** + * Called when a registration request is sent. + * + * @param session the session object that carries out the transaction + */ + public void onRegistering(SipSession session) { + } + + /** + * Called when registration is successfully done. + * + * @param session the session object that carries out the transaction + * @param duration duration in second before the registration expires + */ + public void onRegistrationDone(SipSession session, int duration) { + } + + /** + * Called when the registration fails. + * + * @param session the session object that carries out the transaction + * @param errorCode error code defined in {@link SipErrorCode} + * @param errorMessage error message + */ + public void onRegistrationFailed(SipSession session, int errorCode, + String errorMessage) { + } + + /** + * Called when the registration gets timed out. + * + * @param session the session object that carries out the transaction + */ + public void onRegistrationTimeout(SipSession session) { + } + } + + private final ISipSession mSession; + private Listener mListener; + + SipSession(ISipSession realSession) { + mSession = realSession; + if (realSession != null) { + try { + realSession.setListener(createListener()); + } catch (RemoteException e) { + Log.e(TAG, "SipSession.setListener(): " + e); + } + } + } + + SipSession(ISipSession realSession, Listener listener) { + this(realSession); + setListener(listener); + } + + /** + * Gets the IP address of the local host on which this SIP session runs. + * + * @return the IP address of the local host + */ + public String getLocalIp() { + try { + return mSession.getLocalIp(); + } catch (RemoteException e) { + Log.e(TAG, "getLocalIp(): " + e); + return "127.0.0.1"; + } + } + + /** + * Gets the SIP profile that this session is associated with. + * + * @return the SIP profile that this session is associated with + */ + public SipProfile getLocalProfile() { + try { + return mSession.getLocalProfile(); + } catch (RemoteException e) { + Log.e(TAG, "getLocalProfile(): " + e); + return null; + } + } + + /** + * Gets the SIP profile that this session is connected to. Only available + * when the session is associated with a SIP dialog. + * + * @return the SIP profile that this session is connected to + */ + public SipProfile getPeerProfile() { + try { + return mSession.getPeerProfile(); + } catch (RemoteException e) { + Log.e(TAG, "getPeerProfile(): " + e); + return null; + } + } + + /** + * Gets the session state. The value returned must be one of the states in + * {@link SipSessionState}. + * + * @return the session state + */ + public int getState() { + try { + return mSession.getState(); + } catch (RemoteException e) { + Log.e(TAG, "getState(): " + e); + return State.NOT_DEFINED; + } + } + + /** + * Checks if the session is in a call. + * + * @return true if the session is in a call + */ + public boolean isInCall() { + try { + return mSession.isInCall(); + } catch (RemoteException e) { + Log.e(TAG, "isInCall(): " + e); + return false; + } + } + + /** + * Gets the call ID of the session. + * + * @return the call ID + */ + public String getCallId() { + try { + return mSession.getCallId(); + } catch (RemoteException e) { + Log.e(TAG, "getCallId(): " + e); + return null; + } + } + + + /** + * Sets the listener to listen to the session events. A {@code SipSession} + * can only hold one listener at a time. Subsequent calls to this method + * override the previous listener. + * + * @param listener to listen to the session events of this object + */ + public void setListener(Listener listener) { + mListener = listener; + } + + + /** + * Performs registration to the server specified by the associated local + * profile. The session listener is called back upon success or failure of + * registration. The method is only valid to call when the session state is + * in {@link SipSessionState#READY_TO_CALL}. + * + * @param duration duration in second before the registration expires + * @see Listener + */ + public void register(int duration) { + try { + mSession.register(duration); + } catch (RemoteException e) { + Log.e(TAG, "register(): " + e); + } + } + + /** + * Performs unregistration to the server specified by the associated local + * profile. Unregistration is technically the same as registration with zero + * expiration duration. The session listener is called back upon success or + * failure of unregistration. The method is only valid to call when the + * session state is in {@link SipSessionState#READY_TO_CALL}. + * + * @see Listener + */ + public void unregister() { + try { + mSession.unregister(); + } catch (RemoteException e) { + Log.e(TAG, "unregister(): " + e); + } + } + + /** + * Initiates a call to the specified profile. The session listener is called + * back upon defined session events. The method is only valid to call when + * the session state is in {@link SipSessionState#READY_TO_CALL}. + * + * @param callee the SIP profile to make the call to + * @param sessionDescription the session description of this call + * @param timeout the session will be timed out if the call is not + * established within {@code timeout} seconds. Default value (defined + * by SIP protocol) is used if {@code timeout} is zero or negative. + * @see Listener + */ + public void makeCall(SipProfile callee, String sessionDescription, + int timeout) { + try { + mSession.makeCall(callee, sessionDescription, timeout); + } catch (RemoteException e) { + Log.e(TAG, "makeCall(): " + e); + } + } + + /** + * Answers an incoming call with the specified session description. The + * method is only valid to call when the session state is in + * {@link SipSessionState#INCOMING_CALL}. + * + * @param sessionDescription the session description to answer this call + * @param timeout the session will be timed out if the call is not + * established within {@code timeout} seconds. Default value (defined + * by SIP protocol) is used if {@code timeout} is zero or negative. + */ + public void answerCall(String sessionDescription, int timeout) { + try { + mSession.answerCall(sessionDescription, timeout); + } catch (RemoteException e) { + Log.e(TAG, "answerCall(): " + e); + } + } + + /** + * Ends an established call, terminates an outgoing call or rejects an + * incoming call. The method is only valid to call when the session state is + * in {@link SipSessionState#IN_CALL}, + * {@link SipSessionState#INCOMING_CALL}, + * {@link SipSessionState#OUTGOING_CALL} or + * {@link SipSessionState#OUTGOING_CALL_RING_BACK}. + */ + public void endCall() { + try { + mSession.endCall(); + } catch (RemoteException e) { + Log.e(TAG, "endCall(): " + e); + } + } + + /** + * Changes the session description during a call. The method is only valid + * to call when the session state is in {@link SipSessionState#IN_CALL}. + * + * @param sessionDescription the new session description + * @param timeout the session will be timed out if the call is not + * established within {@code timeout} seconds. Default value (defined + * by SIP protocol) is used if {@code timeout} is zero or negative. + */ + public void changeCall(String sessionDescription, int timeout) { + try { + mSession.changeCall(sessionDescription, timeout); + } catch (RemoteException e) { + Log.e(TAG, "changeCall(): " + e); + } + } + + ISipSession getRealSession() { + return mSession; + } + + private ISipSessionListener createListener() { + return new ISipSessionListener.Stub() { + public void onCalling(ISipSession session) { + if (mListener != null) { + mListener.onCalling(SipSession.this); + } + } + + public void onRinging(ISipSession session, SipProfile caller, + String sessionDescription) { + if (mListener != null) { + mListener.onRinging(SipSession.this, caller, + sessionDescription); + } + } + + public void onRingingBack(ISipSession session) { + if (mListener != null) { + mListener.onRingingBack(SipSession.this); + } + } + + public void onCallEstablished(ISipSession session, + String sessionDescription) { + if (mListener != null) { + mListener.onCallEstablished(SipSession.this, + sessionDescription); + } + } + + public void onCallEnded(ISipSession session) { + if (mListener != null) { + mListener.onCallEnded(SipSession.this); + } + } + + public void onCallBusy(ISipSession session) { + if (mListener != null) { + mListener.onCallBusy(SipSession.this); + } + } + + public void onCallChangeFailed(ISipSession session, int errorCode, + String message) { + if (mListener != null) { + mListener.onCallChangeFailed(SipSession.this, errorCode, + message); + } + } + + public void onError(ISipSession session, int errorCode, String message) { + if (mListener != null) { + mListener.onError(SipSession.this, errorCode, message); + } + } + + public void onRegistering(ISipSession session) { + if (mListener != null) { + mListener.onRegistering(SipSession.this); + } + } + + public void onRegistrationDone(ISipSession session, int duration) { + if (mListener != null) { + mListener.onRegistrationDone(SipSession.this, duration); + } + } + + public void onRegistrationFailed(ISipSession session, int errorCode, + String message) { + if (mListener != null) { + mListener.onRegistrationFailed(SipSession.this, errorCode, + message); + } + } + + public void onRegistrationTimeout(ISipSession session) { + if (mListener != null) { + mListener.onRegistrationTimeout(SipSession.this); + } + } + }; + } +} diff --git a/voip/java/android/net/sip/SipSessionState.java b/voip/java/android/net/sip/SipSessionState.java deleted file mode 100644 index 31e9d3f..0000000 --- a/voip/java/android/net/sip/SipSessionState.java +++ /dev/null @@ -1,94 +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.net.sip; - -/** - * Defines {@link ISipSession} states. - * @hide - */ -public class SipSessionState { - /** When session is ready to initiate a call or transaction. */ - public static final int READY_TO_CALL = 0; - - /** When the registration request is sent out. */ - public static final int REGISTERING = 1; - - /** When the unregistration request is sent out. */ - public static final int DEREGISTERING = 2; - - /** When an INVITE request is received. */ - public static final int INCOMING_CALL = 3; - - /** When an OK response is sent for the INVITE request received. */ - public static final int INCOMING_CALL_ANSWERING = 4; - - /** When an INVITE request is sent. */ - public static final int OUTGOING_CALL = 5; - - /** When a RINGING response is received for the INVITE request sent. */ - public static final int OUTGOING_CALL_RING_BACK = 6; - - /** When a CANCEL request is sent for the INVITE request sent. */ - public static final int OUTGOING_CALL_CANCELING = 7; - - /** When a call is established. */ - public static final int IN_CALL = 8; - - /** Some error occurs when making a remote call to {@link ISipSession}. */ - public static final int REMOTE_ERROR = 9; - - /** When an OPTIONS request is sent. */ - public static final int PINGING = 10; - - /** Not defined. */ - public static final int NOT_DEFINED = 101; - - /** - * Converts the state to string. - */ - public static String toString(int state) { - switch (state) { - case READY_TO_CALL: - return "READY_TO_CALL"; - case REGISTERING: - return "REGISTERING"; - case DEREGISTERING: - return "DEREGISTERING"; - case INCOMING_CALL: - return "INCOMING_CALL"; - case INCOMING_CALL_ANSWERING: - return "INCOMING_CALL_ANSWERING"; - case OUTGOING_CALL: - return "OUTGOING_CALL"; - case OUTGOING_CALL_RING_BACK: - return "OUTGOING_CALL_RING_BACK"; - case OUTGOING_CALL_CANCELING: - return "OUTGOING_CALL_CANCELING"; - case IN_CALL: - return "IN_CALL"; - case REMOTE_ERROR: - return "REMOTE_ERROR"; - case PINGING: - return "PINGING"; - default: - return "NOT_DEFINED"; - } - } - - private SipSessionState() { - } -} diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index e73bca0..f760d27 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -105,5 +105,9 @@ interface IWifiManager void saveNetwork(in WifiConfiguration wifiConfig); void forgetNetwork(int networkId); + + void startWpsPbc(String bssid); + + void startWpsPin(String bssid, int apPin); } diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java index dfa9f75..7ea4872 100644 --- a/wifi/java/android/net/wifi/WifiConfigStore.java +++ b/wifi/java/android/net/wifi/WifiConfigStore.java @@ -23,6 +23,7 @@ import android.net.DhcpInfo; import android.net.wifi.WifiConfiguration.IpAssignment; import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiConfiguration.Status; +import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; import android.os.Environment; import android.text.TextUtils; import android.util.Log; @@ -95,9 +96,9 @@ class WifiConfigStore { * and enable all stored networks in supplicant. */ static void initialize(Context context) { - Log.d(TAG, "Updating config and enabling all networks"); + Log.d(TAG, "Loading config and enabling all networks"); sContext = context; - updateConfiguredNetworks(); + loadConfiguredNetworks(); enableAllNetworks(); } @@ -150,7 +151,7 @@ class WifiConfigStore { static void selectNetwork(WifiConfiguration config) { if (config != null) { int netId = addOrUpdateNetworkNative(config); - if (netId != -1) { + if (netId != INVALID_NETWORK_ID) { selectNetwork(netId); } else { Log.e(TAG, "Failed to update network " + config); @@ -174,7 +175,7 @@ class WifiConfigStore { if (sLastPriority == -1 || sLastPriority > 1000000) { synchronized (sConfiguredNetworks) { for(WifiConfiguration config : sConfiguredNetworks.values()) { - if (config.networkId != -1) { + if (config.networkId != INVALID_NETWORK_ID) { config.priority = 0; addOrUpdateNetworkNative(config); } @@ -204,10 +205,10 @@ class WifiConfigStore { * @param config WifiConfiguration to be saved */ static void saveNetwork(WifiConfiguration config) { - boolean newNetwork = (config.networkId == -1); + boolean newNetwork = (config.networkId == INVALID_NETWORK_ID); int netId = addOrUpdateNetworkNative(config); /* enable a new network */ - if (newNetwork && netId >= 0) { + if (newNetwork && netId != INVALID_NETWORK_ID) { WifiNative.enableNetworkCommand(netId, false); synchronized (sConfiguredNetworks) { sConfiguredNetworks.get(netId).status = Status.ENABLED; @@ -288,13 +289,7 @@ class WifiConfigStore { } if (disableOthers) { - synchronized (sConfiguredNetworks) { - for(WifiConfiguration config : sConfiguredNetworks.values()) { - if(config != null && config.networkId != netId) { - config.status = Status.DISABLED; - } - } - } + markAllNetworksDisabledExcept(netId); } return ret; } @@ -321,6 +316,32 @@ class WifiConfigStore { } /** + * Start WPS pin method configuration + */ + static boolean startWpsPin(String bssid, int apPin) { + if (WifiNative.startWpsPinCommand(bssid, apPin)) { + /* WPS leaves all networks disabled */ + markAllNetworksDisabled(); + return true; + } + Log.e(TAG, "Failed to start WPS pin method configuration"); + return false; + } + + /** + * Start WPS push button configuration + */ + static boolean startWpsPbc(String bssid) { + if (WifiNative.startWpsPbcCommand(bssid)) { + /* WPS leaves all networks disabled */ + markAllNetworksDisabled(); + return true; + } + Log.e(TAG, "Failed to start WPS push button configuration"); + return false; + } + + /** * Fetch the IP configuration for a given network id */ static DhcpInfo getIpConfiguration(int netId) { @@ -350,7 +371,7 @@ class WifiConfigStore { sContext.sendBroadcast(intent); } - private static void updateConfiguredNetworks() { + static void loadConfiguredNetworks() { String listStr = WifiNative.listNetworksCommand(); sLastPriority = 0; @@ -391,6 +412,22 @@ class WifiConfigStore { } } readIpConfigurations(); + sendConfigChangeBroadcast(); + } + + /* Mark all networks except specified netId as disabled */ + private static void markAllNetworksDisabledExcept(int netId) { + synchronized (sConfiguredNetworks) { + for(WifiConfiguration config : sConfiguredNetworks.values()) { + if(config != null && config.networkId != netId) { + config.status = Status.DISABLED; + } + } + } + } + + private static void markAllNetworksDisabled() { + markAllNetworksDisabledExcept(INVALID_NETWORK_ID); } private static void writeIpConfigurations() { @@ -513,20 +550,20 @@ class WifiConfigStore { private static int addOrUpdateNetworkNative(WifiConfiguration config) { /* - * If the supplied networkId is -1, we create a new empty + * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty * network configuration. Otherwise, the networkId should * refer to an existing configuration. */ int netId = config.networkId; boolean updateFailed = true; - boolean newNetwork = netId == -1; - // networkId of -1 means we want to create a new network + boolean newNetwork = (netId == INVALID_NETWORK_ID); + // networkId of INVALID_NETWORK_ID means we want to create a new network if (newNetwork) { netId = WifiNative.addNetworkCommand(); if (netId < 0) { Log.e(TAG, "Failed to add a network!"); - return -1; + return INVALID_NETWORK_ID; } } @@ -700,7 +737,7 @@ class WifiConfigStore { "Failed to set a network variable, removed network: " + netId); } - return -1; + return INVALID_NETWORK_ID; } /* An update of the network variables requires reading them diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 8971bdd..57e9bad 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -43,6 +43,8 @@ public class WifiConfiguration implements Parcelable { public static final String priorityVarName = "priority"; /** {@hide} */ public static final String hiddenSSIDVarName = "scan_ssid"; + /** {@hide} */ + public static final int INVALID_NETWORK_ID = -1; /** {@hide} */ public class EnterpriseField { @@ -313,7 +315,7 @@ public class WifiConfiguration implements Parcelable { public DhcpInfo ipConfig; public WifiConfiguration() { - networkId = -1; + networkId = INVALID_NETWORK_ID; SSID = null; BSSID = null; priority = 0; diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 4435110..0b3a782 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1037,6 +1037,32 @@ public class WifiManager { } /** + * Start Wi-fi protected setup push button Configuration + * + * @param bssid BSSID of the access point + * @hide + */ + public void startWpsPbc(String bssid) { + try { + mService.startWpsPbc(bssid); + } catch (RemoteException e) { } + } + + /** + * Start Wi-fi Protected Setup pin method configuration + * + * @param bssid BSSID of the access point + * @param apPin PIN issued by the access point + * + * @hide + */ + public void startWpsPin(String bssid, int apPin) { + try { + mService.startWpsPin(bssid, apPin); + } catch (RemoteException e) { } + } + + /** * Allows an application to keep the Wi-Fi radio awake. * Normally the Wi-Fi radio may turn off when the user has not used the device in a while. * Acquiring a WifiLock will keep the radio on until the lock is released. Multiple diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java index 862a61b..1251a25 100644 --- a/wifi/java/android/net/wifi/WifiNative.java +++ b/wifi/java/android/net/wifi/WifiNative.java @@ -151,6 +151,10 @@ public class WifiNative { public native static boolean clearBlacklistCommand(); + public native static boolean startWpsPbcCommand(String bssid); + + public native static boolean startWpsPinCommand(String bssid, int apPin); + public native static boolean doDhcpRequest(DhcpInfo results); public native static String getDhcpError(); diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index 6fe7529..7e26028 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -151,7 +151,9 @@ public class WifiStateMachine extends HierarchicalStateMachine { /* Connection to a specific network involves disabling all networks, * this flag tracks if networks need to be re-enabled */ private boolean mEnableAllNetworks = false; - + /* Track if WPS was started since we need to re-enable networks + * and load configuration afterwards */ + private boolean mWpsStarted = false; // Event log tags (must be in sync with event-log-tags) private static final int EVENTLOG_WIFI_STATE_CHANGED = 50021; @@ -299,7 +301,8 @@ public class WifiStateMachine extends HierarchicalStateMachine { * supplicant config. */ private static final int CMD_FORGET_NETWORK = 92; - + /* Start Wi-Fi protected setup */ + private static final int CMD_START_WPS = 93; /** @@ -406,7 +409,7 @@ public class WifiStateMachine extends HierarchicalStateMachine { * Keep track of whether WIFI is running. */ private boolean mIsRunning = false; - + /** * Keep track of whether we last told the battery stats we had started. */ @@ -765,6 +768,14 @@ public class WifiStateMachine extends HierarchicalStateMachine { sendMessage(obtainMessage(CMD_FORGET_NETWORK, netId, 0)); } + public void startWpsPbc(String bssid) { + sendMessage(obtainMessage(CMD_START_WPS, bssid)); + } + + public void startWpsPin(String bssid, int apPin) { + sendMessage(obtainMessage(CMD_START_WPS, apPin, 0, bssid)); + } + public void enableRssiPolling(boolean enabled) { sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0)); } @@ -1597,6 +1608,7 @@ public class WifiStateMachine extends HierarchicalStateMachine { case CMD_CONNECT_NETWORK: case CMD_SAVE_NETWORK: case CMD_FORGET_NETWORK: + case CMD_START_WPS: break; default: Log.e(TAG, "Error! unhandled message" + message); @@ -2355,6 +2367,33 @@ public class WifiStateMachine extends HierarchicalStateMachine { /* Expect a disconnection from the old connection */ transitionTo(mDisconnectingState); break; + case CMD_START_WPS: + String bssid = (String) message.obj; + int apPin = message.arg1; + boolean success; + if (apPin != 0) { + /* WPS pin method configuration */ + success = WifiConfigStore.startWpsPin(bssid, apPin); + } else { + /* WPS push button configuration */ + success = WifiConfigStore.startWpsPbc(bssid); + } + /* During WPS setup, all other networks are disabled. After + * a successful connect a new config is created in the supplicant. + * + * We need to enable all networks after a successful connection + * or when supplicant goes inactive due to failure. Enabling all + * networks after a disconnect is observed as done with connectNetwork + * does not lead to a successful WPS setup. + * + * Upon success, the configuration list needs to be reloaded + */ + if (success) { + mWpsStarted = true; + /* Expect a disconnection from the old connection */ + transitionTo(mDisconnectingState); + } + break; case SCAN_RESULTS_EVENT: /* Set the scan setting back to "connect" mode */ WifiNative.setScanResultHandlingCommand(CONNECT_MODE); @@ -2581,6 +2620,12 @@ public class WifiStateMachine extends HierarchicalStateMachine { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); + /* A successful WPS connection */ + if (mWpsStarted) { + WifiConfigStore.enableAllNetworks(); + WifiConfigStore.loadConfiguredNetworks(); + mWpsStarted = false; + } EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); } @Override @@ -2911,6 +2956,14 @@ public class WifiStateMachine extends HierarchicalStateMachine { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); + + /* A failed WPS connection */ + if (mWpsStarted) { + Log.e(TAG, "WPS set up failed, enabling other networks"); + WifiConfigStore.enableAllNetworks(); + mWpsStarted = false; + } + Message message = getCurrentMessage(); StateChangeResult stateChangeResult = (StateChangeResult) message.obj; |